[nexus] 01/07: New upstream version 4.3.2-svn1921

Andreas Tille tille at debian.org
Thu May 11 07:29:12 UTC 2017


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

tille pushed a commit to branch master
in repository nexus.

commit 1ac01fe7268cc3731cb9384edae52461c3878635
Author: Andreas Tille <tille at debian.org>
Date:   Thu May 11 09:11:46 2017 +0200

    New upstream version 4.3.2-svn1921
---
 AUTHORS                                            |   14 +
 CMakeLists.txt                                     |  363 +++
 COPYING                                            |  515 ++++
 CPackOptions.cmake.in                              |  220 ++
 InstallerBits/Licences/AUTHORS.txt                 |   14 +
 InstallerBits/Licences/COPYING.rtf                 |  131 +
 InstallerBits/Licences/COPYING.txt                 |   34 +
 InstallerBits/Licences/COPYING_hdf4.txt            |   51 +
 InstallerBits/Licences/COPYING_hdf5.txt            |   74 +
 InstallerBits/Licences/COPYING_iconv.txt           |  482 +++
 InstallerBits/Licences/COPYING_libxml2.txt         |    8 +
 InstallerBits/Licences/COPYING_nexus.txt           |  515 ++++
 InstallerBits/Licences/COPYING_zlib.txt            |   38 +
 InstallerBits/nexus.ico                            |  Bin 0 -> 9326 bytes
 Makefile.am                                        |   69 +
 NEWS                                               |  421 +++
 README                                             |   46 +
 README.FORTRAN                                     |   86 +
 README.FORTRAN90                                   |   95 +
 README.MinGW                                       |   54 +
 README.VS2008.pdf                                  |  Bin 0 -> 799504 bytes
 README.cmake                                       |    0
 README.cygwin                                      |   17 +
 README.developers                                  |   79 +
 README.macosx                                      |    8 +
 README.rpm                                         |   45 +
 README.versions                                    |    4 +
 Windows_extra/include/nxconfig.h                   |  200 ++
 Windows_extra/libNeXus-0-Win32.def                 |  124 +
 Windows_extra/libNeXus-0-x64.def                   |   80 +
 acinclude.m4                                       |  496 +++
 applications/CMakeLists.txt                        |   58 +
 applications/Makefile.am                           |   57 +
 applications/NXbrowse/CMakeLists.txt               |   38 +
 applications/NXbrowse/Makefile.am                  |   44 +
 applications/NXbrowse/NXbrowse.c                   |  949 ++++++
 applications/NXbrowse/SConscript                   |    0
 applications/NXbrowse/make_vms.com                 |   13 +
 applications/NXbrowse/nxbrowse.1                   |   90 +
 applications/NXconvert/CMakeLists.txt              |   61 +
 applications/NXconvert/Makefile.am                 |   47 +
 applications/NXconvert/SConscript                  |    0
 applications/NXconvert/nxconvert.1                 |   64 +
 applications/NXconvert/nxconvert.cpp               |  160 +
 applications/NXconvert/nxconvert_common.cpp        |  374 +++
 applications/NXconvert/nxconvert_common.h          |   46 +
 applications/NXdir/.cvsignore                      |    5 +
 applications/NXdir/CHANGES                         |   83 +
 applications/NXdir/CMakeLists.txt                  |   40 +
 applications/NXdir/LICENSE                         |   22 +
 applications/NXdir/Makefile.am                     |   57 +
 applications/NXdir/README                          |   25 +
 applications/NXdir/TODO                            |    5 +
 applications/NXdir/data.cpp                        |  287 ++
 applications/NXdir/data_writer.cpp                 |  536 ++++
 applications/NXdir/main.cpp                        |  651 ++++
 applications/NXdir/nxdir.1                         |   91 +
 applications/NXdir/nxdir.h                         |  121 +
 applications/NXdir/nxdir_help.h                    |   34 +
 applications/NXdir/string_util.cpp                 |  429 +++
 applications/NXdir/tree.cpp                        |  778 +++++
 applications/NXdump/CMakeLists.txt                 |   45 +
 applications/NXdump/Makefile.am                    |   48 +
 applications/NXdump/NXdump.f90                     |   82 +
 applications/NXdump/SConscript                     |    0
 applications/NXsummary/CMakeLists.txt              |   42 +
 applications/NXsummary/LICENSE                     |   22 +
 applications/NXsummary/Makefile.am                 |   42 +
 applications/NXsummary/data_util.cpp               |  417 +++
 applications/NXsummary/data_util.hpp               |   41 +
 applications/NXsummary/main.cpp                    |  252 ++
 applications/NXsummary/nxsummary.1                 |   85 +
 applications/NXsummary/nxsummary.hpp               |   65 +
 applications/NXsummary/output.cpp                  |  146 +
 applications/NXsummary/output.hpp                  |   19 +
 applications/NXsummary/preferences.cpp             |  329 ++
 applications/NXsummary/preferences.hpp             |   48 +
 applications/NXsummary/string_util.cpp             |  174 ++
 applications/NXsummary/string_util.hpp             |   44 +
 applications/NXsummary/xml_util.hpp                |   16 +
 applications/NXtranslate/BUGS                      |   22 +
 applications/NXtranslate/CHANGES                   |    9 +
 applications/NXtranslate/CMakeLists.txt            |   61 +
 applications/NXtranslate/FRM2/CMakeLists.txt       |   32 +
 applications/NXtranslate/FRM2/Makefile.am          |   42 +
 applications/NXtranslate/FRM2/frm2_retriever.cpp   | 3141 +++++++++++++++++++
 applications/NXtranslate/FRM2/frm2_retriever.h     |  144 +
 applications/NXtranslate/LICENSE                   |   22 +
 applications/NXtranslate/Makefile.am               |  108 +
 applications/NXtranslate/Ptr.h                     |   51 +
 applications/NXtranslate/README                    |    7 +
 applications/NXtranslate/attr.cpp                  |   76 +
 applications/NXtranslate/attr.h                    |   29 +
 .../NXtranslate/binary/BinaryRetriever.cpp         |  345 +++
 .../NXtranslate/binary/BinaryRetriever.hpp         |   22 +
 applications/NXtranslate/binary/CMakeLists.txt     |   31 +
 applications/NXtranslate/binary/Makefile.am        |   41 +
 applications/NXtranslate/docs/Makefile.am          |   20 +
 applications/NXtranslate/docs/NXtranslate.docbook  |   46 +
 applications/NXtranslate/docs/overview.docbook     |  123 +
 applications/NXtranslate/docs/retrievers.docbook   |  220 ++
 applications/NXtranslate/docs/translation.docbook  |  671 ++++
 applications/NXtranslate/dynamic_retriever.cpp     |  102 +
 applications/NXtranslate/dynamic_retriever.h       |   59 +
 applications/NXtranslate/esrf_edf/CMakeLists.txt   |   32 +
 applications/NXtranslate/esrf_edf/Makefile.am      |   42 +
 applications/NXtranslate/esrf_edf/edf_reader.cpp   |  385 +++
 applications/NXtranslate/esrf_edf/edf_reader.h     |   66 +
 .../NXtranslate/esrf_edf/edf_retriever.cpp         |  308 ++
 applications/NXtranslate/esrf_edf/edf_retriever.h  |   37 +
 applications/NXtranslate/hrcs1797.run              |  Bin 0 -> 189952 bytes
 applications/NXtranslate/loopy/CMakeLists.txt      |   32 +
 applications/NXtranslate/loopy/Makefile.am         |   41 +
 applications/NXtranslate/loopy/retriever.cpp       |  255 ++
 applications/NXtranslate/loopy/retriever.h         |   23 +
 applications/NXtranslate/main.cpp                  |  243 ++
 applications/NXtranslate/nexus_retriever.cpp       |  238 ++
 applications/NXtranslate/nexus_retriever.h         |   20 +
 applications/NXtranslate/nexus_util.cpp            |  448 +++
 applications/NXtranslate/nexus_util.h              |   33 +
 applications/NXtranslate/node.cpp                  |  315 ++
 applications/NXtranslate/node.h                    |   64 +
 applications/NXtranslate/node_util.cpp             |  183 ++
 applications/NXtranslate/node_util.h               |   24 +
 applications/NXtranslate/nxtranslate.1             |   72 +
 applications/NXtranslate/nxtranslate_debug.h       |   24 +
 applications/NXtranslate/opengenie/Makefile.am     |   43 +
 applications/NXtranslate/opengenie/README          |   29 +
 .../NXtranslate/opengenie/genie_data_access.h      |  174 ++
 applications/NXtranslate/opengenie/geniedefs.h     |  181 ++
 applications/NXtranslate/opengenie/nxgenie.gcl     |  129 +
 applications/NXtranslate/opengenie/opengenie.c     |  123 +
 applications/NXtranslate/retriever.cpp             |  131 +
 applications/NXtranslate/retriever.h               |   52 +
 .../NXtranslate/sns_histogram/CMakeLists.txt       |   33 +
 applications/NXtranslate/sns_histogram/Makefile.am |   43 +
 .../NXtranslate/sns_histogram/SNS_retriever.cpp    | 1686 ++++++++++
 .../NXtranslate/sns_histogram/SNS_retriever.hpp    |  624 ++++
 .../NXtranslate/sns_histogram/retriever.cpp        | 1686 ++++++++++
 applications/NXtranslate/sns_histogram/retriever.h |   24 +
 .../NXtranslate/sns_histogram/retriever.hpp        |  605 ++++
 .../NXtranslate/sns_histogram/retriever_test.cpp   |  165 +
 .../sns_histogram/string_location_format.cpp       |  398 +++
 .../sns_histogram/string_location_format.h         |  135 +
 applications/NXtranslate/spec/CMakeLists.txt       |   33 +
 applications/NXtranslate/spec/Makefile.am          |   42 +
 applications/NXtranslate/spec/SPEClib.cpp          | 1362 ++++++++
 applications/NXtranslate/spec/SPEClib.h            |   60 +
 applications/NXtranslate/spec/spec_retriever.cpp   | 1024 ++++++
 applications/NXtranslate/spec/spec_retriever.h     |   40 +
 applications/NXtranslate/string_util.cpp           |  797 +++++
 applications/NXtranslate/string_util.h             |  110 +
 applications/NXtranslate/test_SNS_3_10_5_linux.dat |  Bin 0 -> 600 bytes
 applications/NXtranslate/test_SNS_nexus.dat        |  Bin 0 -> 120000 bytes
 applications/NXtranslate/test_SNS_nexus.xml        |    5 +
 applications/NXtranslate/test_SNS_nexus3_10_5.dat  |  Bin 0 -> 1200 bytes
 applications/NXtranslate/test_SNS_nexus_3_10_5.dat |  Bin 0 -> 600 bytes
 .../NXtranslate/test_SNS_nexus_3_10_5_mac.dat      |  Bin 0 -> 600 bytes
 .../NXtranslate/test_SNS_nexus_3_10_5_swap.dat     |  Bin 0 -> 600 bytes
 applications/NXtranslate/test_binary.nxt           |    5 +
 applications/NXtranslate/test_dynamic.c            |   57 +
 applications/NXtranslate/test_dynamic.xml          |   15 +
 applications/NXtranslate/test_ipns.xml             |   31 +
 applications/NXtranslate/test_loopy.nxt            |    5 +
 applications/NXtranslate/test_nexus.xml            |   15 +
 applications/NXtranslate/test_nexus_macro.xml      |   15 +
 applications/NXtranslate/test_opengenie.xml        |  113 +
 applications/NXtranslate/test_simple.xml           |   45 +
 applications/NXtranslate/test_text_collist.xml     |   59 +
 applications/NXtranslate/test_text_plain.xml       |    6 +
 applications/NXtranslate/test_text_xml.xml         |    7 +
 .../NXtranslate/text_collist/CMakeLists.txt        |   33 +
 applications/NXtranslate/text_collist/Makefile.am  |   41 +
 .../NXtranslate/text_collist/collist_retriever.cpp |  735 +++++
 .../NXtranslate/text_collist/collist_retriever.h   |   61 +
 applications/NXtranslate/text_collist/mira.txt     |  110 +
 applications/NXtranslate/text_plain/CMakeLists.txt |   32 +
 applications/NXtranslate/text_plain/Makefile.am    |   41 +
 applications/NXtranslate/text_plain/retriever.cpp  |  107 +
 applications/NXtranslate/text_plain/retriever.h    |   22 +
 applications/NXtranslate/text_xml/CMakeLists.txt   |   34 +
 applications/NXtranslate/text_xml/Makefile.am      |   43 +
 applications/NXtranslate/text_xml/retriever.h      |   24 +
 applications/NXtranslate/text_xml/void_copy.cpp    |  170 +
 applications/NXtranslate/text_xml/void_copy.h      |   30 +
 .../NXtranslate/text_xml/xml_retriever.cpp         |  362 +++
 .../NXtranslate/text_xml/xml_retriever_dom.cpp     |  302 ++
 .../NXtranslate/text_xml/xml_retriever_dom.h       |   15 +
 applications/NXtranslate/tree.hh                   | 1921 ++++++++++++
 applications/NXtranslate/xml_parser.cpp            |  601 ++++
 applications/NXtranslate/xml_parser.h              |   21 +
 applications/NXtranslate/xml_util.cpp              |   33 +
 applications/NXtranslate/xml_util.h                |   14 +
 applications/NXtraverse/CMakeLists.txt             |   43 +
 applications/NXtraverse/Makefile.am                |   41 +
 applications/NXtraverse/main.cpp                   |  167 +
 applications/NXtraverse/nxtraverse.cpp             |  651 ++++
 applications/NXtraverse/nxtraverse.h               |   88 +
 applications/NXvalidate/CMakeLists.txt             |   63 +
 applications/NXvalidate/Licence.txt                |    0
 applications/NXvalidate/Makefile.am                |   75 +
 applications/NXvalidate/Readme.txt                 |    0
 applications/NXvalidate/build.xml                  |   76 +
 applications/NXvalidate/doc/help/index.html        |    0
 applications/NXvalidate/install.xml                |  100 +
 applications/NXvalidate/lib/jhall.jar              |  Bin 0 -> 589910 bytes
 applications/NXvalidate/lib/saxon9he.jar           |  Bin 0 -> 5463074 bytes
 applications/NXvalidate/manifest.mf                |    3 +
 applications/NXvalidate/nbproject/build-impl.xml   |  880 ++++++
 .../NXvalidate/nbproject/genfiles.properties       |    8 +
 ...beans-modules-java-j2seproject-copylibstask.jar |  Bin 0 -> 17847 bytes
 .../NXvalidate/nbproject/project.properties        |   76 +
 applications/NXvalidate/nbproject/project.xml      |   13 +
 applications/NXvalidate/nxvalidate.1               |   35 +
 applications/NXvalidate/nxvalidate.bat.in          |   34 +
 applications/NXvalidate/nxvalidate.in              |   48 +
 .../NXvalidate/scripts/Unix_shortcutSpec.xml       |   96 +
 applications/NXvalidate/scripts/install_path       |    1 +
 applications/NXvalidate/scripts/shortcutSpec.xml   |   68 +
 .../org/nexusformat/nxvalidate/AboutDialog.form    |  103 +
 .../org/nexusformat/nxvalidate/AboutDialog.java    |  170 +
 .../nexusformat/nxvalidate/AbstractNXSnode.java    |   42 +
 .../src/org/nexusformat/nxvalidate/Attribute.java  |   46 +
 .../nexusformat/nxvalidate/BulkLoadFilesFrame.form |  191 ++
 .../nexusformat/nxvalidate/BulkLoadFilesFrame.java |  409 +++
 .../nexusformat/nxvalidate/CheckNexusFileType.java |  245 ++
 .../org/nexusformat/nxvalidate/FileActions.java    |  418 +++
 .../src/org/nexusformat/nxvalidate/Logger.java     |   94 +
 .../nexusformat/nxvalidate/NXLoadFilesDialog.form  |  169 +
 .../nexusformat/nxvalidate/NXLoadFilesDialog.java  |  281 ++
 .../org/nexusformat/nxvalidate/NXNodeMapper.java   |  945 ++++++
 .../nexusformat/nxvalidate/NXReducedToTree.java    |  179 ++
 .../nexusformat/nxvalidate/NXSettingsDialog.form   |  137 +
 .../nexusformat/nxvalidate/NXSettingsDialog.java   |  217 ++
 .../src/org/nexusformat/nxvalidate/NXSnode.java    |  340 ++
 .../org/nexusformat/nxvalidate/NXTreeRenderer.java |   76 +
 .../nexusformat/nxvalidate/NXValidateDialog.form   |  140 +
 .../nexusformat/nxvalidate/NXValidateDialog.java   |  218 ++
 .../src/org/nexusformat/nxvalidate/NXconvert.java  |  120 +
 .../org/nexusformat/nxvalidate/NXproperties.java   |  113 +
 .../org/nexusformat/nxvalidate/NXschematron.java   |  213 ++
 .../src/org/nexusformat/nxvalidate/NXvalidate.java |  257 ++
 .../nexusformat/nxvalidate/NXvalidateBasicGui.java |  380 +++
 .../nexusformat/nxvalidate/NXvalidateFrame.form    |  278 ++
 .../nexusformat/nxvalidate/NXvalidateFrame.java    |  693 +++++
 .../nexusformat/nxvalidate/NXvalidateGuiTree.java  |  177 ++
 .../nxvalidate/NodeFilterInterface.java            |   72 +
 .../org/nexusformat/nxvalidate/OSValidator.java    |   58 +
 .../org/nexusformat/nxvalidate/PopupListener.java  |   58 +
 .../src/org/nexusformat/nxvalidate/Report.java     |  114 +
 .../org/nexusformat/nxvalidate/SVRLNodeFilter.java |  381 +++
 .../src/org/nexusformat/nxvalidate/SVRLitem.java   |  178 ++
 .../org/nexusformat/nxvalidate/StreamGobbler.java  |   86 +
 .../org/nexusformat/nxvalidate/TextPaneStyle.java  |  227 ++
 .../src/org/nexusformat/nxvalidate/TreeUtils.java  |  293 ++
 .../org/nexusformat/nxvalidate/UserSettings.java   |  208 ++
 .../org/nexusformat/nxvalidate/ValidatorUtils.java |  175 ++
 .../nexusformat/nxvalidate/XMLIconTreeHandler.java |   74 +
 .../nexusformat/nxvalidate/XMLTreeRenderer.java    |  187 ++
 .../nxvalidate/exceptions/NXvalidateException.java |   58 +
 .../nxvalidate/filter/AllNeXusFilter.java          |   68 +
 .../nxvalidate/filter/ExtensionFilter.java         |   63 +
 .../nexusformat/nxvalidate/filter/HdfFilter.java   |   60 +
 .../nexusformat/nxvalidate/filter/NXDLfilter.java  |   36 +
 .../nexusformat/nxvalidate/filter/NeXusFilter.java |   39 +
 .../nxvalidate/filter/SchematronFilter.java        |   36 +
 .../nexusformat/nxvalidate/filter/XmlFilter.java   |   36 +
 .../src/org/nexusformat/nxvalidate/help.xml        |  297 ++
 .../help/NexusFileValidationTool_001.png           |  Bin 0 -> 11886 bytes
 .../help/NexusFileValidationTool_002.png           |  Bin 0 -> 15770 bytes
 .../help/NexusFileValidationTool_006.png           |  Bin 0 -> 15425 bytes
 .../nexusformat/nxvalidate/help/Open Files_005.png |  Bin 0 -> 11874 bytes
 .../nexusformat/nxvalidate/help/OpenFiles_003.png  |  Bin 0 -> 9181 bytes
 .../org/nexusformat/nxvalidate/help/Open_004.png   |  Bin 0 -> 18126 bytes
 .../src/org/nexusformat/nxvalidate/help/ch01.html  |   16 +
 .../org/nexusformat/nxvalidate/help/ch01s02.html   |    1 +
 .../org/nexusformat/nxvalidate/help/ch01s03.html   |   23 +
 .../org/nexusformat/nxvalidate/help/ch01s04.html   |    6 +
 .../org/nexusformat/nxvalidate/help/ch01s05.html   |   10 +
 .../org/nexusformat/nxvalidate/help/ch01s06.html   |    1 +
 .../org/nexusformat/nxvalidate/help/ch01s07.html   |   14 +
 .../org/nexusformat/nxvalidate/help/ch01s08.html   |    4 +
 .../src/org/nexusformat/nxvalidate/help/ch02.html  |   16 +
 .../src/org/nexusformat/nxvalidate/help/index.html |    1 +
 .../org/nexusformat/nxvalidate/help/jhelpidx.xml   |    3 +
 .../org/nexusformat/nxvalidate/help/jhelpmap.jhm   |   22 +
 .../org/nexusformat/nxvalidate/help/jhelpset.hs    |   27 +
 .../org/nexusformat/nxvalidate/help/jhelptoc.xml   |   19 +
 .../resources/NexusFileValidationTool_001.png      |  Bin 0 -> 11886 bytes
 .../resources/NexusFileValidationTool_002.png      |  Bin 0 -> 15770 bytes
 .../resources/NexusFileValidationTool_006.png      |  Bin 0 -> 15425 bytes
 .../nxvalidate/resources/Open Files_005.png        |  Bin 0 -> 11874 bytes
 .../nxvalidate/resources/OpenFiles_003.png         |  Bin 0 -> 9181 bytes
 .../nexusformat/nxvalidate/resources/Open_004.png  |  Bin 0 -> 18126 bytes
 .../nxvalidate/resources/XSLTResolver.java         |   81 +
 .../nexusformat/nxvalidate/resources/about.html    |   31 +
 .../nxvalidate/resources/admon-caution.png         |  Bin 0 -> 2959 bytes
 .../nxvalidate/resources/admon-important.png       |  Bin 0 -> 2454 bytes
 .../nxvalidate/resources/admon-warning.png         |  Bin 0 -> 2959 bytes
 .../org/nexusformat/nxvalidate/resources/bad.png   |  Bin 0 -> 533 bytes
 .../nexusformat/nxvalidate/resources/caution.png   |  Bin 0 -> 1250 bytes
 .../nexusformat/nxvalidate/resources/checkmark.png |  Bin 0 -> 476 bytes
 .../nxvalidate/resources/dialog-warning.png        |  Bin 0 -> 683 bytes
 .../org/nexusformat/nxvalidate/resources/good.png  |  Bin 0 -> 962 bytes
 .../org/nexusformat/nxvalidate/resources/hand.png  |  Bin 0 -> 523 bytes
 .../org/nexusformat/nxvalidate/resources/info-.png |  Bin 0 -> 533 bytes
 .../nexusformat/nxvalidate/resources/info-bad.png  |  Bin 0 -> 910 bytes
 .../nexusformat/nxvalidate/resources/info-good.png |  Bin 0 -> 1307 bytes
 .../nexusformat/nxvalidate/resources/info-warn.png |  Bin 0 -> 932 bytes
 .../org/nexusformat/nxvalidate/resources/info.png  |  Bin 0 -> 551 bytes
 .../nxvalidate/resources/isis-background.bmp       |  Bin 0 -> 1107790 bytes
 .../nxvalidate/resources/iso_abstract_expand.xsl   |  296 ++
 .../nxvalidate/resources/iso_dsdl_include.xsl      | 1160 +++++++
 .../resources/iso_schematron_message_xslt2.xsl     |   55 +
 .../iso_schematron_skeleton_for_saxon.xsl          | 2244 ++++++++++++++
 .../nxvalidate/resources/iso_svrl_for_xslt2.xsl    |  665 ++++
 .../nxvalidate/resources/messagedlg_warning.png    |  Bin 0 -> 1403 bytes
 .../org/nexusformat/nxvalidate/resources/nexus.ico |  Bin 0 -> 9326 bytes
 .../org/nexusformat/nxvalidate/resources/nexus.png |  Bin 0 -> 13395 bytes
 .../nxvalidate/resources/nexus16x16.png            |  Bin 0 -> 693 bytes
 .../nxvalidate/resources/nexus32x32.png            |  Bin 0 -> 1769 bytes
 .../nxvalidate/resources/nexus64x64.png            |  Bin 0 -> 4934 bytes
 .../nxvalidate/resources/nxvalidate.properties     |   26 +
 .../org/nexusformat/nxvalidate/resources/peg-e.png |  Bin 0 -> 757 bytes
 .../org/nexusformat/nxvalidate/resources/warn.png  |  Bin 0 -> 571 bytes
 applications/NXvalidate/xslt2lib.py                |   82 +
 applications/SConscript                            |   66 +
 applications/nxdiff                                |  716 +++++
 applications/nxdiff.1                              |   96 +
 applications/nxingest/.nxs                         |   92 +
 applications/nxingest/CMakeLists.txt               |   44 +
 applications/nxingest/Makefile.am                  |   18 +
 applications/nxingest/gpl.txt                      |  280 ++
 applications/nxingest/nxingest.h                   |   98 +
 applications/nxingest/nxingest.txt                 |  325 ++
 applications/nxingest/nxingest_debug.cpp           |  101 +
 applications/nxingest/nxingest_debug.h             |   68 +
 applications/nxingest/nxingest_main.cpp            |  164 +
 applications/nxingest/nxingest_main.h              |   39 +
 applications/nxingest/nxingest_nexus.cpp           |  408 +++
 applications/nxingest/nxingest_nexus.h             |   69 +
 applications/nxingest/nxingest_parse.cpp           |  499 +++
 applications/nxingest/nxingest_parse.h             |   51 +
 applications/nxingest/nxingest_time.cpp            |  240 ++
 applications/nxingest/nxingest_time.h              |   61 +
 applications/nxingest/nxingest_utils.cpp           |   98 +
 applications/nxingest/nxingest_utils.h             |   60 +
 autogen.sh                                         |  180 ++
 autoversion.sh                                     |   34 +
 bindings/CMakeLists.txt                            |   42 +
 bindings/Makefile.am                               |   53 +
 bindings/cpp/CMakeLists.txt                        |   77 +
 bindings/cpp/Makefile.am                           |   67 +
 bindings/cpp/NeXusException.cpp                    |   30 +
 bindings/cpp/NeXusException.hpp                    |   50 +
 bindings/cpp/NeXusFile.cpp                         | 1809 +++++++++++
 bindings/cpp/NeXusFile.hpp                         |  853 +++++
 bindings/cpp/NeXusStream.cpp                       |  281 ++
 bindings/cpp/NeXusStream.hpp                       |  291 ++
 bindings/cpp/SConscript                            |   61 +
 bindings/f77/CMakeLists.txt                        |   57 +
 bindings/f77/Makefile.am                           |   39 +
 bindings/f77/napif.f                               |  518 ++++
 bindings/f77/napif.inc                             |   94 +
 bindings/f77/napif_test.f                          |  327 ++
 bindings/f90/CMakeLists.txt                        |   56 +
 bindings/f90/Makefile.am                           |   52 +
 bindings/f90/NXUmodule.f90                         | 1374 +++++++++
 bindings/f90/NXmodule.f90                          | 1371 +++++++++
 bindings/idl/Makefile.am                           |   82 +
 bindings/idl/NXtest.h5                             |  Bin 0 -> 25992 bytes
 bindings/idl/NXtest.hdf                            |  Bin 0 -> 34831 bytes
 bindings/idl/NXtest.xml                            |  451 +++
 bindings/idl/NeXusIDL-API.c                        | 2636 ++++++++++++++++
 bindings/idl/NeXusIDL-API.def                      |    4 +
 bindings/idl/NeXusIDL-API.dlm                      |   40 +
 bindings/idl/NeXusIDL-API.export                   |    1 +
 bindings/idl/README.html                           | 1951 ++++++++++++
 bindings/idl/build_testmodule.pro                  |   67 +
 bindings/idl/build_win.bat                         |   63 +
 bindings/idl/data/dmc01.h5                         |  Bin 0 -> 29488 bytes
 bindings/idl/data/dmc01.hdf                        |  Bin 0 -> 2988622 bytes
 bindings/idl/data/dmc01.xml                        |  245 ++
 bindings/idl/data/dmc02.h5                         |  Bin 0 -> 29488 bytes
 bindings/idl/data/dmc02.hdf                        |  Bin 0 -> 827365 bytes
 bindings/idl/data/dmc02.xml                        |  245 ++
 bindings/idl/data/focus2007n001335.hdf             |  Bin 0 -> 1025567 bytes
 bindings/idl/handle.c                              |  140 +
 bindings/idl/handle.h                              |   23 +
 bindings/idl/nxext.h5                              |  Bin 0 -> 3561 bytes
 bindings/idl/nxext.hdf                             |  Bin 0 -> 3567 bytes
 bindings/idl/nxext.xml                             |  Bin 0 -> 3567 bytes
 bindings/idl/read_test.pro                         |  336 ++
 bindings/idl/recursiveread.pro                     |  161 +
 bindings/idl/recursivesearch.pro                   |  175 ++
 bindings/idl/testfocus.pro                         |    8 +
 bindings/idl/testidlnapi                           |   14 +
 bindings/idl/write_test.pro                        |  379 +++
 bindings/java/CMakeLists.txt                       |  160 +
 bindings/java/COPYING.NCSA                         |   60 +
 bindings/java/Make.alpha                           |  144 +
 bindings/java/Make.linux                           |   99 +
 bindings/java/Make.mingw                           |  121 +
 bindings/java/Make.tux                             |   99 +
 bindings/java/Make.win32                           |   99 +
 bindings/java/Makefile.am                          |  155 +
 bindings/java/NeXus.gif                            |  Bin 0 -> 8074 bytes
 bindings/java/README.JNEXUS                        |   79 +
 bindings/java/bin/README                           |    5 +
 bindings/java/bin/win32/hd413m.def                 |  870 ++++++
 bindings/java/bin/win32/hd413m.dll                 |  Bin 0 -> 476672 bytes
 bindings/java/bin/win32/hd413m.lib                 |  Bin 0 -> 75776 bytes
 bindings/java/bin/win32/hd415m.dll                 |  Bin 0 -> 466944 bytes
 bindings/java/bin/win32/hdf5dll.dll                |  Bin 0 -> 966656 bytes
 bindings/java/bin/win32/hm413m.def                 |  201 ++
 bindings/java/bin/win32/hm413m.dll                 |  Bin 0 -> 91648 bytes
 bindings/java/bin/win32/hm413m.lib                 |  Bin 0 -> 16896 bytes
 bindings/java/bin/win32/hm415m.dll                 |  Bin 0 -> 94208 bytes
 bindings/java/bin/win32/szlibdll.dll               |  Bin 0 -> 77824 bytes
 bindings/java/bin/win32/zlib.dll                   |  Bin 0 -> 53760 bytes
 bindings/java/compilejava.bat                      |    6 +
 bindings/java/ignore-index.html                    |  395 +++
 bindings/java/japinotes.html                       |  388 +++
 bindings/java/jnexustut.html                       |  329 ++
 bindings/java/native/NexusFile.c                   | 1588 ++++++++++
 bindings/java/native/handle.c                      |   61 +
 bindings/java/native/handle.h                      |   21 +
 bindings/java/native/hdfexceptionImp.c             |  166 +
 bindings/java/native/hdfexceptionImp.h             |   10 +
 bindings/java/native/hdfnativeImp.c                | 1258 ++++++++
 bindings/java/ncsa/hdf/hdflib/HDFArray.java        |  850 +++++
 bindings/java/ncsa/hdf/hdflib/HDFConstants.java    |  312 ++
 bindings/java/ncsa/hdf/hdflib/HDFException.java    |   61 +
 .../java/ncsa/hdf/hdflib/HDFJavaException.java     |   37 +
 bindings/java/ncsa/hdf/hdflib/HDFNativeData.java   |  167 +
 .../hdf/hdflib/HDFNotImplementedException.java     |   41 +
 bindings/java/org/nexusformat/AttributeEntry.java  |   19 +
 bindings/java/org/nexusformat/NXlink.java          |   24 +
 .../java/org/nexusformat/NeXusFileInterface.java   |  440 +++
 bindings/java/org/nexusformat/NexusException.java  |   39 +
 bindings/java/org/nexusformat/NexusFile.java       |  686 +++++
 bindings/java/test/TestJapi.java                   |  275 ++
 bindings/matlab/Makefile.am                        |   81 +
 bindings/python/CMakeLists.txt                     |   83 +
 bindings/python/Makefile.am                        |   58 +
 bindings/python/README.html                        |  307 ++
 bindings/python/nxs/__init__.py                    |   21 +
 bindings/python/nxs/napi.py                        | 1470 +++++++++
 bindings/python/nxs/tree.py                        | 3249 ++++++++++++++++++++
 bindings/python/nxs/unit.py                        |  196 ++
 bindings/python/nxstest.py                         |  429 +++
 bindings/python/pythondoc.cmake                    |   29 +
 bindings/python/run_nxstest                        |    6 +
 bindings/python/setup.py                           |   22 +
 bindings/python/test/nxs_napi_lowlevel.py          |  215 ++
 bindings/python/test/runtest.py                    |   19 +
 bindings/swig/CMakeLists.txt                       |  152 +
 bindings/swig/Makefile.am                          |  147 +
 bindings/swig/README                               |   23 +
 bindings/swig/asciidblib.scm                       |  213 ++
 bindings/swig/nxdataset.i                          |  114 +
 bindings/swig/nxdstest.tcl                         |   28 +
 bindings/swig/nxexam.tcl                           |   39 +
 bindings/swig/nxinter.i                            |   95 +
 bindings/swig/nxinter.tex                          |  480 +++
 bindings/swig/nxinterhelper.c                      |  635 ++++
 bindings/swig/nxinterhelper.h                      |   74 +
 bindings/swig/nxintertest.tcl                      |  191 ++
 bindings/swig/nxtest.scm                           |   56 +
 build_rpm.in                                       |   47 +
 build_rules.am                                     |   70 +
 cmake_include/FindAnt.cmake                        |   34 +
 cmake_include/FindCBFLib.cmake                     |   29 +
 cmake_include/FindDocbookUtils.cmake               |   44 +
 cmake_include/FindExtraJava.cmake                  |   44 +
 cmake_include/FindGuile.cmake                      |   41 +
 cmake_include/FindHDF4.cmake                       |   73 +
 cmake_include/FindHDF5.cmake                       |   59 +
 cmake_include/FindIDL.cmake                        |   28 +
 cmake_include/FindJNI.cmake                        |  261 ++
 cmake_include/FindJava.cmake                       |  207 ++
 cmake_include/FindMXML.cmake                       |   66 +
 cmake_include/FindMZScheme.cmake                   |   42 +
 cmake_include/FindOpenGenie.cmake                  |   28 +
 cmake_include/FindPython.cmake                     |  104 +
 cmake_include/FindSZIP.cmake                       |   63 +
 cmake_include/Utilities.cmake                      |   69 +
 cmake_include/WELCOME.txt                          |    1 +
 cmake_include/nexus_description.txt                |    5 +
 cmake_modules/NSIS.template.in                     | 1317 ++++++++
 configure.ac                                       |  977 ++++++
 configure_cmake_build.bat                          |   55 +
 configure_mingw_kit                                |    5 +
 contrib/.cvsignore                                 |    2 +
 contrib/CMakeLists.txt                             |   31 +
 contrib/Makefile.am                                |    8 +
 contrib/README                                     |    6 +
 contrib/applications/.cvsignore                    |    2 +
 contrib/applications/CBFLib/Makefile.am            |   38 +
 contrib/applications/CBFLib/README                 |   13 +
 contrib/applications/CBFLib/cbf2nx.c               | 1528 +++++++++
 contrib/applications/CMakeLists.txt                |   32 +
 contrib/applications/Makefile.am                   |   19 +
 contrib/applications/NXextract/Makefile.am         |   30 +
 contrib/applications/NXextract/example/nxsans2.nxe |   71 +
 .../NXextract/example/sans2009n012333.hdf          |  Bin 0 -> 58499 bytes
 .../applications/NXextract/example/template_1.nxe  |  119 +
 .../applications/NXextract/example/template_2.nxe  |   54 +
 .../example/template_2/scan_1d_extract_image.nxe   |   43 +
 .../example/template_2/scan_1d_extract_scalar.nxe  |   44 +
 .../example/template_2/scan_2d_extract_scalar.nxe  |   54 +
 .../applications/NXextract/example/template_3.nxe  |   66 +
 contrib/applications/NXextract/readme.txt          |   34 +
 contrib/applications/NXextract/src/Makefile.am     |   41 +
 contrib/applications/NXextract/src/base.cpp        | 2718 ++++++++++++++++
 contrib/applications/NXextract/src/base.h          | 1202 ++++++++
 contrib/applications/NXextract/src/bmp.cpp         |  143 +
 contrib/applications/NXextract/src/bmp.h           |   68 +
 contrib/applications/NXextract/src/date.cpp        |  948 ++++++
 contrib/applications/NXextract/src/date.h          |  441 +++
 contrib/applications/NXextract/src/extractor.cpp   | 1875 +++++++++++
 contrib/applications/NXextract/src/extractor.h     |  557 ++++
 .../applications/NXextract/src/extractorapp.cpp    |  257 ++
 contrib/applications/NXextract/src/file.cpp        | 1608 ++++++++++
 contrib/applications/NXextract/src/file.h          |  478 +++
 contrib/applications/NXextract/src/jpegwrap.cpp    |  252 ++
 contrib/applications/NXextract/src/jpegwrap.h      |  132 +
 contrib/applications/NXextract/src/membuf.cpp      |  973 ++++++
 contrib/applications/NXextract/src/membuf.h        |  288 ++
 .../applications/NXextract/src/nexusevaluator.cpp  | 1052 +++++++
 .../applications/NXextract/src/nexusevaluator.h    |  124 +
 contrib/applications/NXextract/src/nxfile.cpp      | 2246 ++++++++++++++
 contrib/applications/NXextract/src/nxfile.h        |  927 ++++++
 .../applications/NXextract/src/templateparsor.cpp  | 1026 +++++++
 .../applications/NXextract/src/templateparsor.h    |   96 +
 contrib/applications/NXextract/src/variant.cpp     |  526 ++++
 contrib/applications/NXextract/src/variant.h       |  143 +
 contrib/applications/NXformat_dfn/NXconvert.py     |  191 ++
 contrib/applications/NXformat_dfn/NXformat_dfn.py  |  234 ++
 contrib/applications/NXformat_dfn/NXprettyprint.py |  159 +
 .../applications/NXformat_dfn/format_docbook.py    |   23 +
 contrib/applications/NXformat_dfn/format_xml.py    |  263 ++
 contrib/applications/nxplot/NXplot/.classpath      |    7 +
 contrib/applications/nxplot/NXplot/.project        |   28 +
 .../NXplot/.settings/org.eclipse.jdt.core.prefs    |    8 +
 .../nxplot/NXplot/META-INF/MANIFEST.MF             |   14 +
 .../applications/nxplot/NXplot/build.properties    |    7 +
 .../nxplot/NXplot/icons/alt_window_16.gif          |  Bin 0 -> 637 bytes
 .../nxplot/NXplot/icons/alt_window_32.gif          |  Bin 0 -> 1192 bytes
 .../applications/nxplot/NXplot/icons/nexusw.png    |  Bin 0 -> 12809 bytes
 .../applications/nxplot/NXplot/icons/nexusw32.png  |  Bin 0 -> 3925 bytes
 contrib/applications/nxplot/NXplot/nxplot.product  |   91 +
 contrib/applications/nxplot/NXplot/plugin.xml      |   55 +
 contrib/applications/nxplot/NXplot/splash.bmp      |  Bin 0 -> 457654 bytes
 .../nexusformat/nxplot/ActionDelegateProxy.java    |   35 +
 .../nxplot/ApplicationActionBarAdvisor.java        |   79 +
 .../nxplot/ApplicationWorkbenchAdvisor.java        |   20 +
 .../nxplot/ApplicationWorkbenchWindowAdvisor.java  |   26 +
 .../org/nexusformat/nxplot/BlankSysAdapter.java    |   40 +
 .../NXplot/src/org/nexusformat/nxplot/NXplot.java  |   55 +
 .../src/org/nexusformat/nxplot/Perspective.java    |   31 +
 .../NXplot/src/org/nexusformat/nxplot/View.java    |   73 +
 contrib/applications/nxplot/README.build           |   61 +
 contrib/applications/nxplot/jnexus/.classpath      |    7 +
 contrib/applications/nxplot/jnexus/.project        |   28 +
 .../jnexus/.settings/org.eclipse.jdt.core.prefs    |    8 +
 contrib/applications/nxplot/jnexus/Linuxi386.lib   |    8 +
 .../nxplot/jnexus/META-INF/MANIFEST.MF             |   12 +
 .../applications/nxplot/jnexus/build.properties    |   34 +
 contrib/applications/nxplot/jnexus/hd421m.dll      |  Bin 0 -> 438272 bytes
 contrib/applications/nxplot/jnexus/hdf5dll.dll     |  Bin 0 -> 909312 bytes
 contrib/applications/nxplot/jnexus/hm421m.dll      |  Bin 0 -> 94208 bytes
 contrib/applications/nxplot/jnexus/iconv.dll       |  Bin 0 -> 888832 bytes
 contrib/applications/nxplot/jnexus/jnexus.dll      |  Bin 0 -> 109286 bytes
 contrib/applications/nxplot/jnexus/libNeXus-0.dll  |  Bin 0 -> 1074850 bytes
 contrib/applications/nxplot/jnexus/libNeXus.so     |  Bin 0 -> 261291 bytes
 contrib/applications/nxplot/jnexus/libNeXus.so.0   |  Bin 0 -> 261291 bytes
 contrib/applications/nxplot/jnexus/libdf.so.4      |  Bin 0 -> 496528 bytes
 .../applications/nxplot/jnexus/libhdf5-1.6.5.so.0  |  Bin 0 -> 1203124 bytes
 contrib/applications/nxplot/jnexus/libhdf5.so      |  Bin 0 -> 1203124 bytes
 contrib/applications/nxplot/jnexus/libjnexus-0.dll |  Bin 0 -> 109286 bytes
 .../applications/nxplot/jnexus/libjnexus.jnilib    |  Bin 0 -> 2013540 bytes
 contrib/applications/nxplot/jnexus/libjnexus.so    |  Bin 0 -> 126666 bytes
 contrib/applications/nxplot/jnexus/libjpeg.so      |  Bin 0 -> 125316 bytes
 contrib/applications/nxplot/jnexus/libjpeg.so.62   |  Bin 0 -> 125316 bytes
 contrib/applications/nxplot/jnexus/libmfhdf.so     |  Bin 0 -> 135168 bytes
 contrib/applications/nxplot/jnexus/libmfhdf.so.4   |  Bin 0 -> 135168 bytes
 contrib/applications/nxplot/jnexus/libmxml.so      |  Bin 0 -> 32496 bytes
 contrib/applications/nxplot/jnexus/libmxml.so.1    |  Bin 0 -> 32496 bytes
 contrib/applications/nxplot/jnexus/libxml2.dll     |  Bin 0 -> 898560 bytes
 contrib/applications/nxplot/jnexus/libz.so.1       |  Bin 0 -> 81240 bytes
 contrib/applications/nxplot/jnexus/macosx.lib      |    1 +
 .../applications/nxplot/jnexus/sharedlib.readme    |   38 +
 .../nxplot/jnexus/src/NexusActivator.java          |   51 +
 .../jnexus/src/ncsa/hdf/hdflib/HDFArray.java       |  850 +++++
 .../jnexus/src/ncsa/hdf/hdflib/HDFConstants.java   |  312 ++
 .../jnexus/src/ncsa/hdf/hdflib/HDFException.java   |   61 +
 .../src/ncsa/hdf/hdflib/HDFJavaException.java      |   37 +
 .../jnexus/src/ncsa/hdf/hdflib/HDFNativeData.java  |  167 +
 .../hdf/hdflib/HDFNotImplementedException.java     |   41 +
 .../jnexus/src/org/nexusformat/AttributeEntry.java |   19 +
 .../nxplot/jnexus/src/org/nexusformat/NXlink.java  |   24 +
 .../src/org/nexusformat/NeXusFileInterface.java    |  346 +++
 .../jnexus/src/org/nexusformat/NexusException.java |   39 +
 .../jnexus/src/org/nexusformat/NexusFile.java      |  780 +++++
 contrib/applications/nxplot/jnexus/szlibdll.dll    |  Bin 0 -> 90112 bytes
 contrib/applications/nxplot/jnexus/windoofx86.lib  |    9 +
 contrib/applications/nxplot/jnexus/zlib1.dll       |  Bin 0 -> 55808 bytes
 .../nxplot/mountaingumnexus/.classpath             |   11 +
 .../applications/nxplot/mountaingumnexus/.project  |   28 +
 .../.settings/org.eclipse.jdt.core.prefs           |    8 +
 .../nxplot/mountaingumnexus/META-INF/MANIFEST.MF   |   15 +
 .../nxplot/mountaingumnexus/build.properties       |    7 +
 .../nxplot/mountaingumnexus/icons/nexusw.png       |  Bin 0 -> 12809 bytes
 .../nxplot/mountaingumnexus/icons/nexusw32.png     |  Bin 0 -> 4387 bytes
 .../nxplot/mountaingumnexus/plugin.xml             |   92 +
 .../mountaingumnexus/schema/NexusMapper.ID.exsd    |   85 +
 .../mountaingum/nexus/Perspective/NameView.java    |   36 +
 .../nexus/Perspective/NexusPerspective.java        |   29 +
 .../mountaingum/nexus/Perspective/NexusTree.java   |   74 +
 .../num/mountaingum/nexus/actions/OpenNexus.java   |   77 +
 .../mountaingum/nexus/actions/PNGNexusGraph.java   |   74 +
 .../mountaingum/nexus/actions/PrintNexusGraph.java |   60 +
 .../num/mountaingum/nexus/actions/SaveNexus.java   |   46 +
 .../num/mountaingum/nexus/actions/SinqFile.java    |   83 +
 .../mountaingum/nexus/actions/SinqFileAction.java  |   62 +
 .../mountaingum/nexus/actions/SinqFileDialog.java  |  156 +
 .../nexus/labelprovider/IconTreeLabelProvider.java |   59 +
 .../mountaingum/nexus/labelprovider/icons/CHAR.gif |  Bin 0 -> 102 bytes
 .../nexus/labelprovider/icons/CHAR_array.gif       |  Bin 0 -> 127 bytes
 .../nexus/labelprovider/icons/DOUBLE.gif           |  Bin 0 -> 125 bytes
 .../nexus/labelprovider/icons/DOUBLE_array.gif     |  Bin 0 -> 150 bytes
 .../nexus/labelprovider/icons/DfnTree.gif          |  Bin 0 -> 115 bytes
 .../nexus/labelprovider/icons/FLOAT.gif            |  Bin 0 -> 121 bytes
 .../nexus/labelprovider/icons/FLOAT_array.gif      |  Bin 0 -> 146 bytes
 .../mountaingum/nexus/labelprovider/icons/INT.gif  |  Bin 0 -> 121 bytes
 .../nexus/labelprovider/icons/INT_array.gif        |  Bin 0 -> 147 bytes
 .../nexus/labelprovider/icons/ISO8601.gif          |  Bin 0 -> 96 bytes
 .../nexus/labelprovider/icons/NXaperture.gif       |  Bin 0 -> 124 bytes
 .../nexus/labelprovider/icons/NXattenuator.gif     |  Bin 0 -> 92 bytes
 .../nexus/labelprovider/icons/NXchopper.gif        |  Bin 0 -> 83 bytes
 .../nexus/labelprovider/icons/NXcollimator.gif     |  Bin 0 -> 105 bytes
 .../nexus/labelprovider/icons/NXcrystal.gif        |  Bin 0 -> 129 bytes
 .../nexus/labelprovider/icons/NXdata.gif           |  Bin 0 -> 101 bytes
 .../nexus/labelprovider/icons/NXdetector.gif       |  Bin 0 -> 98 bytes
 .../nexus/labelprovider/icons/NXentry.gif          |  Bin 0 -> 113 bytes
 .../nexus/labelprovider/icons/NXfilter.gif         |  Bin 0 -> 115 bytes
 .../nexus/labelprovider/icons/NXinstrument.gif     |  Bin 0 -> 112 bytes
 .../nexus/labelprovider/icons/NXlog.gif            |  Bin 0 -> 120 bytes
 .../nexus/labelprovider/icons/NXmonitor.gif        |  Bin 0 -> 86 bytes
 .../nexus/labelprovider/icons/NXmonochromator.gif  |  Bin 0 -> 111 bytes
 .../nexus/labelprovider/icons/NXnote.gif           |  Bin 0 -> 98 bytes
 .../nexus/labelprovider/icons/NXroot.gif           |  Bin 0 -> 120 bytes
 .../nexus/labelprovider/icons/NXsample.gif         |  Bin 0 -> 111 bytes
 .../nexus/labelprovider/icons/NXslit.gif           |  Bin 0 -> 113 bytes
 .../nexus/labelprovider/icons/NXsource.gif         |  Bin 0 -> 92 bytes
 .../nexus/labelprovider/icons/NXuser.gif           |  Bin 0 -> 102 bytes
 .../mountaingum/nexus/labelprovider/icons/UINT.gif |  Bin 0 -> 120 bytes
 .../nexus/labelprovider/icons/UINT_array.gif       |  Bin 0 -> 146 bytes
 .../nexus/labelprovider/icons/graphdata.gif        |  Bin 0 -> 101 bytes
 .../nexus/labelprovider/icons/graphset.gif         |  Bin 0 -> 75 bytes
 .../nexus/labelprovider/icons/incrCol.gif          |  Bin 0 -> 135 bytes
 .../nexus/labelprovider/icons/incrLay.gif          |  Bin 0 -> 168 bytes
 .../nexus/labelprovider/icons/incrRow.gif          |  Bin 0 -> 145 bytes
 .../nexus/labelprovider/icons/transCL.gif          |  Bin 0 -> 139 bytes
 .../nexus/labelprovider/icons/transRC.gif          |  Bin 0 -> 145 bytes
 .../nexus/labelprovider/icons/transRL.gif          |  Bin 0 -> 145 bytes
 .../nexus/labelprovider/icons/unknown.gif          |  Bin 0 -> 75 bytes
 .../mountaingum/nexus/loader/FlatNexusFile.java    |  106 +
 .../num/mountaingum/nexus/loader/NeXusMapper.java  |   28 +
 .../num/mountaingum/nexus/loader/NexusLoader.java  |  971 ++++++
 .../mountaingum/nexus/loader/NexusMapperDemo.java  |   16 +
 .../mountaingum/nexus/loader/NexusParameter.java   |   71 +
 .../mountaingum/nexus/loader/OldFrameCommand.java  |  127 +
 .../mountaingum/nexus/loader/PruneEmptyGroup.java  |   33 +
 .../nexus/loader/sinqascii/ASCIILoader.java        |  142 +
 .../nexus/loader/sinqascii/ASCIIReader.java        |  266 ++
 .../applications/nxplot/mountaingumsys/.classpath  |    7 +
 .../applications/nxplot/mountaingumsys/.project    |   28 +
 .../nxplot/mountaingumsys/META-INF/MANIFEST.MF     |   13 +
 .../nxplot/mountaingumsys/build.properties         |    5 +
 .../applications/nxplot/mountaingumsys/plugin.xml  |    6 +
 .../ch.num.psi.mountaingum.tree.DataFilter.exsd    |  116 +
 .../ch/psi/num/mountaingum/batch/BatchAdapter.java |  186 ++
 .../psi/num/mountaingum/batch/BatchListener.java   |   36 +
 .../ch/psi/num/mountaingum/batch/BatchNode.java    |   31 +
 .../num/mountaingum/batch/BatchParseException.java |   15 +
 .../psi/num/mountaingum/batch/BatchReceiver.java   |   29 +
 .../num/mountaingum/batch/BatchScriptListener.java |   27 +
 .../ch/psi/num/mountaingum/func/ArrayStream.java   |   28 +
 .../num/mountaingum/func/EnumerationStream.java    |   24 +
 .../src/ch/psi/num/mountaingum/func/FuncUtil.java  |   26 +
 .../src/ch/psi/num/mountaingum/func/IFunc.java     |   17 +
 .../src/ch/psi/num/mountaingum/func/IStream.java   |   16 +
 .../psi/num/mountaingum/func/IteratorStream.java   |   26 +
 .../ch/psi/num/mountaingum/sys/DefaultLogger.java  |   36 +
 .../num/mountaingum/sys/IDisconnectListener.java   |   12 +
 .../ch/psi/num/mountaingum/sys/ISystemAdapter.java |   47 +
 .../psi/num/mountaingum/sys/LoggerInterface.java   |   21 +
 .../ch/psi/num/mountaingum/sys/NullTerminal.java   |   41 +
 .../ch/psi/num/mountaingum/sys/QueueListener.java  |   14 +
 .../ch/psi/num/mountaingum/sys/StdoutLogger.java   |   95 +
 .../ch/psi/num/mountaingum/sys/SysRegistry.java    |   53 +
 .../psi/num/mountaingum/sys/TerminalInterface.java |   30 +
 .../psi/num/mountaingum/sys/TerminalListener.java  |   19 +
 .../src/ch/psi/num/mountaingum/test/TestInt.java   |   23 +
 .../ch/psi/num/mountaingum/tree/ChildStream.java   |   31 +
 .../ch/psi/num/mountaingum/tree/CommandNode.java   |   23 +
 .../ch/psi/num/mountaingum/tree/DataFilter.java    |   12 +
 .../ch/psi/num/mountaingum/tree/DoubleValue.java   |   82 +
 .../psi/num/mountaingum/tree/ExecutableNode.java   |  178 ++
 .../ch/psi/num/mountaingum/tree/GraphicsNode.java  |   14 +
 .../src/ch/psi/num/mountaingum/tree/IntValue.java  |   87 +
 .../num/mountaingum/tree/InternalParameter.java    |   25 +
 .../ch/psi/num/mountaingum/tree/LogListener.java   |   39 +
 .../src/ch/psi/num/mountaingum/tree/LongValue.java |   81 +
 .../psi/num/mountaingum/tree/NodeListListener.java |   13 +
 .../psi/num/mountaingum/tree/NodeSearchFunc.java   |   25 +
 .../src/ch/psi/num/mountaingum/tree/NodeValue.java |   92 +
 .../ch/psi/num/mountaingum/tree/ParameterNode.java |   67 +
 .../num/mountaingum/tree/PropertySearchFunc.java   |   32 +
 .../ch/psi/num/mountaingum/tree/TreeListener.java  |   12 +
 .../src/ch/psi/num/mountaingum/tree/TreeNode.java  |  298 ++
 .../ch/psi/num/mountaingum/tree/TreeNodeList.java  |   84 +
 .../ch/psi/num/mountaingum/tree/TreeRegistry.java  |   50 +
 .../src/ch/psi/num/mountaingum/tree/TreeUtil.java  |  258 ++
 .../psi/num/mountaingum/tree/UpdateListener.java   |   22 +
 .../src/ch/psi/num/mountaingum/ui/DataRange.java   |   35 +
 .../src/ch/psi/num/mountaingum/ui/Graph.java       |  123 +
 .../src/ch/psi/num/mountaingum/ui/GraphAxis.java   |   56 +
 .../src/ch/psi/num/mountaingum/ui/GraphData.java   |  159 +
 .../src/ch/psi/num/mountaingum/ui/UIAdapter.java   |   22 +
 .../src/ch/psi/num/mountaingum/ui/UIRegistry.java  |   22 +
 .../ch/psi/num/mountaingum/util/Array2DUtil.java   |  223 ++
 .../ch/psi/num/mountaingum/util/ArrayTools.java    |  409 +++
 .../num/mountaingum/util/DynamicDoubleArray.java   |   81 +
 .../psi/num/mountaingum/util/DynamicIntArray.java  |   86 +
 .../psi/num/mountaingum/util/DynamicLongArray.java |   79 +
 .../src/ch/psi/num/mountaingum/util/Fmt.java       |  610 ++++
 .../ch/psi/num/mountaingum/util/ListSequence.java  |   48 +
 .../src/ch/psi/num/mountaingum/util/Sequence.java  |   56 +
 .../psi/num/mountaingum/util/SequenceStream.java   |   29 +
 .../applications/nxplot/mountaingumuibase/.project |   28 +
 .../.settings/org.eclipse.jdt.core.prefs           |    8 +
 .../nxplot/mountaingumuibase/META-INF/MANIFEST.MF  |   71 +
 .../nxplot/mountaingumuibase/build.properties      |    5 +
 .../nxplot/mountaingumuibase/icons/lock-icon.png   |  Bin 0 -> 775 bytes
 .../nxplot/mountaingumuibase/icons/lock25.gif      |  Bin 0 -> 1516 bytes
 .../nxplot/mountaingumuibase/plugin.xml            |  130 +
 .../schema/mountaingumuibase.NodeEditor.exsd       |  117 +
 contrib/applications/nxplot/nxplot-platform.lis    |  180 ++
 .../org.eclipse.nebula.compositetable/.classpath   |    7 +
 .../org.eclipse.nebula.compositetable/.project     |   28 +
 .../META-INF/MANIFEST.MF                           |   16 +
 .../build.properties                               |    4 +
 .../widgets/compositetable/AbsoluteLayout.class    |  Bin 0 -> 1700 bytes
 .../compositetable/AbstractGridRowLayout.class     |  Bin 0 -> 5362 bytes
 .../compositetable/AbstractNativeHeader$1.class    |  Bin 0 -> 1215 bytes
 .../compositetable/AbstractNativeHeader$2.class    |  Bin 0 -> 1524 bytes
 .../compositetable/AbstractNativeHeader$3.class    |  Bin 0 -> 1963 bytes
 .../compositetable/AbstractNativeHeader$4.class    |  Bin 0 -> 1194 bytes
 .../compositetable/AbstractNativeHeader.class      |  Bin 0 -> 6678 bytes
 .../compositetable/AbstractSelectableRow.class     |  Bin 0 -> 6093 bytes
 .../compositetable/AbstractSortableHeader$1.class  |  Bin 0 -> 1092 bytes
 .../compositetable/AbstractSortableHeader$2.class  |  Bin 0 -> 2229 bytes
 .../compositetable/AbstractSortableHeader.class    |  Bin 0 -> 5311 bytes
 .../compositetable/ColumnControlListener.class     |  Bin 0 -> 443 bytes
 .../widgets/compositetable/CompositeTable$1.class  |  Bin 0 -> 1731 bytes
 .../widgets/compositetable/CompositeTable.class    |  Bin 0 -> 15965 bytes
 .../compositetable/CompositeTableLayout.class      |  Bin 0 -> 547 bytes
 .../widgets/compositetable/DeleteAdapter.class     |  Bin 0 -> 699 bytes
 .../compositetable/EmptyTablePlaceholder$1.class   |  Bin 0 -> 2421 bytes
 .../compositetable/EmptyTablePlaceholder$2.class   |  Bin 0 -> 913 bytes
 .../compositetable/EmptyTablePlaceholder$3.class   |  Bin 0 -> 2186 bytes
 .../compositetable/EmptyTablePlaceholder$4.class   |  Bin 0 -> 1175 bytes
 .../compositetable/EmptyTablePlaceholder$5.class   |  Bin 0 -> 834 bytes
 .../compositetable/EmptyTablePlaceholder$6.class   |  Bin 0 -> 1411 bytes
 .../compositetable/EmptyTablePlaceholder.class     |  Bin 0 -> 5682 bytes
 .../widgets/compositetable/GridRowLayout.class     |  Bin 0 -> 2134 bytes
 .../widgets/compositetable/HeaderLayout$1.class    |  Bin 0 -> 1440 bytes
 .../widgets/compositetable/HeaderLayout$2.class    |  Bin 0 -> 1333 bytes
 .../HeaderLayout$HeaderControlListener.class       |  Bin 0 -> 3084 bytes
 .../widgets/compositetable/HeaderLayout.class      |  Bin 0 -> 12540 bytes
 .../widgets/compositetable/IDeleteHandler.class    |  Bin 0 -> 230 bytes
 .../widgets/compositetable/IInsertHandler.class    |  Bin 0 -> 179 bytes
 .../compositetable/IRowContentProvider.class       |  Bin 0 -> 285 bytes
 .../widgets/compositetable/IRowFocusListener.class |  Bin 0 -> 426 bytes
 .../compositetable/InternalCompositeTable$1.class  |  Bin 0 -> 2254 bytes
 .../compositetable/InternalCompositeTable$10.class |  Bin 0 -> 1218 bytes
 .../compositetable/InternalCompositeTable$11.class |  Bin 0 -> 1104 bytes
 .../compositetable/InternalCompositeTable$12.class |  Bin 0 -> 1043 bytes
 .../compositetable/InternalCompositeTable$2.class  |  Bin 0 -> 1310 bytes
 .../compositetable/InternalCompositeTable$3.class  |  Bin 0 -> 2644 bytes
 .../compositetable/InternalCompositeTable$4.class  |  Bin 0 -> 2025 bytes
 .../compositetable/InternalCompositeTable$5.class  |  Bin 0 -> 1322 bytes
 .../compositetable/InternalCompositeTable$6.class  |  Bin 0 -> 1322 bytes
 .../compositetable/InternalCompositeTable$7.class  |  Bin 0 -> 1760 bytes
 .../compositetable/InternalCompositeTable$8.class  |  Bin 0 -> 1617 bytes
 .../compositetable/InternalCompositeTable$9.class  |  Bin 0 -> 1617 bytes
 .../compositetable/InternalCompositeTable.class    |  Bin 0 -> 34402 bytes
 .../compositetable/ResizableGridRowLayout$1.class  |  Bin 0 -> 2424 bytes
 ...leGridRowLayout$GridColumnControlListener.class |  Bin 0 -> 2693 bytes
 .../compositetable/ResizableGridRowLayout.class    |  Bin 0 -> 4357 bytes
 .../compositetable/RowConstructionListener.class   |  Bin 0 -> 478 bytes
 .../widgets/compositetable/RowFocusAdapter.class   |  Bin 0 -> 1087 bytes
 .../widgets/compositetable/ScrollEvent.class       |  Bin 0 -> 900 bytes
 .../widgets/compositetable/ScrollListener.class    |  Bin 0 -> 448 bytes
 .../nebula/widgets/compositetable/TableRow$1.class |  Bin 0 -> 1077 bytes
 .../nebula/widgets/compositetable/TableRow$2.class |  Bin 0 -> 1194 bytes
 .../nebula/widgets/compositetable/TableRow$3.class |  Bin 0 -> 1193 bytes
 .../nebula/widgets/compositetable/TableRow.class   |  Bin 0 -> 3167 bytes
 .../compositetable/day/CalendarableItemEvent.class |  Bin 0 -> 875 bytes
 .../day/CalendarableItemEventHandler.class         |  Bin 0 -> 735 bytes
 .../day/CalendarableSelectionChangeListener.class  |  Bin 0 -> 535 bytes
 .../widgets/compositetable/day/DayEditor$1.class   |  Bin 0 -> 4154 bytes
 .../widgets/compositetable/day/DayEditor$10.class  |  Bin 0 -> 2000 bytes
 .../widgets/compositetable/day/DayEditor$11.class  |  Bin 0 -> 841 bytes
 .../widgets/compositetable/day/DayEditor$12.class  |  Bin 0 -> 841 bytes
 .../widgets/compositetable/day/DayEditor$13.class  |  Bin 0 -> 1471 bytes
 .../widgets/compositetable/day/DayEditor$2.class   |  Bin 0 -> 1140 bytes
 .../widgets/compositetable/day/DayEditor$3.class   |  Bin 0 -> 2038 bytes
 .../widgets/compositetable/day/DayEditor$4.class   |  Bin 0 -> 2803 bytes
 .../widgets/compositetable/day/DayEditor$5.class   |  Bin 0 -> 1744 bytes
 .../widgets/compositetable/day/DayEditor$6.class   |  Bin 0 -> 2428 bytes
 .../widgets/compositetable/day/DayEditor$7.class   |  Bin 0 -> 1404 bytes
 .../widgets/compositetable/day/DayEditor$8.class   |  Bin 0 -> 938 bytes
 .../widgets/compositetable/day/DayEditor$9.class   |  Bin 0 -> 1318 bytes
 .../widgets/compositetable/day/DayEditor.class     |  Bin 0 -> 31753 bytes
 .../compositetable/day/DayEditorSelection.class    |  Bin 0 -> 1005 bytes
 .../day/ICalendarableItemControl.class             |  Bin 0 -> 835 bytes
 .../widgets/compositetable/day/NewEvent.class      |  Bin 0 -> 536 bytes
 .../compositetable/day/SelectionChangeEvent.class  |  Bin 0 -> 727 bytes
 .../DayEditorCalendarableItemControl$1.class       |  Bin 0 -> 2689 bytes
 .../DayEditorCalendarableItemControl$2.class       |  Bin 0 -> 1956 bytes
 .../DayEditorCalendarableItemControl.class         |  Bin 0 -> 6361 bytes
 .../internal/EventLayoutComputer$EventLayout.class |  Bin 0 -> 1673 bytes
 .../day/internal/EventLayoutComputer.class         |  Bin 0 -> 5977 bytes
 .../TimeSlice$TimeSliceAcrossTimeLayout.class      |  Bin 0 -> 2559 bytes
 .../compositetable/day/internal/TimeSlice.class    |  Bin 0 -> 7523 bytes
 .../compositetable/day/internal/TimeSlot$1.class   |  Bin 0 -> 2639 bytes
 .../compositetable/day/internal/TimeSlot$2.class   |  Bin 0 -> 975 bytes
 .../compositetable/day/internal/TimeSlot$3.class   |  Bin 0 -> 2770 bytes
 .../compositetable/day/internal/TimeSlot$4.class   |  Bin 0 -> 1163 bytes
 .../compositetable/day/internal/TimeSlot$5.class   |  Bin 0 -> 821 bytes
 .../compositetable/day/internal/TimeSlot$6.class   |  Bin 0 -> 862 bytes
 .../compositetable/day/internal/TimeSlot.class     |  Bin 0 -> 7692 bytes
 .../widgets/compositetable/day/internal/clock.png  |  Bin 0 -> 733 bytes
 .../widgets/compositetable/day/internal/clock.svg  |  276 ++
 .../compositetable/internal/DuckType$Wrapper.class |  Bin 0 -> 328 bytes
 .../widgets/compositetable/internal/DuckType.class |  Bin 0 -> 3440 bytes
 .../internal/ISelectableRegionControl.class        |  Bin 0 -> 215 bytes
 .../compositetable/internal/ReflectedMethod.class  |  Bin 0 -> 1671 bytes
 .../internal/ReflectedProperty.class               |  Bin 0 -> 2530 bytes
 .../compositetable/internal/RelaxedDuckType.class  |  Bin 0 -> 2891 bytes
 .../compositetable/month/MonthCalendar$1.class     |  Bin 0 -> 2566 bytes
 .../compositetable/month/MonthCalendar$2.class     |  Bin 0 -> 2841 bytes
 .../compositetable/month/MonthCalendar$3.class     |  Bin 0 -> 2933 bytes
 .../compositetable/month/MonthCalendar.class       |  Bin 0 -> 12316 bytes
 .../month/MonthCalendarSelectedDay.class           |  Bin 0 -> 608 bytes
 .../compositetable/month/internal/Day$1.class      |  Bin 0 -> 1722 bytes
 .../compositetable/month/internal/Day$2.class      |  Bin 0 -> 1329 bytes
 .../compositetable/month/internal/Day$3.class      |  Bin 0 -> 804 bytes
 .../compositetable/month/internal/Day$4.class      |  Bin 0 -> 1550 bytes
 .../compositetable/month/internal/Day.class        |  Bin 0 -> 10843 bytes
 .../internal/MonthCalendarableItemControl$1.class  |  Bin 0 -> 1051 bytes
 .../internal/MonthCalendarableItemControl$2.class  |  Bin 0 -> 1061 bytes
 .../internal/MonthCalendarableItemControl$3.class  |  Bin 0 -> 1781 bytes
 .../internal/MonthCalendarableItemControl$4.class  |  Bin 0 -> 2127 bytes
 .../internal/MonthCalendarableItemControl.class    |  Bin 0 -> 14221 bytes
 .../compositetable/month/internal/Week.class       |  Bin 0 -> 2168 bytes
 .../compositetable/month/internal/WeekHeader.class |  Bin 0 -> 2746 bytes
 .../timeeditor/AbstractEventEditor.class           |  Bin 0 -> 3866 bytes
 .../timeeditor/CalendarableItem$1.class            |  Bin 0 -> 1031 bytes
 .../timeeditor/CalendarableItem.class              |  Bin 0 -> 6671 bytes
 .../timeeditor/CalendarableModel.class             |  Bin 0 -> 12774 bytes
 .../timeeditor/EventContentProvider.class          |  Bin 0 -> 515 bytes
 .../timeeditor/EventCountProvider.class            |  Bin 0 -> 448 bytes
 .../compositetable/timeeditor/IEventEditor.class   |  Bin 0 -> 1399 bytes
 .../compositetable/timeeditor/ModelObject.class    |  Bin 0 -> 2837 bytes
 .../org.eclipse.nebula.compositetable/src.zip      |  Bin 0 -> 138581 bytes
 contrib/applications/nxplot/sgtgraphics/.classpath |    7 +
 contrib/applications/nxplot/sgtgraphics/.project   |   28 +
 .../nxplot/sgtgraphics/META-INF/MANIFEST.MF        |   10 +
 .../nxplot/sgtgraphics/bin/META-INF/MANIFEST.MF    |   62 +
 .../sgtgraphics/bin/gov/noaa/pmel/eps/package.html |    7 +
 .../sgtgraphics/bin/gov/noaa/pmel/io/package.html  |    7 +
 .../bin/gov/noaa/pmel/sgt/PaneIcon16.gif           |  Bin 0 -> 838 bytes
 .../bin/gov/noaa/pmel/sgt/PaneIcon32.gif           |  Bin 0 -> 933 bytes
 .../sgtgraphics/bin/gov/noaa/pmel/sgt/README.txt   |    7 +
 .../bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt    |  158 +
 .../bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt    |   68 +
 .../bin/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt    |  509 +++
 .../gov/noaa/pmel/sgt/beans/DataModelIcon16.gif    |  Bin 0 -> 641 bytes
 .../gov/noaa/pmel/sgt/beans/DataModelIcon32.gif    |  Bin 0 -> 916 bytes
 .../bin/gov/noaa/pmel/sgt/beans/PageIcon16.gif     |  Bin 0 -> 568 bytes
 .../bin/gov/noaa/pmel/sgt/beans/PageIcon32.gif     |  Bin 0 -> 551 bytes
 .../gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif   |  Bin 0 -> 172 bytes
 .../gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif   |  Bin 0 -> 301 bytes
 .../noaa/pmel/sgt/beans/images/AlignBottom24.gif   |  Bin 0 -> 271 bytes
 .../noaa/pmel/sgt/beans/images/AlignCenter24.gif   |  Bin 0 -> 275 bytes
 .../sgt/beans/images/AlignJustifyHorizontal24.gif  |  Bin 0 -> 280 bytes
 .../sgt/beans/images/AlignJustifyVertical24.gif    |  Bin 0 -> 299 bytes
 .../gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif |  Bin 0 -> 267 bytes
 .../noaa/pmel/sgt/beans/images/AlignRight24.gif    |  Bin 0 -> 269 bytes
 .../gov/noaa/pmel/sgt/beans/images/AlignTop24.gif  |  Bin 0 -> 275 bytes
 .../noaa/pmel/sgt/beans/images/DataModelSimple.png |  Bin 0 -> 13695 bytes
 .../bin/gov/noaa/pmel/sgt/beans/images/Edit24.gif  |  Bin 0 -> 1244 bytes
 .../bin/gov/noaa/pmel/sgt/beans/images/New24.gif   |  Bin 0 -> 778 bytes
 .../noaa/pmel/sgt/beans/images/NewDataGroup24.gif  |  Bin 0 -> 160 bytes
 .../gov/noaa/pmel/sgt/beans/images/NewLabel24.gif  |  Bin 0 -> 317 bytes
 .../gov/noaa/pmel/sgt/beans/images/NewLegend24.gif |  Bin 0 -> 341 bytes
 .../bin/gov/noaa/pmel/sgt/beans/images/Open24.gif  |  Bin 0 -> 462 bytes
 .../pmel/sgt/beans/images/PanelModelSimple.png     |  Bin 0 -> 13703 bytes
 .../noaa/pmel/sgt/beans/images/Preferences24.gif   |  Bin 0 -> 240 bytes
 .../gov/noaa/pmel/sgt/beans/images/Remove24.gif    |  Bin 0 -> 287 bytes
 .../noaa/pmel/sgt/beans/images/RunTimeSimple.png   |  Bin 0 -> 13682 bytes
 .../bin/gov/noaa/pmel/sgt/beans/images/Save24.gif  |  Bin 0 -> 266 bytes
 .../gov/noaa/pmel/sgt/beans/images/SaveAs24.gif    |  Bin 0 -> 348 bytes
 .../bin/gov/noaa/pmel/sgt/beans/package.html       |   20 +
 .../bin/gov/noaa/pmel/sgt/contour/package.html     |   14 +
 .../gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml  |  695 +++++
 .../sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TAO.dat |   59 +
 .../bin/gov/noaa/pmel/sgt/demo/TRITON.dat          |   13 +
 .../bin/gov/noaa/pmel/sgt/demo/coarserezcoast.bin  |  Bin 0 -> 82034 bytes
 .../bin/gov/noaa/pmel/sgt/demo/finerezcoast.bin    |  Bin 0 -> 777132 bytes
 .../bin/gov/noaa/pmel/sgt/demo/ncBrowse48.gif      |  Bin 0 -> 2130 bytes
 .../bin/gov/noaa/pmel/sgt/demo/ncBrowse96.gif      |  Bin 0 -> 4803 bytes
 .../bin/gov/noaa/pmel/sgt/demo/package.html        |   17 +
 .../bin/gov/noaa/pmel/sgt/demo/query.gif           |  Bin 0 -> 139 bytes
 .../bin/gov/noaa/pmel/sgt/dm/package.html          |   14 +
 .../bin/gov/noaa/pmel/sgt/overview.html            |   46 +
 .../sgtgraphics/bin/gov/noaa/pmel/sgt/package.html |   43 +
 .../bin/gov/noaa/pmel/sgt/plot/Notes.txt           |   51 +
 .../bin/gov/noaa/pmel/sgt/plot/package.html        |   23 +
 .../bin/gov/noaa/pmel/sgt/plotmarkcodes.gif        |  Bin 0 -> 14530 bytes
 .../bin/gov/noaa/pmel/sgt/swing/package.html       |   14 +
 .../bin/gov/noaa/pmel/sgt/swing/plotmarkcodes.png  |  Bin 0 -> 98569 bytes
 .../bin/gov/noaa/pmel/sgt/swing/prop/package.html  |   22 +
 .../bin/gov/noaa/pmel/sgt/swing/sgt_logo.png       |  Bin 0 -> 4098 bytes
 .../bin/gov/noaa/pmel/space/package.html           |    6 +
 .../bin/gov/noaa/pmel/swing/package.html           |   10 +
 .../bin/gov/noaa/pmel/text/package.html            |    7 +
 .../bin/gov/noaa/pmel/util/package.html            |    7 +
 .../nxplot/sgtgraphics/build.properties            |    4 +
 .../nxplot/sgtgraphics/src/META-INF/MANIFEST.MF    |   62 +
 .../nxplot/sgtgraphics/src/doc_stylesheet.css      |   30 +
 .../sgtgraphics/src/gov/noaa/pmel/eps/package.html |    7 +
 .../sgtgraphics/src/gov/noaa/pmel/io/package.html  |    7 +
 .../src/gov/noaa/pmel/sgt/AbstractPane.java        |  377 +++
 .../noaa/pmel/sgt/AnnotationCartesianRenderer.java |  467 +++
 .../src/gov/noaa/pmel/sgt/Attribute.java           |   77 +
 .../gov/noaa/pmel/sgt/AttributeChangeEvent.java    |   44 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Axis.java    |  734 +++++
 .../gov/noaa/pmel/sgt/AxisNotFoundException.java   |   28 +
 .../src/gov/noaa/pmel/sgt/AxisTransform.java       |  382 +++
 .../src/gov/noaa/pmel/sgt/CLIndexedColorMap.java   |  209 ++
 .../src/gov/noaa/pmel/sgt/CLTransformColorMap.java |  234 ++
 .../src/gov/noaa/pmel/sgt/CartesianGraph.java      | 1006 ++++++
 .../src/gov/noaa/pmel/sgt/CartesianRenderer.java   |  202 ++
 .../gov/noaa/pmel/sgt/ChildNotFoundException.java  |   28 +
 .../src/gov/noaa/pmel/sgt/ColorKey.java            |  744 +++++
 .../src/gov/noaa/pmel/sgt/ColorMap.java            |  137 +
 .../pmel/sgt/ContourLevelNotFoundException.java    |   28 +
 .../src/gov/noaa/pmel/sgt/ContourLevels.java       |  320 ++
 .../src/gov/noaa/pmel/sgt/ContourLevelsAccess.java |   27 +
 .../gov/noaa/pmel/sgt/ContourLineAttribute.java    |  627 ++++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/DataKey.java |   37 +
 .../noaa/pmel/sgt/DataNotAssignedException.java    |   28 +
 .../gov/noaa/pmel/sgt/DataNotFoundException.java   |   29 +
 .../noaa/pmel/sgt/DataNotSameShapeException.java   |   28 +
 .../src/gov/noaa/pmel/sgt/DayMonthAxis.java        |  115 +
 .../noaa/pmel/sgt/DefaultContourLineAttribute.java |  390 +++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Format.java  |  534 ++++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Graph.java   |  290 ++
 .../src/gov/noaa/pmel/sgt/GridAttribute.java       |  292 ++
 .../gov/noaa/pmel/sgt/GridCartesianRenderer.java   |  623 ++++
 .../src/gov/noaa/pmel/sgt/HourDayAxis.java         |  120 +
 .../src/gov/noaa/pmel/sgt/IndexedColor.java        |   41 +
 .../src/gov/noaa/pmel/sgt/IndexedColorMap.java     |  215 ++
 .../src/gov/noaa/pmel/sgt/InvalidMethodError.java  |   28 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/JPane.java   |  754 +++++
 .../src/gov/noaa/pmel/sgt/LabelDrawer.java         |  207 ++
 .../src/gov/noaa/pmel/sgt/LabelDrawer1.java        |  578 ++++
 .../src/gov/noaa/pmel/sgt/LabelDrawer2.java        |  580 ++++
 .../gov/noaa/pmel/sgt/LabelNotFoundException.java  |   28 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Layer.java   |  871 ++++++
 .../src/gov/noaa/pmel/sgt/LayerChild.java          |  103 +
 .../src/gov/noaa/pmel/sgt/LayerContainer.java      |   63 +
 .../src/gov/noaa/pmel/sgt/LayerControl.java        |   50 +
 .../gov/noaa/pmel/sgt/LayerNotFoundException.java  |   28 +
 .../src/gov/noaa/pmel/sgt/LayerStack.java          |   40 +
 .../src/gov/noaa/pmel/sgt/LineAttribute.java       |  475 +++
 .../gov/noaa/pmel/sgt/LineCartesianRenderer.java   |  362 +++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/LineKey.java |  748 +++++
 .../src/gov/noaa/pmel/sgt/LinearTransform.java     |  222 ++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/LogAxis.java |  422 +++
 .../src/gov/noaa/pmel/sgt/LogTransform.java        |  153 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Logo.java    |  420 +++
 .../src/gov/noaa/pmel/sgt/MapGraph.java            |   60 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/MapProj.java |   25 +
 .../noaa/pmel/sgt/MethodNotImplementedError.java   |   28 +
 .../src/gov/noaa/pmel/sgt/MinuteHourAxis.java      |  129 +
 .../src/gov/noaa/pmel/sgt/MonthYearAxis.java       |  112 +
 .../src/gov/noaa/pmel/sgt/Moveable.java            |   74 +
 .../gov/noaa/pmel/sgt/NegativeLogException.java    |   30 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Pane.java    |  500 +++
 .../src/gov/noaa/pmel/sgt/PaneBeanInfo.java        |   69 +
 .../src/gov/noaa/pmel/sgt/PaneIcon16.gif           |  Bin 0 -> 838 bytes
 .../src/gov/noaa/pmel/sgt/PaneIcon32.gif           |  Bin 0 -> 933 bytes
 .../gov/noaa/pmel/sgt/PaneNotFoundException.java   |   28 +
 .../src/gov/noaa/pmel/sgt/PaneProxy.java           |  913 ++++++
 .../src/gov/noaa/pmel/sgt/PlainAxis.java           |  331 ++
 .../src/gov/noaa/pmel/sgt/PlotMark.java            |  262 ++
 .../src/gov/noaa/pmel/sgt/PointAttribute.java      |  404 +++
 .../gov/noaa/pmel/sgt/PointCartesianRenderer.java  |  350 +++
 .../src/gov/noaa/pmel/sgt/PointCollectionKey.java  |  733 +++++
 .../src/gov/noaa/pmel/sgt/PolarGraph.java          |   53 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/README.txt   |    7 +
 .../src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt    |  158 +
 .../src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt    |   68 +
 .../src/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt    |  509 +++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/Ruler.java   |  748 +++++
 .../src/gov/noaa/pmel/sgt/SGException.java         |   28 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/SGLabel.java |  577 ++++
 .../src/gov/noaa/pmel/sgt/Selectable.java          |   66 +
 .../src/gov/noaa/pmel/sgt/SineTransform.java       |   83 +
 .../src/gov/noaa/pmel/sgt/SpaceAxis.java           |  414 +++
 .../src/gov/noaa/pmel/sgt/StackedLayout.java       |   75 +
 .../src/gov/noaa/pmel/sgt/StrokeDrawer.java        |   51 +
 .../src/gov/noaa/pmel/sgt/StrokeDrawer1.java       |   69 +
 .../src/gov/noaa/pmel/sgt/StrokeDrawer2.java       |   95 +
 .../gov/noaa/pmel/sgt/TableLookupTransform.java    |   81 +
 .../src/gov/noaa/pmel/sgt/TimeAxis.java            |  784 +++++
 .../src/gov/noaa/pmel/sgt/TimeAxisStyle.java       |  156 +
 .../src/gov/noaa/pmel/sgt/Transform.java           |  102 +
 .../src/gov/noaa/pmel/sgt/TransformAccess.java     |   26 +
 .../src/gov/noaa/pmel/sgt/TransformColor.java      |   36 +
 .../src/gov/noaa/pmel/sgt/TransformColorMap.java   |  213 ++
 .../src/gov/noaa/pmel/sgt/VectorAttribute.java     |  556 ++++
 .../gov/noaa/pmel/sgt/VectorCartesianRenderer.java |  458 +++
 .../src/gov/noaa/pmel/sgt/VectorKey.java           |  910 ++++++
 .../src/gov/noaa/pmel/sgt/YearDecadeAxis.java      |  111 +
 .../src/gov/noaa/pmel/sgt/beans/AxisHolder.java    |  972 ++++++
 .../gov/noaa/pmel/sgt/beans/AxisHolderDragBox.java |  439 +++
 .../pmel/sgt/beans/AxisHolderPropertyPanel.java    |  694 +++++
 .../src/gov/noaa/pmel/sgt/beans/BorderDialog.java  |  596 ++++
 .../src/gov/noaa/pmel/sgt/beans/DataGroup.java     |  431 +++
 .../gov/noaa/pmel/sgt/beans/DataGroupDragBox.java  |  161 +
 .../gov/noaa/pmel/sgt/beans/DataGroupLayer.java    |  782 +++++
 .../pmel/sgt/beans/DataGroupPropertyPanel.java     |  204 ++
 .../src/gov/noaa/pmel/sgt/beans/DataHolder.java    |   98 +
 .../src/gov/noaa/pmel/sgt/beans/DataModel.java     |  134 +
 .../gov/noaa/pmel/sgt/beans/DataModelBeanInfo.java |   45 +
 .../gov/noaa/pmel/sgt/beans/DataModelEditor.java   |   48 +
 .../gov/noaa/pmel/sgt/beans/DataModelIcon16.gif    |  Bin 0 -> 641 bytes
 .../gov/noaa/pmel/sgt/beans/DataModelIcon32.gif    |  Bin 0 -> 916 bytes
 .../sgt/beans/DataTargetMismatchException.java     |   33 +
 .../gov/noaa/pmel/sgt/beans/DesignListener.java    |   24 +
 .../src/gov/noaa/pmel/sgt/beans/DesignPanel.java   |  541 ++++
 .../src/gov/noaa/pmel/sgt/beans/DragBox.java       |  195 ++
 .../src/gov/noaa/pmel/sgt/beans/Label.java         |  370 +++
 .../src/gov/noaa/pmel/sgt/beans/LabelDragBox.java  |  103 +
 .../noaa/pmel/sgt/beans/LabelPropertyPanel.java    |  278 ++
 .../src/gov/noaa/pmel/sgt/beans/Legend.java        |  606 ++++
 .../src/gov/noaa/pmel/sgt/beans/LegendDragBox.java |  100 +
 .../noaa/pmel/sgt/beans/LegendPropertyPanel.java   |  337 ++
 .../src/gov/noaa/pmel/sgt/beans/Margin.java        |  136 +
 .../src/gov/noaa/pmel/sgt/beans/Page.java          |  457 +++
 .../src/gov/noaa/pmel/sgt/beans/PageBeanInfo.java  |   74 +
 .../src/gov/noaa/pmel/sgt/beans/PageIcon16.gif     |  Bin 0 -> 568 bytes
 .../src/gov/noaa/pmel/sgt/beans/PageIcon32.gif     |  Bin 0 -> 551 bytes
 .../src/gov/noaa/pmel/sgt/beans/Panel.java         |  605 ++++
 .../src/gov/noaa/pmel/sgt/beans/PanelHolder.java   |  535 ++++
 .../noaa/pmel/sgt/beans/PanelHolderDragBox.java    |  215 ++
 .../pmel/sgt/beans/PanelHolderPropertyPanel.java   |  185 ++
 .../src/gov/noaa/pmel/sgt/beans/PanelModel.java    |  602 ++++
 .../noaa/pmel/sgt/beans/PanelModelBeanInfo.java    |   98 +
 .../noaa/pmel/sgt/beans/PanelModelCustomizer.java  |  679 ++++
 .../gov/noaa/pmel/sgt/beans/PanelModelEditor.java  |  301 ++
 .../gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif   |  Bin 0 -> 172 bytes
 .../gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif   |  Bin 0 -> 301 bytes
 .../pmel/sgt/beans/PanelModelPropertyPanel.java    |  250 ++
 .../src/gov/noaa/pmel/sgt/beans/PropertyPanel.java |  439 +++
 .../noaa/pmel/sgt/beans/images/AlignBottom24.gif   |  Bin 0 -> 271 bytes
 .../noaa/pmel/sgt/beans/images/AlignCenter24.gif   |  Bin 0 -> 275 bytes
 .../sgt/beans/images/AlignJustifyHorizontal24.gif  |  Bin 0 -> 280 bytes
 .../sgt/beans/images/AlignJustifyVertical24.gif    |  Bin 0 -> 299 bytes
 .../gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif |  Bin 0 -> 267 bytes
 .../noaa/pmel/sgt/beans/images/AlignRight24.gif    |  Bin 0 -> 269 bytes
 .../gov/noaa/pmel/sgt/beans/images/AlignTop24.gif  |  Bin 0 -> 275 bytes
 .../noaa/pmel/sgt/beans/images/DataModelSimple.png |  Bin 0 -> 13695 bytes
 .../src/gov/noaa/pmel/sgt/beans/images/Edit24.gif  |  Bin 0 -> 1244 bytes
 .../src/gov/noaa/pmel/sgt/beans/images/New24.gif   |  Bin 0 -> 778 bytes
 .../noaa/pmel/sgt/beans/images/NewDataGroup24.gif  |  Bin 0 -> 160 bytes
 .../gov/noaa/pmel/sgt/beans/images/NewLabel24.gif  |  Bin 0 -> 317 bytes
 .../gov/noaa/pmel/sgt/beans/images/NewLegend24.gif |  Bin 0 -> 341 bytes
 .../src/gov/noaa/pmel/sgt/beans/images/Open24.gif  |  Bin 0 -> 462 bytes
 .../pmel/sgt/beans/images/PanelModelSimple.png     |  Bin 0 -> 13703 bytes
 .../noaa/pmel/sgt/beans/images/Preferences24.gif   |  Bin 0 -> 240 bytes
 .../gov/noaa/pmel/sgt/beans/images/Remove24.gif    |  Bin 0 -> 287 bytes
 .../noaa/pmel/sgt/beans/images/RunTimeSimple.png   |  Bin 0 -> 13682 bytes
 .../src/gov/noaa/pmel/sgt/beans/images/Save24.gif  |  Bin 0 -> 266 bytes
 .../gov/noaa/pmel/sgt/beans/images/SaveAs24.gif    |  Bin 0 -> 348 bytes
 .../src/gov/noaa/pmel/sgt/beans/package.html       |   20 +
 .../src/gov/noaa/pmel/sgt/contour/Contour.java     |  913 ++++++
 .../gov/noaa/pmel/sgt/contour/ContourLabel.java    |   55 +
 .../src/gov/noaa/pmel/sgt/contour/ContourLine.java |  434 +++
 .../src/gov/noaa/pmel/sgt/contour/GridFlag.java    |  122 +
 .../noaa/pmel/sgt/contour/PolygonGenerator.java    |    8 +
 .../gov/noaa/pmel/sgt/contour/PolygonRenderer.java |    8 +
 .../src/gov/noaa/pmel/sgt/contour/Sides.java       |   92 +
 .../src/gov/noaa/pmel/sgt/contour/Tree.java        |    8 +
 .../gov/noaa/pmel/sgt/contour/TreeEnumerator.java  |   14 +
 .../gov/noaa/pmel/sgt/contour/TreeGenerator.java   |    8 +
 .../src/gov/noaa/pmel/sgt/contour/package.html     |   14 +
 .../src/gov/noaa/pmel/sgt/demo/AddDataFrame.java   |  927 ++++++
 .../src/gov/noaa/pmel/sgt/demo/BeanDemo.java       |   62 +
 .../src/gov/noaa/pmel/sgt/demo/BeanDemoFrame.java  |  368 +++
 .../gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml  |  695 +++++
 .../src/gov/noaa/pmel/sgt/demo/JDesktopDemo.java   |  300 ++
 .../src/gov/noaa/pmel/sgt/demo/JGridDemo.java      |  377 +++
 .../src/gov/noaa/pmel/sgt/demo/JLayoutDemo.java    |  507 +++
 .../src/gov/noaa/pmel/sgt/demo/JLogLogDemo.java    |  224 ++
 .../src/gov/noaa/pmel/sgt/demo/JPointDemo.java     |  244 ++
 .../src/gov/noaa/pmel/sgt/demo/JProfileDemo.java   |  111 +
 .../src/gov/noaa/pmel/sgt/demo/JRealTimeDemo.java  |  294 ++
 .../gov/noaa/pmel/sgt/demo/JTimeSeriesDemo.java    |  205 ++
 .../src/gov/noaa/pmel/sgt/demo/JVectorDemo.java    |  268 ++
 .../gov/noaa/pmel/sgt/demo/PseudoRealTimeData.java |  239 ++
 .../sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAO.dat |   59 +
 .../src/gov/noaa/pmel/sgt/demo/TAOMap.java         |  680 ++++
 .../src/gov/noaa/pmel/sgt/demo/TRITON.dat          |   13 +
 .../src/gov/noaa/pmel/sgt/demo/TestData.java       |  586 ++++
 .../src/gov/noaa/pmel/sgt/demo/coarserezcoast.bin  |  Bin 0 -> 82034 bytes
 .../src/gov/noaa/pmel/sgt/demo/finerezcoast.bin    |  Bin 0 -> 777132 bytes
 .../src/gov/noaa/pmel/sgt/demo/ncBrowse48.gif      |  Bin 0 -> 2130 bytes
 .../src/gov/noaa/pmel/sgt/demo/ncBrowse96.gif      |  Bin 0 -> 4803 bytes
 .../src/gov/noaa/pmel/sgt/demo/package.html        |   17 +
 .../src/gov/noaa/pmel/sgt/demo/query.gif           |  Bin 0 -> 139 bytes
 .../src/gov/noaa/pmel/sgt/dm/Annotation.java       |  402 +++
 .../src/gov/noaa/pmel/sgt/dm/Annote.java           |  708 +++++
 .../src/gov/noaa/pmel/sgt/dm/Cartesian.java        |   27 +
 .../src/gov/noaa/pmel/sgt/dm/Collection.java       |  149 +
 .../src/gov/noaa/pmel/sgt/dm/CoordinateSystem.java |   25 +
 .../src/gov/noaa/pmel/sgt/dm/Geographic.java       |   27 +
 .../src/gov/noaa/pmel/sgt/dm/PointCollection.java  |  138 +
 .../src/gov/noaa/pmel/sgt/dm/Polar.java            |   28 +
 .../src/gov/noaa/pmel/sgt/dm/SGT3DGrid.java        |   74 +
 .../src/gov/noaa/pmel/sgt/dm/SGT3DVector.java      |  132 +
 .../src/gov/noaa/pmel/sgt/dm/SGTData.java          |  134 +
 .../src/gov/noaa/pmel/sgt/dm/SGTFull3DVector.java  |  219 ++
 .../src/gov/noaa/pmel/sgt/dm/SGTGrid.java          |  128 +
 .../src/gov/noaa/pmel/sgt/dm/SGTImage.java         |   62 +
 .../src/gov/noaa/pmel/sgt/dm/SGTLine.java          |   67 +
 .../src/gov/noaa/pmel/sgt/dm/SGTMetaData.java      |  155 +
 .../src/gov/noaa/pmel/sgt/dm/SGTPoint.java         |   68 +
 .../src/gov/noaa/pmel/sgt/dm/SGTTuple.java         |   41 +
 .../src/gov/noaa/pmel/sgt/dm/SGTVector.java        |  185 ++
 .../src/gov/noaa/pmel/sgt/dm/SimpleGrid.java       |  488 +++
 .../src/gov/noaa/pmel/sgt/dm/SimpleLine.java       |  377 +++
 .../src/gov/noaa/pmel/sgt/dm/SimplePoint.java      |  313 ++
 .../src/gov/noaa/pmel/sgt/dm/SimpleTuple.java      |  370 +++
 .../src/gov/noaa/pmel/sgt/dm/ThreeDGrid.java       |  584 ++++
 .../src/gov/noaa/pmel/sgt/dm/package.html          |   14 +
 .../src/gov/noaa/pmel/sgt/overview.html            |   46 +
 .../sgtgraphics/src/gov/noaa/pmel/sgt/package.html |   43 +
 .../gov/noaa/pmel/sgt/plot/DragNDropManager.java   |   19 +
 .../src/gov/noaa/pmel/sgt/plot/JPlotPane.java      |   59 +
 .../src/gov/noaa/pmel/sgt/plot/Notes.txt           |   51 +
 .../src/gov/noaa/pmel/sgt/plot/PlotLayer.java      |   34 +
 .../src/gov/noaa/pmel/sgt/plot/PlotLayerHints.java |  287 ++
 .../gov/noaa/pmel/sgt/plot/PlotLayerManager.java   |   57 +
 .../src/gov/noaa/pmel/sgt/plot/PlotPaneMode.java   |   43 +
 .../src/gov/noaa/pmel/sgt/plot/PrintManager.java   |   19 +
 .../src/gov/noaa/pmel/sgt/plot/package.html        |   23 +
 .../src/gov/noaa/pmel/sgt/plotmarkcodes.gif        |  Bin 0 -> 14530 bytes
 .../gov/noaa/pmel/sgt/swing/ColorSwatchIcon.java   |  142 +
 .../src/gov/noaa/pmel/sgt/swing/Draggable.java     |   43 +
 .../src/gov/noaa/pmel/sgt/swing/JClassTree.java    |  619 ++++
 .../gov/noaa/pmel/sgt/swing/JGraphicLayout.java    | 1131 +++++++
 .../noaa/pmel/sgt/swing/JLineProfileLayout.java    |  884 ++++++
 .../src/gov/noaa/pmel/sgt/swing/JPlotLayout.java   | 2293 ++++++++++++++
 .../src/gov/noaa/pmel/sgt/swing/PlotMarkIcon.java  |  145 +
 .../src/gov/noaa/pmel/sgt/swing/UserIcon.java      |  354 +++
 .../src/gov/noaa/pmel/sgt/swing/ValueIcon.java     |  373 +++
 .../gov/noaa/pmel/sgt/swing/ValueIconFormat.java   |   80 +
 .../src/gov/noaa/pmel/sgt/swing/package.html       |   14 +
 .../src/gov/noaa/pmel/sgt/swing/plotmarkcodes.png  |  Bin 0 -> 98569 bytes
 .../noaa/pmel/sgt/swing/prop/ArrayEditDialog.java  |  338 ++
 .../gov/noaa/pmel/sgt/swing/prop/ColorDialog.java  |  132 +
 .../noaa/pmel/sgt/swing/prop/ColorEntryPanel.java  |  146 +
 .../pmel/sgt/swing/prop/ContourLevelsDialog.java   |  479 +++
 .../sgt/swing/prop/ContourLineAttributeDialog.java |  923 ++++++
 .../prop/DefaultContourLineAttributeDialog.java    |  655 ++++
 .../gov/noaa/pmel/sgt/swing/prop/FontDialog.java   |  283 ++
 .../noaa/pmel/sgt/swing/prop/GeoDateDialog.java    | 1243 ++++++++
 .../pmel/sgt/swing/prop/GridAttributeDialog.java   |  885 ++++++
 .../pmel/sgt/swing/prop/GridBagConstraints.java    |   57 +
 .../pmel/sgt/swing/prop/LineAttributeDialog.java   |  587 ++++
 .../gov/noaa/pmel/sgt/swing/prop/LogoDialog.java   |  374 +++
 .../noaa/pmel/sgt/swing/prop/NewLevelsDialog.java  |  377 +++
 .../noaa/pmel/sgt/swing/prop/PlotMarkDialog.java   |  215 ++
 .../pmel/sgt/swing/prop/PointAttributeDialog.java  |  475 +++
 .../gov/noaa/pmel/sgt/swing/prop/RulerDialog.java  |  726 +++++
 .../noaa/pmel/sgt/swing/prop/SGLabelDialog.java    |  525 ++++
 .../noaa/pmel/sgt/swing/prop/SpaceAxisDialog.java  |  750 +++++
 .../noaa/pmel/sgt/swing/prop/TimeAxisDialog.java   |  768 +++++
 .../pmel/sgt/swing/prop/VectorAttributeDialog.java |  687 +++++
 .../src/gov/noaa/pmel/sgt/swing/prop/package.html  |   22 +
 .../src/gov/noaa/pmel/sgt/swing/sgt_logo.png       |  Bin 0 -> 4098 bytes
 .../src/gov/noaa/pmel/space/package.html           |    6 +
 .../src/gov/noaa/pmel/swing/JSlider2.java          |  555 ++++
 .../src/gov/noaa/pmel/swing/JSlider2Double.java    |  580 ++++
 .../noaa/pmel/swing/JSystemPropertiesDialog.java   |  205 ++
 .../src/gov/noaa/pmel/swing/MRJUtil.java           |   44 +
 .../src/gov/noaa/pmel/swing/ThreeDotsButton.java   |   34 +
 .../src/gov/noaa/pmel/swing/ThreeDotsIcon.java     |   79 +
 .../gov/noaa/pmel/swing/beans/SliderHandle.java    |  145 +
 .../src/gov/noaa/pmel/swing/package.html           |   10 +
 .../src/gov/noaa/pmel/text/package.html            |    7 +
 .../src/gov/noaa/pmel/util/ColorMap.java           |   85 +
 .../src/gov/noaa/pmel/util/ColorTransform.java     |   75 +
 .../sgtgraphics/src/gov/noaa/pmel/util/Debug.java  |   23 +
 .../src/gov/noaa/pmel/util/Dimension2D.java        |   87 +
 .../sgtgraphics/src/gov/noaa/pmel/util/Domain.java |  221 ++
 .../src/gov/noaa/pmel/util/EPICSystem.java         |   48 +
 .../noaa/pmel/util/ExponentialTransformDown.java   |  185 ++
 .../gov/noaa/pmel/util/ExponentialTransformUp.java |  178 ++
 .../src/gov/noaa/pmel/util/GeoDate.java            |  777 +++++
 .../src/gov/noaa/pmel/util/GeoDateArray.java       |  171 ++
 .../src/gov/noaa/pmel/util/GeographicValue.java    |  152 +
 .../src/gov/noaa/pmel/util/IllegalTimeValue.java   |   29 +
 .../src/gov/noaa/pmel/util/IndexedColorMap.java    |   65 +
 .../src/gov/noaa/pmel/util/Latitude.java           |   28 +
 .../src/gov/noaa/pmel/util/LinearTransform.java    |  168 +
 .../src/gov/noaa/pmel/util/Longitude.java          |   29 +
 .../src/gov/noaa/pmel/util/Point2D.java            |  139 +
 .../sgtgraphics/src/gov/noaa/pmel/util/Range.java  |   50 +
 .../src/gov/noaa/pmel/util/Range2D.java            |  107 +
 .../src/gov/noaa/pmel/util/Rectangle2D.java        |  279 ++
 .../src/gov/noaa/pmel/util/SimpleFileFilter.java   |   55 +
 .../src/gov/noaa/pmel/util/SoTDomain.java          |  183 ++
 .../src/gov/noaa/pmel/util/SoTPoint.java           |  158 +
 .../src/gov/noaa/pmel/util/SoTRange.java           | 1150 +++++++
 .../src/gov/noaa/pmel/util/SoTValue.java           |  544 ++++
 .../src/gov/noaa/pmel/util/TimePoint.java          |   62 +
 .../src/gov/noaa/pmel/util/TimeRange.java          |  106 +
 .../sgtgraphics/src/gov/noaa/pmel/util/Units.java  |  786 +++++
 .../src/gov/noaa/pmel/util/package.html            |    7 +
 .../nxplot/sharedscientific/.classpath             |    7 +
 .../applications/nxplot/sharedscientific/.project  |   28 +
 .../.settings/org.eclipse.jdt.core.prefs           |    7 +
 .../nxplot/sharedscientific/META-INF/MANIFEST.MF   |    8 +
 .../nxplot/sharedscientific/bin/font/Vera.ttf      |  Bin 0 -> 65932 bytes
 .../nxplot/sharedscientific/bin/shared/log4j.xml   |   18 +
 .../sharedscientific/bin/shared/project.properties |    3 +
 .../nxplot/sharedscientific/build.properties       |    4 +
 .../nxplot/sharedscientific/src/font/Vera.ttf      |  Bin 0 -> 65932 bytes
 .../sharedscientific/src/font/package-info.java    |   22 +
 .../sharedscientific/src/lib/package-info.java     |   22 +
 .../sharedscientific/src/shared/Constants.java     |   65 +
 .../src/shared/array/AbstractArray.java            |  332 ++
 .../src/shared/array/AbstractComplexArray.java     |  585 ++++
 .../src/shared/array/AbstractRealArray.java        |  686 +++++
 .../sharedscientific/src/shared/array/Array.java   |  279 ++
 .../src/shared/array/ArrayBase.java                |  396 +++
 .../src/shared/array/ComplexArray.java             |  166 +
 .../src/shared/array/IntegerArray.java             |  381 +++
 .../sharedscientific/src/shared/array/Matrix.java  |   74 +
 .../src/shared/array/ObjectArray.java              |  242 ++
 .../src/shared/array/ProtoArray.java               |  437 +++
 .../src/shared/array/RealArray.java                |  294 ++
 .../src/shared/array/jni/NativeArrayKernel.java    |  122 +
 .../src/shared/array/jni/package-info.java         |   23 +
 .../src/shared/array/kernel/ArrayIOKernel.java     |   53 +
 .../src/shared/array/kernel/ArrayKernel.java       |  664 ++++
 .../src/shared/array/kernel/DimensionOps.java      |  690 +++++
 .../src/shared/array/kernel/ElementOps.java        | 1038 +++++++
 .../src/shared/array/kernel/IndexOps.java          |   85 +
 .../src/shared/array/kernel/JavaArrayKernel.java   |  170 +
 .../src/shared/array/kernel/LinearAlgebraOps.java  | 1180 +++++++
 .../src/shared/array/kernel/MappingOps.java        |  332 ++
 .../src/shared/array/kernel/MatlabIO.java          |  376 +++
 .../src/shared/array/kernel/MatlabIOKernel.java    |  796 +++++
 .../src/shared/array/kernel/MatrixOps.java         |  120 +
 .../shared/array/kernel/ModalArrayIOKernel.java    |   59 +
 .../src/shared/array/kernel/ModalArrayKernel.java  |  200 ++
 .../src/shared/array/kernel/PermutationEntry.java  |  129 +
 .../src/shared/array/kernel/SparseOps.java         |  820 +++++
 .../src/shared/array/kernel/package-info.java      |   22 +
 .../src/shared/array/package-info.java             |   22 +
 .../shared/array/sparse/IntegerSparseArray.java    |  168 +
 .../src/shared/array/sparse/ObjectSparseArray.java |  165 +
 .../src/shared/array/sparse/ProtoSparseArray.java  |  555 ++++
 .../src/shared/array/sparse/RealSparseArray.java   |  171 ++
 .../src/shared/array/sparse/SparseArrayState.java  |   77 +
 .../src/shared/array/sparse/package-info.java      |   22 +
 .../src/shared/event/EnumStatus.java               |   37 +
 .../src/shared/event/EnumType.java                 |   32 +
 .../sharedscientific/src/shared/event/Event.java   |   43 +
 .../sharedscientific/src/shared/event/Handler.java |   33 +
 .../src/shared/event/Processor.java                |  149 +
 .../sharedscientific/src/shared/event/Source.java  |   48 +
 .../src/shared/event/SourceLocal.java              |   33 +
 .../src/shared/event/SourceRemote.java             |   33 +
 .../src/shared/event/StateProcessor.java           |   53 +
 .../src/shared/event/StateTable.java               |  305 ++
 .../src/shared/event/Transitions.java              |   68 +
 .../src/shared/event/XMLEvent.java                 |   53 +
 .../src/shared/event/package-info.java             |   22 +
 .../sharedscientific/src/shared/fft/Cacheable.java |   26 +
 .../src/shared/fft/ConvolutionCache.java           |  233 ++
 .../sharedscientific/src/shared/fft/FFTCache.java  |  137 +
 .../sharedscientific/src/shared/fft/FFTOps.java    |  260 ++
 .../src/shared/fft/FFTService.java                 |   95 +
 .../src/shared/fft/JavaFFTService.java             |  191 ++
 .../src/shared/fft/ModalFFTService.java            |   93 +
 .../src/shared/fft/package-info.java               |   22 +
 .../src/shared/image/IntegralHistogram.java        |  124 +
 .../src/shared/image/IntegralImage.java            |   97 +
 .../src/shared/image/IntensityImages.java          |  262 ++
 .../shared/image/filter/DerivativeOfGaussian.java  |  141 +
 .../src/shared/image/filter/Filters.java           |  123 +
 .../src/shared/image/filter/Gabor.java             |  120 +
 .../src/shared/image/filter/GaborCircular.java     |  104 +
 .../shared/image/filter/LaplacianOfGaussian.java   |   95 +
 .../src/shared/image/filter/Mean.java              |   82 +
 .../src/shared/image/filter/package-info.java      |   22 +
 .../src/shared/image/jni/NativeImageKernel.java    |   47 +
 .../src/shared/image/jni/package-info.java         |   23 +
 .../src/shared/image/kernel/ImageKernel.java       |   70 +
 .../src/shared/image/kernel/ImageOps.java          |  206 ++
 .../src/shared/image/kernel/JavaImageKernel.java   |   45 +
 .../src/shared/image/kernel/ModalImageKernel.java  |   83 +
 .../src/shared/image/kernel/package-info.java      |   22 +
 .../src/shared/image/package-info.java             |   22 +
 .../nxplot/sharedscientific/src/shared/log4j.xml   |   18 +
 .../src/shared/metaclass/FileSystemRegistry.java   |  108 +
 .../src/shared/metaclass/JarRegistry.java          |  205 ++
 .../src/shared/metaclass/Library.java              |   58 +
 .../src/shared/metaclass/Policy.java               |   43 +
 .../src/shared/metaclass/RegistryClassLoader.java  |  575 ++++
 .../src/shared/metaclass/ResourceRegistry.java     |   60 +
 .../src/shared/metaclass/package-info.java         |   22 +
 .../sharedscientific/src/shared/package-info.java  |   22 +
 .../src/shared/parallel/Calculator.java            |   46 +
 .../sharedscientific/src/shared/parallel/Edge.java |   48 +
 .../src/shared/parallel/Engine.java                |  639 ++++
 .../src/shared/parallel/Handle.java                |   38 +
 .../src/shared/parallel/LimitedMemoryPolicy.java   |  158 +
 .../src/shared/parallel/Traversable.java           |   68 +
 .../src/shared/parallel/TraversalPolicy.java       |   42 +
 .../src/shared/parallel/package-info.java          |   22 +
 .../sharedscientific/src/shared/project.properties |    3 +
 .../src/shared/stat/ml/AbstractGMModel.java        |  138 +
 .../src/shared/stat/ml/GMComponents.java           |  104 +
 .../src/shared/stat/ml/GMModel.java                |  121 +
 .../src/shared/stat/ml/KMeans.java                 |  197 ++
 .../src/shared/stat/ml/package-info.java           |   22 +
 .../src/shared/stat/package-info.java              |   22 +
 .../src/shared/stat/plot/DataStyle.java            |  215 ++
 .../src/shared/stat/plot/ErrorDistribution.java    |  183 ++
 .../src/shared/stat/plot/GnuplotContext.java       |  600 ++++
 .../src/shared/stat/plot/Histogram.java            |  151 +
 .../src/shared/stat/plot/Plot.java                 |  176 ++
 .../src/shared/stat/plot/PlotBase.java             |   78 +
 .../src/shared/stat/plot/PlotContext.java          |   89 +
 .../src/shared/stat/plot/Plottable.java            |   72 +
 .../src/shared/stat/plot/PrecisionRecall.java      |   99 +
 .../shared/stat/plot/ProbabilityDistribution.java  |  158 +
 .../sharedscientific/src/shared/stat/plot/ROC.java |  128 +
 .../src/shared/stat/plot/Scatter.java              |   84 +
 .../src/shared/stat/plot/package-info.java         |   22 +
 .../src/shared/stat/util/Combinatorics.java        |  209 ++
 .../src/shared/stat/util/package-info.java         |   22 +
 .../src/shared/util/Arithmetic.java                |  491 +++
 .../sharedscientific/src/shared/util/Arrays.java   |  772 +++++
 .../sharedscientific/src/shared/util/Control.java  | 1053 +++++++
 .../src/shared/util/CoreThread.java                |   80 +
 .../src/shared/util/DynamicArray.java              |   84 +
 .../src/shared/util/DynamicDoubleArray.java        |  158 +
 .../src/shared/util/DynamicIntArray.java           |  158 +
 .../src/shared/util/DynamicLongArray.java          |  158 +
 .../src/shared/util/DynamicObjectArray.java        |  164 +
 .../src/shared/util/Finalizable.java               |   37 +
 .../src/shared/util/LoadableResources.java         |   90 +
 .../sharedscientific/src/shared/util/Loader.java   |  325 ++
 .../src/shared/util/ReferenceReaper.java           |  207 ++
 .../src/shared/util/RequestFuture.java             |   53 +
 .../sharedscientific/src/shared/util/Service.java  |   26 +
 .../sharedscientific/src/shared/util/Services.java |   98 +
 .../src/shared/util/TemporaryFiles.java            |  104 +
 .../src/shared/util/package-info.java              |   22 +
 contrib/bindings/Makefile.am                       |   36 +
 contrib/bindings/README                            |    7 +
 .../java/org/nexusformat/utils/NXutil.java         |  771 +++++
 contrib/bindings/python/Makefile.am                |   41 +
 dir_syntax.cmake                                   |    5 +
 doc/CMakeLists.txt                                 |   37 +
 doc/Makefile.am                                    |   15 +
 doc/README                                         |    9 +
 doc/README.doc                                     |   10 +
 doc/api/CMakeLists.txt                             |   30 +
 doc/api/Makefile.am                                |   11 +
 doc/api/NeXusIntern.html                           |  497 +++
 doc/api/NeXusIntern.pdf                            |  Bin 0 -> 91918 bytes
 doc/api/NeXusIntern.radi                           |  509 +++
 doc/api/NeXusIntern.tex                            |  618 ++++
 doc/api/README                                     |    7 +
 doc/api/napi.tex                                   | 1850 +++++++++++
 doc/doxygen/CMakeLists.txt                         |   94 +
 doc/doxygen/Doxyfile_c                             | 1727 +++++++++++
 doc/doxygen/Doxyfile_c_brief                       | 1727 +++++++++++
 doc/doxygen/Doxyfile_cpp                           | 1532 +++++++++
 doc/doxygen/Doxyfile_f77                           | 1535 +++++++++
 doc/doxygen/Doxyfile_f90                           | 1535 +++++++++
 doc/doxygen/Doxyfile_java                          | 1532 +++++++++
 doc/doxygen/Doxyfile_nxvalidate                    | 1532 +++++++++
 doc/doxygen/Doxyfile_python                        | 1522 +++++++++
 doc/doxygen/Makefile.am                            |   77 +
 doc/doxygen/preamble.h                             |   91 +
 doc/howto/README                                   |    3 +
 doc/nxdict/CMakeLists.txt                          |   30 +
 doc/nxdict/Makefile.am                             |   11 +
 doc/nxdict/NXdict.tex                              |  351 +++
 doc/tech_ref/CMakeLists.txt                        |   61 +
 doc/tech_ref/Makefile.am                           |   26 +
 doc/tech_ref/NeXus_definitions.docbook             |   87 +
 doc/tech_ref/base_classes.docbook                  | 1670 ++++++++++
 doc/tech_ref/methods.docbook                       |   47 +
 doc/tech_ref/monoref.docbook                       |  530 ++++
 doc/tech_ref/monotas.docbook                       |  240 ++
 doc/tech_ref/terminology.docbook                   |   92 +
 doc/tech_ref/tofdgs.docbook                        |  239 ++
 doc/tech_ref/tofnpd.docbook                        |  141 +
 doc/tech_ref/tofnpd.gif                            |  Bin 0 -> 8926 bytes
 doc/tech_ref/tofnpd.jpg                            |  Bin 0 -> 5596 bytes
 doc/tech_ref/tofnref.docbook                       |  356 +++
 doc/tutorial/README                                |    3 +
 examples/CMakeLists.txt                            |   31 +
 examples/Makefile.am                               |   11 +
 examples/README                                    |    8 +
 examples/README.examples                           |   14 +
 file.MinGW                                         |   22 +
 gnu_license.txt                                    |  515 ++++
 include/CMakeLists.txt                             |   33 +
 include/Makefile.am                                |   11 +
 include/napi.h                                     |  964 ++++++
 include/napi4.h                                    |   60 +
 include/napi5.h                                    |   54 +
 include/napiconfig.h                               |   28 +
 include/napiu.h                                    |   72 +
 include/nxconfig_h_cmake.in                        |   37 +
 include/nxconfig_vms.h                             |  201 ++
 include/nxxml.h                                    |   78 +
 install_nexus_dep_rpm                              |   11 +
 macosx_install_kit/Makefile.am                     |   37 +
 macosx_install_kit/ReadMe.txt                      |   11 +
 .../Resources/English.lproj/Conclusion.txt         |    9 +
 .../Resources/English.lproj/Description.plist      |   12 +
 .../Resources/English.lproj/License.txt            |  526 ++++
 .../Resources/English.lproj/ReadMe.txt             |  379 +++
 .../Resources/English.lproj/Welcome.txt            |   10 +
 .../Resources/English.lproj/background.jpg         |  Bin 0 -> 17511 bytes
 macosx_install_kit/Resources/postflight            |    8 +
 macosx_install_kit/Resources/preflight             |   13 +
 macosx_install_kit/bin/dmgpack.sh                  |   65 +
 macosx_install_kit/bin/makepkg.sh                  |  272 ++
 macosx_install_kit/build_mac_kit.sh                |   47 +
 macosx_install_kit/pkg.config.in                   |   15 +
 make_mingw_links                                   |   58 +
 nexus_spec.in                                      |  222 ++
 nsis_install.nsh                                   |    9 +
 nsis_uninstall.nsh                                 |    9 +
 scripts/Makefile.am                                |   10 +
 scripts/nexus-config.in                            |   35 +
 scripts/nexus-cpp.pc.in                            |   14 +
 scripts/nexus.pc.in                                |   14 +
 scripts/nxbuild.in                                 |  109 +
 src/CMakeLists.txt                                 |  139 +
 src/Makefile.am                                    |   98 +
 src/SConscript                                     |   71 +
 src/make_vms.com                                   |   20 +
 src/makefile_f90                                   |   73 +
 src/makefile_hdf4                                  |   71 +
 src/makefile_hdf45                                 |   87 +
 src/makefile_hdf5                                  |   72 +
 src/makefile_options                               |   67 +
 src/napi.c                                         | 2131 +++++++++++++
 src/napi4.c                                        | 1983 ++++++++++++
 src/napi5.c                                        | 2383 ++++++++++++++
 src/napi_exports.c                                 |   19 +
 src/napi_exports.h                                 |  263 ++
 src/napi_exports2.c                                |   20 +
 src/napiu.c                                        |  159 +
 src/nexus_symbols.txt                              |   83 +
 src/nexus_symbols_win.txt                          |   44 +
 src/nx_stptok.h                                    |    6 +
 src/nxdataset.c                                    |  313 ++
 src/nxdataset.h                                    |   74 +
 src/nxdict/Makefile.nxdict                         |   21 +
 src/nxdict/README.nxdict                           |   37 +
 src/nxdict/defines.h                               |   18 +
 src/nxdict/dict.c                                  |   81 +
 src/nxdict/dynstring.c                             |  247 ++
 src/nxdict/dynstring.h                             |   89 +
 src/nxdict/lld.c                                   |  685 +++++
 src/nxdict/lld.h                                   |  137 +
 src/nxdict/nxdict.c                                | 2014 ++++++++++++
 src/nxdict/nxdict.h                                |   94 +
 src/nxdict/nxdict.tex                              | 3053 ++++++++++++++++++
 src/nxdict/nxdict.w                                | 2537 +++++++++++++++
 src/nxdict/nxdictus.tex                            |  378 +++
 src/nxdict/stringdict.c                            |  272 ++
 src/nxdict/stringdict.h                            |   38 +
 src/nxdict/stringdict.w                            |   70 +
 src/nxdict/test.dict                               |   19 +
 src/nxio.c                                         |  749 +++++
 src/nxio.h                                         |   50 +
 src/nxstack.c                                      |  145 +
 src/nxstack.h                                      |   52 +
 src/nxxml.c                                        | 2001 ++++++++++++
 src/stptok.c                                       |   66 +
 svn2cl_nexus_authors.xml                           |   69 +
 test/CMakeLists.txt                                |   37 +
 test/Makefile.am                                   |  262 ++
 test/NXtest.f90                                    |  209 ++
 test/README                                        |   38 +
 test/README.tests                                  |    8 +
 test/SConscript                                    |   68 +
 test/atlocal.in                                    |   86 +
 test/data/dmc01.h5                                 |  Bin 0 -> 29488 bytes
 test/data/dmc01.hdf                                |  Bin 0 -> 965084 bytes
 test/data/dmc01.xml                                |  437 +++
 test/data/dmc02.h5                                 |  Bin 0 -> 29488 bytes
 test/data/dmc02.hdf                                |  Bin 0 -> 673566 bytes
 test/data/dmc02.xml                                |  245 ++
 test/dummy.c                                       |    4 +
 test/leak_test1.c                                  |   29 +
 test/leak_test2.cxx                                |   62 +
 test/leak_test3.cxx                                |   72 +
 test/napi_test.c                                   |  693 +++++
 test/napi_test_cpp.cxx                             |  636 ++++
 test/napif4_test.f                                 |  326 ++
 test/napif5_test.f                                 |  327 ++
 test/napif_test.f                                  |  327 ++
 test/nxbrowse.txt                                  |    2 +
 test/run_leak_test                                 |   13 +
 test/run_test.c                                    |    4 +
 test/setup_test                                    |    7 +
 test/skip_test.c                                   |    4 +
 test/test_nxunlimited.c                            |   78 +
 test/testsuite.at                                  | 2161 +++++++++++++
 test/testsuitetojunit.py                           |  188 ++
 third_party/CMakeLists.txt                         |   32 +
 third_party/Makefile.am                            |   31 +
 third_party/README.txt                             |    4 +
 third_party/tclap/AUTHORS                          |    6 +
 third_party/tclap/Arg.h                            |  672 ++++
 third_party/tclap/ArgException.h                   |  200 ++
 third_party/tclap/ArgTraits.h                      |   81 +
 third_party/tclap/CMakeLists.txt                   |    0
 third_party/tclap/COPYING                          |   25 +
 third_party/tclap/ChangeLog                        | 1199 ++++++++
 third_party/tclap/CmdLine.h                        |  621 ++++
 third_party/tclap/CmdLineInterface.h               |  150 +
 third_party/tclap/CmdLineOutput.h                  |   74 +
 third_party/tclap/Constraint.h                     |   68 +
 third_party/tclap/DocBookOutput.h                  |  299 ++
 third_party/tclap/HelpVisitor.h                    |   69 +
 third_party/tclap/IgnoreRestVisitor.h              |   52 +
 third_party/tclap/Makefile.am                      |   28 +
 third_party/tclap/MultiArg.h                       |  422 +++
 third_party/tclap/MultiSwitchArg.h                 |  216 ++
 third_party/tclap/NEWS                             |   93 +
 third_party/tclap/OptionalUnlabeledTracker.h       |   62 +
 third_party/tclap/README                           |   16 +
 third_party/tclap/StandardTraits.h                 |  184 ++
 third_party/tclap/StdOutput.h                      |  298 ++
 third_party/tclap/SwitchArg.h                      |  228 ++
 third_party/tclap/UnlabeledMultiArg.h              |  301 ++
 third_party/tclap/UnlabeledValueArg.h              |  340 ++
 third_party/tclap/ValueArg.h                       |  411 +++
 third_party/tclap/ValuesConstraint.h               |  147 +
 third_party/tclap/VersionVisitor.h                 |   74 +
 third_party/tclap/Visitor.h                        |   53 +
 third_party/tclap/XorHandler.h                     |  156 +
 third_party/tclap/ZshCompletionOutput.h            |  321 ++
 utils/build_kit_from_svn                           |  120 +
 vms/make_vms.com                                   |   44 +
 windows/README.txt                                 |  103 +
 windows/applications/nxbrowse/nxbrowse.vcproj      |  192 ++
 windows/applications/nxconvert/nxconvert.vcproj    |  211 ++
 windows/applications/nxdir/nxdir.vcproj            |  216 ++
 windows/applications/nxingest/nxingest.vcproj      |  243 ++
 windows/applications/nxsummary/nxsummary.vcproj    |  243 ++
 .../applications/nxtranslate/nxtranslate.vcproj    |  283 ++
 windows/applications/nxtraverse/nxtraverse.vcproj  |  187 ++
 windows/bindings/cpp/nexusCPP.vcproj               |  187 ++
 windows/getopt.c                                   | 1052 +++++++
 windows/getopt.h                                   |  170 +
 windows/makefile.mingw                             |   89 +
 windows/napi4_test/napi4_test.dsp                  |  111 +
 windows/napi5_test/napi5_test.dsp                  |  111 +
 windows/napif_test/napif_test.dsp                  |  114 +
 windows/nexus.dsw                                  |  182 ++
 windows/nexus.sln                                  |  109 +
 windows/nexus/nexus.vcproj                         |  255 ++
 windows/nexus4/nexus4.dsp                          |  125 +
 windows/nexus45/nexus45.dsp                        |  133 +
 windows/nexus5/nexus5.dsp                          |  129 +
 windows/nexusf90/nexusf90.dsp                      |  144 +
 windows/nx45dll/nx45dll.dsp                        |  144 +
 windows/nxbrowse/nxbrowse.dsp                      |  110 +
 windows/nxbrowse_dll/nxbrowse_dll.dsp              |  114 +
 windows/nxtest90/nxtest90.dsp                      |  116 +
 windows/nxtodtd/nxtodtd.dsp                        |  109 +
 windows/nxtoxml/nxtoxml.dsp                        |  109 +
 windows/stdint.h                                   |   40 +
 1619 files changed, 290636 insertions(+)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..2cae2e4
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,14 @@
+Uwe Filges <Uwe.Filges at psi.ch> (CVS/ChangeLog username: uf)
+Przemek Klosowski <przemek at nist.gov> (CVS/ChangeLog username: pk)
+Mark Koennecke <Mark.Koennecke at psi.ch> (CVS/ChangeLog username: mk)
+Nick Maliszewskyj <nickm at nist.gov> (CVS/ChangeLog username: ncm)
+Chris Moreton-Smith <C.M.Moreton-Smith at rl.ac.uk> (CVS/ChangeLog username: cmm)
+Ray Osborn <ROsborn at anl.gov> (CVS/ChangeLog username: rio)
+Jon Tischler <tischlerjz at ornl.gov> (CVS/ChangeLog username: jzt)
+Freddie Akeroyd	<freddie.akeroyd at stfc.ac.uk> (CVS/ChangeLog username: faa59)
+Jens Krueger <jens.krueger at frm2.tum.de> (CVS/ChangeLog username: jk)
+Joern Beckmann <joern.beckmann at frm2.tum.de> (CVS/ChangeLog username: jb)
+Peter Peterson <petersonpf at ornl.gov> (CVS/ChangeLog username: pfp)
+Hartmut Gilde <Hartmut.Gilde at frm2.tum.de> (CVS/ChangeLog username: hg)
+
+$Id$
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..8fe8cd0
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,363 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+# Copyright (C) 2008-2012 NeXus International Advisory Committee (NIAC)
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+# we need 2.8.8 for correct component install with CPACK for archives
+if(WIN32)
+    cmake_minimum_required (VERSION 2.8.8)
+else()
+    cmake_minimum_required (VERSION 2.8.8)
+    if (${CMAKE_VERSION} VERSION_LESS 2.8.4)
+        set(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove this line when CMake >= 2.8.4 is required
+    endif()
+endif()
+
+#
+# convert a native windows path to its equivalent cygwin path
+#
+function(to_cygwin_path PATH RESULT)
+    file(TO_CMAKE_PATH ${PATH} CP)								# changes \ to / on windows
+    string(REGEX REPLACE "^([a-zA-Z]):/" "/\\1/" CP2 ${CP})   	# c:/ -> /c/
+	set(${RESULT} "/cygdrive${CP2}" PARENT_SCOPE) 				# /c/ -> /cygdrive/c/
+endfunction()
+
+# set a default install prefix for windows - we will adjust for 64bit later if this is unchanged
+set(DEFAULT_WIN_INSTALL_PREFIX "c:/nxinstall")
+if(WIN32)
+    set(CMAKE_INSTALL_PREFIX ${DEFAULT_WIN_INSTALL_PREFIX} CACHE PATH "")
+endif()
+
+set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules")
+
+
+#The name of our project
+project (NeXus)
+
+set (NeXus_VERSION_MAJOR 1)
+set (NeXus_VERSION_MINOR 0)
+set (NXLTVERSINFO '4:3:4')
+
+# needed for windows NSIS installer
+file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} CMAKE_SOURCE_DIR_NATIVE) 
+file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} CMAKE_BINARY_DIR_NATIVE) 
+string(REPLACE "\\" "\\\\" CMAKE_SOURCE_DIR_NATIVE_D ${CMAKE_SOURCE_DIR_NATIVE})
+string(REPLACE "\\" "\\\\" CMAKE_BINARY_DIR_NATIVE_D ${CMAKE_BINARY_DIR_NATIVE})
+
+find_program(SVNVERSION svnversion)
+
+#Packages to find that are required for the build
+
+set(HDF5_SEARCH "" CACHE PATH "Where to search for HDF5")
+
+set(HDF4_SEARCH "" CACHE PATH "Where to search for HDF4")
+
+set(MXML_SEARCH "" CACHE PATH "Where to search for MXML")
+
+set(SZIP_SEARCH "" CACHE PATH "Where to search for SZIP")
+
+set(ZLIB_SEARCH "" CACHE PATH "Where to search for ZLIB")
+
+#CMake includes 
+
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(CheckFunctionExists)
+include(CheckTypeSize)
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+
+if(WIN32)
+include(InstallRequiredSystemLibraries)
+endif()
+
+include(cmake_include/Utilities.cmake)
+#include(cmake_include/FindPython.cmake)
+include(cmake_include/FindCBFLib.cmake)
+#include(cmake_include/FindJava.cmake)
+#include(cmake_include/FindJNI.cmake)
+include(cmake_include/FindGuile.cmake)
+include(cmake_include/FindMZScheme.cmake)
+include(cmake_include/FindHDF4.cmake)
+include(cmake_include/FindHDF5.cmake)
+include(cmake_include/FindIDL.cmake)
+include(cmake_include/FindMXML.cmake)
+include(cmake_include/FindOpenGenie.cmake)
+include(cmake_include/FindDocbookUtils.cmake)
+include(cmake_include/FindSZIP.cmake)
+include(cmake_include/FindAnt.cmake)
+
+CHECK_TYPE_SIZE("int" SIZEOF_INT)
+set(HAVE_INT ${HAVE_SIZEOF_INT})
+CHECK_TYPE_SIZE("long int" SIZEOF_LONG_INT)
+set(HAVE_LONG_INT ${HAVE_SIZEOF_LONG_INT})
+CHECK_TYPE_SIZE("long long int" SIZEOF_LONG_LONG_INT)
+set(HAVE_LONG_LONG_INT ${HAVE_SIZEOF_LONG_LONG_INT})
+CHECK_TYPE_SIZE("unsigned long long int" SIZEOF_UNSIGNED_LONG_LONG_INT)
+set(HAVE_UNSIGNED_LONG_LONG_INT ${HAVE_SIZEOF_UNSIGNED_LONG_LONG_INT})
+CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T)
+set(HAVE_SIZE_T ${HAVE_SIZEOF_SIZE_T})
+
+CHECK_FUNCTION_EXISTS(ftime HAVE_FTIME)
+CHECK_FUNCTION_EXISTS(tzset HAVE_TZSET)
+CHECK_FUNCTION_EXISTS(strdup HAVE_STRDUP)
+
+CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H)
+CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
+CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H)
+
+if (SIZEOF_LONG_LONG_INT EQUAL 8)
+	set(PRINTF_INT64 "lld")
+	set(PRINTF_UINT64 "llu")
+elseif (WIN32)
+	set(PRINTF_INT64 "I64d")
+	set(PRINTF_UINT64 "I64u")
+else()
+	message(SEND_ERROR "Cannot printf int64 and uint64")
+endif()
+
+if(UNIX)
+    CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL)
+    CHECK_LIBRARY_EXISTS(pthread pthread_open "" HAVE_LIBPTHREAD)
+endif(UNIX)
+
+#find_package(HDF5 REQUIRED)
+#find_package(HDF5)
+#find_package(JPEG)
+find_package(XMLRPC)
+#find_package(ZLIB)
+find_package(LibXml2)
+find_package(Doxygen)
+find_package(SWIG)
+find_package(TCL)
+find_package(LATEX)
+find_package(PythonInterp)
+
+#Find the java runtime and sdk
+find_package(Java 1.6)
+find_package(JNI)
+
+# set ZLIB_ROOT as hint to find_package
+if (ZLIB_SEARCH)
+    set(ZLIB_ROOT ${ZLIB_SEARCH})
+elseif($ENV{ZLIB_ROOT})
+    set(ZLIB_ROOT $ENV{ZLIB_ROOT})
+else()
+    set(ZLIB_ROOT ${HDF5_ROOT_DIR} ${HDF4_ROOT_DIR} ${SZIP_ROOT_DIR})
+endif()
+find_package(ZLIB)
+
+#Find the libraries for the build.
+
+find_library(M m)
+#find_library(RPC rpc)
+find_library(DL dl)
+find_library(PTHREAD pthread)
+find_library(TERMCAP termcap)
+find_library(READLINE readline)
+find_library(HISTORY history)
+
+if(NOT WIN32)
+CHECK_LIBRARY_EXISTS(${READLINE} readline "" HAVE_LIBREADLINE)
+endif()
+
+if(M)
+   set(M_LINK "-lm")
+endif(M)
+
+if(DL)
+   set(DL_LINK "-ldl")
+endif(DL)
+
+if(PTHREAD)
+   set(PTHREAD_LINK "-lpthread")
+endif(PTHREAD)
+
+if(SZIPLIB_FOUND)
+   set(SZIP_LINK "-lsz") 
+else(SZIPLIB_FOUND)
+   set(SZIP_LIB "")
+endif(SZIPLIB_FOUND)
+
+if(TERMCAP)
+   set(TERMCAP_LINK "")
+endif(TERMCAP)
+
+if(READLINE)
+   set(READLINE_LINK "${READLINE}")
+endif(READLINE)
+
+if(HISTORY)
+   set(HISTORY_LINK "")
+endif(HISTORY)
+
+if (HDF5_FOUND)
+#   set (HDF5_CPP "-DHDF5 -DH5_USE_16_API")
+#   these are needed if HDF5 1.8 has been instaleld with H5_USE_16_API_DEFAULT 
+  set(HDF5_API_DEFS "-DH5Acreate_vers=2 -DH5Aiterate_vers=2 -DH5Dcreate_vers=2 -DH5Dopen_vers=2 -DH5Eclear_vers=2 -DH5Eprint_vers=2 -DH5Epush_vers=2 -DH5Eset_auto_vers=2 -DH5Eget_auto_vers=2 -DH5Ewalk_vers=2 -DH5Gcreate_vers=2 -DH5Gopen_vers=2 -DH5Pget_filter_vers=2 -DH5Pget_filter_by_id_vers=2 -DH5Pinsert_vers=2 -DH5Pregister_vers=2 -DH5Rget_obj_type_vers=2 -DH5Tarray_create_vers=2 -DH5Tcommit_vers=2 -DH5Tget_array_dims_vers=2 -DH5Topen_vers=2")
+  set (HDF5_CPP "-DHDF5 -DH5_NO_DEPRECATED_SYMBOLS ${HDF5_API_DEFS}")
+endif (HDF5_FOUND)
+
+#Options
+
+#Build user contributions
+option (BUILD_CONTRIB 
+        "Should I build the user contributions?" OFF)
+
+#Build user contributions
+option (BUILD_FORTRAN_BINDINGS 
+        "Should I build the fortran bindings?" OFF)
+
+#Use HDF4 in build
+option (BUILD_HDF4 
+        "Should I build HDF4 bindings if libraries available?" ON)
+
+option (BUILD_HDF5 
+        "Should I build HDF4 bindings if libraries available?" ON)
+
+#Use XML in build
+option (BUILD_XML 
+        "Should I build XML bindings if libraries available?" ON)
+set(BUILD_MXML ${BUILD_XML})
+
+#This is a MINGW build
+option (MINGW_MSYS 
+        "We are building under MINGW." OFF)
+
+#This if we have the MS Libraries
+option (HAVE_MS_LIB 
+        "We are building under MINGW." OFF)
+
+if (HAVE_MS_LIB)
+    set (MS_LIB LIB)
+endif (HAVE_MS_LIB)
+
+create_have_vars(HDF4 HDF5 MXML)
+
+#Include source files.
+include_directories(${PROJECT_SOURCE_DIR}/include ${HDF5_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR})
+
+
+if (UNIX)
+    check_add_c_compiler_flags("-Wall -Wno-unused-variable -Wno-sign-compare -Wno-comment")
+    check_add_cxx_compiler_flags("-Wall -Wno-unused-variable -Wno-sign-compare -Wno-comment")
+endif(UNIX)
+
+if (BUILD_FORTRAN_BINDINGS)
+    enable_language(Fortran)
+endif (BUILD_FORTRAN_BINDINGS)
+
+#We need a NXDOCDIR as a place to install the docs for various packages.
+set(NXDOCDIR "share/nexus/doc")
+
+#We need a NXEXAMPLEDIR as a place to install the examples.
+set(NXEXAMPLEDIR  "share/nexus/examples")
+
+#We need a NXINCLUDE and NX_INCLUDE as a place to install the include files.
+set(NXINCLUDE  "include")
+set(NX_INCLUDE "include/nexus")
+
+configure_file("${CMAKE_SOURCE_DIR}/include/nxconfig_h_cmake.in" "${CMAKE_BINARY_DIR}/include/nxconfig.h" @ONLY)
+include_directories("${CMAKE_BINARY_DIR}/include")
+
+if(MSVC)
+# warning 4820 is byte padding in structures
+# warning 4996 is about using _strdup ratherthan strdup etc
+# /W4 rather than /Wall
+# /Zi to get pdb file in all configurations
+    set(NX_CFLAGS "/W4 /wd4820 /wd4996 /Zi")
+    set(NX_CPP -D_CRT_SECURE_NO_WARNINGS)
+	set(CMAKE_DEBUG_POSTFIX "D")
+#	set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /INCREMENTAL" CACHE STRING "" FORCE)   # workaround for problems
+endif(MSVC)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NX_CFLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NX_CFLAGS}")
+
+if (CMAKE_SIZEOF_VOID_P MATCHES "8")
+    set(ARCH64 1)
+	set(ARCHSUFFIX "64")
+else()
+    set(ARCH64 0)
+	set(ARCHSUFFIX "")
+endif()
+
+# if we haven't changed the default windows install prefix, adjust for 64 bit
+if(${CMAKE_INSTALL_PREFIX} STREQUAL ${DEFAULT_WIN_INSTALL_PREFIX})
+    set(CMAKE_INSTALL_PREFIX "${DEFAULT_WIN_INSTALL_PREFIX}${ARCHSUFFIX}" CACHE PATH "" FORCE)
+endif()
+
+if(WIN32)
+	if(ARCH64)
+		include_directories("${NEXUS_THIRD_PARTY}/win64/include")
+		file(GLOB EXTRA_DLLS "${NEXUS_THIRD_PARTY}/win64/bin/*.dll")
+	else()
+		include_directories("${NEXUS_THIRD_PARTY}/win32/include")
+		file(GLOB EXTRA_DLLS "${NEXUS_THIRD_PARTY}/win32/bin/*.dll")
+	endif()
+	install(FILES ${EXTRA_DLLS} DESTINATION bin COMPONENT Runtime)
+endif()
+
+# Recurse into the subdirectories.
+add_subdirectory (src)
+add_subdirectory (bindings)
+add_subdirectory (applications)
+#add_subdirectory (config)
+#add_subdirectory (contrib)
+#add_subdirectory (definitions)
+add_subdirectory (doc)
+add_subdirectory (examples)
+add_subdirectory (include)
+#add_subdirectory (InstallerBits)
+#add_subdirectory (macosx_install_kit)
+#add_subdirectory (scripts)
+add_subdirectory (test)
+#add_subdirectory (third_party)
+#add_subdirectory (vms)
+#add_subdirectory (windows)
+#add_subdirectory (Windows_extra)
+
+#
+# set CPack packaging options
+#
+configure_file("${PROJECT_SOURCE_DIR}/CPackOptions.cmake.in" "${PROJECT_BINARY_DIR}/CPackOptions.cmake"  @ONLY)
+set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/CPackOptions.cmake")
+set (CPACK_GENERATOR TGZ) # not use ZIP on UNIX as problem with symlinks
+set (CPACK_SOURCE_GENERATOR TGZ) # not use ZIP on UNIX as problem with symlinks
+if(WIN32)
+    set (CPACK_GENERATOR ${CPACK_GENERATOR};ZIP;NSIS)
+    set (CPACK_SOURCE_GENERATOR ${CPACK_SOURCE_GENERATOR};ZIP) 
+elseif(APPLE)
+    set (CPACK_GENERATOR ${CPACK_GENERATOR};PackageMaker)
+elseif(CYGWIN)
+    set (CPACK_GENERATOR ${CPACK_GENERATOR};CygwinBinary)
+    set (CPACK_SOURCE_GENERATOR ${CPACK_SOURCE_GENERATOR};CygwinSource) 
+elseif(UNIX)
+    set (CPACK_GENERATOR ${CPACK_GENERATOR};DEB;RPM)
+endif()
+# Include of CPack must always be last
+include(CPack)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..42d5094
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,515 @@
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
diff --git a/CPackOptions.cmake.in b/CPackOptions.cmake.in
new file mode 100644
index 0000000..0669020
--- /dev/null
+++ b/CPackOptions.cmake.in
@@ -0,0 +1,220 @@
+# processed with    configure_file @ONLY   so may need @VAR@ rather than ${VAR} in some circumstances
+# $Id: CPackOptions.cmake.in 1079 2012-05-05 22:17:36Z Freddie Akeroyd $
+#
+#====================================================================
+#  NeXus - A common data format for neutron, x-ray and muon science.
+#  
+#  CPackOptions.cmake.in for building the NeXus library and applications.
+#
+# Copyright (C) 2008-2012 NeXus International Advisory Committee (NIAC)
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+#
+
+include(CPackComponent)
+
+#set(CPACK_ALL_INSTALL_TYPES Full)
+#set(CPACK_COMPONENTS_ALL manual definitions)   # default is all components mentioned
+
+if (NOT WIN32)
+    if (${CMAKE_VERSION} VERSION_LESS 2.8.4)
+        set(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove this line when CMake >= 2.8.4 is required
+    endif()
+endif()
+
+set (CPACK_PACKAGE_NAME "NeXus")
+set (CPACK_PACKAGE_VENDOR "NeXus International Advisory Committee")
+set (CPACK_PACKAGE_VERSION_MAJOR "4")
+set (CPACK_PACKAGE_VERSION_MINOR "3")
+set (CPACK_PACKAGE_VERSION_PATCH "0")
+set (CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+set (CPACK_PACKAGE_CONTACT "NeXus Developers <nexus-tech at nexusformat.org>")
+set (CPACK_PACKAGE_DESCRIPTION_FILE "@CMAKE_SOURCE_DIR@/cmake_include/nexus_description.txt")
+set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "NeXus - a common format for neutron and X-ray scattering data http://www.nexusformat.org/")
+set (CPACK_PACKAGE_FILE_NAME "nexus-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}-${CPACK_PACKAGE_VERSION_PATCH}")
+set (CPACK_SOURCE_PACKAGE_FILE_NAME "nexus-source-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+set (CPACK_PACKAGE_INSTALL_DIRECTORY "NeXus Data Format")
+
+set (CPACK_RESOURCE_FILE_LICENSE "@CMAKE_SOURCE_DIR@/InstallerBits/Licences/COPYING.txt")
+set (CPACK_RESOURCE_FILE_README "@CMAKE_SOURCE_DIR@/cmake_include/nexus_description.txt")
+set (CPACK_RESOURCE_FILE_WELCOME "@CMAKE_SOURCE_DIR@/cmake_include/WELCOME.txt")
+set (CPACK_PACKAGE_ICON "@CMAKE_SOURCE_DIR@/InstallerBits/nexus.ico")
+
+# we do not have any absolute paths, so do not need DESTDIR
+SET(CPACK_SET_DESTDIR "OFF")
+SET(CPACK_PACKAGE_RELOCATABLE "true")
+
+# HKLM\Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@
+#set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "nexus")
+
+set(CPACK_SOURCE_IGNORE_FILES 
+	  "nexus_spec.in;~$;/.svn/;/.cvsignore/;/CMakeFiles/;/nbproject/;autogen.sh;cmake_install.cmake;Makefile;${CPACK_SOURCE_IGNORE_FILES}") 
+
+if (${CPACK_GENERATOR} STREQUAL "DEB")
+    set(CPACK_DEB_COMPONENT_INSTALL ON)
+    set(CPACK_INSTALL_PREFIX "/usr")
+    set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+    set(CPACK_PACKAGE_NAME "nexus") # used for components
+#    set(CPACK_DEBIAN_PACKAGE_DEBUG TRUE)
+    set (CPACK_DEBIAN_PACKAGE_NAME "nexus")
+    set (CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all")
+    set (CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT})
+    set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://www.nexusformat.org/")
+endif()
+if (${CPACK_GENERATOR} STREQUAL "RPM")
+    set(CPACK_INSTALL_PREFIX "/usr")
+    set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+#    set(CPACK_RPM_PACKAGE_PREFIX "/usr")
+#    set(CPACK_RPM_PACKAGE_DEBUG TRUE)
+    set (CPACK_RPM_PACKAGE_NAME "nexus")
+#    set (CPACK_RPM_PACKAGE_ARCHITECTURE "noarch")
+    set (CPACK_RPM_PACKAGE_RELEASE "1")
+#    set (CPACK_RPM_PACKAGE_REQUIRES "python >= 2.5.0, cmake >= 2.8.8")
+    set (CPACK_RPM_PACKAGE_REQUIRES "python >= 2.5.0")
+#    set (CPACK_RPM_PACKAGE_PROVIDES "")
+    set(CPACK_RPM_COMPONENT_INSTALL ON)
+    set(CPACK_RPM_PACKAGE_LICENSE "@CMAKE_SOURCE_DIR@/InstallerBits/Licences/COPYING.txt")
+    set(CPACK_RPM_PACKAGE_URL "http://www.nexusformat.org/")
+#    set(CPACK_RPM_CHANGELOG_FILE "")
+endif()
+if (${CPACK_GENERATOR} STREQUAL "TGZ")
+	set(CPACK_MONOLITHIC_INSTALL ON)
+    set(CPACK_TGZ_COMPONENT_INSTALL OFF)
+    set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY ON)
+    set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY ON)
+    set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
+endif()
+if (${CPACK_GENERATOR} STREQUAL "ZIP")
+	set(CPACK_MONOLITHIC_INSTALL ON)
+    set(CPACK_ZIP_COMPONENT_INSTALL OFF)
+    set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY ON)
+    set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY ON)
+    set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
+endif()
+if (${CPACK_GENERATOR} STREQUAL "CygwinBinary")
+    set(CPACK_CYGWIN_PATCH_NUMBER 1)
+endif()
+if (${CPACK_GENERATOR} STREQUAL "PackageMaker")
+#    set(CPACK_MONOLITHIC_INSTALL ON)
+    # 10.4 is "Tiger", component based install needs 10.4 and above
+    set(CPACK_OSX_PACKAGE_VERSION 10.4) 
+endif()
+if (${CPACK_GENERATOR} STREQUAL "Bundle")
+endif()
+if (${CPACK_GENERATOR} STREQUAL "NSIS")
+    ### NSIS component installs seem to trigger download option at the moment, so set monolithic install and a full package name until we can figure out why
+	set(CPACK_MONOLITHIC_INSTALL ON)
+    set(CPACK_PACKAGE_FILE_NAME "nexus-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+    set(CPACK_NSIS_PACKAGE_NAME "NeXus ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+    set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} NeXus")
+    set(CPACK_NSIS_HELP_LINK "http://www.nexusformat.org/")
+    set(CPACK_NSIS_URL_INFO_ABOUT "http://www.nexusformat.org/")
+    set(CPACK_NSIS_CONTACT "${CPACK_PACKAGE_CONTACT}")
+    set(CPACK_NSIS_MODIFY_PATH OFF)
+    set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "!include '@CMAKE_SOURCE_DIR_NATIVE@\nsis_install.nsh'")
+    set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "!include '@CMAKE_SOURCE_DIR_NATIVE@\nsis_uninstall.nsh'")
+#  set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\MyExecutable.exe")
+    set(CPACK_PACKAGE_ICON "@CMAKE_SOURCE_DIR_NATIVE_D@\\InstallerBits\\nexus.ico")
+	set(CPACK_NSIS_MUI_ICON "@CMAKE_SOURCE_DIR_NATIVE_D@\\InstallerBits\\nexus.ico")
+	set(CPACK_NSIS_MUI_UNIICON "@CMAKE_SOURCE_DIR_NATIVE_D@\\InstallerBits\\nexus.ico")
+	set(CPACK_NSIS_MENU_LINKS "http://www.nexusformat.org/" "NeXus Web Site" "bin\\nxvalidate.bat" "NXvalidate")	
+	if (@ARCH64@)
+		set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
+		set(CPACK_NSIS_DEFINES "!define NEXUSDIRENVSUFFIX 64")	
+	else()
+		set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES32")
+		set(CPACK_NSIS_DEFINES "!define NEXUSDIRENVSUFFIX 32")	
+	endif()
+endif()
+	  
+#set (CPACK_OUTPUT_CONFIG_FILE)
+#set (CPACK_PACKAGE_EXECUTABLES)
+#set (CPACK_STRIP_FILES)
+#set (CPACK_SOURCE_STRIP_FILES)
+#set (CPACK_SOURCE_GENERATOR)
+#set (CPACK_SOURCE_OUTPUT_CONFIG_FILE)
+#set (CPACK_SOURCE_IGNORE_FILES)
+
+if(WIN32)
+    set(NXVALIDATE nxvalidate.bat)
+else()
+    set(NXVALIDATE nxvalidate)
+endif()
+set(CPACK_CREATE_DESKTOP_LINKS "nxbrowse" ${NXVALIDATE})
+set(CPACK_PACKAGE_EXECUTABLES "nxbrowse" "NXbrowse")
+
+#cpack_add_component(Runtime
+#                    DISPLAY_NAME "Binary Applications"
+#                    DESCRIPTION "Binary applications such as nxconvert, nxbrows etc..."
+#                    )
+
+#cpack_add_component(Documentation
+#                    DISPLAY_NAME "Documentation"
+#                    DESCRIPTION "Application Documentation, API and help files."
+#                    )
+
+#cpack_add_component(Development
+#                    DISPLAY_NAME "Development"
+#                    DESCRIPTION "Development libraies and headers."
+#                    )
+
+#cpack_add_component(Examples
+#                    DISPLAY_NAME "Examples"
+#                    DESCRIPTION "Code example files."
+#                    )
+
+#cpack_add_component(definitions
+#                    DISPLAY_NAME "NeXus NXDL definitions"
+#                    DESCRIPTION "Binary applications such as nxconvert, nxbrowse etc..."
+#					INSTALL_TYPES Full
+#					GROUP definitions_group
+#                    )
+
+#cpack_add_component(manual
+#                    DISPLAY_NAME "NeXus Documentation"
+#                    DESCRIPTION "NeXus User Guide and Reference Documentation with examples."
+#					INSTALL_TYPES Full
+#					GROUP manual_group
+#                    )
+
+#cpack_add_install_type(Full DISPLAY_NAME "Full")
+
+#cpack_add_component_group(definitions_group
+#                              DISPLAY_NAME definitions
+#                              DESCRIPTION definitions
+#                              EXPANDED
+#                              BOLD_TITLE)
+
+#cpack_add_component_group(manual_group
+#                              DISPLAY_NAME manual
+#                              DESCRIPTION manual
+#                              EXPANDED
+#                              BOLD_TITLE)
+
+#cpack_add_component(Development
+#                    DISPLAY_NAME "Development"
+#                    DESCRIPTION "Development libraries and headers."
+#                    )
+
+#cpack_add_component(Examples
+#                    DISPLAY_NAME "Examples"
+#                    DESCRIPTION "Code example files."
+#                    )
diff --git a/InstallerBits/Licences/AUTHORS.txt b/InstallerBits/Licences/AUTHORS.txt
new file mode 100644
index 0000000..c4de0e0
--- /dev/null
+++ b/InstallerBits/Licences/AUTHORS.txt
@@ -0,0 +1,14 @@
+The following people have been involved with the development of the NeXus source code
+
+Uwe Filges <Uwe.Filges at psi.ch> (CVS/ChangeLog username: uf)
+Przemek Klosowski <przemek at nist.gov> (CVS/ChangeLog username: pk)
+Mark Koennecke <Mark.Koennecke at psi.ch> (CVS/ChangeLog username: mk)
+Nick Maliszewskyj <nickm at nist.gov> (CVS/ChangeLog username: ncm)
+Chris Moreton-Smith <C.M.Moreton-Smith at rl.ac.uk> (CVS/ChangeLog username: cmm)
+Ray Osborn <ROsborn at anl.gov> (CVS/ChangeLog username: rio)
+Jon Tischler <tischlerjz at ornl.gov> (CVS/ChangeLog username: jzt)
+Freddie Akeroyd	<F.A.Akeroyd at rl.ac.uk> (CVS/ChangeLog username: faa59)
+Jens Krueger <jens.krueger at frm2.tum.de> (CVS/ChangeLog username: jk)
+Joern Beckmann <joern.beckmann at frm2.tum.de> (CVS/ChangeLog username: jb)
+Peter Peterson <petersonpf at ornl.gov> (CVS/ChangeLog username: pfp)
+Hartmut Gilde <Hartmut.Gilde at frm2.tum.de> (CVS/ChangeLog username: hg)
diff --git a/InstallerBits/Licences/COPYING.rtf b/InstallerBits/Licences/COPYING.rtf
new file mode 100644
index 0000000..92702ee
--- /dev/null
+++ b/InstallerBits/Licences/COPYING.rtf
@@ -0,0 +1,131 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f37\froman\fcharset238\fprq2 Times New Roman CE;}{\f38\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f40\froman\fcharset161\fprq2 Times New Roman Greek;}
+{\f41\froman\fcharset162\fprq2 Times New Roman Tur;}{\f42\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f43\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f44\froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\f45\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f47\fswiss\fcharset238\fprq2 Arial CE;}{\f48\fswiss\fcharset204\fprq2 Arial Cyr;}{\f50\fswiss\fcharset161\fprq2 Arial Greek;}{\f51\fswiss\fcharset162\fprq2 Arial Tur;}
+{\f52\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f53\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}{\f54\fswiss\fcharset186\fprq2 Arial Baltic;}{\f55\fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f57\fmodern\fcharset238\fprq1 Courier New CE;}
+{\f58\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f60\fmodern\fcharset161\fprq1 Courier New Greek;}{\f61\fmodern\fcharset162\fprq1 Courier New Tur;}{\f62\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}
+{\f63\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f64\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f65\fmodern\fcharset163\fprq1 Courier New (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;
+\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;
+\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 
+\snext0 Normal;}{\s2\ql \li0\ri0\sb240\sa60\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af1\afs28\alang1025 \ltrch\fcs0 \b\i\f1\fs28\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 
+\sbasedon0 \snext0 \styrsid2637830 heading 2;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv 
+\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}{\*\cs15 \additive \rtlch\fcs1 \af0 
+\ltrch\fcs0 \ul\cf2 \sbasedon10 \styrsid12933061 Hyperlink;}{\*\ts16\tsrowd\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 
+\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype0\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv 
+\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \sbasedon11 \snext16 \styrsid12933061 Table Grid;}{\*\cs17 
+\additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf12 \sbasedon10 \styrsid616184 FollowedHyperlink;}{\s18\ql \li0\ri0\widctlpar
+\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs20\alang1025 \ltrch\fcs0 
+\f2\fs20\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 \sbasedon0 \snext18 \styrsid616184 HTML Preformatted;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}{\*\rsidtbl \rsid96589\rsid423131\rsid471429
+\rsid600082\rsid616184\rsid725387\rsid806464\rsid818576\rsid1051552\rsid1312291\rsid1377015\rsid1517460\rsid1539703\rsid1977259\rsid2119668\rsid2370198\rsid2637830\rsid3304577\rsid3497533\rsid4550405\rsid4590962\rsid4606058\rsid4654447\rsid4916698
+\rsid5663267\rsid6244934\rsid6696468\rsid6829057\rsid6881317\rsid7147049\rsid7426348\rsid7555177\rsid7560631\rsid7562219\rsid7616615\rsid7934244\rsid8079013\rsid8276379\rsid8421298\rsid8601157\rsid8720034\rsid8979643\rsid9006469\rsid9131608\rsid9922756
+\rsid9975124\rsid11012224\rsid11084197\rsid11279011\rsid11614071\rsid11667494\rsid12389127\rsid12675268\rsid12792798\rsid12933061\rsid13727994\rsid13911058\rsid13979980\rsid14041793\rsid14288417\rsid14752071\rsid15020551\rsid15159816\rsid15888689
+\rsid15949818\rsid15954248\rsid16194217}{\*\generator Microsoft Word 11.0.8026;}{\info{\title To be filled in later}{\author Freddie Akeroyd}{\operator  }{\creatim\yr2006\mo1\dy10\hr9\min49}{\revtim\yr2006\mo9\dy25\hr12\min20}{\version18}{\edmins91}
+{\nofpages1}{\nofwords471}{\nofchars2689}{\*\company CCLRC}{\nofcharsws3154}{\vern24609}{\*\password 00000000}}{\*\xmlnstbl {\xmlns1 urn:schemas-microsoft-com:office:smarttags}}
+\paperw12240\paperh15840\margl1800\margr1800\margt1440\margb1440\gutter0\ltrsect \widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1800\dgvorigin1440
+\dghshow1\dgvshow1\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot6696468 
+\fet0{\*\wgrffmtfilter 013f}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang 
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid9131608 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 {
+\rtlch\fcs1 \af0\afs44 \ltrch\fcs0 \fs44\insrsid12675268 Licens}{\rtlch\fcs1 \af0\afs44 \ltrch\fcs0 \fs44\insrsid14752071\charrsid14752071 e}{\rtlch\fcs1 \af0\afs44 \ltrch\fcs0 \fs44\insrsid13979980  Information}{\rtlch\fcs1 \af0\afs44 \ltrch\fcs0 
+\fs44\insrsid14752071\charrsid14752071 
+\par }{\rtlch\fcs1 \af0\afs36 \ltrch\fcs0 \fs36\insrsid14752071 
+\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12933061\charrsid9131608 The NeXus library and utilities are distributed under the terms on the }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid12933061\charrsid9131608 GNU Lesser }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 
+\b\insrsid14041793\charrsid9131608 General }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid12675268 Public Licens}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid12933061\charrsid9131608 e (LGPL)}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12933061\charrsid9131608  
+\endash  see the enclosed }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7147049\charrsid7147049 COPYING_NeXus}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid12933061\charrsid7147049 .txt}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12933061\charrsid9131608  file }{
+\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608 or }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608  HYPERLINK "http://www.opensource.org/licenses/lgpl-license.php" }{\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000003400000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006c00670070006c002d006c006900630065006e00730065002e007000
+680070000000e0c9ea79f9bace118c8200aa004ba90b6800000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006c00670070006c002d006c006900630065006e00730065002e007000680070
+00000000000000000000c5}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid14041793\charrsid9131608 http://www.opensource.org/licenses/lgpl-license.php}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608  }{\rtlch\fcs1 \af0 
+\ltrch\fcs0 \insrsid12933061\charrsid9131608 for further details.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608  The NeXus library }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608 is linked statically against Michael Sweet
+\rquote s}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608  Mini-XML parsing library (}{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608  HYPERLINK "http://www.easysw.com/~mike/mxml/" }{\rtlch\fcs1 
+\af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000002200000068007400740070003a002f002f007700770077002e006500610073007900730077002e0063006f006d002f007e006d0069006b0065002f006d0078006d006c002f000000e0c9ea79f9bace118c8200aa004ba90b4400000068007400740070003a00
+2f002f007700770077002e006500610073007900730077002e0063006f006d002f007e006d0069006b0065002f006d0078006d006c002f00000000000000000000ff}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid14041793\charrsid9131608 http://www.easysw.com/~mike/mxml/}
+}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608 ) which is also governed by the }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid14041793\charrsid7147049 LGPL}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14041793\charrsid9131608 .
+\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12933061\charrsid9131608 
+\par In addition to the NeXus libraries, this kit }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid12933061\charrsid9131608 will also install DLLs from other packages}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12933061\charrsid9131608 
+ that have been linked into the NeXus library. These package}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12675268 s and their licens}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12933061\charrsid9131608 es are as follows:
+\par 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid8979643\charrsid9131608 libxml2.dll}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608  is from the XML C Parser for GNOME (}{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid8979643\charrsid9131608  HYPERLINK "http://xmlsoft.org/" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000001400000068007400740070003a002f002f0078006d006c0073006f00660074002e006f00720067002f000000e0c9ea79f9bace118c8200aa004ba90b2800000068007400740070003a002f002f0078006d006c0073006f00660074002e006f00720067002f00
+000000000000000000c5}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid8979643\charrsid9131608 http://xmlsoft.org/}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608 )}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 
+.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608  Its distribut}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12675268 ion is covered by the MIT Licens}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608 e }{\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid7555177\charrsid9131608 which is }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608 detailed in the enclosed }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid8979643\charrsid9131608 COPYING_libxml2.txt}{\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid8979643\charrsid9131608  file and }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 also }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608 at }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid8979643\charrsid9131608  HYPERLINK "http://www.opensource.org/licenses/mit-license.html" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000003400000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006d00690074002d006c006900630065006e00730065002e0068007400
+6d006c000000e0c9ea79f9bace118c8200aa004ba90b6800000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006d00690074002d006c006900630065006e00730065002e00680074006d006c
+0000000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid8979643\charrsid9131608 http://www.opensource.org/licenses/mit-license.html}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid8979643\charrsid9131608 
+\par 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 hd*.dll }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 and}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608  hm*.dll files }{\rtlch\fcs1 \af0 
+\ltrch\fcs0 \insrsid7555177\charrsid9131608 are the HDF4 libraries developed at the
+\par {\*\xmlopen\xmlns1{\factoidname PlaceName}}{\*\xmlopen\xmlns1{\factoidname place}}{\*\xmlopen\xmlns1{\factoidname PlaceName}}National{\*\xmlclose} {\*\xmlopen\xmlns1{\factoidname PlaceType}}Center{\*\xmlclose}{\*\xmlclose}{\*\xmlclose}
+ for Supercomputing Applications (NCSA) at the 
+\par {\*\xmlopen\xmlns1{\factoidname PlaceType}}{\*\xmlopen\xmlns1{\factoidname place}}{\*\xmlopen\xmlns1{\factoidname PlaceType}}University{\*\xmlclose} of {\*\xmlopen\xmlns1{\factoidname PlaceName}}Illinois{\*\xmlclose}{\*\xmlclose}{\*\xmlclose}
+ at Urbana-Champaign (}{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608  HYPERLINK "http://hdf.ncsa.uiuc.edu/" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000001a00000068007400740070003a002f002f006800640066002e006e006300730061002e0075006900750063002e006500640075002f000000e0c9ea79f9bace118c8200aa004ba90b3400000068007400740070003a002f002f006800640066002e006e006300
+730061002e0075006900750063002e006500640075002f0000000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid7555177\charrsid9131608 http://hdf.ncsa.uiuc.edu/}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 
+). Their distr}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12675268 ibution is covered by the licens}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 e detailed in the enclosed }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 C
+OPYING_hdf4.txt }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 file and at }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 
+ HYPERLINK "ftp://ftp.ncsa.uiuc.edu/HDF/HDF/HDF_Current/src/unpacked/COPYING" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b0200000017000000410000006600740070003a002f002f006600740070002e006e006300730061002e0075006900750063002e006500640075002f004800440046002f004800440046002f004800440046005f00430075007200720065006e0074002f007300720063002f007500
+6e007000610063006b00650064002f0043004f005000590049004e0047000000e0c9ea79f9bace118c8200aa004ba90b820000006600740070003a002f002f006600740070002e006e006300730061002e0075006900750063002e006500640075002f004800440046002f004800440046002f004800440046005f00430075
+007200720065006e0074002f007300720063002f0075006e007000610063006b00650064002f0043004f005000590049004e0047000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid7555177\charrsid9131608 
+ftp://ftp.ncsa.uiuc.edu/HDF/HDF/HDF_Current/src/unpacked/COPYING}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608  
+\par 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid1539703 h}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 df5dll.dll }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 is the HDF5 library developed at the
+\par {\*\xmlopen\xmlns1{\factoidname PlaceName}}{\*\xmlopen\xmlns1{\factoidname place}}{\*\xmlopen\xmlns1{\factoidname PlaceName}}National{\*\xmlclose} {\*\xmlopen\xmlns1{\factoidname PlaceType}}Center{\*\xmlclose}{\*\xmlclose}{\*\xmlclose}
+ for Supercomputing Applications (NCSA) at the 
+\par {\*\xmlopen\xmlns1{\factoidname place}}{\*\xmlopen\xmlns1{\factoidname place}}{\*\xmlopen\xmlns1{\factoidname PlaceType}}University{\*\xmlclose} of {\*\xmlopen\xmlns1{\factoidname place}}Illinois{\*\xmlclose}{\*\xmlclose}{\*\xmlclose}
+ at Urbana-Champaign (}{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608  HYPERLINK "http://hdf.ncsa.uiuc.edu/" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000001a00000068007400740070003a002f002f006800640066002e006e006300730061002e0075006900750063002e006500640075002f000000e0c9ea79f9bace118c8200aa004ba90b3400000068007400740070003a002f002f006800640066002e006e006300
+730061002e0075006900750063002e006500640075002f0000000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid7555177\charrsid9131608 http://hdf.ncsa.uiuc.edu/}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 ). Distr}{
+\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12675268 ibution is covered by the licens}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 e detailed in the enclosed }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 COPYING_hdf5.txt }{
+\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 file and at }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608  HYPERLINK "ftp://ftp.ncsa.uiuc.edu/HDF/HDF5/current/src/unpacked/COPYING" }{\rtlch\fcs1 
+\af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000003e0000006600740070003a002f002f006600740070002e006e006300730061002e0075006900750063002e006500640075002f004800440046002f0048004400460035002f00630075007200720065006e0074002f007300720063002f0075006e0070006100
+63006b00650064002f0043004f005000590049004e0047000000e0c9ea79f9bace118c8200aa004ba90b7c0000006600740070003a002f002f006600740070002e006e006300730061002e0075006900750063002e006500640075002f004800440046002f0048004400460035002f00630075007200720065006e0074002f
+007300720063002f0075006e007000610063006b00650064002f0043004f005000590049004e0047000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid7555177\charrsid9131608 ftp://ftp.ncsa.uiuc.edu/HDF/HDF5/current/src/unpacked/COPYING}}}{
+\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608  
+\par 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid1539703 s}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 zlibdll.dll }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 is the }{\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid15888689\charrsid9131608 decoder-only version of the SZIP compression library \endash  it }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1539703 is licensed for use}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15888689\charrsid9131608 
+ only in conjunction with the enclosed HDF software. For further information see }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15888689\charrsid9131608  HYPERLINK "http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/" }{\rtlch\fcs1 \af0 
+\ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000002c00000068007400740070003a002f002f006800640066002e006e006300730061002e0075006900750063002e006500640075002f0064006f0063005f007200650073006f0075007200630065002f0053005a00490050002f000000e0c9ea79f9bace118c82
+00aa004ba90b5800000068007400740070003a002f002f006800640066002e006e006300730061002e0075006900750063002e006500640075002f0064006f0063005f007200650073006f0075007200630065002f0053005a00490050002f000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 
+\cs15\ul\cf2\insrsid15888689\charrsid9131608 http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15888689\charrsid9131608  and }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15888689\charrsid9131608 
+ HYPERLINK "http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/Commercial_szip.html" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000004000000068007400740070003a002f002f006800640066002e006e006300730061002e0075006900750063002e006500640075002f0064006f0063005f007200650073006f0075007200630065002f0053005a00490050002f0043006f006d006d0065007200
+6300690061006c005f0073007a00690070002e00680074006d006c000000e0c9ea79f9bace118c8200aa004ba90b8000000068007400740070003a002f002f006800640066002e006e006300730061002e0075006900750063002e006500640075002f0064006f0063005f007200650073006f0075007200630065002f0053
+005a00490050002f0043006f006d006d00650072006300690061006c005f0073007a00690070002e00680074006d006c000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid15888689\charrsid9131608 
+http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/Commercial_szip.html}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid725387\charrsid9131608 z}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7555177\charrsid9131608 lib1.dll }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 is }{\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid725387\charrsid9131608 from the the ZLIB compression library }{\field{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11279011  HYPERLINK "}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11279011\charrsid11279011 http://www.gzip.org/}{\rtlch\fcs1 \af0 
+\ltrch\fcs0 \insrsid11279011 zlib/" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000001a00000068007400740070003a002f002f007700770077002e0067007a00690070002e006f00720067002f007a006c00690062002f000000e0c9ea79f9bace118c8200aa004ba90b3400000068007400740070003a002f002f007700770077002e0067007a00
+690070002e006f00720067002f007a006c00690062002f0000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid11279011\charrsid7934244 http://www.gzip.org/zlib/}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11279011  }{\rtlch\fcs1 \af0 
+\ltrch\fcs0 \insrsid725387\charrsid9131608 . Its distribution is covered by the lic}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12675268 ens}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid725387\charrsid9131608 e detailed in the enclosed COPYING_zlib.txt and also at }
+{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid725387\charrsid9131608  HYPERLINK "http://www.zlib.net/zlib_license.html" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000002600000068007400740070003a002f002f007700770077002e007a006c00690062002e006e00650074002f007a006c00690062005f006c006900630065006e00730065002e00680074006d006c000000e0c9ea79f9bace118c8200aa004ba90b4c0000006800
+7400740070003a002f002f007700770077002e007a006c00690062002e006e00650074002f007a006c00690062005f006c006900630065006e00730065002e00680074006d006c000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid725387\charrsid9131608 
+http://www.zlib.net/zlib_license.html}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7555177\charrsid9131608 
+\par }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid725387\charrsid9131608 
+\par iconv.dll }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1539703\charrsid1539703 is from the GNU ICONV library (}{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1539703\charrsid1539703  HYPERLINK "http://www.gnu.org/software/libiconv/" }{
+\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid1539703 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000002600000068007400740070003a002f002f007700770077002e0067006e0075002e006f00720067002f0073006f006600740077006100720065002f006c0069006200690063006f006e0076002f000000e0c9ea79f9bace118c8200aa004ba90b4c0000006800
+7400740070003a002f002f007700770077002e0067006e0075002e006f00720067002f0073006f006600740077006100720065002f006c0069006200690063006f006e0076002f000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid1539703\charrsid1539703 
+http://www.gnu.org/software/libiconv/}}}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1539703\charrsid1539703 ). It is distributed under the terms of the }{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid12675268 GNU Lesser General Public Licens}{\rtlch\fcs1 \ab\af0 
+\ltrch\fcs0 \b\insrsid11667494\charrsid9131608 e (LGPL)}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid7147049  }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7147049\charrsid7147049 as detailed in the enclosed COPYING_iconv.txt}{\rtlch\fcs1 \af0 \ltrch\fcs0 
+\insrsid7147049  and at }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1539703\charrsid1539703 .}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7147049\charrsid7147049  }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid7147049\charrsid9131608 
+ HYPERLINK "http://www.opensource.org/licenses/lgpl-license.php" }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1312291\charrsid9131608 {\*\datafield 
+00d0c9ea79f9bace118c8200aa004ba90b02000000170000003400000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006c00670070006c002d006c006900630065006e00730065002e007000
+680070000000e0c9ea79f9bace118c8200aa004ba90b6800000068007400740070003a002f002f007700770077002e006f00700065006e0073006f0075007200630065002e006f00720067002f006c006900630065006e007300650073002f006c00670070006c002d006c006900630065006e00730065002e007000680070
+0000000000000000000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf2\insrsid7147049\charrsid9131608 http://www.opensource.org/licenses/lgpl-license.php}}}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid725387\charrsid1539703 
+\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid1051552\charrsid9131608 
+\par }}
\ No newline at end of file
diff --git a/InstallerBits/Licences/COPYING.txt b/InstallerBits/Licences/COPYING.txt
new file mode 100644
index 0000000..16adb43
--- /dev/null
+++ b/InstallerBits/Licences/COPYING.txt
@@ -0,0 +1,34 @@
+License Information
+
+The NeXus library and utilities are distributed under the terms on the GNU Lesser General Public License (LGPL) � 
+see the enclosed COPYING_NeXus.txt file or http://www.opensource.org/licenses/lgpl-license.php for further details. 
+The NeXus library is linked statically against Michael Sweet�s Mini-XML parsing library (http://www.easysw.com/~mike/mxml/) 
+which is also governed by the LGPL.
+
+In addition to the NeXus libraries, this kit will also install DLLs from other packages that have been linked into 
+the NeXus library. These packages and their licenses are as follows:
+
+libxml2.dll is from the XML C Parser for GNOME (http://xmlsoft.org/). Its distribution is covered by the MIT License 
+which is detailed in the enclosed COPYING_libxml2.txt file and also at http://www.opensource.org/licenses/mit-license.html
+
+hd*.dll and hm*.dll files are the HDF4 libraries developed at the
+National Center for Supercomputing Applications (NCSA) at the 
+University of Illinois at Urbana-Champaign (http://hdf.ncsa.uiuc.edu/). Their distribution is covered by the license detailed 
+in the enclosed COPYING_hdf4.txt file and at ftp://ftp.ncsa.uiuc.edu/HDF/HDF/HDF_Current/src/unpacked/COPYING 
+
+hdf5dll.dll is the HDF5 library developed at the
+National Center for Supercomputing Applications (NCSA) at the 
+University of Illinois at Urbana-Champaign (http://hdf.ncsa.uiuc.edu/). Distribution is covered by the license detailed in 
+the enclosed COPYING_hdf5.txt file and at ftp://ftp.ncsa.uiuc.edu/HDF/HDF5/current/src/unpacked/COPYING 
+
+szlibdll.dll is the decoder-only version of the SZIP compression library � it is licensed for use only in conjunction with 
+the enclosed HDF software. For further information see http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/ and 
+http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/Commercial_szip.html
+
+zlib1.dll is from the the ZLIB compression library http://www.gzip.org/zlib/ . Its distribution is covered by the 
+license detailed in the enclosed COPYING_zlib.txt and also at http://www.zlib.net/zlib_license.html
+
+iconv.dll is from the GNU ICONV library (http://www.gnu.org/software/libiconv/). It is distributed under the terms 
+of the GNU Lesser General Public License (LGPL) as detailed in the enclosed COPYING_iconv.txt and at . 
+http://www.opensource.org/licenses/lgpl-license.php
+
diff --git a/InstallerBits/Licences/COPYING_hdf4.txt b/InstallerBits/Licences/COPYING_hdf4.txt
new file mode 100644
index 0000000..e4e197a
--- /dev/null
+++ b/InstallerBits/Licences/COPYING_hdf4.txt
@@ -0,0 +1,51 @@
+------------------------------------------------------------------
+
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF) 
+Software Library and Utilities
+
+Copyright 1988-2005 The Board of Trustees of the University of Illinois
+
+All rights reserved.
+
+Contributors:   National Center for Supercomputing Applications 
+(NCSA) at the University of Illinois, Fortner Software, Unidata 
+Program Center (netCDF), The Independent JPEG Group (JPEG), 
+Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment 
+Corporation (DEC).
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted for any purpose (including commercial 
+purposes) provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright 
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright 
+notice, this list of conditions, and the following disclaimer in the 
+documentation and/or materials provided with the distribution.
+
+3. In addition, redistributions of modified forms of the source or 
+binary code must carry prominent notices stating that the original 
+code was changed and the date of the change.
+
+4. All publications or advertising materials mentioning features or use 
+of this software are asked, but not required, to acknowledge that it was 
+developed by the National Center for Supercomputing Applications at the 
+University of Illinois at Urbana-Champaign and credit the contributors.
+
+5. Neither the name of the University nor the names of the Contributors 
+may be used to endorse or promote products derived from this software 
+without specific prior written permission from the University or the 
+Contributors.
+
+DISCLAIMER
+
+THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS" 
+WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED.  In no event 
+shall the University or the Contributors be liable for any damages 
+suffered by the users arising out of the use of this software, even if 
+advised of the possibility of such damage. 
+
+
+
+
diff --git a/InstallerBits/Licences/COPYING_hdf5.txt b/InstallerBits/Licences/COPYING_hdf5.txt
new file mode 100644
index 0000000..7f0f5cb
--- /dev/null
+++ b/InstallerBits/Licences/COPYING_hdf5.txt
@@ -0,0 +1,74 @@
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF)
+Software Library and Utilities
+
+NCSA HDF5 (Hierarchical Data Format 5) Software Library and Utilities 
+Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by the Board of 
+Trustees of the University of Illinois.  All rights reserved.
+
+Contributors: National Center for Supercomputing Applications (NCSA) at the
+University of Illinois at Urbana-Champaign (UIUC), Lawrence Livermore 
+National Laboratory (LLNL), Sandia National Laboratories (SNL), Los Alamos 
+National Laboratory (LANL), Jean-loup Gailly and Mark Adler (gzip library).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted for any purpose (including commercial purposes)
+provided that the following conditions are met:
+
+1.  Redistributions of source code must retain the above copyright notice,
+    this list of conditions, and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions, and the following disclaimer in the documentation
+    and/or materials provided with the distribution.
+
+3.  In addition, redistributions of modified forms of the source or binary
+    code must carry prominent notices stating that the original code was
+    changed and the date of the change.
+
+4.  All publications or advertising materials mentioning features or use of
+    this software are asked, but not required, to acknowledge that it was 
+    developed by the National Center for Supercomputing Applications at the 
+    University of Illinois at Urbana-Champaign and to credit the contributors.
+
+5.  Neither the name of the University nor the names of the Contributors may
+    be used to endorse or promote products derived from this software without
+    specific prior written permission from the University or the Contributors,
+    as appropriate for the name(s) to be used.
+
+6.  THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS"
+    WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED.  In no event
+    shall the University or the Contributors be liable for any damages
+    suffered by the users arising out of the use of this software, even if
+    advised of the possibility of such damage.
+
+--------------------------------------------------------------------------
+Portions of HDF5 were developed with support from the University of 
+California, Lawrence Livermore National Laboratory (UC LLNL).
+The following statement applies to those portions of the product
+and must be retained in any redistribution of source code, binaries,
+documentation, and/or accompanying materials:
+
+    This work was partially produced at the University of California,
+    Lawrence Livermore National Laboratory (UC LLNL) under contract no.
+    W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy 
+    (DOE) and The Regents of the University of California (University) 
+    for the operation of UC LLNL.
+
+    DISCLAIMER:
+    This work was prepared as an account of work sponsored by an agency 
+    of the United States Government.  Neither the United States 
+    Government nor the University of California nor any of their 
+    employees, makes any warranty, express or implied, or assumes any 
+    liability or responsibility for the accuracy, completeness, or 
+    usefulness of any information, apparatus, product, or process 
+    disclosed, or represents that its use would not infringe privately-
+    owned rights.  Reference herein to any specific commercial products, 
+    process, or service by trade name, trademark, manufacturer, or 
+    otherwise, does not necessarily constitute or imply its endorsement, 
+    recommendation, or favoring by the United States Government or the 
+    University of California.  The views and opinions of authors 
+    expressed herein do not necessarily state or reflect those of the 
+    United States Government or the University of California, and shall 
+    not be used for advertising or product endorsement purposes.
+--------------------------------------------------------------------------
+
diff --git a/InstallerBits/Licences/COPYING_iconv.txt b/InstallerBits/Licences/COPYING_iconv.txt
new file mode 100644
index 0000000..9dfe962
--- /dev/null
+++ b/InstallerBits/Licences/COPYING_iconv.txt
@@ -0,0 +1,482 @@
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+

+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+

+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
\ No newline at end of file
diff --git a/InstallerBits/Licences/COPYING_libxml2.txt b/InstallerBits/Licences/COPYING_libxml2.txt
new file mode 100644
index 0000000..3fa5855
--- /dev/null
+++ b/InstallerBits/Licences/COPYING_libxml2.txt
@@ -0,0 +1,8 @@
+The MIT License
+Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/InstallerBits/Licences/COPYING_nexus.txt b/InstallerBits/Licences/COPYING_nexus.txt
new file mode 100644
index 0000000..4bc8bf8
--- /dev/null
+++ b/InstallerBits/Licences/COPYING_nexus.txt
@@ -0,0 +1,515 @@
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
diff --git a/InstallerBits/Licences/COPYING_zlib.txt b/InstallerBits/Licences/COPYING_zlib.txt
new file mode 100644
index 0000000..d4cea67
--- /dev/null
+++ b/InstallerBits/Licences/COPYING_zlib.txt
@@ -0,0 +1,38 @@
+zlib License 
+License 
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.2, October 3rd, 2004
+
+  Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly jloup at gzip.org
+  Mark Adler madler at alumni.caltech.edu
+
+*/
+
+
+Click here to return to the zlib Home Page. 
+
+Last modified 3 October 2004 
+Send all questions about zlib or its license to zlib at gzip.org 
+
+      Web page copyright � 1996-2004 Greg Roelofs and Jean-loup Gailly.
+      zlib software copyright � 1995-2004 Jean-loup Gailly and Mark Adler. 
+      Primary site hosted by France Teaser.
+      zlib.org domain name donated by Andrew Green. 
diff --git a/InstallerBits/nexus.ico b/InstallerBits/nexus.ico
new file mode 100644
index 0000000..28b3098
Binary files /dev/null and b/InstallerBits/nexus.ico differ
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..0b9bdb8
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,69 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Top level Makefile for coordinating NeXus build
+#  
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#  @configure_input@
+#
+#====================================================================
+
+# so   "make test"   is the same as   "make check"
+test: check
+
+if BUILD_CONTRIB
+CONTRIB=contrib
+endif
+SUBDIRS=third_party include src bindings applications test scripts examples doc macosx_install_kit $(CONTRIB)
+
+EXTRA_DIST=build_rules.am nexus_spec.in nexus.spec autoversion.sh \
+		build_rpm.in README.cygwin README.macosx \
+		README.MinGW make_mingw_links \
+		configure_mingw_kit Windows_extra InstallerBits \
+		README.VS2008.pdf
+
+# Add any flags here that you want passed to configure when you do 
+# a "make distcheck"
+DISTCHECK_CONFIGURE_FLAGS=@CONFIGURE_ARGS@
+
+MAINTAINERCLEANFILES = \
+ ChangeLog \
+ INSTALL \
+ aclocal.m4 \
+ configure \
+ doc/tech_ref/NeXus_definitions.pdf \
+ doc/tech_ref/NeXus_definitions.txt \
+ include/nxconfig_h.in \
+ `find "$(srcdir)" -type f -name Makefile.in -print`
+
+ChangeLog :
+	touch $@
+if HAVE_SVN2CL
+	if test -d .svn; then \
+	    echo "Generating ChangeLog from svn via svn2cl"; \
+	    $(SVN2CL) --non-interactive --authors=svn2cl_nexus_authors.xml .; \
+	fi
+endif
+
+#dist-hook : ChangeLog
+
+maintainer-clean-local:
+	-rm -rf config
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e52630d
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,421 @@
+Version 4.3.0
+=============
+
+For the latest information see 
+
+    http://wiki.nexusformat.org/Nexus_43_Release_Notes
+
+
+New Features
+============
+
+* Links to external files via the NeXus external linking mechanism have now been enhanced to take advantage of native HDF5 external linking. Previously a nexus external file link was only visible to NeXus aware programs, and this will continue to be the case for XML and HDF4 based files. In the case of files created with the HDF5 underlying format, external file links will now be visible to any HDF5 (1.8.*) aware program. 
+
+* HDF5 based files can now have multiple "unlimited" dimensions (previously only one was allowed) 
+
+* New API functions have been added to handle very large arrays. Most original NeXus functions had array dimensions of type "int" which restricted the maximum size of an array. New functions with a "64" suffix have been added which use int64_t rather than int - existing functions continue to work as normal, so there is no need to update code unless you want to make use of the larger dimensions. 
+
+* A new python tree API has been added
+
+* A GUI java based NXvalidate program has now been added 
+
+* The NeXus API now ensures thread safety, even if the underlying HDF/XML library is not built that way. The current approach would not allow any concurrency in writing, but HDF5 does not support this anyway at the moment. 
+
+* A new function NXreopen() has been added which will create additional NXhandle objects from an existing NXhandle, allowing you to have several NXhandle structures referring to the same file. This can give a large performance gain if you need to write to different parts of a file as separate threads can be created with their own NXhandles, thus removing the need to open and close data groups that can lead to unnecessary flushing to disk etc. 
+
+* New application NXtraverse added 
+
+Changed Features
+================
+
+* If creating an external link you are no longer supposed to create the group beforehand. As HDF5 can handle groups natively, that is counterproductive and we would have to remove the empty group again (hoping that it is actually empty that is). It is easier to create the group in the API if required.
+* The HDF5 1.6.* series libraries are no longer supported - NeXus now requires 1.8.* or higher. The 1.6.* series is now very old and moving to 1.8.* has allowed us to make use of new and improved features, such as native external file linking (see above) 
+
+System Requirements
+===================
+
+* MXML XML Parsing Library: Version 2.2.2 or higher of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in both source and binary rpm form and is also available as part of Fedora Extras. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly. 
+
+* Python Interface: You will need both the numpy and ctypes modules to be available. These are provided in both the Fedora and EPEL repositories. 
+
+* HDF5 Version: Only the HDF5-1.8.* series (and above) is now supported. 
+
+Version 4.2.0
+=============
+
+For the latest information see 
+
+    http://wiki.nexusformat.org/Nexus_42_Release_Notes
+
+==System Requirements==
+'''MXML XML Parsing Library'''
+
+Version 2.2.2 or higher of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in [http://www.easysw.com/~mike/mxml/software.php both source and binary rpm form] and is also available as part of [http://fedoraproject.org/wiki/Extras/UsingExtras Fedora Extras]. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly.
+
+'''Python Interface'''
+You will need both the numpy and ctypes modules to be available.  These are provided in both the Fedora and EPEL repositories.
+
+==Building Notes==
+===NAG F90/F95 Compiler===
+The NAG compiler needs the '''-mismatch''' flag to be specified or else it will not compile NXmodule.f90 This is achieve by running configure with the '''FCFLAGS''' environment variable set to contain the flag e.g.
+<pre>
+env FCFLAGS="-mismatch" ./configure --with-f90=f95
+</pre>
+===HDF4 on Intel Macs===
+There is a problem with the include file, hdfi.h (normally in /usr/local/include).  See http://coastwatch.noaa.gov/helparc/software/msg00069.html for details of the modifications necessary to fix it.
+
+==New Features==
+===C++ Interface===
+See the [http://download.nexusformat.org/doxygen/html/classNeXus_1_1File.html doxygen documentation] and
+[http://svn.nexusformat.org/code/branches/4.2/test/napi_test_cpp.cxx NeXus API test program]
+
+===C++ Stream Like interface===
+The idea is to provide an IOSteam like interface and allow you to type 
+<pre>
+    // create an entry and a data item
+    File nf(fname, NXACC_CREATE);
+    nf << Group("entry1", "NXentry") << Data("dat1", w, "int_attr", 3);
+    nf.close();
+
+    File nf1(fname, NXACC_RDWR);
+    // add a double_attr to an existing setup
+    nf1 >> Group("entry1", "NXentry") >> Data("dat1") << Attr("double_attr", 6.0);
+    nf1.close();
+
+    // read back data items
+    File nf2(fname, NXACC_READ);
+    nf2 >> Group("entry1", "NXentry") >> Data("dat1", w1, "int_attr", i, "double_attr", d);
+    // alternative way to read d1
+    nf2 >> Data("dat1") >> Attr("double_attr", d1);
+</pre>
+See also the [http://svn.nexusformat.org/code/branches/4.2/test/napi_test_cpp.cxx NeXus API test program]
+
+===IDL Interface===
+There is a new interface to RSI's Interactive Data Language, IDL for NeXus. This 
+interface has to be considered beta. Nevertheless it is working most of the time. 
+Known issues include:
+* Compressed reading and writing do not work for HDF-4 files, probably because of a library version conflict on libz. 
+* There is an issue using NXgetslab on 64 bit operating systems; expect a fix for this pretty soon.
+
+===Python Interface===
+There is now, thanks to Paul Kienzle, a supported interface for the python scripting language. Arrays are stored in numpy arrays and thus allow for efficient data manipulations.
+
+==Changed Features==
+
+==Known Issues==
+See the comments on the IDL interface.
+
+==Miscellaneous bug fixes==
+The following items are bugs reported in previous releases and resolved in
+the 4.2 release.
+
+==Upcoming Features==
+
+Version 4.1.0
+=============
+
+For the latest information see 
+
+    http://wiki.nexusformat.org/Nexus_41_Release_Notes
+
+==System Requirements==
+'''MXML XML Parsing Library'''
+
+Version 2.2.2 or higher of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in [http://www.easysw.com/~mike/mxml/software.php both source and binary rpm form] and is also available as part of [http://fedoraproject.org/wiki/Extras/UsingExtras Fedora Extras]. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly.
+
+==Building Notes==
+===NAG F90/F95 Compiler===
+The NAG compiler needs the '''-mismatch''' flag to be specified or else it will not compile NXmodule.f90 This is achieve by running configure with the '''FCFLAGS''' environment variable set to contain the flag e.g.
+<pre>
+env FCFLAGS="-mismatch" ./configure --with-f90=f95
+</pre>
+===HDF4 on Intel Macs===
+There is a problem with the include file, hdfi.h (normally in /usr/local/include).  See http://coastwatch.noaa.gov/helparc/software/msg00069.html for details of the modifications necessary to fix it.
+
+==New Features==
+* New types NX_INT64 and NX_UINT64 to suppport 64 bit integers (only available in HDF5 and XML) [http://trac.nexusformat.org/code/ticket/87 details].
+* Python bindings are now included in the Windows install kit [http://trac.nexusformat.org/code/ticket/86 details]
+
+==Miscellaneous bug fixes==
+The following items are bugs reported in previous releases and resolved in
+the 4.1 release.
+* The Fortran 90 part of testsuite failed with the Absoft compiler on MacOSX (it passed with g95 and gfortran (4.2)) [http://trac.nexusformat.org/code/ticket/68 details here]
+* NXputattr assumed NULL termination of NX_CHAR attributes, which is usually the case in C but not true for JAVA. A workaround is to add '\0' manually [http://trac.nexusformat.org/code/ticket/83 bug report]
+* pkgconfig issue [http://trac.nexusformat.org/code/ticket/84 bug report]
+* Build issue with MXML-2.3 [http://trac.nexusformat.org/code/ticket/91 bug report]
+* XML buffer resizing performance issue [http://trac.nexusformat.org/code/ticket/92 bug report]
+* Documentation is now installed to "datadir" (/usr/share) [http://trac.nexusformat.org/code/ticket/93 bug report]
+
+Version 4.0.0
+=============
+
+For the latest information see 
+
+    http://wiki.nexusformat.org/Nexus_4_Release_Notes
+
+==System Requirements==
+'''MXML XML Parsing Library'''
+
+Version 2.2.2 of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in [http://www.easysw.com/~mike/mxml/software.php both source and binary rpm form] and is also available as part of [http://fedoraproject.org/wiki/Extras/UsingExtras Fedora Extras]. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly.
+
+==Building Notes==
+===NAG F90/F95 Compiler===
+The NAG compiler needs the '''-mismatch''' flag to be specified or else it will not compile NXmodule.f90 This is achieve by running configure with the '''FCFLAGS''' environment variable set to contain the flag e.g.
+<pre>
+env FCFLAGS="-mismatch" ./configure --with-f90=f95
+</pre>  
+==New Features==
+The following items are features added to the NeXus API to provide new
+functionality to the core library or to assist in the build process.
+*Extended XML-API to handle unlimited dimensions
+*Add building of Doxygen documentation
+*Add support for two dimensional character arrays (HDF4 and HDF5 only)
+*Added group attribute support to HDF4 (2006/05/02). Requires HDF4 version (???)
+*Add NXmakenamedlink (2007/01/09) to all three file formats (external linking)
+*Add NXprintlink
+*Improved link testing in test suite
+*API can now read generic HDF5 files, such as those produced by matlab
+*Add facility to enable/disable error reporting
+*New NXsummary tool for summarising contentes of a NeXus file
+*Fortran 90 API now works with gfortran 4.2 and above as well as with G95
+*PYTHON and TCL bindings provided via a [http://www.swig.org/ SWIG interface]
+*Additional NXtranslate translators: SPEC, ESRF-EDF
+
+==Changed Features==
+The following aspects of the API have changed in a potentially non-backward compatible way
+*The JAVA API now uses org.nexusformat rather than gov.anl.neutron.nexus
+
+==Known Issues==
+* The Fortran 90 part of testsuite fails with the Absoft compiler on MacOSX (it passes with g95 and gfortran (4.2)) [http://trac.nexusformat.org/code/ticket/68 details here]
+
+==Miscellaneous bug fixes==
+The following items are bugs reported in the 3.x releases and resolved for
+the 4.0 release.
+*Leading and trailing whitespace is stripped from char data on a read; this can be disabled by passing the NXACC_NOSTRIP option to NXopen
+*Fix problems with MXML (what problems?)
+*Improve test procedures when not all libraries are present
+*Correct sourcepath for javadoc
+*Updated makefiles for swig bindings (python, tcl)
+
+Changes in Version 3.0.0
+========================
+
+- GNU Autotools are now used for building the API and programs
+
+- XML files can be written by the NeXus API by specifying NXACC_XML to NXopen
+
+- The NXtoXML, NXtoNX4 and NXtoNX5 utilities have been combined into a single utility nxconvert. To make a DTD definition file use nxtodtd
+
+- New utilities nxdir and nxtranslate
+
+- g95 compiler supported by FORTRAN90 bindings. To specify another
+  compiler use the  --with-f90   option of configure
+
+Changes in Version 2.0.0
+========================
+
+- NeXus library updated to allow the reading and writing of HDF5 files
+  using the same API calls.  In creating a file, use NXACC_CREATE4 for
+  HDF4 and NXACC_CREATE5 for HDF5.  As long as both HDF4 and HDF5 
+  libraries are linked, the API will read both HDF4 and HDF5 files 
+  transparently.
+
+- The Makefiles have been reorganized to allow HDF4 and/or HDF5 files to 
+  be linked into the NeXus library, with compile and link options stored
+  in "makefile_options".
+
+- Rearranged the NeXus libraries so that libNeXus.a contains the standard
+  C and F77 interfaces and libNeXus90.a contains the C and F90 interfaces.
+
+- Added the routine NXsameID to the C interface to compare the ID of
+  NeXus groups and data sets.
+
+- Added NXtoXML and NXtoDTD, utilities that translate a NeXus file to 
+  XML, respectively with and without the data.  Note that NXtoDTD does not
+  produce a true XML DTD file.  Instead, it produces a metaDTD as defined
+  on the NeXus web pages (although it will lack proper annotation). 
+
+- Changed NXUmodule.f90 so that NXUfindaxis uses the two accepted methods
+  of defining dimension scales, i.e. adding the "axis" attribute to the
+  axis data or adding the "axes" attribute to the signal data
+
+Changes in Version 1.3.3
+========================
+
+- Added NXflush routine to flush data to the output file.
+
+- Added support for unlimited dimensions.
+
+- Used the NX_EXTERNAL macro to prefix callable NeXus functions and defined
+  this to do the appropriate DLL import/export operation on Windows.
+  README.WIN32 has been updated with instructions on how to make and
+  use a NEXUS.DLL.
+
+- NeXus errors now directed to MessageBox() in a Windows DLL.
+
+- Modified timezone selection to use difftime/gmtime method on all
+  systems except VMS 6.2 (where gmtime() always returns NULL).
+  
+- Corrected spurious overflow errors in NXGETCHARDATA.
+
+- Added some unix-style commands, e.g. ls, cd, cat, as equivalents of
+  standard commands in NXbrowse.
+
+Changes in Version 1.3.2
+========================
+
+- NXbrowse now reads a filename as command line argument and only prompts if
+  none is specified.
+
+- Added "dump <data_name> <file_name>" command to NXbrowse, which dumps a 
+  NeXus data array into an ASCII file.
+  
+- Added a toggle command to NXbrowse, called "byteaschar", which forces 
+  NX_INT8, NX_UINT8 variables to be printed as character strings.  This is 
+  for backward compatibility with files created before the definition of the
+  NX_CHAR data type.  8-byte global attributes will be treated as characters
+  when the program begins, but, after that, the default is to treat NX_INT8
+  and NX_UINT8's as integers.
+  
+- Introduced proper typecasts for dimensions in data access routines.  This 
+  is to correct problems with systems that do not have 4-byte int's.
+
+- Added in the CALLING_STYLE macro to napi.h to allow correct calling of the
+  FORTRAN interface under WINDOWS.  Corrected definition of NXcompress() on 
+  PC.
+  
+- Added README.WIN32 to distribution discussing WINDOWS-specific compilation.
+
+
+Changes in Version 1.3.1
+========================
+
+- Added NXgetgroupinfo, NXinitgroupdir, NXgetattrinfo, and NXinitattrdir
+  to the core C and F77 API's.  They were already present in the F90 API.
+
+- Updated the above routines in NXmodule.f90 so that they called the C
+  versions directly.  This removes the need for the F90 code to know the
+  internal details of the NXhandle C struct.
+
+- Released a new version of NXbrowse written in ISO C.  It is the version
+  that is now installed with the "make NXbrowse" command (on unix systems).
+  The ordering of array indices uses the C convention i.e. it is reversed
+  from the original F90 version.
+
+- Corrected the calculation of time zone offsets when compiled by
+  Metrowerks CodeWarrior for PowerPC Macs.
+
+Changes in Version 1.3.0
+========================
+
+- Added NXcompress to the C, F77, and F90 API's. Compression works only with
+  Release 3 of the HDF-4.1 libraries or better. Note: on my DigitalUnix 4.0D
+  installation I had to link against the jpeg library supplied with HDF 
+  directly due to a conflict with a system shared library. Replace -ljpeg
+  by $HDFROOT/lib/libjpeg.a.
+
+- Added NXUsetcompress to F90 utility API to set default compression 
+  parameters, and added call to NXcompress in NXUwritedata.
+
+- Changed attribute arguments in the F90 routine NXUwriteglobals to optional. 
+
+Changes in Version 1.2.1
+========================
+
+- Released NeXus API under the terms of the GNU Lesser General Public
+  License.
+
+Changes in Version 1.2.0
+========================
+
+- NXGETCHARDATA, NXGETCHARATTR, NXPUTCHARDATA and NXPUTCHARATTR added 
+  to Fortran 77 interface to correct problems with handling character data 
+  and attributes.
+
+- Reversed dimension order and adjusted starting indices in NXGETSLAB 
+  and NXPUTSLAB in Fortran 77 interface for improved compatibility with the 
+  C interface.
+
+- All SDSes created with the DFTAG_NDG tag, rather than DFTAG_SDG,
+  which is now deprecated by HDF.
+
+- Expanded number of NeXus routines and data types checked by the test 
+  programs "napi_test.c", "napif_test.f" and "NXtest.f90". 
+  
+- Excluded null terminator from string length check in REPLACE_STRING to
+  prevent error messages when the string is exactly the right length.
+
+- Added definitions of NX_MAXRANK (max. no. of dataset dimensions = 32) to 
+  and NX_MAXNAMELEN (max. length of dataset name = 64) to header files.
+
+- Made NXIReportError globally visible.
+
+- Improved determination of local time zone when writing the global file
+  attribute "file_time".
+
+- Added option to NXbrowse.f90 to allow display of individual array elements
+  of the specified index.
+
+- Added check for __ABSOFT macro in "napi.h" to make compatible with 
+  Absoft Pro Fortran for Linux.
+
+- Add __stdcall definition to C prototypes under WIN32 so they can link 
+  to FORTRAN. 
+
+Changes in Version 1.1.0
+========================
+
+- First appearance of the Fortran 90 API.
+
+- Added reading and writing of non-character attributes to the Fortran 77 
+  interface.
+
+- Corrected problems with linking groups by making NXgetgroupID 
+  and NXmakelink use the HDF tag/ref pair in NXlink structures.
+
+- Added VMS build file MAKE_VMS.COM.
+
+- Added NEXUS_VERSION CHARACTER constant to NAPIF.INC, with value as defined 
+  in napi.h.
+
+- Made the Fortran 77 interface treat both NX_UINT8 and NX_CHAR as strings, for
+  consistency with the C implementation and also for backward compatability 
+  reasons.
+
+- Fixed memory leak on Fortran 77 side on NXclose.
+
+- NXdict added to the normal distribution.
+
+- Added casts to HDF API calling parameters to eliminate type-mismatch
+  compiler warnings.
+
+- Modified time creation functions to handle non-working gmtime()
+  function on VMS 6.2. 
+
+
+Changes in Version 1.0.0
+========================
+
+- Reversed array dimensions on going from C to FORTRAN, so that the 
+  "fastest varying index" is kept consistent.
+
+- Incorporated fixes suggested by Markus Zolliker (markus.zolliker at psi.ch)
+  for the following problems with the FORTRAN interface:
+
+  (1) NXopen ends with a "Segmentation fault" if the file is not HDF.
+  (2) NXgetentry gives an error message when NAME and CLASS are not
+    initialised to blank.
+
+- Changed "data" from char* to void* in NXgetattr.
+
+- Changed value for NXACC_CREATE to be DFACC_CREATE rather than DFACC_ALL
+  in NAPIF.INC for consistency with C interface.
+
+- Added the following global attributes :
+  NeXus_version - updated whenever a file is opened "read/write", so it
+                  will always contain the latest version of the interface
+                  the file was written with
+  file_name     - set on file creation, then left unchanged
+  file_time     - set on file creation, then left unchanged
+
+$Id$
diff --git a/README b/README
new file mode 100644
index 0000000..9ab5b41
--- /dev/null
+++ b/README
@@ -0,0 +1,46 @@
+-------------------------------------------------------------------------
+NeXus - a common format for neutron and X-ray scattering data
+             http://www.nexusformat.org/
+-------------------------------------------------------------------------
+
+See COPYING file for licence information
+
+Installation Instructions
+=========================
+
+Unix (including Mac OS X) source distribution
+---------------------------------------------
+
+If you have downloaded a source distribution (e.g. nexus-4.3.0.tar.gz) then you will already have a file called "configure" and the basic sequence to follow is:
+
+    ./configure  # use    sh ./configure    if this does not work
+    make
+    make check
+    make install
+
+this may not, however, build all the nexus utilities and binding you require, and may also locate the wrong HDF libraries and final installation directory. Thus you will probably need to pass some options to "configure" to control this.
+
+General information about "configure" is located in the file called INSTALL
+
+To see a list of possible options type
+
+    ./configure --help
+
+HDF libraries used by nexus are available via your system software package manager or can be downloaded from http://www.hdfgroup.org/
+
+A typical run of configure might be:
+
+    ./configure --prefix=/usr/local/nexus --with-hdf5=/usr/local/hdf5
+
+Unix (including Mac OS X) svn checkout
+--------------------------------------
+
+As the "configure" file mentioned is a generated file, it is not included in the version control checkout. To create it run:
+
+   sh autogen.sh
+
+and then follow the same procedure as above. You may also want to look at the README.developers file
+
+----------------------------------------------------------------------------
+
+$Id$
diff --git a/README.FORTRAN b/README.FORTRAN
new file mode 100644
index 0000000..e2d6dcc
--- /dev/null
+++ b/README.FORTRAN
@@ -0,0 +1,86 @@
+The NAPI FORTRAN interface consists of wrapper routines (napif.f) and
+an include file of definitions (napif.inc). The routines are called
+exactly like their C counterparts, but the setup for NXHandle
+and NXlink structures is done slightly differently (see the
+example program "napif_test.f")
+
+For a NXhandle, you use:
+
+    INTEGER FILEID(NXHANDLESIZE)
+
+And for an NXlink
+
+    INTEGER LINK(NXLINKSIZE)
+
+--- Running the Examples ---
+
+The Fortran 77 library is now built by the standard Makefile. See the 
+README file for installation instructions.
+   
+The test program, napif_test, should print the following:
+
+ Number of global attributes:  4
+    NeXus_version = 2.0.0.
+    file_name = NXtest.nxs
+    HDF5_Version = 1.4.3
+    file_time = 2002-05-17 14:40:24-0600
+ Group: entry(NXentry) contains  8 items
+    ch_data( 4)
+    Values : NeXus data
+    Subgroup: data(NXdata)
+    i1_data(20)
+    Values :   1  2  3  4
+    i2_data(22)
+    Values :   1000  2000  3000  4000
+    i4_data(24)
+    Values :      1000000     2000000     3000000     4000000
+    r4_data( 5)
+    Values :    1.00   2.00   3.00   4.00
+           :    5.00   6.00   7.00   8.00
+           :    9.00  10.00  11.00  12.00
+           :   13.00  14.00  15.00  16.00
+           :   17.00  18.00  19.00  20.00
+    r8_data( 6)
+    Values :    1.00   2.00   3.00   4.00
+           :    5.00   6.00   7.00   8.00
+           :    9.00  10.00  11.00  12.00
+           :   13.00  14.00  15.00  16.00
+           :   17.00  18.00  19.00  20.00
+       ch_attribute : NeXus
+       i4_attribute :    42
+       r4_attribute :   3.141593
+    Subgroup: sample(NXsample)
+ Link Check OK
+
+A file called "NXtest.nxs" is also created.
+
+*** FORTRAN Interface Notes ***
+
+- NAPIF.F uses the non-standard type specification BYTE to convert Fortran
+  character data to C strings.  There is no method of specifying single-byte
+  storage under the Fortran 77 standard, but if the BYTE specification is 
+  not allowed by your Fortran compiler, please try one of the other common
+  compiler extensions, e.g., INTEGER*1, LOGICAL*1.
+
+- There are separate routines for reading and writing character data
+  and attributes (NXGETCHARDATA, NXGETCHARATTR, NXPUTCHARDATA, NXPUTCHARATTR).
+  This is necessary because character strings are passed by descriptor rather
+  than by reference.
+
+- If you don't wish to use these routines, it is possible to pass character
+  data to the C interface using the regular routines (i.e. NXGETDATA etc) 
+  by forcing the string arguments to be passed by reference.  Either 
+  equivalence the string to a BYTE array or use the %REF (or equivalent) 
+  function.  It does not appear to be necessary to null-terminate the strings
+  since the string length, passed to the HDF file, does not include the 
+  terminator.
+
+--
+Freddie Akeroyd
+ISIS Facility
+Rutherford Appleton Laboratory
+Chilton, Didcot, OX11 OQX, GB
+
+Email: Freddie.Akeroyd at rl.ac.uk
+
+$Id$
diff --git a/README.FORTRAN90 b/README.FORTRAN90
new file mode 100755
index 0000000..6745015
--- /dev/null
+++ b/README.FORTRAN90
@@ -0,0 +1,95 @@
+The NeXus Fortran 90 interface consists of a single Fortran 90 module
+containing all the global parameters and function definitions. The
+routines are called exactly like their C counterparts, although some
+arguments have been made optional because their values can be determined
+automatically.  See <http://www.neutron.anl.gov/NeXus/NeXus_F90.html>
+for details of the individual routines.
+
+There must be a USE statement to incorporate the NeXus module e.g.
+
+   use NXmodule
+   
+(N.B. if the F90 utility module NXUmodule is USEd, it is not necessary
+to specify NXmodule as well.)
+
+The Fortran 90 interface uses two derived types for the NXhandle and
+NXLink structures.
+
+    type(NXhandle) :: file_id
+    type(NXlink) :: link_id
+
+There are also several KIND parameters defined for producing
+different-length storage.  They are not guaranteed to produce the
+required result, but should work on most Fortran 90 compilers.
+
+    NXi1 - one-byte integers
+    NXi2 - two-byte integers
+    NXi4 - four-byte integers
+    NXr4 - four-byte floating points
+    NXr8 - eight-byte floating points (double precision)
+    
+There is no way of distinguishing signed and unsigned integers, so
+unsigned integers are mapped to signed integers of the same length.  It
+is possible to read variables into arrays of different storage size,
+provided there is no overflow.
+
+--- Compatibility Issues ---
+
+This version has been tested on Alpha/VMS, Windows NT, Linux, and Mac
+OS X (using Absoft Pro Fortran 90).  In the latest versions of the API
+(after v 1.3.1), the Fortran 90 code does not require access to the 
+internal details of the NXhandle structure.
+
+--- Running the Examples ---
+
+The Fortran 90 library is now built by the standard Makefile with the
+following option
+
+   make libf90
+   
+See the README file for further instructions.
+
+The Fortran 90 test program, NXtest, should print the following:
+
+ Number of global attributes:   4
+    NeXus_version = 2.0.0.
+    file_name = NXtest.nx5
+    HDF5_Version = 1.4.3
+    file_time = 2002-05-17 15:22:29
+ Group: entry(NXentry) contains   8 items
+    ch_data : NX_CHAR   
+    Values : NeXus data          
+    Subgroup: data(NXdata)
+    i1_data : NX_INT8   
+    Values :   1  2  3  4
+    i2_data : NX_INT16  
+    Values :   1000  2000  3000  4000
+    i4_data : NX_INT32  
+    Values :   1000000  2000000  3000000  4000000
+    r4_data : NX_FLOAT32
+    Values :   1.00000  2.00000  3.00000  4.00000
+           :   5.00000  6.00000  7.00000  8.00000
+           :   9.00000  10.0000  11.0000  12.0000
+           :   13.0000  14.0000  15.0000  16.0000
+           :   17.0000  18.0000  19.0000  20.0000
+    r8_data : NX_FLOAT64
+    Values :   1.00000  2.00000  3.00000  4.00000
+           :   5.00000  6.00000  7.00000  8.00000
+           :   9.00000  10.0000  11.0000  12.0000
+           :   13.0000  14.0000  15.0000  16.0000
+           :   17.0000  18.0000  19.0000  20.0000
+    ch_attribute : NeXus               
+    i4_attribute :   42
+    r4_attribute :   3.14159
+    Subgroup: sample(NXsample)
+ Link Check OK
+
+--
+Ray Osborn
+Materials Science Division
+Argonne National Laboratory
+Argonne, IL 60439-4845, USA
+
+Email: ROsborn at anl.gov
+
+$Id$
diff --git a/README.MinGW b/README.MinGW
new file mode 100644
index 0000000..3fa3ff3
--- /dev/null
+++ b/README.MinGW
@@ -0,0 +1,54 @@
+Install MinGW from http://www.mingw.org/ using the MINGW installer -
+I used MinGW-5.0.2.exe and installed the "current" binaries. As you need
+to install MSYS later on, DO NOT install MINGW make.
+
+Now download the MSYS installer (I used MSYS-1.0.10.exe) and also the MSYS developer toolkit (msysDTK-1.0.1.exe in my case) from the MinGW downloads page and install. You also need to install mingw-utils (for the pexports command), which you download as a .tar.gz file and then unpack to your c:/MinGW directory
+
+Start MSYS, unpack the nexus distribution and edit the file "make_mingw_links" in the top directory as instructed within it; then run it 
+
+If you wish a Microsoft compatible import library (.LIB file that references a DLL) to also be built, you need to make sure the LIB command is available in your MinGW path. Type LIB at the MSYS prompt now to check if this is so.
+
+Edit applications/NXtranslate/text_xml/Makefile.am and 
+applications/NXtranslate/Makefile.am and in both replace
+`xml2-config --cflags`  with  -I/usr/local/include in  AM_CPPFLAGS
+
+Now just type
+
+  ./configure
+  make
+  make check
+  make install
+
+To build the JAVA interface with gcj you need to pass the JAVA home
+directory to configure. If your gcj command is  /mingw/bin/gcj  then use
+
+  ./configure --with-java-home=/mingw
+
+If you get a compile error about redeclaration of ssize_t when including the HDF5 header, you need to edit /usr/local/hdf5/include/H5pubconf.h and change the definition of H5_SIZEOF_SSIZE_T to e.g.
+
+#define H5_SIZEOF_SSIZE_T  4 /* for 32 bit machines */
+
+
+After building and installing you should get
+
+${prefix}/lib/libNeXus.a       : static library
+${prefix}/lib/libNeXus.dll.a   : import library for libNeXus-0.dll
+${prefix}/bin/libNeXus-0.dll   : NeXus shared library
+${prefix}/bin/libNeXus-0.dll.lib : MS compatible import library for libNeXus-0.dll (only built if you have ther LIB command in your path)
+
+
+Enjoy!
+
+
+
+Use libtool 1.5 but note it has problems as MinGW does not ship the unix "file" command so you get "file magic" errors
+
+to remedy, install  file.MinGW   as /usr/local/bin/file and chmod +x it
+
+also rename libmxml.a as libmxml.dll.a
+
+Freddie Akeroyd (F.A.Akeroyd at rl.ac.uk)
+
+--
+
+$Id$
diff --git a/README.VS2008.pdf b/README.VS2008.pdf
new file mode 100644
index 0000000..007ec80
Binary files /dev/null and b/README.VS2008.pdf differ
diff --git a/README.cmake b/README.cmake
new file mode 100644
index 0000000..e69de29
diff --git a/README.cygwin b/README.cygwin
new file mode 100644
index 0000000..a588553
--- /dev/null
+++ b/README.cygwin
@@ -0,0 +1,17 @@
+The NeXus source code should build under cygwin, but note that
+HDF4 may not work (HDF5 and XML are fine). When building the HDF5
+library you may want to specify an explicit prefix for the 
+install location e.g.
+
+    ./configure --prefix=/usr/local/hdf5  # for building HDF5
+
+Otherwise you will need to configure NeXus with
+
+    ./configure --with=hdf5=/path/to/where/hdf5/went  # for building NeXus
+
+or it will not be able to locate the HDF5 libraries.
+
+Alternatively there is a native Windows kit available
+from http://download.nexusformat.org/kits/windows that supports
+HDF4/HDF5/XML and building applications under both Visual Studio
+and MinGW
diff --git a/README.developers b/README.developers
new file mode 100644
index 0000000..fbcc0f3
--- /dev/null
+++ b/README.developers
@@ -0,0 +1,79 @@
+Initial Setup
+-------------
+
+You first need to type:
+
+    sh autogen.sh
+
+to generate the initial configure and *.in files. You only need to 
+type this again if you upgrade you system's versions of 
+libtool/automake/autoconf and wish to use these newer version for the build
+
+After doing this type:
+
+    ./configure
+
+For a full list of options that can be passed to configure type:
+
+    ./configure --help
+
+(typical configure options include the choice of compiler, enabling or
+ disabling creation of bindings and the location of HDF libraries)
+
+General Building
+----------------
+
+Just typing
+
+    make
+
+should be enough to build the NeXus libraries and executables from source. 
+Make will automatically re-run configure if it needs to.
+The test programs can then be run with
+
+    make check
+
+and everything installed onto the local system with
+
+    make install
+
+Making a distribution kit
+-------------------------
+
+To generate a *.tar.gz distribution kit just type:
+
+    make distcheck
+
+If you need to pass arguments to "configure" during the distcheck process,
+you must add these to the DISTCHECK_CONFIGURE_FLAGS variable in Makefile.am
+
+To generate an RPM install kit see README.rpm
+
+Also see README.versions for setting nexus release versions
+
+If you have problems
+--------------------
+
+If  autogen.sh  reports errors, it may be that you need
+to install/upgrade your versions of autoconf, automake and libtool.
+Source for these can be obtained from:
+
+ftp://ftp.gnu.org/gnu/autoconf
+ftp://ftp.gnu.org/gnu/automake
+ftp://ftp.gnu.org/gnu/libtool
+
+Most likely it will be autoconf that will need updating - NeXus
+now requires autoconf 2.61 or above
+
+NeXus Developer Mailing Lists
+-----------------------------
+
+SVN commit/log messages are automatically sent to the nexus-code-svn at nexusformat.org mailing list - if you wish to receive these, subscribe to the list via the link
+
+  http://lists.nexusformat.org/mailman/listinfo/nexus-code-svn
+
+Any general questions should be directed to nexus at nexusformat.org list - you can subscribe to this via the link
+
+  http://lists.nexusformat.org/mailman/listinfo/nexus
+
+$Id$
diff --git a/README.macosx b/README.macosx
new file mode 100644
index 0000000..871f4d8
--- /dev/null
+++ b/README.macosx
@@ -0,0 +1,8 @@
+If you compile libmxml from source you may need to run
+
+    ranlib /usr/local/lib/libmxl.a
+
+Before NeXus will link to it
+
+--
+$Id$
diff --git a/README.rpm b/README.rpm
new file mode 100644
index 0000000..61ab548
--- /dev/null
+++ b/README.rpm
@@ -0,0 +1,45 @@
+Unless you plan to build the rpm files as root you will need to do the
+following:
+
+(1) Create a   ~/.rpmmacros   file with a line similar to the following
+
+%_topdir	/home/faa/mybuilds
+
+(note: that is a tab separating the two parts)
+
+(2) create the corresponding RPM build directories
+
+    cd /home/faa/mybuilds
+    mkdir BUILD RPMS SOURCES SPECS SRPMS
+    cd RPMS
+    mkdir i386 i486 i586 i686
+
+(i.e. this should look like the default build area /usr/src/redhat)
+
+(3) Now you should be able to run the  build_rpm  script - this
+    will generate src and binary rpms from the current 
+    nexus*.tar.gz created from the last "make distcheck" or "make dist"
+
+(4) The above will generate both a src and binary (probably i386) rpm
+    You can always generate a binary rpm from a source rpm using e.g.
+
+        rpmbuild --rebuild nexus-2.0.0-1.src.rpm
+
+    While re-building files will be copied to a
+    temporary installation directory structure under /tmp/nexus-2.0.0
+    You may change this location using the  --buildroot  option, but
+    be very careful as the "build root" may ultimately get removed by rpm.
+    In particular, DO NOT give "/" as the build root.
+
+    If you want the final files installed in a different directory to
+    the defaults (/usr/local/{bin,lib,nexus}), get/build the binary rpm 
+    and then use the  rpm --prefix  installation option e.g.
+
+        rpm -ivh --prefix /opt nexus-2.0.0-1.i386.rpm
+
+    will install the files to /opt/{bin,lib,nexus}
+
+Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+2004/02/22
+
+$Id$
diff --git a/README.versions b/README.versions
new file mode 100644
index 0000000..f719739
--- /dev/null
+++ b/README.versions
@@ -0,0 +1,4 @@
+To increment the NeXus version you need to:
+- change the argument to AC_INIT in configure.ac
+- update NEXUS_VERSION in include/napi.h
+- change version number printed in test output contained in test/testsuite.at
diff --git a/Windows_extra/include/nxconfig.h b/Windows_extra/include/nxconfig.h
new file mode 100644
index 0000000..29d9a5e
--- /dev/null
+++ b/Windows_extra/include/nxconfig.h
@@ -0,0 +1,200 @@
+/* include/nxconfig.h.  Generated from nxconfig_h.in by configure.  */
+/* include/nxconfig_h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 0
+
+/* Define to 1 if you have the `df' library (-ldf). */
+/* #undef HAVE_LIBDF */
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+/* #undef HAVE_LIBDL */
+
+/* Define to 1 if you have the `hdf5' library (-lhdf5). */
+/* #undef HAVE_LIBHDF5 */
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+/* #undef HAVE_LIBJPEG */
+
+/* Define to 1 if you have the `m' library (-lm). */
+/* #undef HAVE_LIBM */
+
+/* Define to 1 if you have the `mfhdf' library (-lmfhdf). */
+/* #undef HAVE_LIBMFHDF */
+
+/* Define to 1 if you have the `rpc' library (-lrpc). */
+/* #undef HAVE_LIBRPC */
+
+/* Define to 1 if you have the `SystemStubs' library (-lSystemStubs). */
+/* #undef HAVE_LIBSYSTEMSTUBS */
+
+/* Define to 1 if you have the `sz' library (-lsz). */
+#define HAVE_LIBSZ 1
+
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+#define HAVE_LIBXML2 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "nexus"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "nexus-developers at nexusformat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "NeXus Library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "NeXus Library trunk_r1077"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "nexus"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "trunk_r1077"
+
+/* Set to printf format for int64_t */
+#define PRINTF_INT64 "I64d"
+
+/* Set to printf format for uint64_t */
+#define PRINTF_UINT64 "I64u"
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long int', as computed by sizeof. */
+#define SIZEOF_LONG_INT 4
+
+/* The size of `long long int', as computed by sizeof. */
+#define SIZEOF_LONG_LONG_INT 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Version number of package */
+#define VERSION "trunk_r1077"
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to the type of a signed integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+#define int16_t short
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+#define int32_t int
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+typedef INT64 int64_t; 
+
+/* Define to the type of a signed integer type of width exactly 8 bits if such
+   a type exists and the standard includes do not define it. */
+#define int8_t char
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+#define uint16_t unsigned short
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+#define uint32_t unsigned
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+typedef UINT64 uint64_t; 
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+   such a type exists and the standard includes do not define it. */
+#define uint8_t unsigned char
diff --git a/Windows_extra/libNeXus-0-Win32.def b/Windows_extra/libNeXus-0-Win32.def
new file mode 100644
index 0000000..505b70a
--- /dev/null
+++ b/Windows_extra/libNeXus-0-Win32.def
@@ -0,0 +1,124 @@
+LIBRARY libNeXus-0.dll
+EXPORTS
+_NXICLOSE at 4
+_NXICLOSEDATA at 4
+_NXICLOSEGROUP at 4
+_NXICOMPMAKEDATA at 28
+_NXICOMPRESS at 8
+_NXIFCLOSE at 4
+_NXIFCOMPMAKEDATA at 28
+_NXIFCOMPRESS at 8
+_NXIFFLUSH at 4
+_NXIFLUSH at 4
+_NXIFMAKEDATA at 20
+_NXIFOPEN at 12
+_NXIFPUTATTR at 20
+_NXIFREE at 4
+_NXIGETATTR at 20
+_NXIGETATTRINFO at 8
+_NXIGETDATA at 8
+_NXIGETDATAID at 8
+_NXIGETGROUPID at 8
+_NXIGETGROUPINFO at 16
+_NXIGETINFO at 16
+_NXIGETRAWINFO at 16
+_NXIGETNEXTATTR at 16
+_NXIGETNEXTENTRY at 16
+_NXIGETSLAB at 16
+_NXIINITATTRDIR at 4
+_NXIINITGROUPDIR at 4
+_NXIMAKEDATA at 20
+_NXIMAKEGROUP at 12
+_NXIMAKELINK at 8
+_NXIMAKENAMEDLINK at 12
+_NXIMALLOC at 16
+_NXIOPEN at 12
+_NXIOPENDATA at 8
+_NXIOPENGROUP at 12
+_NXIOPENGROUPPATH at 8
+_NXIOPENPATH at 8
+_NXIOPENSOURCEGROUP at 4
+_NXIPUTATTR at 20
+_NXIPUTDATA at 8
+_NXIPUTSLAB at 16
+NXIReportError
+_NXISAMEID at 12
+_NXISETCACHE at 4
+_NXISETNUMBERFORMAT at 12
+NXIprintlink
+NXMDisableErrorReporting
+NXMEnableErrorReporting
+NXMGetError
+NXMSetError
+NXMSetTError
+createNXDataset
+createTextNXDataset
+dropNXDataset
+getNXDatasetByteLength
+getNXDatasetDim
+getNXDatasetLength
+getNXDatasetRank
+getNXDatasetText
+getNXDatasetType
+getNXDatasetValue
+getNXDatasetValueAt
+nxiclose_
+nxiclosedata_
+nxiclosegroup_
+nxicompmakedata_
+nxicompmakedata64_
+nxicompress_
+nxifclose_
+nxifcompmakedata_
+nxifcompress_
+nxifflush_
+nxiflush_
+nxifmakedata_
+nxifopen_
+nxifputattr_
+nxifree_
+nxigetattr_
+nxigetattrinfo_
+nxigetdata_
+nxigetdataid_
+nxigetgroupid_
+nxigetgroupinfo_
+nxigetrawinfo_
+nxigetrawinfo64_
+nxigetinfo_
+nxigetinfo64_
+nxigetnextattr_
+nxigetnextentry_
+nxigetslab_
+nxigetslab64_
+nxiinitattrdir_
+nxiinitgroupdir_
+nxiinquirefile_
+nxiisexternalgroup_
+nxilinkexternal_
+nximakedata_
+nximakedata64_
+nximakegroup_
+nximakelink_
+nximakenamedlink_
+nximalloc_
+nximalloc64_
+nxiopen_
+nxiopendata_
+nxiopengroup_
+nxiopengrouppath_
+nxiopenpath_
+nxiopensourcegroup_
+nxiputattr_
+nxiputdata_
+nxiputslab_
+nxiputslab64_
+nxisameid_
+nxisetcache_
+nxisetnumberformat_
+putNXDatasetValue
+putNXDatasetValueAt
+nxigetpath_
+nxilinkexternaldataset_
+nxiisexternaldataset_
+nxireopen_
diff --git a/Windows_extra/libNeXus-0-x64.def b/Windows_extra/libNeXus-0-x64.def
new file mode 100644
index 0000000..26925e9
--- /dev/null
+++ b/Windows_extra/libNeXus-0-x64.def
@@ -0,0 +1,80 @@
+LIBRARY libNeXus-0.dll
+EXPORTS
+NXIReportError
+NXIprintlink
+NXMDisableErrorReporting
+NXMEnableErrorReporting
+NXMGetError
+NXMSetError
+NXMSetTError
+createNXDataset
+createTextNXDataset
+dropNXDataset
+getNXDatasetByteLength
+getNXDatasetDim
+getNXDatasetLength
+getNXDatasetRank
+getNXDatasetText
+getNXDatasetType
+getNXDatasetValue
+getNXDatasetValueAt
+nxiclose_
+nxiclosedata_
+nxiclosegroup_
+nxicompmakedata_
+nxicompmakedata64_
+nxicompress_
+nxifclose_
+nxifcompmakedata_
+nxifcompress_
+nxifflush_
+nxiflush_
+nxifmakedata_
+nxifopen_
+nxifputattr_
+nxifree_
+nxigetattr_
+nxigetattrinfo_
+nxigetdata_
+nxigetdataid_
+nxigetgroupid_
+nxigetgroupinfo_
+nxigetrawinfo_
+nxigetrawinfo64_
+nxigetinfo_
+nxigetinfo64_
+nxigetnextattr_
+nxigetnextentry_
+nxigetslab_
+nxigetslab64_
+nxiinitattrdir_
+nxiinitgroupdir_
+nxiinquirefile_
+nxiisexternalgroup_
+nxilinkexternal_
+nximakedata_
+nximakedata64_
+nximakegroup_
+nximakelink_
+nximakenamedlink_
+nximalloc_
+nximalloc64_
+nxiopen_
+nxiopendata_
+nxiopengroup_
+nxiopengrouppath_
+nxiopenpath_
+nxiopensourcegroup_
+nxiputattr_
+nxiputdata_
+nxiputslab_
+nxiputslab64_
+nxisameid_
+nxisetcache_
+nxisetnumberformat_
+putNXDatasetValue
+putNXDatasetValueAt
+nxigetpath_
+nxilinkexternaldataset_
+nxiisexternaldataset_
+nxireopen_
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..73f7b3c
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,496 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#
+#  Local autoconf m4 macros - these used by configure.ac
+#  and automatically added to aclocal.m4 by running the "aclocal"
+#  command (a separate file is needed becausle automake needs to
+#  add extra stuff to aclocal.m4 as well)
+#  
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+# AC_CHECK_COMPILER_OPTION tests for a given compiler option; we need to egrep
+# the output as well as check the status as sometimes the compiler 
+# will return success for invalid options
+#
+# Argument 1 is printed and is the real name of the language
+# Argument 2 must be "Fortran 77" or "C" (language to "Push")
+# Argument 3 must be FFLAGS or CFLAGS as appropriate for argument 2
+# Argument 4 is the compiler option to check
+# Argumnet 5 is any extra program body for the test program
+#
+AC_DEFUN(
+ [AC_CHECK_COMPILER_OPTION],
+ [AC_MSG_CHECKING([for $1 compiler option $4])
+  AC_LANG_PUSH($2)
+  COMPFLAGS_SAVE=[$]$3
+  ac_compile="$ac_compile >check_compiler_option.$$ 2>&1"
+  $3="[$]$3 $4"
+  AC_COMPILE_IFELSE(
+    [AC_LANG_PROGRAM(,[$5])],
+    [COMPILER_OPTION=yes],
+    [COMPILER_OPTION=no]) 
+  if test $COMPILER_OPTION = "yes"; then
+    if test `$EGREP "[Uu]nrecogni[sz]ed|[Uu]nknown|[Ii]nvalid|[Ee]rror" check_compiler_option.$$ | wc -l` -gt 0; then COMPILER_OPTION="no"; fi
+  fi
+  if test $COMPILER_OPTION = "yes"; then
+    AC_MSG_RESULT([yes])
+  else
+    AC_MSG_RESULT([no])
+    $3=$COMPFLAGS_SAVE
+  fi
+  rm -f check_compiler_option.$$
+  AC_LANG_POP($2)]
+)
+#
+# AC_CHECK_C_OPTION
+#
+AC_DEFUN(
+ [AC_CHECK_C_OPTION],
+ [AC_CHECK_COMPILER_OPTION(C,C,CFLAGS,[$1],[$2])]
+)
+#
+# AC_CHECK_CPP_OPTION
+#
+AC_DEFUN(
+ [AC_CHECK_CPP_OPTION],
+ [AC_CHECK_COMPILER_OPTION(C,C,CPPFLAGS,[$1],[$2])]
+)
+#
+# AC_CHECK_F77_OPTION
+#
+AC_DEFUN(
+ [AC_CHECK_F77_OPTION],
+ [AC_CHECK_COMPILER_OPTION(Fortran 77,Fortran 77,FFLAGS,[$1],[$2])]
+)
+#
+# AC_CHECK_F90_OPTION
+# We use the F77 test, but switch the name of the compiler
+#
+AC_DEFUN(
+ [AC_CHECK_F90_OPTION],
+ [F77_SAVE=[$]F77
+  FFLAGS_SAVE=[$]FFLAGS
+  F77=[$]F90
+  FFLAGS=[$]F90FLAGS
+  AC_CHECK_COMPILER_OPTION(Fortran 90,Fortran 77,FFLAGS,[$1],[$2])
+  F77=[$]F77_SAVE
+  FFLAGS=[$]FFLAGS_SAVE
+ ]
+)
+
+AC_DEFUN([LINUX_DISTRIBUTION],
+[
+	AC_REQUIRE([AC_CANONICAL_TARGET])
+	DISTRIBUTION=""
+	case "$target" in
+		i[[3456]]86-*-linux-* | i[[3456]]86-*-linux)
+			if test -f /etc/lsb-release ; then
+				DISTRIBUTION=`(. /etc/lsb-release; echo $DISTRIB_DESCRIPTION)`
+			fi
+			if test -z "$DISTRIBUTION"; then
+				for i in /etc/*-release; do
+				    if test "$i" != lsb-release; then DISTRIBUTION=`cat $i | head -1`; fi
+				done
+			fi
+			;;
+	esac
+	if test -z "$DISTRIBUTION"; then DISTRIBUTION="Unknown"; fi
+	AC_SUBST([DISTRIBUTION])
+])
+
+# AC_CHECK_ROOT
+#
+# $1 = name of arg
+# $2 = root variable name to set
+# $3 = list of root paths to try. If the path is a file, assume it is 
+#                                 path/bin/files and then work out path
+# $4 = file in path to locate
+# $5 = default withval
+#
+# e.g. AC_CHECK_ROOT([tcl],[TCLROOT],[/usr /usr/local],[include/tcl.h])
+#
+AC_DEFUN(
+  [AC_CHECK_ROOT],
+  [ $2=""
+    AC_SUBST([$2])
+    AC_ARG_WITH([$1],
+	AC_HELP_STRING([--with-$1=/path/to/$1_install_directory],
+                       [Specify absolute path to root of $1 install directory.]),
+	[if test x$withval != xno -a x$withval != xyes; then $2=$withval; fi], 
+        [with_$1=$5])
+    if test x$with_$1 != xno; then
+        AC_MSG_CHECKING(for $1 root installation directory)
+# if --with secified a file, assume it is ROOT/bin/file
+	if test x[$]$2 != x; then
+	    if test -f [$]$2; then
+		$2=`dirname [$]$2`/..
+	    fi
+	fi
+# $2 should now either be empty or a valid possible root
+        for i in $3; do
+	    if test x[$]$2 = x -a -r $i/$4; then $2=$i; fi
+        done
+        if test x[$]$2 = x; then 
+	    AC_MSG_RESULT(unknown)
+        else 
+	    AC_MSG_RESULT([$]$2)
+        fi
+    fi
+  ])
+
+AC_DEFUN([AC_CHECK_PYTHON_MODULE],
+[
+    if test -z "$PYTHON"; then PYTHON="python"; fi
+    AC_MSG_CHECKING(for python module $1)
+    $PYTHON -c "import $1" 2>/dev/null
+    if test $? -eq 0; then
+        eval PYTHON_$1=1
+        eval PYTHON_$1_found="yes"
+        AC_MSG_RESULT(found)
+    else
+        eval PYTHON_$1=0
+        eval PYTHON_$1_found="no"
+        AC_MSG_RESULT(not found)
+    fi
+    AC_SUBST(PYTHON_$1)
+])
+
+# http://ac-archive.sourceforge.net/ac-archive/ac_prog_java_works.html
+
+AC_DEFUN([AC_PROG_JAVA_WORKS], [
+AC_CHECK_PROG(uudecode, uudecode$EXEEXT, yes)
+if test x$uudecode = xyes; then
+AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [
+dnl /**
+dnl  * Test.java: used to test if java compiler works.
+dnl  */
+dnl public class Test
+dnl {
+dnl
+dnl public static void
+dnl main( String[] argv )
+dnl {
+dnl     System.exit (0);
+dnl }
+dnl
+dnl }
+cat << \EOF > Test.uue
+begin-base64 644 Test.class
+yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE
+bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51
+bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s
+YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG
+aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB
+AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB
+AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ=
+====
+EOF
+if uudecode$EXEEXT Test.uue; then
+        ac_cv_prog_uudecode_base64=yes
+else
+        echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC
+        echo "configure: failed file was:" >&AC_FD_CC
+        cat Test.uue >&AC_FD_CC
+        ac_cv_prog_uudecode_base64=no
+fi
+rm -f Test.uue])
+fi
+if test x$ac_cv_prog_uudecode_base64 != xyes; then
+        rm -f Test.class
+        AC_MSG_WARN([I have to compile Test.class from scratch])
+        if test x$ac_cv_prog_javac_works = xno; then
+                AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly])
+        fi
+        if test x$ac_cv_prog_javac_works = x; then
+                AC_PROG_JAVAC
+        fi
+fi
+AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [
+JAVA_TEST=Test.java
+CLASS_TEST=Test.class
+TEST=Test
+changequote(, )dnl
+cat << \EOF > $JAVA_TEST
+/* [#]line __oline__ "configure" */
+public class Test {
+public static void main (String args[]) {
+        System.exit (0);
+} }
+EOF
+changequote([, ])dnl
+if test x$ac_cv_prog_uudecode_base64 != xyes; then
+        if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then
+                :
+        else
+          echo "configure: failed program was:" >&AC_FD_CC
+          cat $JAVA_TEST >&AC_FD_CC
+          AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?))
+        fi
+fi
+if AC_TRY_COMMAND($JAVA $JAVAFLAGS $TEST) >/dev/null 2>&1; then
+  ac_cv_prog_java_works=yes
+else
+  echo "configure: failed program was:" >&AC_FD_CC
+  cat $JAVA_TEST >&AC_FD_CC
+  AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?))
+fi
+rm -fr $JAVA_TEST $CLASS_TEST Test.uue
+])
+AC_PROVIDE([$0])dnl
+]
+)
+
+# http://ac-archive.sourceforge.net/ac-archive/ac_prog_java.html
+
+AC_DEFUN([AC_PROG_JAVA],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test x$JAVAPREFIX = x; then
+        test x$JAVA = x && AC_CHECK_PROGS(JAVA, kaffe$EXEEXT java$EXEEXT)
+else
+        test x$JAVA = x && AC_CHECK_PROGS(JAVA, kaffe$EXEEXT java$EXEEXT, $JAVAPREFIX)
+fi
+test x$JAVA = x && AC_MSG_ERROR([no acceptable Java virtual machine found in \$PATH])
+AC_PROG_JAVA_WORKS
+AC_PROVIDE([$0])dnl
+])
+
+# http://ac-archive.sourceforge.net/ac-archive/ac_prog_javac_works.html
+
+AC_DEFUN([AC_PROG_JAVAC_WORKS],[
+AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [
+JAVA_TEST=Test.java
+CLASS_TEST=Test.class
+cat << \EOF > $JAVA_TEST
+/* [#]line __oline__ "configure" */
+public class Test {
+}
+EOF
+if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then
+  ac_cv_prog_javac_works=yes
+else
+  AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)])
+  echo "configure: failed program was:" >&AC_FD_CC
+  cat $JAVA_TEST >&AC_FD_CC
+fi
+rm -f $JAVA_TEST $CLASS_TEST
+])
+AC_PROVIDE([$0])dnl
+])
+
+
+# http://ac-archive.sourceforge.net/ac-archive/ac_prog_javac.html
+
+AC_DEFUN([AC_PROG_JAVAC],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test "x$JAVAPREFIX" = x; then
+        test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT javac$EXEEXT)
+else
+        test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT javac$EXEEXT, $JAVAPREFIX)
+fi
+test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH])
+AC_PROG_JAVAC_WORKS
+AC_PROVIDE([$0])dnl
+])
+
+# http://ac-archive.sourceforge.net/ac-archive/ac_try_compile_java.html
+
+AC_DEFUN([AC_TRY_COMPILE_JAVA],[
+AC_REQUIRE([AC_PROG_JAVAC])dnl
+cat << \EOF > Test.java
+/* [#]line __oline__ "configure" */
+ifelse([$1], , , [import $1;])
+public class Test {
+[$2]
+}
+EOF
+if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class
+then
+dnl Don't remove the temporary files here, so they can be examined.
+  ifelse([$3], , :, [$3])
+else
+  echo "configure: failed program was:" >&AC_FD_CC
+  cat Test.java >&AC_FD_CC
+ifelse([$4], , , [  rm -fr Test*
+  $4
+])dnl
+fi
+rm -fr Test*])
+
+# http://ac-archive.sourceforge.net/ac-archive/ac_check_class.html
+
+AC_DEFUN([AC_CHECK_CLASS],[
+AC_REQUIRE([AC_PROG_JAVA])
+ac_var_name=`echo $1 | sed 's/\./_/g'`
+dnl Normaly I'd use a AC_CACHE_CHECK here but since the variable name is
+dnl dynamic I need an extra level of extraction
+AC_MSG_CHECKING([for $1 class])
+AC_CACHE_VAL(ac_cv_class_$ac_var_name, [
+if test x$ac_cv_prog_uudecode_base64 = xyes; then
+dnl /**
+dnl  * Test.java: used to test dynamicaly if a class exists.
+dnl  */
+dnl public class Test
+dnl {
+dnl
+dnl public static void
+dnl main( String[] argv )
+dnl {
+dnl     Class lib;
+dnl     if (argv.length < 1)
+dnl      {
+dnl             System.err.println ("Missing argument");
+dnl             System.exit (77);
+dnl      }
+dnl     try
+dnl      {
+dnl             lib = Class.forName (argv[0]);
+dnl      }
+dnl     catch (ClassNotFoundException e)
+dnl      {
+dnl             System.exit (1);
+dnl      }
+dnl     lib = null;
+dnl     System.exit (0);
+dnl }
+dnl
+dnl }
+cat << \EOF > Test.uue
+begin-base64 644 Test.class
+yv66vgADAC0AKQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE
+bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51
+bWJlclRhYmxlDAAKAAsBAANlcnIBABVMamF2YS9pby9QcmludFN0cmVhbTsJ
+AA0ACQcADgEAEGphdmEvbGFuZy9TeXN0ZW0IABABABBNaXNzaW5nIGFyZ3Vt
+ZW50DAASABMBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgAV
+ABEHABYBABNqYXZhL2lvL1ByaW50U3RyZWFtDAAYABkBAARleGl0AQAEKEkp
+VgoADQAXDAAcAB0BAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylM
+amF2YS9sYW5nL0NsYXNzOwoAHwAbBwAgAQAPamF2YS9sYW5nL0NsYXNzBwAi
+AQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BAAY8aW5pdD4B
+AAMoKVYMACMAJAoAAwAlAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQAhAAEA
+AwAAAAAAAgAJAAUABgABAAcAAABtAAMAAwAAACkqvgSiABCyAAwSD7YAFBBN
+uAAaKgMyuAAeTKcACE0EuAAaAUwDuAAasQABABMAGgAdACEAAQAIAAAAKgAK
+AAAACgAAAAsABgANAA4ADgATABAAEwASAB4AFgAiABgAJAAZACgAGgABACMA
+JAABAAcAAAAhAAEAAQAAAAUqtwAmsQAAAAEACAAAAAoAAgAAAAQABAAEAAEA
+JwAAAAIAKA==
+====
+EOF
+                if uudecode$EXEEXT Test.uue; then
+                        :
+                else
+                        echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC
+                        echo "configure: failed file was:" >&AC_FD_CC
+                        cat Test.uue >&AC_FD_CC
+                        ac_cv_prog_uudecode_base64=no
+                fi
+        rm -f Test.uue
+        if AC_TRY_COMMAND($JAVA $JAVAFLAGS Test $1) >/dev/null 2>&1; then
+                eval "ac_cv_class_$ac_var_name=yes"
+        else
+                eval "ac_cv_class_$ac_var_name=no"
+        fi
+        rm -f Test.class
+else
+        AC_TRY_COMPILE_JAVA([$1], , [eval "ac_cv_class_$ac_var_name=yes"],
+                [eval "ac_cv_class_$ac_var_name=no"])
+fi
+eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`"
+eval "HAVE_$ac_var_name=$`echo ac_cv_class_$ac_var_val`"
+HAVE_LAST_CLASS=$ac_var_val
+if test x$ac_var_val = xyes; then
+        ifelse([$2], , :, [$2])
+else
+        ifelse([$3], , :, [$3])
+fi
+])
+dnl for some reason the above statment didn't fall though here?
+dnl do scripts have variable scoping?
+eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`"
+AC_MSG_RESULT($ac_var_val)
+])
+
+# ===========================================================================
+#      http://www.gnu.org/software/autoconf-archive/ax_check_junit.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_JUNIT
+#
+# DESCRIPTION
+#
+#   AX_CHECK_JUNIT tests the availability of the Junit testing framework,
+#   and set some variables for conditional compilation of the test suite by
+#   automake.
+#
+#   If available, JUNIT is set to a command launching the text based user
+#   interface of Junit, @JAVA_JUNIT@ is set to $JAVA_JUNIT and @TESTS_JUNIT@
+#   is set to $TESTS_JUNIT, otherwise they are set to empty values.
+#
+#   You can use these variables in your Makefile.am file like this :
+#
+#    # Some of the following classes are built only if junit is available
+#    JAVA_JUNIT  = Class1Test.java Class2Test.java AllJunitTests.java
+#
+#    noinst_JAVA = Example1.java Example2.java @JAVA_JUNIT@
+#
+#    EXTRA_JAVA  = $(JAVA_JUNIT)
+#
+#    TESTS_JUNIT = AllJunitTests
+#
+#    TESTS       = StandaloneTest1 StandaloneTest2 @TESTS_JUNIT@
+#
+#    EXTRA_TESTS = $(TESTS_JUNIT)
+#
+#    AllJunitTests :
+#       echo "#! /bin/sh" > $@
+#       echo "exec @JUNIT@ my.package.name.AllJunitTests" >> $@
+#       chmod +x $@
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Luc Maisonobe <luc at spaceroots.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+AU_ALIAS([AC_CHECK_JUNIT], [AX_CHECK_JUNIT])
+AC_DEFUN([AX_CHECK_JUNIT],[
+AC_CACHE_VAL(ac_cv_prog_JUNIT,[
+AC_CHECK_CLASS(junit.textui.TestRunner)
+if test x"`eval 'echo $ac_cv_class_junit_textui_TestRunner'`" != xno ; then
+  ac_cv_prog_JUNIT='$(CLASSPATH_ENV) $(JAVA) $(JAVAFLAGS) junit.textui.TestRunner'
+fi])
+AC_MSG_CHECKING([for junit])
+if test x"`eval 'echo $ac_cv_prog_JUNIT'`" != x ; then
+  JUNIT="$ac_cv_prog_JUNIT"
+  JAVA_JUNIT='$(JAVA_JUNIT)'
+  TESTS_JUNIT='$(TESTS_JUNIT)'
+else
+  JUNIT=
+  JAVA_JUNIT=
+  TESTS_JUNIT=
+fi
+AC_MSG_RESULT($JAVA_JUNIT)
+AC_SUBST(JUNIT)
+AC_SUBST(JAVA_JUNIT)
+AC_SUBST(TESTS_JUNIT)])
diff --git a/applications/CMakeLists.txt b/applications/CMakeLists.txt
new file mode 100644
index 0000000..28e7efe
--- /dev/null
+++ b/applications/CMakeLists.txt
@@ -0,0 +1,58 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2010 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+#The LibXML 2 Libraries
+find_package(LibXml2)
+
+# Recurse into the subdirectories.
+
+add_subdirectory (NXbrowse)
+add_subdirectory (NXdir)
+add_subdirectory (NXconvert)
+
+if (BUILD_FORTRAN_BINDINGS AND CMAKE_Fortran_COMPILER_WORKS)
+    add_subdirectory (NXdump)
+endif()
+
+if (HAVE_MXML)
+add_subdirectory (nxingest)
+endif(HAVE_MXML)
+
+add_subdirectory (NXtraverse)
+
+if(Java_JAVAC_EXECUTABLE AND ANT_FOUND)
+    add_subdirectory (NXvalidate)
+endif(Java_JAVAC_EXECUTABLE AND ANT_FOUND)
+
+if(LIBXML2_FOUND)
+    add_subdirectory (NXsummary)
+    add_subdirectory (NXtranslate)
+endif(LIBXML2_FOUND)
+
+install (PROGRAMS nxdiff DESTINATION bin COMPONENT Runtime)
+
diff --git a/applications/Makefile.am b/applications/Makefile.am
new file mode 100644
index 0000000..28c3c25
--- /dev/null
+++ b/applications/Makefile.am
@@ -0,0 +1,57 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+LIBNEXUS77=$(top_builddir)/bindings/f77/libNeXus77.la
+LIBNEXUS90=$(top_builddir)/bindings/f90/libNeXus90.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+AM_FCFLAGS=-I$(top_builddir)/bindings/f90
+man_MANS = nxdiff.1
+
+dist_bin_SCRIPTS=nxdiff
+
+EXTRA_DIST=SConscript $(man_MANS)
+
+if HAVE_F90
+NXDUMP = NXdump
+endif
+if HAVE_XML
+NXINGEST = nxingest
+endif
+if HAVE_LIBXML2
+NXTRANSLATE=NXtranslate
+NXSUMMARY=NXsummary
+endif
+if HAVE_ANT
+NXVALIDATE = NXvalidate
+endif
+
+SUBDIRS = NXbrowse NXdir NXtraverse NXconvert $(NXVALIDATE) \
+	$(NXDUMP) $(NXTRANSLATE) $(NXSUMMARY) $(NXINGEST)
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXbrowse/CMakeLists.txt b/applications/NXbrowse/CMakeLists.txt
new file mode 100644
index 0000000..dba9bf2
--- /dev/null
+++ b/applications/NXbrowse/CMakeLists.txt
@@ -0,0 +1,38 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_executable (nxbrowse NXbrowse.c)
+
+target_link_libraries(nxbrowse NeXus_Shared_Library 
+                      ${READLINE_LINK}  ${M_LINK}
+                      ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK}
+                      ${HISTORY_LINK})
+
+install (TARGETS nxbrowse DESTINATION bin COMPONENT Runtime)
+install (FILES nxbrowse.1 DESTINATION man/man1 COMPONENT Documentation)
+
diff --git a/applications/NXbrowse/Makefile.am b/applications/NXbrowse/Makefile.am
new file mode 100644
index 0000000..bf9d906
--- /dev/null
+++ b/applications/NXbrowse/Makefile.am
@@ -0,0 +1,44 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1239 2009-04-15 14:37:08Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+LIBNEXUS77=$(top_builddir)/bindings/f77/libNeXus77.la
+LIBNEXUS90=$(top_builddir)/bindings/f90/libNeXus90.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -I/usr/include/readline
+AM_FCFLAGS=-I$(top_builddir)/bindings/f90
+
+EXTRA_DIST=SConscript $(man_MANS)
+
+bin_PROGRAMS = nxbrowse
+man_MANS = nxbrowse.1
+
+nxbrowse_SOURCES = NXbrowse.c
+nxbrowse_LDADD = $(LIBNEXUS)
+nxbrowse_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ @READLINE_LDFLAGS@ $(LDFLAGS)
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXbrowse/NXbrowse.c b/applications/NXbrowse/NXbrowse.c
new file mode 100755
index 0000000..47e22ef
--- /dev/null
+++ b/applications/NXbrowse/NXbrowse.c
@@ -0,0 +1,949 @@
+/*-----------------------------------------------------------------------------
+ NeXus - Neutron & X-ray Common Data Format
+  
+ NeXus Browser
+
+ Copyright (C) 2000, Ray Osborn
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ Contact : R. Osborn <ROsborn at anl.gov>
+           Materials Science Division
+           Argonne National Laboratory
+           Argonne, IL 60439-4845
+           USA
+
+ For further information, see <http://www.nexusformat.org>
+
+ $Id$
+!----------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "napi.h"
+#include "napiconfig.h"
+static char* my_readline(const char* prompt)
+{
+    char inputText[256];
+    char* stringPtr;
+    fprintf(stdout, "%s", prompt);
+    if (fgets(inputText, sizeof(inputText), stdin) == NULL)
+    {
+	return NULL;
+    }
+    if ((stringPtr = strchr(inputText, '\n')) != NULL) 
+    {
+        *stringPtr = '\0';
+    }
+    return strdup(inputText);
+}
+#if HAVE_LIBREADLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#else
+#define rl_completion_matches(a,b) NULL
+#define rl_outstream stdout
+#define readline my_readline
+#endif /* HAVE_LIBREADLINE */
+
+#define StrEq(s1, s2) (strcmp((s1), (s2)) == 0)
+
+#ifdef _WIN32
+#define STRNCASECMP strnicmp
+#else
+#define STRNCASECMP strncasecmp
+#endif /* _WIN32 */
+
+int NXBdir (NXhandle fileId);
+int NXBopen (NXhandle fileId, NXname groupName);
+int NXBread (NXhandle fileId, NXname dataName, char *dimensions);
+int NXBdump (NXhandle fileId, NXname dataName, char *fileName);
+void ConvertUpperCase (char *string);
+void PrintAttributes (NXhandle fileId);
+void PrintDimensions (int rank, int dimensions[]);
+void PrintType (int dataType);
+void PrintData (void* data, int dataType, int numElements);
+void DumpData(FILE *fd, int rank, int dimensions[], int dataType, void *data);
+void WriteData (FILE *fd, char *data, int dataType, int numElements);
+int FindGroup (NXhandle fileId, char *groupName, char *groupClass);
+int FindData (NXhandle fileId, char *dataName);
+static int nxTypeSize(int dataType);
+
+/* if iByteAsChar, NX_INT8 and NX_UINT8 are treated as characters */
+static int iByteAsChar = 1; /* Assume global attributes are all characters */
+static char nxFile[256];
+
+static NXhandle the_fileId;
+
+/* 
+ * Freddie Akeroyd 18/10/2009 
+ *
+ * Add in support for readline and completion (nxbrowse_complete) of commands
+ * (command_generator) and on data/group names (field_generator)
+ * a / character is appended to group names for display, but stripped off
+ * by the cd command (we may want to remove this and use openpath() later)
+ *
+ */
+typedef struct {
+    const char* name;
+    const char* doc;
+} COMMAND;
+
+COMMAND commands[] = {
+    { "cd", "Move into to a group" },
+    { "close", "Move out of a group" },
+    { "dir", "" },
+    { "ls", "" },
+    { "read", "" },
+    { "open", "" },
+    { "help", "" },
+    { "info", "" },
+    { "exit", "" },
+    { "quit", "" },
+    { "dump", "" },
+    { "bytesaschar", "" },
+    { NULL, NULL }
+};
+
+#if HAVE_LIBREADLINE
+static char* command_generator(const char* text, int state)
+{
+    static int len, list_index;
+    const char* name;
+    if (!state)
+    {
+        list_index = 0;
+        len = strlen(text);
+    } 
+    while( (name = commands[list_index].name) != NULL )
+    {
+	++list_index;
+	if (STRNCASECMP(name, text, len) == 0)
+	{
+	    return strdup(name);
+	}
+    }
+    return NULL;
+}
+#endif
+
+struct name_item; /* forward declaration for a linked list */
+
+struct name_item
+{
+    char* name;
+    struct name_item* next;
+};
+    
+#if HAVE_LIBREADLINE
+static char* field_generator(const char* text, int state)
+{
+    static int len;
+    struct name_item *item, *t_item;
+    static struct name_item *names = NULL, *last_item = NULL;
+    char* res;
+    int status, dataType;
+    NXname name, nxclass;
+    if (!state)
+    {
+	item = names;
+	while(item != NULL)
+	{
+	    if (item->name != NULL)
+	    {
+		free(item->name);
+	  	item->name = NULL;
+	    }
+	    t_item = item;
+	    item = item->next;
+	    t_item->next = NULL;
+	    free(t_item);
+	}
+	last_item = names = NULL;
+        len = strlen(text);
+        if (NXinitgroupdir (the_fileId) != NX_OK)
+        {
+	    return NULL;
+        }
+        do 
+        {
+           status = NXgetnextentry (the_fileId, name, nxclass, &dataType);
+           if (status == NX_ERROR) break;
+           if (status == NX_OK) 
+           {
+	      if (strncmp(nxclass,"CDF",3) == 0){ 
+	          ;
+	      }
+	      else if (strncmp(name, text, len) == 0)
+              {
+		  item = (struct name_item*)malloc(sizeof(struct name_item));
+                  item->name = strdup(name);
+	          if (strcmp(nxclass,"SDS") != 0){ 
+		     strcat(item->name, "/");
+		  }
+		  item->next = NULL;
+		  if (last_item == NULL)
+		  {
+		    names = item;
+                  }
+		  else
+		  {
+		    last_item->next = item;
+		  }
+		  last_item = item;
+              }
+           } 
+        } while (status == NX_OK);
+        last_item = names;
+    }
+    if (last_item != NULL)
+    {
+       res = strdup(last_item->name);
+       last_item = last_item->next;
+    }
+    else
+    {
+	res = NULL;
+    }
+    return res;
+}
+#endif
+
+#if HAVE_LIBREADLINE
+static char** nxbrowse_complete(const char* text, int start, int end)
+{
+    char** matches = NULL;
+    static char line[512];
+    strncpy(line, text+start, end-start);
+    line[end-start] = '\0';
+    if (start == 0) 
+    {
+	matches = rl_completion_matches(text, command_generator);
+    }
+    else
+    {
+	matches = rl_completion_matches(text, field_generator);
+    }
+    return matches;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+   char fileName[256], path[256], *command, *dimensions, *stringPtr;
+   char prompt[512];
+   char *inputText;
+   NXname groupName, dataName;
+   int status, groupLevel = 0, i;
+
+#if HAVE_LIBREADLINE
+   rl_readline_name = "NXbrowse";
+   rl_attempted_completion_function = nxbrowse_complete;
+#if READLINE_VERSION >= 0x500
+   rl_catch_signals = 0;
+#else
+#define rl_crlf() fprintf(rl_outstream, "\r\n");
+#define rl_on_new_line() 1
+#endif
+   using_history();
+#else
+#define rl_crlf()
+#define rl_on_new_line()
+#define add_history(a)
+#endif
+
+   printf ("NXBrowse %s Copyright (C) 2009 NeXus Data Format\n", NEXUS_VERSION);
+#if HAVE_LIBREADLINE
+   printf ("Built with readline support - use <TAB> to complete commands and paths\n");
+#endif /* HAVE_LIBREADLINE */
+
+/* if there is a filename given on the command line use that,
+      else ask for a filename */
+   if (argc < 2) {
+      printf ("Give name of NeXus file : ");
+      if (fgets (fileName, sizeof(fileName), stdin) == NULL)
+      {
+	printf("Failed to open %s\n", fileName);
+	return NX_ERROR;
+      }
+      if ((stringPtr = strchr(fileName, '\n')) != NULL) 
+         *stringPtr = '\0';
+   }
+   else {
+     strcpy (fileName, argv[1]);
+   }
+   strcpy (nxFile, fileName);
+ 
+/* Open input file and output global attributes */
+   if (NXopen (fileName, NXACC_READ, &the_fileId) != NX_OK) {
+      printf ("NX_ERROR: Can't open %s\n", fileName);
+      return NX_ERROR;
+   }
+   PrintAttributes (the_fileId);
+   iByteAsChar = 0; /* Display remaining NX_INT8 and NX_UINT8 variables as integers by default */
+/* Input commands until the EXIT command is given */
+   strcpy (path, "NX");
+   do {
+      sprintf (prompt, "%s> ", path);
+      if (getenv("NO_READLINE") != NULL)
+      {
+          inputText = my_readline(prompt);
+      }
+      else
+      {
+          inputText = readline(prompt);
+      }
+      if (inputText == NULL)
+      {
+          inputText = strdup("EXIT");
+      }
+      if (*inputText)
+      {
+          add_history(inputText);
+      }
+      command = strtok(inputText," ");
+      /* Check if a command has been given */
+      if (command == NULL) command = " ";
+      /* Convert it to upper case characters */
+      ConvertUpperCase (command);
+      /* Command is to print a directory of the current group */
+      if (StrEq(command, "DIR") || StrEq(command, "LS")) {
+         status = NXBdir (the_fileId);
+      }    
+      /* Command is to open the specified group */
+      if (StrEq(command, "OPEN") || StrEq(command, "CD")) {
+         stringPtr = strtok(NULL, " /"); 
+         if (stringPtr != NULL) {
+            strcpy (groupName, stringPtr);
+			 if (StrEq(groupName, "..")) {
+				 strcpy(command, "CLOSE");
+			 } else {
+				 status = NXBopen (the_fileId, groupName);
+				 /* Add the group to the prompt string */
+				 if (status == NX_OK) {
+					 strcat (path, "/");
+					 strcat (path, groupName);
+					 groupLevel++;
+				 }
+			 }
+         }
+         else {
+            fprintf (rl_outstream, "NX_ERROR: Specify a group\n");
+         }
+      }
+      /* Command is to  dump data values to a file */
+      if (StrEq(command, "DUMP")) {
+         stringPtr = strtok (NULL, " ");
+         if (stringPtr != NULL) {
+            strcpy (dataName, stringPtr);
+            stringPtr = strtok(NULL," ");
+            if (stringPtr != NULL) {
+               strcpy (fileName, stringPtr);
+               status = NXBdump (the_fileId, dataName, fileName);
+            }
+            else {
+               fprintf (rl_outstream, "NX_ERROR: Specify a dump file name \n");
+            }
+         }
+         else {
+            fprintf (rl_outstream, "NX_ERROR: Specify a data item\n");
+         }
+      }
+      /* Command is to print the values of the data */
+      if (StrEq(command, "READ") || StrEq(command, "CAT")) {
+         stringPtr = strtok (NULL, " [");
+         if (stringPtr != NULL) {
+            strcpy (dataName, stringPtr);
+            dimensions = strtok(NULL, "[]");
+            status = NXBread (the_fileId, dataName, dimensions);
+         }
+         else {
+            fprintf (rl_outstream, "NX_ERROR: Specify a data item\n");
+         }
+      }
+      /* Command is to close the current group */
+      if (StrEq(command, "CLOSE")) {
+         if (groupLevel > 0) {
+            if (NXclosegroup (the_fileId) == NX_OK) {
+               /* Remove the group from the prompt string */
+               stringPtr = strrchr (path, '/'); /* position of last group delimiter */
+               if (stringPtr != NULL) 
+                  *stringPtr = '\0';            /* terminate the string there */
+               groupLevel--;
+            }
+         }
+         else {
+            fprintf (rl_outstream, "NX_WARNING: Already at root level of file\n");
+         }
+      }
+      /* Command is to print help information */
+      if (StrEq(command, "HELP") || StrEq(command, "INFO")) {
+         printf ("NXbrowse commands : DIR\n");
+         printf ("                    LS\n");
+         printf ("                    OPEN <groupName>\n");
+         printf ("                    CD <groupName>\n");
+         printf ("                    READ <dataName>\n");
+         printf ("                    READ <dataName>[<dimension indices...>]\n");
+         printf ("                    DUMP <dataName> <fileName> \n");
+         printf ("                    CLOSE\n");
+         printf ("                    BYTEASCHAR\n");
+         printf ("                    HELP\n");
+         printf ("                    EXIT\n");
+         printf ("\n");
+         printf ("If readline support is enabled, pressing <TAB> after a command \n");
+	 printf ("or partial nexus object name will list/complete possible names\n");
+         printf ("\n");
+	 printf ("    cd ent<TAB KEY PRESSED>     # all items starting with ent are listed\n");
+         printf ("\n");
+      }
+      /* Command is to print byte as char information */
+      if (StrEq(command, "BYTEASCHAR")) {
+         if (iByteAsChar == 1)
+            iByteAsChar = 0;
+         else
+            iByteAsChar = 1;
+      }
+      /* Command is to exit the program */
+      if (StrEq(command, "EXIT") || StrEq(command, "QUIT")) {
+         for (i = groupLevel; i > 0; i--) NXclosegroup (the_fileId);
+         NXclose (&the_fileId);
+         return NX_OK;
+      }
+      status = NX_OK;
+      free(inputText);
+   } while (status == NX_OK);
+   return NX_OK;
+}
+/* Checks for attributes and outputs their values */
+void PrintGroupAttributes (NXhandle fileId, char *groupname)
+{
+   int status, attrLen, attrType;
+   NXname attrName;
+   void *attrBuffer;
+
+   do {
+      status = NXgetnextattr (fileId, attrName, &attrLen, &attrType);
+      if (status == NX_ERROR) return;
+      if (status == NX_OK) {
+         attrLen++; /* Add space for string termination */
+         if (NXmalloc((void**)&attrBuffer, 1, &attrLen, attrType) != NX_OK) return;
+         if (NXgetattr (fileId, attrName, attrBuffer,&attrLen , &attrType) != NX_OK) return;
+         printf ("             %s attribute: %s = ", groupname, attrName);
+         PrintData (attrBuffer, attrType, attrLen);
+         printf ("\n");
+         if (NXfree((void**)&attrBuffer) != NX_OK) return;
+      }
+   } while (status != NX_EOD);
+   return;
+}
+
+/* Outputs the contents of a NeXus group */
+int NXBdir (NXhandle fileId)
+{
+   int status, dataType, dataRank, dataDimensions[NX_MAXRANK], length;
+   NXname name, nxclass, nxurl;
+
+   if (NXinitgroupdir (fileId) != NX_OK) return NX_ERROR;
+   do {
+      status = NXgetnextentry (fileId, name, nxclass, &dataType);
+      if (status == NX_ERROR) break;
+      if (status == NX_OK) {
+	if (strncmp(nxclass,"CDF",3) == 0){ 
+	    ;
+	}
+	else if (strcmp(nxclass,"SDS") == 0){ 
+            printf ("  NX Data  : %s", name);
+            if (NXopendata (fileId, name) != NX_OK) return NX_ERROR;
+            if (NXgetinfo (fileId, &dataRank, dataDimensions, &dataType) != NX_OK) return NX_ERROR;
+            if (NXclosedata(fileId) != NX_OK) return NX_ERROR;
+            PrintDimensions (dataRank, dataDimensions);
+            printf (" ");
+            PrintType (dataType);
+            printf ("\n");
+	} else {
+	    length = sizeof(nxurl);
+	    if(NXisexternalgroup(fileId, name,nxclass,nxurl,length) == NX_OK){
+	      printf ("  NX external Group: %s (%s), linked to: %s \n",name,nxclass,nxurl); 
+            } else {
+	      printf ("  NX Group : %s (%s)\n", name, nxclass);
+	      if((status = NXopengroup(fileId,name,nxclass)) != NX_OK){
+		return status;
+	      } 
+	      PrintGroupAttributes(fileId, name);
+	      if((status = NXclosegroup(fileId)) != NX_OK){
+		return status;
+	      } 
+            }
+	}
+      }
+   } while (status == NX_OK);
+   return status;
+}
+
+/* Opens the requested group */
+int NXBopen (NXhandle fileId, NXname groupName)
+{
+   NXname groupClass;
+
+   if (groupName == NULL) {
+      printf ("NX_ERROR: Specify a group name with the OPEN command\n");
+      return NX_ERROR;
+   }
+   if (FindGroup (fileId, groupName, groupClass) != NX_OK) return NX_ERROR;
+   if (NXopengroup (fileId, groupName, groupClass) != NX_OK) return NX_ERROR;
+   return NX_OK;
+}
+
+/* Outputs requested data */
+int NXBread (NXhandle fileId, NXname dataName, char *dimensions)
+{
+   int dataRank, dataDimensions[NX_MAXRANK], dataType, start[NX_MAXRANK], size[NX_MAXRANK], i, j, total_size;
+   char dimString[80], *subString;
+   void *dataBuffer;
+  
+   /* Check the specified data item exists */
+   if (FindData (fileId, dataName) != NX_OK) return NX_ERROR;
+   /* Open the data and obtain its type and rank details */
+   if (NXopendata (fileId, dataName) != NX_OK) return NX_ERROR;
+   if (NXgetinfo (fileId, &dataRank, dataDimensions, &dataType) != NX_OK) return NX_ERROR;
+   /* Check if a single element has been specified */
+   /* If so, read in the indices */
+   if (dimensions != NULL) {
+      strcpy (dimString, dimensions);      
+      subString = strtok (dimString, ",");
+      for (i = 0; subString != NULL && i < NX_MAXRANK; i++) {
+         if (i >= dataRank) {
+            printf ("NX_ERROR: Data rank = %d\n", dataRank);
+            return NX_ERROR;
+         }
+         sscanf (subString, "%d", &j);
+         if (j > dataDimensions[i] || j < 1) {
+            printf ("NX_ERROR: Data dimension %d = %d\n", (i+1), dataDimensions[i]);
+            return NX_ERROR;
+         }
+         start[i] = j - 1;
+         size[i] = 1;
+         subString = strtok (NULL, ",");
+      }
+      if (i != dataRank) {
+         printf ("NX_ERROR: Data rank = %d\n", dataRank);
+         return NX_ERROR;
+      }
+   }
+   /* Otherwise, allocate enough space for the first 3 elements of each dimension */
+   else {
+      for (i = 0; i < dataRank; i++) {
+         if (dataDimensions[i] > 3 && dataType != NX_CHAR) {
+            start[i] = 0;
+            size[i] = 3;
+         } /* unless it's a character string */
+         else {
+            start[i] = 0;
+            size[i] = dataDimensions[i];
+         }
+      }
+   }
+   total_size = 1;
+   for(i = 0; i < dataRank; i++)
+   {
+       total_size *= dataDimensions[i];
+   }
+   if (NXmalloc((void**)&dataBuffer, dataRank, size, dataType) != NX_OK) return NX_ERROR;
+   /* Read in the data with NXgetslab */
+   if (dataType == NX_CHAR) {
+      if (NXgetdata(fileId, dataBuffer) != NX_OK) return NX_ERROR;
+   }
+   else {
+      if (NXgetslab (fileId, dataBuffer, start, size) != NX_OK) return NX_ERROR;
+   }
+   /* Output data name, dimensions and type */
+   printf ("  %s", dataName);
+   if (dimensions == NULL)
+      PrintDimensions (dataRank, dataDimensions);
+   else 
+      printf ("[%s]", dimensions);
+   printf (" ");
+   PrintType (dataType);
+   printf (" = ");
+   /* Output the data according to data type */
+   if (dimensions == NULL) {  /* Print the first few values (max 3) */
+      if (dataType == NX_CHAR) { /* If the data is a string, output the whole buffer */
+/* this prints the first line of an array; could print more */
+         for(i=0; i<total_size / dataDimensions[dataRank-1]; i++)
+	 {
+             PrintData ((char*)dataBuffer + i * dataDimensions[dataRank-1], dataType, dataDimensions[dataRank-1]);
+	     PrintData ("\n", NX_CHAR, 1);
+         }
+      }
+      else {
+         if (dataRank == 1 && dataDimensions[0] == 1) {    /* It's a scalar */
+            PrintData (dataBuffer, dataType, 1);
+         }
+         else {                                            /* It's an array */
+            printf ("[ ");
+            /* Determine total size of input buffer */
+            for (i = 0, j = 0; i < dataRank; i++)
+               j += dataDimensions[i];
+            /* Output at least 3 values */
+            if (j > 3) {
+               PrintData (dataBuffer, dataType, 3);
+               printf ("...");
+            }
+            /* unless the total size is smaller */
+            else {
+               PrintData (dataBuffer, dataType, j);
+            }
+            printf ("]");
+         }
+      }
+   }
+   else {                      /* Print the requested item */    
+      PrintData (dataBuffer, dataType, 1);
+   }
+   printf ("\n");
+   if (NXfree((void**)&dataBuffer) != NX_OK) return NX_ERROR;
+
+   /* Check for attributes unless a single element is specified */
+   if (dimensions == NULL) 
+      PrintAttributes (fileId);
+
+   /* Close data set */
+   if (NXclosedata(fileId) != NX_OK) return NX_ERROR;
+
+   return NX_OK;
+}
+
+/* Dumps requested data */
+int NXBdump (NXhandle fileId, NXname dataName, char *fileName)
+{
+   int dataRank, dataDimensions[NX_MAXRANK], dataType, i;
+   FILE *fd = NULL;
+   void *dataBuffer;
+  
+   /* Check the specified data item exists */
+   if (FindData (fileId, dataName) != NX_OK) return NX_ERROR;
+
+   /* Open the data and obtain its type and rank details */
+   if (NXopendata (fileId, dataName) != NX_OK) return NX_ERROR;
+   if (NXgetinfo (fileId, &dataRank, dataDimensions, &dataType) != NX_OK) 
+      return NX_ERROR;
+   
+   /* Open the file */
+   fd = fopen (fileName,"w");
+   if(!fd) {
+     printf ("ERROR: failed to open--> %s <-- for writing\n",
+            fileName);
+     return NX_ERROR;
+   }
+
+   /* Allocate data space */
+   if (NXmalloc(&dataBuffer, dataRank, dataDimensions, dataType) != NX_OK)
+      return NX_ERROR;
+
+   /* Read the lot */
+   if (NXgetdata(fileId, dataBuffer) != NX_OK)
+      return NX_ERROR;
+
+   if (NXclosedata(fileId) != NX_OK) return NX_ERROR;
+
+   /* Print a header */
+   fprintf (fd,"File : %s, DataSet: %s \n", nxFile,  dataName);
+   for (i=0; i < dataRank; i++) {
+      fprintf(fd," %d ", dataDimensions[i]);
+   }
+   fprintf(fd,"\n");
+
+   /* Dump the data */
+   DumpData (fd, dataRank, dataDimensions, dataType, dataBuffer);
+
+   /* Clean up */
+   fclose (fd);
+   NXfree (&dataBuffer);
+   return NX_OK;
+}
+
+/* Converts command string to upper case */
+void ConvertUpperCase (char *string)
+{
+   int i;
+   
+   for (i=0; string[i]!=0; i++) {
+      if (string[i] >= 97 && string[i] <= 122) {
+         string[i] = string[i] - 32;
+      }
+   }
+}   
+
+/* Checks for attributes and outputs their values */
+void PrintAttributes (NXhandle fileId)
+{
+   int status, attrLen, attrType;
+   NXname attrName;
+   void *attrBuffer;
+
+   do {
+      status = NXgetnextattr (fileId, attrName, &attrLen, &attrType);
+      if (status == NX_ERROR) return;
+      if (status == NX_OK) {
+         attrLen++; /* Add space for string termination */
+         if (NXmalloc((void**)&attrBuffer, 1, &attrLen, attrType) != NX_OK) return;
+         if (NXgetattr (fileId, attrName, attrBuffer,&attrLen , &attrType) != NX_OK) return;
+         printf ("    %s = ", attrName);
+         PrintData (attrBuffer, attrType, attrLen);
+         printf ("\n");
+         if (NXfree((void**)&attrBuffer) != NX_OK) return;
+      }
+   } while (status != NX_EOD);
+   return;
+}
+
+/* Outputs the specified dimensions as a formatted string */
+void PrintDimensions (int rank, int dimensions[])
+{
+   int i;
+
+   if (rank > 1 || dimensions[0] != 1) {
+      printf ("[");
+      for (i=0; i<rank; i++) {
+         if (i > 0) 
+            printf (",");
+         printf ("%d", dimensions[i]);
+      }
+      printf ("]");
+   }
+}
+
+/* Converts the NeXus data type into a character string */
+void PrintType (int dataType)
+{
+   switch (dataType) {
+      case NX_CHAR:
+        printf ("(NX_CHAR)");
+        break;
+      case NX_FLOAT32:
+        printf ("(NX_FLOAT32)");
+        break;
+      case NX_FLOAT64:
+        printf ("(NX_FLOAT64)");
+        break;
+      case NX_INT8:
+        printf ("(NX_INT8)");
+        break;
+      case NX_UINT8:
+        printf ("(NX_UINT8)");
+        break;
+      case NX_INT16:
+        printf ("(NX_INT16)");
+        break;
+      case NX_UINT16:
+        printf ("(NX_UINT16)");
+        break;
+      case NX_INT32:
+        printf ("(NX_INT32)");
+        break;
+      case NX_UINT32:
+        printf ("(NX_UINT32)");
+        break;
+      case NX_INT64:
+        printf ("(NX_INT64)");
+        break;
+      case NX_UINT64:
+        printf ("(NX_UINT64)");
+        break;
+      default:
+        printf ("(UNKNOWN)");
+        break;
+   }
+}
+
+/* Dumps data to a file. Uses recursion because of unknown number of dimensions. */
+void DumpData(FILE *fd, int rank, int dimensions[], int dataType, void *data)
+{
+   char *dataPtr;
+   int i, dimSize, dataSize, lineSize;
+
+   if (rank > 1) { /* Recursively call DumpData until rank = 1 */
+      for (i = 1, dimSize = 1; i < rank; i++) {
+         dimSize *= dimensions[i];
+      }
+      for (i = 0; i < dimensions[0]; i++) {
+         dataPtr = (char *)data + i * dimSize * nxTypeSize(dataType);        
+         DumpData (fd, rank-1, &dimensions[1], dataType, dataPtr);
+      }
+      return;
+   }
+   else { /* Actually print the data */
+      dataSize = dimensions[0];
+      dataPtr = (char *)data;
+      while(dataSize > 0) {
+        if (dataSize > 10) {
+           lineSize = 10;
+        }
+        else {
+           lineSize = dataSize;
+        }
+        WriteData (fd, dataPtr, dataType, lineSize);
+        fprintf(fd,"\n");
+        dataSize -= lineSize;
+        dataPtr += lineSize * nxTypeSize(dataType);
+      }
+   }
+}
+
+/* Writes data items with the requested type */
+void WriteData (FILE *fd, char *data, int dataType, int numElements)
+{
+   int i;
+
+   for (i=0; i<numElements; i++) {
+      switch(dataType) {
+         case NX_CHAR:
+	    if (data[i] == '\0')
+	    {
+		return;
+	    }
+            fprintf (fd, "%c", ((char *)data)[i]);
+            break;
+         case NX_INT8:
+            if(iByteAsChar) {
+               fprintf (fd, "%c", ((char *)data)[i]);
+            }
+            else {
+               fprintf (fd, "%d ", ((char *)data)[i]);
+            }
+            break;
+         case NX_UINT8:
+            if(iByteAsChar) {
+                fprintf (fd, "%c", ((unsigned char *)data)[i]);
+            }
+            else {
+                fprintf (fd, "%d ", ((unsigned char *)data)[i]);
+            }
+            break;
+         case NX_INT16:
+            fprintf (fd, "%d ", ((short *)data)[i]);
+            break;
+         case NX_UINT16:
+            fprintf (fd, "%d ", ((unsigned short *)data)[i]);
+            break;
+         case NX_INT32:
+            fprintf (fd, "%d ", ((int *)data)[i]);
+            break;
+         case NX_UINT32:
+            fprintf (fd, "%d ", ((unsigned *)data)[i]);
+            break;
+         case NX_INT64:
+            fprintf (fd, "%lld ", (long long)((int64_t *)data)[i]);
+            break;
+         case NX_UINT64:
+            fprintf (fd, "%llu ", (unsigned long long)((uint64_t *)data)[i]);
+            break;
+         case NX_FLOAT32:
+            fprintf (fd, "%f ", ((float *)data)[i]);
+            break;
+         case NX_FLOAT64:
+            fprintf (fd, "%f ", ((double *)data)[i]);
+            break;
+         default:
+            printf ("WriteData: invalid type");
+            break;
+      }
+   }
+}
+
+/* Outputs data items with the requested type */
+void PrintData (void *data, int dataType, int numElements)
+{
+   WriteData (stdout, (char*)data, dataType, numElements);
+}
+/* Searches group for requested group and return its class */
+int FindGroup (NXhandle fileId, char *groupName, char *groupClass)
+{
+   int status, dataType;
+   NXname name, nxclass;
+
+   NXinitgroupdir (fileId);
+   do {
+      status = NXgetnextentry (fileId, name, nxclass, &dataType);
+      if (status == NX_ERROR) return NX_ERROR;
+      if (status == NX_OK) {
+          if (StrEq (groupName, name)) {
+            strcpy (groupClass, nxclass);
+            if (!strncmp(groupClass,"NX",2)) {
+               return NX_OK;
+            }
+            else {
+/*
+ *               printf ("NX_ERROR: %s is not a group\n", groupName);
+ *               return NX_ERROR;
+ */
+		return NX_OK; /* allow non NX (i.e. user defined) groups */
+            }
+         }
+      }
+   } while (status != NX_EOD);
+   printf ("NX_ERROR: %s does not exist\n", groupName);
+   return NX_EOD;
+}
+
+/* Searches group for the requested data item */
+int FindData (NXhandle fileId, char *dataName)
+{
+   int status, dataType;
+   NXname name, nxclass;
+
+   NXinitgroupdir (fileId);
+   do {
+      status = NXgetnextentry (fileId, name, nxclass, &dataType);
+      if (status == NX_ERROR) return NX_ERROR;
+      if (status == NX_OK) {
+         if (StrEq(dataName,name)) {
+            if (!strncmp(nxclass,"SDS",3)) { /* Data has class "SDS" */
+               return NX_OK;
+            }
+            else {
+               printf ("NX_ERROR: %s is not data\n", dataName);
+               return NX_ERROR;
+            }
+         }
+      }
+   } while (status != NX_EOD);
+   printf ("NX_ERROR: %s does not exist\n", dataName);
+   return NX_EOD;
+}
+
+static int nxTypeSize(int dataType)
+{
+#ifdef XXXHDF4
+    return DFKNTsize(dataType);        
+#else
+	int type_size = 0;
+           if ((dataType == NX_CHAR) || (dataType == NX_INT8) || (dataType == NX_UINT8)) {
+            type_size = 1;
+         } else if ((dataType == NX_INT16) || (dataType == NX_UINT16)) {
+            type_size = 2;
+         } else if ((dataType == NX_INT32) || (dataType == NX_UINT32) || (dataType == NX_FLOAT32)) {
+            type_size = 4;
+         } else if (dataType == NX_FLOAT64 || dataType == NX_INT64 || dataType == NX_UINT64) {
+            type_size = 8;
+         }
+	 else
+	 {
+	    printf("error in type %d\n", dataType);
+ 	 }
+    return type_size;
+#endif
+}
diff --git a/applications/NXbrowse/SConscript b/applications/NXbrowse/SConscript
new file mode 100644
index 0000000..e69de29
diff --git a/applications/NXbrowse/make_vms.com b/applications/NXbrowse/make_vms.com
new file mode 100644
index 0000000..c606887
--- /dev/null
+++ b/applications/NXbrowse/make_vms.com
@@ -0,0 +1,13 @@
+$!
+$! $Id: make_vms.com,v 1.7 2000/08/09 13:48:11 faa Exp $
+$!
+$! Build command file for VMS
+$!
+$! Freddie Akeroyd, STFC ISIS facility, GB
+$!
+$ SET VERIFY
+$ DEFINE HDF5_ROOT AXPLIB$DISK:[HDF5.]  ! where you installed HDF5, trailing "." is needed
+$ copt := /prefix=all /float=ieee /include=([-.include],hdf5_root:[include]) /define=(IN_NEXUS_LIBRARY=1,HDF5,H5_USE_16_API)
+$!
+$ CC 'copt nxbrowse.c
+$ link /exec=nxbrowse.exe nxbrowse,[-.src]libnexus.olb/lib,HDF5_ROOT:[lib]hdf5.olb/lib,HDF5_ROOT:[lib]libz.olb/lib
diff --git a/applications/NXbrowse/nxbrowse.1 b/applications/NXbrowse/nxbrowse.1
new file mode 100644
index 0000000..e2cf3dc
--- /dev/null
+++ b/applications/NXbrowse/nxbrowse.1
@@ -0,0 +1,90 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH NXBROWSE 1 "June 2010"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxbrowse \- browse a NeXus file
+.SH SYNOPSIS
+.B nxbrowse
+.RI [ filename ] 
+.SH DESCRIPTION
+.B nxbrowse
+asks for a filename is none is given on the command line. The file is opened and can be interactively
+explored using the commands described below.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH OPTIONS
+No command line options are supported.
+.SH COMMANDS
+When the file is opened 
+.B nxbrowse
+will print out its version number and the contents of the NXroot node of the NeXus file followed by its prompt:
+.B NX>
+.br
+These case insensitive commands are recognised:
+.TP
+.B help
+Give out list of available commands. Synonym:
+.B info
+.TP
+.B exit 
+Exit the program. Synonym: 
+.B quit
+.TP
+.B dir
+List the contents of the current group. Synonym:
+.B ls
+.TP
+.B open \fIgroupName\fP
+Open the NeXus group groupName. Same as:
+.B cd \fIgroupName\fP
+.TP
+.B close
+Closes the NeXus group groupName, i.e. moves up one level in the hierarchy. Same as:
+.B cd ..
+.TP
+.B read \fIdataItem\fP [\fIdimension indicies ...\fP]
+Print the contents of the NeXus data item labelled dataItem.
+\fIdimension indicies\fP is an optional comma separated list of dimensions of the 
+correct rank to specify one value.
+.TP
+.B dump \fIdataItem\fP \fIfileName\fP
+Write the contents of the NeXus data item labelled dataItem to a new file named fileName.
+.TP
+.B byteaschar
+Toggle treating (signed and unsigned) byte data as characters.
+.PP
+If your version of 
+.B nxbrowse 
+has been compiled with readline support you can use 
+tab completion for commands, groups and data.
+.SH SEE ALSO
+.BR nxdir (1)
+.BR http://www.nexusformat.org
+.br
+.SH AUTHOR
+nxbrowse was originally written by Ray Osborn 
+.nh
+<ROsborn at anl.gov>
+.hy
+.PP
+This manual page was written by Tobias Richter 
+.nh
+<Tobias.Richter at diamond.ac.uk>
+.hy
+and may be used by others.
diff --git a/applications/NXconvert/CMakeLists.txt b/applications/NXconvert/CMakeLists.txt
new file mode 100644
index 0000000..cca3a56
--- /dev/null
+++ b/applications/NXconvert/CMakeLists.txt
@@ -0,0 +1,61 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2010 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(../../third_party ../../bindings/cpp)
+
+add_executable (nxconvert nxconvert.cpp nxconvert_common.h )
+
+set(NXCONVERT_LIB_SRC nxconvert_common.cpp nxconvert_common.h )
+
+add_library (NXconvert_Static_Library STATIC ${NXCONVERT_LIB_SRC} )
+
+add_library (NXconvert_Shared_Library SHARED ${NXCONVERT_LIB_SRC} )
+
+#set_target_properties(NXconvert_Static_Library PROPERTIES OUTPUT_NAME NXconvert)
+
+target_link_libraries(NXconvert_Static_Library NeXus_CPP_Static_Library
+                       ${READLINE_LINK} ${M_LINK} ${DL_LINK}
+                      ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK} ${HISTORY_LINK})
+
+target_link_libraries(NXconvert_Shared_Library NeXus_CPP_Shared_Library
+                       ${READLINE_LINK} ${M_LINK} ${DL_LINK}
+                      ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK} ${HISTORY_LINK})
+
+target_link_libraries(nxconvert NXconvert_Shared_Library
+                      ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK}
+                      ${DF_LINK} ${TERMCAP_LINK} ${HISTORY_LINK})
+
+set_property(TARGET NXconvert_Shared_Library PROPERTY ENABLE_EXPORTS YES) 
+
+install (TARGETS NXconvert_Static_Library NXconvert_Shared_Library nxconvert
+         RUNTIME DESTINATION bin COMPONENT Runtime
+         LIBRARY DESTINATION lib COMPONENT Runtime
+         ARCHIVE DESTINATION lib/nexus COMPONENT Development)
+
+install (FILES nxconvert.1 DESTINATION man/man1 COMPONENT Documentation)
+
diff --git a/applications/NXconvert/Makefile.am b/applications/NXconvert/Makefile.am
new file mode 100644
index 0000000..d9a1e78
--- /dev/null
+++ b/applications/NXconvert/Makefile.am
@@ -0,0 +1,47 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1239 2009-04-15 14:37:08Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+LIBNEXUSCPP=$(top_builddir)/bindings/cpp/libNeXusCPP.la
+AM_CPPFLAGS=-I. -DNXCONVERT_EXPORTS -I$(top_srcdir)/include -I$(top_srcdir)/bindings/cpp -I$(top_srcdir)/third_party
+
+EXTRA_DIST=SConscript $(man_MANS)
+
+lib_LTLIBRARIES = libnxconvert.la
+bin_PROGRAMS = nxconvert
+man_MANS = nxconvert.1
+
+libnxconvert_la_SOURCES = nxconvert_common.cpp nxconvert_common.h
+libnxconvert_la_LIBADD = $(LIBNEXUSCPP) $(LIBNEXUS)
+libnxconvert_la_LDFLAGS = -L$(top_builddir)/bindings/cpp/.libs -L$(top_builddir)/src/.libs @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ -version-info $(NXLTVERSINFO)
+
+nxconvert_SOURCES = nxconvert.cpp nxconvert_common.h
+nxconvert_LDADD = libnxconvert.la $(LIBNEXUS)
+nxconvert_LDFLAGS = -static $(LDFLAGS) @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXconvert/SConscript b/applications/NXconvert/SConscript
new file mode 100644
index 0000000..e69de29
diff --git a/applications/NXconvert/nxconvert.1 b/applications/NXconvert/nxconvert.1
new file mode 100644
index 0000000..7bd618b
--- /dev/null
+++ b/applications/NXconvert/nxconvert.1
@@ -0,0 +1,64 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH NXCONVERT 1 "June 2010"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxconvert \- convert a NeXus file between different on disk file formats
+.SH SYNOPSIS
+.B nxconvert
+[-x|-h4|-h5|-d|-o keepws|-o table] [\fIinfile\fP [\fIoutfile\fP]]
+.SH DESCRIPTION
+NeXus supports different file formats for physical storage on disk or other media.
+.B nxconvert
+allows the user to convert a file to a different backend.
+.PP
+If no output file is supplied on the command line, the program asks for one 
+interactively. Same if the input file is not given.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH OPTIONS
+The following options are supported:
+.TP
+.B -x 
+make outfile XML 
+.TP
+.B -h4 
+make outfile HDF4 (this is the default)
+.TP
+.B -h5 
+make outfile HDF5
+.TP
+.B -d
+make a XML based definition file used for validating NeXus files (i.e. remove the data).
+.TP
+.B -o keepws
+the XML file created should preserve whitespace.
+.TP
+.B -o table
+the XML file created should write the data in a table format where the columns and rows are easily imported into spreadsheet programs.
+.SH SEE ALSO
+.BR http://www.nexusformat.org
+.br
+.SH AUTHOR
+nxconvert was originally written by Freddie Akeroyd and Ray Osborn.
+.PP
+This manual page was written by Tobias Richter 
+.nh
+<Tobias.Richter at diamond.ac.uk>
+.hy
+and may be used by others.
diff --git a/applications/NXconvert/nxconvert.cpp b/applications/NXconvert/nxconvert.cpp
new file mode 100644
index 0000000..204283d
--- /dev/null
+++ b/applications/NXconvert/nxconvert.cpp
@@ -0,0 +1,160 @@
+/*-----------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+   
+  Utility to convert a NeXus file into HDF4/HDF5/XML/...
+ 
+  Author: Freddie Akeroyd, Ray Osborn
+ 
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+ 
+ $Id$
+-----------------------------------------------------------------------------*/
+
+#include <iostream>
+#include <stdexcept>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <vector>
+#ifdef _MSC_VER
+#else
+#include <unistd.h>
+#endif
+#include "napi.h"
+#include "nxconvert_common.h"
+#include "tclap/CmdLine.h"
+
+using std::runtime_error;
+using std::string;
+using std::vector;
+using namespace TCLAP;
+
+static const string NXCONVERT_VERSION("1.0");
+static const string EMPTY("");
+
+int main(int argc, char *argv[])
+{
+  try {
+    // set up the command line  arguments
+    CmdLine cmd("Convert a NeXus file between different on disk file formats.",
+		' ', NXCONVERT_VERSION, false);
+    SwitchArg xmlArg("x", "xml", "Output file in xml format", false);
+    vector<int> allowedHdf;
+    allowedHdf.push_back(4);
+    allowedHdf.push_back(5);
+    ValuesConstraint<int> allowedHdfC(allowedHdf);
+    ValueArg<int> hdfArg("h", "hdf", "Specify HDF version to write", false, 0, &allowedHdfC);
+    SwitchArg defArg("d", "dfn",
+		     "Output definition file used for validating NeXus files",
+		     false);
+    ValueArg<string> defValueArg("D", "definition",
+		      "Output definition file used for validating NeXus files. Requires a definition name.",
+			    false, EMPTY, "defintion");
+    vector<string> allowedXml;
+    allowedXml.push_back("keepws");
+    allowedXml.push_back("table");
+    ValuesConstraint<string> allowedXmlC(allowedXml);
+    ValueArg<string> xmlSpecialArg("o", "outputxml",
+				   "Special arguments for xml. keepws defines that the whitespace should be preserved. table specifies a format that is more easiliy imported into spreadsheet programs. Either option forces xml output",
+				   false, "", &allowedXmlC);
+    vector<Arg*> outputformats;
+    outputformats.push_back(&hdfArg);
+    outputformats.push_back(&xmlArg);
+    outputformats.push_back(&defArg);
+    outputformats.push_back(&defValueArg);
+    outputformats.push_back(&xmlSpecialArg);
+    cmd.xorAdd(outputformats);
+
+    UnlabeledMultiArg<string> FileArgs("Files", "Name of input and output files.",
+					false, EMPTY);
+    cmd.add(FileArgs);
+    // parse the arguments and configure converting the file
+    cmd.parse(argc, argv);
+    int nx_format = -1; // output format
+    int nx_write_access = 0; // output write access
+    int nx_read_access = NXACC_READ; // input read access
+    string definition_name; // NEXUS_SCHEMA_BASE is NULL
+
+
+    if (xmlArg.isSet()) {
+      nx_format = NX_XML;
+      nx_write_access |= NXACC_CREATEXML;
+    }
+    if (defArg.isSet() || defValueArg.isSet()) {
+      nx_format = NX_DEFINITION;
+      nx_write_access |= NXACC_CREATEXML;
+      if (defValueArg.isSet())
+	definition_name = defValueArg.getValue();
+    }
+    if (hdfArg.isSet()) {
+      int hdf_type = hdfArg.getValue();
+      if (hdf_type == 4) {
+          nx_format = NX_HDF4;
+          nx_write_access |= NXACC_CREATE4;
+      } else if (hdf_type == 5) {
+          nx_format = NX_HDF5;
+          nx_write_access |= NXACC_CREATE5;
+      }
+    }
+    if (xmlSpecialArg.isSet()) {
+      nx_format |= NX_XML;
+      nx_write_access |= NXACC_CREATEXML;
+      string type = xmlSpecialArg.getValue();
+      if (type.compare("keepws")) {
+	nx_write_access |= NXACC_NOSTRIP;
+	nx_read_access |= NXACC_NOSTRIP;
+      }
+      else if (type.compare("table")) {
+	nx_write_access |= NXACC_TABLE;
+      }
+    }
+    vector<string> file_args = FileArgs.getValue();
+    string inFile, outFile;
+    if (file_args.size() > 0)
+    {
+        inFile = file_args[0];
+    }
+    if (file_args.size() > 1)
+    {
+        outFile = file_args[1];
+    }
+
+    // do the actual conversion
+    std::cout << "Converting " << inFile << " to " << nx_formats[nx_format]
+	      << " NeXus file " << outFile << std::endl;
+    
+    if (convert_file(nx_format, inFile.c_str(), nx_read_access, outFile.c_str(), nx_write_access, definition_name.c_str()) != NX_OK) {
+      std::cerr << "Conversion failed" << std::endl;
+      return 1;
+    }
+
+  }
+  catch (ArgException &e) {
+    std::cerr << "PARSE ERROR:" << e.error() << " for arg " << e.argId()
+	      << std::endl;
+    return -1;
+  }
+  catch (runtime_error &e) {
+    std::cerr << "RUNTIME ERROR:" << e.what() << std::endl;
+    return -1;
+  }
+
+  // tell the user that everything went ok
+  std::cout << "Convertion successful." << std::endl;
+  return 0;
+}
+
diff --git a/applications/NXconvert/nxconvert_common.cpp b/applications/NXconvert/nxconvert_common.cpp
new file mode 100644
index 0000000..4761170
--- /dev/null
+++ b/applications/NXconvert/nxconvert_common.cpp
@@ -0,0 +1,374 @@
+/*-----------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+   
+  Utility to convert a NeXus file into HDF4/HDF5/XML/...
+ 
+  Author: Freddie Akeroyd, Ray Osborn
+ 
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+ 
+ $Id: nxconvert.c 991 2008-03-19 19:30:03Z Freddie Akeroyd $
+-----------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+#ifdef _MSC_VER
+#else
+#include <unistd.h>
+#endif
+#include "napi.h"
+#include "NeXusFile.hpp"
+#include "NeXusStream.hpp"
+#include "nxconvert_common.h"
+
+#include <vector>
+
+static int WriteGroup (int is_definition);
+static int WriteAttributes (int is_definition, int is_group);
+
+static bool is_valid_sds_name(const char* name)
+{
+    static const char* invalid_sds_names[] = { "Dim0.0", "UDim0.0", "CDF0.0", "Var0.0", "RIG0.0", "RI0.0" };
+    for(unsigned i=0; i<sizeof(invalid_sds_names)/sizeof(const char*); ++i)
+    {
+	if (!strcmp(name, invalid_sds_names[i]))
+	{
+	    return false;
+	}
+    }
+    return true;
+}
+
+
+static void clean_string(void* dataBuffer, int dataRank, int dataDimensions[])
+{
+	int i, n = 1;
+    	for(i=0; i<dataRank; ++i)
+    	{
+	    n *= dataDimensions[i];
+ 	}
+	for(i=0; i<n; ++i)
+	{
+	    if (!isprint(((const unsigned char*)dataBuffer)[i]))
+	    {
+		((char*)dataBuffer)[i] = '?';
+	    }
+	}
+}
+
+struct link_to_make
+{
+    char from[1024];   /* path of directory with link */
+    char name[256];    /* name of link */
+    char to[1024];     /* path of real item */
+    link_to_make(const char* _from, const char* _name, const char* _to)
+    {
+	strcpy(from, _from);
+	strcpy(name, _name);
+	strcpy(to, _to);
+    }
+    link_to_make(const link_to_make& val)
+    {
+	strcpy(from, val.from);
+	strcpy(name, val.name);
+	strcpy(to, val.to);
+    }
+    link_to_make& operator=(const link_to_make& val)
+    {
+	if (this != &val)
+	{
+	    strcpy(from, val.from);
+	    strcpy(name, val.name);
+	    strcpy(to, val.to);
+	}
+	return *this;
+    }
+};
+
+static std::vector<link_to_make> links_to_make;
+
+static char current_path[1024];
+
+static int add_path(const char* path)
+{
+    int i;
+    if (path != NULL)
+    {
+        i = strlen(current_path);
+        sprintf(current_path + i, "/%s", path);
+    }
+    return 0;
+}
+
+static int remove_path(const char* path)
+{
+    char *tstr; 
+    tstr = strrchr(current_path, '/');
+    if (path != NULL && tstr != NULL && !strcmp(path, tstr+1))
+    {
+	*tstr = '\0';
+    }
+    else
+    {
+	printf("path error\n");
+    }
+    return 0;
+}
+
+static NXhandle inId, outId;
+static const char* definition_name = NULL;
+
+int convert_file(int nx_format, const char* inFile, int nx_read_access, const char* outFile, int nx_write_access, const char* definition_name_)
+{
+   int nx_is_definition = 0;
+   if (definition_name_ != NULL && definition_name_[0] == '\0') {
+     definition_name = NULL;
+   } else {
+     definition_name = definition_name_;
+   }
+   char* tstr;
+   links_to_make.clear();
+   links_to_make.reserve(2000);
+   current_path[0] = '\0';
+   NXlink link;
+   if (nx_format == NX_DEFINITION)
+   {
+	nx_is_definition = 1;
+	char env_var[] = "NX_IS_DEFINITION=1";
+	putenv(env_var);
+   }
+/* Open NeXus input file and NeXus output file */
+   if (NXopen (inFile, nx_read_access, &inId) != NX_OK) {
+      printf ("NX_ERROR: Can't open %s\n", inFile);
+      return NX_ERROR;
+   }
+
+   if (NXopen (outFile, nx_write_access, &outId) != NX_OK) {
+      printf ("NX_ERROR: Can't open %s\n", outFile);
+      return NX_ERROR;
+   }
+
+/* Output global attributes */
+   if (WriteAttributes (nx_is_definition, 1) != NX_OK)
+   {
+	return NX_ERROR;
+   }
+/* Recursively cycle through the groups printing the contents */
+   if (WriteGroup (nx_is_definition) != NX_OK)
+   {
+	return NX_ERROR;
+   }
+/* close input */
+   if (NXclose (&inId) != NX_OK)
+   {
+	return NX_ERROR;
+   }
+/* now create any required links */
+       for(size_t i=0; i<links_to_make.size(); i++)
+       {
+	    if (NXopenpath(outId, links_to_make[i].to) != NX_OK) return NX_ERROR;
+	    if (NXgetdataID(outId, &link) == NX_OK  || NXgetgroupID(outId, &link) == NX_OK)
+	    {	
+	        if (NXopenpath(outId, links_to_make[i].from) != NX_OK) return NX_ERROR;
+	        tstr = strrchr(links_to_make[i].to, '/');
+		if (tstr != NULL)
+		{
+	            if (!strcmp(links_to_make[i].name, tstr+1))
+	            {
+	                if (NXmakelink(outId, &link) != NX_OK) return NX_ERROR;
+	            }
+	            else
+	            {
+	                if (NXmakenamedlink(outId, links_to_make[i].name, &link) != NX_OK) return NX_ERROR;
+	            }
+		}
+	    }
+	    else
+	    {
+	        return NX_ERROR;
+	    }
+	}
+/* Close the input and output files */
+   if (NXclose (&outId) != NX_OK)
+   {
+	return NX_ERROR;
+   }
+   return NX_OK;
+}
+
+/* Prints the contents of each group as XML tags and values */
+static int WriteGroup (int is_definition)
+{ 
+  
+   int i,  status, dataType, dataRank, dataDimensions[NX_MAXRANK];     
+   static const int slab_start[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+   static const int MAX_DEF_ARRAY_ELEMENTS_PER_DIM = 3; /* doesn't work yet - only 1 element is written */
+   NXname name, nxclass;
+   void *dataBuffer;
+   NXlink link;
+   std::string definition;
+   using namespace NeXus;
+   using namespace NeXus::Stream;
+   File nfile_in(inId), nfile_out(outId);
+
+   do {
+      status = NXgetnextentry (inId, name, nxclass, &dataType);
+      if (status == NX_ERROR) return NX_ERROR;
+      if (status == NX_OK) {
+//         std::cerr << "WriteGroup: " << name << "(" << nxclass << ")" << std::endl;
+         if (!strncmp(nxclass,"SDS",3)) {
+	    add_path(name);
+            if (NXopendata (inId, name) != NX_OK) return NX_ERROR;
+	    if (NXgetdataID(inId, &link) != NX_OK) return NX_ERROR;
+	    if (!strcmp(current_path, link.targetPath))
+	    {
+                if (NXgetinfo (inId, &dataRank, dataDimensions, &dataType) != NX_OK) return NX_ERROR;
+                if (NXmakedata (outId, name, dataType, dataRank, dataDimensions) != NX_OK) return NX_ERROR;
+                if (NXopendata (outId, name) != NX_OK) return NX_ERROR;
+		if ( is_definition && (dataType != NX_CHAR) )
+		{
+		    for(i=0; i<dataRank; ++i)
+		    {
+			if (dataDimensions[i] > MAX_DEF_ARRAY_ELEMENTS_PER_DIM)
+			{
+			    dataDimensions[i] = MAX_DEF_ARRAY_ELEMENTS_PER_DIM;
+			}
+		    }
+                    if (NXmalloc (&dataBuffer, dataRank, dataDimensions, dataType) != NX_OK) return NX_ERROR;
+                    if (NXgetslab (inId, dataBuffer, slab_start, dataDimensions)  != NX_OK) return NX_ERROR;
+                    if (NXputslab (outId, dataBuffer, slab_start, dataDimensions) != NX_OK) return NX_ERROR;
+		}
+		else
+		{
+                    if (NXmalloc (&dataBuffer, dataRank, dataDimensions, dataType) != NX_OK) return NX_ERROR;
+                    if (NXgetdata (inId, dataBuffer)  != NX_OK) return NX_ERROR;
+		    /* fix potential non-UTF8 character issue */
+		    if (is_definition && dataType == NX_CHAR)
+		    {
+			clean_string(dataBuffer, dataRank, dataDimensions);
+		    }
+                    if (NXputdata (outId, dataBuffer) != NX_OK) return NX_ERROR;
+		}
+                if (WriteAttributes (is_definition, 0) != NX_OK) return NX_ERROR;
+                if (NXclosedata (outId) != NX_OK) return NX_ERROR;
+                if (NXfree((void**)&dataBuffer) != NX_OK) return NX_ERROR;
+	        remove_path(name);
+	    }
+	    else
+	    {
+	        remove_path(name);
+		links_to_make.push_back(link_to_make(current_path, name, link.targetPath));
+	    }
+            if (NXclosedata (inId) != NX_OK) return NX_ERROR;
+         }
+         /* napi4.c returns UNKNOWN for DFTAG_VH in groups */
+         else if (!strcmp(nxclass, "UNKNOWN") || !is_valid_sds_name(nxclass)) {
+             ;
+         }
+         else {
+            if (NXopengroup (inId, name, nxclass) != NX_OK) return NX_ERROR;
+	    add_path(name);
+	    if (NXgetgroupID(inId, &link) != NX_OK) return NX_ERROR;
+	    if (!strcmp(current_path, link.targetPath))
+	    {
+                if (NXmakegroup (outId, name, nxclass) != NX_OK) return NX_ERROR;
+                if (NXopengroup (outId, name, nxclass) != NX_OK) return NX_ERROR;
+                if (WriteAttributes (is_definition, 1) != NX_OK) return NX_ERROR;
+		if (is_definition && !strcmp(nxclass, "NXentry"))
+		{
+		    if (definition_name != NULL)
+		    {
+		        nfile_out.putAttr("xsi:type", definition_name);
+		    }
+  		    else
+		    {
+		        try {
+			    nfile_in.openData("definition");
+		            definition = nfile_in.getStrData();
+		            nfile_in.closeData();
+		            nfile_out.putAttr("xsi:type", definition);
+		        }
+		        catch(std::exception& ex)
+		        {
+			    ; // definition not found
+                        }
+		    }
+		}
+                if (WriteGroup (is_definition) != NX_OK) return NX_ERROR;
+	        remove_path(name);
+	    }
+	    else
+	    {
+	        remove_path(name);
+		links_to_make.push_back(link_to_make(current_path, name, link.targetPath));
+         	if (NXclosegroup (inId) != NX_OK) return NX_ERROR;
+	    }
+         }
+      }
+      else if (status == NX_EOD) {
+         if (NXclosegroup (inId) != NX_OK) return NX_ERROR;
+         if (NXclosegroup (outId) != NX_OK) return NX_ERROR;
+         return NX_OK;
+      }
+   } while (status == NX_OK);
+   return NX_OK;
+}
+
+static int WriteAttributes (int is_definition, int is_group)
+{
+   int status, i, attrLen, attrType;
+   NXname attrName;
+   void *attrBuffer;
+   int found_napitype = 0;
+
+   i = 0;
+   do {
+      status = NXgetnextattr (inId, attrName, &attrLen, &attrType);
+      if (status == NX_ERROR) return NX_ERROR;
+      if (status == NX_OK) {
+         if (strcmp(attrName, "NAPItype") == 0)
+	 {
+		found_napitype = 1;
+	 }
+         if (strcmp(attrName, "NeXus_version") && strcmp(attrName, "XML_version") &&
+             strcmp(attrName, "HDF_version") && strcmp(attrName, "HDF5_Version") && 
+             strcmp(attrName, "file_name") && strcmp(attrName, "file_time")) {
+            attrLen++; /* Add space for string termination */
+            if (NXmalloc((void**)&attrBuffer, 1, &attrLen, attrType) != NX_OK) return NX_ERROR;
+            if (NXgetattr (inId, attrName, attrBuffer, &attrLen , &attrType) != NX_OK) return NX_ERROR;
+	    if (is_definition && attrType == NX_CHAR)
+	    {
+		clean_string(attrBuffer, 1, &attrLen);
+	    }
+            if (NXputattr (outId, attrName, attrBuffer, attrLen , attrType) != NX_OK) return NX_ERROR;
+            if (NXfree((void**)&attrBuffer) != NX_OK) return NX_ERROR;
+         }
+         i++;
+      }
+   } while (status != NX_EOD);
+   // if we are creating a reduced file for definiiton purposes,
+   // make sure we always have a NAPItype attribute
+   if (is_definition && !is_group && !found_napitype)
+   {
+       // need to be cleverer - cannot do this
+       //if (NXputattr (outId, "NAPItype", (void*)"NX_CHAR", strlen("NX_CHAR"), NX_CHAR) != NX_OK) return NX_ERROR;
+   }
+   return NX_OK;
+}
+
diff --git a/applications/NXconvert/nxconvert_common.h b/applications/NXconvert/nxconvert_common.h
new file mode 100644
index 0000000..bb3708f
--- /dev/null
+++ b/applications/NXconvert/nxconvert_common.h
@@ -0,0 +1,46 @@
+/*-----------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+   
+  Utility to convert a NeXus file into HDF4/HDF5/XML/...
+ 
+  Author: Freddie Akeroyd, Ray Osborn
+ 
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+ 
+ $Id: nxconvert.c 991 2008-03-19 19:30:03Z Freddie Akeroyd $
+-----------------------------------------------------------------------------*/
+
+#ifndef NXCONVERT_COMMON
+#define NXCONVERT_COMMON 1
+
+#define NX_XML		0
+#define NX_HDF4		1
+#define NX_HDF5		2
+#define NX_DEFINITION	3
+
+static const char* nx_formats[] = { "XML", "HDF4", "HDF5", "DEFINITION", NULL };
+
+#ifdef _WIN32
+#ifdef NXCONVERT_EXPORTS
+__declspec(dllexport)
+#else
+__declspec(dllimport)
+#endif /* NXCONVERT_EXPORTS */ 
+#endif /* _WIN32 */
+extern int convert_file(int nx_format, const char* inFile, int nx_read_access, const char* outFile, int nx_write_access, const char* definition_name_);
+
+#endif /* NXCONVERT_COMMON */
diff --git a/applications/NXdir/.cvsignore b/applications/NXdir/.cvsignore
new file mode 100644
index 0000000..96d238e
--- /dev/null
+++ b/applications/NXdir/.cvsignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+.libs
+nxdir
diff --git a/applications/NXdir/CHANGES b/applications/NXdir/CHANGES
new file mode 100644
index 0000000..e17bcba
--- /dev/null
+++ b/applications/NXdir/CHANGES
@@ -0,0 +1,83 @@
+CHANGES
+======================================================================
+v0.2.5 - May 7, 2004
+
+  P.F.Peterson - Fixed bug in converting void* to concrete types. Also
+  added support for NX_INT8 and NX_UINT8.
+
+v0.2.4 - April 15, 2004
+
+  P.F.Peterson - Added ability to write an NXdata to file as long as
+  the rank of the data is one or two.
+
+v0.2.3 - March 17, 2004
+
+  P.F.Peterson - Implemented a separate recursion level for building
+  and purging tree. Now relative and absolute paths act the same way.
+
+  P.F.Peterson - Added ability to anchor at the end of a path.
+
+v0.2.2 - February 17, 2004
+
+  P.F.Peterson - Fixed infinite loop bug when path was specified as "*".
+
+  P.F.Peterson - Made recursion option invisible.
+
+  P.F.Peterson - Fixed bug where code entered an infinite loop when
+  parameters that required values were not given values.
+
+v0.2.1 - February 13, 2004
+
+  P.F.Peterson - Made "*" fully functional in absolute paths.
+
+  P.F.Peterson - Added "*" to list of characters with special meaning
+  in the path. Works completely with relative paths, but only at
+  begining or end of absolute paths.
+
+  P.F.Peterson - Added verbose flag which prints message if nothing
+  found in file.
+
+  P.F.Peterson - If only one file is detected do not print filename on
+  output.
+
+  P.F.Peterson - Changed style of command line argument with flags to
+  allow space between flag and value.
+
+v0.2.0 - February 03, 2004
+
+  P.F.Peterson - Added hooks to allow for changing format of how tree
+  and data is printed. Exposed those to the command line.
+
+  P.F.Peterson - Major rewrite to have -p be both relative and
+  absolute path, also allowing to specify name, type, or any (with
+  '.').
+
+  P.F.Peterson - Put default values for command line options in
+  'nxdir.h'.
+
+v0.1.0 - January 15, 2004
+
+  P.F.Peterson - Promoted attributes to the level of fields (less
+  special code).
+
+  P.F.Peterson - Fixed bug in tree purging code.
+
+  P.F.Peterson - Added code to allow for arbitraray attribute
+  retrieving.
+
+  P.F.Peterson - Improved performence of converting data to string by
+  one order of magnitude. Also added hooks in main.cpp for timing
+  tests.
+
+  P.F.Peterson - Added a recurse option (needs to be smarter), long
+  option (how much of arrays to print), and rudimentary ability to
+  print 2D arrays.
+
+  P.Kienzle - Fixed string_util.cpp by adding a couple of "using
+  lines".
+
+  P.F.Peterson - Added README, LICENSE, CHANGES, and TODO
+
+v0.0.1 - January 6, 2004
+
+  Initial Release
diff --git a/applications/NXdir/CMakeLists.txt b/applications/NXdir/CMakeLists.txt
new file mode 100644
index 0000000..b91c05d
--- /dev/null
+++ b/applications/NXdir/CMakeLists.txt
@@ -0,0 +1,40 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_executable (nxdir main.cpp string_util.cpp tree.cpp data.cpp
+                data_writer.cpp nxdir.h nxdir_help.h)
+
+target_link_libraries(nxdir NeXus_Shared_Library 
+                      ${MXML_LINK} ${READLINE_LINK} ${M_LINK}
+                      ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK}
+                      ${HISTORY_LINK} )
+
+install (TARGETS nxdir DESTINATION bin COMPONENT Runtime)
+install (FILES nxdir.1 DESTINATION man/man1 COMPONENT Documentation)
+
+
diff --git a/applications/NXdir/LICENSE b/applications/NXdir/LICENSE
new file mode 100644
index 0000000..3ba71bc
--- /dev/null
+++ b/applications/NXdir/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+              Spallation Neutron Source at Oak Ridge National Laboratory
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/applications/NXdir/Makefile.am b/applications/NXdir/Makefile.am
new file mode 100644
index 0000000..c54e975
--- /dev/null
+++ b/applications/NXdir/Makefile.am
@@ -0,0 +1,57 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+bin_PROGRAMS = nxdir
+man_MANS = nxdir.1
+
+nxdir_SOURCES = main.cpp string_util.cpp tree.cpp data.cpp data_writer.cpp \
+		nxdir.h nxdir_help.h
+nxdir_LDADD = $(LIBNEXUS)
+nxdir_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ $(LDFLAGS)
+EXTRA_DIST = CHANGES LICENSE README TODO $(man_MANS)
+
+## extra dependencies (don;t thing needed now)
+##main.o: main.cpp nxdir.h nxdir_help.h
+##data.o: data.cpp nxdir.h
+##string_util.o: string_util.cpp nxdir.h
+##tree.o: tree.cpp nxdir.h
+
+#VERS=0.2.5
+# target taken from "Art of Unix Programming chp19sec02" by ESR
+#NXdir-$(VERS).tar.gz: $(SRC)
+#	@ls $(SRC) | sed s:^:NXdir-$(VERS)/: >MANIFEST
+#	@(cd ..; ln -s NXdir NXdir-$(VERS))
+#	(cd ..;tar -czvf NXdir/NXdir-$(VERS).tar.gz `cat NXdir/MANIFEST`)
+#	@(cd ..; rm NXdir-$(VERS))
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXdir/README b/applications/NXdir/README
new file mode 100644
index 0000000..88a3918
--- /dev/null
+++ b/applications/NXdir/README
@@ -0,0 +1,25 @@
+README
+======================================================================
+
+OVERVIEW
+--------
+NXdir is a utility for querying a NeXus file about its contents. Full
+documentation can be found by running "nxdir -h".
+
+INSTALLATION
+------------
+To compile on Linux:
+
+1) Edit "Makefile" to suit your environment
+2) Type "make"
+
+To compile on MAC OSX:
+
+1) Edit "Makefile" to suit your environment. Specifically add
+"-flat_namespace" to "LD_FLAGS" "-D__unix" to "C_FLAGS".
+2) Type "make"
+
+To compile on IRIX:
+
+1) Edit "Makefile" to suit your environment
+2) Type "make"
diff --git a/applications/NXdir/TODO b/applications/NXdir/TODO
new file mode 100644
index 0000000..45fc08c
--- /dev/null
+++ b/applications/NXdir/TODO
@@ -0,0 +1,5 @@
+TODO
+======================================================================
+- Printing value of n-dimensional fields.
+
+- Switch to using autoconf.
diff --git a/applications/NXdir/data.cpp b/applications/NXdir/data.cpp
new file mode 100644
index 0000000..7e48ea0
--- /dev/null
+++ b/applications/NXdir/data.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <iostream>
+#include <cstring>
+#include <string>
+#include <map>
+#include "nxdir.h"
+
+#define ellipse std::string("...,")
+#define MAX_DIMS 2
+
+using std::string;
+
+/*
+ * This creates a string describing the dimensions of an n-dimensional
+ * field at a specified path. This will return an empty string if the
+ * Path does not point to an SDS.
+ */
+static string read_dims_as_string(NXhandle handle, Path path){
+  if(path.rbegin()->type!=SDS)
+    return string("");
+
+  open_path(handle,path);
+  
+  int rank=0;
+  int type=0;
+  int dims[NX_MAXRANK];
+  if(NXgetinfo(handle,&rank,dims,&type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXgetinfo failed";
+  }
+
+  close_path(handle,path);
+
+  string result("[");
+  for( int i=0 ; i<rank ; i++ ){
+    result=result+int_to_str(dims[i]);
+    if(i+1<rank)
+      result=result+",";
+  }
+  result=result+"]";
+
+  return result;
+}
+
+/*
+ * This collects the dimension strings for the entire tree together.
+ */
+extern StringVector read_all_dims_as_string(NXhandle handle, const Tree tree){
+  StringVector result;
+  int length=tree.size();
+
+  std::string dims;
+  for( int i=0 ; i<length ; i++ ){
+    dims=read_dims_as_string(handle,tree[i]);
+    result.push_back(dims);
+  }
+
+  return result;
+}
+
+
+/*
+ * This reads the value of an attribute at the given Path and returns
+ * it as a string.
+ */
+extern string read_attr_as_string(NXhandle handle, const Path &path, const PrintConfig &config){
+  if(path.rbegin()->type!=ATTR)
+    return string("");
+
+  open_path(handle,path);
+
+  char attr_name[GROUP_STRING_LEN];
+  strcpy(attr_name,path.rbegin()->name.c_str());
+  int attr_length,attr_type;
+
+  if(!has_attr(handle,attr_name,&attr_length,&attr_type)){
+    close_path(handle,path);
+    return string("");
+  }
+
+  // allocate array to store data
+  int dims[1]={attr_length+1};
+  void *data;
+  if(NXmalloc(&data,1,dims,attr_type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXmalloc failed";
+  }
+
+  // get the value
+  if(NXgetattr(handle,attr_name,data,dims,&attr_type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXgetattr failed";
+  }
+
+  // close the path
+  close_path(handle,path);
+
+  // convert the value to a string
+  string result=oneD_to_string(data,attr_length,attr_type,config);
+
+  // release memory
+  if(NXfree(&data)!=NX_OK)
+    throw "NXfree failed";
+
+  return result;
+}
+
+/*
+ * This read the value of an integer attrubte. If it isn't an integer
+ * an exception is thrown.
+ */
+extern long read_int_attr(NXhandle handle, const Path &path){
+  if(path.rbegin()->type!=ATTR)
+    throw "Path is to non-attribute";
+
+  open_path(handle,path);
+  char attr_name[GROUP_STRING_LEN];
+  strcpy(attr_name,path.rbegin()->name.c_str());
+  int attr_length,attr_type;
+
+  if(!has_attr(handle,attr_name,&attr_length,&attr_type)){
+    close_path(handle,path);
+    throw "Specified attribute does not exist";
+  }
+
+  // check that the length is okay
+  if(attr_length!=1)
+    throw "read_int_attr only supports scalar attributes";
+
+  // allocate array to store data
+  int dims[1]={attr_length+1};
+  void *data;
+  if(NXmalloc(&data,1,dims,attr_type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXmalloc failed";
+  }
+
+  // check that the type is okay
+  if(attr_type==NX_INT8){
+  }else if(attr_type==NX_INT16){
+  }else if(attr_type==NX_INT32){
+  }else if(attr_type==NX_INT64){
+  }else if(attr_type==NX_UINT8){
+  }else if(attr_type==NX_UINT16){
+  }else if(attr_type==NX_UINT32){
+  }else if(attr_type==NX_UINT64){
+  }else{
+    throw "Unsupported type in read_int_attr";
+  }
+
+  // get the value
+  if(NXgetattr(handle,attr_name,data,dims,&attr_type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXgetattr failed";
+  }
+
+  close_path(handle,path);
+
+  // convert the value to an integer
+  long result;
+  if(attr_type==NX_INT8)
+    result=static_cast<long>(((int8_t *)data)[0]);
+  else if(attr_type==NX_INT16)
+    result=static_cast<long>(((int16_t *)data)[0]);
+  else if(attr_type==NX_INT32)
+    result=static_cast<long>(((int32_t *)data)[0]);
+  else if(attr_type==NX_INT64)
+    result=static_cast<long>(((int64_t *)data)[0]);
+  else if(attr_type==NX_UINT8)
+    result=static_cast<long>(((uint8_t *)data)[0]);
+  else if(attr_type==NX_UINT16)
+    result=static_cast<long>(((uint16_t *)data)[0]);
+  else if(attr_type==NX_UINT32)
+    result=static_cast<long>(((uint32_t *)data)[0]);
+  else if(attr_type==NX_UINT64)
+    result=static_cast<long>(((uint64_t *)data)[0]);
+  else
+    throw "Unsupported type cast in read_int_attr";
+
+  // release memory
+  if(NXfree(&data)!=NX_OK)
+    throw "NXfree failed";
+
+  return result;
+}
+
+/*
+ * This reads the value of a data item (or attribute) and returns its
+ * value as a string. It will return an empty string if the type of
+ * the ending Node in the Path is not understood.
+ */
+static string read_data_as_string(NXhandle handle, Path path,
+                                                           PrintConfig config){
+  // call the code to read the attribute
+  if(path.rbegin()->type==ATTR)
+    return read_attr_as_string(handle,path,config);
+
+  // if this is not an SDS return an empty string
+  if(path.rbegin()->type!=SDS)
+    return string("");
+
+  open_path(handle,path);
+  
+  // determine the rank and dimension
+  int rank=0;
+  int type=0;
+  int dims[NX_MAXRANK];
+  if(NXgetinfo(handle,&rank,dims,&type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXgetinfo failed";
+  }
+
+  // if the rank is too big close the path and return an empty string
+  if(rank>MAX_DIMS){
+    close_path(handle,path);
+    return "";
+  }
+
+  // allocate space for data
+  void *data;
+  if(NXmalloc(&data,rank,dims,type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXmalloc falied";
+  }
+
+  // retrieve data from the file
+  if(NXgetdata(handle,data)!=NX_OK){
+    close_path(handle,path);
+    throw "NXgetdata failed";
+  }
+
+  // close the path
+  close_path(handle,path);
+
+  // convert to string
+  string result=to_string(data,dims,rank,type,config);
+
+  //free up the pointer
+  if(NXfree(&data)!=NX_OK)
+    throw "NXfree failed";
+
+  return result;
+}
+
+/**
+ * Read the value of all elements of the tree.
+ */
+extern StringVector read_all_data_as_string(NXhandle handle, const Tree tree,
+                                                     const PrintConfig config){
+  StringVector result;
+  int length=tree.size();
+
+  std::string data;
+  for( int i=0 ; i<length ; i++ ){
+    try{
+      data=read_data_as_string(handle,tree[i],config);
+    }catch(const char *str){
+      data=str;
+    }
+    result.push_back(data);
+  }
+
+  return result;
+}
diff --git a/applications/NXdir/data_writer.cpp b/applications/NXdir/data_writer.cpp
new file mode 100644
index 0000000..3a4ee71
--- /dev/null
+++ b/applications/NXdir/data_writer.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <map>
+#include "nxdir.h"
+//#include <utility> // REMOVE
+
+#define NXDATA "NXdata"
+
+using std::string;
+using std::cout;
+using std::endl;
+using std::ostream;
+
+typedef std::vector<Node> NodeVector;
+typedef std::vector<Path> PathVector;
+typedef std::map<std::string,std::string> PathMap;
+
+// define a "data" structure
+typedef struct{
+  Path path;
+  string name;
+  string units;
+  int type;
+  int rank;
+  int dims[NX_MAXRANK];
+  int signal;
+  void *data;
+  PathMap unknown;
+}Data;
+
+// define an "axis" structure
+typedef struct{
+  Path path;
+  string name;
+  string units;
+  int type;
+  int dims[NX_MAXRANK];
+  int axis;
+  int primary;
+  void *data;
+  PathMap unknown;
+}Axis;
+
+static bool path_is_okay(const Path &path){
+  if(path.rbegin()->type==NXDATA)
+    return true;
+  else
+    return false;
+}
+
+extern Tree remove_nondata(const Tree &tree){
+  if(tree.empty())
+    return tree;
+
+  Tree good;
+  for( Tree::const_iterator path=tree.begin() ; path!=tree.end() ; path++ ){
+    if(path_is_okay(*path))
+      good.push_back(*path);
+  }
+
+  return good;
+}
+
+static Path copy_non_attr(const Path &path){
+  Path new_path;
+  for( Path::const_iterator node=path.begin() ; node!=path.end() ; node++ ){
+    if(node->type!=ATTR)
+      new_path.push_back(*node);
+    else
+      break;
+  }
+  return new_path;
+}
+
+static bool contains(const PathVector &vec, const Path &path){
+  for( PathVector::const_iterator comp_path=vec.begin() ; comp_path!=vec.end() ;comp_path++ ){
+    if(compPath(*comp_path,path)==compPath(path,*comp_path))
+      return true;
+  }
+  return false;
+}
+
+static PathVector find_int_attr(NXhandle handle, const Tree &tree,
+                                   const string attr_name, const int attr_val){
+  PathVector attr_tree;
+
+  // find the named attribute
+  for(Tree::const_iterator path=tree.begin() ; path!=tree.end() ; path++ ){
+    Node node=*((*path).rbegin());
+    if(node.type!=ATTR)
+      continue;
+    if(node.name==attr_name){
+      if(read_int_attr(handle,*path)==attr_val){
+        Path short_path=copy_non_attr(*path);
+        if(!contains(attr_tree,short_path))
+          attr_tree.push_back(short_path);
+      }
+    }
+  }
+
+  if(attr_tree.size()<=0)
+    throw "did not find attribute";
+  else 
+    return attr_tree;
+}
+
+static bool starts_with(const Path &path, const Path &begin){
+  Path::const_iterator node=path.begin();
+
+  for( Path::const_iterator begin_node=begin.begin() ; begin_node!=begin.end() ; begin_node++ ){
+    if(begin_node->type!=node->type)
+      return false;
+    if(begin_node->name!=node->name)
+      return false;
+    node++;
+  }
+
+  return true;
+}
+
+static void fill_axis(NXhandle handle, Axis &axis, PathVector &tree,
+                                                    const PrintConfig &config){
+  axis.name=(axis.path.rbegin())->name;
+  axis.type=-1;
+  axis.dims[0]=-1;
+
+  Path units_path;
+  Path primary_path;
+  Path axis_path;
+  PathVector attr_paths;
+
+  // sort out everything
+  for( PathVector::const_iterator path=tree.begin() ; path!=tree.end() ; 
+                                                                      path++ ){
+    Node end_node=*((*path).rbegin());
+    if(end_node.type==ATTR){
+      if(end_node.name=="units"){
+        units_path=*path;
+      }else if(end_node.name=="primary"){
+        primary_path=*path;
+      }else if(end_node.name=="axis"){
+        axis_path=*path;
+      }else{
+        attr_paths.push_back(*path);
+      }
+    }
+  }
+
+  // get the attributes and fill the structure
+  if(units_path.size()>0)
+    axis.units=read_attr_as_string(handle,units_path,config);
+  if(axis_path.size()>0)
+    axis.axis=read_int_attr(handle,axis_path);
+  if(primary_path.size()>0)
+    axis.primary=read_int_attr(handle,primary_path);
+  else
+    axis.primary=-1;
+
+  // get the unknown attributes
+  for( PathVector::const_iterator path=attr_paths.begin() ; path!=attr_paths.end() ; path++ ){
+    string value=read_attr_as_string(handle,*path,config);
+    string key=(*path).rbegin()->name;
+
+    axis.unknown[key]=value;
+  }
+
+  // -- from here down gets the data
+  open_path(handle,axis.path);
+
+  // get the rank, dimensions and type
+  int rank;
+  if(NXgetinfo(handle,&rank,axis.dims,&axis.type)!=NX_OK){
+    close_path(handle,axis.path);
+    throw "NXgetinfo failed";
+  }
+
+  if(rank>1){
+    close_path(handle,axis.path);
+    throw "RANK>1";
+  }
+
+  // allocate space for the data
+  if(NXmalloc(&axis.data,rank,axis.dims,axis.type)!=NX_OK){
+    close_path(handle,axis.path);
+    throw "NXmalloc failed";
+  }
+
+  // retrieve the data from the file
+  if(NXgetdata(handle,axis.data)!=NX_OK){
+    close_path(handle,axis.path);
+    throw "NXgetdata failed";
+  }
+
+  // close the path
+  close_path(handle,axis.path);
+}
+
+static void fill_data(NXhandle handle, Data &data, PathVector &data_tree,
+                                                    const PrintConfig &config){
+  // local variables to put stuff in
+  Path units_path;
+  Path signal_path;
+  PathVector attr_paths;
+
+  // sort out everything
+  for( PathVector::const_iterator path=data_tree.begin() ; path!=data_tree.end() ; path++ ){
+    Node end_node=*((*path).rbegin());
+    if(end_node.type==ATTR){
+      if(end_node.name=="units"){
+        units_path=*path;
+      }else if(end_node.name=="signal"){
+        signal_path=*path;
+      }else{
+        attr_paths.push_back(*path);
+      }
+    }else{
+      data.path=*path;
+      data.name=end_node.name;
+      //data.type=end_node.type;
+    }
+  }
+
+  // get the attributes and fill the structure
+  data.units=read_attr_as_string(handle,units_path,config);
+  data.signal=read_int_attr(handle,signal_path);
+
+  // get the unknown attributes
+  for( PathVector::const_iterator path=attr_paths.begin() ; path!=attr_paths.end() ; path++ ){
+    string value=read_attr_as_string(handle,*path,config);
+    string key=(*path).rbegin()->name;
+    
+    data.unknown[key]=value;
+  }
+
+  // ----- from here down  gets the data
+
+  // open up to the right place
+  open_path(handle,data.path);
+
+  // get the rank, dimensions and type
+  if(NXgetinfo(handle,&data.rank,data.dims,&data.type)!=NX_OK){
+    close_path(handle,data.path);
+    throw "NXgetinfo failed";
+  }
+
+  // allocate space for the data
+  if(NXmalloc(&data.data,data.rank,data.dims,data.type)!=NX_OK){
+    close_path(handle,data.path);
+    throw "NXmalloc failed";
+  }
+
+  // retrieve the data from the file
+  if(NXgetdata(handle,data.data)!=NX_OK){
+    close_path(handle,data.path);
+    throw "NXgetdata failed";
+  }
+
+  // close the path
+  close_path(handle,data.path);
+}
+
+static void split_vec(PathVector &full_vec, PathVector &new_vec,
+                                                       const Path &split_path){
+  PathVector old_full;
+  old_full.insert(old_full.begin(),full_vec.begin(),full_vec.end());
+  full_vec.erase(full_vec.begin(),full_vec.end());
+  
+  for( PathVector::const_iterator path=old_full.begin() ; path!=old_full.end()
+                                                              ; path++ ){
+    if(starts_with(*path,split_path))
+      new_vec.push_back(*path);
+    else
+      full_vec.push_back(*path);
+  }
+}
+
+static string row_to_str(const void *data, const int offset, const int row_len, const int type, const PrintConfig config){
+  string result="";
+  for( int i=0 ; i<row_len ; i++ ){
+    result+=voidptr_to_str(data,offset+i,type);
+    if(i+1<row_len)
+      result+=" ";
+  }
+  return result;
+}
+
+static void write_overview(ostream &out, const Path &path, const PrintConfig &config){
+  out << "# ORIGINAL FILE: " << config.filename << endl;
+  out << "# NXdata LOCATION: " << path_to_str(path,NAME) << endl;
+}
+
+static void write_data_header(ostream &out, const Data &data,const PrintConfig &config){
+  out << "# DATA(signal=" << data.signal << "): " << data.name;
+  if(data.rank==1)
+    out << "[";
+  out << oneD_to_string(data.dims,data.rank,NX_INT16,config);
+  if(data.rank==1)
+    out << "]";
+  out << " (" << data.units << ")" << endl;
+  for( PathMap::const_iterator pair=data.unknown.begin() ; pair!=data.unknown.end() ; pair++ ){
+    out << "#     " << pair->first <<  "=" << pair->second << endl;
+  }
+}
+
+static void write_axis_header(ostream &out, const Axis &axis, const PrintConfig &config){
+  out << "# AXIS";
+  if(axis.primary>0)
+    out << "(primary=" << axis.primary << ")";
+  out << ": " << axis.name << "[" << oneD_to_string(axis.dims,1,NX_INT16,config) << "] (" << axis.units << ")" << endl;
+  for( PathMap::const_iterator pair=axis.unknown.begin() ; pair!=axis.unknown.end() ; pair++ ){
+    out << "#     " << pair->first <<  "=" << pair->second << endl;
+  }
+}
+
+static void write_1D_data(ostream &out,const Path &path, const Data &data,
+                                  const Axis &axis, const PrintConfig &config){
+  // overview information
+  write_overview(out,path,config);
+
+  // information about data
+  write_data_header(out,data,config);
+
+  // information about axis
+  write_axis_header(out,axis,config);
+
+  // space between header and data
+  out << endl;
+
+  // column headings
+  out << "#  " << axis.name << "     " << data.name << endl;
+
+  // figure out the range and if there is one more "axis" than "data"
+  int range=axis.dims[0];
+  bool is_histogram=false;
+  if(data.dims[0]<range)
+    is_histogram=1;
+  else if(data.dims[0]>range)
+    range=data.dims[0];
+
+  // print data itself
+  for( int i=0 ; i<range ; i++ ){
+    out << voidptr_to_str(axis.data,i,axis.type);
+    if(!is_histogram || i<range-1)
+      out << "  " << voidptr_to_str(data.data,i,data.type);
+    out << endl;
+  }
+}
+
+static void write_2D_data(ostream &out, const Path &path, const Data &data,
+              const Axis &axis1, const Axis &axis2, const PrintConfig &config){
+  // overview information
+  write_overview(out,path,config);
+  
+  // information about axis1
+  write_axis_header(out,axis1,config);
+  out << row_to_str(axis1.data,0,axis1.dims[0],axis1.type,config) << endl;
+  out << endl;
+
+  // information about axis1
+  write_axis_header(out,axis2,config);
+  out << row_to_str(axis2.data,0,axis2.dims[0],axis2.type,config) << endl;
+  out << endl;
+
+  // information about data
+  write_data_header(out,data,config);
+  for( int i=0 ; i<data.dims[0] ; i++ )
+    out << row_to_str(data.data,i,data.dims[1],data.type,config) << endl;
+}
+
+static void write_one_data(ostream &out, NXhandle handle, const Path &path,
+                                                    const PrintConfig &config){
+  Tree tree=build_rel_tree(handle,path,-1); // build full tree from this point
+
+  Path data_path;
+  try{
+    PathVector vec=find_int_attr(handle,tree,"signal",1);
+    if(vec.size()==1)
+      data_path=*(vec.begin());
+  }catch( const char *str){
+    cout << endl;
+    return;
+  }
+
+  PathVector data_vec;
+  split_vec(tree,data_vec,data_path);
+
+  Data data;
+  fill_data(handle,data,data_vec,config);
+
+  // check the rank for filling axes
+  Axis axis1;
+  try{
+    PathVector vec=find_int_attr(handle,tree,"axis",1);
+    if(vec.size()==1)
+      axis1.path=*(vec.begin());
+    else
+      throw "more than one axis=1";
+  }catch(const char *str){
+    cout << "!!!!! random stuff wrong finding axis=1" << endl;
+    return;
+  }
+  PathVector axis1_vec;
+  split_vec(tree,axis1_vec,axis1.path);
+  fill_axis(handle,axis1,axis1_vec,config);
+
+  // print out the results for 1D data
+  if(data.rank==1){
+    write_1D_data(out,path,data,axis1,config);
+    return;
+  }
+
+  Axis axis2;
+  try{
+    PathVector vec=find_int_attr(handle,tree,"axis",2);
+    if(vec.size()==1)
+      axis2.path=*(vec.begin());
+    else
+      throw "more than one axis=2";
+  }catch(const char *str){
+    cout << "!!!!! random stuff wrong finding axis=1" << endl;
+    return;
+  }
+  PathVector axis2_vec;
+  split_vec(tree,axis2_vec,axis2.path);
+  fill_axis(handle,axis2,axis2_vec,config);
+
+  // print out the results for 2D data
+  if(data.rank==2){
+    write_2D_data(out,path,data,axis1,axis2,config);
+    return;
+  }
+
+  cout << "NO SUPPORT FOR DATA RANK>2" << endl;
+}
+
+extern void write_data(ostream &out,NXhandle handle, const Tree &tree,
+                                                    const PrintConfig &config){
+  for( Tree::const_iterator path=tree.begin() ; path!=tree.end() ; path++ ){
+    write_one_data(out,handle,*path,config);
+  }
+}
+
+extern void dump_data(std::string &filename,NXhandle handle, const Tree &tree,
+                      const PrintConfig &config){
+  // error check the arguments
+  if(tree.size()!=1){
+    throw std::runtime_error("Can dump only one node");
+  }
+  if(filename.empty()){
+    throw std::runtime_error("Encountered empty filename");
+  }
+
+  // go to the right place in the file
+  Path path=*(tree.begin());
+  open_path(handle,path);
+
+  // find out about the data
+  int rank;
+  int dims[NX_MAXRANK];
+  int type;
+  if(NXgetinfo(handle,&rank,dims,&type)!=NX_OK){
+    close_path(handle,path);
+    throw std::runtime_error("NXgetinfo failed");
+  }
+
+  // determine the "size" of the data
+  int size=1;
+  for( int i=0 ; i<rank ; i++ ){
+    size*=dims[i];
+  }
+  if(type==NX_CHAR || type==NX_INT8 || type==NX_UINT8){
+    // do nothing
+  }else if(type==NX_INT16 || type==NX_UINT16){
+    size*=2;
+  }else if(type==NX_INT32 || type==NX_UINT32 || type==NX_FLOAT32){
+    size*=4;
+  }else if(type==NX_INT64 || type==NX_UINT64 || type==NX_FLOAT64){
+    size*=8;
+  }else{
+    // NX_BOOLEAN NX_UINT
+    // NX_BINARY   21
+    throw std::runtime_error("Do not understand supplied type");
+  }
+
+  // allocate space for the data
+  void *data;
+  if(NXmalloc(&data,rank,dims,type)!=NX_OK){
+    close_path(handle,path);
+    throw "NXmalloc failed";
+  }
+
+  // retrieve the data from the file
+  if(NXgetdata(handle,data)!=NX_OK){
+    close_path(handle,path);
+    throw "NXgetdata failed";
+  }
+
+  // close the path
+  close_path(handle,path);
+
+  // open the output file
+  std::ofstream dump_file(filename.c_str(),std::ios::binary);
+  if(!dump_file.is_open()){
+    throw std::runtime_error("Failed opening dump file");
+  }
+
+  // dump the data
+  dump_file.write(reinterpret_cast<char *>(data),size);
+}
diff --git a/applications/NXdir/main.cpp b/applications/NXdir/main.cpp
new file mode 100644
index 0000000..66f55d9
--- /dev/null
+++ b/applications/NXdir/main.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "nxdir.h"
+#include "nxdir_help.h"
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cstdlib>
+#include <fstream>
+#include <cstdio>
+#include <cstring>
+
+// -------------------- begin TIMING TEST stuff
+#ifdef TIMING_TEST
+#include <time.h> // 
+#define convert_time(time) (1000.*((float)time)/((float)CLOCKS_PER_SEC))
+#define print_time(zero) printf("TIME=%7.3fms\n",convert_time(clock()-zero))
+#endif
+// -------------------- end TIMING TEST stuff
+
+#define NXDIR_VERSION "0.3.0"
+
+// bring stuff into this name space
+using std::cout;
+using std::endl;
+using std::string;
+using std::vector;
+
+// some constants for command line flags
+static const string BINDUMP="--dump";
+static const string WRITEDATA="--write-data";
+static const string TREEMODE="--tree-mode";
+static const string TREEMODE_SHORT="-t";
+static const string PATHMODE="--path-mode";
+static const string DATAMODE="--data-mode";
+static const string OUTPUTMODE="--printline";
+static const string MAXLENGTH="--max-array";
+static const string MAXLENGTH_SHORT="-l";
+static const string PRINTDATA="-o";
+static const string NOT_PRINTDATA="+o";
+static const string ARG_VERSION="--version";
+static const string PATH="-p";
+static const string HELP="--help";
+static const string HELP_SHORT="-h";
+static const string VERBOSE="-v";
+static const string STAR="*";
+#define HELP_PAD "                            "
+
+
+/*
+ * Returns true if str1 starts with str2
+ */
+static bool starts_with( const string str1, const string str2){
+  // empty string can't start with anything
+  if(str1.empty())
+    return false;
+
+  // can't start with something that is longer
+  if(str2.size()>str1.size())
+    return false;
+
+  // if they are the same then just return true
+  if(str1==str2)
+    return true;
+
+  // do the actual comparison
+  string cmp_str=str1.substr(0,str2.size());
+  return (cmp_str==str2);
+}
+
+/*
+ * Returns true if str1 ends with str2
+ */
+static bool ends_with( const string str1, const string str2){
+  // empty string can't start with anything
+  if(str1.empty())
+    return false;
+
+  // can't start with something that is longer
+  if(str2.size()>str1.size())
+    return false;
+
+  // if they are the same then just return true
+  if(str1==str2)
+    return true;
+
+  // do the actual comparison
+  string cmp_str=str1.substr(str1.size()-str2.size(),str1.size());
+  return (cmp_str==str2);
+}
+
+static string trim_arg(const string arg, const string flag){
+  static const string EQUAL="=";
+
+  // trim off the flag
+  string result=arg.substr(flag.size(),arg.size());
+
+  // check that there is something left
+  if(result.size()<=0)
+    return result;
+
+  // trim off the equal sign (if there)
+  if(starts_with(result,EQUAL))
+    result=result.substr(1,result.size());
+
+  // return result
+  return result;
+}
+
+static int get_arg(const string arg1, const string arg2, const string flag, string *result){
+  int return_val=0;
+
+  *result=trim_arg(arg1,flag);
+  if((*result).size()<=0){
+    if(arg2.size()<=0) return -1;
+    if(starts_with(arg2,"-")) return -1;
+    return_val++;
+    *result=arg2;
+  }
+
+  return return_val;
+}
+
+static int set_treemode(const string arg1, const string arg2, const string flag, PrintConfig *config){
+  // get the proper argument to parse
+  string result;
+  int return_val=get_arg(arg1,arg2,flag,&result);
+  if(return_val<0)
+    return 0;
+
+  // convert the string to enum
+  if(result=="script")
+    (*config).tree_mode=TREE_SCRIPT;
+  else if(result=="multi")
+    (*config).tree_mode=TREE_MULTI;
+  else if(result=="tree")
+    (*config).tree_mode=TREE_TREE;
+  else
+    return 0;
+
+  // return the result
+  return return_val;
+}
+
+static string get_treemode_help(){
+  string result="  ";
+
+  result+=TREEMODE_SHORT+"|"+TREEMODE+" <value>";
+
+  result+="    ";
+
+  result+="Sets the formatting of the tree. Allowed values are \n";
+  result+=HELP_PAD;
+
+  if(DEFAULT_TREE_MODE==TREE_SCRIPT)
+    result+="(script)|multi|tree";
+  else if(DEFAULT_TREE_MODE==TREE_MULTI)
+    result+="script|(multi)|tree";
+  else if(DEFAULT_TREE_MODE==TREE_TREE)
+    result+="script|multi|(tree)";
+
+  return result;
+}
+
+static int set_pathmode(const string arg1, const string arg2, const string flag, PrintConfig *config){
+  // get the proper argument to parse
+  string result;
+  int return_val=get_arg(arg1,arg2,flag,&result);
+  if(return_val<0)
+    return 0;
+
+  // convert the string to enum
+  if(result=="name")
+    (*config).path_mode=NAME;
+  else if(result=="class")
+    (*config).path_mode=TYPE;
+  else if(result=="both")
+    (*config).path_mode=NAME_TYPE;
+
+  // return the result
+  return return_val;
+}
+
+static string get_pathmode_help(){
+  string result="  "+PATHMODE+" <value>       ";
+
+  result+="Select whether paths are written with names or \n";
+  result+=HELP_PAD;
+  result+="classes. Allowed values are ";
+
+  if(DEFAULT_PATH_MODE==NAME)
+    result+="(name)|class|both";
+  else if(DEFAULT_PATH_MODE==TYPE)
+    result+="name|(class)|both";
+  else if(DEFAULT_PATH_MODE==NAME_TYPE)
+    result+="name|class|(both)";
+
+  return result;
+}
+
+static int set_datamode(const string arg1, const string arg2, const string flag, PrintConfig *config){
+  // get the proper argument to parse
+  string result;
+  int return_val=get_arg(arg1,arg2,flag,&result);
+  if(return_val<0)
+    return 0;
+
+  // convert the string to enum
+  (*config).print_data=true;
+  if(result=="script")
+    (*config).data_mode=DATA_SCRIPT;
+  else
+    return 0;
+
+  // return the result
+  return return_val;
+}
+
+static string get_datamode_help(){
+  string result="  "+DATAMODE+" <value>       ";
+
+  result+="How data is printed. Allowed values are (script)";
+
+  return result;
+}
+
+static int set_outputmode(const string arg1, const string arg2, const string flag, PrintConfig *config){
+  // get the proper argument to parse
+  string result;
+  int return_val=get_arg(arg1,arg2,flag,&result);
+  if(return_val<0)
+    return 0;
+
+  // convert the string to enum
+  if(result=="single")
+    (*config).output_line_mode=OUT_SINGLE;
+  else
+    return 0;
+
+  // return the result
+  return return_val;
+}
+
+static string get_outputmode_help(){
+  string result="  "+OUTPUTMODE+" <value>       ";
+
+  result+="How data is printed with respect to tree. Allowed \n";
+  result+=HELP_PAD;
+  result+="values are (single).";
+
+  return result;
+}
+
+static string get_printdata_help(){
+  string result="  "+PRINTDATA+"/"+NOT_PRINTDATA+"                     ";
+  result+="Print (or not) the value of selected nodes, if \n";
+  result+=HELP_PAD;
+  result+="possible. ";
+  if(DEFAULT_PRINT_DATA)
+    result+="Defaults to true (-o).";
+  else
+    result+="Defaults to false (+o).";
+
+  return result;
+}
+
+// print the version documentation
+static void print_version(const string progname, int length){
+  cout << progname << " (NXdir) version "<< NXDIR_VERSION << endl;
+
+  if(length<=0) return;
+
+  // print the version information
+  cout << endl;
+  for( int i=0 ; vers_text[i]!=NULL && i<200 ; i++ )
+    cout << vers_text[i] << endl;
+}
+
+// print the help documentation
+static void print_help(const string progname, int length){
+  if(length>0){
+    print_version(progname,1);
+    cout << endl;
+  }
+
+  cout << "Usage: " << progname << " <filename> [options]" << endl;
+  if(length<=0) return;
+
+  // ----- print the standard text
+  for( int i=0 ; help_text[i]!=NULL && i<200 ; i++ )
+    cout << help_text[i] << endl;
+  cout << endl;
+  // ----- print the dynamic text
+  cout << "About NXdir" << endl;
+  cout << "  " << HELP_SHORT << "|" << HELP << "                 Print this help information" << endl;
+  cout << "  " << ARG_VERSION << "                 Print the version information" << endl;
+  cout << endl;
+  cout << "Node Selection" << endl;
+  cout << "  " << PATH << "                        Path inside the file to look in. This can be \n" << HELP_PAD << "absolute or relative and can be class or name of a \n" << HELP_PAD << "given field. To anchor the path at the beginning or \n" << HELP_PAD << "end place a \"/\" there.\n" << HELP_PAD << "To specify that a level must exist, but\n" << HELP_PAD << "the name or class can be anything, use a dot \".\"." << endl;
+  cout << HELP_PAD << "To specify that any number of levels can exist, use " << endl;
+  cout << HELP_PAD << "a star \"*\"." << endl;
+  cout << endl;
+  cout << "Output Control" << endl;
+  cout << get_printdata_help() << endl;
+/*
+  cout << "  " << PRINTDATA << "/" << NOT_PRINTDATA << "                     Print (or not the value of selected nodes, if " << endl;
+  cout << HELP_PAD << "possible. ";
+  if(DEFAULT_PRINT_DATA){
+    cout << "Defaults to true (-o).";
+  }else{
+    cout << "Defaults to false (+o).";
+  }
+  cout << endl;
+*/
+  cout << "  " << MAXLENGTH_SHORT << "|" << MAXLENGTH << "            Change the number of elements that are printed for \n" << HELP_PAD << "arrays. Forces \"" << PRINTDATA << "\". (" << DEFAULT_MAX_LENGTH << ")" << endl;
+  cout << get_treemode_help() << endl;
+  cout << get_pathmode_help() << endl;
+  cout << get_datamode_help() << endl;
+  cout << get_outputmode_help() << endl;
+  cout << "  " << WRITEDATA << " <filename>   "
+       << "Select a file to write out selected NXdata to." << endl;
+  cout << "  " << BINDUMP << " <filename>         " << "Generate a binary dump of the selected node." << endl;
+}
+
+// check if the file exists by opening for reading
+static bool file_exists(const string file){
+  FILE *handle=fopen(file.c_str(),"r");
+
+  bool exists=(handle!=NULL);
+
+  if(exists)
+    fclose(handle);
+
+  return exists;
+}
+
+static void init_print_config(PrintConfig *print_config){
+  print_config->tree_mode=DEFAULT_TREE_MODE;
+  print_config->path_mode=DEFAULT_PATH_MODE;
+  print_config->data_mode=DEFAULT_DATA_MODE;
+  print_config->output_line_mode=DEFAULT_OUT_LINE_MODE;
+  print_config->print_data=DEFAULT_PRINT_DATA;
+  print_config->max_length=DEFAULT_MAX_LENGTH;
+  print_config->show_filename=true;
+}
+
+/*
+ * This tries to set the value of an int. If it for some reason fails
+ * it does nothing to the value.
+ */
+static int set_int(const string arg1, const string arg2, int *val){
+  string number=arg1;
+  int arg_num=0;
+  if(number.size()<=0){
+    number=arg2;
+    arg_num++;
+  }
+
+  // do nothing with empty strings
+  if(number.size()<=0) return 0;
+
+  // do nothing with flag
+  if(starts_with(number,"-")) return 0;
+
+  try{
+    int result=str_to_int(number);
+    *val=result;
+    return arg_num;
+  }catch(const char *str){
+    return 0;
+  }
+
+}
+
+int main(int argc, char *argv[]){
+  // define the default options
+  StringVector files;
+  StringVector abs_path;
+  StringVector rel_path;
+  int recurse=DEFAULT_RECURSE;
+  int build_recurse=DEFAULT_RECURSE;
+  PrintConfig print_config;
+  init_print_config(&print_config);
+  bool verbose=false;
+
+  // get the name of the compiled file
+  string progname=argv[0];
+  progname=*(arrayify(progname).rbegin());
+
+  // process the command line
+  if(argc<=1){
+    cout << "NXdir: no input files" << endl;
+    print_help(progname,0);
+    exit(0);
+  }
+  for( int i=1 ; i<argc ; i++ ){
+
+    // get a string from the argument
+    string arg1=argv[i];
+    string arg2;
+    if(i+1<argc)
+      arg2=argv[i+1];
+    if(arg1==HELP || arg1==HELP_SHORT){
+      print_help(progname,1);
+      exit(0);
+    }else if(arg1==ARG_VERSION){
+      print_version(progname,1);
+      exit(0);
+    }else if(starts_with(arg1,TREEMODE)){
+      int ret=set_treemode(arg1,arg2,TREEMODE,&print_config);
+      if(ret<0){
+        std::cerr << "ERROR: option \"" << TREEMODE
+                  << "\" needs a value specified" << endl;
+        exit(-1);
+      }
+      i+=ret;
+    }else if(starts_with(arg1,TREEMODE_SHORT)){
+      int ret=set_treemode(arg1,arg2,TREEMODE_SHORT,&print_config);
+      if(ret<0){
+        std::cerr << "ERROR: option \"" << TREEMODE_SHORT
+                  << "\" needs a value specified" << endl;
+        exit(-1);
+      }
+      i+=ret;
+    }else if(starts_with(arg1,PATHMODE)){
+      int ret=set_pathmode(arg1,arg2,PATHMODE,&print_config);
+      if(ret<0){
+        std::cerr << "ERROR: option \"" << PATHMODE
+                  << "\" needs a value specified" << endl;
+        exit(-1);
+      }
+      i+=ret;
+    }else if(starts_with(arg1,DATAMODE)){
+      int ret=set_datamode(arg1,arg2,DATAMODE,&print_config);
+      if(ret<0){
+        std::cerr << "ERROR: option \"" << DATAMODE
+                  << "\" needs a value specified" << endl;
+        exit(-1);
+      }
+      i+=ret;
+    }else if(starts_with(arg1,OUTPUTMODE)){
+      int ret=set_outputmode(arg1,arg2,OUTPUTMODE,&print_config);
+      if(ret<0){
+        std::cerr << "ERROR: option \"" << OUTPUTMODE
+                  << "\" needs a value specified" << endl;
+        exit(-1);
+      }
+      i+=ret;
+    }else if(starts_with(arg1,BINDUMP)){
+      i+=get_arg(arg1,arg2,BINDUMP,&print_config.dump_data_file);
+    }else if(starts_with(arg1,WRITEDATA)){
+      i+=get_arg(arg1,arg2,WRITEDATA,&print_config.data_out_file);
+    }else if(arg1==VERBOSE){
+      verbose=true;
+    }else if(arg1==PRINTDATA){
+      print_config.print_data=true;
+    }else if(arg1==NOT_PRINTDATA){
+      print_config.print_data=false;
+    }else if(starts_with(arg1,MAXLENGTH)){
+      print_config.max_length=-1;
+      arg1=trim_arg(arg1,MAXLENGTH);
+      i+=set_int(arg1,arg2,&print_config.max_length);
+      print_config.print_data=true;
+    }else if(starts_with(arg1,MAXLENGTH_SHORT)){
+      print_config.max_length=-1;
+      arg1=trim_arg(arg1,MAXLENGTH_SHORT);
+      i+=set_int(arg1,arg2,&print_config.max_length);
+      print_config.print_data=true;
+    }else if(starts_with(arg1,PATH)){
+      string result;
+      int ret=get_arg(arg1,arg2,PATH,&result);
+      if(ret<0){
+        std::cerr << "ERROR: option \"" << PATH
+                  << "\" needs a value specified" << endl;
+        exit(-1);
+      }
+      i+=ret;
+      rel_path=arrayify(result);
+      if(starts_with(result,"/"))
+        abs_path=rel_path;
+      if(ends_with(result,"/"))
+        recurse=0;
+    }else if(file_exists(arg1)){
+      files.push_back(arg1);
+    }else if(starts_with(arg1,"-")){
+      std::cerr << "ERROR: Do not understand option " << i << ": \"" << arg1 << "\"" << endl;
+      exit(-1);
+    }else{
+      std::cerr << "ERROR: File \"" << arg1 << "\" does not exist (skipping)" << endl;
+    }
+  }
+
+  // fix the relative path (if needed)
+  if( !rel_path.empty() ){
+    bool non_empty_abs=(!abs_path.empty());
+
+    // trim off stars at the beginning
+    if( !rel_path.empty() && *(rel_path.begin())==STAR ){
+      build_recurse=-1;
+      if(non_empty_abs){
+        abs_path.erase(abs_path.begin(),abs_path.end());
+        non_empty_abs=false;
+      }
+      while( !rel_path.empty() && *(rel_path.begin())==STAR )
+        rel_path.erase(rel_path.begin(),rel_path.begin()+1);
+    }
+
+    // trim off stars at the end
+    if( !rel_path.empty() && *(rel_path.rbegin())==STAR ){
+      recurse=-1;
+      if(non_empty_abs) build_recurse=-1;
+      while( !rel_path.empty() && *(rel_path.rbegin())==STAR )
+        rel_path.pop_back();
+    }
+
+    // look for double stars in the middle
+    bool keep_going=!rel_path.empty();
+    while(keep_going){
+      for( StringVector::iterator it=rel_path.begin() ; it!=rel_path.end() ; it++ ){
+        if(*it==STAR){
+          if(it+1!=rel_path.end()){
+            if(*(it+1)==STAR){
+              rel_path.erase(it,it+1);
+              break;
+            }
+          }
+        }
+        if(it+1==rel_path.end())
+          keep_going=false;
+      }
+    }
+
+    // update the absolute path if anything has been changed
+    if( non_empty_abs && (abs_path.size()!=rel_path.size()) ){
+      abs_path.erase(abs_path.begin(),abs_path.end());
+      abs_path.insert(abs_path.end(),rel_path.begin(),rel_path.end());
+    }
+  }
+
+  // set full recursion if no absolute path is set
+  if(abs_path.empty() && !rel_path.empty())
+    build_recurse=-1;
+
+  /* QUICK DEBUG THING
+  std::cout << "ABS:/"; print_strvec(abs_path); // REMOVE
+  std::cout << "REL:"; print_strvec(rel_path); // REMOVE
+  */
+
+  // check that there are files to work with
+  if(files.empty()){
+    cout << "NXdir: no input files" << endl;
+    exit(0);
+  }
+
+  if(files.size()==1)
+    print_config.show_filename=false;
+
+#ifdef TIMING_TEST
+  clock_t time_zero=clock(); // TIMING TEST
+#endif
+
+  if(files.size()>1 && print_config.data_out_file.length()>0){
+    std::cerr << "CANNOT OUTPUT DATA FROM MORE THAN ONE SOURCE FILE" << endl;
+    exit(-1);
+  }
+
+  // loop over files
+  for( StringVector::const_iterator file=files.begin() ; file!=files.end()
+                                                                    ; file++ ){
+    // set the filename
+    print_config.filename=*file;
+
+    // open the file for reading
+    NXhandle handle;
+    char filename[GROUP_STRING_LEN];
+    strcpy(filename,(*file).c_str());
+    if(NXopen(filename,NXACC_READ,&handle)!=NX_OK)
+      continue;
+
+    // create the tree
+    Tree tree;
+    try{
+      tree=build_tree(handle,abs_path,build_recurse);
+    }catch(const char *str){
+      NXclose(&handle);
+      cout << "While reading " << *file << ":" << endl;
+      cout << str << endl;
+      continue;
+    }
+
+    // purge the tree
+    if(!rel_path.empty())
+      tree=purge_tree(tree,rel_path,recurse);
+
+    // remove any non-data from the tree
+    if(print_config.data_out_file.length()>0)
+      tree=remove_nondata(tree);
+
+    if(verbose && tree.empty()){
+      std::cout << "NOTHING MEETS CRITERIA IN FILE: " << filename << std::endl;
+    }
+
+    // print the results
+    try{
+      if(print_config.data_out_file.length()>0){
+        std::ofstream out_file(print_config.data_out_file.c_str());
+        write_data(out_file,handle,tree,print_config);
+      }else if(!print_config.dump_data_file.empty()){
+        dump_data(print_config.dump_data_file,handle,tree,print_config);
+      }else{
+        print_tree_result(handle,tree,print_config);
+      }
+    }catch(const char *str){
+      NXclose(&handle);
+      continue;
+    }
+
+    // close the file
+    if(NXclose(&handle)!=NX_OK){
+      continue;
+    }
+  }
+
+#ifdef TIMING_TEST
+  print_time(time_zero); // TIMING TEST
+#endif
+
+  return 0;
+}
diff --git a/applications/NXdir/nxdir.1 b/applications/NXdir/nxdir.1
new file mode 100644
index 0000000..ba2e871
--- /dev/null
+++ b/applications/NXdir/nxdir.1
@@ -0,0 +1,91 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH NXDIR 1 "June 2010"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxdir \- inspect a NeXus file non interactively
+.SH SYNOPSIS
+.B nxdir
+.RI filename
+.RI [ options ] 
+.SH DESCRIPTION
+.B nxdir
+allows to retrieve the structure and/or data of a NeXus file.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH OPTIONS
+About NXdir
+.TP
+.B  -h|--help
+Print help information and exit.
+.TP
+.B --version
+Print version information and exit.
+.PP
+Node Selection
+.TP
+.B -p \fIpath\fP
+Path inside the file to look in. This can be 
+absolute or relative and can be class or name of a 
+given field. To anchor the path at the beginning or 
+end place a "/" there.
+To specify that a level must exist, but
+the name or class can be anything, use a dot ".".
+To specify that any number of levels can exist, use 
+a star "*".
+.PP
+Output Control
+.TP
+.B -o/+o
+Print (or not) the value of selected nodes, if possible. Defaults to false (+o).
+.TP
+.B -l|--max-array
+Change the number of elements that are printed for arrays. Forces "-o". (default: 10)
+.TP
+.B -t|--tree-mode \fIvalue\fP
+Sets the formatting of the tree. Allowed values are: script, multi, tree. Default is \fBscript\fP.
+.TP
+.B --path-mode \fIvalue\fP
+Select whether paths are written with names or classes. Allowed values are: name, class, both. Default is \fBname\fP.
+.TP
+.B --data-mode \fIvalue\fP
+How data is printed. Allowed value is script
+.TP
+.B --printline \fIvalue\fP
+How data is printed with respect to tree. Allowed values is single
+.TP
+.B --write-data \fIfilename\fP
+Select a file to write out selected NXdata to.
+.TP
+.B --dump \fIfilename\fP
+Generate a binary dump of the selected node.
+.SH SEE ALSO
+.BR nxbrowse (1)
+.BR http://www.nexusformat.org
+.br
+.SH AUTHOR
+nxdir was originally written by P. F. Peterson 
+.nh
+<petersonpf at ornl.gov>
+.hy
+.PP
+This manual page was written by Tobias Richter 
+.nh
+<Tobias.Richter at diamond.ac.uk>
+.hy
+and may be used by others.
diff --git a/applications/NXdir/nxdir.h b/applications/NXdir/nxdir.h
new file mode 100644
index 0000000..b2ad811
--- /dev/null
+++ b/applications/NXdir/nxdir.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef NXDIR_H
+#define NXDIR_H
+/* Default values for various command line options */
+#define DEFAULT_MAX_LENGTH 10   // number of array elements to print
+#define DEFAULT_RECURSE    1    // negative value means all
+#define DEFAULT_PRINT_DATA false // can be true or false
+#define DEFAULT_PATH_MODE NAME // can be NAME, TYPE, or NAME_TYPE
+#define DEFAULT_TREE_MODE TREE_SCRIPT // can be TREE_SCRIPT, TREE_MULTI,
+                                      // or TREE_TREE
+#define DEFAULT_DATA_MODE DATA_SCRIPT // can be DATA_SCRIPT
+#define DEFAULT_OUT_LINE_MODE OUT_SINGLE // can be OUT_SINGLE
+
+/* -------------------- DO NOT EDIT BELOW THIS LINE -------------------- */
+#include "napiconfig.h"
+#include "napi.h"
+#include <string>
+#include <vector>
+#include <iostream>
+
+#define GROUP_STRING_LEN 128
+#define SDS "SDS"
+#define ATTR "ATTR"
+
+typedef struct{
+  std::string name;
+  std::string type;
+}Node;
+
+typedef std::vector<Node> Path;
+typedef std::vector<Path> Tree;
+typedef std::vector<std::string> StringVector;
+
+// enumerations
+enum NXdir_status{NXDIR_FAIL,NXDIR_OK};
+enum TreeMode{TREE_SCRIPT,TREE_MULTI,TREE_TREE};
+enum PathMode{NAME,TYPE,NAME_TYPE};
+enum DataMode{DATA_SCRIPT};
+enum OutputLineMode{OUT_SINGLE};
+
+// print definition config
+typedef struct{
+  std::string filename;
+  TreeMode tree_mode;
+  PathMode path_mode;
+  DataMode data_mode;
+  OutputLineMode output_line_mode;
+  bool print_data; // print array values to cout
+  bool show_filename;
+  int max_length;
+  std::string dump_data_file; // binary dump of data
+  std::string data_out_file; // write data as formatted ascii into file
+}PrintConfig;
+
+// -------------------- data.cpp
+extern StringVector read_all_dims_as_string(NXhandle handle, const Tree tree);
+extern StringVector read_all_data_as_string(NXhandle handle, const Tree tree,
+                                                     const PrintConfig config);
+extern std::string read_attr_as_string(NXhandle handle, const Path &path,
+                                                    const PrintConfig &config);
+extern long read_int_attr(NXhandle handle, const Path &path);
+
+// -------------------- string_util.cpp
+extern StringVector arrayify(const std::string path);
+extern int str_to_int(const std::string arg);
+extern void print_path(const Path path, const PathMode print_mode);
+extern void print_tree(const Tree tree, const PathMode print_mode);
+extern void print_strvec(const StringVector &vec);
+extern void print_tree_result(NXhandle handle, const Tree tree,
+                                               const PrintConfig print_config);
+extern std::string path_to_str(const Path path, const PathMode print_mode);
+extern std::string oneD_to_string(const void *data, const int length,
+                                  const int type, const PrintConfig config);
+extern std::string to_string(const void *data, const int dims[],
+                     const int rank, const int type, const PrintConfig config);
+extern std::string int_to_str(const long value);
+template <typename T>
+extern std::string value_to_string(const T value);
+extern std::string voidptr_to_str(const void *data, int pos,int type);
+
+// -------------------- tree.cpp
+extern Tree purge_tree(const Tree tree, const StringVector rel_path, const int rel_recurse);
+extern Tree build_tree(NXhandle handle, const StringVector abs_path,
+                                                        const int num_recurse);
+extern Tree build_rel_tree(NXhandle handle, const Path &path, int num_recurse);
+extern bool has_attr(NXhandle handle,const std::string name, int *length,
+                                                                    int *type);
+extern int open_path(NXhandle handle, const Path path);
+extern int close_path(NXhandle handle, const Path path);
+extern bool compPath(const Path path1, const Path path2);
+
+// -------------------- data_writer.cpp
+extern void write_data(std::ostream &out,NXhandle handle, const Tree &tree,
+                                                    const PrintConfig &config);
+extern void dump_data(std::string &filename,NXhandle handle, const Tree &tree,
+                      const PrintConfig &config);
+extern Tree remove_nondata(const Tree &tree);
+#endif
diff --git a/applications/NXdir/nxdir_help.h b/applications/NXdir/nxdir_help.h
new file mode 100644
index 0000000..016f2f9
--- /dev/null
+++ b/applications/NXdir/nxdir_help.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+const char* vers_text[]={
+  "Copyright (c) 2004-2006, P.F.Peterson <petersonpf at ornl.gov>",
+  "NXdir can be copied and/or modified under the terms of the \"MIT License\", ",
+  "which may be found in the source distribution.",
+  NULL,
+};
+const char* help_text[]={
+  "For all information below the default (when flag is not given) is denoted by \nparenthesis, \"()\".",
+  NULL,
+};
diff --git a/applications/NXdir/string_util.cpp b/applications/NXdir/string_util.cpp
new file mode 100644
index 0000000..24f80ce
--- /dev/null
+++ b/applications/NXdir/string_util.cpp
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <iostream>
+#include "nxdir.h"
+#include <string>
+#include <algorithm>
+#include <sstream>
+#include <stdio.h>
+
+#define ellipse std::string("...,")
+
+// bring some functions into this namespace
+using std::string;
+using std::stringstream;
+using std::cout;
+using std::endl;
+using std::find;
+using std::find_if;
+
+// alias some data types
+typedef Tree::const_iterator TreeIter;
+typedef StringVector::const_iterator StrVecIter;
+typedef Path::const_iterator PathIter;
+typedef string::const_iterator StrIter;
+
+// function prototypes
+static string path_to_string( PathIter path_begin, PathIter path_end, PathMode print_mode);
+
+// ==================== UTILITY CODE
+/*
+ * Returns true if the supplied character is a digit [0-9].
+ */
+static bool my_isdigit(char c){
+  static const string digits="0123456789";
+  return find(digits.begin(),digits.end(),c)!=digits.end();
+}
+
+/*
+ * Returns the negation of my_isdigit(char c)
+ */
+static bool my_isnotdigit(char c){
+  return !my_isdigit(c);
+}
+
+/*
+ * Converts a string into an integer. This checks that the string
+ * contains only digits.
+ */
+extern int str_to_int(const string str){
+  // check that it is a number
+  StrIter itter=str.begin();
+  itter=find_if(itter,str.end(),my_isnotdigit);
+
+  if(itter!=str.end())
+    throw "argument not an integer";
+
+  return atoi(str.c_str());
+}
+
+/*
+ * Returns true if the supplied character is a forward slash "/"
+ */
+static bool isslash(char c){
+  static const string slash="/";
+  return find(slash.begin(),slash.end(),c)!=slash.end();
+}
+
+/*
+ * Returns the negation of isslash(char c)
+ */
+static bool isnotslash(char c){
+  return !isslash(c);
+}
+
+/*
+ * Converts a slash, "/", delimited string into a Vector of strings.
+ */
+extern StringVector arrayify(const string path){
+  StringVector result;
+
+  StrIter i=path.begin();
+  while(i!=path.end()){
+    // ignore leading stuff
+    i=find_if(i,path.end(),isnotslash);
+
+    // find end of next word
+    StrIter j=find_if(i,path.end(),isslash);
+
+    // copy the characters in [i,j)
+    if(i!=path.end())
+      result.push_back(string(i,j));
+    i=j;
+  }
+
+  return result;
+}
+
+// ==================== PRINTING CODE
+/*
+ * Just like the name says: prints a path followed by a carriage return.
+ */
+extern void print_path(const Path path, const PathMode print_mode){
+  cout << path_to_str(path,print_mode) << endl;
+}
+
+/*
+ * Just like the name says: prints the full tree with each path on a
+ * separate line.
+ */
+extern void print_tree(const Tree tree, const PathMode print_mode){
+  for( TreeIter iter=tree.begin() ; iter!=tree.end() ; iter++ ){
+    print_path(*iter,print_mode);
+  }
+
+  return;
+}
+
+extern void print_strvec(const StringVector &vec){
+  for( StrVecIter it=vec.begin() ; it!=vec.end() ; it++ ){
+    std::cout << *it;
+    if(it+1!=vec.end()) std::cout << "/";
+  }
+  std::cout << std::endl;
+}
+
+static int num_match(const Path path1, const Path path2){
+  int num_match=0;
+  int path1_len=path1.size();
+  int path2_len=path2.size();
+  int len=path1_len;
+  if(path2_len<len)
+    len=path2_len;
+
+  PathIter path1_it=path1.begin();
+  PathIter path2_it=path2.begin();
+
+  for( int i=0 ; i<len ; i++ ){
+    if( (path1_it+i)->type!=(path2_it+i)->type )
+      return num_match;
+    if( (path1_it+i)->name!=(path2_it+i)->name )
+      return num_match;
+    num_match++;
+  }
+
+  return num_match;
+}
+
+static StringVector create_tree_str(const Tree tree, const StringVector dims,
+                                                     const PrintConfig config){
+  StringVector tree_str;
+
+  int length=tree.size();
+  if(length<=0)
+    return tree_str;
+
+  // variable for adding space a begining of tree print when showing filename
+  int tree_tree_space_start=0;
+  if(!config.show_filename)
+    tree_tree_space_start=1;
+
+  for( int i=0 ; i<length ; i++ ){
+    string temp;
+    // build string
+    if(config.tree_mode==TREE_TREE){
+      if(i==0){
+        temp+="/"+path_to_string(tree[i].begin(),tree[i].end(),config.path_mode);
+      }else{
+        int num=num_match(tree[i-1],tree[i]);
+        for( int j=tree_tree_space_start ; j<num ; j++ )
+          temp+="  ";
+        if(num==0)
+          temp+="/";
+        else
+          temp+="|";
+        temp+=path_to_string(tree[i].begin()+num,tree[i].end(),config.path_mode);
+        temp+=dims[i];
+      }
+    }else{
+      if(config.show_filename && config.tree_mode==TREE_SCRIPT)
+        temp+=config.filename+";";
+      else if(config.show_filename && config.tree_mode==TREE_MULTI)
+        temp+="  ";
+
+      // add in the path and dimensions
+      temp+=path_to_str(tree[i],config.path_mode)+dims[i];
+    }
+    // append it to the result
+    tree_str.push_back(temp);
+  }
+
+  return tree_str;
+}
+
+/*
+ * Takes a tree, collects all information needed for printing, and
+ * writes it out.
+ */
+extern void print_tree_result(NXhandle handle, const Tree tree,
+                                               const PrintConfig print_config){
+  // check the size of the tree
+  int length=tree.size();
+  if(length<=0) return;
+
+  // get the dimensions of everything
+  StringVector dims=read_all_dims_as_string(handle,tree);
+
+  // create the tree for everything
+  StringVector tree_str=create_tree_str(tree,dims,print_config);
+
+  // print the filename
+  if(print_config.show_filename && print_config.tree_mode!=TREE_SCRIPT)
+    cout << print_config.filename << endl;
+
+  if(print_config.print_data){
+    // get the data
+    StringVector data=read_all_data_as_string(handle,tree,
+                                                      print_config);
+
+    for(int i=0 ; i<length ; i++ ){
+      if( (tree[i].rbegin()->type!=SDS) && (tree[i].rbegin()->type!=ATTR) )
+        continue;
+      if(print_config.output_line_mode==OUT_SINGLE)
+        cout << tree_str[i] << "=" << data[i] << endl;
+    }
+
+  }else{
+    for( StrVecIter path=tree_str.begin() ; path!=tree_str.end() ; path++ ){
+      cout << *path << endl;
+    }
+  }
+}
+
+// ==================== TOSTRING CODE
+static string path_to_string( PathIter path_begin, PathIter path_end, PathMode print_mode){
+  string result;
+  for( PathIter iter=path_begin ; iter!=path_end ; iter++ ){
+    if(iter->type==ATTR)
+      result=result+"#";
+    if(print_mode==NAME || print_mode==NAME_TYPE)
+      result=result+iter->name;
+    if(print_mode==NAME_TYPE || print_mode==TYPE)
+      result=result+":";
+    if(print_mode==TYPE || print_mode==NAME_TYPE)
+      result=result+iter->type;
+    if(iter->type!=SDS && iter->type!=ATTR)
+      result=result+"/";
+  }
+
+  return result;
+}
+
+/*
+ * Converts a path to a string.
+ */
+extern string path_to_str(const Path path, const PathMode print_mode){
+  return "/"+path_to_string(path.begin(),path.end(),print_mode);
+}
+
+/*
+ * Converts a value to a string using the string stream class.
+ */
+template <typename T>
+extern string value_to_str(const T value) {
+  std::stringstream ss;
+  ss << value;
+  return ss.str();
+}
+
+/*
+ * Converts an integer (any precision) to a string.
+ */
+extern string int_to_str(const long value){
+  return value_to_str(value);
+}
+
+/*
+ * Some character arrays are not null (\0) terminated, but since the
+ * length is known this converts them to a proper string.
+ */
+static string fix_str(char *value,int length){
+  string my_string=string((char *)value);
+  string result=string("");
+  for( int i=0 ; i<length ; i++ ){
+    result+=my_string[i];
+  }
+
+  return result;
+}
+
+/*
+ * Convert an individual void* into a string using the types defined
+ * in the NeXus API header.
+ */
+extern string voidptr_to_str(const void *data, int pos,int type){
+  if(type==NX_FLOAT32)
+    return value_to_str(((float *)data)[pos]);
+  else if(type==NX_FLOAT64)
+    return value_to_str(((double *)data)[pos]);
+  else if(type==NX_INT8)
+    return value_to_str(((int8_t *)data)[pos]);
+  else if(type==NX_INT16)
+    return value_to_str(((int16_t *)data)[pos]);
+  else if(type==NX_INT32)
+    return value_to_str(((int32_t *)data)[pos]);
+  else if(type==NX_INT64)
+    return value_to_str(((int64_t *)data)[pos]);
+  else if(type==NX_UINT8)
+    return value_to_str(((uint8_t *)data)[pos]);
+  else if(type==NX_UINT16)
+    return value_to_str(((uint16_t *)data)[pos]);
+  else if(type==NX_UINT32)
+    return value_to_str(((uint32_t *)data)[pos]);
+  else if(type==NX_UINT64)
+    return value_to_str(((uint64_t *)data)[pos]);
+  else
+    throw "Do not understand type in voidptr_to_str";
+}
+
+/*
+ * Converts a one dimesional array (given as a void pointer) into a
+ * string.
+ */
+extern string oneD_to_string(const void *data, const int length,
+                                     const int type, const PrintConfig config){
+  int max_items=config.max_length;
+  // deal with character array
+  if(type==NX_CHAR)
+    return fix_str((char *)data,length);
+
+  // deal with everything else
+  int itter_length=length;
+  if( (max_items>0) && (length>max_items) )
+    itter_length=max_items;
+
+  // get the first element
+  if(length==1)
+    return voidptr_to_str(data,0,type);
+
+  // build an array string
+  stringstream result;
+  result << "[";
+  for( int i=0 ; i<itter_length ; i++ ){
+    result << voidptr_to_str(data,i,type);
+    if(i+1<length)
+      result << ",";
+  }
+  if(length!=itter_length)
+    result << ellipse << voidptr_to_str(data,length-1,type);
+  result << "]";
+
+  // return the resulting array string
+  return result.str();
+}
+
+/*
+ * Converts a two dimensional array (given as a void pointer) into a string.
+ */
+static string twoD_to_string(const void *data, const int dims[], int type, PrintConfig config){
+  // REMEMBER: int a[10][20] can be accessed using a[20*row+col]
+
+  // set up the result and the length of each dimension
+  string result="[";
+  int offset=0;
+  int col_len=dims[0];
+  int row_len=dims[1];
+  int itter_length=col_len;
+  if( (config.max_length>0) && (col_len>config.max_length) )
+    itter_length=config.max_length;
+
+  // create the string for the first itter_length elements
+  for( int i=0 ; i<itter_length ; i++ ){
+    result+=oneD_to_string((char *)data+offset,row_len,type,config);
+    if(i+1<col_len)
+      result+=",";
+    offset=offset+row_len;
+  }
+
+  // add the ellipses and final element if the not all elements are in
+  // the string
+  if(itter_length!=col_len){
+    result+=ellipse;
+    offset=row_len*(col_len-1);
+
+    result+=oneD_to_string((char *)data+offset,row_len,type,config);
+  }
+  result+="]";
+
+  return result;
+}
+
+/*
+ * Externally available function to allow for converting arrays to strings.
+ */
+extern string to_string(const void *data, const int dims[], const int rank,
+                                     const int type, const PrintConfig config){
+  try{
+    if(rank==1){
+      return oneD_to_string(data,dims[0],type,config);
+    }else if(rank==2){
+      return twoD_to_string(data,dims,type,config);
+    }else{
+      return string("");
+    }
+  }catch(const char *str){
+    return string(str);
+  }
+}
diff --git a/applications/NXdir/tree.cpp b/applications/NXdir/tree.cpp
new file mode 100644
index 0000000..a67a216
--- /dev/null
+++ b/applications/NXdir/tree.cpp
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <iostream>
+#include <string>
+#include <vector>
+#include <string.h>
+#include <algorithm>
+#include "nxdir.h"
+
+typedef std::vector<Node> NodeVector;
+typedef Tree::const_iterator TreeIter;
+typedef Path::const_iterator PathIter;
+typedef StringVector::const_iterator StrVecIter;
+static const std::string DOT=".";
+static const std::string STAR="*";
+
+enum{UNINIT=-1,ISSTAR=-2};
+
+using std::string;
+using std::vector;
+
+/*
+ * Determine the number of groups in the file
+ */
+static int num_group(NXhandle handle){
+  char group_name[GROUP_STRING_LEN];
+  char group_klass[GROUP_STRING_LEN];
+  int num_groups;
+
+  if(NXgetgroupinfo(handle,&num_groups,group_name,group_klass)!=NX_OK)
+    throw "NXgetgroupinfo failed";
+
+  return num_groups;
+}
+
+/*
+ * Get the next group in the file at the current level.
+ */
+static Node get_next_group(NXhandle handle){
+  char name[GROUP_STRING_LEN], class_name[GROUP_STRING_LEN];
+  int datatype;
+
+  // get the information
+  if(NXgetnextentry(handle,name,class_name,&datatype)!=NX_OK)
+    throw "NXgetnextentry failed";
+
+  // copy it into the supplied node
+  Node node;
+  node.name=name;
+  node.type=class_name;
+
+  return node;
+}
+
+/*
+ * Checks the node for certain oddities that should be hidden from the user.
+ */
+static bool node_is_okay(const Node node){
+  if(node.name=="UNKNOWN")
+    return false;
+  if(node.type=="UNKNOWN")
+    return false;
+  if(node.type=="CDF0.0")
+    return false;
+  return true;
+}
+
+/*
+ * Get the listing of groups at the currently opened level.
+ */
+static NodeVector get_groups(NXhandle handle){
+  if(NXinitgroupdir(handle)!=NX_OK)
+    throw "NXinitgroupdir failed";
+
+  // get the listing
+  int num_groups=num_group(handle);
+  Node node;
+  NodeVector result;
+  for( int i=0 ; i<num_groups ; i++ ){
+    node=get_next_group(handle);
+    if(node_is_okay(node))
+      result.push_back(node);
+  }
+
+  if(NXinitgroupdir(handle)!=NX_OK)
+    throw "NXinitgroupdir failed";
+
+  return result;
+}
+
+/*
+ * Get the listing of attributes of the currently opened SDS.
+ */
+static NodeVector get_attrs(NXhandle handle){
+  // initialize the directory function
+  if(NXinitattrdir(handle)!=NX_OK)
+    throw "NXinitattrdir failed";
+
+  // set up for getting listing
+  char attr_name[GROUP_STRING_LEN];
+  int type;
+  int num_attr;
+  int length;
+
+  // find the number of attributes
+  if(NXgetattrinfo(handle,&num_attr)!=NX_OK)
+    throw "NXgetattrinfo failed";
+
+  // itterate through the attributes, pushing the names on the stack
+  NodeVector result;
+  try{
+    for( int i=0 ; i<num_attr ; i++ ){
+      if(NXgetnextattr(handle,attr_name,&length,&type)!=NX_OK)
+        throw "NXgetnextattr failed";
+
+      Node attr;
+      attr.name=attr_name;
+      attr.type=ATTR;
+      result.push_back(attr);
+    }
+  }catch(const char *str){
+    if(NXinitattrdir(handle)!=NX_OK)
+      throw "NXinitattrdir failed";
+    throw; // propogate the exception up
+  }
+
+  // initialize the directory function as cleanup
+  if(NXinitattrdir(handle)!=NX_OK)
+    throw "NXinitattrdir failed";
+
+  return result;
+}
+
+/*
+ * Make a copy of the current path.
+ */
+static Path copy_path(const Path old){
+  Path new_path;
+
+  for( PathIter it=old.begin() ; it!=old.end() ; it++ ){
+    new_path.push_back(*it);
+  }
+
+  return new_path;
+}
+
+/*
+ * Returns true if the named attribute is at the current level. Also
+ * has the side effect of setting the length and type parameters.
+ */
+extern bool has_attr(NXhandle handle,const string name,int *length, int *type){
+  // initialize the directory function
+  if(NXinitattrdir(handle)!=NX_OK)
+    throw "NXinitattrdir failed";
+
+  char attr_name[GROUP_STRING_LEN];
+  const char *my_name=name.c_str();
+  int num_attr;
+
+  // find the number of attributes
+  if(NXgetattrinfo(handle,&num_attr)!=NX_OK)
+    throw "NXgetattrinfo failed";
+
+  // determine if the attribute exists
+  bool found=false;
+  try{
+    for( int i=0 ; i<num_attr ; i++ ){
+      if(NXgetnextattr(handle,attr_name,length,type)!=NX_OK)
+        throw "NXgetnextattr failed";
+      if(strcmp(attr_name,my_name)==0){
+        found=true;
+        break;
+      }
+    }
+  }catch(const char *str){
+    if(NXinitattrdir(handle)!=NX_OK)
+      throw "NXinitattrdir failed";
+    throw; // propogate the exception up
+  }
+
+  // initialize the directory function as cleanup
+  if(NXinitattrdir(handle)!=NX_OK)
+    throw "NXinitattrdir failed";
+
+  return found;
+}
+
+/*
+ * Returns true if there is a group with the correct name at the
+ * current level.
+ */
+static bool has_group(NXhandle handle, const string name){
+  NodeVector groups=get_groups(handle);
+
+  bool found=false;
+  for( NodeVector::const_iterator group=groups.begin() ; group!=groups.end()
+         ; group++ ){
+    if(group->name==name){
+      found=true;
+      break;
+    }
+  }
+
+  return found;
+}
+
+/*
+ * Close the path a particular number of times. has_data specifies if
+ * a SDS needs to be closed first.
+ */
+static int close_num(NXhandle handle, int length, int has_data){
+  if( (has_data<=0) && (length<=0) )
+    return 0;
+
+  int num_closes=0;
+
+  if(has_data){
+    num_closes++;
+    if(NXclosedata(handle)!=NX_OK)
+      throw("IOError closing path (NXclosedata)");
+  }
+
+  for( int i=0 ; i<length ; i++ ){
+    num_closes++;
+    if(NXclosegroup(handle)!=NX_OK)
+      throw("IOError closing path (NXclosegroup)");
+  }
+
+  return num_closes;
+}
+
+/*
+ * Closes the handle according to the specified path.
+ */
+extern int close_path(NXhandle handle, const Path path){
+  int num_entry=0;
+  int has_data=0;
+
+  if(path.empty())
+    return 0;
+
+  if(path.rbegin()->type==SDS)
+    has_data=1;
+
+  num_entry=(int)path.size()-has_data;
+
+  return close_num(handle,num_entry,has_data);
+}
+
+/*
+ * Opens the handle according to the specified path.
+ */
+extern int open_path(NXhandle handle, const Path path){
+  int num_open=0;
+  int has_data=0;
+
+  char name[GROUP_STRING_LEN];
+  char type[GROUP_STRING_LEN];
+  for( PathIter iter=path.begin() ; iter!=path.end() ; iter++ ){
+    if(iter->type==SDS){
+      has_data=1;
+      strcpy(name,iter->name.c_str());
+      if(NXopendata(handle,name)!=NX_OK){
+        close_num(handle,num_open,has_data);
+        throw "NXopendata failed";
+      }
+      break;
+    }else{
+      strcpy(name,iter->name.c_str());
+      strcpy(type,iter->type.c_str());
+      if(!has_group(handle,name)){
+        close_num(handle,num_open,0);
+        throw "Group does not exist";
+      }
+
+      if(NXopengroup(handle,name,type)!=NX_OK){
+        close_num(handle,num_open,0);
+        throw "NXopengroup failed";
+      }
+      num_open++;
+    }
+  }
+
+  return num_open+has_data;
+}
+
+/*
+ * Returns true if two paths point at the same thing
+ */
+static bool paths_equal(const Path path1, const Path path2){
+  if(path1.size()!=path2.size())
+    return false;
+
+  int length=path1.size();
+  PathIter node1=path1.begin();
+  PathIter node2=path2.begin();
+  for( int i=0 ; i<length ; i++ ){
+    if((node1+i)->type!=(node2+i)->type)
+      return false;
+    if((node1+i)->name!=(node2+i)->name)
+      return false;
+  }
+
+  return true;
+}
+
+/*
+ * Adds a Path to the Tree. This confirms that the Path is not already
+ * in the tree.
+ */
+static void add_Path(Tree *tree, Path path){
+
+  // check for the path in the tree
+  for( TreeIter old_path=(*tree).begin() ; old_path!=(*tree).end() ; old_path++ ){
+    if(paths_equal(*old_path,path)){
+      return;
+    }
+  }
+
+  // if it got here the path must not be in the tree already
+  (*tree).push_back(path);
+}
+
+/*
+ * Merges two trees, the second is brought into the first.
+ */
+static void merge_trees(Tree *dest, const Tree *source){
+  for( TreeIter path=(*source).begin() ; path!=(*source).end() ; path++){
+    add_Path(dest,*path);
+  }
+}
+
+static Tree make_tree(Path open_path, NodeVector groups){
+  Tree tree;
+  for( NodeVector::const_iterator group=groups.begin() ; group!=groups.end() ;
+       group++){
+    Path path=copy_path(open_path);
+    path.push_back(*group);
+    tree.push_back(path);
+  }
+
+  return tree;
+}
+
+/*
+ * This builds a tree of attributes from the data at the supplied
+ * path.
+ */
+static Tree build_attr_tree(NXhandle handle, Path path){
+  Tree tree;
+
+  // make sure there is somewhere to go
+  if(path.empty())
+    return tree;
+
+  // make sure that the final spot is an SDS
+  if(path.rbegin()->type!=SDS)
+    return tree;
+
+  // get a listing of attributes at the location
+  open_path(handle,path);
+  NodeVector attrs=get_attrs(handle);
+  close_path(handle,path);
+
+  // create the tree
+  tree=make_tree(path,attrs);
+
+  return tree;
+}
+
+/*
+ * This checks for everything except "*".
+ */
+static bool node_okay( const Node &node, const string &restrict){
+  if(restrict==DOT)
+    return true;
+  else if(restrict==node.name)
+    return true;
+  else if(restrict==node.type)
+    return true;
+
+  return false;
+}
+
+/*
+ * This builds a tree with the restriction that the portion of the
+ * path past what is given must match the supplied iterators.
+ */
+static Tree build_res_rel_tree(NXhandle handle, Path path,StrVecIter res_begin,
+                                                           StrVecIter res_end){
+
+  Tree tree;
+
+  // make sure there is something to match against
+  if(res_begin==res_end)
+    return tree;
+
+  // what to do if the path isn't empty
+  if(!path.empty()){
+    if(path.rbegin()->type==ATTR){
+      return tree;
+    }else if(path.rbegin()->type==SDS){
+      Tree temp_tree=build_attr_tree(handle,path);
+      if(STAR==*res_begin && res_begin+1!=res_end){
+        res_begin++;
+      }
+      for( TreeIter path=temp_tree.begin() ; path!=temp_tree.end() ; path++ ){
+        if( node_okay(*((*path).rbegin()),*res_begin) )
+          tree.push_back(*path);
+      }
+      return tree;
+    }
+  }
+
+  // open the path
+  int num_open=open_path(handle,path);
+  if(num_open!=path.size()){
+    close_num(handle,num_open,0);
+    throw "failed to open path";
+  }
+
+  // get the list of groups in this path
+  NodeVector groups;
+  groups=get_groups(handle);
+
+  // close the path
+  int num_close=close_path(handle,path);
+  if(num_close!=path.size())
+    throw "failed to close path";
+
+  // reduce the possible groups
+  NodeVector good_groups;
+  for( NodeVector::const_iterator group=groups.begin() ; group!=groups.end() ; group++ ){
+    if( node_okay(*group,*res_begin) || (STAR==*res_begin) )
+      good_groups.push_back(*group);
+  }
+
+  // build the new tree at this level
+  tree=make_tree(path,good_groups);
+
+  // return now if done parsing
+  if(res_begin+1==res_end)
+    return tree;
+
+  // recurse down
+  Tree full_tree;
+  for( TreeIter it=tree.begin() ; it!=tree.end() ; it++ ){
+    Tree rel_tree;
+    if(STAR==*res_begin){
+      if(node_okay(*((*it).rbegin()),*(res_begin+1))){
+        if(res_begin+2!=res_end)
+          rel_tree=build_res_rel_tree(handle,*it,res_begin+2,res_end);
+        else
+          return tree;
+      }else{
+        rel_tree=build_res_rel_tree(handle,*it,res_begin,res_end);
+      }
+    }else{
+      rel_tree=build_res_rel_tree(handle,*it,res_begin+1,res_end);
+    }
+    merge_trees(&full_tree,&rel_tree);
+  }
+
+  return full_tree;
+}
+
+/*
+ * Build a tree relative to the supplied path. This is a recursive
+ * function which continues down to any available SDSs. The NXhandle
+ * is back in its initial state after the function completes.
+ */
+extern Tree build_rel_tree(NXhandle handle, const Path &path, int num_recurse){
+  // allocate the static StringVector for use in build_res_rel_tree
+  static StringVector restrict;
+  if(restrict.empty()) restrict.push_back(DOT);
+
+  // prepare the variable to store the tree
+  Tree tree;
+
+  // check for a sensible path to recurse into
+  if(num_recurse==0)
+    return tree;
+
+  // decrease the number of levels left
+  num_recurse--;
+
+  // build this level
+  tree=build_res_rel_tree(handle,path,restrict.begin(),restrict.end());
+
+  // recurse down
+  Tree full_tree;
+  full_tree.insert(full_tree.end(),tree.begin(),tree.end());
+  for( TreeIter it=tree.begin() ; it!=tree.end() ; it++ ){
+    Tree rel_tree=build_rel_tree(handle,*it,num_recurse);
+    merge_trees(&full_tree,&rel_tree);
+  }
+
+  return full_tree;
+}
+
+/*
+ * Open the tree to the absolute path specified suplied and build a
+ * one-level tree there, which is returned. The NXhandle is back in
+ * its initial state after the function completes.
+ */
+static Tree build_tree_start(NXhandle handle, StringVector abs_path){
+  Path path;
+  Tree tree;
+  if(abs_path.empty()){
+    NodeVector groups=get_groups(handle);
+    tree=make_tree(path,groups);
+  }else{  
+    tree=build_res_rel_tree(handle,path,abs_path.begin(),abs_path.end());
+  }
+
+  return tree;
+}
+
+/*
+ * Effectively a writting of operator< for Path.
+ */
+bool compPath(const Path path1, const Path path2){
+
+  // set up for how many elements to itterate over
+  int path1_len=path1.size();
+  int path2_len=path2.size();
+  int len=path1_len;
+  if(path2_len<len)
+    len=path2_len;
+
+  // compare the names alphabetically
+  for( int i=0 ; i<len ; i++ ){
+    if(path1[i].name==path2[i].name)
+      continue;
+    else
+      return (path1[i].name<path2[i].name);
+  }
+
+  // compare the lengths
+  return (path1_len<path2_len);
+}
+
+static int num_star( const StringVector strvec){
+  int num=0;
+  for( StrVecIter str=strvec.begin() ; str!=strvec.end() ; str++ )
+    if(STAR==*str)
+      num++;
+
+  return num;
+}
+
+/*
+ * This will build a Tree of the file as specified by options. The
+ * NXhandle is returned to it original state and the Tree is sorted.
+ */
+extern Tree build_tree(NXhandle handle, const StringVector abs_path,
+                                                        const int num_recurse){
+  // build the start of the tree
+  Tree tree=build_tree_start(handle,abs_path);
+  if(tree.empty())
+    return tree;
+
+  // purge the existing tree if using stars to build the start
+  if(num_star(abs_path)>0)
+    tree=purge_tree(tree,abs_path,-1);
+
+  // adjust the recurse level as necessary
+  int rec_lev=num_recurse;
+  if(abs_path.size()<=0) rec_lev--;
+
+  // if should recurse build from the existing tree
+  if(rec_lev!=0){
+    Tree full_tree;
+    full_tree.insert(full_tree.end(),tree.begin(),tree.end());
+    for( TreeIter it=tree.begin() ; it!=tree.end() ; it++ ){
+      Tree rel_tree=build_rel_tree(handle,*it,rec_lev);
+      merge_trees(&full_tree,&rel_tree);
+    }
+    tree=full_tree;
+  }
+
+  // sort the results
+  std::sort(tree.begin(),tree.end(),compPath);
+
+  return tree;
+}
+
+static bool has_all_res(const Path &path, const StringVector &restrict){
+  int num=0;
+
+  for( StrVecIter res=restrict.begin() ; res!=restrict.end() ; res++ ){
+    if(*res==STAR){
+      num++;
+      continue;
+    }
+    for( PathIter node=path.begin() ; node!=path.end() ; node++ ){
+      if(node_okay(*node,*res)){
+        num++;
+        break;
+      }
+    }
+  }
+
+  return (restrict.size()==num);
+}
+
+static int calc_offset(const int* array, int index){
+  if(index<=0)
+    return 0;
+
+  int val=array[index-1];
+  if(val>=0)
+    return val+1;
+  if(val==ISSTAR)
+    return(calc_offset(array,index-1));
+
+  return 0;
+}
+
+static int * index_path(const Path &path, const StringVector &restrict){
+  int res_len=restrict.size();
+  int* indices=new int[res_len];
+
+  for( int i=0 ; i<res_len ; i++ )
+    indices[i]=UNINIT;
+
+  StrVecIter res=restrict.begin();
+  PathIter node=path.begin();
+  int path_len=path.size();
+  for( int i=0 ; i<res_len ; i++ ){
+    if( *(res+i)==STAR){
+      indices[i]=ISSTAR;
+      continue;
+    }
+    for( int j=calc_offset(indices,i) ; j<path_len ; j++ ){
+      if(node_okay(*(node+j),*(res+i))){
+        indices[i]=j;
+        break;
+      }
+    }
+  }
+
+  return indices;
+}
+
+/*
+ * Returns true or false if the path is okay.
+ */
+static bool path_is_okay(const Path path, const StringVector rel_path){
+  // determine if the path is long enough to hold the relative path
+  if(path.size()<rel_path.size()-num_star(rel_path))
+    return false;
+
+  // determine if all of the required path elements are in the path
+  if(!has_all_res(path,rel_path))
+    return false;
+
+  // index the path
+  int* indices=index_path(path,rel_path);
+
+  /* REMOVE
+  std::cout << "PATH[";
+  for( int i=0 ; i<rel_path.size() ; i++ ){
+    std::cout << indices[i];
+    if(i+1<rel_path.size()) std::cout << ",";
+  }
+  std::cout << "]"; print_path(path,NAME);
+  */
+
+  // do checks against indices
+  int last_index=UNINIT;
+  for( int i=0 ; i<rel_path.size() ; i++ ){
+    int this_index=indices[i];
+    if(this_index==UNINIT)
+      return false;
+    else if(this_index==ISSTAR)
+      continue;
+    if(last_index==UNINIT)
+      last_index=this_index;
+    else if(this_index<=last_index)
+      return false;
+    else
+      last_index=this_index;
+  }
+
+  // if we got this far it must be okay
+  return true;
+}
+
+/*
+ * Determine the location of the restriction from the end.
+ */
+static int find_index(const Path &path, string restrict){
+  int index=0;
+
+  for( Path::const_reverse_iterator node=path.rbegin() ; node!=path.rend()
+                                                                    ; node++ ){
+    if(node_okay(*node,restrict))  break;
+    index++;
+  }
+
+  return index;
+}
+
+/*
+ * Remove unwanted Paths from the tree according to rules in path_is_okay.
+ */
+extern Tree purge_tree(const Tree tree, const StringVector rel_path,
+                                                        const int rel_recurse){
+  if(tree.empty() || rel_path.empty())
+    return tree;
+
+  Tree good;
+
+  for( TreeIter path=tree.begin() ; path!=tree.end() ; path++ ){
+    if(path_is_okay(*path,rel_path))
+      good.push_back(*path);
+  }
+
+  // if the relative recurse level is -1 then just return the full tree
+  if(rel_recurse<0 || rel_path.empty())
+    return good;
+
+  // trim out the tree according to where the final element occurs
+  Tree trimmed;
+  string res_end=*(rel_path.rbegin());
+  for( TreeIter path=good.begin() ; path!=good.end() ; path++ ){
+    if(find_index(*path,res_end)<=rel_recurse)
+      trimmed.push_back(*path);
+  }
+
+  return trimmed;
+}
+
+/*
+ * Remove parts of the tree that do not end with the relative path
+ */
+/*
+extern Tree trim_tree_end(const Tree tree, const StringVector rel_path){
+  if(tree.empty() || rel_path.empty())
+    return tree;
+
+  Tree good;
+  string path_end=*(rel_path.rbegin());
+//  std::cout << "PATH_END=" << path_end << std::endl;
+
+  for( TreeIter path=tree.begin() ; path!=tree.end() ; path++ ){
+    Node node=*((*path).rbegin());
+
+    if( node_okay(node,path_end) )
+      good.push_back(*path);
+  }
+
+  return good;
+}
+*/
diff --git a/applications/NXdump/CMakeLists.txt b/applications/NXdump/CMakeLists.txt
new file mode 100644
index 0000000..6ce6bb0
--- /dev/null
+++ b/applications/NXdump/CMakeLists.txt
@@ -0,0 +1,45 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+if (CMAKE_Fortran_COMPILER_WORKS)
+
+    include_directories(${CMAKE_BINARY_DIR}/bindings/f90)
+
+    add_executable (NXdump NXdump.f90)
+
+    target_link_libraries(NXdump NeXus_Shared_Library NeXus_F90_Shared_Library
+                      ${HDF5_LIBRARIES}
+                      ${MXML_LINK} ${HDF4_LINK} ${READLINE_LINK} ${M_LINK}
+                      ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK}
+                      ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+    install (PROGRAMS NXdump DESTINATION bin COMPONENT Runtime)
+
+endif(CMAKE_Fortran_COMPILER_WORKS)
+
+
diff --git a/applications/NXdump/Makefile.am b/applications/NXdump/Makefile.am
new file mode 100644
index 0000000..8a77d2b
--- /dev/null
+++ b/applications/NXdump/Makefile.am
@@ -0,0 +1,48 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1239 2009-04-15 14:37:08Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+LIBNEXUS77=$(top_builddir)/bindings/f77/libNeXus77.la
+LIBNEXUS90=$(top_builddir)/bindings/f90/libNeXus90.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+AM_FCFLAGS=-I$(top_builddir)/bindings/f90
+
+EXTRA_DIST=SConscript
+
+if HAVE_F90
+F90_TARGETS = NXdump
+endif
+
+bin_PROGRAMS = $(F90_TARGETS)
+
+NXdump_SOURCES = NXdump.f90
+NXdump_LDADD = $(LIBNEXUS90)
+NXdump_LINK = $(FCLINK)
+NXdump_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ $(LDFLAGS)
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXdump/NXdump.f90 b/applications/NXdump/NXdump.f90
new file mode 100755
index 0000000..8223a0e
--- /dev/null
+++ b/applications/NXdump/NXdump.f90
@@ -0,0 +1,82 @@
+!------------------------------------------------------------------------------
+! NeXus - Neutron & X-ray Common Data Format
+!  
+! Fortran 90 utility to list the contents of a NeXus file
+!
+! Copyright (C) 1999, Ray Osborn
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Lesser General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+! Lesser General Public License for more details.
+!
+! You should have received a copy of the GNU Lesser General Public
+! License along with this library; if not, write to the Free Software
+! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+!
+! Contact : R. Osborn <ROsborn at anl.gov>
+!           Materials Science Division
+!           Argonne National Laboratory
+!           Argonne, IL 60439-4845
+!           USA
+!
+!  For further information, see <http://www.nexusformat.org>
+!
+!$Id$
+!------------------------------------------------------------------------------
+
+program NXdump
+
+   use NXmodule
+   character(len=50) :: file_name
+   type(NXhandle) :: file_id
+   integer :: indent
+
+   write (unit=*, fmt="(a)", advance="no") " Give name of NeXus file : "
+   read *, file_name
+!Open input file
+   if (NXopen (trim(file_name), NXACC_READ, file_id) /= NX_OK) stop
+!Cycle through the groups
+   indent = 1
+   call getdir
+   if (NXclose (file_id) /= NX_OK) stop
+
+contains
+   recursive subroutine getdir 
+
+      integer :: status, type, rank, dimensions(NX_MAXRANK)      
+      character(len=100) :: name, class
+
+      indent = indent + 3
+      do
+         status = NXgetnextentry (file_id, name, class, type)
+         if (status == NX_OK) then
+            if (class(1:2) == "NX") then
+               if (NXopengroup (file_id, name, class) /= NX_OK) stop
+               print *, repeat(" ",indent)//"Group """//trim(name)//""" ("//trim(class)//") opened"
+               call getdir
+            else if (class(1:3) == "SDS") then
+               print *, repeat(" ",indent)//"Next entry is """//trim(name)//""""
+               if (NXopendata (file_id, name) /= NX_OK) stop
+               if (NXgetinfo (file_id, rank, dimensions, type) /= NX_OK) stop
+               print *, repeat(" ",indent)//"  Rank = ", rank, "Type = ", NXdatatype(type)
+               print *, repeat(" ",indent)//"  Dimensions = ", dimensions(1:rank)
+               if (NXclosedata (file_id) /= NX_OK) stop
+            endif
+         else if (status == NX_EOD) then
+            if (NXclosegroup (file_id) /= NX_OK) stop
+            indent = indent - 3
+            print *, repeat(" ",indent)//"Group closed"
+            exit
+         else
+            stop
+         end if
+      end do
+   end subroutine getdir
+
+end program NXdump
diff --git a/applications/NXdump/SConscript b/applications/NXdump/SConscript
new file mode 100644
index 0000000..e69de29
diff --git a/applications/NXsummary/CMakeLists.txt b/applications/NXsummary/CMakeLists.txt
new file mode 100644
index 0000000..3c401a3
--- /dev/null
+++ b/applications/NXsummary/CMakeLists.txt
@@ -0,0 +1,42 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+include_directories(${CMAKE_SOURCE_DIR}/third_party ${LIBXML2_INCLUDE_DIR})
+
+add_executable (nxsummary data_util.cpp main.cpp string_util.cpp
+                         preferences.cpp output.cpp data_util.hpp
+                         nxsummary.hpp string_util.hpp
+                         preferences.hpp output.hpp xml_util.hpp)
+
+target_link_libraries(nxsummary NeXus_Shared_Library ${HDF5_LIBRARIES}
+                      ${MXML_LINK} ${HDF4_LINK} ${READLINE_LINK} ${M_LINK}
+                      ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK}
+                      ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES} 
+                      ${LIBXML2_LIBRARIES})
+
+install (TARGETS nxsummary DESTINATION bin COMPONENT Runtime)
+
diff --git a/applications/NXsummary/LICENSE b/applications/NXsummary/LICENSE
new file mode 100644
index 0000000..251fe9e
--- /dev/null
+++ b/applications/NXsummary/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2007, P.F.Peterson <petersonpf at ornl.gov>
+              Spallation Neutron Source at Oak Ridge National Laboratory
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/applications/NXsummary/Makefile.am b/applications/NXsummary/Makefile.am
new file mode 100644
index 0000000..e88c15f
--- /dev/null
+++ b/applications/NXsummary/Makefile.am
@@ -0,0 +1,42 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id: Makefile.am 491 2005-06-09 10:24:27Z faa59 $
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -I$(top_srcdir)/third_party @LIBXML2_CFLAGS@
+man_MANS = nxsummary.1
+
+bin_PROGRAMS = nxsummary
+noinst_HEADERS = data_util.hpp nxsummary.hpp string_util.hpp preferences.hpp output.hpp xml_util.hpp
+   
+nxsummary_SOURCES = data_util.cpp main.cpp string_util.cpp preferences.cpp output.cpp
+nxsummary_LDADD = $(LIBNEXUS)
+nxsummary_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ @LIBXML2_LDFLAGS@ $(LDFLAGS)
+EXTRA_DIST = LICENSE $(man_MANS)
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXsummary/data_util.cpp b/applications/NXsummary/data_util.cpp
new file mode 100644
index 0000000..ce69c6e
--- /dev/null
+++ b/applications/NXsummary/data_util.cpp
@@ -0,0 +1,417 @@
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <cstring>
+#include "napiconfig.h" // needed for HAVE_STDINT_H
+#include "data_util.hpp"
+#include "nxsummary.hpp"
+#include "string_util.hpp"
+
+
+
+// use STDINT if possible, otherwise define the types here
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+typedef signed char             int8_t;
+typedef short int               int16_t;
+typedef int                     int32_t;
+typedef unsigned char           uint8_t;
+typedef unsigned short int      uint16_t;
+typedef unsigned int            uint32_t;
+#ifdef _MSC_VER
+typedef signed __int64          int64_t; 
+typedef unsigned __int64        uint64_t;
+#endif //_MSC_VER
+#endif //HAVE_STDINT_H
+
+
+using std::ostringstream;
+using std::string;
+using std::runtime_error;
+
+// useful strings for printing
+static const string UNITS("units");
+static const string SPACE(" ");
+
+// constants for unit conversions
+static const string SECOND("second");
+static const string MINUTE("minute");
+static const string HOUR("hour");
+static const string DAY("day");
+static const string PICOCOULOMB("picoCoulomb");
+static const string MICROAMPHOUR("microAmp*hour");
+
+// list of allowed operations
+static const string OP_SUM("SUM");
+static const string OP_UNITS("UNITS:");
+static const string OP_DIMS("DIMS");
+static const string OP_COUNT("COUNT");
+
+/*
+ * THIS SHOULD BE ABLE TO DO
+ *
+ * total counts in entry ???
+ * principle investigator ???
+ */
+namespace nxsum {
+  bool operationValid(const std::string &operation) {
+    if (operation.compare(OP_SUM) == 0)
+      {
+        return true;
+      }
+    if (operation.compare(OP_DIMS) == 0)
+      {
+        return true;
+      }
+    if (operation.compare(OP_COUNT) == 0)
+      {
+        return true;
+      }
+    if (operation.find(OP_UNITS)!=string::npos)
+      {
+        return true;
+      }
+    return false;
+  }
+
+  string nxtypeAsString(const int type) {
+    if (type == NX_CHAR)
+      {
+        return "NX_CHAR";
+      }
+    else if(type == NX_FLOAT32)
+      {
+        return "NX_FLOAT32";
+      }
+    else if(type == NX_FLOAT64)
+      {
+        return "NX_FLOAT64";
+      }
+    else if(type == NX_UINT8)
+      {
+        return "NX_UINT8";
+      }
+    else if(type == NX_UINT16)
+      {
+        return "NX_UINT16";
+      }
+    else if(type == NX_UINT32)
+      {
+        return "NX_UINT32";
+      }
+    else if(type == NX_INT8)
+      {
+        return "NX_INT8";
+      }
+    else if(type == NX_INT16)
+      {
+        return "NX_INT16";
+      }
+    else if(type == NX_INT32)
+      {
+        return "NX_INT32";
+      }
+    else
+      {
+        ostringstream s;
+        s << type;
+        return s.str();
+      }
+  }
+
+  bool infoOnly(const string &operation) {
+    if(operation.size() <= 0)
+      {
+        return false;
+      }
+    if (operation.compare(OP_DIMS) == 0)
+      {
+        return true;
+      }
+    if (operation.compare(OP_COUNT) == 0)
+      {
+        return true;
+      }
+    return false;
+  }
+
+  string readAttrAsString(NXhandle handle, const string &label) {
+    if (NXinitattrdir(handle)!=NX_OK)
+      {
+        throw runtime_error("NXinitattrdir failed");
+      }
+    int num_attr;
+    if (NXgetattrinfo(handle, &num_attr)!=NX_OK)
+      {
+        throw runtime_error("NXgetattrinfo failed");
+      }
+    char name[GROUP_STRING_LEN];
+    int length;
+    int type;
+    for (int i = 0 ; i < num_attr ; ++i) {
+      if (NXgetnextattr(handle, name, &length, &type)!=NX_OK)
+        {
+          throw runtime_error("NXgetnextattr failed");
+        }
+      if (label == name)
+        {
+          void *data;
+          if (NXmalloc(&data, 1, &length, type)!=NX_OK)
+            {
+              throw runtime_error("NXmalloc failed");
+            }
+          int dims[1]  = {length};
+          if (NXgetattr(handle, name, data, dims, &type)!=NX_OK)
+            {
+            throw runtime_error("NXgetattr failed");
+            }
+          string result = toString(data, length, type);
+          if (NXfree(&data)!=NX_OK)
+            {
+              throw runtime_error("NXfree failed");
+            }
+        return result;
+        }
+    }
+
+    return "";
+  }
+
+  template <typename NumT>
+  NumT sum(const NumT *data, const int dims[], const int rank) {
+    size_t num_ele = 1;
+    for (size_t i = 0; i < rank; ++i) {
+      num_ele *= dims[i];
+    }
+    NumT result = static_cast<NumT>(0.);
+    for (size_t i = 0; i < num_ele; ++i) {
+      result += data[i];
+    }
+    return result;
+  }
+
+  template <typename NumT>
+  NumT inverse(const NumT data) {
+    return static_cast<NumT>(1.) / data;
+  }
+
+  template <typename NumT>
+  NumT convertUnits(const NumT data, const string &old_units,
+                    const string &new_units) {
+    if (old_units.compare(new_units) == 0)
+      {
+        return data;
+      }
+    else if(old_units.compare(SECOND) == 0)
+      {
+        NumT my_data = data / static_cast<NumT>(60.);
+        if (new_units.compare(MINUTE) == 0)
+          {
+            return my_data;
+          }
+        return convertUnits(my_data, MINUTE, new_units);
+      }
+    else if(old_units.compare(MINUTE) == 0)
+      {
+        if (new_units.compare(SECOND) == 0)
+          {
+            return inverse(convertUnits(data, new_units, old_units));
+          }
+        NumT my_data = data / static_cast<NumT>(60.);
+        if (new_units.compare(HOUR) == 0)
+          {
+            return my_data;
+          }
+        return convertUnits(my_data, HOUR, new_units);
+      }
+    else if(old_units.compare(HOUR) == 0)
+      {
+        if(new_units.compare(MINUTE) == 0)
+          {
+            return inverse(convertUnits(data, new_units, old_units));
+          }
+        NumT my_data = data / static_cast<NumT>(24.);
+        if (new_units.compare(DAY) == 0)
+          {
+            return my_data;
+          }
+        return convertUnits(my_data, DAY, new_units);
+      }
+    else if(old_units.compare(DAY) == 0)
+      {
+        if (new_units.compare(HOUR) == 0)
+          {
+            return inverse(convertUnits(data, new_units, old_units));
+          }
+      }
+    else if(old_units.compare(MICROAMPHOUR) == 0)
+      {
+        if(new_units.compare(PICOCOULOMB) == 0)
+          {
+            return data * static_cast<NumT>(36.E8);
+          }
+      }
+    else if(old_units.compare(PICOCOULOMB) == 0)
+      {
+        if (new_units.compare(MICROAMPHOUR) == 0)
+          {
+            return inverse(convertUnits(data, new_units, old_units));
+          }
+      }
+    
+    // should throw an exception here
+    ostringstream s;
+    s << "Do not know how to convert \"" << old_units << "\" to \""
+      << new_units << "\"";
+    throw runtime_error(s.str());
+  }
+
+  string operateData(const string &operation, const void *data,
+                     const int dims[], const int rank, const int type,
+                     const string & units) {
+    if (operation.size() <= 0)
+      {
+        return toString(data, dims, rank, type) + SPACE + units;
+      }
+
+    if (operation.compare(OP_SUM) == 0)
+      {
+        string result;
+        if (type == NX_FLOAT32)
+          {
+            result = toString(sum((float *)data, dims, rank));
+          }
+        else if(type == NX_FLOAT64)
+          {
+            result = toString(sum((double *)data, dims, rank));
+          }
+        else if(type == NX_UINT32)
+          {
+            result = toString(sum((uint32_t *)data, dims, rank));
+          }
+        else
+          {
+            ostringstream s;
+            s << "Do not know how to convert units with type="
+              << nxtypeAsString(type);
+            throw runtime_error(s.str());
+          }
+        return result + SPACE + units;
+      }
+
+    if (operation.compare(OP_DIMS) == 0)
+      {
+        return toString(dims, rank, NX_INT32);
+      }
+
+    if (operation.compare(OP_COUNT) == 0)
+      {
+        int num_ele = 1;
+        for (size_t i = 0; i < rank; ++i) {
+          num_ele *= dims[i];
+        }
+        return toString(num_ele);
+      }
+
+    if (operation.find(OP_UNITS)!=string::npos)
+      {
+        if ((rank != 1) || (dims[0] != 1))
+          {
+            ostringstream s;
+            s << "Cannot convert units on arrays (rank = " << rank << ")";
+            throw runtime_error(s.str());
+          }
+
+        string new_units = operation.substr(OP_UNITS.size());
+
+        if (type == NX_FLOAT32)
+          {
+            float result = convertUnits(((float *)data)[0], units, new_units);
+            return toString(result) + SPACE + new_units;
+          }
+        else if (type == NX_FLOAT64)
+          {
+            double result =convertUnits(((double *)data)[0], units, new_units);
+            return toString(result) + SPACE + new_units;
+          }
+
+        ostringstream s;
+        s << "Do not know how to convert units with type="
+          << nxtypeAsString(type);
+        throw runtime_error(s.str());
+      }
+
+    ostringstream s;
+    s << "Could not perform operation \"" << operation << "\"";
+    throw runtime_error(s.str());
+  }
+
+  string readAsString(NXhandle handle, const string &path,
+                      const string &operation) {
+    // return empty string if the path is empty
+    if (path.empty())
+      {
+        return string("");
+      }
+
+    // convert the path to something c-friendly
+    char c_path[GROUP_STRING_LEN];
+    strcpy(c_path, path.c_str());
+
+    // open the path
+    if(NXopenpath(handle, c_path)!=NX_OK)
+      {
+        throw runtime_error("COULD NOT OPEN PATH");
+        return "";
+      }
+
+    // determine rank and dimension
+    int rank = 0;
+    int type = 0;
+    int dims[NX_MAXRANK];
+    if (NXgetinfo(handle, &rank, dims, &type)!=NX_OK)
+      {
+        throw runtime_error("COULD NOT GET NODE INFORMATION");
+      }
+
+    // confirm dimension isn't too high
+    if (rank > NX_MAXRANK)
+      {
+        throw runtime_error("DIMENSIONALITY IS TOO HIGH");
+      }
+
+    // get the units
+    string units = readAttrAsString(handle, UNITS);
+
+    // check if this doesn't need the data to get result
+    if (infoOnly(operation))
+      {
+        return operateData(operation, NULL, dims, rank, type, units);
+      }
+
+    // allocate space for data
+    void *data;
+    if(NXmalloc(&data,rank,dims,type)!=NX_OK)
+      {
+        throw runtime_error("NXmalloc falied");
+      }
+
+    // retrieve data from the file
+    if(NXgetdata(handle,data)!=NX_OK)
+      {
+        throw runtime_error("NXgetdata failed");
+      }
+
+    // convert result to string
+    string result = operateData(operation, data, dims, rank, type, units);
+
+    //free up the pointer
+    if(NXfree(&data)!=NX_OK)
+      {
+        throw runtime_error("NXfree failed");
+      }
+
+    return result;
+  }
+}
diff --git a/applications/NXsummary/data_util.hpp b/applications/NXsummary/data_util.hpp
new file mode 100644
index 0000000..f6a8473
--- /dev/null
+++ b/applications/NXsummary/data_util.hpp
@@ -0,0 +1,41 @@
+#ifndef __DATA_UTIL_HPP_GUARD__
+#define __DATA_UTIL_HPP_GUARD__
+
+/**
+ * \file data_util.hpp
+ */
+#include <napi.h>
+#include <string>
+
+namespace nxsum {
+  /**
+   * \param operation The operation to check for support.
+   *
+   * \return True if the operation is supported.
+   */
+  bool operationValid(const std::string &operation);
+
+  /**
+   * This will open the file to the supplied path and perform the
+   * requested operation. Note that this leaves the filehandle
+   * pointing at the node specified in the path.
+   *
+   * \param handle Handle for the NeXus files.
+   * \param path Location in the NeXus file to look for the data at.
+   * \param operation Operation to perform on the data. If empty this
+   * returns the data itself, unchanged.
+   *
+   * \return String version of the data after the operation is performed.
+   */
+  std::string readAsString(NXhandle handle, const std::string &path,
+                           const std::string &operation);
+
+  /**
+   * \param The integer type to convert to a string.
+   *
+   * \return String representation of the supplied type.
+   */
+  std::string nxtypeAsString(const int type);
+}
+
+#endif
diff --git a/applications/NXsummary/main.cpp b/applications/NXsummary/main.cpp
new file mode 100644
index 0000000..58d2fa9
--- /dev/null
+++ b/applications/NXsummary/main.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2007, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "napiconfig.h" // needed for HAVE_STDINT_H
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+#include <string>
+#include <cstring>
+#include <cstdio>
+#include <vector>
+#include "data_util.hpp"
+#include "nxsummary.hpp"
+#include "output.hpp"
+#include "preferences.hpp"
+#include "string_util.hpp"
+#include "tclap/CmdLine.h"
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::ostringstream;
+using std::runtime_error;
+using std::string;
+using std::vector;
+using namespace TCLAP;
+using namespace nxsum;
+
+static const string NXSUM_VERSION("0.1.1");
+static const string EMPTY("");
+
+static void openFile(const string &file, NXhandle &handle) {
+  char filename[GROUP_STRING_LEN];
+  strcpy(filename, file.c_str());
+  if(NXopen(filename,NXACC_READ,&handle)!=NX_OK)
+    {
+      ostringstream s;
+      s << "Could not open file \"" << file << "\"";
+      throw runtime_error(s.str());
+    }
+}
+
+static void closeFile(const string &file, NXhandle &handle) {
+  if (handle == NULL)
+    {
+      return;
+    }
+  if(NXclose(&handle)!=NX_OK)
+    {
+      ostringstream s;
+      s << "Could not close file \"" << file << "\"";
+      throw runtime_error(s.str());
+    }
+}
+
+static void printInfo(NXhandle handle, const Item &item, const Config &config) {
+  try {
+    string value = readAsString(handle, item.path, item.operation);
+    print(item, value, config);
+  } catch(runtime_error &e) {
+    printError(item, e.what(), config);
+  }
+}
+
+static void printSummary(const string &file, const Config &config) {
+  NXhandle handle = NULL;
+  openFile(file, handle);
+
+  vector<string> values;
+  vector<bool> isError;
+
+  size_t length = config.preferences.size();
+  for (size_t i = 0 ; i < length ; ++i ) {
+    try {
+      string value = readAsString(handle, config.preferences[i].path,
+                                  config.preferences[i].operation);
+      values.push_back(value);
+      isError.push_back(false);
+    } catch(runtime_error &e) {
+      values.push_back(e.what());
+      isError.push_back(true);
+    }
+  }
+
+  print(file, config.preferences, values, isError, config);
+
+  closeFile(file, handle);
+}
+
+static void printValue(const string &file, const Item &item,
+                       const Config &config) {
+  NXhandle handle = NULL;
+  openFile(file, handle);
+
+  if (config.multifile)
+    {
+      cout << file << ";";
+    }
+  printInfo(handle, item, config);
+
+  closeFile(file, handle);
+}
+
+int main(int argc, char *argv[]) {
+  try
+    {
+      // set up the long documentation
+      ostringstream descr;
+      descr << "Generate summary of a NeXus file";
+      descr << "\n";
+      descr << "This program relies heavily on the configuration file that is located in \"${HOME}/.nxsummary.conf\" or \"/etc/nxsummary.conf\". A sample configuration file can be obtained using the \"--writeconfig\" flag.";
+      descr << "Each \"item\" tag in the file describes a node to print from the NeXus file. The \"path\" attribute describes where in the NeXus file to get information from. The \"label\" attributes is what will be printed when showing the value of the specified field. The optional \"operation\" attribute provides for certain operations to be performed on the data before printing out the result. Valid operations are:";
+      descr << "\n";
+      descr << "\"COUNT\" - The number of elements in the requested field.";
+      descr << "\n";
+      descr << "\"DIMS\" - The dimensions of the requested field.";
+      descr << "\n";
+      descr << "\"SUM\" - Add together all of the array elements and print the result.";
+      descr << "\n";
+      descr << "\"UNITS:<new units>\" - Specify the units to print the result in.";
+
+      // set up the parser
+      CmdLine cmd(descr.str(), ' ', NXSUM_VERSION);
+
+      // configure the arguments
+      SwitchArg verboseArg("", "verbose", "Turn on verbose printing", 
+                           cmd, false);
+      UnlabeledMultiArg<string> filenameArg("filename",
+                                            "Name of a file to be viewed",
+                                            false, "filename",cmd);
+      ValueArg<string> configArg("", "config", "Specify configuration file",
+                                 false, "", "config", cmd);
+      ValueArg<string> writeConfigArg("", "writeconfig",
+                              "Write the default configuration out to a file",
+                                      false, "", "config", cmd);
+      ValueArg<string> valueArg("", "value",
+                               "Get value of the item pointed to by the label",
+                                false, "", "label", cmd);
+      SwitchArg printXmlArg("", "xml", "Print results as xml",
+                            cmd, false);
+
+      // parse the arguments
+      cmd.parse(argc, argv);
+
+      // fill in the config object
+      struct Config config;
+      config.verbose = verboseArg.getValue();
+      config.show_label = true;
+      config.print_xml = printXmlArg.getValue();
+
+      // load in the preferences
+      loadPreferences(configArg.getValue(), config.preferences);
+
+      // write out the preferences and exit
+      string configOut = writeConfigArg.getValue();
+      if (configOut != "")
+        {
+          writePreferences(configOut, config.preferences);
+          return 0;
+        }
+
+      // turn of NeXus debug printing
+      NXMDisableErrorReporting();
+
+      // get the list of filenames
+      vector<string> files=filenameArg.getValue();
+      if(files.empty())
+        {
+          std::cerr << "ERROR: failed to supply <filename>" << endl;
+          cmd.getOutput()->usage(cmd);
+          return -1;
+        }
+      config.multifile = (files.size()>1);
+
+      // are we looking for a particular value
+      Item item;
+      bool getValue = (valueArg.getValue().size()>0);
+      if (getValue)
+        {
+          item = getPreference(valueArg.getValue(), config.preferences);
+          config.show_label = config.verbose;
+        }
+
+      // go through the list of files
+      for (vector<string>::const_iterator file = files.begin() ;
+           file != files.end() ; file++ )
+        {
+          if (!canRead(*file))
+            {
+              if (config.verbose)
+                {
+                  cout << "Cannot open \"" << *file << "\"" << endl;
+                }
+              continue;
+            }
+          try
+            {
+              if (getValue)
+                {
+                  printValue(*file, item, config);
+                }
+              else
+                {
+                  printSummary(*file, config);
+                }
+            }
+          catch(runtime_error &e)
+            {
+              if ((!config.multifile) || (config.verbose))
+                {
+                  std::cerr << "RUNTIME ERROR:" << e.what() <<endl;
+                }
+            }
+        }
+    }
+  catch(ArgException &e)
+    {
+      std::cerr << "PARSE ERROR:" << e.error() << " for arg " << e.argId()
+                << endl;
+      return -1;
+    }
+  catch(runtime_error &e)
+    {
+      std::cerr << "RUNTIME ERROR:" << e.what() <<endl;
+      return -1;
+    }
+
+  // all is well
+  return 0;
+}
diff --git a/applications/NXsummary/nxsummary.1 b/applications/NXsummary/nxsummary.1
new file mode 100644
index 0000000..898ef75
--- /dev/null
+++ b/applications/NXsummary/nxsummary.1
@@ -0,0 +1,85 @@
+.TH NXSUMMARY 1 "October 2011"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxdiff \- Generate summary of a NeXus file
+.SH SYNOPSIS
+.B nxsummary
+[--xml] [--value \fIlabel\fP] [--writeconfig \fIconfig\fP]
+                [--config \fIconfig\fP] [--verbose] [--] [--version] [-h]
+                [\fIfilename\fP]
+.SH DESCRIPTION
+The
+.B nxsummary
+utility prints summary information about NeXus files. This program relies
+heavily on the configuration file that is located in 
+"\fB${HOME}/.nxsummary.conf\fP" or "\fB/etc/nxsummary.conf\fP". A sample configuration
+file can be obtained using the "\fB--writeconfig\fP" flag. Each \fIitem\fP tag in 
+the file describes a node to print from the NeXus file. The \fIpath\fP
+attribute describes where in the NeXus file to get information from. The 
+\fIlabel\fP attributes is what will be printed when showing the value of 
+the specified field. The optional \fIoperation\fP attribute provides for 
+certain operations to be performed on the data before printing out the 
+result. Valid operations are:
+
+   \fBCOUNT\fP - The number of elements in the requested field.
+
+   \fBDIMS\fP - The dimensions of the requested field.
+
+   \fBSUM\fP - Add together all of the array elements and print the
+   result.
+
+   \fBUNITS:\fP\fInewunits\fP - Specify the units to print the result in.
+
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH OPTIONS
+The following options are supported
+.TP
+.B --version
+Displays version information and exits.
+.TP
+.B -h|--help
+Displays usage information and exits.
+.TP
+.B --xml
+Print results as xml
+.TP
+.B --value \fIlabel\fP
+Get value of the item pointed to by the label
+.TP
+.B --writeconfig \fIconfig\fP
+Write the default configuration out to a file
+.TP
+.B --config \fIconfig\fP
+Specify configuration file
+.TP
+.B --verbose
+Turn on verbose printing
+.TP
+.B --|--ignore_rest
+Ignores the rest of the labeled arguments following this flag.
+.SH SEE ALSO
+.BR nxconvert(1),
+.BR nxdir (1),
+.BR nxtranslate (1),
+.BR http://www.nexusformat.org
+.SH AUTHOR
+.B nxsummary
+was originally written by Peter Peterson 
+.nh
+<petersonpf at ornl.gov>
+.hy
+and may be used by others.
diff --git a/applications/NXsummary/nxsummary.hpp b/applications/NXsummary/nxsummary.hpp
new file mode 100644
index 0000000..fce1bc9
--- /dev/null
+++ b/applications/NXsummary/nxsummary.hpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * \file nxsummary.hpp
+ */
+#ifndef __NXSUMMARY_H_GUARD__
+#define __NXSUMMARY_H_GUARD__
+
+#include <string>
+#include <vector>
+
+// useful constants
+/**
+ * Size of buffer for character arrays used in node names.
+ */
+static const size_t GROUP_STRING_LEN = 512;
+
+/**
+ * String to return when path is not found in the file.
+ */
+static const std::string NOT_FOUND = "NOT FOUND:";
+
+/**
+ * Object used to define a thing to print from the file.
+ */
+struct Item{
+  std::string path;
+  std::string label;
+  std::string operation;
+};
+
+/**
+ * Run time configuration of the process.
+ */
+struct Config{
+  bool verbose;
+  bool multifile;
+  bool show_label;
+  bool print_xml;
+  std::vector<Item> preferences;
+};
+#endif
diff --git a/applications/NXsummary/output.cpp b/applications/NXsummary/output.cpp
new file mode 100644
index 0000000..097de18
--- /dev/null
+++ b/applications/NXsummary/output.cpp
@@ -0,0 +1,146 @@
+#include <iostream>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <sstream>
+#include <stdexcept>
+#include "output.hpp"
+#include "xml_util.hpp"
+
+using std::cout;
+using std::endl;
+using std::ostringstream;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+namespace nxsum {
+  void print(const Item &item, const string &value, const Config &config){
+    if (config.show_label)
+      {
+        cout << item.label << ':';
+      }
+    cout << value << endl;
+  }
+
+  void printError(const Item &item, const string &msg, const Config &config) {
+    if(!config.verbose)
+      {
+        return;
+      }
+    cout << '[' << item.label << ',' << item.path;
+    if (!item.operation.empty())
+      {
+        cout << ',' << item.operation;
+      }
+    cout << "] ERROR: " << msg << endl;
+  }
+
+  static void printStd(const string &filename, const vector<Item> &preferences,
+                       const vector<string> &values,
+                       const vector<bool> &isError, const Config &config) {
+    if (config.multifile)
+      {
+        cout << "********** " << filename << endl;
+      }
+    
+    size_t length = preferences.size();
+    for (size_t i = 0; i < length; ++i)
+      {
+        if (isError[i])
+          {
+            printError(preferences[i], values[i], config);
+          }
+        else
+          {
+            print(preferences[i], values[i], config);
+          }
+      }
+  }
+
+#if defined(LIBXML_TREE_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
+  static void writeItem(xmlNodePtr &parent, const string &label, const string &path, const string &value) {
+    xmlNodePtr node = NULL;
+    if (value.empty())
+      {
+        node = xmlNewChild(parent, NULL, item_name, NULL);
+      }
+    else
+      {
+        node = xmlNewTextChild(parent, NULL, item_name, BAD_CAST value.c_str());
+      }
+    if (!path.empty())
+      {
+        xmlNewProp(node, path_name, BAD_CAST path.c_str());
+      }
+    if (!label.empty())
+      {
+        xmlNewProp(node, label_name, BAD_CAST label.c_str());
+      }
+  }
+
+  static void printXml(const string &filename, const vector<Item> &preferences,
+                       const vector<string> &values,
+                       const vector<bool> &isError, const Config &config) {
+    // set up variables for creating the document
+    xmlDocPtr doc = NULL;        // document pointer
+    xmlNodePtr root_node = NULL; // node pointers
+
+    // create the document and the root node
+    doc = xmlNewDoc(BAD_CAST "1.0");
+    root_node = xmlNewNode(NULL, root_name);
+    xmlDocSetRootElement(doc, root_node);
+
+    // add the name of the file to the output
+    xmlNewProp(root_node, BAD_CAST "filename", BAD_CAST filename.c_str());
+
+    // loop through the values
+    size_t length = preferences.size();
+    for (size_t i = 0; i < length; ++i)
+      {
+        if (!isError[i]) {
+          writeItem(root_node, preferences[i].label, preferences[i].path, values[i]);
+        }
+      }
+
+    // write out to stdout
+    xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
+    xmlFreeDoc(doc);
+    xmlCleanupParser();
+  }
+#endif
+
+  void print(const string &filename, const vector<Item> &preferences,
+             const vector<string> &values, const vector<bool> &isError,
+             const Config &config) {
+    if (preferences.size() != values.size())
+      {
+        ostringstream buffer;
+        buffer << "Number of items (" << preferences.size()
+               << ") does not match number of values (" << values.size()
+               << ')';
+        throw runtime_error(buffer.str());
+      }
+    if (preferences.size() != isError.size())
+      {
+        ostringstream buffer;
+        buffer << "Number of items (" << preferences.size()
+               << ") does not match number of \"isError\" (" << isError.size()
+               << ')';
+        throw runtime_error(buffer.str());
+      }
+
+    if (config.print_xml)
+      {
+#if defined(LIBXML_TREE_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
+
+        printXml(filename, preferences, values, isError, config);
+#else
+        cout << "XML OUTPUT NOT COMPILED IN" << endl;
+#endif
+      }
+    else
+      {
+        printStd(filename, preferences, values, isError, config);
+      }
+  }
+}
diff --git a/applications/NXsummary/output.hpp b/applications/NXsummary/output.hpp
new file mode 100644
index 0000000..85dd3bb
--- /dev/null
+++ b/applications/NXsummary/output.hpp
@@ -0,0 +1,19 @@
+/**
+ * \file output.hpp
+ */
+#ifndef __OUTPUT_HPP_GUARD__
+#define __OUTPUT_HPP_GUARD__
+
+#include <string>
+#include <vector>
+#include "nxsummary.hpp"
+
+namespace nxsum {
+  void print(const Item &item, const std::string &value, const Config &config);
+  void print(const std::string &filename, const std::vector<Item> &preferences,
+             const std::vector<std::string> &values,
+             const std::vector<bool> &isError, const Config &config);
+  void printError(const Item &item, const std::string &msg,
+                  const Config &config);
+}
+#endif
diff --git a/applications/NXsummary/preferences.cpp b/applications/NXsummary/preferences.cpp
new file mode 100644
index 0000000..fa88a66
--- /dev/null
+++ b/applications/NXsummary/preferences.cpp
@@ -0,0 +1,329 @@
+#include <fstream>
+#include <iostream>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <sstream>
+#include <stdexcept>
+#include <stdlib.h>
+#include "data_util.hpp"
+#include "preferences.hpp"
+#include "string_util.hpp"
+#include "xml_util.hpp"
+
+using std::cout;
+using std::endl;
+using std::runtime_error;
+using std::string;
+using std::ostringstream;
+using std::vector;
+
+static const string EMPTY_STRING("");
+
+namespace nxsum {
+  bool canRead(const string &filename) {
+    if (filename.size() <= 0)
+    {
+      return false;
+    }
+    std::ifstream temp(filename.c_str(), std::ifstream::in);
+    temp.close();
+    if (temp.fail())
+      {
+        temp.clear(std::ifstream::failbit);
+        return false;
+      }
+    else
+      {
+        return true;
+      }
+  }
+
+  void addItem(vector<Item> &preferences, const string &path,
+               const string &label) {
+    Item item;
+    item.path = path;
+    item.label = label;
+    preferences.push_back(item);
+  }
+
+  void addItem(vector<Item> &preferences, const string &path,
+               const string &label, const string &operation) {
+    Item item;
+    item.path = path;
+    item.label = label;
+    if (operationValid(operation))
+      {
+        item.operation = operation;
+      }
+    else
+      {
+        ostringstream s;
+        s << "Invalid operation \"" << item.operation
+          << "\" specified";
+        throw runtime_error(s.str());
+      }
+    preferences.push_back(item);
+  }
+
+  void setDefaultPreferences(vector<Item> &preferences) {
+    addItem(preferences, "/entry/title", "TITLE");
+    addItem(preferences, "/entry/notes", "NOTES");
+    addItem(preferences, "/entry/start_time", "START TIME");
+    addItem(preferences, "/entry/end_time", "END TIME");
+    addItem(preferences, "/entry/duration", "DURATION");
+    addItem(preferences, "/entry/proton_charge", "PROTON CHARGE", "UNITS:picoCoulomb");
+    addItem(preferences, "/entry/monitor/data", "TOTAL MONITOR", "SUM");
+    addItem(preferences, "", "SAMPLE");
+    addItem(preferences, "/entry/sample/name", "  NAME");
+    addItem(preferences, "/entry/sample/nature", "  NATURE");
+    addItem(preferences, "/entry/sample/type", "  TYPE");
+    addItem(preferences, "/entry/sample/identifier", "  IDENTIFIER");
+  }
+
+#if defined(LIBXML_TREE_ENABLED)
+  void loadPreferences(const string &filename, xmlDocPtr &doc) {
+    xmlLineNumbersDefault(1);
+    doc = xmlReadFile(filename.c_str(), NULL, 0);
+    if (doc == NULL)
+      {
+        ostringstream s;
+        s << "Could not read configuration file \"" << filename << "\"";
+        throw runtime_error(s.str());
+      }
+  }
+
+  void cleanupXml(xmlDocPtr &doc) {
+    xmlFreeDoc(doc);
+    xmlCleanupParser();
+  }
+
+  void loadPreference(xmlNodePtr &item_node, vector<Item> &preferences) {
+    if (item_node == NULL)
+      {
+        return;
+      }
+    if (item_node->type != XML_ELEMENT_NODE)
+      {
+        return;
+      }
+    if (! xmlStrEqual(item_node->name, item_name))
+      {
+        return;
+      }
+    /*
+    if (item_node->properties == NULL)
+      {
+        return;
+      }
+    */
+    Item item;
+    if (xmlHasProp(item_node, path_name))
+      {
+        item.path = (char *) xmlGetProp(item_node, path_name);
+      }
+    /*
+    else
+      {
+        ostringstream s;
+        s << "Could not find path attribute in configuration file (line ";
+        s << xmlGetLineNo(item_node) << ")";
+        throw runtime_error(s.str());
+      }
+    */
+    if (xmlHasProp(item_node, label_name))
+      {
+        item.label = (char *) xmlGetProp(item_node, label_name);
+      }
+    /*
+    else
+      {
+        ostringstream s;
+        s << "Could not find label attribute in configuration file (line ";
+        s << xmlGetLineNo(item_node) << ")";
+        throw runtime_error(s.str());
+      }
+    */
+    if (xmlHasProp(item_node, operation_name))
+      {
+        item.operation = (char *)xmlGetProp(item_node, operation_name);
+        if (! operationValid(item.operation))
+          {
+            ostringstream s;
+            s << "Invalid operation \"" << item.operation
+              << "\" specified in configuration file (line "
+              << xmlGetLineNo(item_node) << ")";
+            throw runtime_error(s.str());
+          }
+      }
+
+    preferences.push_back(item);
+  }
+
+  void loadPreferences(xmlNodePtr &root_node, vector<Item> &preferences) {
+    xmlNodePtr cur_node = NULL;
+
+    for (cur_node = root_node; cur_node; cur_node = cur_node->next) {
+      if ((cur_node->type == XML_ELEMENT_NODE)
+                                && xmlStrEqual(cur_node->name, root_name)) {
+        for (cur_node = cur_node->children; cur_node;
+             cur_node = cur_node->next) {
+          loadPreference(cur_node, preferences);
+        }
+        return;
+      }
+    }
+  }
+
+  void privateLoadPreferences(const string &filename,
+                              vector<Item> &preferences) {
+    xmlDocPtr doc = NULL; // document pointer
+    loadPreferences(filename, doc);
+    xmlNodePtr root_node = xmlDocGetRootElement(doc);
+    loadPreferences(root_node, preferences);
+    cleanupXml(doc);
+  }
+
+  void loadPreferences(const string &filename, vector<Item> &preferences) {
+    // work with supplied configuration
+    if (filename.size() > 0)
+      {
+        if (canRead(filename))
+          {
+            privateLoadPreferences(filename, preferences);
+            return;
+          }
+        else if (filename == "NONE")
+          {
+            setDefaultPreferences(preferences);
+            return;
+          }
+        else
+          {
+            cout << "Cannot read configuration file \"" << filename << "\""
+                 << endl;
+          }
+      }
+
+    // user's configuration
+    string user_config;
+    if (getenv("HOME") != NULL) // HOME does not exist on WIN32
+    {
+        user_config = string(getenv("HOME")) + string("/.nxsummary.conf");
+        if (canRead(user_config))
+        {
+          privateLoadPreferences(user_config, preferences);
+          return;
+        }
+    }
+
+    // system wide configuration
+    string sys_config("/etc/nxsummary.conf");
+    if (canRead(sys_config))
+      {
+        privateLoadPreferences(sys_config, preferences);
+        return;
+      }
+
+    // default configuration compiled in
+    setDefaultPreferences(preferences);
+  }
+#else
+  void loadPreferences(const string &filename, vector<Item> &preferences) {
+    if (filename != "NONE") {
+      cout << "LIBXML2 tree support not present. Using default preferences."
+           << endl;
+    }
+    setDefaultPreferences(preferences);
+  }
+#endif    
+
+  Item getPreference(const string &label, const vector<Item> &preferences) {
+    string my_label = toUpperCase(label);
+
+    string it_label;
+    vector<Item> possible_items;
+    for (vector<Item>::const_iterator it = preferences.begin() ;
+         it != preferences.end() ; it++ ) {
+      if (it->path.size() <= 0)
+        {
+          continue;
+        }
+      it_label = toUpperCase(it->label);
+      if (it_label.compare(my_label)==0) {
+        return *it;
+      }
+      else if (it_label.find(my_label)!=string::npos) {
+        possible_items.push_back(*it);
+      }
+    }
+
+    size_t num_possible = possible_items.size();
+    if (num_possible == 1)
+      {
+        return *(possible_items.begin());
+      }
+    else if(num_possible == 0)
+      {
+        ostringstream s;
+        s << "Could not find label \"" << label << "\" in configuration";
+        throw runtime_error(s.str());
+      }
+    else
+      {
+        ostringstream s;
+        s << "Label identifier \"" << label << "\" is not unique. Found "
+          << num_possible << " matches:";
+        for (vector<Item>::const_iterator it = possible_items.begin() ;
+             it != possible_items.end() ; it++ ) {
+          s << "\"" << it->label << "\" ";
+        }
+        throw runtime_error(s.str());
+      }
+  }
+
+#if defined(LIBXML_TREE_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
+  void writePreference(xmlNodePtr &parent, const Item &preference) {
+    xmlNodePtr node = xmlNewChild(parent, NULL, item_name, NULL);
+    if (!preference.path.empty())
+      {
+        xmlNewProp(node, path_name, BAD_CAST preference.path.c_str());
+      }
+    if (!preference.label.empty())
+      {
+        xmlNewProp(node, label_name, BAD_CAST preference.label.c_str());
+      }
+    if (!preference.operation.empty())
+      {
+        xmlNewProp(node, operation_name,
+                   BAD_CAST preference.operation.c_str());
+      }
+  }
+
+  void writePreferences(const string &filename,
+                        const vector<Item> &preferences) {
+    // set up variables for creating the document
+    xmlDocPtr doc = NULL;        // document pointer
+    xmlNodePtr root_node = NULL; // node pointers
+
+    // create the document and the root node
+    doc = xmlNewDoc(BAD_CAST "1.0");
+    root_node = xmlNewNode(NULL, root_name);
+    xmlDocSetRootElement(doc, root_node);
+
+    for (vector<Item>::const_iterator it = preferences.begin() ;
+         it != preferences.end() ; it++ ) {
+      writePreference(root_node, *it);
+    }
+
+    // write out to file
+    xmlSaveFormatFileEnc(filename.c_str(), doc, "UTF-8", 1);
+    cleanupXml(doc);
+  }
+#else
+  void writePreferences(const string &filename,
+                        const vector<Item> &preferences) {
+    throw runtime_error(
+                      "LIBXML2 tree support not present. Cannot write config");
+  }
+#endif
+}
diff --git a/applications/NXsummary/preferences.hpp b/applications/NXsummary/preferences.hpp
new file mode 100644
index 0000000..4980a10
--- /dev/null
+++ b/applications/NXsummary/preferences.hpp
@@ -0,0 +1,48 @@
+/**
+ * \file preferences.hpp
+ */
+#ifndef __PREFERENCES_HPP_GUARD__
+#define __PREFERENCES_HPP_GUARD__
+
+#include <string>
+#include <vector>
+#include "nxsummary.hpp"
+
+namespace nxsum {
+  /**
+   * \param filename The name of the file to check.
+   *
+   * \return True if the file can be read.
+   */
+  bool canRead(const std::string &filename);
+
+  /**
+   * Load the preferences from the supplied file. This will search in
+   * other locations if the supplied filename is not readable.
+   *
+   * \param filename The name of the file to load the preferences from.
+   * \param preferences Parameter to put the loaded preferences in.
+   */
+  void loadPreferences(const std::string &filename,
+                       std::vector<Item> &preferences);
+
+  /**
+   * Write out the supplied preferences.
+   *
+   * \param filename The name of the file to write the preferences into.
+   * \param preferences List of preferences to write out.
+   */
+  void writePreferences(const std::string &filename,
+                        const std::vector<Item> &preferences);
+
+  /**
+   * Get a preference with the supplied label. The label does not need
+   * to be an exact match, just unique identifier (case insensitive).
+   *
+   * \param label Preference to look for.
+   * \param preferences List of preferences to search inside of.
+   */
+  Item getPreference(const std::string &label,
+                     const std::vector<Item> &preferences);
+}
+#endif
diff --git a/applications/NXsummary/string_util.cpp b/applications/NXsummary/string_util.cpp
new file mode 100644
index 0000000..35f57eb
--- /dev/null
+++ b/applications/NXsummary/string_util.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2007, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "napiconfig.h" // needed for HAVE_STDINT_H
+#include "nxsummary.hpp"
+#include "string_util.hpp"
+#include <algorithm>
+#include <cctype>
+#include <iostream>
+#include <sstream>
+#include <napi.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include "data_util.hpp"
+
+// use STDINT if possible, otherwise define the types here
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+typedef signed char             int8_t;
+typedef short int               int16_t;
+typedef int                     int32_t;
+typedef unsigned char           uint8_t;
+typedef unsigned short int      uint16_t;
+typedef unsigned int            uint32_t;
+#ifdef _MSC_VER
+typedef signed __int64          int64_t; 
+typedef unsigned __int64        uint64_t;
+#endif //_MSC_VER
+#endif //HAVE_STDINT_H
+
+
+using std::runtime_error;
+using std::string;
+using std::ostringstream;
+using std::vector;
+
+static const size_t NX_MAX_RANK = 25;
+
+namespace nxsum {
+  template <typename NumT>
+  string toString(const NumT thing) {
+    ostringstream s;
+    s << thing;
+    return s.str();
+  }
+
+  // explicit instantiations so they get compiled in
+  template string toString<uint32_t>(const uint32_t thing);
+  template string toString<int>(const int thing);
+  template string toString<double>(const double thing);
+  template string toString<float>(const float thing);
+
+  template <typename NumT>
+  string toString(const NumT *data, const int dims[], const int rank) {
+    int num_ele = 1;
+    for (size_t i = 0; i < rank; ++i ) {
+      num_ele *= dims[i];
+    }
+
+    if (num_ele == 1)
+      {
+        return toString(data[0]);
+      }
+
+    if ((rank == 1) && (num_ele < NX_MAX_RANK))
+      {
+        ostringstream s;
+        s << '[';
+        size_t length = dims[0];
+        for (size_t i = 0; i < length; ++i) {
+          s << toString(data[i]);
+          if (i+1 < length)
+            {
+              s << ',';
+            }
+        }
+        s << ']';
+        return s.str();
+      }
+    else
+      {
+        throw runtime_error("Do not know how to work with arrays");
+      }
+  }
+
+  string toString(const void *data, const int dims[], const int rank,
+                  const int type) {
+    if (type == NX_CHAR)
+      {
+        return (char *) data;
+      }
+    else if (type == NX_FLOAT32)
+      {
+        return toString((float *)data, dims, rank);
+      }
+    else if (type == NX_FLOAT64)
+      {
+        return toString((double *)data, dims, rank);
+      }
+    else if (type == NX_INT8)
+      {
+        return toString((int8_t *)data, dims, rank);
+      }
+    else if (type == NX_UINT8)
+      {
+	return toString((uint8_t *)data, dims, rank);
+      }
+    else if (type == NX_INT16)
+      {
+        return toString((int16_t *)data, dims, rank);
+      }
+    else if (type == NX_UINT16)
+      {
+	return toString((uint16_t *)data, dims, rank);
+      }
+    else if (type == NX_INT32)
+      {
+        return toString((int32_t *)data, dims, rank);
+      }
+    else if (type == NX_UINT32)
+      {
+	return toString((uint32_t *)data, dims, rank);
+      }
+    else if (type == NX_INT64)
+      {
+        return toString((int64_t *)data, dims, rank);
+      }
+    else if (type == NX_UINT64)
+      {
+	return toString((uint64_t *)data, dims, rank);
+      }
+    else
+      {
+        ostringstream s;
+        s << "Do not know how to work with type=" << nxtypeAsString(type);
+        throw runtime_error(s.str());
+      }
+  }
+
+  string toString(const void *data, const int length, const int type) {
+    int dims[1]  = {length};
+    return toString(data, dims, 1, type);
+  }
+
+  string toUpperCase(const string &orig) {
+    string result = orig;
+    std::transform(orig.begin(), orig.end(), result.begin(), (int(*)(int))std::toupper);
+    return result;
+  }
+}
diff --git a/applications/NXsummary/string_util.hpp b/applications/NXsummary/string_util.hpp
new file mode 100644
index 0000000..2c06eae
--- /dev/null
+++ b/applications/NXsummary/string_util.hpp
@@ -0,0 +1,44 @@
+/**
+ * \file string_util.hpp
+ */
+#ifndef __STRING_UTIL_HPP_GUARD__
+#define __STRING_UTIL_HPP_GUARD__
+
+#include <string>
+
+namespace nxsum {
+  /**
+   * Convert a scalar number to a string.
+   *
+   * \param thing The number to convert.
+   *
+   * \return The string version of the number.
+   */
+  template <typename NumT> std::string toString(const NumT thing);
+
+  /**
+   * Convert a multidimensional array to a pointer.
+   *
+   * \param data The multidimensional array.
+   * \param dims Dimensions of the array.
+   * \param rank The number of dimensions.
+   * \param type According to NeXus API.
+   *
+   * \return The string version of the array.
+   */
+  std::string toString(const void *data, const int dims[], const int rank,
+                       const int type);
+  /**
+   * Convert a 1D array to a pointer.
+   *
+   * \param data The 1D array.
+   * \param length Number of elements in the array.
+   * \param type According to NeXus API.
+   *
+   * \return The string version of the array.
+   */
+  std::string toString(const void *data, const int length, const int type);
+
+  std::string toUpperCase(const std::string &orig);
+}
+#endif
diff --git a/applications/NXsummary/xml_util.hpp b/applications/NXsummary/xml_util.hpp
new file mode 100644
index 0000000..4d0e7a5
--- /dev/null
+++ b/applications/NXsummary/xml_util.hpp
@@ -0,0 +1,16 @@
+/**
+ * \file output.hpp
+ */
+#ifndef __XML_UTIL_HPP_GUARD__
+#define __XML_UTIL_HPP_GUARD__
+
+#include <libxml/tree.h>
+
+namespace nxsum {
+  static const xmlChar *root_name = xmlCharStrdup("nxsummary");
+  static const xmlChar *item_name = xmlCharStrdup("item");
+  static const xmlChar *path_name = xmlCharStrdup("path");
+  static const xmlChar *label_name = xmlCharStrdup("label");
+  static const xmlChar *operation_name = xmlCharStrdup("operation");
+}
+#endif
diff --git a/applications/NXtranslate/BUGS b/applications/NXtranslate/BUGS
new file mode 100644
index 0000000..818e877
--- /dev/null
+++ b/applications/NXtranslate/BUGS
@@ -0,0 +1,22 @@
+This file contains a list of known bugs in NXtranslate or one of the
+libraries it depends on. Being smart about how you write your
+translation file will be able to avoid most of them.
+
+OPENING A NEXUS FILE MULTIPLE TIMES - There is an inconsistent bug in
+the NeXus API (napi) where the library will crash if a NeXus file is
+opened for read, closed, then opened for reading again. I have been
+unable to reproduce it in a sample code to submit to the NeXus
+developers.
+
+LINKING TO A ROOT GROUP - Creating a link to a group that exists at
+the root level (e.g. a NXentry) will move the group, not create a
+copy. If the link is at the same level, just inside the root, the
+group will be renamed. If the link is somewhere else in hierarchy the
+group will be moved to that point.
+
+RETURNING AN EMPTY TREE - The retrievers are assumed that they add at
+least one Node to the tree they are given for population. If they do
+not the xml_parser will crash. The user cannot create this error, only
+a programmer can. Instead of returning an empty tree the Retriever
+should throw an exception (invalid_argument, runtime_error, or
+exception) to notify xml_parser of the extraordinary call.
diff --git a/applications/NXtranslate/CHANGES b/applications/NXtranslate/CHANGES
new file mode 100644
index 0000000..2d93068
--- /dev/null
+++ b/applications/NXtranslate/CHANGES
@@ -0,0 +1,9 @@
+v0.2.0
+
+  Fixed bug that accidentily converted text in the translation file
+  into a float value of "0.0".
+
+  Added ability of NeXus retriever to convert Attributes into Nodes.
+
+  Can create links in output file.
+
diff --git a/applications/NXtranslate/CMakeLists.txt b/applications/NXtranslate/CMakeLists.txt
new file mode 100644
index 0000000..99ff8c7
--- /dev/null
+++ b/applications/NXtranslate/CMakeLists.txt
@@ -0,0 +1,61 @@
+# Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+#add_subdirectory (IPNS_CPP)
+add_subdirectory (text_collist)
+add_subdirectory (text_plain)
+add_subdirectory (text_xml)
+add_subdirectory (sns_histogram docs)
+add_subdirectory (FRM2)
+add_subdirectory (loopy)
+add_subdirectory (binary)
+add_subdirectory (spec)
+add_subdirectory (esrf_edf)
+#add_subdirectory ($(GENIESUBDIR)
+
+add_definitions(-DFRM2_RETRIEVER -DTEXT_COLLIST_RETRIEVER -DTEXT_PLAIN_RETRIEVER -DTEXT_XML_RETRIEVER -DDYNAMIC_RETRIEVER -DSNS_HISTOGRAM_RETRIEVER -DLOOPY_RETRIEVER -DBINARY_RETRIEVER -DEDF_RETRIEVER -DSPEC_RETRIEVER)
+
+
+include_directories(. ${LIBXML2_INCLUDE_DIR} text_collist text_plain text_xml sns_histogram FRM2 loopy)
+
+add_executable (nxtranslate attr.cpp main.cpp nexus_retriever.cpp  nexus_util.cpp node.cpp
+	                  node_util.cpp retriever.cpp string_util.cpp xml_parser.cpp
+                          xml_util.h xml_util.cpp attr.h nexus_retriever.h nexus_util.h node.h 
+                          node_util.h nxtranslate_debug.h Ptr.h retriever.h string_util.h xml_parser.h 
+                          tree.hh dynamic_retriever.cpp dynamic_retriever.h)
+
+target_link_libraries(nxtranslate NeXus_Static_Library ${HDF5_LIBRARIES}
+                      ${MXML_LINK} ${READLINE_LINK} ${M_LINK} ${DF_LINK}
+                      ${DL_LINK} ${PTHREAD_LINK} ${TERMCAP_LINK} ${HDF4_LINK}
+                      ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES} 
+                      ${LIBXML2_LIBRARIES} BinaryRetriever Edf FRM2 
+                      Loopy SNShistogram Spec TextCollist TextPlain TextXML
+                      )
+
+install (TARGETS nxtranslate DESTINATION bin COMPONENT Runtime)
+
diff --git a/applications/NXtranslate/FRM2/CMakeLists.txt b/applications/NXtranslate/FRM2/CMakeLists.txt
new file mode 100644
index 0000000..09b2ff1
--- /dev/null
+++ b/applications/NXtranslate/FRM2/CMakeLists.txt
@@ -0,0 +1,32 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (FRM2 STATIC frm2_retriever.cpp frm2_retriever.h)
+
diff --git a/applications/NXtranslate/FRM2/Makefile.am b/applications/NXtranslate/FRM2/Makefile.am
new file mode 100644
index 0000000..1204934
--- /dev/null
+++ b/applications/NXtranslate/FRM2/Makefile.am
@@ -0,0 +1,42 @@
+
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libFRM2.la
+
+libFRM2_la_SOURCES = \
+	frm2_retriever.cpp frm2_retriever.h
+
+#EXTRA_DIST = 
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/FRM2/frm2_retriever.cpp b/applications/NXtranslate/FRM2/frm2_retriever.cpp
new file mode 100644
index 0000000..7da42ed
--- /dev/null
+++ b/applications/NXtranslate/FRM2/frm2_retriever.cpp
@@ -0,0 +1,3141 @@
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <fstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <map>
+#include "frm2_retriever.h"
+#include "../node.h"
+#include "../nexus_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+#include <math.h>
+#include <cstring>
+#include <cstdlib>
+#include <cctype>
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+using std::isspace;
+using std::isdigit;
+using std::isalpha;
+
+#define MIN(a,b) ( (a)<(b)? (a):(b) )
+#define MAX(a,b) ( (a)>(b)? (a):(b) )
+
+class NXunits {
+	public:
+	static const std::string second;		 
+	static const std::string millisecond;	
+	static const std::string microsecond;
+	static const std::string nanosecond;
+	static const std::string minute;
+	static const std::string degree;	
+	static const std::string count;
+	static const std::string volt;
+	static const std::string ampere;
+	static const std::string angstrom;
+	static const std::string inverse_angstrom;
+	static const std::string bar;
+	static const std::string millibar;
+	static const std::string meter;
+	static const std::string millimeter;
+	static const std::string rpm;
+	static const std::string hertz;
+	static const std::string megahertz;
+	static const std::string gigahertz;
+	static const std::string terahertz;
+	static const std::string kelvin;
+	// to be completed later
+};
+
+
+static const int BUFFER_SIZE=4096;
+static const int LOG_BUFFER_SIZE=64000;
+
+const std::string NXunits::second = "second";
+const std::string NXunits::millisecond = "millisecond";
+const std::string NXunits::microsecond = "microsecond";
+const std::string NXunits::nanosecond = "nanosecond";
+const std::string NXunits::minute = "minute";
+const std::string NXunits::degree = "degree";
+const std::string NXunits::count = "counts";
+const std::string NXunits::volt = "volt";
+const std::string NXunits::ampere = "ampere";
+const std::string NXunits::angstrom = "angstrom";
+const std::string NXunits::inverse_angstrom = "angstrom^-1";
+const std::string NXunits::bar = "bar";
+const std::string NXunits::millibar = "millibar";
+const std::string NXunits::meter = "meter";
+const std::string NXunits::millimeter = "millimeter";
+const std::string NXunits::rpm = "rpm";
+const std::string NXunits::hertz = "Hz";
+const std::string NXunits::megahertz = "MHz";
+const std::string NXunits::gigahertz = "GHz";
+const std::string NXunits::terahertz = "THz";
+const std::string NXunits::kelvin = "K";
+
+
+void Frm2Retriever::initUnits() {
+	unit_strings["seconds"] 		= NXunits::second;
+	unit_strings["second"] 			= NXunits::second;
+	unit_strings["secs"] 			= NXunits::second;
+	unit_strings["sec"] 				= NXunits::second;
+	
+	unit_strings["milliseconds"] 	= NXunits::millisecond;
+	unit_strings["msec"] 			= NXunits::millisecond;
+	unit_strings["msecs"] 			= NXunits::millisecond;
+
+	unit_strings["microseconds"] 	= NXunits::microsecond;
+	unit_strings["usec"] 			= NXunits::microsecond;
+	unit_strings["usecs"] 			= NXunits::microsecond;
+	
+	unit_strings["nanoseconds"] 	= NXunits::nanosecond;
+	unit_strings["nsec"] 			= NXunits::nanosecond;
+	unit_strings["ns"] 				= NXunits::nanosecond;
+	
+	unit_strings["minutes"]	= NXunits::minute;
+	unit_strings["minute"]	= NXunits::minute;
+	unit_strings["min"]		= NXunits::minute;
+	
+	unit_strings["deg"] 		= NXunits::degree;
+	unit_strings["degs"] 	= NXunits::degree;
+	unit_strings["degree"] 	= NXunits::degree;
+	unit_strings["degrees"] = NXunits::degree;
+	
+	unit_strings["cts"] 		= NXunits::count;
+	unit_strings["counts"] 	= NXunits::count;
+	unit_strings["count"] 	= NXunits::count;
+	unit_strings["cnt"] 		= NXunits::count;
+	
+	unit_strings["bar"] 		= NXunits::bar;
+	unit_strings["bars"]		= NXunits::bar;
+	
+	unit_strings["mbar"] 	= NXunits::millibar;
+	unit_strings["millibar"]= NXunits::millibar;
+	
+	unit_strings["rpm"] 		= NXunits::rpm;
+	unit_strings["rpms"]		= NXunits::rpm;
+	
+	unit_strings["volt"] 	= NXunits::volt;
+	unit_strings["v"] 		= NXunits::volt;
+	unit_strings["volts"] 	= NXunits::volt;
+	
+	unit_strings["ampere"] 	= NXunits::ampere;
+	unit_strings["amp"] 		= NXunits::ampere;
+	unit_strings["amperes"] = NXunits::ampere;
+	
+	unit_strings["a"] 			= NXunits::angstrom;
+	unit_strings["ang"] 			= NXunits::angstrom;
+	unit_strings["angst"] 		= NXunits::angstrom;
+	unit_strings["angstrom"] 	= NXunits::angstrom;
+	unit_strings["angstroem"] 	= NXunits::angstrom;
+	unit_strings["angstr�m"] 	= NXunits::angstrom;
+	unit_strings["�ngstr�m"] 	= NXunits::angstrom;
+	
+	unit_strings["a^-1"] 				= NXunits::inverse_angstrom;
+	unit_strings["a-1"] 					= NXunits::inverse_angstrom;
+	unit_strings["angst^-1"] 			= NXunits::inverse_angstrom;
+	unit_strings["angst-1"] 			= NXunits::inverse_angstrom;
+	unit_strings["angstrom-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["angstrom^-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["invangstrom"] 		= NXunits::inverse_angstrom;
+	unit_strings["inverse angstrom"] = NXunits::inverse_angstrom;
+	unit_strings["invangstroem"] 		= NXunits::inverse_angstrom;
+	unit_strings["inverse angstroem"]= NXunits::inverse_angstrom;
+	unit_strings["angstroem-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["angstroem^-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["invangstr�m"] 		= NXunits::inverse_angstrom;
+	unit_strings["inverse angstr�m"] = NXunits::inverse_angstrom;
+	unit_strings["angstr�m^-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["angstr�m-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["inv�ngstr�m"] 		= NXunits::inverse_angstrom;
+	unit_strings["inverse �ngstr�m"] = NXunits::inverse_angstrom;
+	unit_strings["�ngstr�m-1"] 		= NXunits::inverse_angstrom;
+	unit_strings["�ngstr�m^-1"] 		= NXunits::inverse_angstrom;
+	
+	unit_strings["m"] 			= NXunits::meter;
+	unit_strings["meter"]		= NXunits::meter;
+	
+	unit_strings["mm"] 			= NXunits::millimeter;
+	unit_strings["millimeter"]	= NXunits::millimeter;
+	
+	unit_strings["hz"]			= NXunits::hertz;
+	unit_strings["hertz"]		= NXunits::hertz;
+	unit_strings["mhz"]			= NXunits::megahertz;
+	unit_strings["megahertz"]	= NXunits::megahertz;
+	unit_strings["ghz"]			= NXunits::gigahertz;
+	unit_strings["gigahertz"]	= NXunits::gigahertz;
+	unit_strings["thz"]			= NXunits::terahertz;
+	unit_strings["terahertz"]	= NXunits::terahertz;
+	
+	unit_strings["k"]				= NXunits::kelvin;
+	unit_strings["kelvin"]		= NXunits::kelvin;
+	unit_strings["kelvins"]		= NXunits::kelvin;
+	
+	unit_strings["none"]			= "";
+}
+
+
+const std::string Frm2Retriever::MIME_TYPE = "text/frm2";
+const std::string Frm2Retriever::COLUMN_TAG = "column";
+const std::string Frm2Retriever::DICT_TAG = "dict";
+const std::string Frm2Retriever::DATETIME_TAG = "datetime";
+const std::string Frm2Retriever::FILENAME_TAG = "filename";
+const std::string Frm2Retriever::DICTARRAY_TAG = "dict_array";
+const std::string Frm2Retriever::DICTMULTI_TAG = "dict_multi";
+const std::string Frm2Retriever::TOFCTS_TAG = "tof_cts";
+const std::string Frm2Retriever::TOFTOF_TAG = "tof_tof";
+const std::string Frm2Retriever::TOFDNR_TAG = "tof_dnr";
+const std::string Frm2Retriever::TOFMONTOF_TAG = "tof_montof";
+const std::string Frm2Retriever::TOFMONCTS_TAG = "tof_moncts";
+const std::string Frm2Retriever::TOFLOG_TAG = "tof_log";
+const std::string Frm2Retriever::LOGCPY_TAG = "log_cpy";
+const std::string Frm2Retriever::DESC_TAG = "desc";
+const std::string Frm2Retriever::FLINE_TAG = "fline";
+const std::string Frm2Retriever::RANGE_OPEN_BRACKET="[";
+const std::string Frm2Retriever::RANGE_CLOSE_BRACKET="]";
+const std::string Frm2Retriever::RANGE_SEPARATOR=":";
+const std::string Frm2Retriever::METHOD_OPEN_BRACKET="(";
+const std::string Frm2Retriever::METHOD_CLOSE_BRACKET=")";
+const std::string Frm2Retriever::TYPE_OPEN_BRACKET="{";
+const std::string Frm2Retriever::TYPE_CLOSE_BRACKET="}";
+const std::string Frm2Retriever::ARG_QUOTE="'";
+const std::string Frm2Retriever::ARG_SEPARATOR="'";
+
+
+const std::string Frm2Retriever::HEADER_TAG = "header";
+const std::string Frm2Retriever::DATA_TAG = "data";
+const std::string Frm2Retriever::HEIDICTS_TAG = "heidi_cts";
+const std::string Frm2Retriever::HEIDIMON_TAG = "heidi_mon";
+const std::string Frm2Retriever::HEIDIIDS_TAG = "heidi_ids";
+const std::string Frm2Retriever::HEIDIOMG_TAG = "heidi_omg";
+const std::string Frm2Retriever::HEIDISO_TAG = "heidi_so";
+const std::string Frm2Retriever::ARRAY_OPEN_BRACKET="[";
+const std::string Frm2Retriever::ARRAY_CLOSE_BRACKET="]";
+const std::string Frm2Retriever::ARRAY_RANGE_SEPARATOR=":";
+const std::string Frm2Retriever::ARRAY_SEPARATOR=",";
+
+const unsigned int Frm2Retriever::HEIDI_LINES_PER_ENTRY=3;
+const unsigned int Frm2Retriever::HEIDI_CHARS_PER_COUNT=5;
+const unsigned int Frm2Retriever::HEIDI_COLS_PER_LINE=16;
+
+
+
+static unsigned int convert_type(std::string nxtype) {
+	if (nxtype =="NX_CHAR") {
+		return NX_CHAR;
+	}
+	else if (nxtype =="NX_BOOLEAN") {
+		return NX_UINT8;
+	}
+	else if (nxtype =="NX_BINARY") {
+		return NX_BINARY;
+	}
+	else if (nxtype =="NX_INT8") {
+		return NX_INT8;
+	}
+	else if (nxtype =="NX_UINT8") {
+		return NX_UINT8;
+	}
+	else if (nxtype =="NX_INT16") {
+		return NX_INT16;
+	}
+	else if (nxtype =="NX_UINT16") {
+		return NX_UINT16;
+	}
+	else if (nxtype =="NX_INT32") {
+		return NX_INT32;
+	}
+	else if (nxtype =="NX_UINT32") {
+		return NX_UINT32;
+	}
+	else if (nxtype =="NX_FLOAT32") {
+		return NX_FLOAT32;
+	}
+	else if (nxtype =="NX_FLOAT32") {
+		return NX_FLOAT32;
+	}
+	else if (nxtype =="ISO8601") {
+		return NX_CHAR;
+	}
+	return NX_FLOAT64;
+}
+
+static double arsin(double x)
+{
+  if (x>0)
+    return(asin(MIN(x, 1.0)));
+  if (x<0)
+    return(asin(MAX(x,-1.0)));
+  return(0);
+}
+
+static double sgn(double x)
+{
+  if (x>0)
+    return(1);
+  else if (x<0)
+    return(-1);
+  else
+    return(0);
+}
+
+
+static void reset_file(ifstream &file) {
+	file.clear();
+	file.seekg(0,std::ios::beg);
+	file.clear();
+}
+
+static string read_line(ifstream &file) {
+	static char buffer[BUFFER_SIZE];
+	file.get(buffer,BUFFER_SIZE);
+	file.get();
+	int state = file.rdstate();
+	//std::cout << "iostate: " << state << " failbit:" << std::ios::failbit << " badbit:"<< std::ios::badbit<<" eofbit:" << std::ios::eofbit<< std::endl;
+	while (file.fail() && (!file.eof())) {
+		file.clear();
+		file.get();
+	}
+	return string(buffer);
+}
+
+static int count_chars(std::string str, char c) {
+	int n=0;
+	for (int i=0; i<str.size(); i++) {
+		if (str[i] == c) {
+			n++;
+		}
+	}
+	return n;
+}
+
+static char read_char(ifstream &file){
+  return file.get();
+}
+
+static void skip_to_line(ifstream &file,int &cur_line, int new_line){
+   file.seekg(0,std::ios::beg);
+  if(new_line==cur_line){ // skip out early if possible
+    return;
+  }else if(new_line<cur_line){  // go to the beginning if necessary
+    file.seekg(0,std::ios::beg);
+    cur_line=0;
+  }
+
+  // scan down to the right place
+  while( (file.good()) && (cur_line<new_line) ){
+    string text=read_line(file);
+    //cout << "LINE" << cur_line << "[" << file.tellg() << "]:" << text << endl;
+    cur_line++;
+  }
+
+  if(!(file.good()))
+    throw invalid_argument("Could not reach line "
+                           +string_util::int_to_str(new_line));
+}
+
+
+
+
+std::string Frm2Retriever::parse_method(std::string location){
+	unsigned int pos = 0;
+	static std::string sub_str;
+	
+	pos = location.find_first_of(Frm2Retriever::METHOD_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(0, pos);
+		return sub_str;			
+	}
+	else {
+		pos = location.find_first_of(Frm2Retriever::RANGE_OPEN_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = location.substr(0, pos);
+			return sub_str;			
+		}
+		else {
+			pos = location.find_first_of(Frm2Retriever::TYPE_OPEN_BRACKET);
+			if (pos != std::string::npos) {
+				sub_str = location.substr(0, pos);
+				return sub_str;			
+			}
+		}
+	}
+	return location;
+}
+
+
+std::vector<unsigned int> Frm2Retriever::parse_dims(std::string dimstr) {
+	unsigned int pos = 0;
+	std::string sub_str;
+	std::vector<unsigned int> dims;
+	
+	pos = dimstr.find_last_of(Frm2Retriever::ARRAY_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = dimstr.substr(pos);
+		sub_str = sub_str.substr(1);
+		pos = sub_str.find_first_of(Frm2Retriever::ARRAY_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			dims = string_util::split_uints(sub_str);	
+		}
+	}
+	return dims;
+}
+
+
+std::vector<unsigned int> Frm2Retriever::parse_type_dims(std::string location, std::string &typestr){
+	unsigned int pos = 0;
+	std::string sub_str;
+	std::vector<unsigned int> dims;
+	
+	pos = location.find_last_of(Frm2Retriever::TYPE_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(pos);
+		sub_str = sub_str.substr(1);
+		pos = sub_str.find_first_of(Frm2Retriever::TYPE_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			pos = sub_str.find_last_of(Frm2Retriever::ARRAY_OPEN_BRACKET);
+			if (pos != std::string::npos) {
+				//std::cout << "dim brackets found: " << sub_str.substr(0,pos) << " " << sub_str << std::endl;
+				typestr = sub_str.substr(0,pos);	
+				return parse_dims(sub_str);
+			}
+			else {
+				typestr = sub_str;			
+			}
+		}
+	}
+	return dims;
+}
+
+std::string Frm2Retriever::parse_type(std::string location){
+	unsigned int pos = 0;
+	static std::string sub_str;
+	
+	pos = location.find_last_of(Frm2Retriever::TYPE_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(pos);
+		sub_str = sub_str.substr(1);
+		pos = sub_str.find_first_of(Frm2Retriever::TYPE_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			return sub_str;			
+		}
+	}
+	return "";
+}
+
+std::vector<std::string> Frm2Retriever::parse_arg(std::string location){
+	// check if column
+	unsigned int start_pos = 0;
+	unsigned int end_pos = 0;
+	static std::string arg_str;
+	static std::string item_str;
+	std::vector<std::string> result;
+	
+	start_pos = location.find_first_of(Frm2Retriever::METHOD_OPEN_BRACKET);
+	if (start_pos != std::string::npos) {
+		arg_str = location.substr(start_pos);
+		arg_str = arg_str.substr(1);
+		arg_str = arg_str.substr(0, arg_str.size()-1);
+
+		// TODO: check if range brackets are to be extracted
+		// no need, they get cut automatically
+		end_pos = arg_str.find_first_of(Frm2Retriever::METHOD_CLOSE_BRACKET);
+		if (end_pos != std::string::npos) {
+			arg_str = arg_str.substr(0, end_pos);
+		}
+		
+		start_pos = arg_str.find_first_of(Frm2Retriever::ARG_QUOTE);
+		if (start_pos == std::string::npos) {
+			result = string_util::split_colons(arg_str);
+			return result;
+		}
+		
+		// check how many args 
+		while (true) {
+			start_pos = arg_str.find_first_of(Frm2Retriever::ARG_QUOTE);
+			if (start_pos != std::string::npos) {
+				
+				arg_str = arg_str.substr(start_pos);
+				arg_str = arg_str.substr(1);
+			
+				end_pos = arg_str.find_first_of(Frm2Retriever::ARG_QUOTE);
+				if (end_pos != std::string::npos) {
+					item_str = arg_str.substr(0, end_pos);
+					arg_str = arg_str.substr(end_pos+1);
+					result.push_back(item_str);
+				}
+			}
+			else {
+				break;
+			}
+		}
+		
+		/*/ check if quotes have to be removed 
+		if (arg_str[0]=='\"' || arg_str[0] == '\'') {
+			arg_str = arg_str.substr(1);
+			arg_str = arg_str.substr(0, arg_str.size()-1);
+		}*/
+	}
+		
+	return result;
+}
+
+
+void Frm2Retriever::parse_range(std::string location, int &x, int &y){
+	unsigned int pos = 0;
+	static std::string sub_str;
+	
+	x = -1;
+	y = -1;
+	
+	pos = location.find_last_of(Frm2Retriever::RANGE_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(pos);
+		pos = sub_str.find_first_of(Frm2Retriever::RANGE_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			
+			pos = sub_str.find_first_of(Frm2Retriever::RANGE_SEPARATOR);
+			if (pos != std::string::npos) {
+				if (isNumber(sub_str.substr(0,pos))) {
+					x = string_util::str_to_int(sub_str.substr(0,pos));
+				}
+				if (isNumber(sub_str.substr(pos))) {
+					y = string_util::str_to_int(sub_str.substr(pos));
+				}
+				return;
+			}
+			else {
+				// if no range separator is found -> go specified position to end of column
+				if (isNumber(sub_str)) {
+					x = string_util::str_to_int(sub_str);
+				}
+				return;
+			}
+		}
+	}
+}
+
+void Frm2Retriever::parse_heidi_range(std::string location, int &line, int &word, int &wcount){
+	unsigned int pos = 0;
+	std::string sub_str;
+
+	wcount = 0;
+	// cut the type part as it may contain range info too ...
+	pos = location.find_last_of(Frm2Retriever::TYPE_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		location = location.substr(0,pos);
+	}
+	
+	pos = location.find_last_of(Frm2Retriever::ARRAY_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(pos+1);
+		pos = sub_str.find_first_of(Frm2Retriever::ARRAY_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			
+			pos = sub_str.find_first_of(Frm2Retriever::ARRAY_SEPARATOR);
+			if (pos != std::string::npos) {
+				//std::cout << "conv to line: " << sub_str.substr(0,pos) << std::endl;
+				line = string_util::str_to_int(sub_str.substr(0,pos));
+				sub_str = sub_str.substr(pos+1);
+				//std::cout << "XD sub_str: " << sub_str << std::endl;
+				
+				pos = sub_str.find_first_of(Frm2Retriever::ARRAY_RANGE_SEPARATOR);
+				if (pos != std::string::npos) {
+					//std::cout << "conv to word: " << sub_str.substr(0,pos) << std::endl;
+					word = string_util::str_to_int(sub_str.substr(0,pos));
+					//std::cout << "conv to wcount: " << sub_str.substr(pos+1) << std::endl;
+					wcount = string_util::str_to_int(sub_str.substr(pos+1));
+				}
+				else {
+					word = string_util::str_to_int(sub_str);
+					wcount=0;
+				}
+				return;
+			}
+			else {
+				line = 0;
+				pos = sub_str.find_first_of(Frm2Retriever::ARRAY_RANGE_SEPARATOR);
+				if (pos != std::string::npos) {
+					//std::cout << "intstr: " << sub_str << sub_str.substr(0,pos) << std::endl;
+					word = string_util::str_to_int(sub_str.substr(0,pos));
+					int upperlimit = string_util::str_to_int(sub_str.substr(pos+1));
+					wcount = upperlimit-word;
+					//std::cout << "word: " << word << " wcount: " << wcount << std::endl;	
+				}
+				else {
+					word = string_util::str_to_int(sub_str);
+				}
+				return;
+			}
+		}
+	}
+	line = -1;
+	word = -1;
+	wcount = 0;
+}
+
+bool Frm2Retriever::isdata(std::string line) {
+	unsigned int i=0;
+	int digit_count = 0;
+	int alpha_count = 0;
+	int space_count = 0;
+	
+	if (line.size()==0) {
+		return false;
+	}
+
+	while(i<line.size()){
+		if (isdigit(line[i])) {
+			digit_count++;
+		}
+		else if (isalpha(line[i])) {
+			alpha_count++;
+		}
+		else if (isspace(line[i])) {
+			space_count++;
+		}
+		i++;
+	}
+	// if alpha count is greater than 75 percent -> assume its a data row
+
+	if (line.size() > space_count) {
+//cout << "chars: " << line.size()-space_count << " digits: " << digit_count <<" percent: " <<digit_count*100/(line.size()-space_count)<<endl;
+		if (digit_count*100/(line.size()-space_count) > 70) {
+			return true;
+		}
+	}
+	else {
+		return false;
+	}
+	return false;
+}
+
+
+bool Frm2Retriever::isunit(std::string line) {
+	unsigned int unit_count = 0;
+	std::vector<std::string> strings = string_util::split_whitespace(line);
+	strings = string_util::strip_punct(strings);
+	
+	for (std::vector<std::string>::iterator its=strings.begin(); its!=strings.end(); its++) {
+		std::string str_word = *its;
+		for (std::map<std::string, std::string>::iterator it = unit_strings.begin(); it != unit_strings.end(); it++) {
+			std::string str_unit= it->first;
+			if (str_word == str_unit) {
+				unit_count++;
+				break;
+			}
+		}
+	}
+	//std::cout << " unit_count: " << unit_count << std::endl;
+	if (unit_count > 1) {
+		return true;
+	}
+	return false;
+}
+
+void Frm2Retriever::strip(std::string& str) {
+	while (isspace(str[0])){
+		str = str.substr(1);
+	}
+	while (isspace(str[str.size()-1])){
+		str = str.substr(0, str.size()-1);
+	}
+}
+
+bool Frm2Retriever::isNumber(std::string str) {
+	// eliminate whitespace on both ends
+	while (isspace(str[0])){
+		str = str.substr(1);
+	}
+	while (isspace(str[str.size()-1])){
+		str = str.substr(0, str.size()-1);
+	}
+	
+	// if string is empty -> nan
+	if (str.size()<=0) {
+		return false;
+	}
+
+	if (str[0]=='-' || str[0]=='+') {
+		str = str.substr(1);
+	}
+	
+	// if string is empty -> nan
+	if (str.size()<=0) {
+		return false;
+	}
+
+	for (unsigned int i=0; i < str.size(); i++) {
+		if (!isdigit(str[i])) {
+			return false;
+		}
+	}
+	return true;
+}
+
+bool Frm2Retriever::isheidiheader(std::string line) {
+	unsigned int i=0;
+	int digit_count = 0;
+	int alpha_count = 0;
+	int space_count = 0;
+	
+	while(i<line.size()){
+		if (isdigit(line[i])) {
+			digit_count++;
+		}
+		else if (isalpha(line[i])) {
+			alpha_count++;
+		}
+		else if (isspace(line[i])) {
+			space_count++;
+		}
+		i++;
+	}
+
+	if (alpha_count >=3 && string_util::contains(line, "=") ) {
+		return true;
+	}
+	return false;
+}
+
+
+bool Frm2Retriever::isheidicountdata(std::string line) {
+	unsigned int i=0;
+	int digit_count = 0;
+	int alpha_count = 0;
+	int space_count = 0;
+	
+	while(i<line.size()){
+		if (isdigit(line[i])) {
+			digit_count++;
+		}
+		else if (isalpha(line[i])) {
+			alpha_count++;
+		}
+		else if (isspace(line[i])) {
+			space_count++;
+		}
+		i++;
+	}
+
+	if (digit_count > 38) {
+		return true;
+	}
+	return false;
+}
+
+
+
+void Frm2Retriever::extract_headers(std::string line) {
+	//std::cout << "header line: " << line << std::endl;
+	headers = string_util::split_whitespace(line); 
+	headers = string_util::strip_punct(headers);
+	/*for (unsigned int i=0; i< headers.size(); i++) {
+		std::cout << "headers["<<i<<"]: " << headers.at(i) << std::endl;
+	}*/
+}
+
+
+void Frm2Retriever::extract_toflogheaders(std::ifstream &file) {
+	int cur_line=0;
+	int i=0;
+	unsigned int pos=0;
+	std::string str="";
+	std::string value="";
+	std::map<int, std::string> key_pairs; 
+	
+	reset_file(file);
+	while (file.good() && (cur_line++)<=data_section) {
+		
+		std::string line = read_line(file);
+		
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+		pos = line.find("#++");
+		if (pos != std::string::npos && pos<2) {
+			line = line.substr(pos+3);
+			pos = line.find(":", pos);
+			if (pos != std::string::npos) {
+				value = line.substr(0, pos);
+				while (isspace(value[0])){
+					value = value.substr(1);
+				}
+				
+				str = line.substr(pos+1);
+				while (isspace(str[0])){
+					str = str.substr(1);
+				}
+				while (isspace(str[str.size()-1])){
+					str = str.substr(0, str.size()-1);
+				}
+				
+				if (isNumber(str)) {
+					int key = string_util::str_to_int(str);
+					key_pairs[key] = value;
+				}
+			}
+		}
+	}
+
+	headers.clear();
+	// map map to header vector 
+	for (unsigned int i=0; i< key_pairs.size(); i++) {
+		//std::cout << "pushing " << key_pairs[i] << " into headers" << std::endl;
+		headers.push_back(key_pairs[i]);
+	}
+}
+
+std::vector<std::string>& Frm2Retriever::clear_units(std::vector<std::string> &units) {
+	for (std::vector<std::string>::iterator it=units.begin(); it!=units.end(); it++) {
+		std::string unit = *it;
+		if (unit == "-" ) {
+			units.erase(it);
+			units.insert(it, "none");
+		}
+	}
+	return units;
+}
+	
+void Frm2Retriever::extract_units(std::string line) {
+	units = string_util::split_whitespace(line);
+	units = clear_units(units);
+	units = string_util::strip_punct(units);
+	for (unsigned int i=0; i< units.size(); i++) {
+		std::cout << "units["<<i<<"]: " << units.at(i) << std::endl;
+	}
+}
+
+
+std::string Frm2Retriever::extract_datetime(std::ifstream &file, std::vector<std::string> args, unsigned int nxtype) {
+	std::string datetime;
+	std::string date;
+	std::string time;
+	
+	// size of args must be at least 1 (time)
+	if (args.size() < 1) {
+		return "";
+	}
+	if (args.size() < 2 ) {
+		// we got only a timestring
+		std::map<std::string, std::string> raw_map = extract_dictentry(file, args[0], nxtype);
+		datetime = raw_map["values"];
+	}
+	else {
+		// we got date and time string separately
+		std::map<std::string, std::string> raw_map;
+		raw_map = extract_dictentry(file, args[0], nxtype);
+		date = raw_map["values"];
+		raw_map = extract_dictentry(file, args[1], nxtype);
+		time = raw_map["values"];
+		
+		datetime = date+" "+time;
+		if (count_chars(datetime, '.') > 1) {
+			datetime = toftof_datetime_2_iso(datetime);
+		}
+		else if (count_chars(datetime, '/') > 1) {
+			datetime = nicos_datetime_2_iso(datetime);
+		}
+		else if (count_chars(datetime, '-') > 1) {
+			datetime = heidi_datetime_2_iso(datetime);
+		}
+	}
+	
+	return datetime;	
+}
+
+
+std::map<std::string, std::string> Frm2Retriever::extract_dictmulti(std::ifstream &file, std::vector<std::string> args, unsigned int nxtype) {
+	std::string values = "";
+	std::string value = "";
+	std::string units = "";
+	std::map<std::string, std::string> result;
+	
+	for (std::vector<std::string>::iterator it=args.begin(); it!=args.end();it++) {
+		std::map<std::string, std::string> raw_map = extract_dictentry(file, *it, nxtype);
+		value = raw_map["values"];
+		if (raw_map["units"] != "" && raw_map["units"] != "unknown") {
+			units = raw_map["units"];
+		}
+		values = values + value; 
+		if (it!=(args.begin()-1)) {
+			values = values + " ";
+		}
+	}	
+	result["values"] = values;
+	result["units"] = units;
+	reset_file(infile);
+	return result;	
+}
+
+
+// only for numeric arrays
+std::map<std::string, std::string> Frm2Retriever::extract_dictarray(std::ifstream &file, std::string arg, unsigned int nxtype) {
+	int i=0;
+	unsigned int k=0, l=0;
+	unsigned int pos=0, pos2=0;
+	bool newnum=false;
+	std::map<std::string, std::string> result;
+	std::string str="";
+	std::string units="";
+	std::string values="";
+
+	if (nxtype == NX_CHAR) {
+		return result;
+	}
+	
+	reset_file(infile);
+	while (infile.good()) {
+		std::string line = read_line(infile);
+		//std::cout << "current line: " << line << std::endl;	
+		
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+		
+		//std::cout << "to find: " << arg << " current line: " << line << std::endl;	
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			line = line.substr(pos+arg.size());
+			pos2 = line.find(":", pos);
+			if (pos2 != std::string::npos) {
+				
+				str = line.substr(pos2+1);
+				//std::cout << "found dict: " << str << std::endl;	
+				
+				while(k<str.size() && ((ispunct(str[k]) && str[k]!='+' && str[k]!='-' ) || isspace(str[k]))) {
+					k++;
+				}
+				str = str.substr(k);
+				
+				while (isspace(str[str.size()-1]) || ispunct(str[str.size()-1])){
+					str = str.substr(0, str.size()-1);
+				}
+				
+				while(l<str.size()) {
+					if (isdigit(str[l]) || ispunct(str[l]) || str[l]=='e' || str[l]=='E' || str[l]=='+' || str[l]=='-') {
+						if (str[l]=='e' || str[l]=='E') {
+							if (l>0) {
+								if (isdigit(str[l-1])){
+									if (newnum) {
+										values = values + " ";
+										newnum= false;
+									}
+									values = values+str[l];
+								}
+							}
+						}
+						/*else if (str[l]=='+' || str[l]=='-') {
+							if (l>0) {
+								if (str[l-1]=='e' || str[l-1]=='E'){
+									if (newnum) {
+										values = values + " ";
+										newnum= false;
+									}
+									values = values+str[l];
+								}
+							}
+						}*/
+						else {	
+							if (newnum) {
+								values = values + " ";
+								newnum= false;
+							}
+							values = values+str[l];
+						}
+					}
+					else {
+						if (units == "") {
+							while (isalpha(str[l])) {
+								units = units+str[l];
+								l++;
+							}
+						}
+						newnum = true;
+					}
+					l++;
+				}
+			}
+			break;
+		}
+	}
+	result["values"]=values;
+	result["units"]=units;
+	reset_file(infile);
+	return result;
+}
+
+
+std::vector<std::vector<unsigned int> > Frm2Retriever::extract_tofcts(std::ifstream &file, std::string arg, unsigned int nxtype, bool is_monitor) {
+	std::vector<std::vector<unsigned int> > result;
+	std::string line = "";
+	unsigned int pos=0;
+	int i=0, count=0;
+	int monitor_number=-1;
+	
+	std::map<std::string, std::string> raw_map = extract_dictentry(infile, "TOF_MonitorInput", NX_INT32);
+	std::string raw_minput = raw_map["values"];
+	std::string units= raw_map["units"];
+	
+	if (isNumber(raw_minput)) {
+		monitor_number = string_util::str_to_int(raw_minput);
+	}
+	
+	std::vector<unsigned int> dInfo = extract_desc(infile, "aData",NX_INT32);
+	
+	reset_file(infile);
+	while (infile.good()) {
+		line = read_line(infile);
+		
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+		
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			break;
+		}
+	}
+	while (infile.good()) {
+		line = read_line(infile);
+		if (is_monitor) {
+			if (count == monitor_number) {
+				std::vector<unsigned int> counts = string_util::split_uints(line);
+				result.push_back(counts);
+			}
+			count++;
+		}
+		else {
+			monitor_number = -1;
+			if (count != monitor_number) {
+				std::vector<unsigned int> counts = string_util::split_uints(line);
+				while (counts.size() < dInfo.at(1)) {
+					// add missing .. zeros
+					counts.push_back(0);
+				}
+				while (counts.size() > dInfo.at(1)) {
+					// cut superflouos
+					counts.pop_back();
+				}
+				if (result.size() < dInfo.at(0)) {
+					result.push_back(counts);
+				}
+			}
+			count++;
+		}
+	}
+	
+	// if some entrys are missing -> adapt
+	while (result.size() < dInfo.at(0)) {
+		// add empty vectors
+		std::vector<unsigned int> counts;
+		for (unsigned int i=0; i < dInfo.at(1); i++) {
+			counts.push_back(0);
+		}
+		result.push_back(counts);
+	}
+	
+	reset_file(infile);
+	return result;
+}
+
+
+std::vector<double> Frm2Retriever::extract_toftof(std::ifstream &file, std::string arg, unsigned int nxtype, bool is_monitor) {
+	std::vector<double> result;
+	std::string line = "";
+	unsigned int pos=0;
+	int i=0;
+	unsigned int channel_width = 1;
+	
+	std::vector<unsigned int> dInfo = extract_desc(infile, "aData",NX_INT32);
+
+	std::map<std::string, std::string> raw_map = extract_dictentry(infile, "TOF_ChannelWidth", NX_INT32);
+	std::string ch_width = raw_map["values"];
+	
+	if (isNumber(ch_width)) {
+		channel_width = string_util::str_to_int(ch_width);
+	}
+
+	
+	reset_file(infile);
+	while (infile.good()) {
+		line = read_line(infile);
+		
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			break;
+		}
+	}
+
+	if (infile.good()) {
+		line = read_line(infile);
+		std::vector<unsigned int> counts = string_util::split_uints(line);
+		while (counts.size() < dInfo.at(1)) {
+			// add missing .. zeros
+			counts.push_back(0);
+		}
+		while (counts.size() > dInfo.at(1)) {
+			// cut superflouos
+			counts.pop_back();
+		}
+
+		for (unsigned int i=0; i<counts.size(); i++) {
+			result.push_back((((double)i)+0.5)*channel_width*50);
+		}
+	}
+
+	reset_file(infile);
+	return result;
+}
+
+
+std::string Frm2Retriever::extract_filename(std::ifstream &file, std::string source, std::string arg, unsigned int nxtype) {
+	unsigned int pos=0;
+	unsigned int from=0, to=source.size();
+	std::string result="0";
+	
+	
+	pos = source.rfind("/");
+	if (pos != std::string::npos) {
+		result = source.substr(pos+1);
+		to = result.size();
+	}
+	pos = arg.find(":");
+	if (pos != std::string::npos) {
+		if (isNumber(arg.substr(0, pos)) && isNumber(arg.substr(pos+1))) {
+			from 	= string_util::str_to_int(arg.substr(0, pos));
+			to 	= string_util::str_to_int(arg.substr(pos+1)) - from;
+		}
+	}
+	result = result.substr(from, to);
+	return result;
+}
+
+
+std::vector<unsigned int> Frm2Retriever::extract_desc(std::ifstream &file, std::string arg, unsigned int nxtype) {
+	int i=0;
+	unsigned int pos=0;
+	std::string line="";
+	std::vector<unsigned int> result;
+	
+	reset_file(infile);
+	while (infile.good()) {
+		std::string line = read_line(infile);
+
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			pos = line.find(Frm2Retriever::METHOD_OPEN_BRACKET, pos);
+			if (pos != std::string::npos) {
+				line = line.substr(pos+1);
+				pos = line.find(Frm2Retriever::METHOD_CLOSE_BRACKET);
+				if (pos != std::string::npos) {
+					line = line.substr(0,pos);
+					result = string_util::split_uints(line);	
+				}
+			}
+			break;
+		}
+	}
+	reset_file(infile);
+	return result;
+}
+
+
+std::string Frm2Retriever::extract_logcpy(std::ifstream &file, std::string filename) {
+	char ch;
+	std::stringstream ss;
+	
+	reset_file(infile);
+   while( infile.get(ch)) {
+     ss << ch;
+	}
+	
+	reset_file(infile);
+	return ss.str();
+}
+
+
+std::vector<std::string> Frm2Retriever::extract_toflog(std::ifstream &file, std::string col_name, int from, int to) {
+	bool use_col_number=true;
+	int count = 0;
+	int index = 0;
+	std::vector<std::string> values;
+	int cur_line=0;
+	std::string line = ""; // read_line(infile);
+
+	reset_file(infile);
+	
+	skip_to_line(infile, cur_line, data_section+((from<0)?0:from)); 
+	
+	use_col_number = isNumber(col_name);
+	
+	if (!use_col_number) {
+		std::vector<std::string>::iterator it;
+		for (it = headers.begin(); it !=headers.end(); it++) {
+			if (*it != col_name)  {
+				index++;
+			}
+			else {
+				break;
+			}
+		}
+		if (it== headers.end()) {
+			std::cout << "no column '"<< col_name << "' found " << std::endl;
+			return values;
+		}
+	}
+	else {
+		index = string_util::str_to_int(col_name);
+		index--;
+	}
+	
+	line = read_line(infile);
+	while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+		if (!isdata(line)) {
+			break;
+		}
+		try {
+			std::vector<std::string> line_values = string_util::split_values(line);
+			/*for (std::vector<std::string>::iterator itt=values.begin(); itt!=values.end(); itt++) {
+				std::cout << "column------- vector: " << *itt << std::endl;
+			}*/
+			/*std::cout << endl << "pushing data: " << (string_util::str_to_float(string_values.at(index))) << std::endl;	
+			//double dbl_val = string_util::str_to_float(string_values.at(index));*/
+			values.push_back(line_values.at(index));
+		}
+		catch(...) {
+			cout << "exception in transforming column values " << endl;	
+		}
+		count++;
+		line = read_line(infile);
+	}
+		
+	reset_file(infile);
+	return values;
+}
+
+
+std::string Frm2Retriever::extract_line_below(std::ifstream &file, std::string arg, unsigned int nxtype) {
+	unsigned int pos=0;
+	std::string line="";
+	
+	reset_file(infile);
+	while (infile.good()) {
+		line = read_line(infile);
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			line = read_line(infile);
+			break;
+		}
+	}
+	reset_file(infile);
+	return line;
+}
+
+
+std::map<std::string,std::string > Frm2Retriever::extract_dictentry(std::ifstream &file, std::string arg, unsigned int nxtype) {
+	int i=0;
+	unsigned int k=0, l=0;
+	unsigned int pos=0, pos2=0;
+	bool newnum=false;
+	std::string str="";
+	
+	std::string units="";
+	std::string description="";
+	std::string values="";
+
+	std::map<std::string,std::string > result;
+	
+	reset_file(infile);
+	while (infile.good()) {
+		std::string line = read_line(infile);
+		//std::cout << "current line: " << line << std::endl;	
+	
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			line = line.substr(pos+arg.size());
+			//std::cout << "got line: " << 	line << std::endl;
+			/* extract description*/
+			description = line;
+			pos = description.find("-");
+			if (pos != std::string::npos) {
+				description = description.substr(pos+1);
+				pos=description.find(":");
+				if (pos != std::string::npos) {
+					description = description.substr(0, pos);			
+				}
+			}
+			else {
+				description ="";
+			}
+			while (isspace(description[0])){
+				description=description.substr(1);
+			}
+			while (isspace(description[description.size()-1])){
+				description = description.substr(0, description.size()-1);
+			}
+			result["description"] = description;
+			/*end description*/
+			
+			pos2 = line.find(":", pos);
+			if (pos2 != std::string::npos) {
+				str = line.substr(pos2+1);
+				
+				while(k<str.size() && (ispunct(str[k]) || isspace(str[k])) && (str[k]!='-') && (str[k]!='+')) {
+					k++;
+				}
+				str = str.substr(k);
+				
+				while(l<str.size()) {
+					if (nxtype == NX_CHAR) {
+						if (!isspace(str[l])) {
+							if (newnum) {
+								values = values + " ";
+								newnum= false;
+							}
+							values = values+str[l];
+						}
+						else {
+							if (units == "") {
+								while ( isalpha(str[l]) && !isspace(str[l])  ) {
+									units = units+str[l];
+									l++;
+								}
+							}
+							newnum = true;
+						}
+					}
+					else {
+						if (   (!isspace(str[l]) && !isalpha(str[l])) 
+							 || ( (l>0) && isdigit(str[l-1]) && ((str[l]=='e') || (str[l]=='E')) ) 
+							 || (str[l]=='-') || (str[l]=='+') ) {
+							if (newnum) {
+								//std::cout << "starting new word! " << std::endl;
+								values = values + " ";
+								newnum= false;
+							}
+							//std::cout << "appending: " << str[l] << std::endl;
+							values = values+str[l];
+						}
+						else {
+							if (units == "") {
+								while (isalpha(str[l]) && !isspace(str[l])) {
+									units = units+str[l];
+									l++;
+								}
+							}
+							newnum = true;
+						}
+					}
+					l++;
+				}
+			}
+			break;
+		}
+	}
+	result["values"]=values;
+	result["units"]=units;
+	reset_file(infile);
+	return result;
+}
+
+std::vector<std::string> Frm2Retriever::extract_column(ifstream &file, std::string col_name, int from, int to)
+{
+	bool use_col_number=true;
+	int count = 0;
+	int index = 0;
+	std::vector<std::string> values;
+	reset_file(infile);
+	int cur_line=0;
+	std::string line = ""; // read_line(infile);
+
+	//std::cout << "datasection starts at line: " << data_section << std::endl;
+	skip_to_line(infile, cur_line, data_section+((from<0)?0:from)); 
+	//cout << endl << "counting headers: " << *(headers.begin()) << endl;	
+	
+	use_col_number = isNumber(col_name);
+	
+	if (!use_col_number) {
+		std::vector<std::string>::iterator it = headers.begin();
+		while (*it != col_name && it != headers.end()) {
+			it++;
+			index++;
+		}
+		if (it== headers.end()) {
+			std::cout << "no column '"<< col_name << "' found " << std::endl;
+			/*while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+				if (!isdata(line)) {
+					break;
+				}
+				values.push_back("0");
+				count++;
+				line = read_line(infile);
+			}*/
+			return values;
+		}
+	}
+	else {
+		index = string_util::str_to_int(col_name);
+		index--;
+	}
+	
+
+//cout << endl << "pushing data.. [" << to << ","<< count<<"] error:"<< infile.good()<< endl;	
+	line = read_line(infile);
+	while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+		if (!isdata(line)) {
+			//std::cout << "NO DATA LINE:" << line << std::endl;
+			break;
+		}
+		try {
+			//std::cout << "transforming..." << std::endl;
+			std::vector<std::string> line_values = string_util::split_values(line);
+			/*for (std::vector<std::string>::iterator itt=line_values.begin(); itt!=line_values.end(); itt++) {
+				std::cout << "column------- vector: " << *itt << std::endl;
+			}*/
+			/*std::cout << endl << "pushing data: " << (string_util::str_to_float(string_values.at(index))) << std::endl;	
+			//double dbl_val = string_util::str_to_float(string_values.at(index));*/
+			values.push_back(line_values.at(index));
+		}
+		catch(...) {
+			cout << "exception in transforming column values " << endl;	
+		}
+		count++;
+		line = read_line(infile);
+	}
+	reset_file(infile);
+	return values;
+}
+
+
+std::vector<unsigned int> Frm2Retriever::extract_dnr(std::ifstream &file, std::string arg, unsigned int nxtype) {
+	std::vector<unsigned int> result;
+	std::string line = "";
+	unsigned int pos=0;
+	unsigned int i=0, count=0;
+	int monitor_number = -1;
+
+	std::map<std::string, std::string> raw_map = extract_dictentry(infile, "TOF_MonitorInput", NX_INT32);
+	std::string raw_minput = raw_map["values"];
+	
+	if (isNumber(raw_minput)) {
+		monitor_number= string_util::str_to_int(raw_minput);
+	}
+	
+	std::vector<unsigned int> dInfo = extract_desc(infile, "aData",NX_INT32);
+
+	reset_file(infile);
+	while (infile.good()) {
+		line = read_line(infile);
+		
+		// eliminate whitespace at start of line
+		while (isspace(line[0])){
+			line = line.substr(1);
+		}
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			break;
+		}
+	}
+	while (infile.good()) {
+		line = read_line(infile);
+		if (count != monitor_number) { 
+			if (result.size() < dInfo.at(1)) {
+				result.push_back(count);
+			}
+		}
+		count++;
+	}
+	
+	while (result.size() > dInfo.at(1)) {
+		result.pop_back();
+	}
+	
+	reset_file(infile);
+	return result;
+}
+
+std::string Frm2Retriever::extract_header(std::ifstream &file, std::string arg, unsigned int nxtype, unsigned int word, unsigned int wcount) {
+	int i=0, j=0;
+	unsigned int k=0, l=0, u1=0, u2=0;
+	unsigned int pos=0, pos2=0;
+	std::string str="";
+	std::string result="";
+
+	reset_file(infile);
+	if (arg[arg.size()-1]!='=') {
+		arg.append("=");
+	}
+	
+	//std::cout << "data_section: " << data_section << std::endl;
+	while (i<data_section) {
+		std::string line = read_line(infile);
+		pos = line.find(arg);
+		//std::cout << "line: " << line << std::endl;
+		//std::cout << "arg: " << arg << std::endl;
+		if (pos != std::string::npos) {
+			//got the right line in data_section !!
+			str = line.substr(pos+arg.size());
+			//std::cout << "getting val: " << str << std::endl;
+			
+			// scan for word ...
+			std::vector<std::string> words = string_util::split_whitespace(str);
+			
+			// special case for heidi Omat extends over 3 lines
+			if (arg.find("Omat")>=0) {
+				line = read_line(infile);
+				std::vector<std::string> words2 = string_util::split_whitespace(line);
+				for (unsigned int i=0; i< words2.size(); i++) {
+					words.push_back(words2.at(i)); 
+				}
+				line = read_line(infile);
+				std::vector<std::string> words3 = string_util::split_whitespace(line);
+				for (unsigned int i=0; i< words3.size(); i++) {
+					words.push_back(words3.at(i)); 
+				}
+			}
+			
+			//std::cout << "words: " << word << " wcount: " << wcount <<std::endl;
+			for (int j=word; j<word+wcount;j++) {
+				result.append(words[j]).append(" ");
+				//std::cout << "appending: " <<  words[j] <<std::endl;
+			}
+			break;
+		}
+		i++;
+	}
+	//std::cout << "extract_header returning: " << result << std::endl; //REMOVE
+	return result;
+}
+
+#ifdef _WIN32
+static double round(double x)
+{
+	if (x >= 0.0)
+	{
+		return (double)(long long)(x + 0.5);
+	}
+	else
+	{
+		return (double)(long long)(x - 0.5);
+	}
+}
+#endif
+
+std::vector<double> Frm2Retriever::extract_heidi_so(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int word, unsigned int wcount) {
+	const double dlim=1e-8;
+	int i=0, j=0;
+	double x, y;
+	double vl, wl;
+	double psi;
+	double xyz[3];
+  
+	double c;
+	
+	double schi0;
+	double cchi0;
+	double omg1;
+	double phi1;
+	double psr;
+	
+	double angle[5]; 
+	
+	std::vector<double> result;
+	
+	//unsigned int k=0, l=0, u1=0, u2=0;
+	//unsigned int pos=0, pos2=0;
+	//double omat[3][3]; 
+	//std::string str="";
+	//std::string result="";
+	
+	//reset_file(infile);
+	
+printf("extract the orientation matrix\n");	
+	// extract the orientation matrix
+	std::string omat_str = extract_header(file, "Omat", NX_FLOAT64, 0, 9);
+printf("orientation matrix extracted\n");	
+   std::vector<double> om = string_util::split_doubles(omat_str);	
+printf("vector of doubles created: \n%f%f%f\n%f%f%f\n%f%f%f\n\n", om[0], om[1],om[2],om[3],om[4],om[5],om[6],om[7],om[8]);	
+	
+	// extract wavelength
+	std::string wl_str = extract_header(file, "Wave", NX_FLOAT64, 0, 1);
+   wl = string_util::str_to_float(wl_str);	
+	
+	// extract the hkls 
+   std::string hkl_str = extract_data(file, entry_num, NX_INT32, 0, 0, 3);
+printf("hkls extracted:%s\n",hkl_str.c_str());	
+	std::vector<int> hkl = string_util::split_ints(hkl_str);	
+printf("hkls extracted:%d %d %d\n",hkl[0], hkl[1], hkl[2]);	
+	
+	// extract psi
+	std::string psi_str = extract_data(file, entry_num, NX_FLOAT64, 0, 6, 1); 
+printf("psi extracted:%s\n",psi_str.c_str());	
+	psi = (double)atoi(psi_str.c_str());
+
+	// calculate vector length
+	//vl=sqrt(pow(xyz[0], 2)+pow(xyz[1], 2)+pow(xyz[2], 2));
+
+
+  // calculate direction vectors
+  for (i=0; i<3; ++i)
+  {
+    xyz[i]=0.0;
+    for (j=0; j<3; ++j)
+      xyz[i]+=om[(i*3)+j]*hkl[j];
+  }
+
+  // calculate scalar product
+  c=0.0;
+  for (i=0; i<3; ++i) {
+    c+=xyz[i]*xyz[i];
+  }
+  
+  vl=sqrt(c);
+
+  if (vl<dlim)
+    vl=1.0;
+
+  for (i=0; i<3; ++i) {
+    xyz[i]/=vl;
+  }
+
+  x       =xyz[0];
+  y       =xyz[1];
+  schi0   =xyz[2];
+
+  //printf("vl:%f, xyz: %f %f %f, psi:%f\n", vl, xyz[0], xyz[1], xyz[2]);
+  printf("vl:%f, xyz: %f %f %f\n", vl, xyz[0], xyz[1], xyz[2]);
+  angle[2]=arsin(0.5*vl*wl);
+  angle[1]=2.0*angle[2];
+  angle[3]=arsin(schi0);
+  angle[4]=0;
+
+  if ((x*x+y*y)>0) {
+    angle[4]=atan2(-y, x);
+  }
+
+  // psi rotation
+  if (psi!=0)
+  {
+    psr=psi*1.74532925199e-2;
+    cchi0=cos(angle[3]);
+
+    // chi0=0
+    if (fabs(angle[3])==0)
+    {
+      omg1=90.0*1.74532925199e-2;
+      angle[3]=psr+angle[3];
+      phi1=sgn(omg1);
+    }
+    else
+    {
+      if (fabs(cchi0)==0)
+      {
+        omg1=0.0;
+        phi1=psr*sgn(-angle[3]);
+      }
+      else
+      {
+        omg1=atan(sin(psr)*cchi0/schi0);
+        x=cos(omg1);
+        angle[3]=atan2(schi0/x, cchi0*cos(psr));
+        phi1=atan2(-sin(omg1)/cchi0, x*cos(angle[3])/cchi0);
+      }
+    }
+    angle[2]-=omg1;
+    angle[4]-=phi1;
+  }
+
+  for (i=1; i<5; ++i) {
+    angle[i]*=57.2957795130;
+  }
+  x=angle[3];
+
+  if (fabs(x)>180) {
+    angle[3]=x-sgn(360-x);
+  }
+
+  angle[4]+=round(-angle[4]/360)*360.0;
+  if (/*(lphi==0) &&*/ (angle[4]<0)) {
+      angle[4]=angle[4]+360.0;
+  }
+
+  result.push_back(angle[0]);
+  result.push_back(angle[1]);
+  result.push_back(angle[2]);
+  result.push_back(angle[3]);
+	// now we hopefully got the orientation matrix
+   // re-calculate angles, omega, chi and phi  now ...
+   // convert strings to floats
+	// do matrix calculations (inverse from dif4)
+	
+	//std::cout << "extract_header returning: " << result << std::endl; //REMOVE
+	
+	/*while (i<data_section) {
+		std::string line = read_line(infile);
+		pos = line.find(arg);
+		//std::cout << "line: " << line << std::endl;
+		//std::cout << "arg: " << arg << std::endl;
+		if (pos != std::string::npos) {
+			//got the right line in data_section !!
+			str = line.substr(pos+arg.size());
+			//std::cout << "getting val: " << str << std::endl;
+			
+			// scan for word ...
+			std::vector<std::string> words = string_util::split_whitespace(str);
+			for (unsigned int i=0; i< words.size(); i++) {
+				omat[0][i] = string_util::str_to_float(words.at(i));	
+			}
+			
+			// special case for heidi Omat extends over 3 lines
+			if (arg.find("Omat")>=0) {
+				line = read_line(infile);
+				std::vector<std::string> words2 = string_util::split_whitespace(line);
+				for (unsigned int i=0; i< words2.size(); i++) {
+					words.push_back(words2.at(i)); 
+					omat[1][i] = string_util::str_to_float(words2.at(i));	
+			   }		
+				line = read_line(infile);
+				std::vector<std::string> words3 = string_util::split_whitespace(line);
+				for (unsigned int i=0; i< words3.size(); i++) {
+					words.push_back(words3.at(i)); 
+					omat[2][i] = string_util::str_to_float(words2.at(i));	
+				}
+			}
+			
+			//std::cout << "words: " << word << " wcount: " << wcount <<std::endl;
+			for (int j=word; j<word+wcount;j++) {
+				result.append(words[j]).append(" ");
+				//std::cout << "appending: " <<  words[j] <<std::endl;
+			}
+			break;
+		}
+		i++;
+	 }*/
+   
+	return result;
+}
+
+
+std::vector<double> Frm2Retriever::extract_heidi_counts(ifstream &file, int entry_num, bool monitor_counts)
+{
+	int count = 0;
+	int index = 0;
+	std::vector<double> values;
+	reset_file(infile);
+	int cur_line=0;
+	skip_to_line(infile, cur_line, data_section); 
+// strategy: find datasection -> skip 3*entry_num lines -> read 8 param of first line -> 
+// n = number of scans -> read n 
+	std::string line = read_line(infile);
+	std::vector<std::string> words = string_util::split_whitespace(line);
+	int nitems = 1;
+	int nlines = 0;
+	if (isNumber(words.at(7))) {
+		nitems =string_util::str_to_int(words.at(7));
+		nlines = (int)ceil(((double)(nitems*2))/Frm2Retriever::HEIDI_COLS_PER_LINE);
+	}
+
+	if (entry_num>0) {
+		for (unsigned int i=0; i<((entry_num*(nlines+2))-1); i++) {
+			read_line(infile);
+		}
+		line = read_line(infile);
+	}
+	//std::cout << "line: " << line << std::endl;
+	words = string_util::split_whitespace(line);
+			
+	//std::cout << "words: " << word << " wcount: " << wcount <<std::endl;
+	int numcounts = 0;
+	if (isNumber(words[7])) {
+		numcounts = string_util::str_to_int(words[7]);
+	}
+	else {
+		std::ios::pos_type fpos = infile.tellg();
+		line = read_line(infile);
+		line = read_line(infile);
+		numcounts = line.size() / (Frm2Retriever::HEIDI_CHARS_PER_COUNT*2);
+		infile.seekg(fpos);
+	}
+	line = read_line(infile);
+	
+	//std::cout << "CURRENT LINE: " << line << std::endl;
+	char count_str[Frm2Retriever::HEIDI_CHARS_PER_COUNT+1];
+	if (monitor_counts) {
+		int num_line_breaks = (int)floor(((double)numcounts)/((double)Frm2Retriever::HEIDI_COLS_PER_LINE));
+		infile.seekg(((Frm2Retriever::HEIDI_CHARS_PER_COUNT*numcounts)+num_line_breaks), std::ios_base::cur);
+	}
+	for (int i=0; i<numcounts; i++) {
+		for (int j=0; j<Frm2Retriever::HEIDI_CHARS_PER_COUNT;j++) { 
+			count_str[j] = read_char(infile);
+			if (count_str[j] == '\n') {
+				count_str[j] = read_char(infile);
+			}
+		}
+		count_str[Frm2Retriever::HEIDI_CHARS_PER_COUNT]='\0';
+		//std::cout << "pushing back: " << std::string(count_str) << std::endl;
+		values.push_back(string_util::str_to_float(std::string(count_str)));
+		//std::cout << "pushing back: " << string_util::str_to_float(std::string(count_str)) << std::endl;
+	}
+	
+//cout << endl << "counting headers: " << *(headers.begin()) << endl;	
+
+	/*std::vector<std::string>::iterator it = headers.begin();
+	while (*it != col_name && it != headers.end()) {
+		it++;
+		index++;
+	}
+
+	std::string line = read_line(infile);
+
+	if (it== headers.end()) {
+		std::cout << "no column '"<< col_name << "' found in file ... filling with 0s" << std::endl;
+		while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+			if (!isdata(line)) {
+				break;
+			}
+			values.push_back(0);
+			count++;
+			line = read_line(infile);
+		}
+		return values;
+	}
+
+//cout << endl << "pushing data: " << to << " "<< count<<" "<< infile.good()<< endl;	
+	while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+		if (!isdata(line)) {
+			break;
+		}
+		try {
+			std::vector<std::string> string_values = string_util::split_values(line);
+	//cout << endl << "pushing data: " << (string_util::str_to_float(string_values.at(index))) << endl;	
+			double dbl_val = string_util::str_to_float(string_values.at(index));
+			values.push_back(dbl_val);
+		}
+		catch(...) {
+			cout << "exception in transforming column values " << endl;	
+					
+		}
+		count++;
+		line = read_line(infile);
+	}*/
+	return values;
+}
+
+std::string Frm2Retriever::extract_data(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int lineno, unsigned int word, unsigned int wcount)
+{
+	int cur_line=0;
+	std::string result="";
+
+	std::string line;
+
+	reset_file(infile);
+	skip_to_line(infile, cur_line, data_section);
+
+	line = read_line(infile);
+	std::vector<std::string> words = string_util::split_whitespace(line);
+	int nitems = 1;
+	int nlines = 0;
+	if (isNumber(words.at(7))) {
+		nitems =string_util::str_to_int(words.at(7));
+		nlines = (int)ceil(((double)(nitems*2))/Frm2Retriever::HEIDI_COLS_PER_LINE);
+	}
+	//std::cout << "nlines: " << nlines << std::endl;
+	if (entry_num > 0) {
+		for (unsigned int i=0; i<((entry_num*(nlines+2))+lineno)-1; i++) {
+			read_line(infile);
+		}
+		line = read_line(infile);
+	}
+	//std::cout << "XD line: " << line << "lineno: " << lineno<< std::endl;
+	words = string_util::split_whitespace(line);
+	/*for (unsigned int i =0; i< words.size(); i++) {
+		std::cout << "words["<<i<<"]: " << words[i] << std::endl;
+	}*/
+	//std::cout << "XD words: " << word << " wcount: " << wcount <<std::endl;
+	for (int j=word; j<word+wcount;j++) {
+		result.append(words[j]).append(" ");
+		//std::cout << "XD appending: " <<  words[j] <<std::endl;
+	}
+	//std::cout << "XD result: " << result<< std::endl;
+	return result;
+}
+
+
+std::string Frm2Retriever::extract_heidiids(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int lineno, unsigned int word)
+{
+	int cur_line=0;
+	std::string result="";
+
+	std::string line;
+
+	reset_file(infile);
+	skip_to_line(infile, cur_line, data_section);
+
+	line = read_line(infile);
+	std::vector<std::string> words = string_util::split_whitespace(line);
+	int nitems = 1;
+	int nlines = 0;
+	if (isNumber(words.at(7))) {
+		nitems =string_util::str_to_int(words.at(7));
+		nlines = (int)ceil(((double)(nitems*2))/Frm2Retriever::HEIDI_COLS_PER_LINE);
+	}
+	//std::cout << "nlines: " << nlines << std::endl;
+	if (entry_num > 0) {
+		for (unsigned int i=0; i<((entry_num*(nlines+2))+lineno)-1; i++) {
+			read_line(infile);
+		}
+		line = read_line(infile);
+	}
+	//std::cout << "XD line: " << line << "lineno: " << lineno<< std::endl;
+	words = string_util::split_whitespace(line);
+	/*for (unsigned int i =0; i< words.size(); i++) {
+		std::cout << "words["<<i<<"]: " << words[i] << std::endl;
+	}*/
+	//std::cout << "XD words: " << word << " wcount: " << wcount <<std::endl;
+	
+	result.append(std::string(1,words[word][0])).append(" ");
+	result.append(std::string(1,words[word][1]));
+		//std::cout << "XD appending: " <<  words[j] <<std::endl;
+	//std::cout << "XD result: " << result<< std::endl;
+	return result;
+}
+
+
+std::string Frm2Retriever::extract_heidi_omg(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int word, unsigned int wcount)
+{	
+	int ncts=0;
+	double domg=0.0;
+	std::string result="";
+	std::string line;
+	
+   line =  extract_data(file, entry_num, nxtype, 0, 7, 1);
+	if (isNumber(line)) {
+		strip(line);
+		ncts = string_util::str_to_int(line);
+	}
+	line = extract_header(file, "Scan", nxtype, 0, 1);
+	domg = string_util::str_to_float(line); 
+	
+	for (int i=0; i<ncts; i++) {
+   	std::stringstream ss;
+		ss << domg*((double)(i+1));
+		printf("ss.str(): %s\n", ss.str().c_str());
+		result.append(ss.str());
+		if (i<(ncts-1)) {
+			result.append(" ");
+		}
+	}
+	return result;
+}
+
+
+int Frm2Retriever::number_of_columns(std::string header_line) {
+	std::vector<std::string> entrys = string_util::split_whitespace(header_line);
+	entrys = string_util::strip_punct(entrys);
+	return entrys.size();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+ 
+Frm2Retriever::Frm2Retriever(const string &str): source(str),current_line(0){
+  //cout << "Frm2Retriever(" << source << ")" << endl; // REMOVE
+
+  // open the file
+  infile.open(source.c_str());
+
+  // check that open was successful
+  if(! infile.is_open()) {
+    //throw invalid_argument("Could not open file: "+source);
+	 return;
+  }
+	
+	initUnits();
+
+	this->number_of_cols = 0;
+	this->number_of_entrys = 0;
+	
+	int cur_line = 0;
+	std::string line; /* = read_line(infile);*/
+	std::string prev1_line="";
+	std::string prev2_line="";
+	std::string prev3_line="";
+	std::string prev4_line="";
+	
+ 	//std::cout << "current line: " << line << std::endl;
+	while (infile.good())  {
+		line = read_line(infile);
+		//std::cout << "current line: " << line << std::endl;
+		//std::cout << "prev1_line: " << prev1_line << std::endl;
+		//std::cout << "prev2_line: " << prev2_line << std::endl;
+		if(isdata(line) && isdata(prev1_line) && isdata(prev2_line)) {
+			break;
+		}
+		prev4_line = prev3_line;
+		prev3_line = prev2_line;
+		prev2_line = prev1_line;
+		prev1_line=line;
+		cur_line++;
+	}
+
+	//std::cout << "data line: " << line << "  isdata?: " << !isdata(line) << "   isfileok?: " << infile.good()<< std::endl;
+	header_section = cur_line-3;
+	// this is dangerous as it assumes the unit line to be present and always under the header line
+	// alternative: check if in header line is some occurence of unit string -> treat is as unit line
+	if (isunit(prev3_line)) {
+//std::cout << "extracting units from: " << prev_line << std::endl;
+		extract_units(prev3_line);
+//std::cout << "extracting headers from: " << prev_prev_line << std::endl;
+		extract_headers(prev4_line);
+	}
+	else {
+		extract_headers(prev3_line);
+	}
+
+	data_section = cur_line-2;
+	// check if we have a tof file ...
+	reset_file(infile);
+	cur_line=0;
+	while (infile.good()) {
+		line = read_line(infile);
+		int pos = line.find("aDetInfo");
+		if (pos != std::string::npos) {
+			//std::cout << "seems that we got a tof file" << std::endl;
+			data_section = cur_line+3;
+			read_line(infile);
+			extract_headers(read_line(infile));
+			break;
+		}
+		cur_line++;
+	}
+
+	
+	// check if we have a heidi file ...
+	reset_file(infile);
+	cur_line=0;
+	std::string lastheader = "Omat";  	
+	while (infile.good()) {
+		line = read_line(infile);
+		if (string_util::contains(line, lastheader)) {
+			data_section = cur_line+3;
+			break;
+		}
+		cur_line++;
+	}
+
+	//std::cout << "data_section: " << data_section << std::endl;
+
+	// check if we have a tof continous log file ...
+	reset_file(infile);
+	cur_line=0;
+	int pos = str.find("_");
+	if (pos!=std::string::npos) {
+		if (str[pos+1] == '5') {
+			if (str[pos+2] == '0') {
+				//std::cout << "seems that we got a tof log file " << data_section << std::endl;
+				extract_toflogheaders(infile);
+			}
+		}
+	}
+	reset_file(infile);
+	
+	
+	/*for (std::vector<std::string>::iterator it=headers.begin(); it!= headers.end(); it++) {
+		std::cout << "headers: " << *it << std::endl;
+	}*/
+	
+	/*int num_of_cols, num_of_cols2, num_of_cols3;
+	//std::cout << "compare data line 1: " << line << std::endl;
+	num_of_cols = number_of_columns(line);
+	if (isdata(line)) {
+		line = read_line(infile);
+	//std::cout << "compare data line 2: " << line << std::endl;
+		num_of_cols2 = number_of_columns(line);
+		if (isdata(line)) {
+			line = read_line(infile);
+	//std::cout << "compare data line 3: " << line << std::endl;
+			num_of_cols3 = number_of_columns(line);
+		}
+	}
+	if ((num_of_cols == num_of_cols2) && (num_of_cols == num_of_cols3)) {
+		number_of_cols = num_of_cols;
+		number_of_headers = std::min(number_of_cols, number_of_headers); 
+		number_of_cols = std::min(number_of_cols, number_of_headers);
+	}
+	else {
+  		//cout << "numbers of cols: " << num_of_cols <<" "<< num_of_cols2 <<" "<< num_of_cols3 << endl; 
+		printf("ERROR: number of columns must remain constant. check your ASCII file\n");
+	}*/
+
+}
+
+
+Frm2Retriever::~Frm2Retriever(){
+  //cout << "~Frm2Retriever()" << endl;
+
+  // close the file
+  if(infile)
+    infile.close();
+}
+
+
+
+
+Node* Frm2Retriever::createEmptyNode(std::string nodename, unsigned int nxtype) {
+	/*int* empty_dims = new int[1];
+	empty_dims[0] = 1;
+	void *data;
+	
+	if(NXmalloc(&data, 1, empty_dims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+	*((int*)data)=0;
+	return (new Node(nodename, data, 1, empty_dims, nxtype));*/
+	return NULL;
+}
+
+
+Node* Frm2Retriever::createNode(std::string nodename, std::vector<unsigned int> values, unsigned int nxtype) {
+	int nxrank = 1;
+	int* nxdims = new int[1];
+	nxdims[0] = values.size();
+
+	// allocate space for the data
+	void *data;
+	if(NXmalloc(&data, nxrank, nxdims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+
+	for( unsigned int i=0 ; i<values.size() ; i++ ) {
+		switch (nxtype) {
+			case NX_INT32: 
+				*(((int*)data)+i)=static_cast<int>(values.at(i));
+				break;
+			case NX_UINT32: 
+				*(((unsigned int*)data)+i)=static_cast<unsigned int>(values.at(i));
+				break;
+			case NX_INT16: 
+				*(((short*)data)+i)=static_cast<short>(values.at(i));
+				break;
+			case NX_UINT16: 
+				*(((unsigned short*)data)+i)=static_cast<unsigned short>(values.at(i));
+				break;
+			case NX_INT8: 
+				*(((char*)data)+i)=static_cast<char>(values.at(i));
+				break;
+			case NX_UINT8: 
+				*(((unsigned char*)data)+i)=static_cast<unsigned char>(values.at(i));
+				break;
+		}	
+	}
+	return (new Node("empty", data, nxrank, nxdims, nxtype));
+	
+}
+
+Node* Frm2Retriever::createNode(std::string nodename, std::vector<double> values, unsigned int nxtype, std::string units, std::vector<unsigned int> dims) {
+	int nxrank = 1;
+	int* nxdims = new int[1];
+	nxdims[0] = values.size();
+
+
+	if (dims.size()>0) {
+		nxrank = dims.size();
+		nxdims = new int[nxrank];
+		for (unsigned int i=0; i<dims.size();i++) {
+			nxdims[i] = dims.at(i);  
+		}
+	}
+
+	// allocate space for the data
+	void *data;
+	if(NXmalloc(&data, nxrank, nxdims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+
+	for( unsigned int i=0 ; i<values.size() ; i++ ) {
+		switch (nxtype) {
+			case NX_INT32: 
+				*(((int*)data)+i)=static_cast<int>(values.at(i));
+				break;
+			case NX_UINT32: 
+				*(((unsigned int*)data)+i)=static_cast<unsigned int>(values.at(i));
+				break;
+			case NX_INT16: 
+				*(((short*)data)+i)=static_cast<short>(values.at(i));
+				break;
+			case NX_UINT16: 
+				*(((unsigned short*)data)+i)=static_cast<unsigned short>(values.at(i));
+				break;
+			case NX_INT8: 
+				*(((char*)data)+i)=static_cast<char>(values.at(i));
+				break;
+			case NX_UINT8: 
+				*(((unsigned char*)data)+i)=static_cast<unsigned char>(values.at(i));
+				break;
+			case NX_FLOAT64:
+				*(((double*)data)+i)=static_cast<double>(values.at(i));
+				break;
+			case NX_FLOAT32:
+				*(((float*)data)+i)=static_cast<float>(values.at(i));
+				break;
+		}	
+	}
+	Node* node = new Node("empty", data, nxrank, nxdims, nxtype);
+	if (units!="" && nxtype != NX_CHAR) {
+		std::vector<Attr> attrs;
+		Attr attr("units", units.c_str(), units.size(), NX_CHAR);
+		attrs.push_back(attr);
+		node->update_attrs(attrs);
+	}
+	return node;
+}
+
+
+Node* Frm2Retriever::createNode(std::string nodename, std::string value, unsigned int nxtype, std::string units) {
+	int nxrank = 1;
+	int* nxdims = new int[1];
+	if (nxtype == NX_CHAR || nxtype==NX_BINARY) {
+		nxdims[0] = value.size();
+	}
+	else {
+		nxdims[0] = 1;
+	}
+
+	// allocate space for the data
+	void *data;
+	if(NXmalloc(&data, nxrank, nxdims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+	
+	switch (nxtype) {
+		case NX_CHAR:
+			data = (char*)value.c_str();
+			//nxdims[0] = value.size();
+			break;
+		case NX_INT32: 
+			*((int*)data) = static_cast<int>(string_util::str_to_int(value.c_str()));
+			break;
+		case NX_UINT32: 
+			*((unsigned int*)data) = static_cast<unsigned int>(string_util::str_to_int(value.c_str()));
+			break;
+		case NX_INT16: 
+			*((short*)data) = static_cast<short>(string_util::str_to_int(value.c_str()));
+			break;
+		case NX_UINT16: 
+			*((unsigned short*)data) = static_cast<unsigned short>(string_util::str_to_int(value.c_str()));
+			break;
+		case NX_INT8: 
+			*((char*)data) = static_cast<char>(string_util::str_to_int(value.c_str()));
+			break;
+		case NX_UINT8:
+                        data = const_cast<char*>(value.c_str());
+			//nxdims[0] = value.size();
+			//*((unsigned char*)data) = static_cast<unsigned char>(string_util::str_to_int(value.c_str()));
+			break;
+		case NX_FLOAT64:
+			*((double*)data) = static_cast<double>(string_util::str_to_float(value.c_str()));
+			break;
+		case NX_FLOAT32:
+			*((float*)data) = static_cast<float>(string_util::str_to_float(value.c_str()));
+			break;
+	}
+
+	// create a data node
+	Node* node = new Node("empty", data, nxrank, nxdims, nxtype);
+	if (units!="" && nxtype != NX_CHAR) {
+		std::vector<Attr> attrs;
+		Attr attr("units", units.c_str(), units.size(), NX_CHAR);
+		attrs.push_back(attr);
+		node->update_attrs(attrs);
+	}
+	return node;
+}
+
+Node* Frm2Retriever::createNode(std::string nodename, std::vector<std::vector<double> >values, unsigned int nxtype) {
+	int nxrank = 2;
+	int* nxdims = new int[2];
+	nxdims[0] = values.size();
+	nxdims[1] = values.at(0).size();
+
+	// allocate space for the data
+	void *data;
+	if(NXmalloc(&data, nxrank, nxdims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+
+	for( unsigned int i=0 ; i<values.size() ; i++ ) {
+		for( unsigned int j=0 ; j<values.at(i).size() ; j++ ) {
+			
+			switch (nxtype) {
+				case NX_INT32: 
+					*(((int*)data)+(i*nxdims[1]+j))=static_cast<int>(values.at(i).at(j));
+					break;
+				case NX_UINT32: 
+					*(((unsigned int*)data)+(i*nxdims[1]+j))=static_cast<unsigned int>(values.at(i).at(j));
+					break;
+				case NX_INT16: 
+					*(((short*)data)+(i*nxdims[1]+j))=static_cast<short>(values.at(i).at(j));
+					break;
+				case NX_UINT16: 
+					*(((unsigned short*)data)+(i*nxdims[1]+j))=static_cast<unsigned short>(values.at(i).at(j));
+					break;
+				case NX_INT8: 
+					*(((char*)data)+(i*nxdims[1]+j))=static_cast<char>(values.at(i).at(j));
+					break;
+				case NX_UINT8: 
+					*(((unsigned char*)data)+(i*nxdims[1]+j))=static_cast<unsigned char>(values.at(i).at(j));
+					break;
+				case NX_FLOAT64:
+					*(((double*)data)+(i*nxdims[1]+j))=static_cast<double>(values.at(i).at(j));
+					break;
+				case NX_FLOAT32:
+					*(((float*)data)+(i*nxdims[1]+j))=static_cast<float>(values.at(i).at(j));
+					break;
+			}	
+		}
+	}
+	return (new Node("empty", data, nxrank, nxdims, nxtype));
+}
+Node* Frm2Retriever::createNode(std::string nodename, std::vector<std::vector<unsigned int> >values, unsigned int nxtype) {
+	int nxrank = 2;
+	int* nxdims = new int[2];
+	nxdims[0] = values.size();
+	nxdims[1] = values.at(0).size();
+
+	// allocate space for the data
+	void *data;
+	if(NXmalloc(&data, nxrank, nxdims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+
+	for( unsigned int i=0 ; i<values.size() ; i++ ) {
+		for( unsigned int j=0 ; j<values.at(i).size() ; j++ ) {
+			
+			switch (nxtype) {
+				case NX_INT32: 
+					*(((int*)data)+(i*nxdims[1]+j))=static_cast<int>(values.at(i).at(j));
+					break;
+				case NX_UINT32: 
+					*(((unsigned int*)data)+(i*nxdims[1]+j))=static_cast<unsigned int>(values.at(i).at(j));
+					break;
+				case NX_INT16: 
+					*(((short*)data)+(i*nxdims[1]+j))=static_cast<short>(values.at(i).at(j));
+					break;
+				case NX_UINT16: 
+					*(((unsigned short*)data)+(i*nxdims[1]+j))=static_cast<unsigned short>(values.at(i).at(j));
+					break;
+				case NX_INT8: 
+					*(((char*)data)+(i*nxdims[1]+j))=static_cast<char>(values.at(i).at(j));
+					break;
+				case NX_UINT8: 
+					*(((unsigned char*)data)+(i*nxdims[1]+j))=static_cast<unsigned char>(values.at(i).at(j));
+					break;
+			}	
+		}
+	}
+	return (new Node("empty", data, nxrank, nxdims, nxtype));
+}
+
+
+Node* Frm2Retriever::createNode(std::string nodename, std::vector<std::string> values, unsigned int nxtype, std::string units) {
+	int nxrank = 1;
+	int* nxdims = new int[1];
+	nxdims[0] = values.size();
+	
+	std::string cvalues="";
+	if (nxtype== NX_CHAR) {
+		for( unsigned int i=0 ; i<values.size() ; i++ ) {
+			cvalues.append(values.at(i));
+			if (i!= values.size()-1) {
+				cvalues.append(",");
+			}
+		}
+	}
+	// allocate space for the data
+	void *data;
+	if(NXmalloc(&data, nxrank, nxdims, nxtype)!=NX_OK) {
+		throw runtime_error("NXmalloc failed");
+	}
+	
+	for( unsigned int i=0 ; i<values.size() ; i++ ) {
+		switch (nxtype) {
+			case NX_CHAR:
+				data = (char*)cvalues.c_str();
+				nxdims[0] = cvalues.size();
+				break;
+			case NX_INT32: 
+				*(((int*)data)+i) = static_cast<int>(string_util::str_to_int(values.at(i)));
+				break;
+			case NX_UINT32: 
+				*(((unsigned int*)data)+i) = static_cast<unsigned int>(string_util::str_to_int(values.at(i)));
+				break;
+			case NX_INT16: 
+				*(((short*)data)+i) = static_cast<short>(string_util::str_to_int(values.at(i)));
+				break;
+			case NX_UINT16: 
+				*(((unsigned short*)data)+i) = static_cast<unsigned short>(string_util::str_to_int(values.at(i)));
+				break;
+			case NX_INT8: 
+				*(((char*)data)+i) = static_cast<char>(string_util::str_to_int(values.at(i)));
+				break;
+			case NX_UINT8: 
+				*(((unsigned char*)data)+i) = static_cast<unsigned char>(string_util::str_to_int(values.at(i)));
+				break;
+			case NX_FLOAT32:
+				{
+				float ft = static_cast<float>(string_util::str_to_float(values.at(i)));
+				//std::cout << std::setprecision(9);
+				//std::cout << "string: "<< values.at(i) << "logged float: " << string_util::str_to_float(values.at(i)) << "  " << ft << std::endl;
+				*(((float*)data)+i) = static_cast<float>(string_util::str_to_float(values.at(i)));
+				}
+				break;
+			case NX_FLOAT64:
+				*(((double*)data)+i) = static_cast<double>(string_util::str_to_float(values.at(i)));
+				break;
+		}
+	}
+
+	// create a data node
+	Node* node = new Node("empty", data, nxrank, nxdims, nxtype);
+	if (units!="" && nxtype != NX_CHAR) {
+		std::vector<Attr> attrs;
+		Attr attr("units", units.c_str(), units.size(), NX_CHAR);
+		attrs.push_back(attr);
+		node->update_attrs(attrs);
+	}
+	return node;
+}
+
+
+/**
+ * This is the method for retrieving data from a file. The whole
+ * tree will be written to the new file immediately after being
+ * called. Interpreting the string is left up to the implementing
+ * code.
+ */
+void Frm2Retriever::getData(const string &location, tree<Node> &tr){
+	cout << "Frm2Retriever::getData(" << location << ",tree)" << endl; // REMOVE
+	// check that the argument is not an empty string
+	//printf("extracting...%s", location.c_str()); 
+	if(!infile) {
+		//std::cout << "infile not valid returning: " << infile << std::endl;
+		return;
+	}
+	if(location.size()<=0) {
+		throw invalid_argument("cannot parse empty string");
+	}
+
+	// so far ... all locations must refer to a column name 
+	std::string arg = "";
+	std::string method 	= parse_method(location);
+	std::vector<std::string> args	= parse_arg(location);
+	
+	std::string nxtype;
+	//nxtype 	= parse_type(location);
+
+	std::vector<unsigned int> vdims;
+	vdims = parse_type_dims(location, nxtype);
+	
+	if (args.size() ==1 ) {
+		arg = args[0];
+	}
+	if (nxtype == "") {
+		// default type is NX_FLOAT64
+		nxtype = "NX_FLOAT64";
+	}
+	
+	// get range bounds if specified 
+	int from, to;
+	parse_range(location, from, to); 
+
+	//start: this is heidi only stuff
+	int line, word, wcount;
+	parse_heidi_range(location, line, word, wcount); 
+	wcount++; 	
+	
+	int heidi_entry_num = 0;
+	if (args.size()>0) {
+		if (isNumber(args.at(0))) {
+			heidi_entry_num = string_util::str_to_int(args.at(0));
+		}
+	}
+	//end: this is heidi only stuff
+	
+	//cout << "location: " << method << "(\'" << arg << "\')" << "[" << from << "," << to << "]{" << nxtype <<"}" << "[" << word << "," << wcount << "]" << endl << endl;	
+ 	Node* node;
+	
+	if (method == Frm2Retriever::COLUMN_TAG) { 
+		std::vector<std::string> values = extract_column(infile, arg, from, to);
+  		if (values.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			int unit_pos=0;
+			std::string unit="";
+			std::vector<std::string>::iterator it = headers.begin();
+			while (*it != arg && it != headers.end()) {
+				it++;
+				unit_pos++;
+			}
+			if (it!= headers.end()) {
+				if (units.size()>unit_pos) {
+					if (unit_strings.find(string_util::lower_str(units.at(unit_pos)))!=unit_strings.end()) {
+						unit = unit_strings[units.at(unit_pos)];
+					}
+					else {
+						unit = units.at(unit_pos);
+					}
+				}
+			}
+			//std::cout << endl << "pushing data: " << (string_util::str_to_float(string_values.at(index))) << std::endl;	
+			//double dbl_val = string_util::str_to_float(string_values.at(index));
+			//values.push_back(dbl_val);
+			
+			/*for (std::vector<std::string>::iterator itt=values.begin(); itt!=values.end(); itt++) {
+				std::cout << "column------- vector: " << *itt << std::endl;
+			}*/
+			node = createNode("empty", values, convert_type(nxtype), unit);
+			
+		}
+	}
+	else if (method == Frm2Retriever::DICT_TAG) { 
+		std::map<std::string, std::string> raw_map = extract_dictentry(infile, arg, convert_type(nxtype));
+		std::string raw_string=raw_map["values"];
+		std::string units=raw_map["units"];
+		std::string description=raw_map["description"];
+		
+		if (unit_strings.find(string_util::lower_str(units))!=unit_strings.end()) {
+			units = unit_strings[units];
+		}
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			if (convert_type(nxtype) == NX_CHAR) {
+				if (nxtype == "ISO8601") {
+					// check if its in heidi form
+					if (count_chars(raw_string, '.') > 1) {
+						raw_string = toftof_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '/') > 1) {
+						raw_string = nicos_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '-') > 1) {
+						raw_string = heidi_datetime_2_iso(raw_string);
+					}
+				}
+				node = createNode("empty", raw_string, convert_type(nxtype), units);
+			}
+			else {
+				std::vector<double> values = string_util::split_doubles(raw_string);	
+				node = createNode("empty", values, convert_type(nxtype), units);
+			}
+			//cout << "dict value: '" << entry << "'"<<std::endl;
+			//node = createNode("empty", raw_string, convert_type(nxtype), units);
+			if (description.size() > 0) {	
+				std::vector<Attr> attrs;
+				Attr attr("description", description.c_str(), description.size(), NX_CHAR);
+				attrs.push_back(attr);
+				node->update_attrs(attrs);
+			}
+		}
+	}
+	else if (method == Frm2Retriever::FLINE_TAG) { 
+		std::string raw_string = extract_line_below(infile, arg, convert_type(nxtype));
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			if (convert_type(nxtype) == NX_CHAR) {
+				if (nxtype == "ISO8601") {
+					// check if its in heidi form
+					if (count_chars(raw_string, '.') > 1) {
+						raw_string = toftof_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '/') > 1) {
+						raw_string = nicos_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '-') > 1) {
+						raw_string = heidi_datetime_2_iso(raw_string);
+					}
+				}
+				node = createNode("empty", raw_string, convert_type(nxtype));
+			}
+			else {
+				std::vector<double> values = string_util::split_doubles(raw_string);	
+				node = createNode("empty", values, convert_type(nxtype));
+			}
+		}
+	}
+	else if (method == Frm2Retriever::DATETIME_TAG) { 
+		std::string entry="";
+		std::string units="";
+		std::string raw_string = extract_datetime(infile, args, convert_type(nxtype));
+ 		//cout << "dict value: '" << raw_string << "'"<<std::endl;  
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			unsigned int pos = raw_string.find("value:");
+			if (pos != std::string::npos) {
+				entry = raw_string.substr(pos+6);
+			}
+			pos = raw_string.find("units:");
+			if (pos != std::string::npos) {
+				units = raw_string.substr(pos+6);
+				unsigned int pos2 = units.find(";", pos);
+				if (pos2 != std::string::npos) {
+					units = units.substr(0, pos2);
+					//std::cout << " units extracted: " << units <<  std::endl;
+				}
+			}
+			else {
+				entry = raw_string;
+			}
+			node = createNode("empty", entry, convert_type(nxtype), units);
+		}
+	}
+	else if (method == Frm2Retriever::DICTMULTI_TAG) { 
+		std::map<std::string, std::string> raw_map = extract_dictmulti(infile, args, convert_type(nxtype));
+		std::string raw_string = raw_map["values"];
+		std::string units = raw_map["units"];
+		
+		if (unit_strings.find(string_util::lower_str(units))!=unit_strings.end()) {
+			units = unit_strings[units];
+		}
+ 		//cout << "dict value: '" << raw_string << "'"<<std::endl; 
+		while (isspace(raw_string[0])) {
+			raw_string = raw_string.substr(1);
+		} 
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			std::vector<std::string> vals = string_util::split_values(raw_string);
+			/*for (std::vector<std::string>::iterator it=vals.begin(); it!= vals.end();it++) {
+				std::cout << "vals: " << *it << std::endl;
+			}*/
+			node = createNode("empty", string_util::split_values(raw_string), convert_type(nxtype), units);
+		}
+	}
+	else if (method == Frm2Retriever::DICTARRAY_TAG) { 
+ 		//cout << "calling dict_array '" <<  std::endl;  
+		std::map<std::string, std::string> raw_map = extract_dictarray(infile, arg, convert_type(nxtype));
+		std::string raw_string=raw_map["values"];
+		std::string units=raw_map["units"];
+		
+		if (unit_strings.find(string_util::lower_str(units))!=unit_strings.end()) {
+			units = unit_strings[units];
+		}
+ 		//cout << "dict value: '" << raw_string << "'"<<std::endl;  
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", string_util::split_values(raw_string), convert_type(nxtype), units);
+		}
+	}
+	else if (method == Frm2Retriever::TOFCTS_TAG) {
+		std::vector<std::string> values;
+		std::vector<std::vector<unsigned int> > ivalues= extract_tofcts(infile, arg, convert_type(nxtype), false);
+  		if (ivalues.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", ivalues, convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::TOFMONCTS_TAG) {
+		std::vector<std::string> values;
+		std::vector<std::vector<unsigned int> > ivalues= extract_tofcts(infile, arg, convert_type(nxtype), true);
+  		if (ivalues.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", ivalues.at(0), convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::TOFTOF_TAG) { 
+		std::vector<double> dvalues= extract_toftof(infile, arg, convert_type(nxtype), false);
+  		if (dvalues.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", dvalues, convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::TOFMONTOF_TAG) { 
+		std::vector<double> dvalues= extract_toftof(infile, arg, convert_type(nxtype), true);
+  		if (dvalues.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", dvalues, convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::TOFDNR_TAG) { 
+		std::vector<unsigned int> ivalues= extract_dnr(infile, arg, convert_type(nxtype));
+  		if (ivalues.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", ivalues, convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::DESC_TAG) { 
+		std::vector<unsigned int> ivalues= extract_desc(infile, arg, convert_type(nxtype));
+  		if (ivalues.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", ivalues, convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::FILENAME_TAG) {
+		std::string entry = extract_filename(infile, source, arg,convert_type(nxtype));
+		node = createNode("empty", entry, convert_type(nxtype));
+	}
+	else if (method == Frm2Retriever::TOFLOG_TAG) {
+		std::vector<std::string> logs = extract_toflog(infile, arg);
+  		if (logs.size() <= 0) {
+			node = createEmptyNode("", convert_type(nxtype));
+		}
+		else {
+			node = createNode("empty", logs, convert_type(nxtype));
+			if (arg =="nicd_time") {
+				std::map<std::string, std::string> raw_map = extract_dictentry(infile, "# File_Creation_Time", NX_CHAR);
+				std::string tstr=raw_map["values"];
+				tstr = toflog_datetime_2_iso(tstr);
+				
+				std::vector<Attr> attrs;
+				Attr attr("start", tstr.c_str(), tstr.size(), NX_CHAR);
+				attrs.push_back(attr);
+				node->update_attrs(attrs);
+			}
+		}
+		
+	}
+	else if (method == Frm2Retriever::LOGCPY_TAG) {
+		std::string entry = extract_logcpy(infile, source);
+		node = createNode("empty", entry, convert_type(nxtype));
+	}
+	else if (method == Frm2Retriever::HEIDICTS_TAG || method == Frm2Retriever::HEIDIMON_TAG) {
+		std::cout << "creating heidi mon cts node now 0" << std::endl;
+		std::vector<double> values = extract_heidi_counts(infile, heidi_entry_num, (method==Frm2Retriever::HEIDIMON_TAG));
+		//std::cout << "creating heidi mon cts node now 1" << std::endl;
+  		if (values.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			//std::cout << "creating heidi mon cts node now 2"  << std::endl;
+			node = createNode("empty", values, convert_type(nxtype));
+		}
+	}
+	else if (method == Frm2Retriever::HEADER_TAG) {
+		std::cout << "getting header data now" << std::endl;
+		std::string raw_string = extract_header(infile, arg, convert_type(nxtype), word, wcount);
+		std::cout << "extracted header string: '" << raw_string << "'" << std::endl;
+		std::vector<double> values;
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			unsigned int pos = raw_string.find("value:");
+			if (pos != std::string::npos) {
+				raw_string = raw_string.substr(pos+6);
+			}
+			if (convert_type(nxtype) == NX_CHAR) {
+				if (nxtype == "ISO8601") {
+					// check if its in heidi form
+					if (count_chars(raw_string, '.') > 1) {
+						raw_string = toftof_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '/') > 1) {
+						raw_string = nicos_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '-') > 1) {
+						raw_string = heidi_datetime_2_iso(raw_string);
+					}
+				}
+				node = createNode("empty", raw_string, convert_type(nxtype));
+			}
+			else {
+				values = string_util::split_doubles(raw_string);	
+				node = createNode("empty", values, convert_type(nxtype), "", vdims);
+			}
+		}
+	}
+	else if (method == Frm2Retriever::DATA_TAG) {
+		std::cout << "extracting data now... '"  << "'" << std::endl;
+		std::string raw_string = extract_data(infile, heidi_entry_num, convert_type(nxtype), line, word, wcount);
+		std::cout << "extracted data string: '" << raw_string << "'" << std::endl;
+		std::vector<double> values;
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			unsigned int pos = raw_string.find("value:");
+			if (pos != std::string::npos) {
+				raw_string = raw_string.substr(pos+6);
+			}
+			if (convert_type(nxtype) == NX_CHAR) {
+				std::cout << "bingo ... got a char ..." << std::endl;
+				if (nxtype == "ISO8601") {
+					std::cout << "bingo ... got a time value ..." << std::endl;
+					// check if its in heidi form
+					if (count_chars(raw_string, '.') > 1) {
+						raw_string = toftof_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '/') > 1) {
+						std::cout << "bingo ... convert ..." << std::endl;
+						raw_string = nicos_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '-') > 1) {
+						raw_string = heidi_datetime_2_iso(raw_string);
+					}
+				}
+				node = createNode("empty", raw_string, convert_type(nxtype));
+			}
+			else {
+				values = string_util::split_doubles(raw_string);	
+				node = createNode("empty", values, convert_type(nxtype), "", vdims);
+			}
+		}
+	}
+	else if (method == Frm2Retriever::HEIDIIDS_TAG) {
+		std::cout << "extracting ids now... '"  << "'" << std::endl;
+		std::string raw_string = extract_heidiids(infile, heidi_entry_num, convert_type(nxtype), line, word);
+		std::cout << "extracted ids string: '" << raw_string << "'" << std::endl;
+		std::vector<double> values;
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			unsigned int pos = raw_string.find("value:");
+			if (pos != std::string::npos) {
+				raw_string = raw_string.substr(pos+6);
+			}
+			if (convert_type(nxtype) == NX_CHAR) {
+				std::cout << "bingo ... got a char ..." << std::endl;
+				if (nxtype == "ISO8601") {
+					std::cout << "bingo ... got a time value ..." << std::endl;
+					// check if its in heidi form
+					if (count_chars(raw_string, '.') > 1) {
+						raw_string = toftof_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '/') > 1) {
+						std::cout << "bingo ... convert ..." << std::endl;
+						raw_string = nicos_datetime_2_iso(raw_string);
+					}
+					else if (count_chars(raw_string, '-') > 1) {
+						raw_string = heidi_datetime_2_iso(raw_string);
+					}
+				}
+				node = createNode("empty", raw_string, convert_type(nxtype));
+			}
+			else {
+				values = string_util::split_doubles(raw_string);	
+				node = createNode("empty", values, convert_type(nxtype), "", vdims);
+			}
+		}
+	}
+	else if (method == Frm2Retriever::HEIDISO_TAG) {
+		std::cout << "getting heidiso data now" << std::endl;
+		std::vector<double> values = extract_heidi_so(infile, heidi_entry_num, convert_type(nxtype), word, wcount);
+		for (int ii=0; ii< values.size(); ii++) {
+			printf("values[%d]:%f\n", ii, values.at(ii));
+		}
+  		if (values.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			// remove first value (2theta)
+			values.erase(values.begin());
+			node = createNode("empty", values, convert_type(nxtype), "", vdims);
+		}
+	}
+	else if (method == Frm2Retriever::HEIDIOMG_TAG) {
+		std::string raw_string = extract_heidi_omg(infile, heidi_entry_num, convert_type(nxtype), word, wcount);
+		std::vector<double> values;
+  		if (raw_string.size() <= 0) {
+			node = createEmptyNode(arg, convert_type(nxtype));
+		}
+		else {
+			unsigned int pos = raw_string.find("value:");
+			if (pos != std::string::npos) {
+				raw_string = raw_string.substr(pos+6);
+			}
+			values = string_util::split_doubles(raw_string);	
+			node = createNode("empty", values, convert_type(nxtype), "", vdims);
+		}
+	}
+	else {
+		// unknown method
+		node = createEmptyNode("", NX_INT32);
+		node = NULL;
+	}
+	if (node != NULL) {
+		tr.insert(tr.begin(),*node);
+	}
+}
+
+
+
+std::string Frm2Retriever::month_strtonum(std::string &monthstr) {
+	std::string result="Jan";
+	
+	if (monthstr == "Jan") {
+		result = "01";	
+	}
+	else if (monthstr == "Feb") {
+		result = "02";	
+	}
+	else if (monthstr=="Mar") {
+		result = "03";	
+	}
+	else if (monthstr=="Apr") {
+		result = "04";	
+	}
+	else if (monthstr=="May" || monthstr=="Mai") {
+		result = "05";	
+	}
+	else if (monthstr=="Jun") {
+		result = "06";	
+	}
+	else if (monthstr=="Jul") {
+		result = "07";	
+	}
+	else if (monthstr=="Aug") {
+		result = "08";	
+	}
+	else if (monthstr=="Sep") {
+		result = "09";	
+	}
+	else if (monthstr=="Oct" || monthstr=="Oct") {
+		result = "10";	
+	}
+	else if (monthstr=="Nov") {
+		result = "11";	
+	}
+	else if (monthstr=="Dec" || monthstr=="Dez") {
+		result = "12";	
+	}
+
+	return result;
+}
+
+std::string Frm2Retriever::toflog_datetime_2_iso(std::string &datetimestr) {
+	/* toflog: Mon Aug 29 12:05:12 2005 */
+	/* iso: 2005-05-17 03:13:37 */
+	unsigned int pos, pos2;
+	std::string datestr, timestr;
+	std::string day="";
+	std::string month="";
+	std::string year="";
+	
+	// eliminate whitespace 
+	while (isspace(datetimestr[0])){
+		datetimestr = datetimestr.substr(1);
+	}
+	while (isspace(datetimestr[datetimestr.size()-1])){
+		datetimestr = datetimestr.substr(0, datetimestr.size()-1);
+	}
+
+	pos = datetimestr.find(" ");
+	if (pos != std::string::npos) {
+		datetimestr = datetimestr.substr(pos+1);
+		pos = datetimestr.find(" ");
+		if (pos != std::string::npos) {
+			month = datetimestr.substr(0, pos);
+			month = month_strtonum(month);
+			datetimestr = datetimestr.substr(pos+1);
+			
+			pos = datetimestr.find(" ");
+			if (pos != std::string::npos) {
+				day = datetimestr.substr(0, pos);
+				datetimestr = datetimestr.substr(pos+1);
+				
+				pos2 = datetimestr.rfind(" ");  
+				if (pos2 != std::string::npos) {
+					year = datetimestr.substr(pos2+1);
+					timestr = datetimestr.substr(0, pos2);
+				}
+			}
+		}
+	}
+	//sample together new string
+	if (timestr!="" && day!="" && month!="" && year !="") {
+		datetimestr = year+"-"+month+"-"+day+" "+timestr;	
+	}
+	//std::cout << "year: " << year << ", month: " << month << ", day: "<< day << ", datetime:" << datetimestr <<  std::endl;
+	return datetimestr;
+}
+
+
+std::string Frm2Retriever::heidi_datetime_2_iso(std::string &datetimestr) {
+	/* heidi: 14-Jun-05 15:57 */
+	/* iso: 2005-05-17 03:13:37 */
+	unsigned int pos, pos2;
+	std::string datestr, timestr;
+	std::string day="";
+	std::string month="";
+	std::string year="";
+	
+	pos = datetimestr.find(" ");
+	if (pos != std::string::npos) {
+		datestr = datetimestr.substr(0, pos);
+		timestr = datetimestr.substr(pos+1);
+		
+		pos = datestr.find("-");
+		if (pos != std::string::npos) {
+			day = datestr.substr(0, pos);
+			pos2 = datestr.rfind("-");  
+			if (pos2 != std::string::npos) {
+				year = datestr.substr(pos2+1);
+				month = datestr.substr(0,pos2);
+				month = month.substr(pos+1);
+				month = month_strtonum(month);
+				year = string("20").append(year);
+			}
+		}
+	}
+	//sample together new string
+	if (timestr!="" && day!="" && month!="" && year !="") {
+		datetimestr = year+"-"+month+"-"+day+" "+timestr;	
+	}
+	//std::cout << "year: " << year << ", month: " << month << ", day: "<< day << ", datetime:" << datetimestr <<  std::endl;
+	return datetimestr;
+}
+
+
+
+std::string Frm2Retriever::toftof_datetime_2_iso(std::string &datetimestr) {
+	/* toftof: 17.05.2005 03:13:37 */
+	/* iso: 2005-05-17 03:13:37 */
+	unsigned int pos, pos2;
+	std::string datestr, timestr;
+	std::string day="";
+	std::string month="";
+	std::string year="";
+	pos = datetimestr.find(" ");
+	if (pos != std::string::npos) {
+		datestr = datetimestr.substr(0, pos);
+		timestr = datetimestr.substr(pos+1);
+		
+		pos = datestr.find(".");
+		if (pos != std::string::npos) {
+			day = datestr.substr(0, pos);
+			pos2 = datestr.rfind(".");  
+			if (pos2 != std::string::npos) {
+				year = datestr.substr(pos2+1);
+				month = datestr.substr(0, pos2);
+				month = month.substr(pos+1);
+			}
+		}
+	}
+	//sample together new string
+	if (timestr!="" && day!="" && month!="" && year !="") {
+		datetimestr = year+"-"+month+"-"+day+" "+timestr;	
+	}
+	//std::cout << "year: " << year << ", month: " << month << ", day: "<< day << ", datetime:" << datetimestr <<  std::endl;
+	return datetimestr;
+}
+
+std::string Frm2Retriever::nicos_datetime_2_iso(std::string &datetimestr) {
+	/* nicos: 05/17/2005 03:13:37 */
+	/* iso: 2005-05-17 03:13:37 */
+	unsigned int pos, pos2;
+	std::string datestr, timestr;
+	std::string day="";
+	std::string month="";
+	std::string year="";
+	pos = datetimestr.find(" ");
+	if (pos != std::string::npos) {
+		datestr = datetimestr.substr(0, pos);
+		timestr = datetimestr.substr(pos+1);
+		
+		pos = datestr.find("/");
+		if (pos != std::string::npos) {
+			month = datestr.substr(0, pos);
+			pos2 = datestr.rfind("/");  
+			if (pos2 != std::string::npos) {
+				year = datestr.substr(pos2+1);
+				day = datestr.substr(0, pos2);
+				day = day.substr(pos+1);
+			}
+		}
+	}
+	//sample together new string
+	if (timestr!="" && day!="" && month!="" && year !="") {
+		datetimestr = year+"-"+month+"-"+day+" "+timestr;	
+	}
+	//std::cout << "year: " << year << ", month: " << month << ", day: "<< day << ", datetime:" << datetimestr <<  std::endl;
+	return datetimestr;
+}
+
+
+std::string Frm2Retriever::toString() const{
+  return "["+MIME_TYPE+"] "+source;
+}
diff --git a/applications/NXtranslate/FRM2/frm2_retriever.h b/applications/NXtranslate/FRM2/frm2_retriever.h
new file mode 100644
index 0000000..c866166
--- /dev/null
+++ b/applications/NXtranslate/FRM2/frm2_retriever.h
@@ -0,0 +1,144 @@
+#ifndef __FRM2_RETRIEVER
+#define __FRM2_RETRIEVER
+
+#include "../retriever.h"
+#include <fstream>
+#include <map>
+
+
+// this is not intended to be inherited from
+class Frm2Retriever: public Retriever{
+ public:
+  Frm2Retriever(const std::string &);
+  ~Frm2Retriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  Frm2Retriever(const Frm2Retriever&);
+  Frm2Retriever& operator=(const Frm2Retriever&);
+  std::string source;
+
+protected:
+  int current_line;
+  std::ifstream infile;
+  int number_of_cols;
+  int number_of_headers;
+  int number_of_entrys;
+  int header_section;
+  int data_section;
+  
+  std::vector<std::string> headers;
+  std::vector<std::string> units;
+  
+  std::vector<std::string> detector_counts;
+  std::vector<std::string> monitor_counts;
+  
+  
+	void extract_headers(std::string line);
+	void extract_toflogheaders(std::ifstream &file);
+	void extract_units(std::string line);
+	std::vector<std::string>& clear_units(std::vector<std::string> &units);
+	int number_of_columns(std::string line);
+
+
+  std::string 										extract_header			(std::ifstream &file, std::string arg, unsigned int nxtype, unsigned int word=0, unsigned int wcount=1);
+  std::string 										extract_data			(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int lineno, unsigned int word=0, unsigned int wcount=1);
+  std::vector<double>							extract_heidi_so		(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int word=0, unsigned int wcount=1);
+  std::string 										extract_heidi_omg		(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int word=0, unsigned int wcount=1);
+  std::string 										extract_heidiids			(std::ifstream &file, int entry_num, unsigned int nxtype, unsigned int lineno, unsigned int word=0);
+  std::vector<double> 							extract_heidi_counts	(std::ifstream &file, int entry_num, bool monitor_counts=false);
+  std::vector<std::vector<unsigned int> > extract_tofcts			(std::ifstream &file, std::string arg, unsigned int nxtype, bool is_monitor=false);
+  std::vector<double> 							extract_toftof			(std::ifstream &file, std::string arg, unsigned int nxtype, bool is_monitor=false);
+  std::string 										extract_filename		(std::ifstream &file, std::string source, std::string arg, unsigned int nxtype);
+  std::string 										extract_line_below	(std::ifstream &file, std::string arg, unsigned int nxtype);
+  std::vector<unsigned int> 					extract_desc			(std::ifstream &file, std::string arg, unsigned int nxtype);
+  std::vector<unsigned int> 					extract_dnr				(std::ifstream &file, std::string arg, unsigned int nxtype);
+  std::map<std::string, std::string>		extract_dictentry		(std::ifstream &file, std::string arg, unsigned int nxtype);
+  std::map<std::string, std::string>		extract_dictmulti		(std::ifstream &file, std::vector<std::string> args, unsigned int nxtype);
+  std::map<std::string, std::string>		extract_dictarray		(std::ifstream &file, std::string arg, unsigned int nxtype);
+  std::string 										extract_datetime		(std::ifstream &file, std::vector<std::string> args, unsigned int nxtype);
+  std::string 										extract_logcpy			(std::ifstream &file, std::string filename);
+  
+  std::vector<std::string> 					extract_toflog			(std::ifstream &file, std::string col_name, int from=-1, int to=-1);
+  std::vector<std::string> 					extract_column			(std::ifstream &file, std::string col_name, int from=-1, int to=-1);
+  
+  
+  
+  std::vector<std::string> parse_arg(std::string location);
+  std::string parse_method(std::string location);
+  std::string parse_type(std::string location);
+  void parse_range(std::string location, int &x, int &y);
+  void parse_heidi_range(std::string location, int &line, int &word, int &wcount);
+  std::vector<unsigned int> parse_dims(std::string dimstr);
+  std::vector<unsigned int> parse_type_dims(std::string location, std::string &typestr);
+  
+  std::string nicos_datetime_2_iso(std::string &timestr);
+  std::string toftof_datetime_2_iso(std::string &timestr);
+  std::string toflog_datetime_2_iso(std::string &timestr);
+  std::string heidi_datetime_2_iso(std::string &timestr);
+  std::string month_strtonum(std::string &monthstr);
+  
+  void initUnits();
+  
+  Node* createEmptyNode(std::string nodename, unsigned int nxtype);
+  Node* createNode(std::string nodename, std::vector<std::vector<double> >values, unsigned int nxtype);
+  Node* createNode(std::string nodename, std::vector<std::vector<unsigned int> >values, unsigned int nxtype);
+  Node* createNode(std::string nodename, std::vector<unsigned int>values, unsigned int nxtype);
+  Node* createNode(std::string nodename, std::vector<double>values, unsigned int nxtype, std::string units="", std::vector<unsigned int> dims= (std::vector<unsigned int, std::allocator<unsigned int> >)(0));
+  Node* createNode(std::string nodename, std::vector<std::string>values, unsigned int nxtype, std::string units="");
+  Node* createNode(std::string nodename, std::string value, unsigned int nxtype, std::string units="");
+  
+  
+public: 
+  static bool isdata(std::string line);
+  static void strip(std::string& line);
+  bool isunit(std::string line);
+  static bool isNumber(std::string str);
+  static bool isheidicountdata(std::string line);
+  static bool isheidiheader(std::string line);
+  static const std::string COLUMN_TAG;
+  static const std::string DICT_TAG;
+  static const std::string DATETIME_TAG;
+  static const std::string DICTARRAY_TAG;
+  static const std::string DICTMULTI_TAG;
+  static const std::string HEADER_TAG;
+  static const std::string DATA_TAG;
+  static const std::string HEIDIMON_TAG;
+  static const std::string HEIDICTS_TAG;
+  static const std::string HEIDIIDS_TAG;
+  static const std::string HEIDIOMG_TAG;
+  static const std::string HEIDISO_TAG;
+  static const std::string TOFCTS_TAG;
+  static const std::string TOFTOF_TAG;
+  static const std::string TOFDNR_TAG;
+  static const std::string TOFMONTOF_TAG;
+  static const std::string TOFMONCTS_TAG;
+  static const std::string TOFLOG_TAG;
+  static const std::string LOGCPY_TAG;
+  static const std::string DESC_TAG;
+  static const std::string FILENAME_TAG;
+  static const std::string FLINE_TAG;
+  static const std::string RANGE_OPEN_BRACKET;
+  static const std::string RANGE_CLOSE_BRACKET;
+  static const std::string RANGE_SEPARATOR;
+  static const std::string METHOD_OPEN_BRACKET;
+  static const std::string METHOD_CLOSE_BRACKET;
+  static const std::string TYPE_OPEN_BRACKET;
+  static const std::string TYPE_CLOSE_BRACKET;
+  static const std::string ARRAY_OPEN_BRACKET;
+  static const std::string ARRAY_CLOSE_BRACKET;
+  static const std::string ARRAY_SEPARATOR;
+  static const std::string ARRAY_RANGE_SEPARATOR;
+  static const std::string ARG_QUOTE;
+  static const std::string ARG_SEPARATOR;
+  
+  static const unsigned int HEIDI_LINES_PER_ENTRY;
+  static const unsigned int HEIDI_CHARS_PER_COUNT;
+  static const unsigned int HEIDI_COLS_PER_LINE;
+  
+  std::map<std::string, std::string> unit_strings; 
+  
+
+};
+#endif
diff --git a/applications/NXtranslate/LICENSE b/applications/NXtranslate/LICENSE
new file mode 100644
index 0000000..3ba71bc
--- /dev/null
+++ b/applications/NXtranslate/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+              Spallation Neutron Source at Oak Ridge National Laboratory
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/applications/NXtranslate/Makefile.am b/applications/NXtranslate/Makefile.am
new file mode 100644
index 0000000..6ac389a
--- /dev/null
+++ b/applications/NXtranslate/Makefile.am
@@ -0,0 +1,108 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -DFRM2_RETRIEVER -DTEXT_COLLIST_RETRIEVER -DTEXT_PLAIN_RETRIEVER -DTEXT_XML_RETRIEVER -DDYNAMIC_RETRIEVER -DSNS_HISTOGRAM_RETRIEVER -DLOOPY_RETRIEVER -DBINARY_RETRIEVER -DEDF_RETRIEVER -DSPEC_RETRIEVER @LIBXML2_CFLAGS@ @HDF4_CPPFLAGS@ @HDF5_CPPFLAGS@ @XML_CPPFLAGS@
+
+if HAVE_OPENGENIE
+GENIESUBDIR=opengenie
+endif
+SUBDIRS=text_collist text_plain text_xml sns_histogram docs \
+	FRM2 loopy binary spec esrf_edf $(GENIESUBDIR)
+
+bin_PROGRAMS = nxtranslate
+man_MANS = nxtranslate.1
+
+nxtranslate_SOURCES = \
+	attr.cpp main.cpp nexus_retriever.cpp  nexus_util.cpp node.cpp \
+	node_util.cpp retriever.cpp string_util.cpp xml_parser.cpp \
+        xml_util.h xml_util.cpp \
+	attr.h nexus_retriever.h nexus_util.h node.h node_util.h \
+	nxtranslate_debug.h Ptr.h retriever.h string_util.h xml_parser.h \
+	tree.hh dynamic_retriever.cpp dynamic_retriever.h
+
+EXTRA_nxtranslate_SOURCES= \
+	text_collist/collist_retriever.h \
+	text_plain/retriever.h \
+	text_xml/retriever.h \
+        sns_histogram/retriever.h \
+	FRM2/frm2_retriever.h \
+        loopy/retriever.h
+
+nxtranslate_LDADD = $(LIBNEXUS) -lxml2 \
+	text_collist/libTextCollist.la \
+	text_plain/libTextPlain.la text_xml/libTextXML.la \
+	sns_histogram/libSNShistogram.la \
+	FRM2/libFRM2.la \
+        loopy/libLoopy.la \
+	binary/libBinaryRetriever.la \
+	spec/libSpec.la \
+	esrf_edf/libEdf.la
+
+nxtranslate_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ @LIBXML2_LDFLAGS@ $(LDFLAGS)
+
+EXTRA_DIST = $(srcdir)/*.xml $(srcdir)/*.nxt $(srcdir)/*.dat $(srcdir)/*.run $(man_MANS)
+
+include $(top_srcdir)/build_rules.am
+
+test_dynamic.nxs: nxtranslate test_dynamic.xml test_dynamic.so
+	env LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:. ./nxtranslate test_dynamic.xml
+
+test_dynamic.so : test_dynamic.c
+	gcc -I$(top_srcdir)/include -shared -o $@ test_dynamic.c
+
+test_opengenie: nxtranslate test_opengenie.xml
+	( cd opengenie; for i in *.raw; do \
+             echo "Processing  $$i"; \
+	     k=`expr substr $$i 1 3`; \
+	     for j in 4 5; do \
+		env LD_LIBRARY_PATH=.:.libs:../../../src/.libs:@OPENGENIEROOT@/genie:$$LD_LIBRARY_PATH GENIE_SMALLTALK_IMAGE=@OPENGENIEROOT@/genie/genie.im GENIE_GROWTO_IMAGE_SIZE=64 NXGENIE_INIT=nxgenie.gcl ../nxtranslate --hdf$$j -DINPUT_FILE=$$i -DSHORT_NAME=$$k -o $$i.nx$$j ../test_opengenie.xml; \
+          done; done )
+
+test_simple.nxs: nxtranslate test_simple.xml
+	./nxtranslate test_simple.xml
+
+test_nexus.nxs: nxtranslate test_nexus.xml
+	./nxtranslate test_nexus.xml
+
+test_nexus_macro.nxs: nxtranslate test_nexus_macro.xml
+	./nxtranslate test_nexus_macro.xml -DFILE=test_simple.nxs
+
+test_ipns.nxs: nxtranslate test_ipns.xml hrcs1797.run
+	./nxtranslate test_ipns.xml -DfileName=hrcs1797.run
+
+test_text_plain.nxs: nxtranslate test_text_plain.xml test_simple.xml
+	./nxtranslate test_text_plain.xml
+
+test-clean:
+	rm -f $(TEST_RESULT)
+
+
diff --git a/applications/NXtranslate/Ptr.h b/applications/NXtranslate/Ptr.h
new file mode 100644
index 0000000..31eee6d
--- /dev/null
+++ b/applications/NXtranslate/Ptr.h
@@ -0,0 +1,51 @@
+#ifndef __GUARD_PTR_H
+#define __GUARD_PTR_H
+
+#include <stdexcept>
+
+template <class T> class Ptr{
+ public:
+  Ptr(): p(0), refptr(new std::size_t(1)){ }
+  Ptr(T* t): p(t), refptr(new std::size_t(1)){ }
+  Ptr(const Ptr& h): p(h.p), refptr(h.refptr){
+    ++(*refptr);
+  }
+  Ptr& operator=(const Ptr& rhs){
+    ++*rhs.refptr;
+
+    // free the left-hand side, destroying pointers if appropriate
+    if(--*refptr==0){
+      delete refptr;
+      delete p;
+    }
+
+    // copy in values from the right-hand side
+    refptr=rhs.refptr;
+    p=rhs.p;
+    return *this;
+  }
+  ~Ptr(){
+    if(--*refptr==0){
+      delete refptr;
+      delete p;
+    }
+  }
+
+  operator bool() const{ return p; }
+  T& operator*() const{
+    if(p)
+      return *p;
+    throw std::runtime_error("unbound Ptr");
+  }
+  T* operator->() const{
+    if(p)
+      return p;
+    throw std::runtime_error("unbound Ptr");
+  }
+
+ private:
+  T* p;
+  std::size_t* refptr;
+};
+
+#endif
diff --git a/applications/NXtranslate/README b/applications/NXtranslate/README
new file mode 100644
index 0000000..42c832f
--- /dev/null
+++ b/applications/NXtranslate/README
@@ -0,0 +1,7 @@
+Please see the documentation for more information.
+
+The quick installation for unix is
+  make
+  make test
+  make install
+which will place the executable in the directory /usr/local/bin
diff --git a/applications/NXtranslate/attr.cpp b/applications/NXtranslate/attr.cpp
new file mode 100644
index 0000000..039f2e7
--- /dev/null
+++ b/applications/NXtranslate/attr.cpp
@@ -0,0 +1,76 @@
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+#include <vector>
+#include "attr.h"
+#include "nexus_util.h"
+
+using std::runtime_error;
+using std::logic_error;
+using std::out_of_range;
+using std::string;
+using std::vector;
+
+// ==================== Node implementation
+Attr::Attr(const string name, const void* val,const int len, const int type): __name(name), __length(len), __type(type){
+  // create dimensions
+  int dims[1]={__length};
+
+  // copy the value
+  NXmalloc(&_value,1,dims,__type);
+  size_t size=nexus_util::calc_size(1,dims,__type);
+  memcpy(_value,val,size);
+}
+
+Attr::Attr(const Attr& old): __name(old.__name), __length(old.__length), __type(old.__type){
+  // create dimensions
+  int dims[1]={__length};
+
+  // copy the value
+  NXmalloc(&_value,1,dims,__type);
+  size_t size=nexus_util::calc_size(1,dims,__type);
+  memcpy(_value,old._value,size);
+}
+
+Attr::~Attr(){
+  if(NXfree(&_value)!=NX_OK)
+    throw runtime_error("NXfree failed");
+}
+
+Attr& Attr::operator=(const Attr& old){
+  if(this==&old) return *this;
+
+  if(NXfree(&_value)!=NX_OK)
+    throw runtime_error("NXfree failed");
+
+  // copy everything other than the value
+  __name=old.__name;
+  __length=old.__length;
+  __type=old.__type;
+
+  // create dimensions
+  int dims[1]={__length};
+
+  // copy the value
+  NXmalloc(&_value,1,dims,__type);
+  size_t size=nexus_util::calc_size(1,dims,__type);
+  memcpy(_value,old._value,size);
+
+  return *this;
+}
+
+std::string Attr::name(){
+  return __name;
+}
+
+void* Attr::value(){
+  return _value;
+}
+
+int Attr::length(){
+  return __length;
+}
+
+int Attr::type(){
+  return __type;
+}
diff --git a/applications/NXtranslate/attr.h b/applications/NXtranslate/attr.h
new file mode 100644
index 0000000..b11dd25
--- /dev/null
+++ b/applications/NXtranslate/attr.h
@@ -0,0 +1,29 @@
+#ifndef __ATTR_H_GUARD
+#define __ATTR_H_GUARD
+
+#include <vector>
+#include <string>
+#include <napiconfig.h>
+#include <napi.h>
+#include <iostream>
+
+// ==================== Attribute definition
+class Attr{
+ public:
+  Attr(const std::string name, const void* val,const int len, const int type);
+  Attr(const Attr&);
+  ~Attr();
+  Attr& operator=(const Attr&);
+
+  std::string name();
+  void *value();
+  int length();
+  int type();
+
+ private:
+  std::string __name;
+  void *_value;
+  int __length;
+  int __type;
+};
+#endif
diff --git a/applications/NXtranslate/binary/BinaryRetriever.cpp b/applications/NXtranslate/binary/BinaryRetriever.cpp
new file mode 100644
index 0000000..36d606c
--- /dev/null
+++ b/applications/NXtranslate/binary/BinaryRetriever.cpp
@@ -0,0 +1,345 @@
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <vector>
+#include <cstdlib>
+#include <cstring>
+#include "napiconfig.h"
+#include "binary/BinaryRetriever.hpp"
+#include "string_util.h"
+
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::vector;
+using std::cout;
+using std::endl;
+
+static const string myINT8("INT8");
+static const string myINT16("INT16");
+static const string myINT32("INT32");
+static const string myUINT8("UINT8");
+static const string myUINT16("UINT16");
+static const string myUINT32("UINT32");
+static const string myFLOAT32("FLOAT32");
+static const string myFLOAT64("FLOAT64");
+static const string myBYTE("BYTE");
+
+static const int NX_DEFAULT_TYPE=NX_UINT32;
+
+/**
+ * \file NXtranslate/binary/BinaryRetriever.cpp
+ */
+
+/**
+ * All nodes returned by BinaryRetriever::getData will have this name.
+ */
+static const string NAME("binary");
+
+/**
+ * This is the constructor for the object. No resources are allocated.
+ *
+ * \param str The source string is ignored, but necessary to implement
+ * the interface.
+ */
+BinaryRetriever::BinaryRetriever(const string &source_file): filename(source_file)
+{
+  // there is nothing additional to allocate
+}
+
+/**
+ * Since no resources were allocated, the destructor does nothing
+ */
+BinaryRetriever::~BinaryRetriever()
+{
+  // there is nothing to deallocate
+}
+
+static size_t calculate_position(const vector<int> &file_size, 
+                                 const vector<int> &pos)
+{
+  size_t rank=file_size.size();
+  size_t result=0;
+  for( size_t i=0 ; i<rank ; ++i )
+    {
+      result=static_cast<size_t>(file_size[i]*result+pos[i]);
+    }
+
+  return result;
+}
+
+static bool increment_position(const vector<int> &offset,
+                               const vector<int> &size,
+                               vector<int> &pos)
+{
+  int index=size.size()-2;
+
+  while(index>=0){
+    if(pos[index]+1<offset[index]+size[index])
+      {
+        pos[index]++;
+        return true;
+      }
+    else
+      {
+        pos[index]=offset[index];
+        index--;
+      }
+  }
+  return false;
+}
+
+/**
+ * This function turns the type as a string into an integer for use
+ * with NeXus.
+ */
+static int getDataType(const string &str_type){
+  if(str_type.empty()){
+    return NX_DEFAULT_TYPE;
+  }else if(str_type==myINT8){
+    return NX_INT8;
+  }else if(str_type==myINT16){
+    return NX_INT16;
+  }else if(str_type==myINT32){
+    return NX_INT32;
+  }else if(str_type==myUINT8){
+    return NX_UINT8;
+  }else if(str_type==myUINT16){
+    return NX_UINT16;
+  }else if(str_type==myUINT32){
+    return NX_UINT32;
+  }else if(str_type==myFLOAT32){
+    return NX_FLOAT32;
+  }else if(str_type==myFLOAT64){
+    return NX_FLOAT64;
+  }else if(str_type==myBYTE){
+    return NX_CHAR;
+  }else{
+    throw invalid_argument("Invalid type: "+str_type);
+  }
+}
+
+/**
+ * This function turns the type as a string into a platform dependent
+ * size.
+ */
+static size_t getDataTypeSize(const int type){
+  if(type==NX_INT8){
+    return sizeof(int8_t);
+  }else if(type==NX_INT16){
+    return sizeof(int16_t);
+  }else if(type==NX_INT32){
+    return sizeof(int32_t);
+  }else if(type==NX_UINT8){
+    return sizeof(uint8_t);
+  }else if(type==NX_UINT16){
+    return sizeof(uint16_t);
+  }else if(type==NX_UINT32){
+    return sizeof(uint32_t);
+  }else if(type==NX_FLOAT32){
+    return sizeof(float);
+  }else if(type==NX_FLOAT64){
+    return sizeof(double);
+  }else if(type==NX_CHAR){
+    return sizeof(char);
+  }else{
+    throw invalid_argument("This statement should never be reached");
+  }
+}
+
+/**
+ * This is the method for retrieving data from a file. The string must
+ * be of the form "type:offset,delta,number".
+ *
+ * \param location is the string that is used by the retriever to
+ * create the data.
+ * \param tr is the tree to put the result into.
+ */
+void BinaryRetriever::getData(const string &location, tree<Node> &tr)
+{
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    {
+      throw invalid_argument("cannot parse empty string");
+    }
+
+  // break the location string into a type and sizing information
+  int type;
+  string sizing;
+  {
+    vector<string> temp=string_util::split(location,":");
+    if(temp.size()==1){
+      type=getDataType("");
+      sizing=location;
+    }else if(temp.size()==2){
+      type=getDataType(temp[0]);
+      sizing=temp[1];
+    }else{
+      throw invalid_argument("can only specify one type in location string");
+    }
+  }
+
+  // break the location string into three parts: file_size,data_start,data_size
+  string file_size_str;
+  string start_str;
+  string size_str;
+  {
+    vector<string> temp=string_util::split(sizing,"][");
+    if(temp.size()!=3)
+      {
+        throw invalid_argument("wrong number of groups in location string");
+      }
+    file_size_str=temp[0].substr(1);
+    start_str=temp[1];
+    size_str=temp[2].substr(0,temp[2].size()-1);
+  }
+
+  // convert the parts into vector<int>
+  vector<int> file_size=string_util::str_to_intVec(file_size_str);
+  vector<int> start=string_util::str_to_intVec(start_str);
+  vector<int> size=string_util::str_to_intVec(size_str);
+
+  // check for the same dimension
+  int rank=file_size.size();
+  if(start.size()!=rank || size.size()!=rank)
+    {
+      throw invalid_argument("All parts of the location string must be the same rank");
+    }
+
+  // confirm that the size doesn't have a zero component
+  for( size_t i=0 ; i<rank ; ++i )
+    {
+      if( size[i]<=0 )
+        {
+          throw invalid_argument("the size arguments must all be greater than zero");
+        }
+    }
+
+  // check that the request doesn't seek past the end of the file
+  for( size_t i=0 ; i<rank ; ++i )
+    {
+      if(file_size[i]<start[i]+size[i])
+        {
+          throw invalid_argument("start[i]+size[i] must be less than file_size[i]");
+        }
+    }
+
+  // determine the total file size
+  size_t tot_file_size=1;
+  for( vector<int>::iterator it=file_size.begin() ; it!=file_size.end() ; ++it)
+    {
+      tot_file_size*=(*it);
+    }
+
+  // set up the starting position
+  vector<int> pos;
+  for( size_t i=0 ; i<start.size() ; i++ )
+    {
+      pos.push_back(start[i]);
+    }
+
+  // create integer copy of size
+  std::vector<int> dims(size.size());
+  for( size_t i=0 ; i<size.size() ; ++i )
+    {
+      dims[i]=size[i];
+    }
+
+  // allocate the space for the result
+  void *data;
+  if(NXmalloc(&data,rank,&(dims[0]),type)!=NX_OK)
+    {
+      throw runtime_error("NXmalloc failed");
+    }
+
+  // prepare data buffer
+  size_t data_size=getDataTypeSize(type);
+  /*
+  size_t num_items=1;
+  size_t buffer_size=num_items; // read a single element at a time
+  data_t data_buffer[buffer_size];
+  */
+
+  // open the file
+  std::ifstream data_file(filename.c_str(), std::ios::binary);
+  if(!(data_file.is_open()))
+    {
+      throw runtime_error("Failed opening file");
+    }
+
+  // check the file size against claims
+  {
+    data_file.seekg(0,std::ios::beg);
+    long begin=data_file.tellg();
+    data_file.seekg(0,std::ios::end);
+    long end=data_file.tellg();
+    if( (end-begin)!=(tot_file_size*data_size) )
+      {
+        throw runtime_error("Actual file size does not match claimed file size");
+      }
+  }
+
+  // number for the scalar version of the offset
+  size_t scalar_position;
+
+  // index into data array
+  size_t data_index=0;
+
+  // buffer to read data into
+  size_t num_items=*(size.rbegin());
+  size_t buffer_size=num_items*data_size;
+  std::vector<char>   data_buffer(buffer_size);
+
+  // push through the file grabbing the proper bits
+  scalar_position=data_size*calculate_position(file_size,pos);
+  data_file.seekg(scalar_position,std::ios::beg);
+  data_file.read(&(data_buffer[0]),buffer_size);
+
+  // copy into final array
+  memcpy((static_cast<char *>(data))+data_index*data_size,&(data_buffer[0]),buffer_size);
+  data_index+=num_items;
+
+  while(increment_position(start,size,pos))
+    {
+      // calculate where to go and read in a block of data
+      scalar_position=data_size*calculate_position(file_size,pos);
+      data_file.seekg(scalar_position,std::ios::beg);
+      data_file.read(&(data_buffer[0]),buffer_size);
+      // copy into final array
+      memcpy((static_cast<char *>(data))+data_index*data_size,&(data_buffer[0]),buffer_size);
+      data_index+=num_items;
+    }
+
+  // close the file
+  data_file.close();
+
+  // create the node - this copies the data
+  Node node=Node(NAME,data,rank,&(dims[0]),type);
+
+  // insert the data into the tree
+  tr.insert(tr.begin(),node);
+
+  // delete the data
+  if(NXfree(&data)!=NX_OK)
+    {
+      throw runtime_error("NXfree failed");
+    }
+}
+
+/**
+ * The MIME_TYPE is necessary so the retriever can be selected by the
+ * factory.
+ */
+const string BinaryRetriever::MIME_TYPE("binary");
+
+/**
+ * This function returns a string representation of the retriever for
+ * debugging. Since no resources are allocated the string is always
+ * identical.
+ *
+ * \return The string returned is always "[loopy]".
+ */
+string BinaryRetriever::toString() const
+{
+  return "["+MIME_TYPE+"]:"+filename;
+}
diff --git a/applications/NXtranslate/binary/BinaryRetriever.hpp b/applications/NXtranslate/binary/BinaryRetriever.hpp
new file mode 100644
index 0000000..bd953f1
--- /dev/null
+++ b/applications/NXtranslate/binary/BinaryRetriever.hpp
@@ -0,0 +1,22 @@
+#ifndef _BINARY_RETRIEVER_HPP
+#define _BINARY_RETRIEVER_HPP 1
+
+#include "retriever.h"
+
+/**
+ */
+// this is not intended to be inherited from
+class BinaryRetriever: public Retriever{
+ public:
+  BinaryRetriever(const std::string &source_file);
+  ~BinaryRetriever();
+  void getData(const std::string &location, tree<Node> &tr);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private: // do not allow these automatically created functions to be called
+  BinaryRetriever(const BinaryRetriever &other); //copy constructor
+  BinaryRetriever& operator=(const BinaryRetriever &other);//operator "=" overloading
+  std::string filename;
+};
+
+#endif
diff --git a/applications/NXtranslate/binary/CMakeLists.txt b/applications/NXtranslate/binary/CMakeLists.txt
new file mode 100644
index 0000000..b2abda5
--- /dev/null
+++ b/applications/NXtranslate/binary/CMakeLists.txt
@@ -0,0 +1,31 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (BinaryRetriever STATIC BinaryRetriever.cpp BinaryRetriever.hpp)
diff --git a/applications/NXtranslate/binary/Makefile.am b/applications/NXtranslate/binary/Makefile.am
new file mode 100644
index 0000000..5e021c8
--- /dev/null
+++ b/applications/NXtranslate/binary/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -I$(top_srcdir)/applications/NXtranslate
+
+noinst_LTLIBRARIES = libBinaryRetriever.la
+
+libBinaryRetriever_la_SOURCES = \
+        BinaryRetriever.cpp BinaryRetriever.hpp
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/docs/Makefile.am b/applications/NXtranslate/docs/Makefile.am
new file mode 100644
index 0000000..b72596e
--- /dev/null
+++ b/applications/NXtranslate/docs/Makefile.am
@@ -0,0 +1,20 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id$
+#
+DOC_SRC=NXtranslate.docbook overview.docbook \
+		translation.docbook retrievers.docbook
+
+nxtranslatedocdir		= $(NXDOCDIR)/NXtranslate
+nxtranslatedoc_DATA		= $(DOC_OUTPUT)
+EXTRA_DIST 			= $(DOC_OUTPUT) $(DOC_SRC)
+
+if HAVE_DOCBOOK
+DOC_OUTPUT=NXtranslate.pdf NXtranslate.txt
+NXtranslate.pdf: $(DOC_SRC)
+	$(DOCBOOK2PDF) NXtranslate.docbook
+
+NXtranslate.txt: $(DOC_SRC)
+	$(DOCBOOK2TXT) NXtranslate.docbook
+endif
diff --git a/applications/NXtranslate/docs/NXtranslate.docbook b/applications/NXtranslate/docs/NXtranslate.docbook
new file mode 100644
index 0000000..c0228c1
--- /dev/null
+++ b/applications/NXtranslate/docs/NXtranslate.docbook
@@ -0,0 +1,46 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.0//EN" [
+ <!ENTITY overview    SYSTEM "overview.docbook">
+ <!ENTITY translation SYSTEM "translation.docbook">
+ <!ENTITY retrievers  SYSTEM "retrievers.docbook">
+ <!ENTITY nxtranslate "<application>NXtranslate</application>">
+ <!ENTITY napi        "<acronym>napi</acronym>">
+ <!ENTITY mime-type   "<parameter>NXS:mime_type</parameter>">
+ <!ENTITY source      "<parameter>NXS:source</parameter>">
+ <!ENTITY location    "<parameter>NXS:location</parameter>">
+ <!ENTITY make-link   "<parameter>target</parameter>">
+ <!ENTITY link-tag    "<parameter>NAPIlink</parameter>">
+]>
+ 
+<book id="NXtranslate" lang="en">
+
+<bookinfo>
+<title>NXtranslate</title>
+<date>30 July, 2004</date>
+<authorgroup>
+<author>
+<firstname>Peter</firstname>
+<othername>F.</othername>
+<surname>Peterson</surname>
+</author>
+</authorgroup>
+
+<abstract>
+
+<para>&nxtranslate is an anything to NeXus converter. This is
+accomplished by using translation files and a plugin style of
+architecture where &nxtranslate can read from new formats as plugins
+become available. This document describes the usage of &nxtranslate by
+three types of individuals: the person using existing translation
+files to create NeXus files, the person creating translation files,
+and the person writing new Retrievers. All of these concepts are
+discussed in detail.</para>
+
+</abstract>
+
+</bookinfo>
+
+&overview
+&translation
+&retrievers
+
+</book>
diff --git a/applications/NXtranslate/docs/overview.docbook b/applications/NXtranslate/docs/overview.docbook
new file mode 100644
index 0000000..780d700
--- /dev/null
+++ b/applications/NXtranslate/docs/overview.docbook
@@ -0,0 +1,123 @@
+<!-- ******************** OVERVIEW ******************** -->
+<chapter id="overview"><title>Overview</title>
+
+<para>&nxtranslate is designed to be the anything to NeXus
+converter. To this end it is built in a modular fashion so the types
+of files that can be read from can vary between different
+installations. The reason for this is to minimize the size of the
+executable. In line with this modularity is the author's desire to
+work with users of &nxtranslate to add abilities, clarify
+documentation, and fix bugs.</para>
+
+<para>&nxtranslate operates by parsing a <link
+linkend="translation-file">translation file</link> to create a NeXus
+file. The translation file contains the organization of the resulting
+NeXus file, data, and instructions on other how to obtain data using
+<link linkend="retrievers">retrievers</link>. This book is organized
+into chapters with an increasingly sophisticated user in mind. The
+chapter you are reading is a general overview on how to use
+&nxtranslate with an existing installation and existing translation
+files. <link linkend="translation-file">Chapter 2</link> is aimed at
+writing translation files and <link linkend="retrievers">chapter
+3</link> will discuss in more detail what retrievers are and how to
+write them.</para>
+
+<sect1><title>Command line arguments</title>
+
+<para>This section will explain the various command line arguments to
+&nxtranslate . For all of the examples here the name of the
+translation file is <filename>test.xml</filename>.</para>
+
+<cmdsynopsis>
+  <command>nxtranslate</command>
+  <arg>--help</arg>
+  <arg>-o <replaceable>outputfile</replaceable></arg>
+  <group>
+    <arg>--hdf4</arg>
+    <arg>--hdf5</arg>
+  </group>
+  <arg>-D <replaceable>macro</replaceable></arg>
+  <arg choice="req"><replaceable>translationfile</replaceable></arg>
+  <arg>--append <replaceable>outputfile</replaceable></arg>
+</cmdsynopsis>
+
+<para>First to get the easy arguments out of the way. Typing just
+<command>nxtranslate</command> will give a usage statement similar to
+what is above. <command>nxtranslate</command>
+<parameter>--help</parameter> will print the full help
+message. Generally speaking this is not what you are interested
+in.</para>
+
+<para>The minimum argument list for &nxtranslate to do anything other
+than print the usage message is to supply a translation file. The
+cannonical example is
+
+<informalexample><programlisting>
+<prompt>bash$</prompt> <command>nxtranslate</command> <filename>test.xml</filename>
+</programlisting></informalexample>
+
+This tells &nxtranslate to parse the file
+<filename>test.xml</filename> and produce a NeXus file called
+<filename>test.nxs</filename> using the default base format (base
+format is discussed below). To change the name of the output file use
+the "<parameter>-o</parameter>" switch.
+
+<informalexample><programlisting>
+<prompt>bash$</prompt> <command>nxtranslate</command> <filename>test.xml</filename> <parameter>-o</parameter> <filename>my_file.nxs</filename>
+</programlisting></informalexample>
+
+The only difference with the previous example is that the resulting
+NeXus file is <filename>my_file.nxs</filename>.
+</para>
+
+<para>The switches "<parameter>--hdf4</parameter>" and
+"<parameter>--hdf5</parameter>" are mutually exclusive and take no
+arguments. These are used to select the base format for the output
+file. NeXus is actually written using the Hierarchical Data Format
+(HDF) which is produced by the National Center for Supercomputer
+Applications (NCSA). There are two (incompatible) versions of HDF that
+have widespread use that are commonly referred to as HDF4 and
+HDF5. Part of the purpose of the NeXus API is to hide the difference
+between the different bases. In this spirit &nxtranslate only exposes
+the bases with these switches. To create two files with the same
+structure and diffent bases is easy.
+
+<informalexample><programlisting>
+<prompt>bash$</prompt> <command>nxtranslate</command> <parameter>--hdf4</parameter> <filename>test.xml</filename> <parameter>-o</parameter> <filename>my_hdf4.nxs</filename>
+<prompt>bash$</prompt> <command>nxtranslate</command> <parameter>--hdf5</parameter> <filename>test.xml</filename> <parameter>-o</parameter> <filename>my_hdf5.nxs</filename>
+</programlisting></informalexample>
+
+</para>
+
+<para>The last command line argument is the
+"<parameter>-D</parameter>" switch. This switch allows for
+substituting strings in the the translation file for the &mime-type ,
+&source , and &location attributes in the translation file. To get a
+better understanding of what this means see Chapter 2. For now it is enough to show an example. 
+
+<informalexample><programlisting>
+<prompt>bash$</prompt> <command>nxtranslate</command> <filename>test.xml</filename> <parameter>-D</parameter>FILE1=<filename>old_nexus.nxs</filename>
+</programlisting></informalexample>
+
+This example assumes that there is a macro
+<parameter>FILE1</parameter> in the translation file. &nxtranslate will
+convert the string <parameter>FILE1</parameter> into
+<filename>old_nexus.nxs</filename> before creating the resulting NeXus
+file. This allows for a script to convert an entire directory of files
+to look like (using python)
+
+<informalexample><programlisting>
+listing=glob.glob("*.nxs")
+for file in listing:
+    os.system("<command>nxtranslate</command> <filename>converter.xml</filename> -DFILE1=%s -o new_%s" % (file,file))
+</programlisting></informalexample>
+
+This bit of code (plus the proper import statements) would use the
+translation file <filename>converter.xml</filename> to translate all
+<filename>*.nxs</filename> in the current working directory.
+
+</para>
+
+</sect1>
+
+</chapter>
diff --git a/applications/NXtranslate/docs/retrievers.docbook b/applications/NXtranslate/docs/retrievers.docbook
new file mode 100644
index 0000000..7847468
--- /dev/null
+++ b/applications/NXtranslate/docs/retrievers.docbook
@@ -0,0 +1,220 @@
+<!-- ******************** RETRIEVERS ******************** -->
+<chapter id="retrievers">
+<title>Retriever Details</title>
+
+<example id="retriever.h"><title>listing of <filename>retriever.h</filename></title>
+  <programlisting role="C++">
+<![CDATA[class Retriever{
+  typedef Ptr<Retriever> RetrieverPtr;
+
+ public:
+  /**
+   * The factory will call the constructor with a string. The string
+   * specifies where to locate the data (e.g. a filename), but
+   * interpreting the string is left up to the implementing code.
+   */
+  //Retriever(const std::string &);
+
+  /**
+   * The destructor must be virtual to make sure the right one is
+   * called in the end.
+   */
+  virtual ~Retriever()=0;
+
+  /**
+   * This is the method for retrieving data from a file. The whole
+   * tree will be written to the new file immediately after being
+   * called. Interpreting the string is left up to the implementing
+   * code.
+   */
+  virtual void getData(const std::string &, tree<Node> &)=0;
+
+  /**
+   * This method is to be used for debugging purposes only. While the
+   * string can be anything, most useful is "[mime_type] source".
+   */
+  virtual std::string toString() const=0;
+
+  /**
+   * Factory method to create new retrievers.
+   */
+  static RetrieverPtr getInstance(const std::string &, const std::string &);
+};]]>
+  </programlisting>
+</example>
+
+<para><xref linkend="retriever.h"> is the listing of the Retriever
+abstract base class. In addition to these methods there are a couple
+of assumptions made about classes that implement this interface
+
+<orderedlist><title>Other constraints</title>
+ <listitem id="no-copy-or-assign"><para>The copy constructor and
+ assignment operator will not be used. It is suggested that they are
+ made private methods.</para></listitem>
+ <listitem id="mime-type"><para>There is a static const string called
+ MIME_TYPE which will be used to determine if that particular
+ Retriever should be created by the factory. Care must be made to
+ select a unique MIME_TYPE to prevent name clashing.</para></listitem>
+ <listitem id="destructor"><para>The destructor will properly
+ deallocate all resources allocated in the construtor. Specifically,
+ if a file is opened in the constructor, it should be closed in the
+ destructor.</para></listitem>
+ <listitem id="exception"><para>If anything goes wrong during the
+ course of the Retriever's operation, an std::exception will be
+ thrown.</para></listitem>
+</orderedlist> </para>
+
+<para> The rest of this chapter describes how to create the body of
+code, and header, for an example implementation.</para>
+
+<sect1><title>The Simple ASCII Retriever as an Example</title>
+
+<para>The simplest retriever is the the one for the &mime-type
+<parameter>text/plain</parameter>. Because of this it makes a good
+example of how to create your own retriever. The files are located in
+the <filename>text_plain</filename> subdirectory as
+<filename>retriever.h</filename> and
+<filename>retriever.cpp</filename>.</para>
+
+<example id="text-plain-retriever.h"><title>listing of <filename>text_plain/retriever.h</filename></title>
+  <programlisting role="C++">
+<![CDATA[#include "../retriever.h"
+#include <fstream>
+
+// this is not intended to be inherited from
+class TextPlainRetriever: public Retriever{
+ public:
+  TextPlainRetriever(const std::string &);
+  ~TextPlainRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  TextPlainRetriever(const TextPlainRetriever&);
+  TextPlainRetriever& operator=(const TextPlainRetriever&);
+  std::string source;
+  int current_line;
+  std::ifstream infile;
+};]]>
+  </programlisting>
+</example>
+
+<para>Note that none of the methods are virtual, so this is not
+intended to be derived from directly. That being said, you may want to
+copy the header and code for your own retriever as a basis of what
+works. In this example the copy constructor and assignment operator
+are made private as specified in Other constraints <xref
+linkend="no-copy-or-assign">. The private data is a filehandle and the
+name of the file that is open for reading. The file name and
+&mime-type are used in the <function>toString</function> to identify
+it uniquely for debugging as seen in <xref
+linkend="text-plain-toString">.</para>
+
+<example id="text-plain-toString"><title>Listing of simple ascii <function>toString</function></title>
+  <programlisting role="C++">
+<![CDATA[string TextPlainRetriever::toString() const{
+  return "["+MIME_TYPE+"] "+source;
+}]]>
+  </programlisting>
+</example>
+
+<para>The first non-trivial function to write is the constructor. The
+constructor is not very complicated or insightful. The
+<parameter>source</parameter> and accounting for where in the file the
+reading is (<parameter>current_line</parameter>) are initialized in
+line 1. Line 3 opens the file, and line 6 confirms that it was opened
+without error. An exception is thrown if there is a problem to follows
+Other constraints <xref linkend="exception">. The constructor is very
+brief because C++ <parameter>fstream</parameter> library provides the
+<parameter>ifstream</parameter> object that does most of the
+work.</para>
+
+<example id="simple-ascii-constructor"><title>Listing of the simple ascii constructor</title>
+  <programlisting role="C++" linenumbering="numbered">
+<![CDATA[TextPlainRetriever::TextPlainRetriever(const string &str): source(str),current_line(0){
+  // open the file
+  infile.open(source.c_str());
+
+  // check that open was successful
+  if(!infile.is_open())
+    throw invalid_argument("Could not open file: "+source);
+}]]>
+  </programlisting>
+</example>
+
+<para>The destructor for the Retriever in <xref
+linkend="simple-ascii-destructor"> is just as simple simpler since all
+it has to do is close the file. There were no calls in the constructor
+(or anywhere else) to <function>new</function> or
+<function>malloc</function> so the constructor does not need to call
+<function>delete</function> or <function>free</function>.</para>
+
+<example id="simple-ascii-destructor"><title>Listing of the simple ascii destructor</title>
+  <programlisting role="C++">
+<![CDATA[TextPlainRetriever::~TextPlainRetriever(){
+  // close the file
+  if(infile)
+    infile.close();
+}]]>
+  </programlisting>
+</example>
+
+<para>Next is the <function>getData</function> function which is
+simple as well. All that <function>getData</function> does is grab a
+line of text from the file and create a node. Lines 3-4 are error
+checking, and line 7 converts the <parameter>location</parameter>
+string into an integer. Line 10 moves to the appropriate place in the
+file while line 12 gets the string on that line. Since every
+<function>getData</function> must put a <parameter>node</parameter>
+into the provided <parameter>tree</parameter>, line 15 creates a
+<parameter>node</parameter> to be filled with data. Lines 18-20 update
+the generic <parameter>node</parameter> with the string read in from
+the source file. Finally line 21 adds the single node to the supplied
+tree.</para>
+
+<example id="simple-ascii-getData"><title>Listing of the simple ascii <function>getData</function></title>
+  <programlisting role="C++" linenumbering="numbered">
+<![CDATA[void TextPlainRetriever::getData(const string &location, tree<Node> &tr){
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    throw invalid_argument("cannot parse empty string");
+
+  // check that the argument is an integer
+  int line_num=string_util::str_to_int(location);
+
+  // set stream to the line before
+  skip_to_line(infile,current_line,line_num);
+  // read the line and print it to the console
+  string text=read_line(infile);
+
+  // create an empty node
+  Node node("empty","empty");
+
+  // put the data in the node
+  vector<int> dims;
+  dims.push_back(text.size());
+  update_node_from_string(node,text,dims,Node::CHAR);
+  tr.insert(tr.begin(),node);
+}]]>
+  </programlisting>
+</example>
+
+<para><xref linkend="simple-ascii-getData"> is brief because it
+leverages existing functionality. The <parameter>ifstream</parameter>
+objects does all of the work of getting information out of a
+file. <function>skip_to_line</function> and
+<function>read_line</function> are very short functions that scan to a
+point in an ascii file and read from a point to the next end-of-line
+character, respectively. Finally, the function
+<function>update_node_from_string</function> existed in &nxtranslate
+already to assist <parameter>node</parameter> creation while reading
+the translation file. The interested reader can look at the source of
+<filename>node_util.cpp</filename> and
+<filename>text_plain/retriever.cpp</filename> to see the body of the
+functions.
+
+</para>
+
+</sect1>
+
+</chapter>
diff --git a/applications/NXtranslate/docs/translation.docbook b/applications/NXtranslate/docs/translation.docbook
new file mode 100644
index 0000000..a848386
--- /dev/null
+++ b/applications/NXtranslate/docs/translation.docbook
@@ -0,0 +1,671 @@
+<!-- ******************** TRANSLATION-FILE ******************** -->
+<chapter id="translation-file">
+<title>The Translation File</title>
+
+<para>The file produced by &nxtranslate is entirely determined by the
+contents of the translation file. This chapter discusses the format of
+a translation file as well as listing "location strings" for the
+external formats.</para>
+
+<sect1><title>Overview</title>
+
+<para>Translation files are written in xml and read using an xml
+parser. For this reason they must be a valid xml
+file. <footnote><para>There are many places to find more information
+about XML <ulink
+url="http://www.w3.org/XML/"><citetitle>W3C</citetitle></ulink> is the
+definitive standard while <ulink
+url="http://studio.tellme.com/general/xmlprimer.html"><citetitle>Tellme
+Studio</citetitle></ulink> has a one page overview of what XML
+is.</para></footnote> This means that the following rules must be
+adhered to
+
+<itemizedlist>
+<listitem><para>Every opening tag must have a corresponding closing
+tag at the same level. This means that
+<function><![CDATA[<entry><data></data></entry>]]></function> is
+allowed while
+<function><![CDATA[<entry><data></entry></data>]]></function> and
+<function><![CDATA[<entry><data></data>]]></function> are
+not.</para></listitem>
+<listitem><para>Tags and attribute names are case sensitive. Therefore
+<parameter><![CDATA[<entry>]]></parameter> and
+<parameter><![CDATA[<Entry>]]></parameter> are distinct tags. While this
+can lead to confusion when writing a translation file it is easily
+avoided in practice.</para></listitem>
+<listitem><para>Attribute values must be inside single (') or double (")
+quotes.</para></listitem>
+<listitem><para>Tags and attribute names cannot start with a number or
+special character. Another way of saying this is that the name must start 
+with a letter.</para></listitem>
+<listitem><para>Certain characters will break the parsing of the
+xml. The characters, and how to create them are &lt
+(<function><![CDATA[&lt]]></function>), &gt
+(<function><![CDATA[&gt]]></function>), &amp
+(<function><![CDATA[&amp]]></function>), &quot
+(<function><![CDATA[&quot]]></function>), and &apos
+(<function><![CDATA[&apos]]></function>).</para></listitem>
+<listitem><para>Empty tags,
+<function><![CDATA[<data></data>]]></function>, can be replaced with a
+single tag, <function><![CDATA[<data/>]]></function>. This convenience
+will make more sense during the discussion of translation files when
+specifying information outside of the file.</para></listitem>
+</itemizedlist>
+</para>
+
+<para>There are some other rules to note about the translation
+file. It is not simply a XML file, there are additional
+constraints. However, the translation file is not directly validated
+to follow these constraints, but failing to follow them will result in
+the program exiting early without creating a NeXus file. Also,
+NXtranslate is intended to be used to write any file readable by the
+NeXus API, so the translation file is not validated against definition
+files. <footnote><para>This decision was made on the basis of
+performance since it was determined that most of the time a "standard"
+translation file will be used to convert a large number of
+files.</para></footnote> First some definitions used througout this
+document.
+
+<variablelist><title>Translation file definitions</title>
+
+<varlistentry><term>&napi</term><listitem><para>An abbreviation for the NeXus Abstract Program Interface.</para></listitem></varlistentry>
+
+<varlistentry><term>node</term><listitem><para>A point in the
+hierarchy, it can either contain other nodes (be a parent with
+children) or not (a leaf node). Any pair of opening an closing tags
+represents a single node.</para></listitem></varlistentry>
+
+<varlistentry><term>group</term><listitem><para>A node that contains
+other nodes.</para></listitem></varlistentry>
+
+<varlistentry><term>field</term><listitem><para>A node that does not
+contain other nodes (a leaf node). In other places in NeXus this is
+sometimes refered to as a "data" or a
+"SDS".</para></listitem></varlistentry>
+
+<varlistentry><term><parameter>retriever</parameter></term><listitem><para>An
+object whose job is to retrieve information from a source external to
+the translation file. Which retriever is created is determined by the
+value of &mime-type . The retriever is initialized using the value of
+&source . Information is produced by the retriever using the &location
+.</para></listitem></varlistentry>
+
+<varlistentry><term>special attribute</term><listitem><para>An
+attribute that is interpreted by &nxtranslate as a command to deal
+with external information. The special attributes are &mime-type , &source ,
+&location , and &make-link .</para></listitem></varlistentry>
+
+<varlistentry><term>&mime-type</term><listitem><para>A keyword that
+denotes what library to use to retrieve information from an external
+source. It can be a valid mime type.</para></listitem></varlistentry>
+
+<varlistentry><term>&source</term><listitem><para>A string denoting
+what a retriever should use to initialize itself. This is generally a
+file on the local system for the retriever to
+open. </para></listitem></varlistentry>
+
+<varlistentry><term>&location</term><listitem><para>A string passed to
+the retriever for it to generate data from. For example, when using
+the NeXus retriever this is a path to a particular node in the file
+which will be written out to the resulting NeXus
+file.</para></listitem></varlistentry>
+
+<varlistentry><term>&link-tag</term><listitem><para>This denotes a
+node that is a link to another node in the file. It must have a
+&make-link attribute. All other attributes will be
+ignored</para></listitem></varlistentry>
+
+<varlistentry><term>&make-link</term><listitem><para>The attribute
+denoting what a &link-tag node should be linked to. The syntax for
+describing location is the same as for the <link linkend="nexus">NeXus
+retriever</link>. If this attribute appears in a node other than
+&link-tag it will be treated as a normal
+attribute.</para></listitem></varlistentry>
+
+<varlistentry><term>primative type</term><listitem><para>Any of the
+following types (ignoring bit-length): <parameter>NX_UINT</parameter>
+(unsigned integer), <parameter>NX_INT</parameter> (signed integer),
+<parameter>NX_FLOAT</parameter> (floating point number),
+<parameter>NX_CHAR</parameter> (character),
+<parameter>NX_BOOLEAN</parameter> (boolean, or true/false),
+<parameter>NX_BINARY</parameter> (binary value). At the moment
+<parameter>NX_BOOLEAN</parameter> and <parameter>NX_BINARY</parameter>
+are not supported by &nxtranslate and the NeXus API supports only one
+dimension arrays of <parameter>NX_CHAR</parameter>.
+</para></listitem></varlistentry>
+
+</variablelist>
+</para>
+
+<para>Now that the definitions have been presented the other constraints of a translation file can be explained.
+<itemizedlist>
+
+<listitem><para>The root node in a file will be
+<parameter><![CDATA[<NXroot>]]></parameter>. There will be nothing
+before or after it, and only one of them. The NXroot can be used to
+set global values for &mime-type and &source .</para></listitem>
+
+<listitem><para>Only groups can exist directly inside the
+root. This is a constraint of the NeXus API.</para></listitem>
+
+<listitem><para>Every node (except the <parameter>NXroot</parameter>
+and &link-tag ) needs a <parameter>name</parameter> and
+<parameter>type</parameter>. If the node has a &location then the type
+can be omitted since the retriever will provide it.</para></listitem>
+
+<listitem><para>Groups cannot have any attribute other than the
+special ones. Fields can have any attribute. This reflects a
+restriction in the NeXus API and does not constrain the contents of
+resulting NeXus files in any way.</para></listitem>
+
+<listitem><para>Groups cannot have any data in them. In other words
+things similar to <parameter><![CDATA[<data type="NXdata">1 2 3
+4</data>]]></parameter> are incorrect.</para></listitem>
+
+<listitem><para>To specify the dimensions of a field, use square
+brackets [] affter the type. A single precision floating point array
+with five elements would have
+<parameter>type="NX_FLOAT32[5]"</parameter>. If the field has only one
+element, or is a character array, the dimensions can be left off. For
+character arrays, the dimensions are ignored.</para></listitem>
+
+<listitem><para>To specify the type of a attribute denote the
+primative type separated from the value using square brackets. For
+numeric types only scalars are allowed. If no type is specified it is
+assumed to be a character array (length is determined
+automatically).</para></listitem>
+
+</itemizedlist>
+</para>
+
+
+</sect1>
+
+<sect1 id="simple-translation"><title>Simple Translation</title>
+
+<para>While &nxtranslate is the anything to NeXus translator, it is
+possible to have everything specfied in the translation file. <xref
+linkend="simple-translation-xml"> shows a translation file where no
+information will be taken from any other file.</para>
+
+<example id="simple-translation-xml"><title>Simple translation file <filename>test_simple.xml</filename></title>
+<programlisting role="XML" linenumbering="numbered">
+<![CDATA[<NXroot>
+  <NXentry name="entry1">
+    <NXnote name="note">
+      <author type="NX_CHAR">George User</author>
+      <type type="NX_CHAR">text/plain</type>
+      <data type="NX_CHAR">The data is a simple parabola, f(x)=x^2
+      </data>
+    </NXnote>
+    <NXdata name="parabola_1D">
+      <x type="NX_INT8[11]" axis="NX_INT:1" units="number">
+            0 1 2 3  4  5  6  7  8  9  10
+      </x>
+      <f_x type="NX_INT16[11]" signal="NX_INT:1" units="number">
+            0 1 4 9 16 25 36 49 64 81 100
+      </f_x>
+    </NXdata>
+  </NXentry>
+  <NXentry name="entry2">
+    <NXnote name="note">
+      <author type="NX_CHAR">George User</author>
+      <type type="NX_CHAR">text/plain</type>
+      <data type="NX_CHAR">The data is a two dimensional parabola,
+                           f(x,y)=x^2+y^2</data>
+    </NXnote>
+    <NXdata name="parabola_2D">
+      <x type="NX_FLOAT32[4]" axis="NX_INT:1" units="number">
+           1.0 4.7 2.3 1.6
+      </x>
+      <y type="NX_FLOAT32[3]" axis="NX_INT:2" units="number">
+           3.3 6.2 9.2
+      </y>
+      <f_x_y type="NX_FLOAT64[4,3]" signal="NX_INT:1" axes="x,y" units="number">
+            11.89 32.98 16.18
+            13.45 39.44 60.53
+            43.73 41.00 85.64
+           106.73 89.93 87.20
+      </f_x_y>
+    </NXdata>
+  </NXentry>
+</NXroot>]]>
+</programlisting>
+</example>
+
+<para>This example follows all of the rules laid out in the previous
+section and serves to introduce several of the features of the
+translation file. First a style note though, in XML files there is a
+concept of "ignorable whitespace". These are carriage returns
+(<![CDATA[\n]]>), line feeds (<![CDATA[\r]]>), tabs (<![CDATA[\t]]>),
+and spaces. These are ignored (as suggested by the term "ignorable
+whitespace") and are present to aid those looking at the raw XML to
+see the node hierarchy.</para>
+
+<para>The main purpose of <xref linkend="simple-translation-xml"> is
+to show how to specify information in a translation file. Line 4
+demonstrates the method for strings. Here the
+<parameter>name</parameter> is <parameter>author</parameter> and the
+<parameter>type</parameter> is <parameter>NX_CHAR</parameter>. The
+length of the character array is determined from the actual string
+supplied rather than what is specified in the
+<parameter>type</parameter> attribute. The value is created by reading
+in the supplied string, converting tabs, carriage returns, and line
+feeds into a single space, turning any sections of multiple whitespace
+into a single space, then chopping off any whitespace at both ends of
+the string. This allows the person writting the file to add whitespace
+in strings as needed to make the raw XML easier to read, without
+changing what is written into the final NeXus file.</para>
+
+<para>Next to look at is how arrays of numbers are specified. Lines
+24-27 show both one and two dimensional arrays. The dimension of the
+array is specified with the type as discussed above.  <quote>The thing to
+notice here is that arrays of numbers are specified as comma delimited
+lists. The brackets in the list of values are "syntatic sugar". When
+the values are read in &nxtranslate converts them into commas then
+converts multiple adjacent commas into a single comma. The purpose of
+this is so translation file authors can more easily see each dimension
+of the array that they wrote. The brackets can also be removed
+altogether as seen in line 24.</quote></para>
+
+</sect1>
+
+<sect1 id="nexus-translation"><title>Translation from NeXus</title>
+
+<para>Next is to show how to use NXtranslate to bring in information
+from external sources. <xref linkend="nexus-translation-xml">
+demonstrates various features of importing information from external
+sources, including modifying it before writing.</para>
+
+<example id="nexus-translation-xml"><title>Translation from NeXus file <filename>test_nexus.xml</filename></title>
+<programlisting role="XML" linenumbering="numbered">
+<![CDATA[<NXroot NXS:source="test_simple.nxs" NXS:mime_type="application/x-NeXus">
+  <entry_1D NXS:location="/entry1"/>
+  <entry_2D type="NXentry">
+    <note NXS:location="/entry1/note">
+       <description type="NX_CHAR">The functional form of the data
+             </description>
+    </note>
+    <parabola_2D type="NXdata">
+      <x axis="2" NXS:location="/entry2/parabola_2D/x"/>
+      <y axis="1" NXS:location="/entry2/parabola_2D/y"/>
+      <f_x_y type="NX_FLOAT64[3,4]" axes=""
+            NXS:location="/entry2/parabola_2D/f_x_y"/>
+    </parabola_2D>
+  </entry_2D>
+</NXroot>]]>
+</programlisting>
+</example>
+
+<para>As suggested earlier the root node (line 1) has defined a
+&source and &mime-type to use for creating a retriever. Line 2
+demonstrates that entire entries can be copied from one file to the
+next and that the name of a node can be changed. In this case it is
+from <parameter>entry1</parameter> to
+<parameter>entry_1D</parameter>. Lines 4-7 show how to copy over an
+entire group and add a new field to it. For finer control of what is
+added and have the ability to change attributes look at lines
+9-12. Line 11 shows how to change the dimensions of the field by using
+the <parameter>type</parameter> attribute. Please note that this will
+not work for character arrays and the total number of array items must
+remain constant. Also, the type itself cannot be changed (single
+precision float to double precision float, etc.). Since the dimensions
+of the <parameter>f_x_y</parameter> array change it makes sense to
+change the axes for plotting. This is done in both line 9 and 10 by
+specifying the attribute and its new value. To add another attribute
+just specify it similarly. Line 11 demonstrates erasing the
+<parameter>axes</parameter> attribute. Specify the attribute with an
+empty string as the value.</para>
+
+<para>These two examples have shown the way to set up a translation
+file. You can import information from multiple files by declaring
+another &source and &mime-type . There are a couple of things to know
+about these as well. The default &mime-type is
+"<parameter>application/x-NeXus</parameter>" so it does not need to be
+specified. For each &source , whatever &mime-type was defined in the
+parent node will be used for the current &source . <xref
+linkend="convoluted-translation-xml"> shows what, in principle, could
+be done with &nxtranslate as more retrievers get
+written.<footnote><para>While retrievers that import information from
+mySQL and jpeg images would be nice, they do not currently
+exist.</para></footnote> </para>
+
+<example id="convoluted-translation-xml"><title>A contrived example</title>
+<programlisting role="XML" linenumbering="numbered">
+<![CDATA[<NXroot>
+  <entry1  NXS:source="test_simple.nxs" NXS:location="/entry1">
+    <user type="NXuser" NXS:source="127.0.0.1" NXS:mime_type="mySQL">
+      <name type="NX_CHAR">George User</name>
+      <address NXS:location="query(George User):address"/>
+      <email NXS:location="query(George User):email"/>
+      <phone NXS:location="query(George User):phone"/>
+      <picture NXS:source="GeorgeUser.jpg" NXS:mime_type="img/jpeg" NXS:location="all"/>
+    </user>
+  </entry1>
+  <entry2 NXS:source="test_nexus.nxs" NXS:location="/entry_2D"/>
+</NXroot>]]>
+</programlisting>
+</example>
+
+<sect2 id="links"><title>Anatomy of Links</title>
+
+<para>The two nodes involved in a link are the source and link. The
+source is the original version of the information, the link is the
+copy. There is no way to decipher which is the original and which is
+the copy without direct comparison of ids using the NeXus api. Links
+can be either to a group or field. Links to attributes are not
+supported by the &napi . A link to a group and field are both shown in
+<xref linkend="two-links-xml">. The first link is to a group whose
+name was <parameter>group1</parameter>, while the second link is to a
+field <parameter>array1</parameter>.</para>
+
+<example id="two-links-xml"><title>Two links</title>
+<programlisting role="XML">
+<![CDATA[<NAPIlink target="/entry/group1"/>
+<NAPIlink target="/entry/group1/array1"/>]]>
+</programlisting>
+</example>
+
+</sect2>
+</sect1>
+
+<sect1 id="translation-strings"><title>Strings for Translation</title>
+
+<para>The previous section discussed how to write a translation file
+and several of its features. This section will explain in more detail
+the strings available for use in a translation file. In principle this
+section is incomplete because there may exist retrievers that the
+authors have not been informed of so consider this list
+incomplete. Also, by nature, the retrievers are quite decouple so the
+location strings for each retriever can be significantly different
+from the others.</para>
+
+<sect2 id="nexus"><title>NeXus</title>
+
+<para>As seen earlier in this chapter the &mime-type for NeXus files
+is <parameter>application/x-NeXus</parameter>. Similarly the &location
+strings are as simple as possible. NeXus files are organized
+hierarchically similar to the translation file. A good analogy is to
+compare it to a file system where the groups are directories and the
+fields are files. Using this analogy the &location strings are
+absolute paths to the directory or file to be copied. Since there
+examples of NeXus location strings in <xref
+linkend="nexus-translation-xml"> and <xref
+linkend="convoluted-translation-xml"> there is only one other thing to
+mention, the path separator is a forward slash, "/".
+
+</para>
+
+</sect2>
+
+<sect2 id="text-plain"><title>Simple ASCII</title>
+
+<para>The &mime-type for the simple ASCII retriever is
+<parameter>text/plain</parameter>. The functionality of the simple
+ASCII retriever is limited. This is to emphasize the methodology for
+building retrievers, rather than build a general purpose one. All of
+the location strings are integers defining the line number to use. The
+first line of the file is zero.</para>
+
+</sect2>
+
+<sect2 id="SNS-histogram"><title>SNS Histogram</title>
+
+<para>The &mime-type for the SNS histogram retriever is
+<parameter>application/x-SNS-histogram</parameter>.</para>
+
+<para>The &location is of the general form
+
+<informalexample><programlisting>[...,dim2,dim1][...,dimY,dimX]#{tag_name_1|operator_1}keyword_1{tag_name_2|
+operator2}keyword_2...</programlisting></informalexample>
+
+Notice that the &location is divided into two parts, declaration and
+definition, separated by <parameter>#</parameter>. The declaration
+describes the dimension of the retrieved data. The definition
+describes which information the data consists of. Both of these will
+be described in greated detail below.</para>
+
+<para>The declaration part, <parameter>[...,dim2,dim1][...,dimY,dimX]</parameter> 
+surrounded by square brackets, contains between the first brackets the size of each dimension of the array to be returned, separated by commas, and between the second set of brackets, the dimensions of the array to read from. The values are
+specified as positive integers. The current version of the retriever returns an array of the same size as the initial array, no matter the dimensions given between the first set of brackets.
+</para>
+
+<para>The definition part,
+<parameter>{tag_name_1|operator_1}keyword_1{tag_name_2|operator2}...</parameter>,
+is where selecting the data to be transfered from the SNS histogram
+file is described. Each part of the definition consists of a
+<parameter>tag_name</parameter> and
+<parameter>operator</parameter> separated by a vertical slash <parameter>"|"
+</parameter>. Multiple definitions can exist in a
+single &location separated by <parameter>keyword</parameter>s. If the
+definition is missing, then all of the available data will be
+retrieved.</para>
+
+<para>The possible values for the <parameter>tag_name</parameter> are
+
+<variablelist>
+
+<varlistentry><term><parameter>pixelID</parameter></term>
+<listitem><para>Select using unique pixel identifiers. Applicable for all
+detectors.</para></listitem>
+</varlistentry>
+
+<varlistentry><term><parameter>pixelX</parameter></term>
+<listitem><para>Select using column numbers. Applicable for all area
+detectors</para></listitem>
+</varlistentry>
+
+<varlistentry><term><parameter>pixelY</parameter></term>
+<listitem><para>Select using row numbers. Applicable for all area
+detectors</para></listitem>
+</varlistentry>
+
+<varlistentry><term><parameter>Tbin</parameter></term>
+<listitem><para>Select using time channels. Applicable for all
+detectors</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</para>
+
+<para>The <parameter>operator</parameter> can be of one of two forms
+
+<itemizedlist>
+
+<listitem><para><function>loop(start,end,increment)</function> is used
+to specify a series of identifiers that runs inclusively from
+<parameter>start</parameter> to <parameter>end</parameter> in steps of
+<parameter>increment</parameter>.</para></listitem>
+
+<listitem><para>List of identifiers. The identifiers specify which
+data to include. The identifiers must be separated by commas.</para></listitem>
+
+</itemizedlist>
+
+</para>
+
+<para>The <parameter>keyword</parameter> is used to link various
+declarations together into unions and intersections. Keywords are
+entirely optional. Keywords that work on two definitions are left
+associative.
+
+<variablelist>
+
+<varlistentry><term><parameter>!</parameter></term>
+<listitem><para>The logical "not" operator. This negates the definition
+following it. Must be placed just in front of the curly braces it is
+associated with.</para></listitem></varlistentry>
+
+<varlistentry><term><parameter>()</parameter></term>
+<listitem><para>Grouping operation. This can be used to clarify what
+order multiple keywords are applied. No associative parentheses are allowed within
+the curly braces.</para></listitem></varlistentry>
+
+<varlistentry><term><parameter>AND</parameter></term>
+<listitem><para>The logical "and" operator. This generates the
+intersection of two definitions. This parameter is case sensitive.</para></listitem></varlistentry>
+
+<varlistentry><term><parameter>OR</parameter></term>
+<listitem><para>The logical "or" operator. This generates the union of
+two definitions. This parameter is case sensitive.</para></listitem></varlistentry>
+</variablelist>
+</para>
+
+<variablelist><title>Examples</title>
+
+<varlistentry><term><parameter>[150,256,167][304,256,167]#{pixelID|loop(1,38400,1)}</parameter></term>
+<listitem>
+
+<para>This retrieves the first 38400 pixel identifiers and
+put the data into a 150x256x167 array where the 167 dimension 
+changes the fastest. In this example, there are 167 time channels,
+256 columns, and 150 rows. The data are coming from a binary file where the data
+are stored as a 304x256x167 flat array </para></listitem></varlistentry>
+
+<varlistentry><term><parameter>[50,256,100][304,256,167]#{pixelID|loop(1,12800,1)}AND{Tbin|loop(1,100,1)}</parameter></term>
+<listitem>
+
+<para>This retrieves the union of the first 12800 pixel
+identifiers with the first 100 time channels then places the data into
+a 50x256x100 array. One must keep in mind that if the array declared
+is of a different size than the data defined, an error will be
+generated.</para></listitem></varlistentry>
+
+<varlistentry><term><parameter>[7,167][304,256,167]#{pixelX|45,53,60,61,62,34500,34501}</parameter></term>
+<listitem><para>This retrieves a series of
+columns.</para></listitem></varlistentry>
+
+</variablelist>
+
+
+</sect2>
+
+<sect2 id="text-xml"><title>XML retriever</title>
+
+<para>The &mime-type for the XML retriever is
+<parameter>text/xml</parameter>. The XML retriever is built on top of
+libxml2's document object model (DOM) parser. Because of this the
+entire file for information to be retrived from is loaded into memory
+as a character arrays. The DOM API was chosen to allow for jumping
+around the source file without needed to parse its contents multiple
+times. The location string will be formatted according to the
+following rules:
+
+<itemizedlist>
+
+<listitem><para>The location string for a field will look like a
+(unix) path. Each level of the hierarchy is separated by a forward
+slash, "/".</para></listitem>
+
+<listitem><para>To specify the type the value is preceeded using a
+name separated using a colon, ":". The allowed names are
+"INT8,INT16,INT32,UINT8,UINT16,UINT32,FLOAT32,FLOAT64". If no name is
+specified it is (implicitly) a string. Therefore to get "the_answer"
+as a double precision float the location is
+"FLOAT64:/numbers/the_answer".</para></listitem>
+
+<listitem><para>In the case where the field has a "type" attribute
+with the value being one of the types above that will be used rather
+than as a character array. Specifying the type in the location will
+override what is in the source file.</para></listitem>
+
+<listitem><para>Arrays can be specified as part of the type as either
+an attribute in the XML file or in the location string. To get a six
+element integer array use the location "/numbers/array" which points to a whitespace delimited list. Multiple dimensions are specified by using a comma
+delimited list in the square brackets
+(i.e. "INT16[3,2]:/numbers/array")</para></listitem>
+
+<listitem><para>To get an attribute specify it at the end of a path
+separated by a hash symbol, "#". Therefore to get attr2 as a single
+precision float the location is
+"FLOAT32:/numbers#attr2".</para></listitem>
+
+</itemizedlist>
+
+This methodolgy does not allow for automatically detecting the type of
+an imported attribute (it will be read as a string), or
+differentiating two fields at the same level with the same tag
+name.</para>
+
+<!--
+<example><title>announcement email</title>
+<programlisting role="XML">
+<![CDATA[Everybody,
+
+Rob and I talked some more about this via phone and made some
+decisions. Please object as necessary so the correct thing is
+implemented. Since it was deciding what "special features" the xml
+file could have I will just relist the entire feature set of the
+retriever (now with numbers).
+
+First a new example file:
+
+<numbers attr1="hi">
+  <the_answer attr3="hello" type="INT16">42</the_answer>
+  <the_better_answer attr3="hello">43</the_better_answer>
+  <gravity>9.81</gravity>
+  <gravity>32</gravity>
+  <array type="INT16[5]">0,1,2,3,4</array>
+</numbers>
+<best_units attr2="3.14">
+  furlongs/fortnight
+</best_units>
+
+The (revised methodology)
+
+  (1) XML files will be read using the Document Object Model (DOM)
+  parser provided by libxml2 (libxml2's SAX parser is used by
+  NXtranslate for the translation file). The DOM parser is preferred
+  since the user will (in principle) jump around the file at random to
+  get different bits of information.
+
+  (2) The location string for a field will look like a (unix) path. To
+  get the string "43" with the string attribute "hello" the location
+  is "/numbers/the_better_answer".
+
+  (3) To specify the type the value is preceeded using a name
+  separated using a colon, ":". The allowed names are
+  "INT8,INT16,INT32,UINT8,UINT16,UINT32,FLOAT32,FLOAT64". If no name
+  is specified it is (implicitly) a character array. Therefore to get
+  "the_answer" as a double precision float the location is
+  "FLOAT64:/numbers/the_answer".
+
+  (4) In the case where the field has a "type" attribute with the
+  value being one of the types in (3) that will be used rather than as
+  a character array. Specifying the type in the location will override
+  this.
+
+  (5) Arrays can be specified as part of the type as either an
+  attribute in the XML file or in the location string. To get a five
+  element integer array from the example use the location
+  "/numbers/array". Multiple dimensions are specified by using a comma
+  delimited list in the square brackets (i.e. "INT16[3,2]")
+
+  (6) To get an attribute specify it at the end of a path separated by
+  a hash symbol, "#". Therefore to get "3.14" as a single precision
+  float the location is "FLOAT32:/best_units#attr2".
+
+Problems with this:
+
+  (1) I have no way of figuring out how to get "9.81" rather than
+  "32". The problem is that with a DOM parser the order is not
+  guaranteed to be preserved. Does anyone have a good suggestion of
+  how to do this? Or are we all comfortable saying that the retriever
+  only deals with unique paths? This means that the rest of the
+  information is available, but "number/gravity" will give an
+  undertermined result.
+
+  (2) I don't have a way to define the type for attributes that come
+  automatically (hello in the first example).
+
+P^2]]>
+</programlisting>
+</example>
+-->
+
+</sect2>
+
+</sect1>
+
+</chapter>
diff --git a/applications/NXtranslate/dynamic_retriever.cpp b/applications/NXtranslate/dynamic_retriever.cpp
new file mode 100644
index 0000000..9e5fd87
--- /dev/null
+++ b/applications/NXtranslate/dynamic_retriever.cpp
@@ -0,0 +1,102 @@
+//
+// $Id$
+//
+// NXtranslate Dynamic retriever
+//
+// Freddie Akeroyd, CCLRC ISIS Facility <F.A.Akeroyd at rl.ac.uk>
+//
+// see dynamic_retriever.h for details of interface
+//
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <napiconfig.h>
+#include "node.h"
+#include "node_util.h"
+#include "string_util.h"
+#include "tree.hh"
+#include "dynamic_retriever.h"
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+#define dlopen(a,b)	NULL
+#define dlsym(a,b)	NULL
+#define dlclose(a)	NULL
+#define dlerror()	"Dynamic loading not supported - no <dlfcn.h>"
+#define RTLD_NOW	2
+#endif /* HAVE_DLFCN_H */
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+DynamicRetriever::DynamicRetriever(const string &source, const string& mime_type) : m_mime_type(mime_type), m_dlhandle(NULL), m_ref(NULL)
+{
+    int i = mime_type.find("/");
+    m_module_name = mime_type.substr(i+1);
+    m_dlhandle = dlopen(m_module_name.c_str(), RTLD_NOW);
+    if (m_dlhandle == NULL)
+    {
+	throw invalid_argument("Cannot load " + m_module_name + ": " + dlerror());
+    }
+    // initialize and getdata are required
+    m_init_func = (init_func_t)dlsym(m_dlhandle, "nxtinit");
+    if (m_init_func == NULL)
+    {
+	throw invalid_argument("Cannot find initialize() in " + m_module_name + ": " + dlerror());
+    }
+    m_data_func = (getData_func_t)dlsym(m_dlhandle, "nxtgetdata");
+    if (m_data_func == NULL)
+    {
+	throw invalid_argument("Cannot find getdata() in " + m_module_name + ": " + dlerror());
+    }
+    // freedata and cleanup are optional
+    m_free_func = (free_func_t)dlsym(m_dlhandle, "nxtfreedata");
+    m_cleanup_func = (cleanup_func_t)dlsym(m_dlhandle, "nxtcleanup");
+    // get our unique reference ID to pass to other functions
+    m_ref = (*m_init_func)(source.c_str());
+}
+
+DynamicRetriever::~DynamicRetriever()
+{
+  if (m_ref != NULL && m_cleanup_func != NULL)
+  {
+        (*m_cleanup_func)(m_ref);
+        m_ref = NULL;
+  }
+  if (m_dlhandle != NULL)
+  {
+	dlclose(m_dlhandle);
+	m_dlhandle = NULL;
+  }
+}
+
+void DynamicRetriever::getData(const string &location, tree<Node> &tr)
+{
+  int free_data = 0, rank = 1, dims[NX_MAXRANK], type = NX_CHAR;
+  void* data = NULL;
+  dims[0] = 1;
+
+  data = (*m_data_func)(m_ref, location.c_str(), &type, dims, &rank, &free_data);
+
+  // add an attribute to say where the data came from
+  vector<Attr> attrs;
+  Attr my_attr("translate_source", location.c_str(), 
+               location.length(), NX_CHAR);
+  attrs.push_back(my_attr);
+
+  Node node(location, data, rank, dims, type);
+  node.set_attrs(attrs);
+  tr.insert(tr.begin(),node);
+  if (free_data)
+  {
+	(*m_free_func)(m_ref, data);
+  }
+}
+
+string DynamicRetriever::toString() const
+{
+  return "["+m_mime_type+"]";
+}
diff --git a/applications/NXtranslate/dynamic_retriever.h b/applications/NXtranslate/dynamic_retriever.h
new file mode 100644
index 0000000..2fcfaec
--- /dev/null
+++ b/applications/NXtranslate/dynamic_retriever.h
@@ -0,0 +1,59 @@
+//
+// $Id$
+//
+// Basic NXtranslate dynamic retriever
+//
+// Allows a retriever to be implemented as a dynamic library external to 
+// NXtranslate
+//
+// Author: Freddie Akeroyd, CCLRC ISIS <F.A.Akeroyd at rl.ac.uk>
+//
+// The dynamic library just needs to export the following functions
+//
+// required:
+//
+//    void* nxtinit(const char* source) 
+//    void* nxtgetdata(void* ref, const char* arg, int* data_type, 
+//                     int* dims_array, int* ndims, int* free_data);
+//
+// optional:
+//
+//    void nxtfreedata(void* ref, void* arg)
+//    void nxtcleanup(void* ref)
+//
+//  see "test_dynamic.c" for an example of implementing this
+//
+
+#ifndef __DYNAMIC_RETRIEVER_GUARD
+#define __DYNAMIC_RETRIEVER_GUARD
+
+#include "retriever.h"
+//#include <ltdl.h>
+
+typedef void* (*getData_func_t)(void* ref, const char* arg, int* data_type, int* dims_array, int* ndims, int* free_data);
+typedef int (*free_func_t)(void* ref, void* arg);
+typedef void* (*init_func_t)(const char* source); // returns a "ref"
+typedef int (*cleanup_func_t)(void* ref);
+
+class DynamicRetriever: public Retriever {
+ public:
+  DynamicRetriever(const std::string& source, const std::string& mime_type);
+  ~DynamicRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  DynamicRetriever(const DynamicRetriever&);
+  DynamicRetriever& operator=(const DynamicRetriever&);
+  std::string m_module_name; // name of dynamic library
+  std::string m_mime_type;   // mime type of library
+//  lt_dlhandle m_dlhandle;    // reference to loaded shared library
+  void*  m_dlhandle;    // reference to loaded shared library
+  getData_func_t m_data_func;
+  free_func_t m_free_func;
+  init_func_t m_init_func;
+  cleanup_func_t m_cleanup_func;
+  void* m_ref; // internal reference pointer returned by dynamic module
+};
+
+#endif
diff --git a/applications/NXtranslate/esrf_edf/CMakeLists.txt b/applications/NXtranslate/esrf_edf/CMakeLists.txt
new file mode 100644
index 0000000..bee51ce
--- /dev/null
+++ b/applications/NXtranslate/esrf_edf/CMakeLists.txt
@@ -0,0 +1,32 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (Edf STATIC edf_reader.cpp edf_reader.h edf_retriever.cpp edf_retriever.h)
+
diff --git a/applications/NXtranslate/esrf_edf/Makefile.am b/applications/NXtranslate/esrf_edf/Makefile.am
new file mode 100644
index 0000000..1047cae
--- /dev/null
+++ b/applications/NXtranslate/esrf_edf/Makefile.am
@@ -0,0 +1,42 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id: Makefile.am,v 1.3 2005/11/15 22:05:48 pfp Exp $
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libEdf.la
+
+libEdf_la_SOURCES = \
+	edf_reader.cpp  edf_reader.h  \
+	edf_retriever.cpp  edf_retriever.h
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/esrf_edf/edf_reader.cpp b/applications/NXtranslate/esrf_edf/edf_reader.cpp
new file mode 100644
index 0000000..0c629d1
--- /dev/null
+++ b/applications/NXtranslate/esrf_edf/edf_reader.cpp
@@ -0,0 +1,385 @@
+//+**********************************************************************
+//
+// File:	edf_reader.cpp
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	implementation of a edf_reader class. It is a library,
+//              which makes possible reading data from EDF format.
+//		EDF file is read using the constructor of the class.
+//              Every key-values pairs from the header are stored   
+//              in the one of two dictionaries(private members).
+//              Image is read into the memory allocated dynamically, 
+//              and a pointer on that memory is a class's private 
+//              member.
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	April 2006
+//
+//+**********************************************************************
+
+#include "edf_reader.h"
+
+using namespace std;
+
+/**
+* Destructor method. It realese memory allocated for the image. 
+*/
+edf_reader::~edf_reader(){
+    //
+    // release the image array
+    //
+    delete [] image;  
+}
+
+/**
+* Initial constructor 
+*/    
+edf_reader::edf_reader(){
+    key_double.clear();
+    key_string.clear();
+    header_numbers[0]=0;
+    header_numbers[1]=0;
+    header_numbers[2]=0;
+}
+
+/**
+* Constructor responsible for reading data from the EDF file.
+* It reads data from the header and stores key-value pairs in dictionry.
+* Also EDF image is read.
+*/
+edf_reader::edf_reader(ifstream &in){
+    
+    char buffer[256], value_string[256];
+    double value;
+    char a = ' ';
+    bool is_header = 0;
+    int dim1, dim2;
+    //
+    //read first character from the file
+    //
+    in.get(a);
+    //
+    // read file until bace closing the header is met
+    //
+    while(in.peek()!='}'){
+        //
+	//prevention from corrupted bits in file
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(buffer, 255);
+            break;
+        }
+	//
+	//check if the header begins
+	//
+	if((a=='{') || is_header==1){
+	    //
+	    //set flag if first time in the loop 
+	    //
+	    if(!is_header){
+	        in.get(a);
+	        is_header = 1;
+	    }
+	    //
+	    //get key 
+	    //
+	    in.getline(buffer, 255,' ');
+	    string key(buffer);
+	    //
+	    //check if key corresponds to float value
+	    //
+	    if(!strcmp(buffer,"Center_1")||!strcmp(buffer,"Center_2")||!strcmp(buffer,"DDummy")||!strcmp(buffer,"Dummy")||!strcmp(buffer,"Offset_2")||!strcmp(buffer,"Psize_1")||!strcmp(buffer,"Psize_2")||!strcmp(buffer,"SampleDistance")||!strcmp(buffer,"SaxsDataVersion")||!strcmp(buffer,"WaveLength")||!strcmp(buffer,"EDF_BinarySize")||!strcmp(buffer,"Image")||!strcmp(buffer, "Offset_1")) {
+	        
+	        //
+		//get value corresponding to key
+		//
+		in.getline(buffer, 255, '=');
+		while(in.peek()==' ')in.ignore(1,'\n');
+                in >> value;
+		//
+		//store pairs key-double value in key_double dictionary
+		//
+		key_double.insert(pair<string, double>(key, value));        
+	    }
+	    
+	    //
+	    //get dimension separately and store in dictionary
+	    //
+	    
+	    else if(!strcmp(buffer,"Dim_1")){
+	        in.getline(buffer, 255, '=');
+		while(in.peek()==' ')in.ignore(1,'\n');
+                in >> value;
+		dim1 = (int)value;
+		(void)dim1; // TODO unused varable - quiet warnings
+		key_double.insert(pair<string, double>(key, value));	            
+	    }
+	    
+	    //
+	    //get dimension separately and store in dictionary
+	    //
+	    
+	    else if(!strcmp(buffer,"Dim_2")){
+	        in.getline(buffer, 255, '=');
+		while(in.peek()==' ')in.ignore(1,'\n');
+                in >> value;
+		dim2 = (int)value;
+		(void)dim2; // TODO unused varable - quiet warnings
+		key_double.insert(pair<string, double>(key, value));	            
+	    }
+	    
+	    //
+	    //get size of image, store in the dictionary as well as in image_size field
+	    //it is used to allocate space for EDF image in the memory
+	    //
+	    
+	    else if(!strcmp(buffer,"Size")){
+	        in.getline(buffer, 255, '=');
+		while(in.peek()==' ')in.ignore(1,'\n');
+                in >> value;
+		image_size = (int)value;
+		key_double.insert(pair<string, double>(key, value));	            
+	    }
+	    
+	    //
+	    //in case of HeaderID store in separate fields, not in dictionary
+	    //
+	    
+	    else if(!strcmp(buffer,"HeaderID")){
+	        in.getline(buffer, 255, ':');
+	        in >> header_numbers[0];
+		in.getline(buffer, 255, ':');
+		in >> header_numbers[1];
+		in.getline(buffer, 255, ':');
+		in >> header_numbers[2];		
+		in.getline(buffer, 255, ';');
+	    }
+	    
+	    //
+	    //values corresponding to the rest of keys store in key_string diciotnary
+	    //
+	    
+	    else{
+	        if(!strcmp(buffer," ")||!strcmp(buffer,"\n")||strlen(buffer)==0){
+                    in.get(buffer, 255);
+                }
+                else{
+                    in.getline(buffer, 255, '=');
+                    while(in.peek()==' ')in.ignore(1,'\n');
+                    in.getline(value_string, 255,';');
+		    //
+		    //store pairs key-double value in key_string dictionary
+		    //
+		    key_string.insert(pair<string, string>(key, value_string));       
+	        }
+	    }
+	    
+	    //
+	    //go to next line    
+	    //
+	    do{
+	        in.get(a);
+	    } while(a!='\n');
+	}	    
+    }
+    //
+    //after header was read, read the image
+    //
+    try{
+        //
+	//allocate memory for the image
+        //
+	image = new char [image_size]; 
+    }catch (bad_alloc xa){
+        cout<<"Allocation Failure\n";
+	exit(1);
+    }
+    //
+    //go at the beginning of the image
+    //
+    in.getline(buffer, 255, '\n');
+    //
+    //read the image into the buffer
+    //
+    in.read(image, image_size);
+    //
+    //reset flags in stream for EOF
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    //
+    //rewind at the beginnig of the file
+    //
+    in.seekg(0, ios::beg);
+}
+
+
+/**
+* Method returns current header value.
+*/
+int edf_reader::get_current_headerID(){
+    
+    return header_numbers[0];
+
+}
+
+/**
+* Method returns previous header value.
+*/
+int edf_reader::get_previous_headerID(){
+    
+    return header_numbers[2];
+
+}
+
+/**
+* Method returns next header value.
+*/
+int edf_reader::get_next_headerID(){
+    
+    return header_numbers[1];
+
+}
+
+/**
+* Method returns pointer to the EDF image.
+*/
+char* edf_reader::get_image(){
+    
+    return image;
+
+}
+
+/**
+* Method returns size of the image.
+*/
+int edf_reader::get_image_size(){
+    
+    return image_size;
+
+}
+
+/**
+* Method returns number of entries in the key-double_values dictionary.
+*/
+int edf_reader::size_map_double(){
+
+    return key_double.size();
+
+}
+
+/**
+* Method returns number of entries in the key-string_values dictionary.
+*/
+int edf_reader::size_map_string(){
+
+    return key_string.size();
+
+}
+
+/**
+* Method returns the name of the key and corresponding value
+* from key-double_value dictionary. The key number parameter decides
+* which key is read.
+* Parameters: input - int key_number
+*             output - double value
+* Returns: string of the key
+*/
+string edf_reader::get_key_double(int key_number, double &value){
+    
+    map<string, double>::iterator p;
+    //
+    //set iterator at the beginning of the dictionary
+    //
+    p = key_double.begin();
+    //
+    //go to   invoked pair
+    //
+    for(int i=1; i<key_number; i++)p++;
+    //
+    //read value
+    //
+    value = p->second;
+    //
+    //return key
+    //
+    return p->first;
+
+}
+
+/**
+* Method returns the name of the key and corresponding value
+* from key-string_value dictionary. The key number parameter decides
+* which key is read.
+* Parameters: input - int key_number
+*             output - string value
+* Returns: string name of the key
+*/
+string edf_reader::get_key_string(int key_number, string &value){
+
+    map<string, string>::iterator p;
+    p = key_string.begin();
+    for(int i=1; i<key_number; i++)p++;    
+    value = p->second;
+    
+    return p->first;
+
+}
+
+/**
+* Method returns value corresponding to the key invoked by name(not position),
+* from key-double_value dictionary. 
+* Parameters: input - string key
+*             output - double value
+* Returns: true if key value was found, false otherwise
+*/
+bool edf_reader::double_by_key(string key, double &value){
+
+    bool exist=0;
+    map<string, double>::iterator p;
+    //
+    //look for key
+    //
+    p = key_double.find(key);
+    //
+    //key_double.end() is set if thekey does not exist in the dictionary
+    //
+    if(p!=key_double.end()){
+        //
+	//read the value corresponding to the key
+	//
+	value = p->second;
+	//
+	//key exist in the dictionary
+	//
+	exist=1;
+    }
+    
+    return exist;
+}
+
+/**
+* Method returns value corresponding to the key invoked by name(not position),
+* from key-string_value dictionary. 
+* Parameters: input - string key
+*             output - string value
+* Returns: true if key value was found, false otherwise
+*/
+bool edf_reader::string_by_key(string key, string &value){
+    
+    bool exist=0;
+    map<string, string>::iterator p;
+    
+    p = key_string.find(key);
+    
+    if(p!=key_string.end()){
+        value = p->second;
+	exist=1;
+    }    
+    return exist;
+}
+
diff --git a/applications/NXtranslate/esrf_edf/edf_reader.h b/applications/NXtranslate/esrf_edf/edf_reader.h
new file mode 100644
index 0000000..153ddd4
--- /dev/null
+++ b/applications/NXtranslate/esrf_edf/edf_reader.h
@@ -0,0 +1,66 @@
+//+**********************************************************************
+//
+// File:	edf_reader.h
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	definition of a edf_reader class. It is a library,
+//              which makes possible reading data from EDF format.
+//		EDF file is read using the constructor of the class.
+//              Every key-values pairs from the header are stored   
+//              in the one of two dictionaries(private members).
+//              Image is read into the memory allocated dynamically, 
+//              and a pointer on that memory is a class's private 
+//              member.
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	April 2006
+//
+//+**********************************************************************
+
+#ifndef EDF_READER_H
+#define EDF_READER_H 
+
+#include <iostream> 
+#include <fstream>
+#include <map>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+
+using namespace std; 
+
+
+class edf_reader
+{
+    private:
+        
+        int header_numbers[3];
+        map<string, double>key_double;
+	map<string, string>key_string;
+        int image_size;
+	char *image;
+    
+    public:
+        
+        ~edf_reader();
+        edf_reader();
+        edf_reader(ifstream &in);
+	int get_current_headerID();   
+        int get_previous_headerID();
+	int get_next_headerID();
+	int size_map_double();
+        int size_map_string();
+	char* get_image();
+	int get_image_size();
+	string get_key_double(int key_number, double &value);
+        string get_key_string(int key_number, string &value);
+        bool double_by_key(string key, double &value);
+        bool string_by_key(string key, string &value);
+};
+
+
+
+#endif
+
diff --git a/applications/NXtranslate/esrf_edf/edf_retriever.cpp b/applications/NXtranslate/esrf_edf/edf_retriever.cpp
new file mode 100644
index 0000000..c701cdb
--- /dev/null
+++ b/applications/NXtranslate/esrf_edf/edf_retriever.cpp
@@ -0,0 +1,308 @@
+//+**********************************************************************
+//
+// File:	edf_retriever.cpp
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	code for implementing a retriever of data from edf files.
+//		It is added into NXtranslate program in the form of plugin. 
+//              By parsing a XML configuration file of
+//              NXtranslate program using this plugin, data from EDF image 
+//              header as well as the image itself can be read and stored
+//              in NeXus file.
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	April 2006
+//
+//+**********************************************************************
+
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include "edf_retriever.h"
+#include "edf_reader.h"
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+//
+//delimiter used to separate statements in location parameter.
+//used in command parser
+//
+#define DELIMITER ':'    
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+
+/** 
+* Fuction parses location command from .xml configuration file.
+* Command can be of the form letter or letter:variable_name.
+* It does all the checkins for correctness of the command. There are
+* only three letters allowed "A", "I", "S". Only in case of letter "S"(single label),
+* variable_name parameter can be in the location.
+* Parameters: input - string location(command)
+*             output - char* key, 
+* Returns: 0 in case of A letter, 1 in case of S letter, 
+* 2 in case of L letter.
+* In case of any other labels error will occur. 
+*/
+int command_parser(const string &location, char* key){
+   
+    int if_label=0; //initialization of flag 
+    int size = location.size(); //check size of command string
+    //
+    //location cannot be empty
+    //
+    if(size<=0)
+        throw invalid_argument(" cannot parse empty string ");
+    // 
+    //label only of the form A(all paramters from header) S:key(value for the given key is saved)	
+    // or I(only image saved)
+    //
+    if(location[0]!='A' && location[0]!='S' && location[0]!='I')
+        throw invalid_argument(" bad location parameter only A , I or S:key are allowed ");    
+    //
+    //check syntax for All keys and Image location(only letter A or I allowed)	
+    //
+    if(location[0]=='A' || location[0]=='I'){
+        if(size!=1)
+            throw invalid_argument(" for all only A for image only I ");
+    }
+    //
+    //check syntax for Single key location(syntax-> S:key)
+    //
+    if(location[0]=='S'){
+        if(size<3 || location[1]!=DELIMITER)
+            throw invalid_argument(" Bad syntax. Correct syntax: S:key ");
+    } 
+    //  
+    //case for Single key
+    //
+    if(location[0]=='S'){
+        for(int i=2; i<size; i++){
+            key[i-2]=location[i];//subscribe key
+	}
+	key[size-2]='\0';
+	if_label=1;
+    }
+    //
+    //case for Image 
+    //
+    if(location[0]=='I'){
+	if_label=2;
+    }
+    return if_label;  //returns 2 for Image, 1 for Single key, 0 All
+}
+
+
+
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+EdfRetriever::EdfRetriever(const string &str): source(str){
+    
+    //
+    // open the file
+    //
+    infile.open(source.c_str());
+    //
+    // check that open was successful
+    //
+    if(!infile.is_open())
+        throw invalid_argument("Could not open file: "+source);
+
+}
+
+/**
+* Destructor is closing the file opened for reading.
+*/
+EdfRetriever::~EdfRetriever(){
+    //
+    // close the file
+    //
+    if(infile)
+        infile.close();
+}
+
+/**
+* This is the method for retrieving data from a file. The whole
+* tree will be written to the new file immediately after being
+* called. Interpreting the string is made by command_parser method.
+*/
+void EdfRetriever::getData(const string &location, tree<Node> &tr){
+
+    char key[256];//variable for holding variable name
+    int label_case = command_parser(location, key);//parse location, and check for case with label
+    //
+    //case for single label  
+    //
+    if(label_case==1){
+        double double_value;    
+        string string_value;
+        int dims[1]={0};
+        edf_reader Edf = edf_reader(infile);//parse edf file and built object with header values
+	string key_string(key);//built string from the name of variable
+	//
+	//go thru the whole double value dictionary and look for key
+	//if key exists read double value, and store in the NeXus file in the place from which it was invoked
+	//
+	if(Edf.double_by_key(key_string, double_value)){
+            
+	    double valueD[1]={double_value}; 	
+	    dims[0] = 1;	
+	    Node node(key, (void*)valueD, 1, dims, NX_FLOAT64);
+            tr.insert(tr.begin(),node);
+	}
+	else {
+	
+	//
+	//go thru the whole string dictionary and look for key
+	//if key exists read string value, and store in the NeXus file in the place from which it was invoked
+	//    
+	    if(Edf.string_by_key(key_string, string_value)){
+		
+	        const int size=string_value.size();//check size of string
+	        std::vector<char> valueS(size);
+		for(int i=0; i<size; i++){
+		    valueS[i]=string_value[i];//translate C++ string into C-style string, NXtranslate convetion
+		}
+		dims[0]=size;
+		Node node(key, (void*)&(valueS[0]), 1, dims, NX_CHAR);
+                tr.insert(tr.begin(),node);	        
+	    }
+	    //
+	    //key does not exist in any of both dictionaries, store empty string
+	    //
+	    else{
+	    
+	        cout<<" Key "<<key_string<<" does not exist in the header. Empty string is saved.\n";
+	        char empty[1];
+		Node node(key, (void*)empty, 1, dims, NX_CHAR);
+                tr.insert(tr.begin(),node);	    
+	    
+	    }    	
+	}
+    }
+    //
+    //case of single Image(I letter)
+    //
+    else if(label_case==2){
+        //
+	//read EDF file and create object with header values and image
+	//
+	edf_reader Edf = edf_reader(infile);
+	//
+	//check the size of image
+	//
+	int image_dim[1]={Edf.get_image_size()};
+        //
+	//store image in the place of the NeXus hierarchy from the command was invoked in .xml file
+	//
+	Node node_data("Image", (void*)Edf.get_image(), 1, image_dim, NX_INT8);
+	tr.insert(tr.end(),node_data);        
+    
+    }
+    //
+    //case for storing every keys from header with an image
+    //
+    else{
+        
+        double valueD[1];
+        double double_value;    
+        string string_value;
+	int dims1[1]={1};
+        //
+	//create object with header values and Image
+	//
+	edf_reader Edf = edf_reader(infile);
+	string key;
+	//
+	//get size of both dictionaries
+	//
+	int double_map_size = Edf.size_map_double();
+        int string_map_size = Edf.size_map_string();
+	//
+	//iterators used for creation of hierarchical subtree
+	//
+	tree<Node>::iterator root, log, data;
+	//
+	//create NXentry root group, in the place where command was invoked,  
+	//
+	Node node("empty", "NXentry"); 
+	root = tr.insert(tr.end(),node);//insert root to the tree
+	//
+	//create NXlog group for storing header values
+	//group is a sub group of NXentry root group
+	//
+	Node log_node("EDF_log", "NXlog"); 
+	log = tr.append_child(root,log_node);
+        //
+	//create NXdata group for storing EDF image
+	//group is a sub group of NXentry root group		
+	//
+	Node data_node("EDF_image", "NXdata"); 
+	data = tr.append_child(root,data_node);	
+	//
+	//get every keys and values from dicitonary of double values
+	//
+	for(int i=1; i<double_map_size+1; i++){
+	    key=Edf.get_key_double(i, double_value);
+	    valueD[0]=double_value;
+	    //
+	    //store pairs key-double value in NXlog group
+	    //
+	    Node node_child(key, (void*)valueD, 1, dims1, NX_FLOAT64);
+            tr.append_child(log,node_child);	    
+	}
+        //
+	//get every keys and values from dicitonary of string values
+	//
+	for(int i=1; i<string_map_size+1; i++){
+	    key=Edf.get_key_string(i, string_value);
+	    int size=string_value.size();
+	    dims1[0]=size;
+	    std::vector<char> valueS(size);
+	    //  
+	    //convert C++ string into C-style string, NXtranslate convention
+	    //
+	    for(int i=0; i<size; i++){
+	        valueS[i]=string_value[i];
+            }
+	    //
+	    //store pairs key-string value in NXlog group
+	    //
+	    Node node_child(key, (void*)&(valueS[0]), 1, dims1, NX_CHAR);
+            tr.append_child(log,node_child);	    
+	}
+	//
+	//prepare image size 
+	//
+	int image_dim[1]={Edf.get_image_size()};
+        //
+	//store edf-image in NXdata group
+	//
+	Node node_data("Image", (void*)Edf.get_image(), 1, image_dim, NX_INT8);
+	tr.append_child(data,node_data);
+    }
+}	
+//
+//indicate mime type
+//
+const string EdfRetriever::MIME_TYPE("edf");
+
+string EdfRetriever::toString() const{
+    return "["+MIME_TYPE+"] "+source;
+}
+ 
diff --git a/applications/NXtranslate/esrf_edf/edf_retriever.h b/applications/NXtranslate/esrf_edf/edf_retriever.h
new file mode 100644
index 0000000..7eaae04
--- /dev/null
+++ b/applications/NXtranslate/esrf_edf/edf_retriever.h
@@ -0,0 +1,37 @@
+//+**********************************************************************
+//
+// File:	edf_retriever.h
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	definition of a edf_retriever class. The retriever allows to
+//              read data from EDF file and store in Nexus file format.
+//		It is a plugin of NXtranslate program. 
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	April 2006
+//
+//+**********************************************************************
+
+
+#ifndef __EDF_RETRIEVER_GUARD
+#define __EDF_RETRIEVER_GUARD
+
+#include "../retriever.h"
+#include <fstream>
+//
+// this is not intended to be inherited from
+//
+class EdfRetriever: public Retriever{
+ public:
+  EdfRetriever(const std::string &);
+  ~EdfRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  std::string source;
+  std::ifstream infile;
+};
+#endif
diff --git a/applications/NXtranslate/hrcs1797.run b/applications/NXtranslate/hrcs1797.run
new file mode 100644
index 0000000..e7f4256
Binary files /dev/null and b/applications/NXtranslate/hrcs1797.run differ
diff --git a/applications/NXtranslate/loopy/CMakeLists.txt b/applications/NXtranslate/loopy/CMakeLists.txt
new file mode 100644
index 0000000..df18b42
--- /dev/null
+++ b/applications/NXtranslate/loopy/CMakeLists.txt
@@ -0,0 +1,32 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (Loopy STATIC retriever.cpp retriever.h)
+
diff --git a/applications/NXtranslate/loopy/Makefile.am b/applications/NXtranslate/loopy/Makefile.am
new file mode 100644
index 0000000..e3e0ebc
--- /dev/null
+++ b/applications/NXtranslate/loopy/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libLoopy.la
+
+libLoopy_la_SOURCES = \
+        retriever.cpp retriever.h
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/loopy/retriever.cpp b/applications/NXtranslate/loopy/retriever.cpp
new file mode 100644
index 0000000..60d2042
--- /dev/null
+++ b/applications/NXtranslate/loopy/retriever.cpp
@@ -0,0 +1,255 @@
+#include <stdexcept>
+#include "napiconfig.h"
+#include "retriever.h"
+#include "../string_util.h"
+
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+
+
+/**
+ * \file NXtranslate/retriever.cpp
+ */
+
+/**
+ * All nodes returned by LoopyRetriever::getData will have this name.
+ */
+static const string NAME("loopy");
+
+/**
+ * This is the constructor for the object. No resources are allocated.
+ *
+ * \param str The source string is ignored, but necessary to implement
+ * the interface.
+ */
+LoopyRetriever::LoopyRetriever(const string &str)
+{
+  // there is nothing to allocate
+}
+
+/**
+ * Since no resources were allocated, the destructor does nothing
+ */
+LoopyRetriever::~LoopyRetriever()
+{
+  // there is nothing to deallocate
+}
+
+/**
+ * Converts a string describing a type into an enumeration.
+ *
+ * \param type The string version of the type.
+ *
+ * \return The integer from the napi.h enumeration.
+ */
+static int str_to_type(const string &type){
+  if(type.find("INT8")==0)
+    {
+      return NX_INT8;
+    }
+  else if(type.find("INT16")==0)
+    {
+      return NX_INT16;
+    }
+  else if(type.find("INT32")==0)
+    {
+      return NX_INT32;
+    }
+  else if(type.find("UINT8")==0)
+    {
+      return NX_UINT8;
+    }
+  else if(type.find("UINT16")==0)
+    {
+      return NX_UINT16;
+    }
+  else if(type.find("UINT32")==0)
+    {
+      return NX_UINT32;
+    }
+  else if(type.find("UINT32")==0)
+    {
+      return NX_UINT32;
+    }
+ else if(type.find("FLOAT32")==0)
+   {
+     return NX_FLOAT32;
+   }
+ else if(type.find("FLOAT64")==0)
+   {
+     return NX_FLOAT64;
+   }
+  throw invalid_argument("Do not understand type:"+type);
+}
+
+/**
+ * Does the mathematics involved in filling the data array. This is
+ * done according to the equation:
+ * \f[
+ * data[i]=delta i + offset
+ * \f]
+ * where \f$i\f$ is the looping variable
+ *
+ * \param data reference to the allocated data array to be filled
+ * \param offset is the constant to be added to each value
+ * \param delta is the constant spacing between values
+ * \param num the number of values to put into the array
+ */
+template <typename NumT>
+void
+fill_array(void *&data, const NumT offset, const NumT &delta, const int num){
+  // the looping variable is an int because NeXus holds the data
+  // length as an int.
+  for( int i=0 ; i<num ; i++ )
+    {
+      (static_cast<NumT *>(data))[i]=(delta*static_cast<NumT>(i)+offset);
+    }
+}
+
+/**
+ * This is the method for retrieving data from a file. The string must
+ * be of the form "type:offset,delta,number".
+ *
+ * \param location is the string that is used by the retriever to
+ * create the data.
+ * \param tr is the tree to put the result into.
+ */
+void LoopyRetriever::getData(const string &location, tree<Node> &tr)
+{
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    {
+      throw invalid_argument("cannot parse empty string");
+    }
+
+  // check that it has the correct number of colons
+  if(string_util::count_occur(location,":")!=1)
+    {
+      throw invalid_argument("location must contain only one colon");
+    }
+
+  // check that it has 
+  if(string_util::count_occur(location,",")!=2)
+    {
+      throw invalid_argument("location must contain only two commas");
+    }
+
+  string::size_type index;
+
+  // split the string into type and loop information
+  index=location.find(":");
+  string type=location.substr(0,index);
+  string loopinfo=location.substr(index+1);
+
+  // split the loop parameters into separate strings
+  index=loopinfo.find(",");
+  string offset_str=loopinfo.substr(0,index);
+  loopinfo=loopinfo.substr(index+1);
+  index=loopinfo.find(",");
+  string delta_str=loopinfo.substr(0,index);
+  string num_str=loopinfo.substr(index+1);
+
+  // create the dimensions array - this can throw an exception
+  int dims[]={static_cast<int>(string_util::str_to_int(num_str))};
+
+  // convert the type to an integer
+  int int_type=str_to_type(type);
+
+  // get memory for the data
+  void *data;
+  if(NXmalloc(&data,1,dims,int_type)!=NX_OK)
+    {
+      throw runtime_error("NXmalloc failed");
+    }
+
+  // fill the data array
+  if(int_type==NX_INT8)
+    {
+      fill_array(data,
+                 static_cast<int8_t>(string_util::str_to_int(offset_str)),
+                 static_cast<int8_t>(string_util::str_to_int(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_INT16)
+    {
+      fill_array(data,
+                 static_cast<int16_t>(string_util::str_to_int(offset_str)),
+                 static_cast<int16_t>(string_util::str_to_int(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_INT32)
+    {
+      fill_array(data,
+                 static_cast<int32_t>(string_util::str_to_int(offset_str)),
+                 static_cast<int32_t>(string_util::str_to_int(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_UINT8)
+    {
+      fill_array(data,
+                 static_cast<uint8_t>(string_util::str_to_uint(offset_str)),
+                 static_cast<uint8_t>(string_util::str_to_uint(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_UINT16)
+    {
+      fill_array(data,
+                 static_cast<uint16_t>(string_util::str_to_uint(offset_str)),
+                 static_cast<uint16_t>(string_util::str_to_uint(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_UINT32)
+    {
+      fill_array(data,
+                 static_cast<uint32_t>(string_util::str_to_uint(offset_str)),
+                 static_cast<uint32_t>(string_util::str_to_uint(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_FLOAT32)
+    {
+      fill_array(data,
+                 static_cast<float>(string_util::str_to_float(offset_str)),
+                 static_cast<float>(string_util::str_to_float(delta_str)),
+                 dims[0]);
+    }
+  else if(int_type==NX_FLOAT64)
+    {
+      fill_array(data,
+                 static_cast<double>(string_util::str_to_float(offset_str)),
+                 static_cast<double>(string_util::str_to_float(delta_str)),
+                 dims[0]);
+    }
+
+  // create the node - this copies the data
+  Node node=Node(NAME,data,1,dims,int_type);
+  // insert the data into the tree
+  tr.insert(tr.begin(),node);
+
+  // delete the data
+  if(NXfree(&data)!=NX_OK)
+    {
+      throw runtime_error("NXfree failed");
+    }
+
+}
+
+/**
+ * The MIME_TYPE is necessary so the retriever can be selected by the
+ * factory.
+ */
+const string LoopyRetriever::MIME_TYPE("loopy");
+
+/**
+ * This function returns a string representation of the retriever for
+ * debugging. Since no resources are allocated the string is always
+ * identical.
+ *
+ * \return The string returned is always "[loopy]".
+ */
+string LoopyRetriever::toString() const
+{
+  return "["+MIME_TYPE+"] ";
+}
diff --git a/applications/NXtranslate/loopy/retriever.h b/applications/NXtranslate/loopy/retriever.h
new file mode 100644
index 0000000..5642fd5
--- /dev/null
+++ b/applications/NXtranslate/loopy/retriever.h
@@ -0,0 +1,23 @@
+#ifndef __LOOPY_RETRIEVER_GUARD
+#define __LOOPY_RETRIEVER_GUARD
+
+#include "../retriever.h"
+
+/**
+ * The loopy retriever creates an array based on information supplied
+ * in the location string. There are no resources allocated.
+ */
+// this is not intended to be inherited from
+class LoopyRetriever: public Retriever{
+ public:
+  LoopyRetriever(const std::string &);
+  ~LoopyRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const; // done
+  static const std::string MIME_TYPE; // done
+ private: // do not allow these automatically created functions to be called
+  LoopyRetriever(const LoopyRetriever&); //copy constructor
+  LoopyRetriever& operator=(const LoopyRetriever&); //operator "=" overloading
+};
+
+#endif
diff --git a/applications/NXtranslate/main.cpp b/applications/NXtranslate/main.cpp
new file mode 100644
index 0000000..2a95b30
--- /dev/null
+++ b/applications/NXtranslate/main.cpp
@@ -0,0 +1,243 @@
+#include <fstream>
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <string>
+#include <cstring>
+#include "xml_parser.h"
+#include <napi.h>
+#include "string_util.h"
+#include <cstdio>
+
+using std::cout;
+using std::endl;
+using std::find;
+using std::string;
+using string_util::starts_with;
+
+static const string TRANSLATE_VERSION="0.3.0";
+
+// structure to hold options
+typedef struct{
+  string infile;
+  string outfile;
+  NXaccess base;
+  bool append;
+  bool timing;
+  std::map<string,string> map;
+}Options;
+
+// constant argument for this file
+static const string EQUAL="=";
+
+static bool is_equal(char c){
+  return find(EQUAL.begin(),EQUAL.end(),c)!=EQUAL.end();
+}
+
+// the return string is the first part, the argument is missing it and an EQUAL
+static string split(string& str){
+  typedef string::size_type string_size;
+  string_size i=0;
+
+  // find the break
+  while(i<str.size() && !is_equal(str[i]))
+    i++;
+
+  // perform the split
+  string result=str.substr(0,i);
+  str.erase(0,i+1);
+
+  return result;
+}
+
+/*
+ * This takes a string and trims off the flag and returns what is left
+ */
+static void trim_arg(string &arg, const string &flag){
+
+  // trim off the flag
+  arg.erase(0,flag.size());
+
+  // check that there is something left
+  if(arg.size()<=0)
+    return;
+
+  // trim off the equal sign (if there)
+  if(starts_with(arg,EQUAL))
+    arg.erase(0,1);
+}
+
+static void print_version(){
+  cout << "nxtranslate (NXtranslate) version " << TRANSLATE_VERSION << endl;
+  cout << endl;
+  cout << "Copyright (c) 2004-2006, P.F.Peterson <petersonpf at ornl.gov>" << endl;
+  cout << "NXtranslate can be copied under the terms of the \"MIT License\", which may be " << endl;
+  cout << "found in the source distribution." << endl;
+}
+
+static void print_help(const string &progname, int level){
+  print_version();
+  cout << endl;
+
+  cout << "USAGE: " << progname << " [filename] <options>" << endl;
+
+  if(level<1) return;
+
+  cout << endl;
+  cout << "OPTIONS:" << endl;
+  cout << " --help        Print out this message and exit" << endl;
+  cout << " --version     Print out the version and exit" << endl;
+  cout << "  -o <outfile> Specify output file. The default is the translation file with\n"
+       << "               \".nxs\" appended." << endl;
+  cout << " --append <outfile> Specify appending to the output file." << endl;
+#ifdef HDF4
+  cout << " --hdf4        Write file using the hdf4 base." << endl;
+#endif
+#ifdef HDF5
+  cout << " --hdf5        Write file using the hdf5 base." << endl;
+#endif
+#ifdef NXXML
+  cout << " --xml         Write file using the xml base." << endl;
+#endif
+  cout << "  -D <macro>   Specify a macro. The macro should be in the form of\n"
+       << "               \"FILE=old_nexus.nxs\". The \"=\" is required." << endl;
+#ifdef USE_TIMING
+  cout << "  --timing     Print out timing information for the execution of the program." << endl;
+#endif
+}
+
+int main(int argc, char *argv[]){
+#ifdef USE_TIMING
+  time_t start_time = time(NULL);
+#endif
+  Options options;
+  options.base=NXACC_CREATE;
+  options.append=false;
+  options.timing=false;
+
+  // parse the command line options (i=0 is the program name
+  for( int i=1 ; i<argc ; i++ ){
+    // set up strings for this and the next argument
+    string arg1=argv[i];
+    string arg2;
+    if(i+1<argc)
+      arg2=argv[i+1];
+
+    if(starts_with(arg1,"--help")){
+      print_help(argv[0],10);
+      exit(0);
+    }else if(starts_with(arg1,"--version")){
+      print_version();
+      exit(0);
+    }else if(starts_with(arg1,"-o")){
+      trim_arg(arg1,"-o");
+      if(arg1.size()>0){
+        options.outfile=arg1;
+      }else if(arg2.size()>0){
+        options.outfile=arg2;
+        i++;
+      }else{
+        print_help(argv[0],0);
+        exit(-1);
+      }
+    }else if(starts_with(arg1,"--append")){
+      trim_arg(arg1,"--append");
+      options.append=true;
+      if(arg1.size()>0){
+        options.outfile=arg1;
+      }else if(arg2.size()>0){
+        options.outfile=arg2;
+        i++;
+      }else{
+        print_help(argv[0],0);
+        exit(-1);
+      }
+    }else if(starts_with(arg1,"-D")){
+      trim_arg(arg1,"-D");
+      if(arg1.size()<=0){
+        arg1=arg2;
+        i++;
+      }
+      string key=split(arg1);
+      options.map.insert(make_pair(key,arg1));
+    }else if(starts_with(arg1, "--timing")) {
+      options.timing = true;
+#ifdef HDF4
+    }else if(starts_with(arg1,"--hdf4")){
+      options.base=NXACC_CREATE4;
+#endif
+#ifdef HDF5
+    }else if(starts_with(arg1,"--hdf5")){
+      options.base=NXACC_CREATE5;
+#endif
+#ifdef NXXML
+    }else if(starts_with(arg1,"--xml")){
+      options.base=NXACC_CREATEXML;
+#endif
+    }else{
+      options.infile=arg1;
+    }
+  }
+
+  // print usage if there is no input file
+  if(options.infile.size()<=0){
+    print_help(argv[0],0);
+    exit(-1);
+  }
+
+  // check what is needed for appending
+  if(options.append){
+    if(options.outfile.size()<=0){
+      cout << "Need to specify a file for \"append\" mode." << endl;
+      exit(-1);
+    }
+    std::ifstream checkFile(options.outfile.c_str());
+    bool is_readable(checkFile);
+    checkFile.close();
+    if(!is_readable)
+      options.append=false;
+  }
+
+  // if the output file name is blank then create one
+  if(options.outfile.size()<=0){
+    options.outfile=options.infile;
+    string::size_type size=options.outfile.size();
+    if(options.outfile.substr(size-4,size)==".xml")
+      options.outfile.erase(size-4,size);
+    else if(options.outfile.substr(size-4,size)==".nxt")
+      options.outfile.erase(size-4,size);
+    options.outfile+=".nxs";
+  }
+
+  // open the output file
+  NXhandle handle;
+  char out_file[50];
+  strcpy(out_file,options.outfile.c_str());
+  NXaccess base=options.base;
+  if(options.append)
+    base=NXACC_RDWR;
+  if(NXopen(out_file,base,&handle)!=NX_OK){
+    std::cerr << "Error opening output file \"" << options.outfile << "\"" << endl;
+    return -1;
+  }
+
+  // parse the file
+  bool result=xml_parser::parse_xml_file(options.map,options.infile,&handle,
+                                         options.timing);
+
+  // close the output file
+  NXclose(&handle);
+
+  // delete the created file if result is non-zero
+  if(result){
+    if(std::remove(options.outfile.c_str()))
+      std::perror("ERROR DELETING FILE");
+  }
+  
+#ifdef USE_TIMING
+  if (options.timing) {
+    cout << print_time(start_time) << " total time" << endl;
+  }
+#endif
+  return result;
+}
diff --git a/applications/NXtranslate/nexus_retriever.cpp b/applications/NXtranslate/nexus_retriever.cpp
new file mode 100644
index 0000000..88389fe
--- /dev/null
+++ b/applications/NXtranslate/nexus_retriever.cpp
@@ -0,0 +1,238 @@
+#include <fstream>
+#include <stdexcept>
+#include <string>
+#include <cstring>
+#include "nexus_retriever.h"
+#include "nexus_util.h"
+#include "node.h"
+#include "retriever.h"
+#include "string_util.h"
+#include "tree.hh"
+
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+const static int    GROUP_STRING_LEN = 128;
+const static string SDS              = "SDS";
+
+typedef tree<Node> NodeTree;
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+NexusRetriever::NexusRetriever(const string &str): source(str){
+  // allocate memory for the handle
+  handle=new NXhandle;
+
+  // check if the filename is nonzero
+  if(str.size()<=0)
+    throw invalid_argument("Cannot initialize from an empty string");
+
+  // check if the file is readable
+  { // have the variable quickly go out of scope to enable cleanup
+    std::ifstream checkFile(source.c_str());
+    bool is_readable(checkFile);
+    checkFile.close();
+    if(!is_readable)
+      throw runtime_error(source+" is not readable");
+  }
+
+  // open the file using NAPI
+  char filename[50];
+  strcpy(filename,str.c_str());
+  if(NXopen(filename,NXACC_READ,handle)!=NX_OK){
+    delete handle;
+    throw runtime_error("NXopen failed");
+  }
+
+}
+
+NexusRetriever::~NexusRetriever(){
+  if(handle!=NULL){
+    if(NXclose(handle)!=NX_OK)
+      throw runtime_error("NXclose failed");
+    delete handle;
+  }
+}
+
+/**
+ * This can throw a runtime_error if something goes wrong
+ */
+static void getAttrAsNode(NXhandle *handle, NodeTree &tree, string &name){
+  // get ready to find the correct attribute
+  if(NXinitattrdir(*handle)!=NX_OK)
+    throw runtime_error("NXinitattrdir failed");
+  char attr_name[GROUP_STRING_LEN];
+  int attr_type;
+  int num_attr;
+  int attr_len;
+  if(NXgetattrinfo(*handle,&num_attr)!=NX_OK)
+    throw runtime_error("NXgetattrinfo failed");
+
+  // find the correct attribute
+  bool found=false;
+  for( int i=0 ; i<num_attr ; i++ ){
+    if(NXgetnextattr(*handle,attr_name,&attr_len,&attr_type)!=NX_OK)
+      throw runtime_error("NXgetnextattr failed");
+    if(name==attr_name){
+      found=true;
+      break;
+    }
+  }
+  if (!found) {
+    throw runtime_error("failed to find attribute");
+  }
+  // get the value
+  int attr_dims[1]={attr_len+1};
+  void *attr_value;
+  if(NXmalloc(&attr_value,1,attr_dims,attr_type)!=NX_OK)
+    throw runtime_error("NXmalloc failed");
+  if(NXgetattr(*handle,attr_name,attr_value,attr_dims,&attr_type)!=NX_OK)
+    throw runtime_error("NXgetattr failed");
+  Node node(name,attr_value,1,attr_dims,attr_type);
+  if(NXfree(&attr_value)!=NX_OK)
+    throw runtime_error("NXfree failed");
+
+  // put the attribute in the tree
+  tree.insert(tree.begin(),node);
+}
+
+/**
+ * This can throw a runtime_error if something goes wrong
+ */
+static void getDataNode(NXhandle *handle, string &name, Node &node){
+  // get the node and all of its attributes
+  int rank=0;
+  int type=0;
+  int dims[NX_MAXRANK];
+  if(NXgetinfo(*handle,&rank,dims,&type)!=NX_OK)
+    throw runtime_error("NXgetinfo failed");
+
+  // allocate space for the data
+  void *data;
+  if(NXmalloc(&data,rank,dims,type)!=NX_OK)
+    throw runtime_error("NXmalloc failed");
+
+  // retrieve data from the file
+  if(NXgetdata(*handle,data)!=NX_OK)
+    throw runtime_error("NXgetdata failed");
+
+  // retrieve attributes from the file
+  if(NXinitattrdir(*handle)!=NX_OK)
+    throw runtime_error("NXinitattrdir failed");
+  char attr_name[GROUP_STRING_LEN];
+  int attr_type;
+  int num_attr;
+  int attr_len;
+  if(NXgetattrinfo(*handle,&num_attr)!=NX_OK)
+    throw runtime_error("NXgetattrinfo failed");
+  vector<Attr> attrs;
+  for( int i=0 ; i<num_attr ; i++ ){
+    if(NXgetnextattr(*handle,attr_name,&attr_len,&attr_type)!=NX_OK)
+      throw runtime_error("NXgetnextattr failed");
+    int attr_dims[1]={attr_len+1};
+    void *attr_value;
+    if(NXmalloc(&attr_value,1,attr_dims,attr_type)!=NX_OK)
+      throw runtime_error("NXmalloc failed");
+    if(NXgetattr(*handle,attr_name,attr_value,attr_dims,&attr_type)!=NX_OK)
+      throw runtime_error("NXgetattr failed");
+    Attr my_attr(attr_name,attr_value,attr_len,attr_type);
+    if(NXfree(&attr_value)!=NX_OK)
+      throw runtime_error("NXfree failed");
+    attrs.push_back(my_attr);
+  }
+
+  // create the data
+  node=Node(name,data,rank,dims,type);
+  //node.set_name(name);
+  //node.set_data(data,rank,dims,type);
+  node.set_attrs(attrs);
+
+  // free the temporary data
+  if(NXfree(&data)!=NX_OK)
+    throw runtime_error("NXfree failed");
+}
+
+void get_subtree(NXhandle *handle, NodeTree &tree, NodeTree::pre_order_iterator parent, string &name){
+  //std::cout << "get_subtree(handle,tree,parent," << name << ")" << std::endl; // REMOVE
+  static const string SDS="SDS";
+  // open the correct level and deal with things correctly
+  string type=nexus_util::open(handle,name);
+  Node node(name,type);
+  bool is_data=(type==SDS);
+
+  // if we are at a data get it and return
+  if(is_data){
+    // get the data
+    try{
+      getDataNode(handle,name,node);
+    }catch(runtime_error &e){ // cleanup and rethrow
+      nexus_util::close(handle,node);
+      throw;
+    }
+  }
+
+  // add the node to the tree
+  NodeTree::pre_order_iterator new_parent;
+  if(parent==tree.end())
+    new_parent=tree.insert(tree.begin(),node);
+  else
+    new_parent=tree.append_child(parent,node);
+
+  if(!is_data){
+    // get the listing and check result
+    typedef vector<string> StringVec;
+    StringVec listing=nexus_util::get_list(handle);
+    if(listing.size()%2 || !listing.size()){
+      nexus_util::close(handle,node);
+      throw runtime_error("listing of NeXus file returned odd result");
+    }
+  
+    // itterate through the listing
+    for( StringVec::iterator it=listing.begin() ; it!=listing.end() ; it+=2 )
+      get_subtree(handle,tree,new_parent,*it);
+  }
+  // close the path to the node
+  nexus_util::close(handle,node);
+}
+
+/**
+ * This is the method for retrieving data from a file. The whole
+ * tree will be written to the new file immediately after being
+ * called. Interpreting the string is left up to the implementing
+ * code.
+ */
+void NexusRetriever::getData(const string &location, NodeTree &tree){
+  //std::cout << "\"" << source << "\"." << "getData(" << location << ",tree)" << std::endl; // REMOVE
+  if(location.size()<=0)
+    throw invalid_argument("cannot parse empty string");
+
+  // get the name
+  vector<string> path=string_util::string_to_path(location);
+  string name=*(path.rbegin());
+  // remove the last bit from the path
+  path.pop_back();
+
+  // open the path to the node
+  int num_group=0;
+  int num_data=0;
+  nexus_util::open_path(handle,path,num_group,num_data);
+  // get the subtree
+  if(num_data>0)
+    getAttrAsNode(handle,tree,name);
+  else
+    get_subtree(handle,tree,tree.end(),name);
+
+  // close the path to the node
+  nexus_util::close_path(handle,num_group,num_data);
+}
+
+const string NexusRetriever::MIME_TYPE("application/x-NeXus");
+
+string NexusRetriever::toString() const{
+  return "["+MIME_TYPE+"] "+source;
+}
diff --git a/applications/NXtranslate/nexus_retriever.h b/applications/NXtranslate/nexus_retriever.h
new file mode 100644
index 0000000..fe270a3
--- /dev/null
+++ b/applications/NXtranslate/nexus_retriever.h
@@ -0,0 +1,20 @@
+#ifndef __NEXUS_RETRIEVER_GUARD
+#define __NEXUS_RETRIEVER_GUARD
+
+#include "retriever.h"
+
+// this is not intended to be inherited from
+class NexusRetriever: public Retriever{
+ public:
+  NexusRetriever(const std::string &);
+  ~NexusRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  NexusRetriever(const NexusRetriever&);
+  NexusRetriever& operator=(const NexusRetriever&);
+  NXhandle *handle;
+  std::string source;
+};
+#endif
diff --git a/applications/NXtranslate/nexus_util.cpp b/applications/NXtranslate/nexus_util.cpp
new file mode 100644
index 0000000..41fb462
--- /dev/null
+++ b/applications/NXtranslate/nexus_util.cpp
@@ -0,0 +1,448 @@
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <vector>
+#include "nexus_util.h"
+#include "string_util.h"
+#include "nxtranslate_debug.h"
+
+// ----- start of declaring debug levels
+#ifdef DEBUG3_NEXUS_UTIL
+#define DEBUG2_NEXUS_UTIL
+#endif
+#ifdef DEBUG2_NEXUS_UTIL
+#define DEBUG1_NEXUS_UTIL
+#endif
+// ----- end of declaring debug levels
+
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+typedef struct{
+  string name;
+  string type;
+}SimpleNode;
+
+typedef vector<string> StringVec;
+typedef vector<SimpleNode> SimpleNodeVec;
+typedef tree<Node> TreeNode;
+
+static const int    GROUP_STRING_LEN = 128;
+static const string NXROOT           = "NXroot";
+static const string SDS              = "SDS";
+static const string ATTR             = "ATTR";
+
+static SimpleNodeVec get_groups(NXhandle *handle);
+
+static bool node_exists(NXhandle *handle, const Node &node){
+  SimpleNodeVec groups=get_groups(handle);
+
+  for(SimpleNodeVec::const_iterator group=groups.begin() ; group!=groups.end() ; group++ ){
+    if(group->name==node.name()){
+      if(group->type==node.type())
+        return true;
+      if(node.is_data() && group->type==SDS)
+        return true;
+    }
+  }
+
+  return false;
+}
+
+extern void nexus_util::open(NXhandle *handle, const Node &node){
+#ifdef DEBUG2_NEXUS_UTIL
+  std::cout << "nexus_util::open(handle," << node.name() << ":" << node.type()
+            << ")" << std::endl;
+#endif
+  // do nothing with a root
+  if(node.name()==NXROOT) return;
+
+  // the name is needed by all "make" functions
+  char name[GROUP_STRING_LEN];
+  strcpy(name,node.name().c_str());
+
+  bool existing_node=node_exists(handle,node);
+
+  if(node.is_data()){
+    if(!existing_node){
+      int type=(int)node.int_type(); // get the type and cast as an int
+      int rank=node.rank();
+      if(rank<=0) return;
+
+      int dims[NX_MAXRANK];
+      { // copy the dimensions from the node
+        vector<int> vec_dim=node.dims();
+        for( int i=0 ; i<rank ; i++ )
+          dims[i]=vec_dim[i];
+      }
+
+      // create the data
+      int comp_type=node.compress_type();
+      if(comp_type==Node::COMP_NONE){
+        //std::cout << "in open: " << node.type() << " " << *(node.dims().begin()) << std::endl; // REMOVE
+        if(NXmakedata(*handle,name,type,rank,dims)!=NX_OK){
+          std::cout << "NXmakedata failed" << std::endl;
+          throw runtime_error("NXmakedata failed");
+        }
+      }else{
+        vector<int> buff_size_vec=node.comp_buffer_dims();
+        int *buff_size=new int[rank];
+        for( size_t i=0 ; i<rank ; i++ ){
+          buff_size[i]=buff_size_vec[i];
+        }
+
+        buff_size[rank-1]=dims[rank-1];
+        if(NXcompmakedata(*handle,name,type,rank,dims,comp_type,buff_size)!=NX_OK){
+          std::cout << "NXcompmakedata failed" << std::endl;
+          throw runtime_error("NXcompmakedata failed");
+        }
+        delete buff_size; // FIXME - is this the correct form?
+      }
+    }
+    // open the data that was just created
+    if(NXopendata(*handle,name)!=NX_OK)
+      throw runtime_error("NXopendata failed");
+  }else{
+    char type[GROUP_STRING_LEN];
+    strcpy(type,node.type().c_str());
+    if(!existing_node) 
+      if(NXmakegroup(*handle,name,type)!=NX_OK)
+        throw runtime_error("NXmakegroup failed");
+    if(NXopengroup(*handle,name,type)!=NX_OK)
+      throw runtime_error("NXopengroup failed");
+  }
+}
+
+static void add_attribute(NXhandle *handle, const Node& node,
+                                                           const int attr_num){
+  Attr attr=(node.get_attr(attr_num));
+
+  char name[GROUP_STRING_LEN];
+  strcpy(name,attr.name().c_str());
+
+  if(NXputattr(*handle,name,attr.value(),attr.length(),attr.type())!=NX_OK)
+    throw runtime_error("NXputattr failed");
+}
+
+extern void nexus_util::make_data(NXhandle *handle, const Node& node){
+  //std::cout << "make(" << node.name() << ")" << std::endl; // REMOVE
+  // do nothing with a root
+  if(node.name()==NXROOT) return;
+  // do nothing unless this is a data
+  if(!node.is_data()) return;
+
+  // put in the attributes
+  for( int i=0 ; i<node.num_attr() ; i++ )
+    add_attribute(handle,node,i);
+
+  // put in the data
+  void *data(NULL);
+  node.copy_data(data);
+  if(data==NULL)
+    throw runtime_error("CANNOT ADD NULL DATA");// << std::endl;
+  if(NXputdata(*handle,data)!=NX_OK)
+    throw runtime_error("NXputdata failed");
+  NXfree(&data);
+}
+
+static void recurse_make_data(NXhandle *handle, const TreeNode &tree, const TreeNode::sibling_iterator &begin, const TreeNode::sibling_iterator &end){
+  using namespace nexus_util;
+  for( TreeNode::sibling_iterator sib=begin ; sib!=end ; sib++ ){
+    open(handle,*sib);
+    if(sib->is_data())
+      make_data(handle,*sib);
+    else
+      recurse_make_data(handle,tree,tree.begin(sib),tree.end(sib));
+    close(handle,*sib);
+    sib.skip_children();
+  }
+}
+
+extern void nexus_util::make_data(NXhandle *handle, const TreeNode &tree){
+  //std::cout << "make_data(handle,tree[" << tree.size() << "])" << std::endl; // REMOVE
+  // check that the tree is not empty
+  if(tree.size()<=0)
+    throw invalid_argument("Cannot write empty tree to file");
+
+  // recursively write out the tree
+  for( TreeNode::iterator it=tree.begin() ; it!=tree.end() ; it++ ){
+    open(handle,*it);
+    if(it->is_data())
+      make_data(handle,*it);
+    else
+      recurse_make_data(handle,tree,tree.begin(it),tree.end(it));
+    close(handle,*it);
+    it.skip_children();
+  }
+}
+
+extern void nexus_util::close(NXhandle *handle, const Node &node){
+#ifdef DEBUG2_NEXUS_UTIL
+  std::cout << "nexus_util::close(handle," << node.name() << ":" 
+            << node.type() << ")" << std::endl;
+#endif
+
+  // do nothing with a root
+  if(node.name()==NXROOT) return;
+
+  if(node.is_data()){
+    // check that there was something created
+    if(node.rank()<=0) return;
+
+    if(NXclosedata(*handle)!=NX_OK)
+      throw runtime_error("NXclosedata failed");
+  }else{
+    if(NXclosegroup(*handle)!=NX_OK)
+      throw runtime_error("NXclosegroup failed");
+  }
+}
+
+static int num_group(NXhandle *handle){
+  char group_name[GROUP_STRING_LEN];
+  char group_class[GROUP_STRING_LEN];
+  int num_groups;
+
+  if(NXgetgroupinfo(*handle,&num_groups,group_name,group_class)!=NX_OK)
+    throw runtime_error("NXgetgroupinfo failed");
+
+  return num_groups;
+}
+
+static SimpleNode get_next_group(NXhandle *handle){
+  //std::cout << "get_next_group(handle)" << std::endl;
+  char name[GROUP_STRING_LEN], class_name[GROUP_STRING_LEN];
+  int datatype;
+
+  // get the information
+  if(NXgetnextentry(*handle,name,class_name,&datatype)!=NX_OK)
+    throw "NXgetnextentry failed";
+
+  // copy it into the supplied node
+  SimpleNode node;
+  node.name=name;
+  node.type=class_name;
+
+  return node;
+}
+
+static bool node_is_okay(const SimpleNode& node){
+  static const string UNKNOWN="UNKNOWN";
+  if(node.name==UNKNOWN)
+    return false;
+  if(node.type==UNKNOWN)
+    return false;
+  if(node.type=="CDF0.0")
+    return false;
+  return true;
+}
+
+static SimpleNodeVec get_groups(NXhandle *handle){
+  //std::cout << "get_groups(handle)" << std::endl; // REMOVE
+
+  // reset the directory
+  if(NXinitgroupdir(*handle)!=NX_OK)
+    throw runtime_error("NXinitgroupdir failed");
+
+  // determine the number of groups at the current location
+  int num_groups = 0;
+  try{
+    num_groups=num_group(handle);
+  }catch(runtime_error &e){
+    // let it drop on the floor
+  }
+
+  // set up for the listing
+  SimpleNodeVec result;
+  if(num_groups<=0) return result;
+
+  // get the listing
+  SimpleNode node;
+  for( int i=0 ; i<num_groups ; i++ ){
+    node=get_next_group(handle);
+    if(node_is_okay(node))
+      result.push_back(node);
+  }
+
+  return result;
+}
+
+extern vector<string> nexus_util::get_list(NXhandle *handle){
+  SimpleNodeVec vec=get_groups(handle);
+
+  vector<string> result;
+  for( SimpleNodeVec::const_iterator it=vec.begin() ; it!=vec.end() ; it++ ){
+    result.push_back(it->name);
+    result.push_back(it->type);
+  }
+
+  return result;
+}
+
+static string get_type(NXhandle *handle, const string &name){
+  SimpleNodeVec groups=get_groups(handle);
+
+  for(SimpleNodeVec::const_iterator group=groups.begin() ; group!=groups.end() ; group++ ){
+    if(group->name==name)
+      return group->type;
+  }
+  return "";
+}
+
+static void open_node(NXhandle *handle, const string &name, const string &type, int &num_group, int &num_data){
+  // do nothing for attributes
+  if(type==ATTR)
+    return;
+
+  // everything else needs a name
+  char ch_name[GROUP_STRING_LEN];
+  strcpy(ch_name,name.c_str());
+
+  // open a data if appropriate
+  if(type==SDS){
+    if(NXopendata(*handle,ch_name)!=NX_OK)
+      throw runtime_error("NXopendata failed");
+    num_data++;
+    return;
+  }
+
+  // open the group
+  char ch_type[GROUP_STRING_LEN];
+  strcpy(ch_type,type.c_str());
+  if(NXopengroup(*handle,ch_name,ch_type)!=NX_OK)
+    throw runtime_error("NXopengroup failed");
+  num_group++;
+}
+
+extern string nexus_util::open(NXhandle *handle, const string &name){
+  string type=get_type(handle,name);
+  if(type.size()<=0)
+    throw runtime_error(string("could not find type for node[")+name+"]");
+  int num_group=0;
+  int num_data=0;
+  open_node(handle,name,type,num_group,num_data);
+  return type;
+}
+
+static string path_to_str(const StringVec &path){
+  string str="";
+  for( StringVec::const_iterator it=path.begin() ; it!=path.end() ; it++ )
+    str+=("/"+*it);
+  return str;
+}
+
+extern void nexus_util::open_path(NXhandle *handle, const StringVec &path, int &num_group, int &num_data){
+#ifdef DEBUG1_NEXUS_UTIL
+  std::cout << "open_path(" << handle << ",";
+  for( StringVec::const_iterator it=path.begin() ; it!=path.end() ; it++ )
+    std::cout << "/" << *it;
+  std::cout << "," << num_group << "," << num_data << ")" << std::endl;
+#endif
+  for( StringVec::const_iterator it=path.begin() ; it!=path.end() ; it++ ){
+    string type=get_type(handle,*it);
+    if(type.size()<=0){
+      close_path(handle,num_group,num_data);
+      throw runtime_error("Path ["+path_to_str(path)+"] did not exist");
+    }
+    try{
+      open_node(handle,*it,type,num_group,num_data);
+    }catch(runtime_error &e){
+      throw  runtime_error("Could not open path ["+path_to_str(path)+"]");
+    }
+  }
+}
+
+extern void nexus_util::close_path(NXhandle *handle, int &num_group, int &num_data){
+#ifdef DEBUG1_NEXUS_UTIL
+  std::cout << "close_path(" << handle << "," << num_group << ","
+            << num_data << ")" << std::endl;
+#endif
+  if( (num_group<=0) && (num_data<=0) ){
+    num_group=0;
+    num_data=0;
+    return;
+  }
+
+  if(num_data){
+    if(NXclosedata(*handle)!=NX_OK)
+      throw runtime_error("NXclosedata failed");
+    num_data--;
+  }
+
+  for( ; num_group>0 ; num_group-- ){
+    if(NXclosegroup(*handle)!=NX_OK)
+      throw runtime_error("NXclosegroup failed");
+  }
+}
+
+extern size_t nexus_util::calc_size(int rank, int *dims, int type){
+  // check that the rank is reasonable
+  if(rank<=0) throw invalid_argument("Do not understand rank<=0");
+
+  // determine how much to copy
+  size_t size=1;
+  for( int i=0 ; i<rank ; i++ )
+    size*=dims[i];
+  if(type==NX_CHAR || type==NX_INT8 || type==NX_UINT8){
+    // size is already correct
+  }else if(type==NX_INT16 || type==NX_UINT16){
+    size*=2;
+  }else if(type==NX_INT32 || type==NX_UINT32 || type==NX_FLOAT32){
+    size*=4;
+  }else if(type==NX_FLOAT64 || type==NX_UINT64 || type==NX_INT64){
+    size*=8;
+  }else{
+    throw invalid_argument("Did not understand type in nexus_util::calc_size");
+  }
+
+  return size;
+}
+
+extern void nexus_util::make_link(NXhandle *handle, const vector<string> &link, const vector<string> &source){
+/*
+  // ********** begin debug print
+  std::cout << "LINKING ";
+  for( vector<string>::const_iterator it=link.begin() ; it!=link.end() ; it++ )
+    std::cout << "/" << *it;
+  std::cout << " -> ";
+  for( vector<string>::const_iterator it=source.begin() ; it!=source.end() ; it++ )
+    std::cout << "/" << *it;
+  std::cout << std::endl;
+  // ********** end debug print
+*/
+  // keep track of location in file
+  NXlink *link_id=(NXlink *)malloc(sizeof(NXlink));
+  int num_group=0;
+  int num_data=0;
+
+  // open the path to the source
+  nexus_util::open_path(handle,source,num_group,num_data);
+
+  // get the link_id
+  if(num_data>0){
+    if(NXgetdataID(*handle,link_id)!=NX_OK)
+      throw new runtime_error("could not get data ID for linking");
+  }else{
+    if(NXgetgroupID(*handle,link_id)!=NX_OK)
+      throw new runtime_error("could not get group ID for linking");
+  }
+
+  // return to the root node in the file
+  nexus_util::close_path(handle,num_group,num_data);
+
+  // open to link's parent location
+  nexus_util::open_path(handle,link,num_group,num_data);
+
+  // create the link
+  if(NXmakelink(*handle,link_id)!=NX_OK)
+    throw new runtime_error("could not create link");
+
+  // return to the root node in the file
+  nexus_util::close_path(handle,num_group,num_data);
+
+  // free up the NXlink variable
+  free(link_id);
+}
diff --git a/applications/NXtranslate/nexus_util.h b/applications/NXtranslate/nexus_util.h
new file mode 100644
index 0000000..1898f66
--- /dev/null
+++ b/applications/NXtranslate/nexus_util.h
@@ -0,0 +1,33 @@
+#ifndef __NEXUS_UTIL_H_GUARD
+#define __NEXUS_UTIL_H_GUARD
+
+#include <napiconfig.h>
+#include <napi.h>
+#include <string>
+#include "node.h"
+#include "tree.hh"
+
+namespace nexus_util{
+  // open the group or data
+  extern void open(NXhandle *handle, const Node &node);
+  // open the group or data
+  extern std::string open(NXhandle *handle, const std::string &name);
+  // fill the opened data with contents of node
+  extern void make_data(NXhandle *handle, const Node& node);
+  // create a tree, closing the whole thing when done
+  extern void make_data(NXhandle *handle, const tree<Node> &tree);
+  // close the group or data
+  extern void close(NXhandle *handle, const Node &node);
+  // open to a specific place
+  extern void open_path(NXhandle *handle, const std::vector<std::string> &path, int &num_group, int &num_data);
+  // close from a specific place
+  extern void close_path(NXhandle *handle, int &num_group, int &num_data);
+  // calculate size of a data for copying
+  extern size_t calc_size(int rank, int *dims, int type);
+  // create a listing of the currently open level. In pairs of (name,type).
+  extern std::vector<std::string> get_list(NXhandle *handle);
+  // creates a link from link to source
+  extern void make_link(NXhandle *handle, const std::vector<std::string> &link, const std::vector<std::string> &source);
+}
+#endif
+
diff --git a/applications/NXtranslate/node.cpp b/applications/NXtranslate/node.cpp
new file mode 100644
index 0000000..28c3647
--- /dev/null
+++ b/applications/NXtranslate/node.cpp
@@ -0,0 +1,315 @@
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+#include <vector>
+#include "nexus_util.h"
+#include "node.h"
+#include "string_util.h"
+
+using std::invalid_argument;
+using std::runtime_error;
+using std::logic_error;
+using std::out_of_range;
+using std::string;
+using std::vector;
+
+static const string LEFT  = "[";
+static const string RIGHT = "]";
+
+static string convert_type(int type){
+  if(type==Node::CHAR)
+    return "NX_CHAR";
+  else if(type==Node::FLOAT32)
+    return "NX_FLOAT32";
+  else if(type==Node::FLOAT64)
+    return "NX_FLOAT64";
+  else if(type==Node::INT8)
+    return "NX_INT8";
+  else if(type==Node::INT16)
+    return "NX_INT16";
+  else if(type==Node::INT32)
+    return "NX_INT32";
+  else if(type==Node::INT64)
+    return "NX_INT64";
+  else if(type==Node::UINT8)
+    return "NX_UINT8";
+  else if(type==Node::UINT16)
+    return "NX_UINT16";
+  else if(type==Node::UINT32)
+    return "NX_UINT32";
+  else if(type==Node::UINT64)
+    return "NX_UINT64";
+  else
+    throw runtime_error("Did not understand type in set_data");
+}
+
+// ==================== Node implementation
+Node::Node(const std::string &name, const std::string &type):__name(name),__type(type),_value(NULL),__comp_type(COMP_NONE),__ref_count(new size_t(1)){
+  // determine if this is data
+  try{
+    Node::NXtype int_type=Node::int_type(); // throws an exception if not data
+    __is_data=true;
+  }catch(runtime_error &err){
+    __is_data=false;
+  }
+}
+
+Node::Node(const Node &old): __name(old.__name), __type(old.__type), __is_data(old.__is_data), __dims(old.__dims), _value(old._value), __attrs(old.__attrs), __comp_type(old.__comp_type), __ref_count(old.__ref_count){
+  (*__ref_count)++;
+  //std::cout << "Node(" << __name << ")" << std::endl; // REMOVE
+}
+
+Node::Node(const string &name, void * data, const int rank, const int* dims, const int type): __name(name), __is_data(true), __comp_type(COMP_NONE), __ref_count(new size_t(1)){
+  this->set_data(data,rank,dims,type);
+}
+
+Node& Node::operator=(const Node &old){
+  if(this==&old) return *this;
+
+  // delete the old value (if necessary)
+  (*__ref_count)--;
+  if( (__is_data) && (*__ref_count==0) && (_value!=NULL) )
+    NXfree(&_value);
+
+  // copy everything except the value
+  __name=old.__name;
+  __type=old.__type;
+  __is_data=old.__is_data;
+  __dims.clear();
+  __dims.insert(__dims.begin(),old.__dims.begin(),old.__dims.end());
+  __attrs.clear();
+  __attrs.insert(__attrs.begin(),old.__attrs.begin(),old.__attrs.end());
+  __comp_type=old.__comp_type;
+  __ref_count=new size_t(1);
+  _value=NULL;
+
+
+  // copy the value
+  if(__is_data){
+    int rank=__dims.size();
+    int dims[NX_MAXRANK];
+    for( int i=0 ; i<rank ; i++ )
+      dims[i]=__dims[i];
+    int type=this->int_type();
+
+    // allocate space for the data
+    NXmalloc(&_value,rank,dims,type);
+
+    // determine how much to copy
+    size_t size=nexus_util::calc_size(rank,dims,type);
+
+    // copy the array
+    memcpy(_value,old._value,size);
+  }
+
+  return *this;
+}
+
+Node::~Node(){
+  //std::cout << "~Node(" << __name << "," << *__ref_count << ")" << std::endl; // REMOVE
+  (*__ref_count)--;
+  if(*__ref_count==0){
+    if(_value!=NULL){
+      if(NXfree(&_value)!=NX_OK)
+        throw runtime_error("NXfree failed in destructor");
+      _value=NULL;
+    }
+    delete __ref_count;
+  }
+}
+
+const string Node::name() const{
+  return __name;
+}
+
+const string Node::type() const{
+  return __type;
+}
+
+const bool Node::is_data() const{
+  return __is_data;
+}
+
+const int Node::rank() const{
+  if(!__is_data)
+    throw logic_error("node is not data");
+
+  return __dims.size();
+}
+
+const vector<int> Node::dims() const{
+  vector<int> vec(__dims.begin(),__dims.end());
+
+  return vec;
+}
+
+const Node::NXtype Node::int_type() const{
+  if(__type=="NX_CHAR")
+    return CHAR;
+  else if(__type=="NX_FLOAT32")
+    return FLOAT32;
+  else if(__type=="NX_FLOAT64")
+    return FLOAT64;
+  else if(__type=="NX_INT8")
+    return INT8;
+  else if(__type=="NX_INT16")
+    return INT16;
+  else if(__type=="NX_INT32")
+    return INT32;
+  else if(__type=="NX_INT64")
+    return INT64;
+  else if(__type=="NX_UINT8")
+    return UINT8;
+  else if(__type=="NX_UINT16")
+    return UINT16;
+  else if(__type=="NX_UINT32")
+    return UINT32;
+  else if(__type=="NX_UINT64")
+    return UINT64;
+  else
+    throw runtime_error("do not understand type");
+}
+
+const Node::NXcompress Node::compress_type() const{
+  return __comp_type;
+}
+
+const std::vector<int> Node::comp_buffer_dims() const{
+  return __comp_buffer_dims;
+}
+
+void* Node::data() const{
+  return _value;
+}
+
+void Node::copy_data(void *&data)const{
+  // determine the type
+  int type=int_type();
+
+  // determine the rank
+  int int_rank=rank();
+
+  // int array version of dimensions
+  int my_dims[NX_MAXRANK];
+  for( int i=0 ; i<int_rank ; i++ )
+    my_dims[i]=__dims[i];
+
+
+  // allocate space for the data
+  NXmalloc(&data,int_rank,my_dims,type);
+
+  // determine how much to copy
+  size_t size=nexus_util::calc_size(int_rank,my_dims,type);
+
+  // copy the array
+  memcpy(data,_value,size);
+}
+
+const int Node::num_attr() const{
+  return (__attrs.size());
+}
+
+Attr Node::get_attr(const int attr_num) const{
+  if(attr_num>this->num_attr())
+    throw out_of_range("asked for attribute with higher index than size");
+  return (*(__attrs.begin()+attr_num));
+}
+
+const void Node::set_comp(const string &comp_type){
+  if(string_util::starts_with(comp_type,"NONE")){
+    __comp_type=COMP_NONE;
+  }else if(string_util::starts_with(comp_type,"LZW")){
+    __comp_type=COMP_LZW;
+  }else if(string_util::starts_with(comp_type,"RLE")){
+    __comp_type=COMP_RLE;
+  }else if(string_util::starts_with(comp_type,"HUF")){
+    __comp_type=COMP_HUF;
+  }else{
+    throw invalid_argument("Do not understand compression type: "+comp_type);
+  }
+
+  // work with user specified dimension information
+  vector<string> temp=string_util::split(comp_type,":");
+  if(temp.size()==2){
+    __comp_buffer_dims=string_util::str_to_intVec(*(temp.rbegin()));
+  }
+
+  // use default if anything is wrong
+  if(__comp_buffer_dims.size()!=__dims.size()){
+    __comp_buffer_dims=__dims;
+    for( size_t i=0 ; i<__comp_buffer_dims.size()-1 ; ++i ){
+      __comp_buffer_dims[i]=1;
+    }
+  }
+}
+
+const void Node::set_name(const string &name){
+  __name=name;
+}
+
+const void Node::set_data(void *&data,const int irank, const int* dims,const int type){
+  // copy the dimensions
+  __dims.clear();
+  int my_dims[NX_MAXRANK];
+  for( int i=0 ; i<irank ; i++ ){
+    __dims.push_back(dims[i]);
+    my_dims[i]=dims[i];
+  }
+
+  // copy the type
+  /* __type=str_type; */
+  __type=convert_type(type);
+
+  // allocate space for the data
+  NXmalloc(&_value,irank,my_dims,type);
+
+  // determine how much to copy
+  size_t size=nexus_util::calc_size(irank,my_dims,type);
+
+  // copy the array
+  memcpy(_value,data,size);
+
+  // set that this is a data
+  __is_data=true;
+}
+
+const void Node::set_attrs(const vector<Attr> &attrs){
+  __attrs.clear();
+  __attrs.insert(__attrs.begin(),attrs.begin(),attrs.end());
+}
+
+const void Node::update_attr(Attr &attr){
+  for( vector<Attr>::iterator it=__attrs.begin() ; it!=__attrs.end() ; it++ ){
+    if(it->name()==attr.name()){
+      __attrs.erase(it);
+      it--;
+    }
+  }
+  if(attr.length()>0)
+    __attrs.push_back(attr);
+}
+
+const void Node::update_attrs(vector<Attr> &attrs){
+  for( vector<Attr>::iterator it=attrs.begin() ; it!=attrs.end() ; it++ )
+    update_attr(*it);
+}
+
+const void Node::update_dims(std::vector<int> &dims){
+  // make sure that the caller is trying to do something
+  if(dims.size()<=0) return;
+
+  // compare sizes
+  int old_total_size=1;
+  for( unsigned int i=0 ; i<__dims.size() ; i++ )
+    old_total_size*=__dims[i];
+  int new_total_size=1;
+  for( unsigned int i=0 ; i<dims.size() ; i++ )
+    new_total_size*=dims[i];
+
+  // throw an exception if the total number of elements is not conserved
+  if(old_total_size!=new_total_size)
+    throw invalid_argument("old and new dimensions must describe same number of elements");
+
+  // set the new dimensions
+  __dims=dims;
+}
diff --git a/applications/NXtranslate/node.h b/applications/NXtranslate/node.h
new file mode 100644
index 0000000..fd334cc
--- /dev/null
+++ b/applications/NXtranslate/node.h
@@ -0,0 +1,64 @@
+#ifndef __NODE_H_GUARD
+#define __NODE_H_GUARD
+
+#include <vector>
+#include <string>
+#include <napiconfig.h>
+#include <napi.h>
+#include <iostream>
+#include "attr.h"
+
+// ==================== Node definition
+class Node{
+ public:
+  // enum for types
+  enum NXtype{CHAR=NX_CHAR,   FLOAT32=NX_FLOAT32, FLOAT64=NX_FLOAT64,
+              INT8=NX_INT8,   INT16=NX_INT16,     INT32=NX_INT32, INT64=NX_INT64,
+              UINT8=NX_UINT8, UINT16=NX_UINT16,   UINT32=NX_UINT32, UINT64=NX_UINT64,
+              GROUP};
+  enum NXcompress{COMP_NONE=NX_COMP_NONE, COMP_LZW=NX_COMP_LZW,
+                  COMP_RLE=NX_COMP_RLE,   COMP_HUF=NX_COMP_HUF};
+
+  // constructors and copy control
+  Node(const std::string &name, const std::string &type); // for creating a group
+  Node(const std::string &name, void * data, const int rank, const int* dims, const int type);
+  Node(const Node &); // copies share reference to the data
+  ~Node();
+  Node& operator=(const Node &); // asignment operator
+
+  // accesor methods
+  const std::string name() const;
+  const std::string type() const;
+  const bool is_data() const;
+  const int rank() const;
+  const std::vector<int> dims() const;
+  const std::vector<int> comp_buffer_dims() const;
+  const NXtype int_type() const;
+  const NXcompress compress_type() const;
+  void* data() const; // do not mutate value
+  void copy_data(void *&)const;
+  const int num_attr() const;
+  Attr get_attr(const int) const;
+
+  // mutator methods
+  const void set_comp(const std::string &comp_type);
+  const void set_name(const std::string &name);
+  const void set_data(void *&data,const int rank,const int* dims,const int type);
+  const void set_attrs(const std::vector<Attr> &attrs);
+  const void update_attrs(std::vector<Attr> &attrs);
+  const void update_dims(std::vector<int> &dims);
+
+ private:
+  const void update_attr(Attr &attr);
+
+  std::string __name;
+  std::string __type;
+  bool __is_data;
+  std::vector<int> __dims;
+  std::vector<int> __comp_buffer_dims;
+  void *_value;
+  std::vector<Attr> __attrs;
+  NXcompress __comp_type;
+  std::size_t* __ref_count;
+};
+#endif
diff --git a/applications/NXtranslate/node_util.cpp b/applications/NXtranslate/node_util.cpp
new file mode 100644
index 0000000..c2a466b
--- /dev/null
+++ b/applications/NXtranslate/node_util.cpp
@@ -0,0 +1,183 @@
+#include <iostream>
+#include <string>
+#include <cstring>
+#include <stdexcept>
+#include <vector>
+#include "node.h"
+#include "node_util.h"
+//#include "nexus_util.h"
+//#include "retriever.h"
+#include "string_util.h"
+//#include "xml_parser.h"
+//#include "Ptr.h"
+//#include "tree.hh"
+//#include "nxtranslate_debug.h"
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::exception;
+using std::invalid_argument;
+//using std::map;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+/**
+ * The void pointer passed to this function must have enough space
+ * allocated to be filled with values generated from the string.
+ */
+extern void void_ptr_from_string(void *&value, string &char_data, int rank,
+                                       int *dims, Node::NXtype type){
+  /*
+   *    type    | napi4_test    | napi5_test    | nxbrowse
+   * -----------|---------------|---------------|-----------
+   * NX_CHAR    | char          | char          | char
+   * NX_FLOAT32 | float         | float         | float
+   * NX_FLOAT64 | double        | double        | double
+   * NX_INT8    | unsigned char | unsigned char | char
+   * NX_INT16   | short int     | short int     | short
+   * NX_INT32   | int           | int           | int
+   * NX_UINT8   |               |               | unsigned char
+   * NX_UINT16  |               |               | unsigned short
+   * NX_UINT32  |               |               | unsigned int
+   */
+
+  // REMEMBER: int a[10][20] can be accessed using a[20*row+col]
+  int len=1;
+  for( int i=0 ; i<rank ; i++ )
+    len*=dims[i];
+  if(type==NX_CHAR){
+    strcpy((char*)value,char_data.c_str());
+  }else if(type==NX_FLOAT32){
+    string_util::str_to_floatArray(char_data,(float *)value,len);
+  }else if(type==NX_FLOAT64){
+    string_util::str_to_doubleArray(char_data,(double *)value,len);
+  }else if(type==NX_INT8){
+    string_util::str_to_ucharArray(char_data,(unsigned char *)value,len);
+  }else if(type==NX_INT16){ // something got gobbled
+    string_util::str_to_shortArray(char_data,(short int *)value,len);
+  }else if(type==NX_INT32){
+    string_util::str_to_intArray(char_data,(int *)value,len);
+  }else if(type==NX_INT64){
+    string_util::str_to_int64Array(char_data,(long long*)value,len);
+  }else if(type==NX_UINT8){
+    string_util::str_to_ucharArray(char_data,(unsigned char *)value,len);
+  }else if(type==NX_UINT16){ // something got gobbled
+    string_util::str_to_ushortArray(char_data,(unsigned short *)value,len);
+  }else if(type==NX_UINT32){
+    string_util::str_to_uintArray(char_data,(unsigned int *)value,len);
+  }else if(type==NX_UINT64){
+    string_util::str_to_uint64Array(char_data,(unsigned long long*)value,len);
+  }else{
+    throw runtime_error("unknown type in end_add_char()");
+  }
+}
+
+/*
+ * This routine changes a node by giving it a value (from a string),
+ * dimensions and a type.
+ */
+extern void update_node_from_string(Node &node, string &char_data,
+                                      vector<int> &v_dims, Node::NXtype type){
+  // local variables to do the work
+  int rank=v_dims.size();
+  if(type==NX_CHAR)
+    rank=1;
+  int dims[NX_MAXRANK];
+  if(type==NX_CHAR){
+    dims[0]=char_data.size();
+  }else{
+    for( int i=0 ; i<rank ; i++ )
+      dims[i]=v_dims[i];
+  }
+  void *value;
+
+  // allocate a space for the value
+  NXmalloc(&value,rank,dims,type);
+
+  // fill the void pointer with data generated from the string
+  void_ptr_from_string(value,char_data,rank,dims,type);
+
+  // set the value of the data
+  node.set_data(value,rank,dims,type);
+
+  // free up created value
+  NXfree(&value);
+}
+
+extern Node::NXtype node_type(const std::string &str){
+  if(str=="NX_CHAR")
+    return Node::CHAR;
+  else if(str=="NX_FLOAT32")
+    return Node::FLOAT32;
+  else if(str=="NX_FLOAT64")
+    return Node::FLOAT64;
+  else if(str=="NX_INT8")
+    return Node::INT8;
+  else if(str=="NX_INT16")
+    return Node::INT16;
+  else if(str=="NX_INT32")
+    return Node::INT32;
+  else if(str=="NX_INT64")
+    return Node::INT64;
+  else if(str=="NX_UINT8")
+    return Node::UINT8;
+  else if(str=="NX_UINT16")
+    return Node::UINT16;
+  else if(str=="NX_UINT32")
+    return Node::UINT32;
+  else if(str=="NX_UINT64")
+    return Node::UINT64;
+  else
+    throw runtime_error("Could not understand type in node_type("+str+")");
+}
+
+extern Attr make_attr(const string &name, const string &value){
+  // if value is empty return empty attribute (delete it from node)
+  if(value.size()<=0)
+    return Attr(name,NULL,0,NX_CHAR);
+
+  // if the attribute does not start with "NX_" it is a character
+  if(value.substr(0,3)!="NX_")
+    return Attr(name,value.c_str(),value.size(),NX_CHAR);
+  //else                                                          // REMOVE
+  //std::cout << "FOUND:" << name << "|" << value << std::endl; // REMOVE
+
+  // split the string for type and value
+  static const char COLON=':';
+  string::size_type loc=1;
+  for( ; loc<value.size() ; loc++ )
+    if(COLON==value[loc]) break;
+  string my_type=value.substr(0,loc);
+  string my_val=value.substr(loc+1,value.size());
+
+  //std::cout << "TYPE=" << my_type << " VALUE=" << my_val << std::endl; //REMOVE
+
+  // convert the string type to an integer type
+  Node::NXtype int_type;
+  try{
+    int_type=node_type(my_type);
+  }catch(runtime_error &e){
+    return Attr(name,NULL,0,NX_CHAR);
+  }
+  
+  int rank=1;
+  int dims[NX_MAXRANK];
+  if(int_type==Node::CHAR)
+    dims[0]=my_val.size();
+  else
+    dims[0]=1;
+
+  void *data;
+  NXmalloc(&data,rank,dims,int_type);
+  try{
+    void_ptr_from_string(data,my_val,rank,dims,int_type);
+  }catch(std::invalid_argument &e){
+    NXfree(&data);
+    throw e;
+  }
+  Attr attr(name,data,dims[0],int_type);
+  NXfree(&data);
+  return attr;
+}
diff --git a/applications/NXtranslate/node_util.h b/applications/NXtranslate/node_util.h
new file mode 100644
index 0000000..d6f70ea
--- /dev/null
+++ b/applications/NXtranslate/node_util.h
@@ -0,0 +1,24 @@
+#ifndef __NODE_UTIL_H_GUARD
+#define __NODE_UTIL_H_GUARD
+
+#include <iostream>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include "node.h"
+//#include "nexus_util.h"
+//#include "retriever.h"
+//#include "xml_parser.h"
+//#include "string_util.h"
+//#include "Ptr.h"
+//#include "tree.hh"
+//#include "nxtranslate_debug.h"
+
+extern void void_ptr_from_string(void *&value, std::string &char_data,
+                                 int rank, int *dims, Node::NXtype type);
+extern void update_node_from_string(Node &node, std::string &char_data,
+                                  std::vector<int> &v_dims, Node::NXtype type);
+extern Node::NXtype node_type(const std::string &str);
+extern Attr make_attr(const std::string &name, const std::string &value);
+#endif
+
diff --git a/applications/NXtranslate/nxtranslate.1 b/applications/NXtranslate/nxtranslate.1
new file mode 100644
index 0000000..0129707
--- /dev/null
+++ b/applications/NXtranslate/nxtranslate.1
@@ -0,0 +1,72 @@
+.TH NXTRANSLATE 1 "October 2011"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxtranslate \- convert anything into a NeXus file
+.SH SYNOPSIS
+.B nxtranslate
+[options] [--hd4|--hdf5|--xml] [\fIinfile\fP] [-o|--append \fIoutfile\fP]
+.SH DESCRIPTION
+.B nxtranslate
+is an anything to NeXus converter. This is
+accomplished by using translation files and a plugin style of
+architecture where 
+.B nxtranslate
+can read from new formats as plugins
+become available. This document describes the usage of
+.B nxtranslate
+by three types of individuals: the person using existing translation
+files to create NeXus files, the person creating translation files,
+and the person writing new Retrievers. All of these concepts are
+discussed in detail.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH OPTIONS
+The following options are supported
+.TP
+.B --help
+Print out the help message and exit
+.TP
+.B --version
+Print out the version and exit
+.TP
+.B -o outfile
+Specify output file. The default is the translation file with ".nxs" appended.
+.TP
+.B --append outfile
+Specify appending to the output file.
+.TP
+.B --hdf4
+Write file using the hdf4 base.
+.TP
+.B --hdf5
+Write file using the hdf5 base.
+.TP
+.B --xml
+Write file using the xml base.
+.TP
+.B -D macro
+Specify a macro. The macro should be in the form of "FILE=old_nexus.nxs". The "=" is required.
+.SH SEE ALSO
+.BR nxconvert(1),
+.BR nxdir (1),
+.BR http://www.nexusformat.org
+.SH AUTHOR
+.B nxtranslate
+was originally written by Peter Peterson 
+.nh
+<petersonpf at ornl.gov>
+.hy
+and may be used by others.
diff --git a/applications/NXtranslate/nxtranslate_debug.h b/applications/NXtranslate/nxtranslate_debug.h
new file mode 100644
index 0000000..8f18ed8
--- /dev/null
+++ b/applications/NXtranslate/nxtranslate_debug.h
@@ -0,0 +1,24 @@
+// define default debug level
+#ifdef DEBUG_NXTRANSLATE
+#define DEBUG1_NXTRANSLATE
+#endif
+
+// ----- level three debugging
+#ifdef DEBUG3_NXTRANSLATE
+#define DEBUG2_NXTRANSLATE
+#define DEBUG3_NEXUS_UTIL
+#define DEBUG3_XML_PARSER
+#endif
+
+// ----- level two debugging
+#ifdef DEBUG2_NXTRANSLATE
+#define DEBUG1_NXTRANSLATE
+#define DEBUG2_NEXUS_UTIL
+#define DEBUG2_XML_PARSER
+#endif
+
+// ----- level one debugging
+#ifdef DEBUG1_NXTRANSLATE
+#define DEBUG1_NEXUS_UTIL
+#define DEBUG1_XML_PARSER
+#endif
diff --git a/applications/NXtranslate/opengenie/Makefile.am b/applications/NXtranslate/opengenie/Makefile.am
new file mode 100644
index 0000000..b94c7d8
--- /dev/null
+++ b/applications/NXtranslate/opengenie/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2005, Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+#               CCLRC ISIS Facility
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -Wall
+
+lib_LTLIBRARIES = libnxgenie.la
+
+libnxgenie_la_SOURCES = \
+	opengenie.c geniedefs.h genie_data_access.h
+libnxgenie_la_LIBADD = -lgenie
+libnxgenie_la_LDFLAGS = -no-undefined -export-dynamic -module $(LDFLAGS)
+
+EXTRA_DIST = README nxgenie.gcl
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/opengenie/README b/applications/NXtranslate/opengenie/README
new file mode 100644
index 0000000..e9f4a75
--- /dev/null
+++ b/applications/NXtranslate/opengenie/README
@@ -0,0 +1,29 @@
+NXtranslate interface to ISIS Open GENIE package using the dynamic interface
+----------------------------------------------------------------------------
+
+Note: There is currently a problem with activating "genie.so" dynamically -
+to make it work you need to have genie linked into the nxtranslate 
+exectuable which you do by adding   -lgenie   to the   nxtranslate_LDADD  
+line in the Makefile.am file; then rebuild nxtranslate
+
+To run the test, type
+
+       make test_opengenie.nxs
+
+in the NXtranslate directory - this will read the test_opengenie.xml
+configuration file and generate the requested output file
+
+
+Usage
+-----
+
+The module is loaded  via the NXtranslate NXS:mime_type="dynamic/libnxgenie.so"
+On loading, additional GCL commands can be installed by setting the 
+NXGENIE_INIT environment variable to point at the relevant file
+
+see test_opengenie.xml for an example of usage
+
+Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+
+---
+$Id$
diff --git a/applications/NXtranslate/opengenie/genie_data_access.h b/applications/NXtranslate/opengenie/genie_data_access.h
new file mode 100644
index 0000000..48503cc
--- /dev/null
+++ b/applications/NXtranslate/opengenie/genie_data_access.h
@@ -0,0 +1,174 @@
+#ifndef GENIE_DATA_ACCESS
+#define	GENIE_DATA_ACCESS
+
+#define HAVE_LIBF2C
+
+/* Include this here for external use of this header */
+#include "geniedefs.h"
+
+/* GENIE data access interface in C++
+ *
+ * Designed for calling directly from FORTRAN but not
+ * with strings !! (we expect NULL terminated strings by
+ * ref at this point). The header will also allow linking
+ * from C (as long as parameters are passed by reference).
+ */ 
+
+#ifdef __cplusplus
+
+// Simple utility class to allow easy creation of Dims arrays when calling from C++
+// ie  CDims(n,...) =  { n, ... n }
+class CDims
+{
+	int *m_pDims, m_iSize;
+
+public:
+	CDims(int dim1)
+	{
+		m_iSize = 1;
+		m_pDims = new int [1];
+		m_pDims[0] = dim1;
+	}
+
+	CDims(int dim1, int dim2)
+	{
+		m_iSize = 2;
+		m_pDims = new int [2];
+		m_pDims[0] = dim1;
+		m_pDims[1] = dim2;
+	}
+
+	CDims(int dim1, int dim2, int dim3)
+	{
+		m_iSize = 3;
+		m_pDims = new int [3];
+		m_pDims[0] = dim1;
+		m_pDims[1] = dim2;
+		m_pDims[2] = dim3;
+	}
+
+	CDims(int dim1, int dim2, int dim3, int dim4)
+	{
+		m_iSize = 4;
+		m_pDims = new int [4];
+		m_pDims[0] = dim1;
+		m_pDims[1] = dim2;
+		m_pDims[2] = dim3;
+		m_pDims[3] = dim4;
+	}
+
+	~CDims()
+	{
+		delete m_pDims;
+	}
+
+	operator int*()
+	{
+		return m_pDims;
+	}
+
+	int GetDims()
+	{
+		return  m_iSize;
+	}
+};
+
+
+#endif /* C++ */
+
+/*
+ * Interface routines are all declared so C/FORTRAN can get at them
+ */
+
+/* First get cross platform/language portability sorted out */
+
+#define CONCAT(__a,__b)	__a##__b
+
+#ifndef _WIN32
+#	if defined(__VMS)
+#		define MANGLE(__arg)	__arg
+#	elif defined(HAVE_LIBF2C)
+#		define MANGLE(__arg)	CONCAT(__arg,__)
+#	else /* __unix__ */
+#		define MANGLE(__arg)	CONCAT(__arg,_)
+#	endif
+#	define	GX_activate_session	MANGLE(gx_activate_session)
+#	define	GX_deactivate_session	MANGLE(gx_deactivate_session)
+#	define	GX_select_source	MANGLE(gx_select_source)
+#	define	GX_select_destination	MANGLE(gx_select_destination)
+#	define	GX_directory		MANGLE(gx_directory)
+#	define	GX_get			MANGLE(gx_get)
+#	define	GX_put			MANGLE(gx_put)
+#	define	GX_assign_handle	MANGLE(gx_assign_handle)
+#	define	GX_release_handle	MANGLE(gx_release_handle)
+#	define	GX_transfer		MANGLE(gx_transfer)
+#	define	GX_get_var_type		MANGLE(gx_get_var_type)
+#	define	GX_free				MANGLE(gx_free)
+#else
+#	define	GX_activate_session	GX_ACTIVATE_SESSION
+#	define	GX_deactivate_session	GX_DEACTIVATE_SESSION
+#	define	GX_select_source	GX_SELECT_SOURCE
+#	define	GX_select_destination	GX_SELECT_DESTINATION
+#	define	GX_directory		GX_DIRECTORY
+#	define	GX_get			GX_GET
+#	define	GX_put			GX_PUT
+#	define	GX_assign_handle	GX_ASSIGN_HANDLE
+#	define	GX_release_handle	GX_RELEASE_HANDLE
+#	define	GX_transfer		GX_TRANSFER
+#	define	GX_get_var_type		GX_GET_VAR_TYPE
+#	define	GX_free				GX_FREE
+#endif
+
+typedef const char* GDAI_STRING;	// Only string to be used in the DATA interface
+
+/*
+ * Define the external interface for FORTRAN and C/C++, note that for C we
+ * are just defining the interface, not the rest of the class stuff.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Get GENIE going */
+GENIEIMPORT int GENIEMECHANISM GX_activate_session( GDAI_STRING default_format, int inf, int debug );
+/* and the other thing */
+GENIEIMPORT int GENIEMECHANISM GX_deactivate_session( void );
+
+/* for file association and contents inspection */
+GENIEIMPORT int GENIEMECHANISM GX_select_source( GDAI_STRING filename );
+GENIEIMPORT int GENIEMECHANISM GX_select_destination( GDAI_STRING filename, GDAI_STRING file_format );
+GENIEIMPORT int GENIEMECHANISM GX_directory( GDAI_STRING filename );
+
+/* Data reading/writing */
+GENIEIMPORT int GENIEMECHANISM GX_get( GDAI_STRING handle, GDAI_STRING tag, int object_id );
+GENIEIMPORT int GENIEMECHANISM GX_put( GDAI_STRING handle, GDAI_STRING tag, int object_id, GDAI_STRING flag, GDAI_STRING comment );
+
+
+/* Routines for manipulating handles */
+GENIEIMPORT int GENIEMECHANISM GX_assign_handle( GDAI_STRING handle_lval, GDAI_STRING handle_rval );
+GENIEIMPORT int GENIEMECHANISM GX_release_handle( GDAI_STRING handle );
+
+/* Bi-directional access to Open GENIE Data objects */
+GENIEIMPORT int GENIEMECHANISM GX_transfer( GDAI_STRING handle, GDAI_STRING direction, GDAI_STRING data_type,
+                                  void* the_data, int* ndims, int dims[]);
+
+GENIEIMPORT int GENIEMECHANISM GX_get_var_type( GDAI_STRING var, void* the_data, int* len);
+
+GENIEIMPORT int GENIEMECHANISM GX_free(void* data, int is_array);
+
+/*
+ * Some other possibilities
+ * friend int GX_compress_file( const char* filename );
+ */
+
+#ifdef __cplusplus
+}
+
+// Currently there is only one session global to Open GENIE but this could change
+// When Open GENIE is running interatively this is initialized in main().
+#endif /* __cplusplus */
+
+
+#endif /* GENIE_DATA_ACCESS */
diff --git a/applications/NXtranslate/opengenie/geniedefs.h b/applications/NXtranslate/opengenie/geniedefs.h
new file mode 100644
index 0000000..f0febe6
--- /dev/null
+++ b/applications/NXtranslate/opengenie/geniedefs.h
@@ -0,0 +1,181 @@
+#ifndef GENIEDEFS__
+#define GENIEDEFS__
+
+#if defined(__unix__) && !defined(__unix)
+#define __unix 1
+#endif 
+
+/*
+ * Define the calling mechanism for calls external to C/C++
+ * ie FORTRAN and Windows system calls on Win32
+ */
+#ifdef _WIN32
+#	define GENIEMECHANISM __stdcall
+
+#	ifdef IN_GENIE_DLL					/* Test whether we are a user of */
+#		define GENIEIMPORT    __declspec( dllexport )	/* the dll or the producer */
+#		define GENIE_IMPLEMENTATION__			/* Only trap streams inside the DLL */
+#	else
+#		define GENIEIMPORT    __declspec( dllimport )	/* Import and export for Win 32 */
+#	endif
+
+#	define GENIEEXPORT    __declspec( dllexport )		/* DLL shareable libraries */
+
+#else
+#	define GENIEMECHANISM
+#	define GENIEIMPORT
+#	define GENIEEXPORT
+#endif
+
+
+ /* General definitions which pervade all GENIE source, not specific to the
+   parser or the smalltalk interpreter */
+#define LONGCHARBUFF	13200	    /* Should hold at least 100 lines of 132 column text */
+#define SHORTCHARBUFF	132	    /* One screen widths worth of 132 column text */
+
+
+/* PROJECT GLOBAL INCLUDES   
+ * =======================
+ * This breaks the rule of not nesting includes but is done to ensure that anything
+ * including geniedefs.h also gets the genie IO interface.  All the includes here are
+ * essential for iofuncs.h and hence will be included for the whole of Open GENIE.
+ */
+
+/* Include gnu autoconfig header file to sort out versioning */
+#ifdef HAVE_CONFIG_H
+#	if defined(READLINE_LIBRARY)
+#		include <readlineconfig.h>
+#	elif defined(__GST__)
+#		include <smalltalkconfig.h>
+#	elif defined(IN_TERMCAP)
+#		include <termcapconfig.h>
+#	endif
+#endif
+
+/* This include file must really be near the top of everything if it is used at all */
+#ifdef HAVE_LIBPTHREADS
+#	include <pthread.h>
+#endif
+
+#if defined(__VMS) && HAVE_LIBCMA
+#    define HAVE_LIBPTHREADS 	1
+#endif
+
+#ifdef _WIN32
+#	ifndef STRICT
+#	    define  STRICT 1	// Ensure we only use fully prototyped headers in win32
+#	endif
+#	include <windows.h>	// Include to make avoid namespace clashes later
+#	include <process.h>	// do this as we are multithreaded
+#	include <stdlib.h>	// Include this before iofuncs.h because stdlib defines perror
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+#   include <iostream>
+#	include <gnustring.h>
+#	if defined(_WIN32) && !defined(__VMS)
+#		include <sstream>
+#	else
+#		include <sstream>
+#	endif
+#   include <iomanip>
+#   ifdef __GNUG__
+#	define OMANIP(T) omanip<T>	// GNU uses templates normally
+#   endif
+#   include "genie_ostream.h"
+#endif
+
+
+/* Don't I/O Sabotage if this is included by a file outside GENIE */
+#ifdef GENIE_IMPLEMENTATION__	/* i.e. we are in the genie code */
+#   include "iofuncs.h"
+#endif
+
+/* END PROJECT GLOBAL INCLUDES */
+
+
+#ifdef __cplusplus
+#    define EXTERN_PREFIX extern "C"
+#else
+#    define EXTERN_PREFIX extern
+#endif /* __cplusplus */
+
+EXTERN_PREFIX const char* g_version;  /* GENIE wide versioning available */
+EXTERN_PREFIX void* genie_malloc(size_t nbytes); 
+EXTERN_PREFIX void genie_free(void* addr); 
+
+#define MAIL_GENIE_BUG 	"Please email a bug report to genie at isise.rl.ac.uk"
+
+/* 
+ *  This is taken from the CVS manual. If you have used a line of the form:
+ *
+ *   		static const char* rcsid = "$Id$";
+ *
+ * Then you should add the line:
+ * 
+ *		USE_RCSID(rcsid);
+ *
+ * Immediately below it so (1) it is not optimised away and (2) so you get no "unused variable" warnings
+ */ 
+
+/* #define USE_RCSID(rcsid)	static void* use_##rcsid = (&use_##rcsid, (void*)&rcsid) */
+#define USE_RCSID(rcsid)	static void* use_##rcsid = (void*)&rcsid
+
+#if (defined(vms) || defined(VMS)) && !defined(__VMS)
+#define __VMS
+#endif
+
+#if defined(__VMS) && !defined(VMS)
+#define VMS
+#endif
+
+/* 
+ * some file system specific definitions such as the
+ * character we need to insert when concatenating a directory
+ * and a file together to make a complete path 
+ */
+#if defined(__VMS)
+#define DIRECTORY_SEPARATOR	""
+#define NULL_OUTPUT_DEVICE	"NL:"
+#define CURRENT_DIRECTORY	"SYS$DISK:[]"
+#elif defined(_WIN32)
+#define DIRECTORY_SEPARATOR	"\\"
+#define NULL_OUTPUT_DEVICE	"NUL"
+#define CURRENT_DIRECTORY	"."
+#else	/* unix */
+#define DIRECTORY_SEPARATOR	"/"
+#define NULL_OUTPUT_DEVICE	"/dev/null"
+#define CURRENT_DIRECTORY	"."
+#endif
+#define CURRENT_DIRECTORY_PATH	CURRENT_DIRECTORY DIRECTORY_SEPARATOR
+
+
+/* 
+ * Replace sigsetjmp() and siglongjmp() if we lack them
+ */
+#ifndef HAVE_SIGJMP_BUF
+#define sigjmp_buf jmp_buf
+#define siglongjmp longjmp
+#define sigsetjmp(__env,__savemask)	setjmp(__env)
+#endif /* HAVE_SIGJMP_BUF */
+
+#ifdef __cplusplus
+    // Make available a global pointer to the GENIE object (needs casting by the user)
+    // This is set in the CGenie class on creation of a CGenie object
+    extern void* g_pGenie;
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#define my_strdup(__string) strcpy((char*)malloc(strlen(__string)+1), __string)
+
+#endif /* GENIEDEFS__ */
diff --git a/applications/NXtranslate/opengenie/nxgenie.gcl b/applications/NXtranslate/opengenie/nxgenie.gcl
new file mode 100644
index 0000000..9085aab
--- /dev/null
+++ b/applications/NXtranslate/opengenie/nxgenie.gcl
@@ -0,0 +1,129 @@
+#
+# $Id$
+#
+# Additional procedures needed by NXtranslate GENIE
+#
+# Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+#
+PRINTIN "Loading additional OpenGENIE  procedures"
+TOGGLE/INFO/OFF
+TOGGLE/DEBUG/OFF
+
+PROCEDURE MKISO
+PARAMETERS name=String
+RESULT RES
+LOCAL day month year s
+day=SUBSTRING(name,1,2)
+IF substring(day,1,1) = " "; day = "0" + substring(day,2,1); ENDIF
+month=substring(name,4,3)
+year=substring(name,8,4)
+IF month = "JAN"; s = "01"; ENDIF
+IF month = "FEB"; s = "02"; ENDIF
+IF month = "MAR"; s = "03"; ENDIF
+IF month = "APR"; s = "04"; ENDIF
+IF month = "MAY"; s = "05"; ENDIF
+IF month = "JUN"; s = "06"; ENDIF
+IF month = "JUL"; s = "07"; ENDIF
+IF month = "AUG"; s = "08"; ENDIF
+IF month = "SEP"; s = "09"; ENDIF
+IF month = "OCT"; s = "10"; ENDIF
+IF month = "NOV"; s = "11"; ENDIF
+IF month = "DEC"; s = "12"; ENDIF
+res <~ year + "-" + s + "-" + day
+ENDPROCEDURE
+
+PROCEDURE GETDAT
+QUALIFIERS /GANG # want values by spectrum
+PARAMETERS name=String num=Integer
+RESULT RES
+GLOBAL CNT1 SPEC UDET NSP NDET MDET NTC NMON sorted_spec LEN2 tcb tcb_widths
+LOCAL TMP dstidx i j dummy_int_array hdr
+IF NOT DEFINED(CNT1)
+    SPEC <~ GET("SPEC")
+    sorted_spec = spec
+    sort rank(spec) sorted_spec
+    UDET <~ GET("UDET")
+    nsp <~ GET("NSP1")
+    ntc <~ GET("NTC1")
+    tmp <~ GET("CNT1")
+    cnt1 <~ tmp[2:(nsp+1),2:(ntc+1)] # remove spectrum 0 and time channel 0
+    mdet <~ GET("MDET")
+    ndet <~ GET("NDET")
+    len2 <~ GET("LEN2")
+    nmon <~ GET("NMON")
+    tcb <~ GET("TIM1")
+    tcb_widths <~ tcb[2:(ntc+1)] - tcb[1:(ntc)]
+ENDIF
+IF name = "CNT1"
+    res <~ cnt1
+    RETURN
+ENDIF
+IF name = "START"
+    hdr <~ GET("HDR")
+    res <~ MKISO(substring(hdr,53,11)) + "T" + substring(hdr,65,8) + "Z"
+    RETURN
+ENDIF
+IF name = "END"
+    res <~ MKISO((GET("CRPB"))[17]) + "T" + (GET("CRPB"))[20] + "Z"
+    RETURN
+ENDIF
+dstidx <~ dimensions(nsp)
+fill dstidx 1 1
+IF name = "MON_DET"
+    IF (num > nmon); res = 0; RETURN; ENDIF
+    i <~ MDET[num]
+    IF (i < 1) OR (i > NDET); res = 0; RETURN; ENDIF
+    IF GANG
+        res <~ SPEC[i]
+    ELSE
+        res <~ UDET[i]
+    ENDIF
+    RETURN
+ENDIF
+IF name = "MON_DIST"
+    IF (num > nmon); res = 0.0; RETURN; ENDIF
+    i <~ MDET[num]
+    IF (i < 1) OR (i > NDET); res = 0.0; RETURN; ENDIF
+    res <~ len2[i]
+    RETURN
+ENDIF
+IF name = "MON"
+    dummy_int_array <~ dimensions(ntc)
+    fill dummy_int_array 0
+    IF (num > nmon); res <~ dummy_int_array; RETURN; ENDIF
+    i <~ MDET[num]
+    IF (i < 1) OR (i > NDET); res <~ dummy_int_array; RETURN; ENDIF
+    j <~ SPEC[i]
+    IF (j < 1) OR (j > NSP); res <~ dummy_int_array; RETURN; ENDIF
+    RES <~ redim(CNT1[j,1:(ntc)],ntc)
+    RETURN
+ENDIF
+IF GANG AND (name = "UDET")
+    RES <~ DSTIDX
+    RETURN
+ENDIF
+IF (name = "GROUP_INDEX")
+    dstidx <~ dimensions(ndet)
+    fill dstidx 1
+    RES <~ DSTIDX
+    RETURN
+ENDIF
+IF (name = "GANG_COUNT") OR (name = "GANG_INDEX")
+    TMP <~ UNIQUE_ELEMENTS:IGNMISS(sorted_spec, dstidx)
+    IF name = "GANG_COUNT"
+        res <~ tmp.counts
+    ENDIF
+    IF name = "GANG_INDEX"
+        res <~ tmp.offsets
+    ENDIF
+    RETURN
+ENDIF
+TMP <~ GET(NAME)
+IF GANG
+    RES <~ INDEXEDCOPY:ZEROMISSING:AVERAGE:IGNSRCDUP(dstidx,spec,tmp)
+ELSE
+    SORT RANK(SPEC) TMP 
+    RES <~ TMP
+ENDIF
+ENDPROCEDURE
+
diff --git a/applications/NXtranslate/opengenie/opengenie.c b/applications/NXtranslate/opengenie/opengenie.c
new file mode 100644
index 0000000..25ba1ab
--- /dev/null
+++ b/applications/NXtranslate/opengenie/opengenie.c
@@ -0,0 +1,123 @@
+/*
+ * $Id$
+ * 
+ * Open GENIE bindings to NXtranslate DynamicRetriever class
+ * implements functions required by dynamic_retriever.h
+ *
+ * Freddie Akeroyd, CCLRC ISIS Facility <F.A.Akeroyd at rl.ac.uk>
+ *
+ */
+#include <string.h>
+#include <stdlib.h>
+#include "napi.h"
+#include "genie_data_access.h"
+
+// this is called when a DynamicRetriever instance is created
+void* nxtinit(const char* source)
+{
+    char command[256];
+    GX_activate_session("GENIE",1,1);
+    if (getenv("NXGENIE_INIT") != NULL)
+    {
+	sprintf(command, "INCLUDE \"%s\"", getenv("NXGENIE_INIT"));
+        GX_assign_handle(command, "");
+    }
+    return strdup(source); // this will be passed back as "ref" argument to 
+                           // other functions. It can be anything e.g. a 
+                           // file pointer or handle
+}
+
+// this is called when a DynamicRetriever instance is destroyed
+int nxtcleanup(void* ref)
+{
+    free(ref);
+    return 0;
+}
+
+typedef enum { gnone=0, gstring, ginteger, greal, gstringarray, grealarray, gintegerarray } g_export_type;
+static const char* g_export_name[] = {
+ "NONE", "STRING", "INT32", "FLOAT64", "STRING[]", "FLOAT64[]", "INT32[]" };
+static const int g_export_size[] = {
+    0, 1, 4, 8, 1, 8, 4 };
+static const int g_nx_type[] = {
+ NX_CHAR, NX_CHAR, NX_INT32, NX_FLOAT64, NX_UINT8, NX_FLOAT64, NX_INT32 };
+
+// retrieves data from location specified in arg
+// arg is a complete genie expression that evaluates to a data object
+void* nxtgetdata(void* ref, const char* arg, int* data_type, int* dims_array, 
+              int* ndims, int* free_data)
+{
+    char* command;
+    void* result;
+    char genie_type[20];
+    int i, n, type_size;
+    g_export_type gtype;
+    *free_data = 1; // we want NXtranslate to call freedata() on "result" for us
+// set input source
+    GX_select_source((char*)ref);
+// assign results to temporary variable so we can 
+// gwt its type before transfer
+    command = malloc(strlen(arg) + 20);
+    sprintf(command, "__nxtmp <~ %s", arg);
+    GX_assign_handle(command, "");
+    free(command);
+    type_size = sizeof(genie_type);
+    GX_get_var_type("__nxtmp", genie_type, &type_size);
+    gtype = gnone;
+    switch(genie_type[0])
+    {
+	case 'S':  // "String"
+	    gtype = gstring;
+	    break;
+	case 'I':  // "Integer"
+	    gtype = ginteger;
+	    break;
+	case 'F':  // "Float"
+	    gtype = greal;
+	    break;
+	default:
+	    switch (genie_type[2])
+	    {
+		case 'S':  // "GXStringarray"
+		    gtype = gstringarray;
+		    break;
+		case 'I':  // "GXIntegerarray"
+		    gtype = gintegerarray;
+		    break;
+		case 'R':  // "GXRealarray"
+		    gtype = grealarray;
+		    break;
+		default:
+		    gtype = gnone;
+		    break;
+	    }
+    }
+    if (gtype == gnone)
+    {
+	GX_assign_handle("__nxtmp <~ \"<undefined>\"", "");
+	gtype = gstring;
+    }
+// get size
+    GX_transfer("__nxtmp", "-->", g_export_name[gtype], NULL, ndims, dims_array);
+// allocate storage and get real values
+    *data_type = g_nx_type[gtype];
+    n = 1;
+    for(i=0; i < *ndims; i++)
+    {
+	n *= dims_array[i];
+    }
+    result = malloc(n * g_export_size[gtype] + (gtype == gstring ? 1 : 0) );
+    GX_transfer("__nxtmp", "-->", g_export_name[gtype], result, ndims, dims_array);
+    if (gtype == gstring)
+    {
+        *((char*)result + n * g_export_size[gtype]) = '\0';
+    }
+    return result;
+}
+
+int nxtfreedata(void* ref, void* arg)
+{
+    free(arg);
+    return 0;
+}
+
diff --git a/applications/NXtranslate/retriever.cpp b/applications/NXtranslate/retriever.cpp
new file mode 100644
index 0000000..ed44405
--- /dev/null
+++ b/applications/NXtranslate/retriever.cpp
@@ -0,0 +1,131 @@
+#include <stdexcept>
+#include <map>
+#include "retriever.h"
+#include "nexus_retriever.h"
+
+#ifdef IPNS_RETRIEVER
+#include "IPNS_CPP/ipns_retriever.h"
+#endif
+#ifdef TEXT_PLAIN_RETRIEVER
+#include "text_plain/retriever.h"
+#endif
+#ifdef SPEC_RETRIEVER
+#include "spec/spec_retriever.h"
+#endif
+#ifdef EDF_RETRIEVER
+#include "esrf_edf/edf_retriever.h"
+#endif
+#ifdef TEXT_XML_RETRIEVER
+#include "text_xml/retriever.h"
+#endif
+#ifdef TEXT_COLLIST_RETRIEVER
+#include "text_collist/collist_retriever.h"
+#endif
+#ifdef BINARY_RETRIEVER
+#include "binary/BinaryRetriever.hpp"
+#endif
+#ifdef DYNAMIC_RETRIEVER
+#include "dynamic_retriever.h"
+#endif
+#ifdef SNS_HISTOGRAM_RETRIEVER
+#include "sns_histogram/retriever.h"
+#endif
+#ifdef FRM2_RETRIEVER
+#include "FRM2/frm2_retriever.h"
+#endif
+#ifdef LOOPY_RETRIEVER
+#include "loopy/retriever.h"
+#endif
+
+using std::map;
+using std::string;
+using std::invalid_argument;
+
+typedef Ptr<Retriever> RetrieverPtr;
+
+// hold a map of retrievers that have been instantiated so it can be cached
+map<string, RetrieverPtr> retrievers;
+
+RetrieverPtr getNewInstance(const string & type,
+                            const string & source) {
+  // return appropriate retriever based on type
+  if(type==NexusRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new NexusRetriever(source));
+    return ptr;
+#ifdef IPNS_RETRIEVER
+  }else if(type==IpnsRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new IpnsRetriever(source));
+    return ptr;
+#endif
+#ifdef TEXT_PLAIN_RETRIEVER
+  }else if(type==TextPlainRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new TextPlainRetriever(source));
+    return ptr;
+#endif
+#ifdef SPEC_RETRIEVER
+  }else if(type==SpecRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new SpecRetriever(source));
+    return ptr;
+#endif
+#ifdef EDF_RETRIEVER
+  }else if(type==EdfRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new EdfRetriever(source));
+    return ptr;
+#endif
+#ifdef TEXT_COLLIST_RETRIEVER
+  }else if(type==TextCollistRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new TextCollistRetriever(source));
+    return ptr;
+#endif
+#ifdef TEXT_XML_RETRIEVER
+  }else if(type==TextXmlRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new TextXmlRetriever(source));
+    return ptr;
+#endif
+#ifdef BINARY_RETRIEVER
+  }else if(type==BinaryRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new BinaryRetriever(source));
+    return ptr;
+#endif
+#ifdef DYNAMIC_RETRIEVER
+  }else if(type.substr(0,8) == "dynamic/"){
+    RetrieverPtr ptr(new DynamicRetriever(source, type));
+    return ptr;
+#endif
+#ifdef SNS_HISTOGRAM_RETRIEVER
+  }else if(type==SnsHistogramRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new SnsHistogramRetriever(source));
+    return ptr;
+#endif
+#ifdef FRM2_RETRIEVER
+  }else if(type==Frm2Retriever::MIME_TYPE){
+    RetrieverPtr ptr(new Frm2Retriever(source));
+    return ptr;
+#endif
+#ifdef LOOPY_RETRIEVER
+  }else if(type==LoopyRetriever::MIME_TYPE){
+    RetrieverPtr ptr(new LoopyRetriever(source));
+    return ptr;
+#endif
+  }
+
+  // if it gets this far the type is not understood
+  throw invalid_argument("do not understand mime_type ("+type+") in retriever_factory");
+}
+
+// Implementation of a pure virtual destructor. This makes the compiler happy.
+Retriever::~Retriever(){}
+
+// factory method
+Retriever::RetrieverPtr Retriever::getInstance(const string & type,
+                                               const string &source){
+  map<string, RetrieverPtr>::iterator existing = retrievers.find(source);
+  if (existing != retrievers.end()) {
+    return (existing->second);
+  }
+  else {
+    RetrieverPtr retriever = getNewInstance(type, source);
+    retrievers.insert(make_pair(source, retriever));
+    return retriever;
+  }
+}
diff --git a/applications/NXtranslate/retriever.h b/applications/NXtranslate/retriever.h
new file mode 100644
index 0000000..7a0b540
--- /dev/null
+++ b/applications/NXtranslate/retriever.h
@@ -0,0 +1,52 @@
+#ifndef __RETRIEVER_H_GAURD
+#define __RETRIEVER_H_GAURD
+
+#include <string>
+#include "node.h"
+#include "tree.hh"
+#include "Ptr.h"
+
+/**
+ * The design of this class is that a factory will use a key to choose
+ * which concrete Retriever to create and return. The Retriever will
+ * then return partial trees each time that getData(string) is
+ * called. In practice getData(string) will be called several times
+ * with each instance.
+ */
+class Retriever{
+  typedef Ptr<Retriever> RetrieverPtr;
+
+ public:
+  /**
+   * The factory will call the constructor with a string. The string
+   * specifies where to locate the data (e.g. a filename), but
+   * interpreting the string is left up to the implementing code.
+   */
+  //Retriever(const std::string &);
+
+  /**
+   * The destructor must be virtual to make sure the right one is
+   * called in the end.
+   */
+  virtual ~Retriever()=0;
+
+  /**
+   * This is the method for retrieving data from a file. The whole
+   * tree will be written to the new file immediately after being
+   * called. Interpreting the string is left up to the implementing
+   * code.
+   */
+  virtual void getData(const std::string &, tree<Node> &)=0;
+
+  /**
+   * This method is to be used for debugging purposes only. While the
+   * string can be anything, most useful is "[mime_type] source".
+   */
+  virtual std::string toString() const=0;
+
+  /**
+   * Factory method to create new retrievers.
+   */
+  static RetrieverPtr getInstance(const std::string &, const std::string &);
+};
+#endif
diff --git a/applications/NXtranslate/sns_histogram/CMakeLists.txt b/applications/NXtranslate/sns_histogram/CMakeLists.txt
new file mode 100644
index 0000000..1ce0fb5
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/CMakeLists.txt
@@ -0,0 +1,33 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (SNShistogram STATIC string_location_format.cpp string_location_format.h
+                                 SNS_retriever.cpp SNS_retriever.hpp retriever.hpp)
+
diff --git a/applications/NXtranslate/sns_histogram/Makefile.am b/applications/NXtranslate/sns_histogram/Makefile.am
new file mode 100644
index 0000000..dc2ade6
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libSNShistogram.la
+
+libSNShistogram_la_SOURCES = \
+	string_location_format.cpp string_location_format.h \
+        SNS_retriever.cpp SNS_retriever.hpp retriever.hpp
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+EXTRA_DIST = retriever_test.cpp
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/sns_histogram/SNS_retriever.cpp b/applications/NXtranslate/sns_histogram/SNS_retriever.cpp
new file mode 100644
index 0000000..8fad73f
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/SNS_retriever.cpp
@@ -0,0 +1,1686 @@
+#include "retriever.hpp"
+
+#define SWAP_ENDIAN  //triger the swapping endian subroutine (if needed)
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+   
+/*********************************
+/SnsHistogramRetriever constructor
+/*********************************/
+SnsHistogramRetriever::SnsHistogramRetriever(const string &str): source(str) 
+{
+  // open the file
+  BinaryFile=fopen(source.c_str(),"rb");
+  
+  // check that open was successful
+  if (BinaryFile==NULL)
+    throw invalid_argument("Could not open file: "+source);
+}
+
+/*********************************
+/SnsHistogramRetriever destructor
+/*********************************/
+SnsHistogramRetriever::~SnsHistogramRetriever()
+{
+  // close the file
+  if(BinaryFile)
+    fclose(BinaryFile);
+}
+
+/**
+ * \brief This function creates the array according to the 
+ * string location
+ *
+ * \param location (INPUT) is the string location coming from the 
+ * translation file
+ * \param tr (INPUT) is where to put the final array created
+ */
+void SnsHistogramRetriever::getData(const string &location, tree<Node> &tr)
+{
+  string new_location;
+  string definition_version_with_groups = "";  //use to determine priorities
+
+  vector<string> decla_def;           //declaration and definition parts
+  vector<string> LocGlobArray; //local and global array (declaration part)
+  vector<string> Ope;                //Operators of the defintion part
+  int OperatorNumber; 
+  string DefinitionPart;             //use to determine the operators
+  vector<int> GrpPriority;           //Vector of priority of each group
+  vector<int> OpePriority;           //Vector of priority for each operator
+  vector<int> InverseDef; //True=Inverse definition, False=keep it like it is
+  int Everything = 0;                //0= we don't want everything, 1=we do
+  int GlobalArraySize = 1;           //Size of global array within our program
+  vector<string> Tag, Def;
+  vector<int> LocalArray, GlobalArray;
+
+  vector<Grp_parameters> GrpPara;
+  Grp_parameters record;
+
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    throw invalid_argument("cannot parse empty string");
+  
+  //format the string location (remove white spaces)
+  without_white_spaces(location, new_location);  
+  
+  DeclaDef_separator(new_location, decla_def);  //Separate Declaration part from Definition part -> decla_def
+  
+  //check if the defintion part has a valid format
+  if (decla_def[1].size() > 0 && decla_def[1].size()<7)
+    throw runtime_error("Definition part is not valid");
+  
+  //check if we want everything
+  check_want_everything (decla_def, Everything, Tag, Ope);
+  
+  //Separate declaration arrays (local and global)
+  declaration_separator(decla_def[0], LocGlobArray);
+  
+  if (Everything == 0)
+    {
+      //Work on definition part
+      DefinitionPart = decla_def[1];
+      
+      //Parse defintion part, separate Tag from Def
+      TagDef_separator(decla_def[1], Tag, Def, definition_version_with_groups);
+      
+      //check if we have at least one tag
+      if (Tag.size()<1)
+	throw runtime_error("Definition part is not valid");
+      
+      //Store operators
+      OperatorNumber = Tag.size();
+      store_operators(DefinitionPart,
+                      OperatorNumber, 
+                      Ope);
+      
+      //Give to each grp its priority
+      assign_grps_priority(definition_version_with_groups, 
+                           OperatorNumber, 
+                           GrpPriority, 
+                           InverseDef,
+                           OpePriority);   
+      
+      //Store parameters of the definition part into GrpPara[0], GrpPara[1]...
+      
+      store_para_of_definition(Def,
+                               OperatorNumber,
+                               GrpPara,
+                               record);
+    }
+  
+  //parse Local and Global Array from Declaration part
+  parse_declaration_array(LocGlobArray, 
+                          LocalArray, 
+                          GlobalArray);
+  
+  //allocate memory for the binary Array
+  for (int i=0; i<GlobalArray.size(); i++)
+    {
+      GlobalArraySize *= GlobalArray[i];
+    }
+  
+  binary_type * BinaryArray = new binary_type [GlobalArraySize];
+  
+  //transfer the data from the binary file into the GlobalArray
+  fread(&BinaryArray[0],sizeof(BinaryArray[0]), GlobalArraySize, BinaryFile);
+  
+  //swap endian if necessary
+#ifdef SWAP_ENDIAN
+
+  swap_endian (GlobalArray, BinaryArray);
+  
+#endif  //SWAP_ENDIAN
+  
+  //Calculate arrays according to definition
+  calculate_array(GrpPriority,
+                  InverseDef, 
+                  BinaryArray, 
+                  Ope, 
+                  OpePriority, 
+                  tr,
+                  Tag,
+                  Def,
+                  LocalArray,
+                  GlobalArray,
+                  GrpPara);
+}
+
+/*********************************
+/SnsHistogramRetriever::MIME_TYPE 
+/*********************************/
+const string SnsHistogramRetriever::MIME_TYPE("application/x-SNS-histogram");
+
+string SnsHistogramRetriever::toString() const
+{
+  return "["+MIME_TYPE+"] "+source;
+}
+
+/**
+ * \brief This function isolate the different parameters of the definition
+ * part of the location string
+ *
+ * \param def (INPUT) is the full definition part of the string location
+ * \param OperatorNumber (INPUT) is the number of definition part the
+ * string location contains
+ * \para GrpPara (OUTPUT) is the list of operators (loop or list of 
+ * identifiers
+ * \param record (OUTPUT) is a structure Grp_parameters that contains
+ * all the information of the different defintion part
+ */
+void store_para_of_definition(vector<string> Def, 
+                              int HowManyDef, 
+                              vector<Grp_parameters> & GrpPara, 
+                              Grp_parameters & record)
+{
+  //find out first if it's a loop or a list of identifiers
+  for (int i=0; i<HowManyDef ; ++i)
+    {
+      if (Def[i].find("loop") < Def[i].size()) 
+	{
+	  record.c = 'l';
+        }
+      else
+	{
+	  record.c = 'p';
+        }
+      GrpPara.push_back(record);
+    }
+  
+  //isolate the variable
+  for (int i=0; i<HowManyDef ; ++i)
+    {
+      if (GrpPara[i].c == 'l')      //loop
+	{
+	  InitLastIncre(Def[i],i, GrpPara);
+	}
+      else                          //(....)
+	{
+	  ParseGrp_Value(Def[i],i, GrpPara);
+	}
+    }
+ return;
+}
+
+/**
+ * brief This function parse the definition and isolate the three parts 
+ * of the loop definition; the initial value, the final value and the increment
+ *
+ * \param def (INPUT) the definition part to parse
+ * \param i (INPUT) the index of the defintion part to parse
+ * \param GrpPara (OUTPUT) the Grp_parameters structre of the defintion part
+ */
+void InitLastIncre (string & def, 
+                    int i, 
+                    vector<Grp_parameters> & GrpPara)
+{
+  static const string sep=",";
+  int pos1, pos2;
+  string new_def;
+  
+  //Remove "loop(" and ")"
+  def=def.substr(5,def.size()-6);
+  
+  //store the info into GrpPara[i].init, end and increment
+  pos1 = def.find(sep);
+  new_def = def.substr(pos1+1,def.size()-pos1);
+  pos2 = new_def.find(sep);
+ 
+  GrpPara[i].init =atoi((def.substr(0,pos1)).c_str());
+  GrpPara[i].last =atoi((def.substr(pos1+1,pos2).c_str()));
+  GrpPara[i].increment = atoi((new_def.substr(pos2+1, new_def.size()-1).c_str()));
+  
+  return;
+}
+
+/**
+ * \brief This function parses the value of the list of identifiers
+ *
+ * \param def (INPUT) is the definition part to parse
+ * \param GrpPara (INPUT) is the Grp_parameters structure of the list of 
+ * identifiers
+ */
+void ParseGrp_Value(string& def, int i, 
+                    vector<Grp_parameters> & GrpPara)
+{
+  int b=0, a=0;
+
+  while (b <= def.size())
+    {
+      if (def[b]==',')
+	{
+	  GrpPara[i].value.push_back(atoi((def.substr(a,b-a)).c_str()));
+	  a=b+1;
+	}
+      if (b==def.size())
+	{
+	  GrpPara[i].value.push_back(atoi((def.substr(a,b-a)).c_str()));
+	}
+      ++b;
+    }
+
+  return;
+}
+
+/**
+ * \brief This function parse the local and global array of the 
+ * declaration part
+ *
+ * \param LocGlobArray (INPUT) is the full string of the declaration part
+ * \param LocalArray (OUTPUT) is the list of parameters of the local part
+ * \param GlobalArray (OUTPUT) is the list of parameters of the global part
+ */
+void parse_declaration_array(vector<string> & LocGlobArray,
+                             vector<int> & LocalArray,
+                             vector<int> & GlobalArray)
+{
+  int a=0, b=0;
+  
+  //Parse Local array
+  int i=0;
+  
+  //remove square braces
+  LocGlobArray[i]=LocGlobArray[i].substr(1,LocGlobArray[i].size()-2);
+  
+  while (b <= LocGlobArray[i].size())
+    {
+      if (LocGlobArray[i][b]==',')
+	{
+	  LocalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+          a=b+1;}
+	
+      if (b==LocGlobArray[i].size())
+	{
+	  LocalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+        }
+	
+      ++b;
+    }
+
+  i=1,a=0,b=0;
+  
+  //Parse Global Array
+  
+  //remove square braces
+  LocGlobArray[i]=LocGlobArray[i].substr(1,LocGlobArray[i].size()-2);
+  
+  while (b <= LocGlobArray[i].size())
+    {
+      if (LocGlobArray[i][b]==',')
+	{
+	  GlobalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+          a=b+1;}
+	
+      if (b==LocGlobArray[i].size())
+	{
+	  GlobalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+        }
+      
+      ++b;
+    }
+
+  return;
+}
+
+/**
+ * \brief This function calculates the final array according to the 
+ * string location
+ *
+ * \param GrpPriority (INPUT) is a list of the groups priorities
+ * \param InverseDef (INPUT) inverses or not the meaning of the definition
+ * part having the same index
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param Ope (INPUT) is the list of the operators
+ * \param OpePriority (INPUT) is a list of the operator priorities
+ * \param tr (INPUT) is the final location of the array in the NeXus file
+ * \param Tag (INPUT) is the list of the tag_names
+ * \param Def (INPUT) is the list of the tag_definitions
+ * \param LocalArray (INPUT) is the list of parameters of the local declaration
+ * part
+ * \param GlobalArray (INPUT) is the list of parameters of the global 
+ * declaration part
+ * \param GrpPara (INPUT) is a list of structures of all the parameters of the
+ * defintion part
+ */
+void calculate_array (vector<int> & GrpPriority, 
+                      vector<int> & InverseDef, 
+                      binary_type * BinaryArray, 
+                      vector<string> Ope, 
+                      vector<int> & OpePriority, 
+                      tree<Node> & tr, 
+                      vector<string> & Tag, 
+                      vector<string> & Def, 
+                      vector<int> & LocalArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara)
+{
+  int HighestPriority;
+  int GrpNumber = GrpPriority.size();
+  int ArraySize = 1;
+  int ArraySizeGlobal = 1;
+ 
+  if (Tag[0]!="*")
+    {
+      HighestPriority = FindMaxPriority(GrpPriority);
+    }
+  
+  //determine array size
+  for (int i=0 ; i<LocalArray.size() ; ++i)
+    {
+      ArraySize *= LocalArray[i];
+    }
+  
+  if (Tag[0] == "*")
+    {
+      GrpNumber=1;
+      GrpPriority.push_back(1);
+    }
+  
+  //determine array size
+  for (int i=0 ; i<GlobalArray.size() ; ++i)
+    {
+      ArraySizeGlobal *= GlobalArray[i];
+    }
+  
+  //Allocate memory for each grp
+  binary_type **MyGrpArray;
+  MyGrpArray = new binary_type*[GrpPriority.size()];
+
+  for (int i=0 ; i<GrpPriority.size() ; ++i)
+    {
+      MyGrpArray[i]=new binary_type[ArraySizeGlobal];
+      InitializeArray(MyGrpArray[i], GlobalArray);
+    }
+
+  //Allocate memory for the final array created
+  void * NewArray;
+  int rank=3;
+  std::vector<int> dims(GlobalArray.size());
+  for (int j=0 ; j< GlobalArray.size() ; ++j)
+    {
+      dims[j]=GlobalArray[j];
+    }
+  
+  //  int dims[]={3,10,5};
+  NXmalloc(&NewArray,rank,&(dims[0]),NX_INT32);
+  
+  //make an array for each group
+  for (int i=0 ; i<GrpPriority.size() ; ++i)
+    {
+      
+      if (Tag[i]=="pixelID") 
+        {
+          MakeArray_pixelID(MyGrpArray[i],
+                            BinaryArray,
+                            i,
+                            InverseDef[i], 
+                            Def, 
+                            LocalArray, 
+                            GlobalArray, 
+                            GrpPara);
+        }
+      else if (Tag[i]=="pixelX")
+        {
+          MakeArray_pixelX(MyGrpArray[i],
+                           BinaryArray,
+                           i,
+                           InverseDef[i], 
+                           Def, 
+                           LocalArray, 
+                           GlobalArray, 
+                           GrpPara);
+        }
+      else if (Tag[i]=="pixelY")
+        {
+          
+          MakeArray_pixelY(MyGrpArray[i],
+                           BinaryArray,
+                           i,
+                           InverseDef[i], 
+                           Def, 
+                           LocalArray, 
+                           GlobalArray, 
+                           GrpPara);
+        }
+      else if (Tag[i]=="Tbin")
+        {
+          MakeArray_Tbin(MyGrpArray[i],
+                         BinaryArray,
+                         i,
+                         InverseDef[i], 
+                         Def, 
+                         LocalArray, 
+                         GlobalArray, 
+                         GrpPara);
+        }
+      else if (Tag[i]=="*")
+        {
+          MakeArray_Everything(MyGrpArray[i],
+                               BinaryArray, 
+                               LocalArray, 
+                               GlobalArray);
+        }
+    }
+  
+  //free memory of binary array 
+  delete[] BinaryArray;    
+  
+  //calculate the final Array according to all the parameters 
+  //retrieved in the rest of the code 
+  MakePriorities (GrpPriority, 
+                  HighestPriority, 
+                  OpePriority, 
+                  MyGrpArray, 
+                  GlobalArray, 
+                  LocalArray, 
+                  Ope, 
+                  GrpPara);
+ 
+  NewArray = MyGrpArray[0];
+  
+  delete[] MyGrpArray;  
+  
+  //write into nexus file
+  Node node("New Array from string location",NewArray,rank,&(dims[0]),NX_INT32);
+  
+  tr.insert(tr.begin(),node);   
+  
+  NXfree(&NewArray);
+  
+  return;  
+}
+
+/**
+ * \brief This function determines the highest priority of all the groups.
+ * A group is a set of operation, can be a loop or a list of identifiers
+ *
+ * \param GrpPriority (INPUT) is the list of the priority
+ *
+ * \return the last maximum value of the list
+ */
+int FindMaxPriority (vector<int> & GrpPriority)
+{
+  int MaxValue = 0;
+  
+  for (int i=0 ; i<GrpPriority.size() ; ++i)
+    {
+      if (GrpPriority[i]>MaxValue)
+        {
+          MaxValue = GrpPriority[i];
+        }
+    }
+
+  return MaxValue;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is PixelID
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelID (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        int grp_number, 
+                        int InverseDef, 
+                        vector<string> & Def, 
+                        vector<int> & LocalArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0])  //case with loop
+    {
+      
+      if (InverseDef==1)    //case inverse for loop
+        {
+          InversePixelIDLoop (MyGrpArray, 
+                              BinaryArray, 
+                              GlobalArray, 
+                              GrpPara, 
+                              grp_number);
+        }
+      else   //normal case for loop
+        {
+          PixelIDLoop (MyGrpArray, 
+                       BinaryArray, 
+                       GlobalArray, 
+                       GrpPara, 
+                       grp_number);
+        }
+    }
+  else   //case with list of identifiers
+    {
+      if (InverseDef==1)   //case inverse for list
+        {
+          InversePixelIDList (MyGrpArray, 
+                              BinaryArray, 
+                              GlobalArray, 
+                              GrpPara, 
+                              grp_number);
+        }
+      else   //normal case for list
+        {
+          PixelIDList (MyGrpArray, 
+                       BinaryArray, 
+                       GlobalArray, 
+                       GrpPara, 
+                       grp_number);
+        }
+    }
+  
+  return;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is PixelX
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelX (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0]) 
+    {
+      if (InverseDef==1)   //case inverse with loop
+        {
+          InversePixelXLoop (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else   //normal case with loop
+        {
+          PixelXLoop (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }  
+  else
+    {
+      if(InverseDef==1) //case inverse with list
+        {
+          InversePixelXList (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else   //normal case with list
+        {
+          PixelXList (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is PixelY
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelY (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0]) 
+    {
+      if (InverseDef==1)  //inverse case for loop
+        {
+          InversePixelYLoop (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else  //normal case for loop
+        {
+          PixelYLoop (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }
+  else
+    {
+      if (InverseDef==1)   //case inverse with list
+        {
+          InversePixelYList (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else    //normal case
+        {
+          PixelYList (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is Tbin
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_Tbin (binary_type* MyGrpArray, 
+                     binary_type* BinaryArray,
+                     int grp_number,
+                     int InverseDef, 
+                     vector<string> & Def, 
+                     vector<int> & LocalArray, 
+                     vector<int> & GlobalArray, 
+                     vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0]) 
+    {
+      if (InverseDef ==1)  //case inverse with loop
+        {
+          InverseTbinLoop (MyGrpArray, 
+                           BinaryArray, 
+                           GlobalArray, 
+                           GrpPara, 
+                           grp_number);
+        }
+      else   //normal case with loop
+        {
+          TbinLoop (MyGrpArray, 
+                    BinaryArray, 
+                    GlobalArray, 
+                    GrpPara, 
+                    grp_number);
+        }
+    }
+  else
+    {
+      if (InverseDef==1)  //case inverse with list
+        {
+          InverseTbinList (MyGrpArray, 
+                           BinaryArray, 
+                           GlobalArray, 
+                           GrpPara, 
+                           grp_number);
+        }
+      else  //normal case with list
+        {
+          TbinList (MyGrpArray, 
+                    BinaryArray, 
+                    GlobalArray, 
+                    GrpPara, 
+                    grp_number);
+        }
+    }
+  
+  return;
+}
+
+/**
+ * \brief This function makes a copy of the binary array
+ *
+ * \param MyGrpArray (OUTPUT) is the local copy of the binary array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the global
+ * declaration part
+ */
+void  MakeArray_Everything (binary_type* MyGrpArray, 
+                            binary_type* BinaryArray, 
+                            vector<int> & LocalArray, 
+                            vector<int> & GlobalArray)
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0;tbin<GlobalArray[2];++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+\
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+\
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }	     
+        }
+    }
+  return ;
+}
+
+/**
+ * \brief This function does the actual calculation between the two
+ * arrays that are pass in
+ *
+ * \param GrpArray1 (INPUT/OUTPUT) is the first array to operate on
+ * \param GrpArray2 (INPUT) is the second array to operate on
+ * \param Operator (INPUT) is the operator (or,and)
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the 
+ * global declarataion part
+ * \param GrpPara (INPUT) ??? not used ???
+*/
+void DoCalculation (binary_type * GrpArray1, 
+                    binary_type * GrpArray2, 
+                    string Operator, 
+                    vector<int> & LocalArray, 
+                    vector<int> & GlobalArray, 
+                    vector<Grp_parameters> & GrpPara)
+{
+  string OR="OR";
+  
+  if (Operator[0] == OR[0])
+    {
+      for (int y=0 ; y<GlobalArray[0] ; ++y)
+        {
+          for (int x=0 ; x<GlobalArray[1] ; ++x)
+            { 
+              for (int tbin=0;tbin<GlobalArray[2];tbin++)
+                {	  
+                  if ((GrpArray1[(x*GlobalArray[2]+tbin)+
+                                 (y*GlobalArray[2]*GlobalArray[1])]==0)&&
+                      (GrpArray2[(x*GlobalArray[2]+tbin)+
+                                 (y*GlobalArray[2]*GlobalArray[1])]!=0))
+                    {
+                      GrpArray1[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])]=
+                        GrpArray2[(x*GlobalArray[2]+tbin)+
+                                  (y*GlobalArray[2]*GlobalArray[1])];
+                    }
+                }
+            }
+        }
+    }
+  else
+    {
+      for (int y=0 ; y<GlobalArray[0] ; ++y)
+        {
+          for (int x=0 ; x<GlobalArray[1]; ++x)
+            {
+              for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+                {
+                  if (GrpArray2[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])]!=
+                      GrpArray1[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])])
+                    {
+                      GrpArray1[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])]=0;
+                    }	     
+                }
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function swap endians
+ *
+ * \param x (INPUT/OUTPUT) number to swap
+ */
+inline void endian_swap (binary_type & x)
+{
+  x = ((x>>24) & 0x000000FF) |
+    ((x<<8) & 0x00FF0000) |
+    ((x>>8) & 0x0000FF00) |
+    ((x<<24) & 0xFF000000);
+}
+
+/**
+ * \brief This function initialize the array to 0
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the array to initialized
+ * \param GlobalArray (INPUT) is the dimension of the array
+ */
+void InitializeArray(binary_type * MyGrpArray, 
+                     vector<int> & GlobalArray)
+{
+  for (int a=0 ; a<GlobalArray[1] ; ++a)
+    {
+      for (int b=0 ; b<GlobalArray[0] ; ++b)
+	{
+	  for (int c=0 ; c<GlobalArray[2] ; ++c)
+	    {
+	      MyGrpArray[c+b*GlobalArray[1]*
+                         GlobalArray[2]+a*GlobalArray[2]]=0;
+	    }
+	}
+    }  
+  return;   
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+*/
+void InversePixelIDLoop (binary_type * MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int i=GrpPara[grp_number].init;i<=GrpPara[grp_number].last;i=
+         i+GrpPara[grp_number].increment)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[i*GlobalArray[2]+tbin]=0;
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDLoop (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number)
+{
+  for (int i=GrpPara[grp_number].init;
+       i<=GrpPara[grp_number].last;
+       i=i+GrpPara[grp_number].increment)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[i*GlobalArray[2]+tbin]=
+            BinaryArray[i*GlobalArray[2]+tbin];
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelIDList (binary_type * MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int j=0 ; j<GrpPara[grp_number].value.size() ; ++j)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[GrpPara[grp_number].value[j]*GlobalArray[2]+tbin]=0;
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDList (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number)
+{
+  for (int j=0 ; j<GrpPara[grp_number].value.size() ; ++j)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[GrpPara[grp_number].value[j]*GlobalArray[2]+tbin]=
+            BinaryArray[GrpPara[grp_number].value[j]*GlobalArray[2]+tbin];
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x = GrpPara[grp_number].init; 
+           x <= GrpPara[grp_number].last; 
+           x = x + GrpPara[grp_number].increment)
+        {
+          for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXLoop (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number)
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x = GrpPara[grp_number].init; 
+           x <= GrpPara[grp_number].last; 
+           x = x + GrpPara[grp_number].increment)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2]; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GrpPara[grp_number].value.size() ; ++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(GrpPara[grp_number].value[x]*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number)
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GrpPara[grp_number].value.size() ; ++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(GrpPara[grp_number].value[x]*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(GrpPara[grp_number].value[x]*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=GrpPara[grp_number].init; 
+       y<=GrpPara[grp_number].last; 
+       y=y + GrpPara[grp_number].increment)
+    {
+      for (int x=0; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYLoop  (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number) 
+{
+  for (int y=GrpPara[grp_number].init; 
+       y<=GrpPara[grp_number].last; 
+       y=y + GrpPara[grp_number].increment)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GrpPara[grp_number].value.size() ; ++y)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (GrpPara[grp_number].value[y]*
+                          GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        }
+    } 
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number) 
+{
+  for (int y=0 ; y<GrpPara[grp_number].value.size() ; ++y)
+    {
+      for (int x=0; x<GlobalArray[1] ;++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+	    {
+	      MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (GrpPara[grp_number].value[y]*
+                          GlobalArray[2]*GlobalArray[1])]= 
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (GrpPara[grp_number].value[y]*
+                             GlobalArray[2]*GlobalArray[1])];
+	    }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinLoop (binary_type * MyGrpArray, 
+                      binary_type * BinaryArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara, 
+                      int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y )
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=GrpPara[grp_number].init; 
+               tbin <= GrpPara[grp_number].last; 
+               tbin = tbin + GrpPara[grp_number].increment)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinLoop (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number) 
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y )
+    {
+      for (int x=0; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=GrpPara[grp_number].init; 
+               tbin <= GrpPara[grp_number].last;
+               tbin = tbin + GrpPara[grp_number].increment)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinList  (binary_type * MyGrpArray, 
+                       binary_type * BinaryArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara, 
+                       int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0 ; tbin<GrpPara[grp_number].value.size() ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+GrpPara[grp_number].value[tbin])+
+                         y*GlobalArray[2]*GlobalArray[1]]=0;
+            }
+        }
+    } 
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinList (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number) 
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0 ; tbin<GrpPara[grp_number].value.size() ; tbin++)
+            {
+              MyGrpArray[(x*GlobalArray[2]+GrpPara[grp_number].value[tbin])+
+                         y*GlobalArray[2]*GlobalArray[1]]= 
+		BinaryArray[(x*GlobalArray[2]+GrpPara[grp_number].value[tbin])+
+                            y*GlobalArray[2]*GlobalArray[1]];
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function check for the highest priority in all the groups
+ *
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param CurrentPriority (INPUT/OUTPUT) is the current highest priority
+ * \param GrpPriority (INPUT) is the list of the groups priority
+ */
+void CheckHighestPriority (int & GrpPriority_size, 
+                           int &  CurrentPriority, 
+                           vector<int> & GrpPriority)
+{
+  int find_one = 0;
+  for (int m=0 ; m<GrpPriority_size ; ++m)
+    {
+      if (GrpPriority[m] >= CurrentPriority)
+        {
+          find_one = 1;
+          break;
+        }
+    }
+  if (find_one == 0)
+    {
+      --CurrentPriority;
+    }
+  return;
+}
+
+/**
+ * \brief This function shift to the left all the priority of the groups
+ * behind index i
+ *
+ * \param GrpPriority (INPUT/OUTPUT) is the list of groups priority
+ * \param GrpPriority_size (INPUT) is the size of the groups priority
+ * \param i (INPUT) is the index of the group priority of interest
+ */
+void Shift_GrpPriorities_Left (vector<int> & GrpPriority, 
+                               int & GrpPriority_size, 
+                               int & i)
+{
+  for (int k=i+1 ; k<GrpPriority_size-1 ; ++k)
+    {
+      GrpPriority[k]=GrpPriority[k+1];
+    }
+  return;
+}
+
+/**
+ * \brief This function shift to the left all the operators behind index i
+ *
+ * \param OpePriority (INPUT/OUTPUT) is the list of operator priority
+ * \param Ope (INPUT/OUTPUT) is the list of operators 
+ * \param GrpPriority_size (INPUT) is the number of groups 
+ * \param i (INPUT) is the index of the operator priority of interest
+ */
+void Shift_Ope_OpePriority_Left (vector<int> & OpePriority, 
+                                 vector<string> & Ope, 
+                                 int & GrpPriority_size, 
+                                 int & i)
+{
+  for (int j=i;j<GrpPriority_size-2;++j)
+    {
+      OpePriority[j]=OpePriority[j+1];
+      Ope[j]=Ope[j+1];
+    }
+  return;
+}
+
+/**
+ * \brief This function shift to the left all the array corresponding to 
+ * each groups
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) are the array of each group
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param i (INPUT) is the index of the array of interest
+ */
+void Shift_MyGrpArray_Left (binary_type ** MyGrpArray, 
+                            int & GrpPriority_size, 
+                            int & i)
+{
+  for (int k=i+1;k<GrpPriority_size-1;++k)
+    {
+      MyGrpArray[k]=MyGrpArray[k+1];
+    }
+  return;
+}
+
+/**
+ * \brief This function calculated the final array according to the priorities
+ * of all the groups and of all the operators
+ *
+ * \param GrpPriority (INPUT) is the list of groups priority
+ * \param HighestPriority (INPUT) is the highest priority
+ * \param OpePriority (INPUT) is the list of the operators priority
+ * \param MyGrpArray (INPUT) are the array of each groups
+ * \param GlobalArray (OUTPUT) is the final array
+ * \param LocalArray (INPUT) 
+ * \param Ope (INPUT) is the list of operators
+ * \param GrpPara (INPUT) is the list of the groups parameters
+ */
+void MakePriorities (vector<int> & GrpPriority, 
+                     int & HighestPriority, 
+                     vector<int> & OpePriority, 
+                     binary_type ** MyGrpArray, 
+                     vector<int> & GlobalArray, 
+                     vector<int> & LocalArray, 
+                     vector<string> & Ope, 
+                     vector<Grp_parameters> & GrpPara)
+{
+  int CurrentPriority = HighestPriority;    
+  int GrpPriority_size = GrpPriority.size();   //number of grp
+  
+  while (GrpPriority_size > 1) //as long as we have more than just one array
+    {
+      for (int i=0 ; i<GrpPriority_size ; ++i)   
+        {
+          //find position of first group with the highest priority
+          if (GrpPriority[i] == CurrentPriority)
+            {
+              //check if it's the last one
+              if (i == GrpPriority_size-1)
+                {
+                  --GrpPriority[i];
+                  break;   //exit the for loop
+                }
+              else
+                {
+                  //check if the next operator has the same priority
+                  if ((OpePriority[i] == GrpPriority[i]) && 
+                      (GrpPriority[i+1] == GrpPriority[i]))
+                    {
+                      //do calculation according to Ope[i]
+                      DoCalculation(MyGrpArray[i],
+                                    MyGrpArray[i+1],
+                                    Ope[i], 
+                                    LocalArray, 
+                                    GlobalArray, 
+                                    GrpPara);
+
+                      if (i < GrpPriority_size-2)
+                        {  
+                          //shift to the left the rest of the GrpPriorities
+                          Shift_GrpPriorities_Left(GrpPriority, 
+                                                   GrpPriority_size, 
+                                                   i);
+                          
+                          //shift to the left the rest of the 
+                          //operators and operators priorities
+                          Shift_Ope_OpePriority_Left(OpePriority,
+                                                     Ope, 
+                                                     GrpPriority_size, 
+                                                     i);
+                          
+                          //shift to the left the rest of the arrays
+                          Shift_MyGrpArray_Left(MyGrpArray, 
+                                                GrpPriority_size,
+                                                i);
+                        }
+                      
+                      //we have one less array/grp
+                      --GrpPriority_size; 
+                      --i;
+                    }
+                  else
+                    {
+                      --GrpPriority[i];   
+                    }
+                }
+            }
+        }
+      
+      //check what is the highest priority
+      CheckHighestPriority(GrpPriority_size, 
+                           CurrentPriority, 
+                           GrpPriority);
+    }
+  return;
+}  
+
+/**
+ * \brief This function checks if we want everything
+ *
+ * \param decla_def (INPUT) is the declaration part of the string location
+ * \param Everything (INPUT,OUTPUT) is 1 if we want everything
+ * \param Tag (INPUT) is the list of tags
+ * \param Ope (INPUT) is the list of Operators
+ */
+void check_want_everything (vector<string> & decla_def, 
+                            int & Everything, 
+                            vector<string> & Tag, 
+                            vector<string> & Ope) 
+{
+  if (decla_def[1] == "")
+    {
+      Everything = 1;
+      Tag.push_back("*");
+      Ope.push_back("*");
+    }
+  return;
+}
+
+/**
+ * \brief This function swap endians of all the numbers of the BinaryArray
+ *
+ * \param GlobalArray (INPUT) is the size of the binary array
+ * \param BinaryArray (INPUT/OUTPUT) is the array coming from the binary file
+ */
+void swap_endian (vector<int> & GlobalArray, 
+                 binary_type * BinaryArray)
+{
+  for (int j=0 ; j<GlobalArray[1]*GlobalArray[2]*GlobalArray[0] ; ++j)
+    {
+      endian_swap(BinaryArray[j]);
+    } 
+  return;
+}
diff --git a/applications/NXtranslate/sns_histogram/SNS_retriever.hpp b/applications/NXtranslate/sns_histogram/SNS_retriever.hpp
new file mode 100644
index 0000000..3a35a2f
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/SNS_retriever.hpp
@@ -0,0 +1,624 @@
+#ifndef __SNS_HISTOGRAM_RETRIEVER_GUARD
+#define __SNS_HISTOGRAM_RETRIEVER_GUARD
+
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "string_location_format.h"
+#include "../tree.hh"
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include "retriever.h"
+#include <sstream>
+#include <stdexcept>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+//Type of binary file
+typedef int binary_type;
+
+// this is not intended to be inherited from
+class SnsHistogramRetriever: public Retriever{
+ public:
+  SnsHistogramRetriever(const std::string &);
+  ~SnsHistogramRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  SnsHistogramRetriever(const SnsHistogramRetriever&); //copy constructor
+  SnsHistogramRetriever& operator=(const SnsHistogramRetriever&); //operator "=" overloading
+  std::string source;
+  std::string location;
+  FILE *BinaryFile;
+};
+
+struct Grp_parameters   //parameters of the different definitions
+{
+  int init, last, increment;  //with loop(init,end,increment)
+  vector<int> value;          //(value[0],value[1],....)
+  char c;                     //c=l for loop and c=p for (x,y,z,...)
+};
+
+/**
+ * \brief This function isolate the different parameters of the definition
+ * part of the location string
+ *
+ * \param def (INPUT) is the full definition part of the string location
+ * \param OperatorNumber (INPUT) is the number of definition part the
+ * string location contains
+ * \para GrpPara (OUTPUT) is the list of operators (loop or list of 
+ * identifiers
+ * \param record (OUTPUT) is a structure Grp_parameters that contains
+ * all the information of the different defintion part
+ */
+void store_para_of_definition(vector<string> Def,
+                              int OperatorNumber, 
+                              vector<Grp_parameters> & GrpPara, 
+                              Grp_parameters & record);
+
+/**
+ * brief This function parse the definition and isolate the three parts 
+ * of the loop definition; the initial value, the final value and the increment
+ *
+ * \param def (INPUT) the definition part to parse
+ * \param i (INPUT) the index of the defintion part to parse
+ * \param GrpPara (OUTPUT) the Grp_parameters structre of the defintion part
+ */
+void InitLastIncre (string & def, 
+                    int i, 
+                    vector<Grp_parameters> & GrpPara);   
+
+/**
+ * \brief This function parses the value of the list of identifiers
+ *
+ * \param def (INPUT) is the definition part to parse
+ * \param GrpPara (INPUT) is the Grp_parameters structure of the list of 
+ * identifiers
+ */
+void ParseGrp_Value (string & def, 
+                     int i, 
+                     vector<Grp_parameters> & GrpPara);  
+/**
+ * \brief This function parse the local and global array of the 
+ * declaration part
+ *
+ * \param LocGlobArray (INPUT) is the full string of the declaration part
+ * \param LocalArray (OUTPUT) is the list of parameters of the local part
+ * \param GlobalArray (OUTPUT) is the list of parameters of the global part
+ */
+void parse_declaration_array(vector<string> & LocGlobArray, 
+                           vector<int> & LocalArray,
+                           vector<int> & GlobalArray);  
+
+/**
+ * \brief This function determines the highest priority of all the groups.
+ * A group is a set of operation, can be a loop or a list of identifiers
+ *
+ * \param GrpPriority (INPUT) is the list of the priority
+ *
+ * \return the last maximum value of the list
+ */
+int FindMaxPriority (vector<int>& GrpPriority);  
+
+
+/**
+ * \brief This function calculates the final array according to the 
+ * string location
+ *
+ * \param GrpPriority (INPUT) is a list of the groups priorities
+ * \param InverseDef (INPUT) inverses or not the meaning of the definition
+ * part having the same index
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param Ope (INPUT) is the list of the operators
+ * \param OpePriority (INPUT) is a list of the operator priorities
+ * \param tr (INPUT) is the final location of the array in the NeXus file
+ * \param Tag (INPUT) is the list of the tag_names
+ * \param Def (INPUT) is the list of the tag_definitions
+ * \param LocalArray (INPUT) is the list of parameters of the local declaration
+ * part
+ * \param GlobalArray (INPUT) is the list of parameters of the global 
+ * declaration part
+ * \param GrpPara (INPUT) is a list of structures of all the parameters of the
+ * defintion part
+ */
+void calculate_array (vector<int> & GrpPriority, 
+                      vector<int> & InverseDef, 
+                      binary_type * BinaryArray, 
+                      vector<string> Ope, 
+                      vector<int> & OpePriority,
+                      tree<Node> & tr, 
+                      vector<string> & Tag, 
+                      vector<string> & Def, 
+                      vector<int> & LocalArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara);  
+/**
+ * \brief This function calculates the array if the definition tag is PixelID
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelID (binary_type* MyGrpArray, 
+                        binary_type* BinaryArray,
+                        int grp_number,
+                        int InverseDef, 
+                        vector<string> & Def, 
+                        vector<int> & LocalArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara);  
+/**
+ * \brief This function calculates the array if the definition tag is PixelX
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelX (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara);   
+/**
+ * \brief This function calculates the array if the definition tag is PixelY
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelY (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara);   
+/**
+ * \brief This function calculates the array if the definition tag is Tbin
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_Tbin (binary_type* MyGrpArray, 
+                     binary_type* BinaryArray,
+                     int grp_number,
+                     int InverseDef, 
+                     vector<string> & Def, 
+                     vector<int> & LocalArray, 
+                     vector<int> & GlobalArray, 
+                     vector<Grp_parameters> & GrpPara);     
+
+/**
+ * \brief This function makes a copy of the binary array
+ *
+ * \param MyGrpArray (OUTPUT) is the local copy of the binary array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the global
+ * declaration part
+ */
+void MakeArray_Everything (binary_type* MyGrpArray, 
+                           binary_type* BinaryArray, 
+                           vector<int> & LocalArray, 
+                           vector<int> & GlobalArray); 
+
+/**
+ * \brief This function does the actual calculation between the two
+ * arrays that are pass in
+ *
+ * \param GrpArray1 (INPUT/OUTPUT) is the first array to operate on
+ * \param GrpArray2 (INPUT) is the second array to operate on
+ * \param Operator (INPUT) is the operator (or,and)
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the 
+ * global declarataion part
+ * \param GrpPara (INPUT) ??? not used ???
+*/
+void DoCalculation (binary_type* GrpArray1, 
+                    binary_type* GrpArray2,
+                    string Operator, 
+                    vector<int> & LocalArray, 
+                    vector<int> & GlobalArray, 
+                    vector<Grp_parameters> & GrpPara);  
+
+/**
+ * \brief This function swap endians
+ *
+ * \param x (INPUT/OUTPUT) number to swap
+ */
+inline void endian_swap(binary_type & x);  
+
+/**
+ * \brief This function initialize the array to 0
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the array to initialized
+ * \param GlobalArray (INPUT) is the dimension of the array
+ */
+void InitializeArray(binary_type * MyGrpArray, 
+                     vector<int> & GlobalArray);    
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+*/
+void InversePixelIDLoop (binary_type* MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number);  
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDLoop (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelIDList (binary_type * MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDList (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXLoop (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYLoop  (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinLoop (binary_type * MyGrpArray, 
+                      binary_type * BinaryArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara, 
+                      int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinLoop (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinList  (binary_type * MyGrpArray, 
+                       binary_type * BinaryArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara, 
+                       int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinList (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number); 
+
+/**
+ * \brief This function check for the highest priority in all the groups
+ *
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param CurrentPriority (INPUT/OUTPUT) is the current highest priority
+ * \param GrpPriority (INPUT) is the list of the groups priority
+ */
+void CheckHighestPriority (int & GrpPriority_size, 
+                           int & CurrentPriority, 
+                           vector<int> & GrpPriority);
+
+/**
+ * \brief This function shift to the left all the priority of the groups
+ * behind index i
+ *
+ * \param GrpPriority (INPUT/OUTPUT) is the list of groups priority
+ * \param GrpPriority_size (INPUT) is the size of the groups priority
+ * \param i (INPUT) is the index of the group priority of interest
+ */
+void Shift_GrpPriorities_Left (vector<int> & GrpPriority, 
+                               int & GrpPriority_size, 
+                               int & i);
+
+/**
+ * \brief This function shift to the left all the operators behind index i
+ *
+ * \param OpePriority (INPUT/OUTPUT) is the list of operator priority
+ * \param Ope (INPUT/OUTPUT) is the list of operators 
+ * \param GrpPriority_size (INPUT) is the number of groups 
+ * \param i (INPUT) is the index of the operator priority of interest
+ */
+void Shift_Ope_OpePriority_Left (vector<int> & OpePriority, 
+                                 vector<string> & Ope, 
+                                 int & GrpPriority_size, 
+                                 int & i);
+
+/**
+ * \brief This function shift to the left all the array corresponding to 
+ * each groups
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) are the array of each group
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param i (INPUT) is the index of the array of interest
+ */
+void Shift_MyGrpArray_Left (binary_type ** MyGrpArray, 
+                            int & GrpPriority_size, 
+                            int & i);
+
+/**
+ * \brief This function calculated the final array according to the priorities
+ * of all the groups and of all the operators
+ *
+ * \param GrpPriority (INPUT) is the list of groups priority
+ * \param HighestPriority (INPUT) is the highest priority
+ * \param OpePriority (INPUT) is the list of the operators priority
+ * \param MyGrpArray (INPUT) are the array of each groups
+ * \param GlobalArray (OUTPUT) is the final array
+ * \param LocalArray (INPUT) 
+ * \param Ope (INPUT) is the list of operators
+ * \param GrpPara (INPUT) is the list of the groups parameters
+ */
+void MakePriorities (vector<int> & GrpPriority, 
+                     int & HighestPriority, 
+                     vector<int> & OpePriority, 
+                     binary_type ** MyGrpArray, 
+                     vector<int> & GlobalArray, 
+                     vector<int> & LocalArray, 
+                     vector<string> & Ope, 
+                     vector<Grp_parameters> & GrpPara);
+
+/**
+ * \brief This function checks if we want everything
+ *
+ * \param DeclaDef (INPUT) is the declaration part of the string location
+ * \param Everything (INPUT,OUTPUT) is 1 if we want everything
+ * \param Tag (INPUT) is the list of tags
+ * \param Ope (INPUT) is the list of Operators
+ */
+void check_want_everything (vector<string> & DeclaDef, 
+                            int & Everything, 
+                            vector<string> & Tag, 
+                            vector<string> & Ope); 
+
+/**
+ * \brief This function swap endians of all the numbers of the BinaryArray
+ *
+ * \param GlobalArray (INPUT) is the size of the binary array
+ * \param BinaryArray (INPUT/OUTPUT) is the array coming from the binary file
+ */
+void swap_endian (vector<int> & GlobalArray, 
+                  binary_type * BinaryArray);
+#endif
diff --git a/applications/NXtranslate/sns_histogram/retriever.cpp b/applications/NXtranslate/sns_histogram/retriever.cpp
new file mode 100644
index 0000000..90d6168
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/retriever.cpp
@@ -0,0 +1,1686 @@
+#include "retriever.hpp"
+
+//#define SWAP_ENDIAN  //triger the swapping endian subroutine (if needed)
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+   
+/*********************************
+/SnsHistogramRetriever constructor
+/*********************************/
+SnsHistogramRetriever::SnsHistogramRetriever(const string &str): source(str) 
+{
+  // open the file
+  BinaryFile=fopen(source.c_str(),"rb");
+  
+  // check that open was successful
+  if (BinaryFile==NULL)
+    throw invalid_argument("Could not open file: "+source);
+}
+
+/*********************************
+/SnsHistogramRetriever destructor
+/*********************************/
+SnsHistogramRetriever::~SnsHistogramRetriever()
+{
+  // close the file
+  if(BinaryFile)
+    fclose(BinaryFile);
+}
+
+/**
+ * \brief This function creates the array according to the 
+ * string location
+ *
+ * \param location (INPUT) is the string location coming from the 
+ * translation file
+ * \param tr (INPUT) is where to put the final array created
+ */
+void SnsHistogramRetriever::getData(const string &location, tree<Node> &tr)
+{
+  string new_location;
+  string definition_version_with_groups = "";  //use to determine priorities
+
+  vector<string> decla_def;           //declaration and definition parts
+  vector<string> LocGlobArray; //local and global array (declaration part)
+  vector<string> Ope;                //Operators of the defintion part
+  int OperatorNumber; 
+  string DefinitionPart;             //use to determine the operators
+  vector<int> GrpPriority;           //Vector of priority of each group
+  vector<int> OpePriority;           //Vector of priority for each operator
+  vector<int> InverseDef; //True=Inverse definition, False=keep it like it is
+  int Everything = 0;                //0= we don't want everything, 1=we do
+  int GlobalArraySize = 1;           //Size of global array within our program
+  vector<string> Tag, Def;
+  vector<int> LocalArray, GlobalArray;
+
+  vector<Grp_parameters> GrpPara;
+  Grp_parameters record;
+
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    throw invalid_argument("cannot parse empty string");
+  
+  //format the string location (remove white spaces)
+  format_string_location(location, new_location);  
+  
+  DeclaDef_separator(new_location, decla_def);  //Separate Declaration part from Definition part -> decla_def
+  
+  //check if the defintion part has a valid format
+  if (decla_def[1].size() > 0 && decla_def[1].size()<7)
+    throw runtime_error("Definition part is not valid");
+  
+  //check if we want everything
+  check_want_everything (decla_def, Everything, Tag, Ope);
+  
+  //Separate declaration arrays (local and global)
+  declaration_separator(decla_def[0], LocGlobArray);
+  
+  if (Everything == 0)
+    {
+      //Work on definition part
+      DefinitionPart = decla_def[1];
+      
+      //Parse defintion part, separate Tag from Def
+      TagDef_separator(decla_def[1], Tag, Def, definition_version_with_groups);
+      
+      //check if we have at least one tag
+      if (Tag.size()<1)
+	throw runtime_error("Definition part is not valid");
+      
+      //Store operators
+      OperatorNumber = Tag.size();
+      store_operators(DefinitionPart,
+                      OperatorNumber, 
+                      Ope);
+      
+      //Give to each grp its priority
+      assign_grps_priority(definition_version_with_groups, 
+                           OperatorNumber, 
+                           GrpPriority, 
+                           InverseDef,
+                           OpePriority);   
+      
+      //Store parameters of the definition part into GrpPara[0], GrpPara[1]...
+      
+      store_para_of_definition(Def,
+                               OperatorNumber,
+                               GrpPara,
+                               record);
+    }
+  
+  //parse Local and Global Array from Declaration part
+  parse_declaration_array(LocGlobArray, 
+                          LocalArray, 
+                          GlobalArray);
+  
+  //allocate memory for the binary Array
+  for (int i=0; i<GlobalArray.size(); i++)
+    {
+      GlobalArraySize *= GlobalArray[i];
+    }
+  
+  binary_type * BinaryArray = new binary_type [GlobalArraySize];
+  
+  //transfer the data from the binary file into the GlobalArray
+  fread(&BinaryArray[0],sizeof(BinaryArray[0]), GlobalArraySize, BinaryFile);
+  
+  //swap endian if necessary
+#ifdef SWAP_ENDIAN
+
+  swap_endian (GlobalArray, BinaryArray);
+  
+#endif  //SWAP_ENDIAN
+  
+  //Calculate arrays according to definition
+  calculate_array(GrpPriority,
+                  InverseDef, 
+                  BinaryArray, 
+                  Ope, 
+                  OpePriority, 
+                  tr,
+                  Tag,
+                  Def,
+                  LocalArray,
+                  GlobalArray,
+                  GrpPara);
+}
+
+/*********************************
+/SnsHistogramRetriever::MIME_TYPE 
+/*********************************/
+const string SnsHistogramRetriever::MIME_TYPE("application/x-SNS-histogram");
+
+string SnsHistogramRetriever::toString() const
+{
+  return "["+MIME_TYPE+"] "+source;
+}
+
+/**
+ * \brief This function isolate the different parameters of the definition
+ * part of the location string
+ *
+ * \param def (INPUT) is the full definition part of the string location
+ * \param OperatorNumber (INPUT) is the number of definition part the
+ * string location contains
+ * \para GrpPara (OUTPUT) is the list of operators (loop or list of 
+ * identifiers
+ * \param record (OUTPUT) is a structure Grp_parameters that contains
+ * all the information of the different defintion part
+ */
+void store_para_of_definition(vector<string> Def, 
+                              int HowManyDef, 
+                              vector<Grp_parameters> & GrpPara, 
+                              Grp_parameters & record)
+{
+  //find out first if it's a loop or a list of identifiers
+  for (int i=0; i<HowManyDef ; ++i)
+    {
+      if (Def[i].find("loop") < Def[i].size()) 
+	{
+	  record.c = 'l';
+        }
+      else
+	{
+	  record.c = 'p';
+        }
+      GrpPara.push_back(record);
+    }
+  
+  //isolate the variable
+  for (int i=0; i<HowManyDef ; ++i)
+    {
+      if (GrpPara[i].c == 'l')      //loop
+	{
+	  InitLastIncre(Def[i],i, GrpPara);
+	}
+      else                          //(....)
+	{
+	  ParseGrp_Value(Def[i],i, GrpPara);
+	}
+    }
+ return;
+}
+
+/**
+ * brief This function parse the definition and isolate the three parts 
+ * of the loop definition; the initial value, the final value and the increment
+ *
+ * \param def (INPUT) the definition part to parse
+ * \param i (INPUT) the index of the defintion part to parse
+ * \param GrpPara (OUTPUT) the Grp_parameters structre of the defintion part
+ */
+void InitLastIncre (string & def, 
+                    int i, 
+                    vector<Grp_parameters> & GrpPara)
+{
+  static const string sep=",";
+  int pos1, pos2;
+  string new_def;
+  
+  //Remove "loop(" and ")"
+  def=def.substr(5,def.size()-6);
+  
+  //store the info into GrpPara[i].init, end and increment
+  pos1 = def.find(sep);
+  new_def = def.substr(pos1+1,def.size()-pos1);
+  pos2 = new_def.find(sep);
+ 
+  GrpPara[i].init =atoi((def.substr(0,pos1)).c_str());
+  GrpPara[i].last =atoi((def.substr(pos1+1,pos2).c_str()));
+  GrpPara[i].increment = atoi((new_def.substr(pos2+1, new_def.size()-1).c_str()));
+  
+  return;
+}
+
+/**
+ * \brief This function parses the value of the list of identifiers
+ *
+ * \param def (INPUT) is the definition part to parse
+ * \param GrpPara (INPUT) is the Grp_parameters structure of the list of 
+ * identifiers
+ */
+void ParseGrp_Value(string& def, int i, 
+                    vector<Grp_parameters> & GrpPara)
+{
+  int b=0, a=0;
+
+  while (b <= def.size())
+    {
+      if (def[b]==',')
+	{
+	  GrpPara[i].value.push_back(atoi((def.substr(a,b-a)).c_str()));
+	  a=b+1;
+	}
+      if (b==def.size())
+	{
+	  GrpPara[i].value.push_back(atoi((def.substr(a,b-a)).c_str()));
+	}
+      ++b;
+    }
+
+  return;
+}
+
+/**
+ * \brief This function parse the local and global array of the 
+ * declaration part
+ *
+ * \param LocGlobArray (INPUT) is the full string of the declaration part
+ * \param LocalArray (OUTPUT) is the list of parameters of the local part
+ * \param GlobalArray (OUTPUT) is the list of parameters of the global part
+ */
+void parse_declaration_array(vector<string> & LocGlobArray,
+                             vector<int> & LocalArray,
+                             vector<int> & GlobalArray)
+{
+  int a=0, b=0;
+  
+  //Parse Local array
+  int i=0;
+  
+  //remove square braces
+  LocGlobArray[i]=LocGlobArray[i].substr(1,LocGlobArray[i].size()-2);
+  
+  while (b <= LocGlobArray[i].size())
+    {
+      if (LocGlobArray[i][b]==',')
+	{
+	  LocalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+          a=b+1;}
+	
+      if (b==LocGlobArray[i].size())
+	{
+	  LocalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+        }
+	
+      ++b;
+    }
+
+  i=1,a=0,b=0;
+  
+  //Parse Global Array
+  
+  //remove square braces
+  LocGlobArray[i]=LocGlobArray[i].substr(1,LocGlobArray[i].size()-2);
+  
+  while (b <= LocGlobArray[i].size())
+    {
+      if (LocGlobArray[i][b]==',')
+	{
+	  GlobalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+          a=b+1;}
+	
+      if (b==LocGlobArray[i].size())
+	{
+	  GlobalArray.push_back(atoi((LocGlobArray[i].substr(a,b-a)).c_str()));
+        }
+      
+      ++b;
+    }
+
+  return;
+}
+
+/**
+ * \brief This function calculates the final array according to the 
+ * string location
+ *
+ * \param GrpPriority (INPUT) is a list of the groups priorities
+ * \param InverseDef (INPUT) inverses or not the meaning of the definition
+ * part having the same index
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param Ope (INPUT) is the list of the operators
+ * \param OpePriority (INPUT) is a list of the operator priorities
+ * \param tr (INPUT) is the final location of the array in the NeXus file
+ * \param Tag (INPUT) is the list of the tag_names
+ * \param Def (INPUT) is the list of the tag_definitions
+ * \param LocalArray (INPUT) is the list of parameters of the local declaration
+ * part
+ * \param GlobalArray (INPUT) is the list of parameters of the global 
+ * declaration part
+ * \param GrpPara (INPUT) is a list of structures of all the parameters of the
+ * defintion part
+ */
+void calculate_array (vector<int> & GrpPriority, 
+                      vector<int> & InverseDef, 
+                      binary_type * BinaryArray, 
+                      vector<string> Ope, 
+                      vector<int> & OpePriority, 
+                      tree<Node> & tr, 
+                      vector<string> & Tag, 
+                      vector<string> & Def, 
+                      vector<int> & LocalArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara)
+{
+  int HighestPriority;
+  int GrpNumber = GrpPriority.size();
+  int ArraySize = 1;
+  int ArraySizeGlobal = 1;
+ 
+  if (Tag[0]!="*")
+    {
+      HighestPriority = FindMaxPriority(GrpPriority);
+    }
+  
+  //determine array size
+  for (int i=0 ; i<LocalArray.size() ; ++i)
+    {
+      ArraySize *= LocalArray[i];
+    }
+  
+  if (Tag[0] == "*")
+    {
+      GrpNumber=1;
+      GrpPriority.push_back(1);
+    }
+  
+  //determine array size
+  for (int i=0 ; i<GlobalArray.size() ; ++i)
+    {
+      ArraySizeGlobal *= GlobalArray[i];
+    }
+  
+  //Allocate memory for each grp
+  binary_type **MyGrpArray;
+  MyGrpArray = new binary_type*[GrpPriority.size()];
+
+  for (int i=0 ; i<GrpPriority.size() ; ++i)
+    {
+      MyGrpArray[i]=new binary_type[ArraySizeGlobal];
+      InitializeArray(MyGrpArray[i], GlobalArray);
+    }
+
+  //Allocate memory for the final array created
+  void * NewArray;
+  int rank=3;
+  int dims[GlobalArray.size()];
+  for (int j=0 ; j< GlobalArray.size() ; ++j)
+    {
+      dims[j]=GlobalArray[j];
+    }
+  
+  //  int dims[]={3,10,5};
+  NXmalloc(&NewArray,rank,dims,NX_INT32);
+  
+  //make an array for each group
+  for (int i=0 ; i<GrpPriority.size() ; ++i)
+    {
+      
+      if (Tag[i]=="pixelID") 
+        {
+          MakeArray_pixelID(MyGrpArray[i],
+                            BinaryArray,
+                            i,
+                            InverseDef[i], 
+                            Def, 
+                            LocalArray, 
+                            GlobalArray, 
+                            GrpPara);
+        }
+      else if (Tag[i]=="pixelX")
+        {
+          MakeArray_pixelX(MyGrpArray[i],
+                           BinaryArray,
+                           i,
+                           InverseDef[i], 
+                           Def, 
+                           LocalArray, 
+                           GlobalArray, 
+                           GrpPara);
+        }
+      else if (Tag[i]=="pixelY")
+        {
+          
+          MakeArray_pixelY(MyGrpArray[i],
+                           BinaryArray,
+                           i,
+                           InverseDef[i], 
+                           Def, 
+                           LocalArray, 
+                           GlobalArray, 
+                           GrpPara);
+        }
+      else if (Tag[i]=="Tbin")
+        {
+          MakeArray_Tbin(MyGrpArray[i],
+                         BinaryArray,
+                         i,
+                         InverseDef[i], 
+                         Def, 
+                         LocalArray, 
+                         GlobalArray, 
+                         GrpPara);
+        }
+      else if (Tag[i]=="*")
+        {
+          MakeArray_Everything(MyGrpArray[i],
+                               BinaryArray, 
+                               LocalArray, 
+                               GlobalArray);
+        }
+    }
+  
+  //free memory of binary array 
+  delete[] BinaryArray;    
+  
+  //calculate the final Array according to all the parameters 
+  //retrieved in the rest of the code 
+  MakePriorities (GrpPriority, 
+                  HighestPriority, 
+                  OpePriority, 
+                  MyGrpArray, 
+                  GlobalArray, 
+                  LocalArray, 
+                  Ope, 
+                  GrpPara);
+ 
+  NewArray = MyGrpArray[0];
+  
+  delete[] MyGrpArray;  
+  
+  //write into nexus file
+  Node node("New Array from string location",NewArray,rank,dims,NX_INT32);
+  
+  tr.insert(tr.begin(),node);   
+  
+  NXfree(&NewArray);
+  
+  return;  
+}
+
+/**
+ * \brief This function determines the highest priority of all the groups.
+ * A group is a set of operation, can be a loop or a list of identifiers
+ *
+ * \param GrpPriority (INPUT) is the list of the priority
+ *
+ * \return the last maximum value of the list
+ */
+int FindMaxPriority (vector<int> & GrpPriority)
+{
+  int MaxValue = 0;
+  
+  for (int i=0 ; i<GrpPriority.size() ; ++i)
+    {
+      if (GrpPriority[i]>MaxValue)
+        {
+          MaxValue = GrpPriority[i];
+        }
+    }
+
+  return MaxValue;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is PixelID
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelID (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        int grp_number, 
+                        int InverseDef, 
+                        vector<string> & Def, 
+                        vector<int> & LocalArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0])  //case with loop
+    {
+      
+      if (InverseDef==1)    //case inverse for loop
+        {
+          InversePixelIDLoop (MyGrpArray, 
+                              BinaryArray, 
+                              GlobalArray, 
+                              GrpPara, 
+                              grp_number);
+        }
+      else   //normal case for loop
+        {
+          PixelIDLoop (MyGrpArray, 
+                       BinaryArray, 
+                       GlobalArray, 
+                       GrpPara, 
+                       grp_number);
+        }
+    }
+  else   //case with list of identifiers
+    {
+      if (InverseDef==1)   //case inverse for list
+        {
+          InversePixelIDList (MyGrpArray, 
+                              BinaryArray, 
+                              GlobalArray, 
+                              GrpPara, 
+                              grp_number);
+        }
+      else   //normal case for list
+        {
+          PixelIDList (MyGrpArray, 
+                       BinaryArray, 
+                       GlobalArray, 
+                       GrpPara, 
+                       grp_number);
+        }
+    }
+  
+  return;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is PixelX
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelX (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0]) 
+    {
+      if (InverseDef==1)   //case inverse with loop
+        {
+          InversePixelXLoop (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else   //normal case with loop
+        {
+          PixelXLoop (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }  
+  else
+    {
+      if(InverseDef==1) //case inverse with list
+        {
+          InversePixelXList (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else   //normal case with list
+        {
+          PixelXList (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is PixelY
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelY (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0]) 
+    {
+      if (InverseDef==1)  //inverse case for loop
+        {
+          InversePixelYLoop (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else  //normal case for loop
+        {
+          PixelYLoop (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }
+  else
+    {
+      if (InverseDef==1)   //case inverse with list
+        {
+          InversePixelYList (MyGrpArray, 
+                             BinaryArray, 
+                             GlobalArray, 
+                             GrpPara, 
+                             grp_number);
+        }
+      else    //normal case
+        {
+          PixelYList (MyGrpArray, 
+                      BinaryArray, 
+                      GlobalArray, 
+                      GrpPara, 
+                      grp_number);
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array if the definition tag is Tbin
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_Tbin (binary_type* MyGrpArray, 
+                     binary_type* BinaryArray,
+                     int grp_number,
+                     int InverseDef, 
+                     vector<string> & Def, 
+                     vector<int> & LocalArray, 
+                     vector<int> & GlobalArray, 
+                     vector<Grp_parameters> & GrpPara)
+{
+  string loop="loop";
+  
+  if (Def[grp_number][0] == loop[0]) 
+    {
+      if (InverseDef ==1)  //case inverse with loop
+        {
+          InverseTbinLoop (MyGrpArray, 
+                           BinaryArray, 
+                           GlobalArray, 
+                           GrpPara, 
+                           grp_number);
+        }
+      else   //normal case with loop
+        {
+          TbinLoop (MyGrpArray, 
+                    BinaryArray, 
+                    GlobalArray, 
+                    GrpPara, 
+                    grp_number);
+        }
+    }
+  else
+    {
+      if (InverseDef==1)  //case inverse with list
+        {
+          InverseTbinList (MyGrpArray, 
+                           BinaryArray, 
+                           GlobalArray, 
+                           GrpPara, 
+                           grp_number);
+        }
+      else  //normal case with list
+        {
+          TbinList (MyGrpArray, 
+                    BinaryArray, 
+                    GlobalArray, 
+                    GrpPara, 
+                    grp_number);
+        }
+    }
+  
+  return;
+}
+
+/**
+ * \brief This function makes a copy of the binary array
+ *
+ * \param MyGrpArray (OUTPUT) is the local copy of the binary array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the global
+ * declaration part
+ */
+void  MakeArray_Everything (binary_type* MyGrpArray, 
+                            binary_type* BinaryArray, 
+                            vector<int> & LocalArray, 
+                            vector<int> & GlobalArray)
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0;tbin<GlobalArray[2];++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+\
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+\
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }	     
+        }
+    }
+  return ;
+}
+
+/**
+ * \brief This function does the actual calculation between the two
+ * arrays that are pass in
+ *
+ * \param GrpArray1 (INPUT/OUTPUT) is the first array to operate on
+ * \param GrpArray2 (INPUT) is the second array to operate on
+ * \param Operator (INPUT) is the operator (or,and)
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the 
+ * global declarataion part
+ * \param GrpPara (INPUT) ??? not used ???
+*/
+void DoCalculation (binary_type * GrpArray1, 
+                    binary_type * GrpArray2, 
+                    string Operator, 
+                    vector<int> & LocalArray, 
+                    vector<int> & GlobalArray, 
+                    vector<Grp_parameters> & GrpPara)
+{
+  string OR="OR";
+  
+  if (Operator[0] == OR[0])
+    {
+      for (int y=0 ; y<GlobalArray[0] ; ++y)
+        {
+          for (int x=0 ; x<GlobalArray[1] ; ++x)
+            { 
+              for (int tbin=0;tbin<GlobalArray[2];tbin++)
+                {	  
+                  if ((GrpArray1[(x*GlobalArray[2]+tbin)+
+                                 (y*GlobalArray[2]*GlobalArray[1])]==0)&&
+                      (GrpArray2[(x*GlobalArray[2]+tbin)+
+                                 (y*GlobalArray[2]*GlobalArray[1])]!=0))
+                    {
+                      GrpArray1[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])]=
+                        GrpArray2[(x*GlobalArray[2]+tbin)+
+                                  (y*GlobalArray[2]*GlobalArray[1])];
+                    }
+                }
+            }
+        }
+    }
+  else
+    {
+      for (int y=0 ; y<GlobalArray[0] ; ++y)
+        {
+          for (int x=0 ; x<GlobalArray[1]; ++x)
+            {
+              for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+                {
+                  if (GrpArray2[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])]!=
+                      GrpArray1[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])])
+                    {
+                      GrpArray1[(x*GlobalArray[2]+tbin)+
+                                (y*GlobalArray[2]*GlobalArray[1])]=0;
+                    }	     
+                }
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function swap endians
+ *
+ * \param x (INPUT/OUTPUT) number to swap
+ */
+inline void endian_swap (binary_type & x)
+{
+  x = ((x>>24) & 0x000000FF) |
+    ((x<<8) & 0x00FF0000) |
+    ((x>>8) & 0x0000FF00) |
+    ((x<<24) & 0xFF000000);
+}
+
+/**
+ * \brief This function initialize the array to 0
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the array to initialized
+ * \param GlobalArray (INPUT) is the dimension of the array
+ */
+void InitializeArray(binary_type * MyGrpArray, 
+                     vector<int> & GlobalArray)
+{
+  for (int a=0 ; a<GlobalArray[1] ; ++a)
+    {
+      for (int b=0 ; b<GlobalArray[0] ; ++b)
+	{
+	  for (int c=0 ; c<GlobalArray[2] ; ++c)
+	    {
+	      MyGrpArray[c+b*GlobalArray[1]*
+                         GlobalArray[2]+a*GlobalArray[2]]=0;
+	    }
+	}
+    }  
+  return;   
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+*/
+void InversePixelIDLoop (binary_type * MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int i=GrpPara[grp_number].init;i<=GrpPara[grp_number].last;i=
+         i+GrpPara[grp_number].increment)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[i*GlobalArray[2]+tbin]=0;
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDLoop (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number)
+{
+  for (int i=GrpPara[grp_number].init;
+       i<=GrpPara[grp_number].last;
+       i=i+GrpPara[grp_number].increment)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[i*GlobalArray[2]+tbin]=
+            BinaryArray[i*GlobalArray[2]+tbin];
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelIDList (binary_type * MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int j=0 ; j<GrpPara[grp_number].value.size() ; ++j)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[GrpPara[grp_number].value[j]*GlobalArray[2]+tbin]=0;
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDList (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number)
+{
+  for (int j=0 ; j<GrpPara[grp_number].value.size() ; ++j)
+    {
+      for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+        {
+          MyGrpArray[GrpPara[grp_number].value[j]*GlobalArray[2]+tbin]=
+            BinaryArray[GrpPara[grp_number].value[j]*GlobalArray[2]+tbin];
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x = GrpPara[grp_number].init; 
+           x <= GrpPara[grp_number].last; 
+           x = x + GrpPara[grp_number].increment)
+        {
+          for (int tbin=0 ; tbin < GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXLoop (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number)
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x = GrpPara[grp_number].init; 
+           x <= GrpPara[grp_number].last; 
+           x = x + GrpPara[grp_number].increment)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number)
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2]; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GrpPara[grp_number].value.size() ; ++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(GrpPara[grp_number].value[x]*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number)
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GrpPara[grp_number].value.size() ; ++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(GrpPara[grp_number].value[x]*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(GrpPara[grp_number].value[x]*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=GrpPara[grp_number].init; 
+       y<=GrpPara[grp_number].last; 
+       y=y + GrpPara[grp_number].increment)
+    {
+      for (int x=0; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYLoop  (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number) 
+{
+  for (int y=GrpPara[grp_number].init; 
+       y<=GrpPara[grp_number].last; 
+       y=y + GrpPara[grp_number].increment)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GrpPara[grp_number].value.size() ; ++y)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (GrpPara[grp_number].value[y]*
+                          GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        }
+    } 
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number) 
+{
+  for (int y=0 ; y<GrpPara[grp_number].value.size() ; ++y)
+    {
+      for (int x=0; x<GlobalArray[1] ;++x)
+        {
+          for (int tbin=0 ; tbin<GlobalArray[2] ; ++tbin)
+	    {
+	      MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (GrpPara[grp_number].value[y]*
+                          GlobalArray[2]*GlobalArray[1])]= 
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (GrpPara[grp_number].value[y]*
+                             GlobalArray[2]*GlobalArray[1])];
+	    }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinLoop (binary_type * MyGrpArray, 
+                      binary_type * BinaryArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara, 
+                      int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y )
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=GrpPara[grp_number].init; 
+               tbin <= GrpPara[grp_number].last; 
+               tbin = tbin + GrpPara[grp_number].increment)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=0;
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinLoop (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number) 
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y )
+    {
+      for (int x=0; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=GrpPara[grp_number].init; 
+               tbin <= GrpPara[grp_number].last;
+               tbin = tbin + GrpPara[grp_number].increment)
+            {
+              MyGrpArray[(x*GlobalArray[2]+tbin)+
+                         (y*GlobalArray[2]*GlobalArray[1])]=
+                BinaryArray[(x*GlobalArray[2]+tbin)+
+                            (y*GlobalArray[2]*GlobalArray[1])];
+            }
+        } 
+    }
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinList  (binary_type * MyGrpArray, 
+                       binary_type * BinaryArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara, 
+                       int grp_number) 
+{
+  for (int i=0 ; i<GlobalArray[0]*GlobalArray[1] ; ++i)
+    {
+      for (int k=0 ; k<GlobalArray[2] ; ++k)
+        {
+          MyGrpArray[i*GlobalArray[2]+k]=BinaryArray[i*GlobalArray[2]+k];
+        }
+    }
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0 ; tbin<GrpPara[grp_number].value.size() ; ++tbin)
+            {
+              MyGrpArray[(x*GlobalArray[2]+GrpPara[grp_number].value[tbin])+
+                         y*GlobalArray[2]*GlobalArray[1]]=0;
+            }
+        }
+    } 
+  return;
+}
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinList (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number) 
+{
+  for (int y=0 ; y<GlobalArray[0] ; ++y)
+    {
+      for (int x=0 ; x<GlobalArray[1] ; ++x)
+        {
+          for (int tbin=0 ; tbin<GrpPara[grp_number].value.size() ; tbin++)
+            {
+              MyGrpArray[(x*GlobalArray[2]+GrpPara[grp_number].value[tbin])+
+                         y*GlobalArray[2]*GlobalArray[1]]= 
+		BinaryArray[(x*GlobalArray[2]+GrpPara[grp_number].value[tbin])+
+                            y*GlobalArray[2]*GlobalArray[1]];
+            }
+        }
+    }
+  return;
+}
+
+/**
+ * \brief This function check for the highest priority in all the groups
+ *
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param CurrentPriority (INPUT/OUTPUT) is the current highest priority
+ * \param GrpPriority (INPUT) is the list of the groups priority
+ */
+void CheckHighestPriority (int & GrpPriority_size, 
+                           int &  CurrentPriority, 
+                           vector<int> & GrpPriority)
+{
+  int find_one = 0;
+  for (int m=0 ; m<GrpPriority_size ; ++m)
+    {
+      if (GrpPriority[m] >= CurrentPriority)
+        {
+          find_one = 1;
+          break;
+        }
+    }
+  if (find_one == 0)
+    {
+      --CurrentPriority;
+    }
+  return;
+}
+
+/**
+ * \brief This function shift to the left all the priority of the groups
+ * behind index i
+ *
+ * \param GrpPriority (INPUT/OUTPUT) is the list of groups priority
+ * \param GrpPriority_size (INPUT) is the size of the groups priority
+ * \param i (INPUT) is the index of the group priority of interest
+ */
+void Shift_GrpPriorities_Left (vector<int> & GrpPriority, 
+                               int & GrpPriority_size, 
+                               int & i)
+{
+  for (int k=i+1 ; k<GrpPriority_size-1 ; ++k)
+    {
+      GrpPriority[k]=GrpPriority[k+1];
+    }
+  return;
+}
+
+/**
+ * \brief This function shift to the left all the operators behind index i
+ *
+ * \param OpePriority (INPUT/OUTPUT) is the list of operator priority
+ * \param Ope (INPUT/OUTPUT) is the list of operators 
+ * \param GrpPriority_size (INPUT) is the number of groups 
+ * \param i (INPUT) is the index of the operator priority of interest
+ */
+void Shift_Ope_OpePriority_Left (vector<int> & OpePriority, 
+                                 vector<string> & Ope, 
+                                 int & GrpPriority_size, 
+                                 int & i)
+{
+  for (int j=i;j<GrpPriority_size-2;++j)
+    {
+      OpePriority[j]=OpePriority[j+1];
+      Ope[j]=Ope[j+1];
+    }
+  return;
+}
+
+/**
+ * \brief This function shift to the left all the array corresponding to 
+ * each groups
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) are the array of each group
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param i (INPUT) is the index of the array of interest
+ */
+void Shift_MyGrpArray_Left (binary_type ** MyGrpArray, 
+                            int & GrpPriority_size, 
+                            int & i)
+{
+  for (int k=i+1;k<GrpPriority_size-1;++k)
+    {
+      MyGrpArray[k]=MyGrpArray[k+1];
+    }
+  return;
+}
+
+/**
+ * \brief This function calculated the final array according to the priorities
+ * of all the groups and of all the operators
+ *
+ * \param GrpPriority (INPUT) is the list of groups priority
+ * \param HighestPriority (INPUT) is the highest priority
+ * \param OpePriority (INPUT) is the list of the operators priority
+ * \param MyGrpArray (INPUT) are the array of each groups
+ * \param GlobalArray (OUTPUT) is the final array
+ * \param LocalArray (INPUT) 
+ * \param Ope (INPUT) is the list of operators
+ * \param GrpPara (INPUT) is the list of the groups parameters
+ */
+void MakePriorities (vector<int> & GrpPriority, 
+                     int & HighestPriority, 
+                     vector<int> & OpePriority, 
+                     binary_type ** MyGrpArray, 
+                     vector<int> & GlobalArray, 
+                     vector<int> & LocalArray, 
+                     vector<string> & Ope, 
+                     vector<Grp_parameters> & GrpPara)
+{
+  int CurrentPriority = HighestPriority;    
+  int GrpPriority_size = GrpPriority.size();   //number of grp
+  
+  while (GrpPriority_size > 1) //as long as we have more than just one array
+    {
+      for (int i=0 ; i<GrpPriority_size ; ++i)   
+        {
+          //find position of first group with the highest priority
+          if (GrpPriority[i] == CurrentPriority)
+            {
+              //check if it's the last one
+              if (i == GrpPriority_size-1)
+                {
+                  --GrpPriority[i];
+                  break;   //exit the for loop
+                }
+              else
+                {
+                  //check if the next operator has the same priority
+                  if ((OpePriority[i] == GrpPriority[i]) && 
+                      (GrpPriority[i+1] == GrpPriority[i]))
+                    {
+                      //do calculation according to Ope[i]
+                      DoCalculation(MyGrpArray[i],
+                                    MyGrpArray[i+1],
+                                    Ope[i], 
+                                    LocalArray, 
+                                    GlobalArray, 
+                                    GrpPara);
+
+                      if (i < GrpPriority_size-2)
+                        {  
+                          //shift to the left the rest of the GrpPriorities
+                          Shift_GrpPriorities_Left(GrpPriority, 
+                                                   GrpPriority_size, 
+                                                   i);
+                          
+                          //shift to the left the rest of the 
+                          //operators and operators priorities
+                          Shift_Ope_OpePriority_Left(OpePriority,
+                                                     Ope, 
+                                                     GrpPriority_size, 
+                                                     i);
+                          
+                          //shift to the left the rest of the arrays
+                          Shift_MyGrpArray_Left(MyGrpArray, 
+                                                GrpPriority_size,
+                                                i);
+                        }
+                      
+                      //we have one less array/grp
+                      --GrpPriority_size; 
+                      --i;
+                    }
+                  else
+                    {
+                      --GrpPriority[i];   
+                    }
+                }
+            }
+        }
+      
+      //check what is the highest priority
+      CheckHighestPriority(GrpPriority_size, 
+                           CurrentPriority, 
+                           GrpPriority);
+    }
+  return;
+}  
+
+/**
+ * \brief This function checks if we want everything
+ *
+ * \param decla_def (INPUT) is the declaration part of the string location
+ * \param Everything (INPUT,OUTPUT) is 1 if we want everything
+ * \param Tag (INPUT) is the list of tags
+ * \param Ope (INPUT) is the list of Operators
+ */
+void check_want_everything (vector<string> & decla_def, 
+                            int & Everything, 
+                            vector<string> & Tag, 
+                            vector<string> & Ope) 
+{
+  if (decla_def[1] == "")
+    {
+      Everything = 1;
+      Tag.push_back("*");
+      Ope.push_back("*");
+    }
+  return;
+}
+
+/**
+ * \brief This function swap endians of all the numbers of the BinaryArray
+ *
+ * \param GlobalArray (INPUT) is the size of the binary array
+ * \param BinaryArray (INPUT/OUTPUT) is the array coming from the binary file
+ */
+void swap_endian (vector<int> & GlobalArray, 
+                 binary_type * BinaryArray)
+{
+  for (int j=0 ; j<GlobalArray[1]*GlobalArray[2]*GlobalArray[0] ; ++j)
+    {
+      endian_swap(BinaryArray[j]);
+    } 
+  return;
+}
diff --git a/applications/NXtranslate/sns_histogram/retriever.h b/applications/NXtranslate/sns_histogram/retriever.h
new file mode 100644
index 0000000..1488b73
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/retriever.h
@@ -0,0 +1,24 @@
+#ifndef __SNS_HISTOGRAM_RETRIEVER_GUARD
+#define __SNS_HISTOGRAM_RETRIEVER_GUARD
+
+#include "../retriever.h"
+#include <fstream>
+#include <iostream>
+
+// this is not intended to be inherited from
+class SnsHistogramRetriever: public Retriever{
+ public:
+  SnsHistogramRetriever(const std::string &);
+  ~SnsHistogramRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  SnsHistogramRetriever(const SnsHistogramRetriever&); //copy constructor
+  SnsHistogramRetriever& operator=(const SnsHistogramRetriever&); //operator "=" overloading
+  std::string source;
+  std::string location;
+  FILE *BinaryFile;
+};
+
+#endif
diff --git a/applications/NXtranslate/sns_histogram/retriever.hpp b/applications/NXtranslate/sns_histogram/retriever.hpp
new file mode 100644
index 0000000..f52eec9
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/retriever.hpp
@@ -0,0 +1,605 @@
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <iterator>
+#include <stdlib.h>
+#include "retriever.h"
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+#include "string_location_format.h"
+
+//Type of binary file
+typedef int binary_type;
+
+
+struct Grp_parameters   //parameters of the different definitions
+{
+  int init, last, increment;  //with loop(init,end,increment)
+  vector<int> value;          //(value[0],value[1],....)
+  char c;                     //c=l for loop and c=p for (x,y,z,...)
+};
+
+/**
+ * \brief This function isolate the different parameters of the definition
+ * part of the location string
+ *
+ * \param def (INPUT) is the full definition part of the string location
+ * \param OperatorNumber (INPUT) is the number of definition part the
+ * string location contains
+ * \para GrpPara (OUTPUT) is the list of operators (loop or list of 
+ * identifiers
+ * \param record (OUTPUT) is a structure Grp_parameters that contains
+ * all the information of the different defintion part
+ */
+void store_para_of_definition(vector<string> Def,
+                              int OperatorNumber, 
+                              vector<Grp_parameters> & GrpPara, 
+                              Grp_parameters & record);
+
+/**
+ * brief This function parse the definition and isolate the three parts 
+ * of the loop definition; the initial value, the final value and the increment
+ *
+ * \param def (INPUT) the definition part to parse
+ * \param i (INPUT) the index of the defintion part to parse
+ * \param GrpPara (OUTPUT) the Grp_parameters structre of the defintion part
+ */
+void InitLastIncre (string & def, 
+                    int i, 
+                    vector<Grp_parameters> & GrpPara);   
+
+/**
+ * \brief This function parses the value of the list of identifiers
+ *
+ * \param def (INPUT) is the definition part to parse
+ * \param GrpPara (INPUT) is the Grp_parameters structure of the list of 
+ * identifiers
+ */
+void ParseGrp_Value (string & def, 
+                     int i, 
+                     vector<Grp_parameters> & GrpPara);  
+/**
+ * \brief This function parse the local and global array of the 
+ * declaration part
+ *
+ * \param LocGlobArray (INPUT) is the full string of the declaration part
+ * \param LocalArray (OUTPUT) is the list of parameters of the local part
+ * \param GlobalArray (OUTPUT) is the list of parameters of the global part
+ */
+void parse_declaration_array(vector<string> & LocGlobArray, 
+                           vector<int> & LocalArray,
+                           vector<int> & GlobalArray);  
+
+/**
+ * \brief This function determines the highest priority of all the groups.
+ * A group is a set of operation, can be a loop or a list of identifiers
+ *
+ * \param GrpPriority (INPUT) is the list of the priority
+ *
+ * \return the last maximum value of the list
+ */
+int FindMaxPriority (vector<int>& GrpPriority);  
+
+
+/**
+ * \brief This function calculates the final array according to the 
+ * string location
+ *
+ * \param GrpPriority (INPUT) is a list of the groups priorities
+ * \param InverseDef (INPUT) inverses or not the meaning of the definition
+ * part having the same index
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param Ope (INPUT) is the list of the operators
+ * \param OpePriority (INPUT) is a list of the operator priorities
+ * \param tr (INPUT) is the final location of the array in the NeXus file
+ * \param Tag (INPUT) is the list of the tag_names
+ * \param Def (INPUT) is the list of the tag_definitions
+ * \param LocalArray (INPUT) is the list of parameters of the local declaration
+ * part
+ * \param GlobalArray (INPUT) is the list of parameters of the global 
+ * declaration part
+ * \param GrpPara (INPUT) is a list of structures of all the parameters of the
+ * defintion part
+ */
+void calculate_array (vector<int> & GrpPriority, 
+                      vector<int> & InverseDef, 
+                      binary_type * BinaryArray, 
+                      vector<string> Ope, 
+                      vector<int> & OpePriority,
+                      tree<Node> & tr, 
+                      vector<string> & Tag, 
+                      vector<string> & Def, 
+                      vector<int> & LocalArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara);  
+/**
+ * \brief This function calculates the array if the definition tag is PixelID
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelID (binary_type* MyGrpArray, 
+                        binary_type* BinaryArray,
+                        int grp_number,
+                        int InverseDef, 
+                        vector<string> & Def, 
+                        vector<int> & LocalArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara);  
+/**
+ * \brief This function calculates the array if the definition tag is PixelX
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelX (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara);   
+/**
+ * \brief This function calculates the array if the definition tag is PixelY
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_pixelY (binary_type* MyGrpArray, 
+                       binary_type* BinaryArray,
+                       int grp_number,
+                       int InverseDef, 
+                       vector<string> & Def, 
+                       vector<int> & LocalArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara);   
+/**
+ * \brief This function calculates the array if the definition tag is Tbin
+ *
+ * \param MyGrpArray (INPUT) 
+ * \param BinaryArray (INPUT) is the array that comes from the binary file
+ * \param grp_number (INPUT) is the group index
+ * \param InverseDef (INPUT) allows to check if we want or not the inverse
+ * of the defintion 
+ * \param def (INPUT) is the list of definition
+ * \param LocalArray (INPUT) ???not used???
+ * \param GlobalArray (INPUT) 
+ * \param GrpPara (INPUT) is the list of parameters of the group
+ * 
+*/
+void MakeArray_Tbin (binary_type* MyGrpArray, 
+                     binary_type* BinaryArray,
+                     int grp_number,
+                     int InverseDef, 
+                     vector<string> & Def, 
+                     vector<int> & LocalArray, 
+                     vector<int> & GlobalArray, 
+                     vector<Grp_parameters> & GrpPara);     
+
+/**
+ * \brief This function makes a copy of the binary array
+ *
+ * \param MyGrpArray (OUTPUT) is the local copy of the binary array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the global
+ * declaration part
+ */
+void MakeArray_Everything (binary_type* MyGrpArray, 
+                           binary_type* BinaryArray, 
+                           vector<int> & LocalArray, 
+                           vector<int> & GlobalArray); 
+
+/**
+ * \brief This function does the actual calculation between the two
+ * arrays that are pass in
+ *
+ * \param GrpArray1 (INPUT/OUTPUT) is the first array to operate on
+ * \param GrpArray2 (INPUT) is the second array to operate on
+ * \param Operator (INPUT) is the operator (or,and)
+ * \param LocalArray (INPUT) ??? not used ???
+ * \param GlobalArray (INPUT) is the list of parameters of the 
+ * global declarataion part
+ * \param GrpPara (INPUT) ??? not used ???
+*/
+void DoCalculation (binary_type* GrpArray1, 
+                    binary_type* GrpArray2,
+                    string Operator, 
+                    vector<int> & LocalArray, 
+                    vector<int> & GlobalArray, 
+                    vector<Grp_parameters> & GrpPara);  
+
+/**
+ * \brief This function swap endians
+ *
+ * \param x (INPUT/OUTPUT) number to swap
+ */
+inline void endian_swap(binary_type & x);  
+
+/**
+ * \brief This function initialize the array to 0
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the array to initialized
+ * \param GlobalArray (INPUT) is the dimension of the array
+ */
+void InitializeArray(binary_type * MyGrpArray, 
+                     vector<int> & GlobalArray);    
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+*/
+void InversePixelIDLoop (binary_type* MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number);  
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDLoop (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelIDList (binary_type * MyGrpArray, 
+                         binary_type * BinaryArray, 
+                         vector<int> & GlobalArray, 
+                         vector<Grp_parameters> & GrpPara, 
+                         int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>pixelID</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelIDList (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXLoop (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelXList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>pixelX</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelXList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYLoop (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYLoop  (binary_type * MyGrpArray, 
+                  binary_type * BinaryArray, 
+                  vector<int> & GlobalArray, 
+                  vector<Grp_parameters> & GrpPara, 
+                  int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>!pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InversePixelYList (binary_type * MyGrpArray, 
+                        binary_type * BinaryArray, 
+                        vector<int> & GlobalArray, 
+                        vector<Grp_parameters> & GrpPara, 
+                        int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>pixelY</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void PixelYList (binary_type * MyGrpArray, 
+                 binary_type * BinaryArray, 
+                 vector<int> & GlobalArray, 
+                 vector<Grp_parameters> & GrpPara, 
+                 int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinLoop (binary_type * MyGrpArray, 
+                      binary_type * BinaryArray, 
+                      vector<int> & GlobalArray, 
+                      vector<Grp_parameters> & GrpPara, 
+                      int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>loop</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinLoop (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number);
+
+/**
+ * \brief This function calculates the array for the <b>!Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void InverseTbinList  (binary_type * MyGrpArray, 
+                       binary_type * BinaryArray, 
+                       vector<int> & GlobalArray, 
+                       vector<Grp_parameters> & GrpPara, 
+                       int grp_number); 
+
+/**
+ * \brief This function calculates the array for the <b>Tbin</b> case
+ * for the <b>list of identifiers</b> case
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) is the resulting array
+ * \param BinaryArray (INPUT) is the array coming from the binary file
+ * \param GlobalArray (INPUT) is the the size of the array to return
+ * \param GrpPara (INPUT) is the list of the parameters of the loop operator
+ * \param grp_number (INPUT) is the index of the group 
+ */
+void TbinList (binary_type * MyGrpArray, 
+               binary_type * BinaryArray, 
+               vector<int> & GlobalArray, 
+               vector<Grp_parameters> & GrpPara, 
+               int grp_number); 
+
+/**
+ * \brief This function check for the highest priority in all the groups
+ *
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param CurrentPriority (INPUT/OUTPUT) is the current highest priority
+ * \param GrpPriority (INPUT) is the list of the groups priority
+ */
+void CheckHighestPriority (int & GrpPriority_size, 
+                           int & CurrentPriority, 
+                           vector<int> & GrpPriority);
+
+/**
+ * \brief This function shift to the left all the priority of the groups
+ * behind index i
+ *
+ * \param GrpPriority (INPUT/OUTPUT) is the list of groups priority
+ * \param GrpPriority_size (INPUT) is the size of the groups priority
+ * \param i (INPUT) is the index of the group priority of interest
+ */
+void Shift_GrpPriorities_Left (vector<int> & GrpPriority, 
+                               int & GrpPriority_size, 
+                               int & i);
+
+/**
+ * \brief This function shift to the left all the operators behind index i
+ *
+ * \param OpePriority (INPUT/OUTPUT) is the list of operator priority
+ * \param Ope (INPUT/OUTPUT) is the list of operators 
+ * \param GrpPriority_size (INPUT) is the number of groups 
+ * \param i (INPUT) is the index of the operator priority of interest
+ */
+void Shift_Ope_OpePriority_Left (vector<int> & OpePriority, 
+                                 vector<string> & Ope, 
+                                 int & GrpPriority_size, 
+                                 int & i);
+
+/**
+ * \brief This function shift to the left all the array corresponding to 
+ * each groups
+ *
+ * \param MyGrpArray (INPUT/OUTPUT) are the array of each group
+ * \param GrpPriority_size (INPUT) is the number of groups
+ * \param i (INPUT) is the index of the array of interest
+ */
+void Shift_MyGrpArray_Left (binary_type ** MyGrpArray, 
+                            int & GrpPriority_size, 
+                            int & i);
+
+/**
+ * \brief This function calculated the final array according to the priorities
+ * of all the groups and of all the operators
+ *
+ * \param GrpPriority (INPUT) is the list of groups priority
+ * \param HighestPriority (INPUT) is the highest priority
+ * \param OpePriority (INPUT) is the list of the operators priority
+ * \param MyGrpArray (INPUT) are the array of each groups
+ * \param GlobalArray (OUTPUT) is the final array
+ * \param LocalArray (INPUT) 
+ * \param Ope (INPUT) is the list of operators
+ * \param GrpPara (INPUT) is the list of the groups parameters
+ */
+void MakePriorities (vector<int> & GrpPriority, 
+                     int & HighestPriority, 
+                     vector<int> & OpePriority, 
+                     binary_type ** MyGrpArray, 
+                     vector<int> & GlobalArray, 
+                     vector<int> & LocalArray, 
+                     vector<string> & Ope, 
+                     vector<Grp_parameters> & GrpPara);
+
+/**
+ * \brief This function checks if we want everything
+ *
+ * \param DeclaDef (INPUT) is the declaration part of the string location
+ * \param Everything (INPUT,OUTPUT) is 1 if we want everything
+ * \param Tag (INPUT) is the list of tags
+ * \param Ope (INPUT) is the list of Operators
+ */
+void check_want_everything (vector<string> & DeclaDef, 
+                            int & Everything, 
+                            vector<string> & Tag, 
+                            vector<string> & Ope); 
+
+/**
+ * \brief This function swap endians of all the numbers of the BinaryArray
+ *
+ * \param GlobalArray (INPUT) is the size of the binary array
+ * \param BinaryArray (INPUT/OUTPUT) is the array coming from the binary file
+ */
+void swap_endian (vector<int> & GlobalArray, 
+                  binary_type * BinaryArray);
diff --git a/applications/NXtranslate/sns_histogram/retriever_test.cpp b/applications/NXtranslate/sns_histogram/retriever_test.cpp
new file mode 100644
index 0000000..01f7ad6
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/retriever_test.cpp
@@ -0,0 +1,165 @@
+#include <iostream>
+#include <vector>
+#include <string>
+
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+
+
+void CheckMakeArrayPixelList (int i, vector<int> & GlobalArray, binary_type * MyGrpArray, string str);
+void checkMakePriorities(vector<int> & GrpPriority, int GrpPriority_size);
+void checkGrpParaValue(int i, vector<Grp_parameters> & GrpPara);
+void view_array(int & x, int & y, int & z, binary_type * MyGrpArray);
+void checkDeclaration(vector<int> & LocalArray, vector<int> & GlobalArray);
+
+
+void CheckMakeArrayPixelList (int i, vector<int> & GlobalArray, binary_type * MyGrpArray, string str)
+{
+  if (str == "PIXELX")
+    {
+      cout << endl << "****RETRIEVER_MAKE_ARRAY_PIXELX_LIST****************************************"<<endl;
+      cout << endl << "Check if MyGrpArray["<<i<<"] after MakeArray_pixelX in CalculateArray is correct: " << endl;
+    }
+  else if (str == "PIXELY")
+    {
+      cout << endl << "****RETRIEVER_MAKE_ARRAY_PIXELY_LIST****************************************"<<endl;
+      cout << endl << "Check if MyGrpArray["<<i<<"] after MakeArray_pixelY in CalculateArray is correct: " << endl;
+    }
+  else if (str == "PIXELYbefore")
+    {
+      cout << endl << "****RETRIEVER_MAKE_ARRAY_PIXELY_LIST****************************************"<<endl;
+      cout << endl << "Check if MyGrpArray["<<i<<"] before MakeArray_pixelY in CalculateArray is correct: " << endl;
+    }
+  else if (str == "TBIN")
+    {
+      cout << endl << "****RETRIEVER_MAKE_ARRAY_TBIN_LIST****************************************"<<endl;
+      cout << endl << "Check if MyGrpArray["<<i<<"] after MakeArray_Tbin in CalculateArray is correct: " << endl;
+    }
+  else if (str == "EVERYTHING")
+    {
+      cout << endl << "****RETRIEVER_EVERYTHING****************************************";
+      cout << endl << "Check if MyGrpArray["<<i<<"] in CalculateArray is correct: " << endl<<endl;
+    }
+  else if (str == "FINAL")
+    {
+      cout << endl << "****RETRIEVER_FINAL_RESULT****************************************";
+      cout << endl << "Check the final NewArray: " << endl<<endl;
+    }
+  else if (str == "PIXELID")
+    {
+      cout << endl << "****RETRIEVER_MAKE_ARRAY_PIXELID_LIST*******************************"<<endl;;
+      cout << endl << "Check if MyGrpArray in Make_PixelID is correct: " << endl;
+    }
+  else if (str == "PIXELIDbefore")
+    {
+      cout << endl << "****RETRIEVER_MAKE_ARRAY_PIXELID_LIST*******************************"<<endl;;
+      cout << endl << "Check if MyGrpArray["<<i<<"] in CalculateArray is correct: " << endl;
+    }
+  
+  int ll = 0;
+  int mm = 0;
+          cout << "   ";
+
+	  for (int j=0; j<GlobalArray[1]*GlobalArray[2]*GlobalArray[0]; ++j)
+	    {
+	      cout << MyGrpArray[j] << " ";            //listing of MyGrpArray    
+      
+	      if (ll == (GlobalArray[2]-1))
+		{
+		  cout << endl << "   ";
+		  ll = 0;
+		  ++mm;
+		}
+	      else
+		{
+		  ++ll;
+		}
+	      if (mm == (GlobalArray[1]))
+		{
+		  cout << endl;
+		  cout << "   ";
+		  mm = 0;
+		}
+	    } 
+
+  return;
+}
+
+void checkMakePriorities(vector<int> & GrpPriority, int GrpPriority_size)
+{
+    cout << endl << "****RETRIEVER_MAKE_PRIORITIES***************************"<<endl;
+
+      for (int j=0; j<GrpPriority_size;j++)
+	{
+	  if (GrpPriority[j]>-1)
+	    {
+	      cout << "   Grp["<<j<<"]/Pri#"<<GrpPriority[j];
+	    }
+	  else
+	    {
+	      cout << "   Grp["<<j<<"]/Pri#"<<GrpPriority[j]+1<<" ==>Done!"<<endl;
+	    }
+	}
+
+      cout << endl;
+
+  return;
+}
+
+void checkGrpParaValue(int i, vector<Grp_parameters> & GrpPara)
+{
+  cout << endl << "Def["<<i<<"], list of values from list of identifiers: " << endl;
+
+   for (int j=0; j<GrpPara[i].value.size(); j++)
+    {
+      cout << "   GrpPara.value["<<i<<"]= " << GrpPara[i].value[j]<<endl;
+    }
+
+  return;
+}
+
+/*******************************************
+/Print array for testing purpose
+/*******************************************/
+void view_array(int & x, int & y, int & z, binary_type * MyGrpArray)
+{
+   for (int a=0; a<y;++a)
+	{
+	  for (int b=0; b<x;++b)
+	    {
+	      for (int c=0; c<z;++c)
+		{
+		  cout << MyGrpArray[c+b*y*z+a*z];
+		  
+		  cout << " ";
+		}
+	      cout << "\t";
+	    }
+	  cout << endl;
+	}
+      cout << endl;
+	 
+      return;
+}
+
+
+void checkDeclaration(vector<int> & LocalArray, vector<int> & GlobalArray)
+{
+  cout << endl << "Parsing of values: " << endl;
+  cout << "   Local array" << endl;
+
+  for (int j=0; j<LocalArray.size();j++)
+    {
+      cout << "      LocalArray["<<j<<"]= "<<LocalArray[j];
+    }
+
+  cout << endl <<"   Global array" << endl;
+  
+  for (int k=0; k<GlobalArray.size();++k)
+    {
+      cout << "      GlobalArray["<<k<<"]= "<<GlobalArray[k];
+    }
+  return;
+}
diff --git a/applications/NXtranslate/sns_histogram/string_location_format.cpp b/applications/NXtranslate/sns_histogram/string_location_format.cpp
new file mode 100644
index 0000000..2471672
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/string_location_format.cpp
@@ -0,0 +1,398 @@
+#include "string_location_format.h"
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+
+using std::string;
+using std::vector;
+using std::runtime_error;
+using std::invalid_argument;
+
+/**
+ * \brief This function removes white spaces in the string location
+ *
+ * \param location (INPUT) is the string location as found in the 
+ * translation file
+ * \param new_location (INPUT) is the string location without white spaces 
+ */
+void without_white_spaces(const string & location,
+                          string & new_location)
+{
+  typedef std::string::size_type string_size;
+  string_size i=0;
+  std::string ret="";
+ 
+  while (i != location.size())
+    {
+      while (i != location.size() && isspace(location[i]))
+	{
+	  ++i;	
+        }
+      
+      //find end of next word
+      string_size j=i;
+      while (j != location.size() && !isspace(location[j]))
+        {
+          ++j;
+        }
+      
+      if (i != j)
+        {
+          ret+=location.substr(i,j-i);
+          i=j;
+        }
+    } 
+  new_location = ret;
+  return;
+}
+
+/**
+ * \brief This function separates the definition part from the declaration
+ * part in the string location
+ *
+ * \param new_location (INPUT) the string location formated (whithout white
+ * spaces for example)
+ * \param decla_def (OUTPUT) is the declaration and definition part isolated
+ */
+void DeclaDef_separator(string & new_location,
+                        vector<string> & decla_def)
+{
+  typedef std::string::size_type string_size;
+  int Dposition = new_location.find("#");
+  
+  if (Dposition == -1)
+    throw runtime_error("Declaration/Definition spacer invalid or not present");
+  
+  string_size taille = new_location.size();
+  
+  decla_def.push_back(new_location.substr(0,Dposition));
+  
+  if (taille == Dposition+1)
+    {
+        decla_def.push_back("");
+    }
+  else
+    {
+      decla_def.push_back(new_location.substr(Dposition+1, 
+                                              taille - decla_def[0].size()-1));
+    }
+  return;
+}
+
+/*********************************
+/Separate local from global array
+/*********************************/
+/**
+ * \brief This function separates the two parts of the declaration part, the
+ * local and global array declaration
+ *
+ * \param declaration_part (INPUT) is the declaration part of the string
+ * location
+ * \param LocGlobArray (OUTPUT) is the local and global parts of the 
+ * declaration part
+ */
+void declaration_separator(string declaration_part, 
+                           vector<string> & LocGlobArray)
+{
+  std::string str;
+  typedef string::size_type string_size;
+  string_size declaration_partSize = declaration_part.size();
+  int SeparatorPosition = declaration_part.find("][");
+  
+  if (SeparatorPosition == -1)
+    throw runtime_error("Format of declaration not valid");  
+
+  LocGlobArray.push_back(declaration_part.substr(0,SeparatorPosition+1));
+  LocGlobArray.push_back(declaration_part.substr(SeparatorPosition+1,
+                         declaration_partSize-LocGlobArray[0].size()));
+  
+  return;
+}
+
+/**
+ * \brief This function separates the tag parts from the definition part
+ * of the string location. A tag is a set of tag_name and a operator.
+ *
+ * \param DefinitionPart (INPUT) is the definition part of the string location
+ * \param Tag (OUTPUT) is the tag_name part of the tag
+ * \param Def (OUTPUT) is the operator part of the tag
+ * \DefinitionGrpVersion (OUTPUT) is a string where all the tags are replaces
+ * by the word "grp" + their index. This will be used later to determine
+ * the priorities of the tags
+ */
+void TagDef_separator(string & DefinitionPart, 
+                      vector<string> & Tag, 
+                      vector<string> & Def, 
+                      string & definition_version_with_groups)
+{
+  std::vector<string> ret;
+  typedef string::iterator iter;
+  iter b = DefinitionPart.begin();
+  iter e =  DefinitionPart.end();
+  iter a;
+  int CPosition;
+  int OpenBraPosition;
+  int CloseBraPosition = 1;
+  string  separator = "|";
+  string StringLocationGroup = DefinitionPart;
+  static const string OpenBracket = "{";
+  static const string CloseBracket = "}";
+  int HowManyTimes = 0;
+  int i = 0;
+  int length = DefinitionPart.size();
+
+  while (b!=e)
+    { 
+       if (find(b, DefinitionPart.end(), separator[0]) 
+           !=  DefinitionPart.end())
+      	{
+	   ++HowManyTimes;
+	   b = find(b, DefinitionPart.end(),separator[0]);
+	   b+=1;
+	}
+        b+=1;
+    }
+
+  while (i < HowManyTimes)
+    {
+      CPosition =  DefinitionPart.find(separator[0]);
+      OpenBraPosition =  DefinitionPart.find(OpenBracket);
+      CloseBraPosition =  DefinitionPart.find(CloseBracket);
+
+      CheckSpacerValidity(OpenBraPosition,CPosition,CloseBraPosition);
+
+      Tag.push_back( DefinitionPart.substr(OpenBraPosition+1,
+                                           CPosition-OpenBraPosition-1));
+   
+      CheckTagValidity(Tag[i]);
+      Def.push_back( DefinitionPart.substr(CPosition+1,
+                                           CloseBraPosition-CPosition-1));
+
+       DefinitionPart = DefinitionPart.substr(CloseBraPosition+1, 
+                                              length-CloseBraPosition-1);
+       ++i;
+    };
+
+   ReplaceTagDef_by_Grp(StringLocationGroup,
+                        HowManyTimes,
+                        definition_version_with_groups);
+   return;
+}
+
+/**
+ * \brief This function replaces the set of tag_name and operator, also
+ * called the tag_definition, by "grp"
+ *
+ * \param StringLocationGroup (INPUT) is the definition part of the string
+ * location
+ * \param HowManyTimes (INPUT) is the number of tag_name/tag_operator in the
+ * definition part
+ * \param DefinitionGrpVersion (OUTPUT) is the definition part of the string
+ * location where the set of tag_names and tag_definition have been replaced 
+ * by "grp"
+ */
+void ReplaceTagDef_by_Grp(string & StringLocationGroup, 
+                          int HowManyTimes, 
+                          string & definition_version_with_groups)
+{
+  static const string  separator = "|";
+  static const string OpenBracket = "{";
+  static const string CloseBracket = "}";
+  string part1, part2;
+  int OpenBraPosition, CloseBraPosition;
+ 
+  for (int j=0 ; j<HowManyTimes ; ++j)
+  
+    {
+      std::ostringstream Grp;
+      OpenBraPosition =  StringLocationGroup.find(OpenBracket);
+      CloseBraPosition =  StringLocationGroup.find(CloseBracket);
+      
+      StringLocationGroup.erase(OpenBraPosition, 
+                                CloseBraPosition + 1 - OpenBraPosition);
+     
+      part1 = StringLocationGroup.substr(0,OpenBraPosition);
+      part2 = StringLocationGroup.substr(OpenBraPosition, 
+                                         StringLocationGroup.size());
+      
+      Grp << "grp" << j ;  
+      StringLocationGroup = part1 + Grp.str() + part2;
+    }
+
+  definition_version_with_groups = StringLocationGroup;
+
+  return;
+}
+
+/**
+ * \brief This function check if there is a "|" present in each
+ * group
+ *
+ * \param OpenBra (INPUT) is the position of the open bracket of the group
+ * \param spacerPosition (INPUT) is the position of the "|"
+ * \param closeBra (INPUT) is the position of the close bracket of the group
+ */
+void CheckSpacerValidity(int openBra, int spacerPosition, int closeBra)
+{
+  if (spacerPosition < openBra || spacerPosition > closeBra)
+    {
+      throw runtime_error("Missing \"|\" spacer or wrong definition declaration");
+    }
+  return;
+}
+
+/**
+ * \brief This function checks if the tag_name is a valid tag
+ *
+ * \param Tag (INPUT) is the tag_name part of the tag
+ */
+void CheckTagValidity (string & Tag)
+{
+ if (Tag == "pixelID" ||
+     Tag == "pixelX" || 
+     Tag == "pixelY" || 
+     Tag == "Tbin")
+   {
+     return;
+   }
+  else
+    {
+      throw runtime_error("One of the Tag is not a valid Tag");
+    }
+return;
+}
+
+/**
+ * \brief This function stores the operators which are between the tags
+ *
+ * \param StrS (INPUT) is the definition part of the string location
+ * \param HowMany (INPUT) is the number of groups, or tags
+ * \param Ope (INPUT) is a list of the operators 
+ */
+void store_operators(string & StrS, 
+                    int & HowMany, 
+                    vector<string> & Ope)
+{
+  typedef string::iterator iter;
+  std::vector<iter> VecIter;             //vector of iterators
+  std::string::iterator a;
+  string operatorOR = "OR";
+  string operatorAND = "AND";
+
+ //Store each position of "|" into VecIter
+ VecIter = PositionSeparator(StrS,HowMany);
+  
+  for (int i=0 ; i<HowMany-1; ++i)
+    {
+      if (find(VecIter[i],VecIter[i+1],operatorOR[0])!=VecIter[i+1])
+      { 
+	Ope.push_back("OR");
+      }
+      else if (find(VecIter[i],VecIter[i+1],operatorAND[0])!=VecIter[i+1])
+	{
+	  Ope.push_back("AND");
+	}
+      else
+        {
+          throw runtime_error("Not a valid operator");
+        }
+    }	  
+  return;
+}
+
+/**
+ * \brief This function localize the position of each operator
+ *
+ * \param s (INPUT) is the definition part of the string location
+ * \param TagName_Number (INPUT) is the number of tags, or groups.
+ */
+vector<string::iterator> PositionSeparator(string s, 
+                                           int TagName_Number)
+{ 
+  std::vector<string::iterator> VecIter;
+  int i = 0;
+  typedef string::iterator iter;
+  iter b = s.begin();  
+  string separator = "|";
+
+  while (i < TagName_Number)
+    {
+      VecIter.push_back(find(b, s.end(), separator[0]));
+      b = find(b,s.end(),separator[0])+1;
+      ++i;
+    }
+  return VecIter;
+}
+
+/*********************************
+/Give priority for each group
+/*********************************/
+/**
+ * \brief This function gives for each group a priority value
+ *
+ * \param s (INPUT) is the definition part of the string location
+ * \param OperatorNumber (INPUT) is the number of operator
+ * \param GrpPriority (OUTPUT) is a list of groups priorities
+ * \param InverseDef (OUTPUT) equals to 1 or 0 for each groups; 1 means we want
+ * to reverse the tag_operator meaning.
+ * \param OpePriority (OUTPUT) is the list of the groups priorities
+ */
+void assign_grps_priority( string & s, 
+                           int OperatorNumber, 
+                           vector<int> & GrpPriority, 
+                           vector<int> & InverseDef, 
+                           vector<int> & OpePriority)
+{
+  int DefinitionString_size = s.size();
+  int GrpNumberLive = 0;
+  int Priority = 0;
+    
+  //Initialization of vector<int> and vector<bool>
+  for (int i=0; i<OperatorNumber; i++)
+    {
+      GrpPriority.push_back(0);
+      InverseDef.push_back(0);
+      OpePriority.push_back(0);
+    }
+  
+  //move along the definition part and look for g,A,O,!,(,and ).
+  for (int j=0 ; j<DefinitionString_size; ++j)
+    {
+      switch (s[j])
+	{
+	case 'g':
+          j=j+3;   //move to end of grp#
+	  GrpPriority[GrpNumberLive]=Priority;
+   	  ++GrpNumberLive;
+     	  break;
+	case '!':
+	  InverseDef[GrpNumberLive]=1;
+          break;
+	case '(':
+	  ++Priority;
+          break;
+	case ')':
+	  --Priority;
+          break;
+	case 'A':
+	  OpePriority[GrpNumberLive-1]=Priority;
+	  break;
+	case 'O':
+	  OpePriority[GrpNumberLive-1]=Priority;
+	  break;
+	default:
+          // do nothing
+	  break;
+	}
+    }
+ 
+  if (Priority != 0)
+    {
+      throw runtime_error("Format of parentheses not valid");
+    }
+
+  return;
+}
+
diff --git a/applications/NXtranslate/sns_histogram/string_location_format.h b/applications/NXtranslate/sns_histogram/string_location_format.h
new file mode 100644
index 0000000..6b028d5
--- /dev/null
+++ b/applications/NXtranslate/sns_histogram/string_location_format.h
@@ -0,0 +1,135 @@
+#include <string>
+#include <stdlib.h>
+#include <vector>
+
+using std::string;
+using std::vector;
+
+/**
+ * \brief This function removes white spaces in the string location
+ *
+ * \param location (INPUT) is the string location as found in the 
+ * translation file
+ * \param new_location (INPUT) is the string location without white spaces 
+ */
+void without_white_spaces(const string & s, 
+                          string & s_output);
+                   
+
+/**
+ * \brief This function separates the definition part from the declaration
+ * part in the string location
+ *
+ * \param new_location (INPUT) the string location formated (whithout white
+ * spaces for example)
+ * \param decla_def (OUTPUT) is the declaration and definition part isolated
+ */
+void DeclaDef_separator(string & s,
+                        vector<string> & decla_def);
+
+/*********************************
+/Separate local from global array
+/*********************************/
+/**
+ * \brief This function separates the two parts of the declaration part, the
+ * local and global array declaration
+ *
+ * \param declaration_part (INPUT) is the declaration part of the string
+ * location
+ * \param LocGlobArray (OUTPUT) is the local and global parts of the 
+ * declaration part
+ */
+void declaration_separator(string declaration_part, 
+                           vector<string> & LocGlobArray); 
+
+/**
+ * \brief This function separates the tag parts from the definition part
+ * of the string location. A tag is a set of tag_name and a operator.
+ *
+ * \param DefinitionPart (INPUT) is the definition part of the string location
+ * \param Tag (OUTPUT) is the tag_name part of the tag
+ * \param Def (OUTPUT) is the operator part of the tag
+ * \DefinitionGrpVersion (OUTPUT) is a string where all the tags are replaces
+ * by the word "grp" + their index. This will be used later to determine
+ * the priorities of the tags
+ */
+void TagDef_separator(string & DefinitionPart, 
+                      vector<string> & Tag, 
+                      vector<string> & Def, 
+                      string & definition_version_with_groups); 
+
+
+/**
+ * \brief This function replaces the set of tag_name and operator, also
+ * called the tag_definition, by "grp"
+ *
+ * \param StringLocationGroup (INPUT) is the definition part of the string
+ * location
+ * \param HowManyTimes (INPUT) is the number of tag_name/tag_operator in the
+ * definition part
+ * \param DefinitionGrpVersion (OUTPUT) is the definition part of the string
+ * location where the set of tag_names and tag_definition have been replaced 
+ * by "grp"
+ */
+void ReplaceTagDef_by_Grp(string & s, 
+                          int a, 
+                          string & GrpVersion); 
+
+/**
+ * \brief This function check if there is a "|" present in each
+ * group
+ *
+ * \param OpenBra (INPUT) is the position of the open bracket of the group
+ * \param spacerPosition (INPUT) is the position of the "|"
+ * \param closeBra (INPUT) is the position of the close bracket of the group
+ */
+void CheckSpacerValidity(int i, 
+                         int j, 
+                         int k);
+
+/**
+ * \brief This function checks if the tag_name is a valid tag
+ *
+ * \param Tag (INPUT) is the tag_name part of the tag
+ */
+void CheckTagValidity (string & Tag);
+
+/**
+ * \brief This function stores the operators which are between the tags
+ *
+ * \param StrS (INPUT) is the definition part of the string location
+ * \param HowMany (INPUT) is the number of groups, or tags
+ * \param Ope (INPUT) is a list of the operators 
+ */
+void store_operators(string & s, 
+                    int & HowMany, 
+                    vector<string> & Ope);
+
+/**
+ * \brief This function localize the position of each operator
+ *
+ * \param s (INPUT) is the definition part of the string location
+ * \param TagName_Number (INPUT) is the number of tags, or groups.
+ */
+vector<string::iterator> PositionSeparator(string s, 
+                                           int TagName_Number);
+
+/*********************************
+/Give priority for each group
+/*********************************/
+/**
+ * \brief This function gives for each group a priority value
+ *
+ * \param s (INPUT) is the definition part of the string location
+ * \param OperatorNumber (INPUT) is the number of operator
+ * \param GrpPriority (OUTPUT) is a list of groups priorities
+ * \param InverseDef (OUTPUT) equals to 1 or 0 for each groups; 1 means we want
+ * to reverse the tag_operator meaning.
+ * \param OpePriority (OUTPUT) is the list of the groups priorities
+ */
+void assign_grps_priority( string & s, 
+                           int OperatorNumber, 
+                           vector<int> & GrpPriority, 
+                           vector<int> & InverseDef, 
+                           vector<int> & OpePriority);
+
diff --git a/applications/NXtranslate/spec/CMakeLists.txt b/applications/NXtranslate/spec/CMakeLists.txt
new file mode 100644
index 0000000..006dc11
--- /dev/null
+++ b/applications/NXtranslate/spec/CMakeLists.txt
@@ -0,0 +1,33 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (Spec STATIC SPEClib.cpp SPEClib.h spec_retriever.cpp  spec_retriever.h)
+
+
diff --git a/applications/NXtranslate/spec/Makefile.am b/applications/NXtranslate/spec/Makefile.am
new file mode 100644
index 0000000..e0917e0
--- /dev/null
+++ b/applications/NXtranslate/spec/Makefile.am
@@ -0,0 +1,42 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id: Makefile.am,v 1.3 2005/11/15 22:05:48 pfp Exp $
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libSpec.la
+
+libSpec_la_SOURCES = \
+	SPEClib.cpp  SPEClib.h  \
+	spec_retriever.cpp  spec_retriever.h
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/spec/SPEClib.cpp b/applications/NXtranslate/spec/SPEClib.cpp
new file mode 100644
index 0000000..1f97f26
--- /dev/null
+++ b/applications/NXtranslate/spec/SPEClib.cpp
@@ -0,0 +1,1362 @@
+//+**********************************************************************
+//
+// File:	SPEClib.cpp
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	implementation of a SPEClib functions. It is a library,
+//              which makes possible reading data from SPEC format.
+//              The library consists set of functions which parse
+//              SPEC file(pure ASCI file). Every single function
+//              retrieves different information from the file.
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	March 2006
+//
+//+**********************************************************************
+
+#include "SPEClib.h"
+
+/**
+* Function reads file name from SPEC file. 
+* Parameters: input - input file stream, 
+*             output - char *result for storing file name
+* Returns: true if file name was specified in the SPEC, false otherwise  
+*/
+bool get_file_name(ifstream &in, char *result){
+    bool empty=0;
+    char a,b;
+  
+    in.seekg(0, ios::beg);//rewind stream
+    //
+    //stop searching for tag when #S will be met
+    //
+    while(!(a =='#' && b =='S')){
+        //
+	//prevent from corrupted part of file
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(result, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign in line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+        //
+	//check if file tag was met
+	//
+	if(a=='#'&& b=='F'){
+            empty=1;//indicate data collection
+            while(in.peek()==' ') in.ignore(3,' ');
+            in.getline(result, BUFFER_SIZE-1);//read file name
+            break;
+        }
+	//
+	//go to next line if #F was not met
+        //
+	else
+            in.getline(result, BUFFER_SIZE-1);
+    }
+    //
+    //after data collection rewind file
+    //
+    in.seekg(0, ios::beg);
+    return empty; 
+}
+
+
+/**
+* Function reads date of given scan from SPEC file. 
+* Parameters: input - input file stream, 
+*             output - char *result for storing scanning date
+* Returns: true if date of scan was specified in the SPEC, false otherwise  
+*/
+bool get_date(ifstream &in, char *result){
+    bool empty=0;
+    char a,b;
+    //
+    //finish searching when #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//prevention from corrupted bits in file
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(result, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign in line    
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+	//
+	//case for data tag
+        //
+	if(a=='#'&& b=='D'){
+            empty=1;
+            while(in.peek()==' ') in.ignore(3,' ');
+	    //read date of the scan
+            in.getline(result, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//go to next line in case wrong tag
+        //
+	else
+            in.getline(result, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when job is finished
+    //
+    in.seekg(0, ios::beg);
+    return empty; 
+}
+
+
+/**
+* Function reads user ID of an owner of the SPEC file. 
+* Parameters: input - input file stream, 
+*             output - char *result for storing user ID
+* Returns: true if user ID was specified in the SPEC, false otherwise  
+*/
+bool get_userID(ifstream &in, char *result){
+    bool empty=0;
+    char a,b;
+    //
+    //finish searching when tag of new scan is met
+    //
+    while(!(a =='#' && b =='S')){
+        //
+	//prevention from bad bits in the file
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(result, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign from the line      
+        //
+	in.get(a);
+        while(isspace(a)!=0){//rewind if space
+            in.get(a);
+        }
+	//
+	//get the second sign from the file
+        //
+	in.get(b);	
+	//
+	//tag with user ID 
+        //
+	if(a=='#'&& b=='C'){
+            empty=1;
+            in.getline(result, BUFFER_SIZE-1, '=');//go to user ID after '='sign
+            while(in.peek()==' ') in.ignore(3,' ');//ignore white spaces after '='
+            in.getline(result, BUFFER_SIZE-1);//read user ID
+            break;
+        }
+	//
+	//go to next line in case of wrong label
+        //
+	else
+            in.getline(result, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when job is finished
+    //
+    in.seekg(0, ios::beg);
+    return empty; 
+}
+
+
+
+/**
+* Function reads refilling mode of a scan from SPEC file. 
+* Parameters: input - input file stream, 
+*             output - char *result for storing refilling mode
+* Returns: true if mode was specified for the scan, false otherwise  
+*/
+bool refill_mode(ifstream &in, char *result){
+    bool exists=0;
+    char a,b;
+    int u_counter=0;
+    //
+    //finish when tag #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//prevention from corrupted bits
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(result, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign in the line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);//rewind white spaces
+        }
+	//
+	//get the second sign from the file
+        //
+	in.get(b);
+	//
+	//case for user notes tag
+        //
+	if(a=='#'&& b=='U'){
+            if(u_counter==2){//we are interested in #U2 tag
+                exists=1;
+                in.getline(result, BUFFER_SIZE-1, ':');//go to refill mode section
+                while(in.peek()==' ') in.ignore(3,' ');//ignore white spaces after ':'
+                in.getline(result, BUFFER_SIZE-1, ' ');//read mode of refill
+                break;
+            }
+            else u_counter++;//if #U but not #U2
+        }
+	//
+	//go to next line if tag does not match
+        //
+	in.getline(result, BUFFER_SIZE-1);
+    }
+    //
+    //dont close the stream even if EOF is met
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    //
+    //check for bad bits
+    //
+    if(in.fail()){
+        in.clear(in.rdstate() & ~ios::failbit);
+    } 
+    //
+    //rewind file when job is finished
+    //
+    in.seekg(0, ios::beg);
+    return exists; 
+}
+
+
+
+/**
+* Function reads refilling time of a scan from SPEC file. 
+* Parameters: input - input file stream, 
+*             output - char *result for storing refilling time
+* Returns: true if refill time was specified for the scan, false otherwise  
+*/
+bool refill_time(ifstream &in, char *result){
+    bool exists=0;
+    char a,b;
+    int u_counter=0;
+    //
+    //finish searching when #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//bad bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(result, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign in line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);//rewind white spaces
+        }
+	//
+	//get second sign in line
+        //
+	in.get(b);
+	//
+	//#U tag met
+        //
+	if(a=='#'&& b=='U'){
+            if(u_counter==2){//we look for #U2
+                exists=1;
+                in.getline(result, BUFFER_SIZE-1, ' ');
+                while(in.peek()==' ') in.ignore(3,' ');
+                in.getline(result, BUFFER_SIZE-1, ',');//get time of refill
+                break;
+            }
+            else u_counter++;//if #U but not #U2
+        }
+        in.getline(result, BUFFER_SIZE-1);//go to next line if not #U
+    }
+    //
+    //do not finish working with stream in case of EOF notified
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    //
+    //bad bit prevention
+    //
+    if(in.fail()){
+        in.clear(in.rdstate() & ~ios::failbit);
+    } 
+    //
+    //rewind stream when job is finished
+    //
+    in.seekg(0, ios::beg);
+    return exists; 
+}
+
+
+
+/**
+* Function returns position of the given label.
+* It searches in #L group of labels if interested label exists.
+* If yes, position number is returned.
+* Parameters: input - input file stream, char *label, int number of scan 
+*             
+* Returns: int position of a label or zero if label does not exists  
+*/
+int get_label_position(ifstream &in, char *label, int scan){ 
+    int position;
+    //
+    //go to the scan
+    //
+    scan_rewinder(in, scan);
+    int MAX=count_columns(in);
+    char temp[50];
+    char str[BUFFER_SIZE];
+    char a=' ';
+    char b=' ';
+    int counter=1;
+    //
+    //finish searching when #S tag is met 
+    //
+    while(!(a =='#' && b =='S')){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+        }
+	//
+	//get first sign from the line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//second sign from the line
+        //
+	in.get(b);
+	//
+	//check for #L tag
+        //
+	if(a=='#'&& b=='L'){
+	    //
+	    //go to first label
+	    //
+	    while(in.peek()==' ') in.ignore(3, ' ');
+            //
+	    //check labels apart of the last one
+	    //
+	    while(counter<MAX){ 
+                in.getline(str, 49, ' ');          
+                while(in.peek()!=' '){
+                    strcat(str, " ");//labels can have one white spaces in the name
+                    in.getline(temp, 49, ' ');
+                    strcat(str, temp);           
+                }
+	        if(!strcmp(label, str))break;//chack if label matches
+                counter++;//go to next label
+                while(in.peek()==' '){//rewind white spaces
+                    in.ignore(3,' ');
+                } 
+            }
+	    //
+	    //case for the last label
+            //
+	    if(counter==MAX)in.getline(str, 150);
+            if(strcmp(label, str))counter=0;//check if last label matches
+            break;
+        }
+        else
+            in.getline(str, 255);//go to next line if tag doesnot match
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+    return counter;
+}
+
+
+/**
+* Function counts columns of #L measurements. Used in get_label_position(...)
+* function.
+* Parameters: input - input file stream,  
+*             
+* Returns: int number of columns, zero in case of error  
+*/
+int count_columns(ifstream &in){
+    long int columns_number=0;
+    char string[BUFFER_SIZE];
+    char a,b;
+    //
+    //end if #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//fail bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(string, BUFFER_SIZE-1);
+        }
+	//
+	//get first sign in the line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+        if(a=='#'&& b=='N'){
+            in >> columns_number;//read number of columns
+            break;
+        }
+        else
+	    //
+	    //go to next line if tag is wrong
+            //
+	    in.getline(string, 255);
+    }
+    return columns_number; 
+}
+
+
+
+/**
+* Function reads data obtained during experiment for the given variable.
+* Variable is inserted into the function by its position.
+* To get position of the variable use get_label_position(...) function.
+* Parameters: input - input file stream, int position, int scan number, 
+*             output - double results[] - array with results obtained during experiment.
+* Returns: true if data was read, false otherwise  
+*/
+bool get_values(ifstream &in, int number, double results[], int scan_number){
+    double value;
+    int counter=0; 
+    bool flag=0;
+    //
+    //label position must be greater then zero
+    //
+    if(number == 0){
+        cout<<"Uncorrect number of label\n";
+        exit(1);
+    }
+    //
+    //go to the scan
+    //
+    scan_rewinder(in, scan_number);
+    //
+    //finish working until EOF
+    //
+    while(!in.eof()){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+        }
+	//
+	//always look for EOF
+        //
+	if(in.peek()==EOF)break;
+	//
+	//ignore rows with # sign or starting with white space
+        //
+	if(in.peek()=='#' || isspace(in.peek())!=0){
+            in.ignore(500, '\n');
+            if(flag==1)break;
+            continue;      
+        }
+	//
+	//if values section read values of the interesting label indicated by position 'number'
+        //
+	for(int i=0; i<number; i++){
+            in >> value;
+        }
+	//
+	//put vaules into the array
+        //
+	results[counter]=value;
+        counter++;
+        flag=1;
+        in.ignore(500,'\n');
+    }
+    //
+    //reset stream flags in case of EOF
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg); 
+    return flag;
+}
+
+
+
+/**
+* Function counts data sets during one scanning procedure.
+* Main purpose of the function is to allocate enough memory 
+* in the array for results.
+* Parameters: input - input file stream,  
+*             
+* Returns: int number data sets, zero if no data was collected  
+*/
+int count_data_sets(ifstream &in){
+    int data_sets=0;
+    bool flag=0; 
+    //
+    //search till EOF
+    //
+    while(!in.eof()){
+        //
+	//fail bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+        }
+	//
+	//ignore lines starting with '#' or white space
+        //
+	if((in.peek()=='#' || isspace(in.peek())!=0)){
+            in.ignore(500, '\n');
+            if(flag==1)break;//if already read break
+            continue;      
+        }
+	//
+	//count rows with data
+        //
+	if(in.peek()!=EOF)data_sets++;
+        in.ignore(500, '\n');
+        flag=1;//set flag indicationg that it was read already
+    }
+    //
+    //clear flag in case of EOF
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+    return data_sets;
+}
+
+
+
+
+/**
+* Function returns position of given motor for the specified scan,
+* as well as number of motor group where that motor belongs to. 
+* Function compares name of the motor we are interested in with all the motors
+* from the given scan.
+* Parameters: input - input file stream, char *label with name of the motor,
+              int scan number
+*             output - int motor group where given motor is
+* Returns: int position of motor in the group, or zero if motor does not belogs to any,  
+*/
+int get_motor_position(ifstream &in, char *label, int &motor_group, int scan){
+    char str[BUFFER_SIZE];
+    char temp1[BUFFER_SIZE], temp2[50];
+    char a,b;
+    bool new_motors = 0;
+    int total_motor_groups, motors_in_last_group;
+    int counter=1;
+    //
+    //go to scan and check if new motors are specified  
+    //
+    if(scan>1){
+        scan_rewinder(in, scan);
+        new_motors = is_motor(in);
+    }
+    //
+    //if there are new motors in the scan go there
+    //
+    if(new_motors)scan_rewinder(in, scan);
+    //
+    //count motor groups
+    //
+    if(!(total_motor_groups = motor_counter(in))){  
+        cout<<"NO motors in the file\n";
+        exit(1);
+    }
+    //
+    //count motors in last group, in the rest of the groups there is always 8
+    //
+    scan_rewinder(in, scan);  
+    if(!(motors_in_last_group = m_label_counter(in, total_motor_groups-1 ))) {
+        cout<<"NO motors in last group\n";
+        exit(1);
+    }
+    //
+    //if new motors in the scan go there, else work at the beginnig of the file 
+    //
+    if(new_motors)scan_rewinder(in, scan);
+  
+    motor_group = 0;
+    //
+    //stop searching for motors if #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//fail bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//read first sign in line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+        //
+	//motor section
+        //
+	if(a=='#'&& b=='O'){
+            //
+	    //go through every motor groups when searching for the motor
+            //
+	    while(motor_group<total_motor_groups-1){
+                //
+		//ignore motor number (i.e. #O4)
+		//
+		in.ignore(7,' ');
+		//
+		//ignore white spaces until first motor
+	        //
+		while(in.peek()==' ') in.ignore(1, ' ');
+		//
+		//check until last motor
+                //
+		while(counter<8){
+		    //
+		    //get motor name
+                    //
+		    in.getline(temp1, 49, ' ');          
+                    while(in.peek()!=' '){
+                        strcat(temp1, " ");//single one spaces can be in the motor name
+                        in.getline(temp2, 49, ' ');
+                        strcat(temp1, temp2);            
+                    } 
+                    if(!strcmp(label, temp1)){//check if motor match
+                        break;
+                    }
+                    counter++;//increment counter of labels in the group if not found
+                    //
+		    //get rid of white spaces separating motors
+		    //
+		    while(in.peek()==' '){
+                        in.ignore(1,' ');
+                    } 
+                }
+		//
+		//case of last motor in group
+                //
+		if(counter!=8)break;
+                //
+		//get last moto and check if matches
+		//
+		else{
+                    in.getline(temp1, 150);
+                    if(!strcmp(label, temp1))break;
+                    motor_group++;//if not go to next group
+                    counter=1;
+                }
+            }
+	    //
+	    //case for last group where there is <=8 motors
+            //
+	    if(motor_group==total_motor_groups-1){
+                //
+		//ignore motor number in the tag
+		//
+		in.ignore(7,' ');
+                //
+		//ignore white spaces
+		//
+		while(in.peek()==' ') in.ignore(1, ' ');
+                //
+		//check motors until last in the last group
+		//
+		while(counter<motors_in_last_group){
+                    in.getline(temp1, 49, ' ');          
+                    while(in.peek()!=' '){
+                        strcat(temp1, " ");
+                        in.getline(temp2, 49, ' ');
+                        strcat(temp1, temp2);            
+                    } 
+                    if(!strcmp(label, temp1)){//check if motor match
+                        break;
+                    }
+                    counter++;
+                    while(in.peek()==' '){//get rod of white spaces separating motors
+                        in.ignore(1,' ');
+                    } 
+                }
+		//
+		//case for last motor in last group
+                //
+		if(counter==motors_in_last_group){
+                    in.getline(temp1, 150);//get motor name
+                    if(!strcmp(label, temp1))break;//check if matches
+                    counter=0;//any of motors mathc the one invoked
+                }          
+            }
+            break;
+        }
+        else
+	    //
+	    //go to next line in case of wrong tag
+            //
+	    in.getline(str, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+    return counter;
+}
+
+
+
+/**
+* Function counts how many motor groups exist in the scan.
+* Used in get_motor_position(...) function. 
+* Parameters: input - input file stream, 
+* 
+* Returns: number of motor groups in the scan, zero if there is no motors.  
+*/
+int motor_counter(ifstream &in){
+    char str[BUFFER_SIZE];
+    char a,b;
+    int counter=0; 
+    bool flag=0;
+    //
+    //search until #L tag is found
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//fail bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign in the line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+	//
+	//check for motor tag
+        //
+	if(a=='#'&& b=='P'){
+            counter++;
+            flag=1;
+        }
+	//
+	//if counted already break
+        //
+	else if(flag==1)break;
+        //
+	//go to next line in case of wrong tag
+        //
+	in.getline(str, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+    return counter;
+}
+
+
+
+/**
+* Function counts how many motors are in the given group.
+* Used in get_motor_position(...) function for last 
+* motor group, because in the rest there is always 8. 
+* Parameters: input - input file stream, int motor group
+* 
+* Returns: number of motors in the group, zero if there is no motors.  
+*/
+int m_label_counter(ifstream &in, int noMotor){
+    char str[BUFFER_SIZE];
+    long double value;
+    char a,b;
+    int motor=0;
+    int counter=0;
+    //
+    //search until #L is found
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get the first sign from the line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one 
+        //
+	in.get(b);
+	//
+	//interesting case
+        //
+	if(a=='#'&& b=='P'){
+            in.ignore(5,' ');
+            if(motor==noMotor){//check if the interesting group is met
+                while(in.peek()!='\n'){
+                    if(in.peek()==' ')in.ignore(3,' ');
+                    //
+		    //count values of the motor in the motor group
+		    //
+		    else{
+                        in >> value;
+                        counter++;
+                    }
+                }
+                break;
+            }
+	    //
+	    //increment motor group
+            //
+	    else motor++;
+        }
+	//
+	//next line, tag does not match
+        //
+	in.getline(str, BUFFER_SIZE-1);
+    }
+    //
+    //rewind the file when finished
+    //
+    in.seekg(0, ios::beg);
+    return counter;
+}
+
+
+
+/**
+* Function checks if there are new motors in the scan.
+* Used in get_motor_position(...) function. If there are any
+* new motors in the scan, function get_motor_position(...) 
+* search for motor at the beginning of the file. 
+* Parameters: input - input file stream, 
+* 
+* Returns: true if new motor exist in the scan, false otherwise.  
+*/
+bool is_motor(ifstream &in){
+    bool exist = 0;
+    char str[BUFFER_SIZE];
+    char a,b; 
+    //
+    //search until #P is met 
+    //
+    while(!(a =='#' && b =='P')){
+        //
+	//fail bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//get first sign
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+	//
+	//motor tag
+        //
+	if(a=='#'&& b=='O'){
+            exist=1;//motors met
+            break;
+        }
+	//
+	//go to next line 
+        //
+	else in.getline(str, BUFFER_SIZE);
+    }
+    //
+    //rewind file
+    //
+    in.seekg(0, ios::beg);
+    return exist;
+}
+
+
+
+/**
+* Function reads value of given motor in the given scan. Values
+* of motor position and motor groups are calculated 
+* by get_motor_position(...) function.  
+* search for motor at the beginning of the file. 
+* Parameters: input - input file stream, int motor group,   
+*             int motor position, int scan number 
+* Returns: double value of the motor in the scan.  
+*/
+double get_motor_value(ifstream &in, int noMotor, int noValue, int scan){
+    char str[BUFFER_SIZE];
+    double value;
+    //
+    //go to scan
+    //
+    scan_rewinder(in, scan);
+    //
+    //count motors in the group
+    //
+    int MAX = m_label_counter(in, noMotor);
+    if(noValue>MAX || noValue<1){
+        cout<<"Uncorrect number of value\n";
+        exit(1);
+    }
+    //
+    //go back to the scan
+    //
+    scan_rewinder(in, scan);
+    char a,b;
+    int motor=0;
+    //
+    //stop working when #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+            break;
+        }
+        in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+        in.get(b);
+	//
+	//motor values section
+        //
+	if(a=='#'&& b=='P'){
+            in.ignore(5,' ');
+            if(motor==noMotor){
+                for(int i=0; i<noValue; i++){
+                    in >> value;//read value until intersted motor
+                }
+                break;
+            }
+            else motor++;
+        }
+        in.getline(str, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+    return value;
+}
+
+
+
+/**
+* Function set the carriage at the beginning of the scan,
+* from which we want to read data. If the scan number parameter
+* is bigger then number of last scan in the file, error will notified. 
+* Parameters: input - input file stream, int scan number
+*            
+* Returns: true if scan was found, false otherwise  
+*/
+bool scan_rewinder(ifstream &in, int scan_number){
+    //
+    //check if the scan number exist in the file
+    //
+    if(scan_number>total_scans(in)){
+        cout<<" Scan number "<<scan_number<<" does not exist in the file. ";
+        in.seekg(0);
+        exit(1);
+    }
+    bool correct=0;
+    int counter=0;
+    char string[BUFFER_SIZE];
+    char a,b;
+    //
+    //rewind file
+    //
+    in.seekg(0);
+    //
+    //finish with EOF
+    //
+    while(!(in.eof())){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(string, BUFFER_SIZE-1);
+        }
+        in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+        in.get(b);
+	//
+	//check for new scan seciotn
+        //
+	if(a=='#'&& b=='S'){
+            counter++;//count scans
+            if(counter==scan_number){
+            correct=1;//break if the interesting scan is reached
+            break;
+            }
+        }
+        in.getline(string, BUFFER_SIZE-1);
+    }
+    //
+    //reset falgs in stream in case of EOF
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    return correct;   
+}
+
+
+
+/**
+* Function counts all scans in the file.
+* Carriage is rewinded at the beginning of the file
+* after scans were counted. 
+* Parameters: input - input file stream, 
+*            
+* Returns: int number of scans.  
+*/
+int total_scans(ifstream &in){
+    int counter=0;
+    char string[BUFFER_SIZE];
+    char a,b;
+    //
+    //rewind file
+    //
+    in.seekg(0);
+    //
+    //finish with the end of file
+    //
+    while(!(in.eof())){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(string, BUFFER_SIZE-1);
+        }
+        in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+        in.get(b);
+	//
+	//new scan section
+        //
+	if(a=='#'&& b=='S'){
+            counter++;//count scans
+        }
+        in.getline(string, 255);
+    }
+    //
+    //reset flags in stream for EOF
+    //
+    if(in.eof()){
+        in.clear(in.rdstate() & ~ios::eofbit & ~ios::failbit);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0);
+    return counter;   
+}
+
+
+
+/**
+* Function returns name of the label corresponding to its position.
+* It searches in #L group until position is met. 
+* Parameters: input - input file stream, int position, int number of scan 
+*             output - char* label
+* Returns: zero if there is no label for that postion, 1 otherwise  
+*/
+bool get_label(ifstream &in, int number, char *label, int scan_number){ 
+    bool empty = 0;
+    scan_rewinder(in, scan_number);
+    char temp[50];
+    char str[BUFFER_SIZE];
+    char a,b;
+    int counter=0;
+    //
+    //count labels
+    //
+    int MAX=count_columns(in);
+    if(number==MAX) counter=1;
+    if (number>MAX){
+        cout<<" Label number "<<number<<" does not exist in the file. ";
+	exit(1);
+    }
+    //
+    //stop when #S is met
+    //
+    while(!(a =='#' && b =='S')){
+        //
+	//fail bit prevention
+        //
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+        }
+        in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+        in.get(b);
+	//
+	//variable section
+        //
+	if(a=='#'&& b=='L'){
+            while(in.peek()==' ') in.ignore(3, ' ');
+            //
+	    //loop until the interested label
+	    //
+	    while(counter<number){ 
+                in.getline(label, 49, ' ');          
+                while(in.peek()!=' '){
+                    strcat(label, " ");
+                    in.getline(temp, 49, ' ');
+                    strcat(label, temp);           
+                }
+                counter++;
+                while(in.peek()==' '){
+                    in.ignore(3,' ');
+                } 
+            }
+	    //
+	    //in case of last label 
+            //
+	    if(counter==(MAX))in.getline(label, 150);
+                empty = 1;
+                break;
+        }
+        else
+	    //
+	    //go to next line if not #L
+  	    //
+	    in.getline(str, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+    return empty;
+}
+
+/**
+* Function returns name of the motor corresponding to its position.
+* It searches in #O group until position is met. 
+* Parameters: input - input file stream, int position, int motor group 
+*             output - char* motor_name
+* Returns:   
+*/
+void get_motor_name(ifstream &in, char *motor_name, int motor_group, int motor_position){
+    char str[BUFFER_SIZE];
+    char temp2[50];
+    char a,b;
+    int total_motor_groups, motors_number;
+    int counter=0;
+    
+    in.seekg(0, ios::beg);
+    //
+    //count motor groups
+    //
+    if(!(total_motor_groups = motor_counter(in))){  
+        cout<<"NO motors in the file\n";
+        exit(1);
+    }
+    if(motor_group>total_motor_groups-1){
+        cout<<" Motor group "<<motor_group<<" is not in the file\n";
+	exit(1);
+    }
+    //
+    //count motors in last group, in the rest of the groups there is always 8 
+    //
+    if(!(motors_number = m_label_counter(in, motor_group ))) {
+        cout<<"NO motors in last group\n";
+        exit(1);
+    }
+    if(motor_position>motors_number || motor_position<1){
+        cout<<" Uncorrect number of label\n";
+        exit(1);
+    }    
+    //
+    //set counter to 1 if last motor in the group
+    //
+    if(motor_position==motors_number) counter=1;
+    //
+    //stop searching for motors if #L is met
+    //
+    while(!(a =='#' && b =='L')){
+        //
+	//fail bit prevention
+	//
+	if(in.fail()){
+            in.clear(in.rdstate() & ~ios::failbit);
+            in.getline(str, BUFFER_SIZE-1);
+            break;
+        }
+	//
+	//read first sign in line
+        //
+	in.get(a);
+        while(isspace(a)!=0){
+            in.get(a);
+        }
+	//
+	//get the second one
+        //
+	in.get(b);
+        //
+	//motor section
+        //
+	if(a=='#'&& b=='O'){    
+	        //
+		//go to invoked group
+		//
+		for(int i=0; i<motor_group; i++){
+		    in.getline(str, BUFFER_SIZE-1);
+		}
+		//
+		//ignore motor number (i.e. #O4)
+		//
+		in.ignore(7,' ');
+		//
+		//ignore white spaces until first motor
+	        //
+		while(in.peek()==' ') in.ignore(1, ' ');
+		//
+		//check until last motor
+		//
+		while(counter<motor_position){
+		    //
+		    //get motor name
+                    //
+		    in.getline(motor_name, 49, ' ');          
+                    while(in.peek()!=' '){
+                        strcat(motor_name, " ");//single one spaces can be in the motor name
+                        in.getline(temp2, 49, ' ');
+                        strcat(motor_name, temp2);            
+                    } 
+                        
+                    counter++;//increment counter of labels in the group if not found
+                    //     
+	            //get rid of white spaces separating motors
+		    //
+		    while(in.peek()==' '){
+                        in.ignore(1,' ');
+                    } 
+                }
+	        //
+		//case of last motor in group
+	        //
+		if(motor_position==motors_number)
+                    //
+		    //get last moto 
+                    //
+		    in.getline(motor_name, 150);
+	       
+	       break;    
+        }
+        else
+	    //
+	    //go to next line in case of wrong tag
+            //
+	    in.getline(str, BUFFER_SIZE-1);
+    }
+    //
+    //rewind file when finished
+    //
+    in.seekg(0, ios::beg);
+}
+
+
+
+
+
diff --git a/applications/NXtranslate/spec/SPEClib.h b/applications/NXtranslate/spec/SPEClib.h
new file mode 100644
index 0000000..dc243f2
--- /dev/null
+++ b/applications/NXtranslate/spec/SPEClib.h
@@ -0,0 +1,60 @@
+//+**********************************************************************
+//
+// File:	SPEClib.h
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	definitions of a SPEClib functions. It is a library,
+//              which makes possible reading data from SPEC format.
+//              The library consists set of functions which parse
+//              SPEC file(pure ASCI file). Every single function
+//              retrieves different information from the file.
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	March 2006
+//
+//+**********************************************************************
+
+#ifndef SPECLIB_H_
+#define SPECLIB_H_
+
+#include <stdexcept>
+#include <iostream>
+#include <cstring>
+#include <cstdio>
+#include <cctype>
+#include <cstdlib>
+#include <fstream>
+#include <iomanip>
+
+#define BUFFER_SIZE  256
+//#define DELIMITER ':'
+using namespace std;
+
+bool get_file_name(ifstream &in, char *result);
+bool get_date(ifstream &in, char *result);
+bool get_userID(ifstream &in, char *result);
+bool refill_time(ifstream &in, char *result);
+bool refill_mode(ifstream &in, char *result);
+bool get_label(ifstream &in, int number, char *label, int scan_number);
+int count_columns(ifstream &in);
+//long double get_value(ifstream &in, int number, int scanNumber);
+bool get_values(ifstream &in, int number, double results[], int scan_number);
+int get_motor_position(ifstream &in, char *label, int &motor_group, int scan);
+int motor_counter(ifstream &in);
+double get_motor_value(ifstream &in, int noMotor, int noValue, int scan);
+//bool get_scan_comment(ifstream &in, char *result);
+//double time_used(ifstream &in);
+//int get_scan_number(ifstream &in);
+int get_label_position(ifstream &in, char *label, int scan);
+int count_data_sets(ifstream &in);
+int m_label_counter(ifstream &in, int noMotor);
+//int count_scans(ifstream &in);*/
+int total_scans(ifstream &in);
+bool scan_rewinder(ifstream &in, int scan_number);
+bool is_motor(ifstream &in);
+void get_motor_name(ifstream &in, char *motor_name, int motor_group, int motor_position);
+//bool command_parser(const string &location, char &letter, char *label, int &scan);
+
+#endif /*SPECLIB_H_*/
diff --git a/applications/NXtranslate/spec/spec_retriever.cpp b/applications/NXtranslate/spec/spec_retriever.cpp
new file mode 100644
index 0000000..5d0c1c3
--- /dev/null
+++ b/applications/NXtranslate/spec/spec_retriever.cpp
@@ -0,0 +1,1024 @@
+//+**********************************************************************
+//
+// File:	spec_retriever.cpp
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	code for implementing a retriever of data from spec files.
+//		It is added into NXtranslate program in the form of plugin. 
+//              By parsing a XML configuration file of
+//              NXtranslate program using this plugin, data from SPEC tags 
+//              can be read and stored in NeXus file.
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	March 2006
+//
+//+**********************************************************************
+
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include "spec_retriever.h"
+#include "SPEClib.h"
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+//
+//delimiter used to separate statements in location parameter.
+//used in command parser
+//
+#define DELIMITER ':'    
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+
+
+
+
+
+/** 
+* Function parses location command from .xml configuration file.
+* It divides command on three parts. letter:label:scan_number.
+* It do all the checkins for correctness of the command. Command need 
+* to be built from these three parts(letter, label, int) separated by colons ':'.
+* Parameters: input - string location(command)
+*             output - char letter, char *label, int scan number
+* Returns: true if letter indicates that label is needed(L, O, U), 
+* false for the case of letters(D, F, C) were label can be ommited.
+* In case of any other labels error will occur. 
+*/
+bool command_parser(const string &location, char &letter, char *label, int &scan){
+    bool if_label=0;
+    int size = location.size(); 
+    int counter=0;
+    int second_delimiter;
+    //
+    //location cannot be empty
+    //
+    if(size<=0)
+        throw invalid_argument(" cannot parse empty string ");
+    //
+    //check second place in string for delimiter(L:label:scna_number)	
+    //
+    if(location[1]!=DELIMITER)
+        throw invalid_argument(" after the letter suppose to be delimiter ");    
+    //
+    //count delimiters in location, starting from first one	
+    //
+    for(int i=2; i<size; i++){
+        if(location[i]==DELIMITER){
+            second_delimiter=i;
+            counter++;
+        }
+    }
+    //
+    //after the first supposed to be only one delimiter in the string
+    //
+    if(counter!=1)
+        throw invalid_argument(" insert just two delimiters in the string "); 
+    //
+    //letter always on the first position
+    //
+    letter = location[0];  
+    
+    // 
+    //case for tags with labels
+    //
+    if(letter=='L' || letter=='O' || letter=='U' ){
+        for(int i=2; i<second_delimiter; i++){
+            label[i-2]=location[i];//subscribe label
+        }
+        label[second_delimiter-2]='\0';
+        if_label=1;
+    }
+    
+    //
+    //case for tags without labels
+    //
+    else if(letter=='F' || letter=='D' || letter=='C' )if_label=0;
+  
+    //
+    //letter does not match any of cases
+    //
+    else
+        throw invalid_argument(" the letter indicating label group is not supported ");
+    //
+    //temp is equal to last paramter in location(scan number)
+    //
+    string temp = string(location, second_delimiter+1, size-second_delimiter);
+    
+    //
+    //check if scan number is a number  
+    //
+    if(temp[0]!='*'){
+        scan = string_util::str_to_int(temp);
+        //
+	//scan number must be geater than zero
+        //
+	if(scan<=0)
+            throw invalid_argument(" scan number must be bigger than zero ");
+    }
+    //
+    //case where scan_number == '*', retrieve data from every scans
+    //
+    else scan=0;
+  
+    return if_label;  //returns 1 for tags with labels, 0 otherwise
+}
+
+
+
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+SpecRetriever::SpecRetriever(const string &str): source(str){
+    //
+    // open the file
+    //
+    infile.open(source.c_str());
+
+    //
+    // check that open was successful
+    //
+    if(!infile.is_open())
+        throw invalid_argument("Could not open file: "+source);
+}
+
+SpecRetriever::~SpecRetriever(){
+
+    //
+    // close the file
+    //
+    if(infile)
+        infile.close();
+}
+
+/**
+ * This is the method for retrieving data from a file. The whole
+ * tree will be written to the new file immediately after being
+ * called. Interpreting the string is left up to the implementing
+ * code.
+ */
+void SpecRetriever::getData(const string &location, tree<Node> &tr){
+
+    char letter;
+    char label[BUFFER_SIZE];
+    int scan_number;
+    
+    //
+    //parse location, and check for case with label  
+    //
+    if(command_parser(location, letter, label, scan_number)){
+        //
+        //case for L tag
+        //
+	if(letter=='L'){
+	    //
+	    //iterators for setting the structure of the tree of NeXus file
+	    //
+	    tree<Node>::iterator root, first_gen, second_gen;
+	    //
+	    //case for every labels from the scan
+	    //
+	    if(!strcmp(label,"*")){
+                
+		string scan_group = "scan_";//template for name of the scan NXentry
+                char lab[BUFFER_SIZE];//name of the label
+                char number[5];//temporary array for storing scan number
+                int MaxLabel; 
+                //
+		//case for every scans(L:*:*) 	    	     
+                //
+		if(scan_number==0){
+                    auto_translation(tr);
+                } 
+		//
+		//case for L:*:scan_number, store data of every labels for given scan  
+                //
+		else{
+	            //
+		    //create folder for the interesting scan
+	            //
+		    Node node("empty", "NXentry"); 
+	            first_gen = tr.insert(tr.end(),node);
+	            
+		    //
+		    //go to the scan and count number of measurements
+	            //
+		    scan_rewinder(infile, scan_number);
+	        const int size_of_data = count_data_sets(infile);
+	            if(!(size_of_data)){
+	                cout<<" No data was collected in the scan "<<scan_number<<"\n";
+	                exit(1);
+	            }
+	            //
+		    //create array for storing data
+	            //
+		    std::vector<double> data(size_of_data);
+                    const int dims[1]={size_of_data};
+	            //
+		    //count labels
+	            //
+		    scan_rewinder(infile,scan_number);
+		    if(!(MaxLabel = count_columns(infile))){
+	                cout<<" No labels in the scan "<<scan_number<<"\n";
+	                exit(1);		    
+		    }
+		    //
+		    //loop through every labels
+	            //
+		    for(int j=1; j<MaxLabel+1; j++){
+		        //
+			//get the name of the label j-th
+	                //
+			if(!get_label(infile, j, lab, scan_number)){
+		            cout<<" Label number "<<j<<" in scan number "<<scan_number<<" does not exist. ";
+		            strcpy(lab, "translation_error");
+		        }
+		        
+			//
+			//put '_' instead of every spaces in the name of the label    
+			//
+			for(int a=0; a<strlen(lab); a++){
+			    if(lab[0]<57)lab[0]='A';
+		            if(lab[a]==' ' || lab[a]=='(' || lab[a]==')')lab[a]='_';
+		        }
+		        //
+			//get values corresponding to label j-th
+	                //
+			get_values(infile, j, &(data[0]), scan_number);
+	            
+			//
+			//create NXdata group for storing label data item
+		        //
+			Node child_group(lab, "NXdata");
+			//
+			//append NXdata group to NXentry(scan) group
+	                //
+			second_gen = tr.append_child(first_gen, child_group);
+		        //
+			//insert data item into NXdata group
+		        //
+			Node node_child(lab, (void*)&(data[0]), 1, dims, NX_FLOAT64);
+                        tr.append_child(second_gen,node_child);	      
+	            }              
+                }     
+            }
+	    //
+	    //case for single label
+            //
+	    else{
+	        
+      	        int size_of_data;
+	        int label_position;
+		//	
+		//single label from single scan
+		//
+		if(scan_number!=0){
+                    //
+		    //get position of label indicated by "label" parameter 
+	            //
+		    if(!(label_position = get_label_position(infile, label, scan_number))){
+	                cout<<" Variable "<<label<<" is not in the scan number "<<scan_number<<"\n";
+	                exit(1);
+	            }
+                    //
+		    //go to scan
+	            //
+		    scan_rewinder(infile, scan_number);
+	            //
+		    //count data sets and prepare array for results
+		    //
+		    if(!(size_of_data = count_data_sets(infile))){
+                        cout<<" No data was collected in the scan "<<scan_number<<"\n";
+	                exit(1);
+	            }
+	            
+	            std::vector<double> data(size_of_data);
+                    const int dims[1]={size_of_data}; 
+                    //
+		    //store values read from scan
+                    //
+		    get_values(infile, label_position, &(data[0]), scan_number);
+                    //
+		    //insert data item with label values
+	            //
+		    Node node(location, (void*)&(data[0]), 1, dims, NX_FLOAT64);
+                    tr.insert(tr.begin(),node);
+	        }
+		//
+		//case for single label from every scans(L:label:*)
+	        //
+		else{
+	            //
+		    //prepare name for scan entry  
+		    //
+		    string scan_group = "scan_";
+	            char number[5];
+	            string item_name = string(label);
+		    //
+		    //insert "_" instead of every spaces in label name to name data item in nexus
+		    //
+		    for(int a=0; a<strlen(label); a++){
+			if(label[0]<57)label[0]='A';
+		        if(label[a]==' ' || label[a]=='(' || label[a]==')')label[a]='_';
+		    }
+		    //
+		    //create entry for data corresponding to label from every scans 
+	            //
+		    Node node("empty", "NXentry");
+                    first_gen = tr.insert(tr.end(),node);
+	            //
+		    //count scans
+	            //
+		    int scan_total=total_scans(infile);
+                    //
+		    //fetch data from every scans	
+	            //
+		    for(int i=1; i<scan_total+1; i++){
+		        //
+			//find postion of label
+	                //
+			if(!(label_position = get_label_position(infile, label, i))){
+	                    cout<<" Variable "<<label<<" is not in the scan number "<<i<<"\n";
+	                }
+			//
+			//prepare name of the scan
+	                //
+			sprintf(number,"%d",i);
+	                scan_group.replace(5,5,number);
+	                //
+			//go to scan i and count data sets in order to prepare array for data
+			//
+			scan_rewinder(infile, i);
+	                if(!(size_of_data = count_data_sets(infile))){
+	                    cout<<" No data was collected in the scan "<<i<<"\n";
+	                    exit(1);
+			}
+	                
+	                std::vector<double> data(size_of_data);
+                        const int dims[1]={size_of_data}; 
+                        //
+			//fetch data corresponding to label in i-th scan
+	                //
+			get_values(infile, label_position, &(data[0]), i);
+                        //
+			//insert data group with the name of the scan, 
+	                //
+			Node child_group(scan_group, "NXdata");
+	                second_gen = tr.append_child(first_gen, child_group);
+		        //
+			//store plottable data item in the group NXdata, for given scan
+                        //
+			Node node_child(item_name, (void*)&(data[0]), 1, dims, NX_FLOAT64);
+                        tr.append_child(second_gen,node_child);	
+	
+	            }              
+	        }
+            }
+        }
+        //
+	//case for motors
+        //
+	else if(letter=='O'){
+	    //
+	    //iterators for setting the structure of the tree of NeXus file
+	    //
+	    tree<Node>::iterator root, first_gen, second_gen;
+	    int motor_position;
+	    int motor_group;
+	    int motor_groups;
+	    int motors_in_last_group;
+	    double motor_value[1];//single values for motors
+	    const int dims[1]={1};
+	    //
+	    //case for every motors from the scan
+	    //
+	    if(!strcmp(label,"*")){
+                string scan_group = "moto_";
+		char number[5];
+
+		char lab[BUFFER_SIZE];//name of the label
+
+                //		    
+		//create folder for the interesting scan
+	        //
+		Node node("empty", "NXlog"); 
+	        first_gen = tr.insert(tr.end(),node);
+		    
+	        scan_rewinder(infile, scan_number);
+		//
+		//count motor groups
+                //
+		if(!(motor_groups = motor_counter(infile))){  
+                    cout<<"NO motors in the file\n";
+                    exit(1);
+                }
+                //
+                //count motors in last group, in the rest of the groups there is always 8
+                //
+		scan_rewinder(infile, scan_number);  
+                if(!(motors_in_last_group = m_label_counter(infile, motor_groups-1 ))) {
+                    cout<<"NO motors in last group\n";
+                    exit(1);
+                }
+                //
+		//loop through motors from every groups apart of the last one
+	        //
+		for(int j=0; j<motor_groups-1; j++){
+		    for(int k=1; k<9; k++){
+		        //   
+		        //get the name of the k-th motor from the j-th motor group
+		        //
+			get_motor_name(infile, lab, j, k);
+                        //
+		        //put '_' instead of every spaces in the name of the label    
+		        //
+			for(int a=0; a<strlen(lab); a++){
+			    if(lab[0]<57)lab[0]='A';
+		            if(lab[a]==' ' || lab[a]=='(' || lab[a]==')')lab[a]='_';
+	                }
+
+		       //
+		       //get position of the motor k-th from j-th
+	               // 
+			motor_value[0] = get_motor_value(infile, j, k, scan_number);
+		        //
+	                //insert data item with motor value into NXlog group
+		        //
+			Node node_child(lab, (void*)motor_value, 1, dims, NX_FLOAT64);
+                        tr.append_child(first_gen,node_child);
+		    }	      
+	        }
+		//
+		//get motor positions from the last group 
+		//
+		for(int k=1; k<motors_in_last_group+1; k++){
+		    //
+		    //get the name of the k-th motor from the j-th motor group
+		    //
+		    get_motor_name(infile, lab, motor_groups-1, k);
+                    //
+		    //put '_' instead of every spaces in the name of the label    
+		    //
+		    for(int a=0; a<strlen(lab); a++){
+			    if(lab[0]<57)lab[0]='A';
+		            if(lab[a]==' ' || lab[a]=='(' || lab[a]==')')lab[a]='_';
+	            }
+		    
+		    //    
+		    //get position of the motor k-th from j-th
+	            //
+		    motor_value[0] = get_motor_value(infile, motor_groups-1, k, scan_number);
+		    //    
+	            //insert data item with motor value into NXlog group
+		    //
+		    Node node_child(lab, (void*)motor_value, 1, dims, NX_FLOAT64);
+                    tr.append_child(first_gen,node_child);		
+		}		
+            }
+	    //
+	    //single motor
+	    //
+	    else{
+	        //
+		//single motor from single scan
+	        //
+		if(scan_number!=0){
+	            //    
+	            //look for motor position in the list of motors
+	            //
+		    if(!(motor_position = get_motor_position(infile, label, motor_group, scan_number))){
+	                cout<<" Variable "<<label<<" is not in the scan number "<<scan_number<<"\n";
+	                exit(1);
+	            }        
+                    //
+	            //fetch motor value from interesting scan
+	            //
+		    motor_value[0] = get_motor_value(infile, motor_group, motor_position, scan_number);
+                    //
+	            //insert data item in the place from where it was called
+    	            //
+		    Node node(location, (void*)motor_value, 1, dims, NX_FLOAT64);
+                    tr.insert(tr.begin(),node);
+                }
+	        //
+		//single motor from every scans
+	        //
+		else{
+	            //
+		    //prepare name for scan entry  
+		    //
+		    string scan_group = "scan_";
+	            char number[5];
+	            string item_name=string(label);
+		    //
+		    //insert "_" instead of every spaces in label name to name data item in nexus
+		    //
+		    for(int a=0; a<strlen(label); a++){
+			if(label[0]<57)item_name[0]='A';
+		        if(label[a]==' ' || label[a]=='(' || label[a]==')')item_name[a]='_';
+		    }
+		    //
+		    //create entry for data corresponding to motor from every scans 
+	            //
+		    Node node("empty", "NXentry");
+	            first_gen = tr.insert(tr.end(),node);
+		    //
+		    //count scans
+	            //
+		    int scan_total=total_scans(infile);
+                    //
+		    //fetch data from every scans	
+	            //
+		    for(int i=1; i<scan_total+1; i++){
+	                //
+			//look for motor position in the list of motors
+	                //
+			if(!(motor_position = get_motor_position(infile, label, motor_group, i))){
+	                    cout<<" Variable "<<label<<" is not in the scan number "<<i<<"\n";
+	                    exit(1);
+	                }        
+                        //
+	                //fetch motor value from interesting scan
+	                //
+			motor_value[0] = get_motor_value(infile, motor_group, motor_position, i);
+		        //
+		        //prepare name of the scan
+	                //
+			sprintf(number,"%d",i);
+	                scan_group.replace(5,5,number);
+		    	   
+		        //
+	                //insert log group with the name of the scan, 
+	                //
+			Node child_group(scan_group, "NXlog");
+	                second_gen = tr.append_child(first_gen, child_group);
+		        //
+	                //store motor's value item in the group NXlog, for given scan
+                        //
+			Node node_child(item_name, (void*)motor_value, 1, dims, NX_FLOAT64);
+                        tr.append_child(second_gen,node_child);
+		    }
+	        }
+	    }
+	}
+	//
+	//case for user notes tag
+        //
+	else if(letter=='U'){
+	
+            char refill[BUFFER_SIZE];
+	    //
+	    //case for refill mode
+            //
+	    if(!(strcmp(label, "mode"))){
+                //
+	        //go to scan
+	        //
+		scan_rewinder(infile, scan_number);
+	        //
+		//read refill mode
+	        //
+		if(!(refill_mode(infile, refill))){
+	            cout<<" There is no refill mode indicated in scan "<<scan_number<<"\n";
+	            cout<<" Empty string saved in the nexus file\n";
+	            strcpy(refill," ");
+	        } 
+		//
+		//prepare dimensions for storing refill mode       
+	        //
+		const int dims[1]={strlen(refill)};
+	        //
+		//store refill mode item in the place in hierarchy from where it was invoked
+    	        //
+		Node node(location, (void*)refill, 1, dims, NX_CHAR);
+                tr.insert(tr.begin(),node);	  
+            }
+            //
+	    //case for time of refill
+            //
+	    else if(!(strcmp(label, "time"))){
+                //
+		//go to scan
+	        //
+		scan_rewinder(infile, scan_number);
+	        //
+		//read time of refill, print error if it is not found
+	        //
+		if(!(refill_time(infile, refill))){
+	            cout<<" There is no refill time indicated in scan "<<scan_number<<"\n";
+	            cout<<" Empty string saved in the nexus file\n";
+	            strcpy(refill," ");
+	        } 
+		//
+		//prepare dimension parameter for storing time of refill information       
+	        //
+		const int dims[1]={strlen(refill)};
+	        //
+		//store refill time in the place from invoked
+    	        //
+		Node node(location, (void*)refill, 1, dims, NX_CHAR);
+                tr.insert(tr.begin(),node);	  
+            }
+       
+            else {
+                //
+		//letter does not match anything in SPEC file
+	        //
+		cout<<" Wrong label "<<label<<" for U mode.\n";
+	        exit(1);
+            }   
+        }
+    }  
+    //
+    //case for tags which do not need label argument
+    //
+    else{
+    
+        char result[BUFFER_SIZE];
+        //
+	//check letter
+        //
+	switch(letter){
+            //
+	    //file name tag
+	    //
+	    case 'F':
+                //
+		//read file name of SPEC file 
+		//
+		if(!get_file_name(infile, result)){
+	            cout<<" File name not specified. Empty string written into the nexus file.\n";
+	            strcpy(result," ");
+	        }
+                break;
+	    //
+	    //comment tag(user ID is specified there)
+            //
+	    case 'C':
+                //
+		//read user ID
+		//
+		if(!get_userID(infile, result)){
+	            cout<<" User Id not specified. Empty string written into the nexus file.\n";
+	            strcpy(result," ");
+	        }	
+                break;
+	    //
+	    //scan data tag
+            //
+	    case 'D':
+	    	if(scan_number!=0){
+		    //
+		    //go to the scan
+	            //
+		    scan_rewinder(infile, scan_number);
+	            //
+		    //read date of the scan 
+		    //
+		    if(!get_date(infile, result)){
+	                cout<<" Date of scan "<<scan_number<<" not specified. Empty string written into the nexus file.\n";
+	                strcpy(result," ");
+	            }
+		}
+		//
+                //get dates of every scans	        
+		//
+		else{
+		    //
+		    //prepare iterators for the hierarchy
+		    //
+		    tree<Node>::iterator root;
+		    //
+	            //prepare name for scan date  
+		    //
+		    string scan_group = "date_of_scan_";
+	            char number[5];
+	            //
+		    //create entry for data corresponding to dates of every scans 
+	            //
+		    Node node("empty", "NXlog");
+	            root = tr.insert(tr.end(),node);
+	            //
+		    //count scans
+	            //
+		    int scan_total=total_scans(infile);
+                    //
+		    //fetch data from every scans	
+	            //
+		    for(int i=1; i<scan_total+1; i++){
+		        //
+			//go to the scan
+	                //
+			scan_rewinder(infile, i);
+			//
+			//get date of the file
+		        //
+			if(!get_date(infile, result)){
+	                cout<<" Date of scan "<<scan_number<<" not specified. Empty string written into the nexus file.\n";
+	                strcpy(result," ");
+	                }
+			//
+			//prepare name of the scan
+	                //
+			sprintf(number,"%d",i);
+	                scan_group.replace(13,5,number);
+	                
+	                
+                        const int dims[1]={strlen(result)};	 
+		        //
+                        //store just read data in the place from invoked 
+                        //
+			Node node_child(scan_group, (void*)result, 1, dims, NX_CHAR);
+                        tr.append_child(root,node_child);	
+	
+	            }              
+	        }
+                break;
+
+            default:
+	        break; //it will never go here
+        }  
+        if(scan_number!=0){
+            const int dims[1]={strlen(result)};
+            //
+	    //store just read data in the place from invoked 
+            //
+	    Node node(location, (void*)result, 1, dims, NX_CHAR);
+            tr.insert(tr.begin(),node);	 
+        }
+    } 
+
+}
+//
+//indicate mime type
+//
+const string SpecRetriever::MIME_TYPE("spec");
+
+string SpecRetriever::toString() const{
+    return "["+MIME_TYPE+"] "+source;
+}
+ 
+
+/** 
+* Method is used for automatic translation of the file.
+* Details about the rules of translation are in the documantation of the retriever.
+* The method is called from the SpecRetriever::getDate() method, when
+* location paramter is "L:*:*". The whole Spec file is translated automatically. 
+*/
+void SpecRetriever::auto_translation(tree<Node> &t){
+
+    string scan_group = "scan_";//template for name of the scan NXentry
+    char lab[BUFFER_SIZE];//name of the label
+    char number[5];//temporary array for storing scan number
+    int MaxLabel; 
+    int size_of_data;
+
+    tree<Node>::iterator root, first_gen, second_gen;
+    //
+    //set number of scans from the file
+    //
+    int MAX =total_scans(infile);
+    //
+    //for text fields of date, userId, file name
+    //
+    char result[BUFFER_SIZE];
+    //
+    //create root folder, it is advised to call for L:*:* from root level 
+    //
+    Node node("empty", "NXroot"); 
+    root = t.insert(t.end(),node);//insert root to the tree
+ 
+    Node node_user("User_data", "NXuser"); 
+    first_gen = t.append_child(root,node_user);                   
+    //		    
+    //read file name of SPEC file 
+    //
+    if(!get_file_name(infile, result)){
+        cout<<" File name not specified. Empty string written into the nexus file.\n";
+	strcpy(result," ");
+    }
+    //
+    //dimensions of file name
+    //
+    const int dims_file[1]={strlen(result)};	 
+    //	    
+    //store file name in the user group 
+    //
+    Node node_file("file_name", (void*)result, 1, dims_file, NX_CHAR);
+    t.append_child(first_gen,node_file);
+    //	    
+    //read user ID
+    //
+    if(!get_userID(infile, result)){
+        cout<<" User Id not specified. Empty string written into the nexus file.\n";
+	strcpy(result," ");
+    }
+    //
+    //dimensions of userId
+    //
+    const int dims_id[1]={strlen(result)};	 
+    //	    
+    //store user Id in the user group
+    //
+    Node node_id("user_id", (void*)result, 1, dims_id, NX_CHAR);
+    t.append_child(first_gen,node_id);		    
+		    		    
+    //	    
+    //go thru every scans 
+    //
+    for(int i=1; i<MAX+1; i++){
+    //
+    //set the name of every scans(NXentry)
+    //
+	sprintf(number,"%d",i);
+	scan_group.replace(5,5,number);
+        //	                
+	//create NXentry folders for every scans,    
+	//
+	Node node_parent(scan_group, "NXentry"); 
+	//
+	//append as a childs to the root in the tree hierarchy
+	//
+	first_gen = t.append_child(root,node_parent);	    
+	//                
+	//go to the scan i and set number of data sets obtained during experiment    
+	//
+	scan_rewinder(infile, i);
+	if(!(size_of_data = count_data_sets(infile))){
+	    cout<<" No data was collected in the scan "<<i<<"\n";
+	    exit(1);
+	}
+	//                
+	//create array for data sets
+	//
+	std::vector<double> data(size_of_data);
+        const int dims[1]={size_of_data};
+	//               
+	//go back to scan and count every labels
+	//
+	scan_rewinder(infile,i);
+	if(!(MaxLabel = count_columns(infile))){
+	    cout<<" No labels in the scan "<<i<<"\n";
+	    exit(1);		    
+        }
+	//	        
+	//loop through every labels
+        //
+	for(int j=1; j<MaxLabel+1; j++){
+	//                    
+	//get name of the j-th label in scan i-th    
+	//
+	if(!get_label(infile, j, lab, i)){
+	    cout<<" Label number "<<j<<" in scan number "<<i<<" does not exist. ";
+	    strcpy(lab, "translation_error");
+        }
+	//
+	//put underline sign for every spaces in the name of the label
+        //
+	for(int a=0; a<strlen(lab); a++){
+            if(lab[0]<57)lab[0]='A';
+            if(lab[a]==' ' || lab[a]=='(' || lab[a]==')')lab[a]='_';
+        } 
+	//	            
+	//get the results coresponding to j-th label in i-th scan 
+	//
+	get_values(infile, j, &(data[0]), i);
+	//            
+	//create folder to keep data items
+	//
+	Node child_group(lab, "NXdata");
+	//
+	//append folder to the NXentry folder representing i-th scan
+        //
+	second_gen = t.append_child(first_gen, child_group);
+	//	            
+	//store data items in NXdata folder 
+	//
+	Node node_child(lab, (void*)&(data[0]), 1, dims, NX_FLOAT64);
+        t.append_child(second_gen,node_child);	      
+        }
+	//		
+	//add motors to the subtree
+	//
+	int motor_position;
+	int motor_group;
+	int motor_groups;
+	int motors_in_last_group;
+	double motor_value[1];//single values for motors
+	const int dims_moto[1]={1}; 
+	string moto_group = "moto_";
+
+	char lab[BUFFER_SIZE];//name of the label
+ 
+	//	    
+	//create folder for the interesting scan
+	//
+	Node node_motors("Motors", "NXlog"); 
+	second_gen = t.append_child(first_gen,node_motors);
+		    
+        scan_rewinder(infile, i);
+	//
+	//count motor groups
+        //
+	if(!(motor_groups = motor_counter(infile))){  
+            cout<<"NO motors in the file\n";
+            exit(1);
+        }
+        //
+        //count motors in last group, in the rest of the groups there is always 8
+        //
+	scan_rewinder(infile, i);  
+        if(!(motors_in_last_group = m_label_counter(infile, motor_groups-1 ))) {
+            cout<<"NO motors in last group\n";
+            exit(1);
+        }
+        //
+	//loop through motors from every groups apart of the last one
+	//
+	for(int j=0; j<motor_groups-1; j++){
+	    for(int k=1; k<9; k++){
+	        //
+	        //get the name of the k-th motor from the j-th motor group
+		//
+		get_motor_name(infile, lab, j, k);
+                //
+		//put '_' instead of every spaces in the name of the label    
+		//
+		for(int a=0; a<strlen(lab); a++){
+		    if(lab[0]<57)lab[0]='A';
+		    if(lab[a]==' ' || lab[a]=='(' || lab[a]==')')lab[a]='_';
+	        }
+	       //	        
+	       //get value of the motor k-th from j-th
+	       // 
+		motor_value[0] = get_motor_value(infile, j, k, i);
+                //       
+	        //insert data item with motor value into NXlog group
+		//
+		Node node_motor(lab, (void*)motor_value, 1, dims_moto, NX_FLOAT64);
+                t.append_child(second_gen,node_motor);
+            }     
+	}
+	//
+	//get motor positions from the last group 
+	//
+	for(int k=1; k<motors_in_last_group+1; k++){
+            //
+	    //get the name of the k-th motor from the j-th motor group
+            //
+	    get_motor_name(infile, lab, motor_groups-1, k);
+	    //
+	    //put '_' instead of every spaces in the name of the label    
+	    //
+	    for(int a=0; a<strlen(lab); a++){
+                if(lab[0]<57)lab[0]='A';
+		if(lab[a]==' ' || lab[a]=='(' || lab[a]==')')lab[a]='_';
+            }
+            //
+            //get value of the motor k-th from j-th
+	    //
+	    motor_value[0] = get_motor_value(infile, motor_groups-1, k, i);
+            //        
+	    //insert data item with motor value into NXlog group
+            //
+	    Node node_child(lab, (void*)motor_value, 1, dims_moto, NX_FLOAT64);
+            t.append_child(second_gen,node_child);		
+        }
+	//
+	//insert dates of scanning into NXlog group
+	//go to the scan
+	//
+	scan_rewinder(infile, i);
+	//
+	//read date of the scan 
+	//
+	if(!get_date(infile, result)){
+	    cout<<" Date of scan "<<i<<" not specified. Empty string written into the nexus file.\n";
+	    strcpy(result," ");
+        }
+	const int dims_date[1]={strlen(result)};
+        //
+        //go to the scan
+	//
+	scan_rewinder(infile, i);
+	//                
+	//store data in NXlog group
+        //
+	Node node_date("date_of_scan", (void*)result, 1, dims_date, NX_CHAR);
+        t.append_child(second_gen,node_date);	    
+    }
+}
diff --git a/applications/NXtranslate/spec/spec_retriever.h b/applications/NXtranslate/spec/spec_retriever.h
new file mode 100644
index 0000000..95ee11e
--- /dev/null
+++ b/applications/NXtranslate/spec/spec_retriever.h
@@ -0,0 +1,40 @@
+//+**********************************************************************
+//
+// File:	spec_retriever.h
+//
+// Project:	 Fable data to NeXus translation
+//
+// Description:	definition of a spec_retriever class. The retriever allows to
+//              read data from SPEC file and store in Nexus file format.
+//		It uses SPEClib for reading SPEC files. It is a plugin of NXtranslate
+//              program. 
+//
+// Author(s):	Jaroslaw Butanowicz
+//
+// Original:	March 2006
+//
+//+**********************************************************************
+
+#ifndef __SPEC_RETRIEVER_GUARD
+#define __SPEC_RETRIEVER_GUARD
+
+#include "../retriever.h"
+#include <fstream>
+//
+// this is not intended to be inherited from
+//
+class SpecRetriever: public Retriever{
+ public:
+  SpecRetriever(const std::string &);
+  ~SpecRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  void auto_translation(tree<Node> &);
+ // SpecRetriever(const SpecRetriever&);
+ // SpecRetriever& operator=(const SpecRetriever&);
+  std::string source;
+  std::ifstream infile;
+};
+#endif
diff --git a/applications/NXtranslate/string_util.cpp b/applications/NXtranslate/string_util.cpp
new file mode 100644
index 0000000..225e1b4
--- /dev/null
+++ b/applications/NXtranslate/string_util.cpp
@@ -0,0 +1,797 @@
+#include <algorithm>
+#include <cctype>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <stdlib.h>
+#include <stdio.h>
+#include <vector>
+#include "string_util.h"
+
+using std::cout;
+using std::endl;
+using std::find;
+using std::find_if;
+using std::invalid_argument;
+using std::runtime_error;
+using std::isspace;
+using std::string;
+using std::vector;
+
+typedef vector<string> StrVec;
+typedef vector<string>::const_iterator StrVecIter;
+
+static bool my_isnotdigit(char c){
+  return !isdigit(c);
+}
+
+static bool my_isnotfloatdigit(char c){
+  if(c=='.')
+    return false;
+  else
+    return my_isnotdigit(c);
+}
+
+static bool has_non_zero(const string &str){
+  string::size_type size=str.size();
+
+  if(str.find("1")<size || str.find("2")<size || str.find("3")<size || str.find("4")<size
+     || str.find("5")<size || str.find("6")<size || str.find("7")<size || str.find("8")<size
+     || str.find("9")<size )
+    return true;
+
+  return false;
+}
+
+extern bool string_util::starts_with(const string &str1, const string &str2){
+  // empty string can't start with anything
+  if(str1.empty())
+    return false;
+
+  // can't start with something that is longer
+  if(str2.size()>str1.size())
+    return false;
+
+  // if they are the same then just return true
+  if(str1==str2)
+    return true;
+
+  // do the actual comparison
+  string cmp_str=str1.substr(0,str2.size());
+  return (cmp_str==str2);
+}
+
+/*
+ * strip leading and trailing spaces from the string.
+ */
+extern string string_util::trim (const string &str) {
+  typedef string::size_type string_size;
+  string new_str="";
+  string_size i=0;
+  while(i<str.size()){
+    //skip initial whitespace
+    while(i<str.size() && isspace(str[i])) {
+      i++;
+    }
+
+    // find the extent of ending whitespace
+    string_size  j=str.size();
+    while(j>i && isspace(str[j-1])) {
+      j--;
+      }
+
+    //copy the non-whitespace into the new string
+    
+    if (i!=j){
+      new_str+=str.substr(i,j-i);
+      i=j;
+    }
+  }
+  return new_str;
+}
+
+extern long string_util::str_to_int(const string &str){
+  if(str.substr(0,1)=="-")
+    return -1*str_to_int(str.substr(1,str.size()));
+
+  string::const_iterator it=str.begin();
+  it=find_if(it,str.end(),my_isnotdigit);
+
+  if(it!=str.end())
+    throw invalid_argument("str_to_int(string) argument is not an integer");
+
+  return atol(str.c_str());
+}
+
+extern long long string_util::str_to_int64(const string &str){
+  if(str.substr(0,1)=="-")
+    return -1*str_to_int64(str.substr(1,str.size()));
+
+  string::const_iterator it=str.begin();
+  it=find_if(it,str.end(),my_isnotdigit);
+
+  if(it!=str.end())
+    throw invalid_argument("str_to_int(string) argument is not an integer");
+#ifdef _WIN32
+  return _atoi64(str.c_str());
+#else
+  return atoll(str.c_str());
+#endif
+}
+
+extern unsigned long string_util::str_to_uint(const string &str){
+  long num=str_to_int(str);
+  if(num<0)
+    throw invalid_argument("str_to_uint(string) argument is not an integer");
+  return num;
+}
+
+extern unsigned long long string_util::str_to_uint64(const string &str){
+  long long num=str_to_int64(str);
+  if(num<0)
+    throw invalid_argument("str_to_uint(string) argument is not an integer");
+  return num;
+}
+
+extern double string_util::str_to_float(const string &str){
+  double num=atof(str.c_str());
+
+  // check if the return is bad
+  if((num==0.0) || (!num)){
+    string::const_iterator it=str.begin();
+    it=find_if(it,str.end(),my_isnotfloatdigit);
+    if(it!=str.end() || has_non_zero(str)){
+      throw invalid_argument("str_to_float(string) argument is not a float");
+    }
+  }
+
+  return num;
+}
+
+static bool is_bracket(char c){
+  static const string BRACKETS="[]";
+  return find(BRACKETS.begin(),BRACKETS.end(),c)!=BRACKETS.end();
+}
+
+extern bool string_util::is_comma(char c){
+  static const string COMMA=",";
+  return find(COMMA.begin(),COMMA.end(),c)!=COMMA.end();
+}
+
+extern StrVec string_util::split(const string &source,const string &split)
+{
+  string::size_type number=count_occur(source,split);
+  if(number==0)
+    {
+      StrVec result;
+      result.push_back(source);
+      return result;
+    }
+
+  vector<string> result;
+  string::size_type start=0;
+  string::size_type stop=0;
+  string inner;
+  while(true)
+    {
+      stop=source.find(split,start);
+      if(stop==string::npos)
+        {
+          result.push_back(source.substr(start));
+          break;
+        }
+      else
+        {
+          result.push_back(source.substr(start,stop-start));
+          start=stop+split.size();
+        }
+    }
+  return result;
+}
+
+/*
+ * split a string up using commas as the delimiter
+ */
+extern StrVec string_util::split(const string &str){
+  static const string COMMA=",";
+
+  return split(str,COMMA);
+}
+
+static bool is_slash(char c){
+  static const string SLASH="/";
+  return find(SLASH.begin(),SLASH.end(),c)!=SLASH.end();
+}
+
+static bool is_colon(char c){
+  static const string COLON=":";
+  return find(COLON.begin(),COLON.end(),c)!=COLON.end();
+}
+
+extern vector<string> string_util::string_to_path(const string &str){
+  vector<string> result;
+  typedef string::size_type string_size;
+
+  string_size i=0;
+  while(i<str.size()){
+    // skip seperators at the end of the last word
+    while(i<str.size() && (is_slash(str[i]) || is_colon(str[i])) )
+      i++;
+
+    // find end of a "word"
+    string_size j=i;
+    while(j<str.size() && (!is_slash(str[j])) && (!is_colon(str[j])) )
+      j++;
+
+    if(i!=j){
+      result.push_back(str.substr(i,j-i));
+      i=j;
+    }
+  }
+
+  return result;
+}
+
+static bool global_replace(string &str, const string &search, 
+                           const string &replace){
+  string::size_type index=str.find(search);
+
+  if(index==string::npos){
+    return false;
+  }
+
+  string::size_type search_size=search.size();
+  string::size_type replace_size=replace.size();
+  while(index!=string::npos){
+    // replace the search string with the replace string
+    str.replace(index,search_size,replace);
+    // the next place to look is just past where we last found the
+    // search string (which is now the replace string)
+    index=str.find(search,index+replace_size);
+  }
+
+  return true;
+}
+
+static StrVec shrink_and_split(string &str){
+  static const char *COMMA=",";
+  typedef string::size_type string_size;
+
+  // replace brackets with commas
+  for( string::iterator ch=str.begin() ; ch!=str.end() ; ch++ ){
+    if(is_bracket(*ch))
+      *ch=*COMMA;
+  }
+
+  // replace the first space with a comma
+  bool space=false;
+  for( string::iterator ch=str.begin() ; ch!=str.end() ; ch++ ){
+    if(isspace(*ch)){
+      if(!space){
+        space=true;
+        *ch=*COMMA;
+      }
+    }else{
+      space=false;
+    }
+  }
+
+  // remove spaces
+  {
+    string new_str="";
+    string_size i=0;
+    while(i<str.size()){
+      // skip initial whitespace
+      while(i<str.size() && isspace(str[i]))
+        i++;
+
+      // find the end of the non-whitespace section
+      string_size j=i;
+      while(j<str.size() && !isspace(str[j]))
+        j++;
+
+      // copy the non-whitespace into the new string
+      if(i!=j){
+        new_str+=str.substr(i,j-i);
+        i=j;
+      }
+    }
+    str=new_str;
+  }
+
+  // remove commas that are next to each other
+  while(global_replace(str,",,",",")){
+    // the test does the work
+  }
+
+  // trim extra commas off of the beginning
+  while(str.substr(0,1)==COMMA)
+    str.erase(0,1);
+
+  // trim extra commas off of the end
+  while(str.substr(str.size()-1,str.size())==COMMA)
+    str.erase(str.size()-1,str.size());
+
+  return string_util::split(str);
+}
+
+extern void string_util::str_to_shortArray(std::string & str,short *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(short)str_to_int(*(strIt+i));
+}
+
+extern void string_util::str_to_int64Array(std::string & str,long long *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(long long)str_to_int64(*(strIt+i));
+}
+
+extern void string_util::str_to_intArray(std::string & str,int *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(int)str_to_int(*(strIt+i));
+}
+
+extern vector<int> string_util::str_to_intVec(string &str){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  // turn each string into an integer
+  vector<int> result;
+  for( StrVec::const_iterator str=splitted.begin() ; str!=splitted.end() ; str++ )
+    result.push_back(str_to_int(*str));
+
+  // return the vector<int>
+  return result;
+}
+
+extern void string_util::str_to_longArray(std::string & str,long *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(long)str_to_int(*(strIt+i));
+}
+
+extern void string_util::str_to_ushortArray(std::string & str,unsigned short *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(unsigned short)str_to_uint(*(strIt+i));
+}
+
+extern void string_util::str_to_uint64Array(std::string & str,unsigned long long *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(unsigned long long)str_to_uint64(*(strIt+i));
+}
+
+extern void string_util::str_to_uintArray(std::string & str,unsigned int *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(unsigned int)str_to_uint(*(strIt+i));
+}
+
+extern void string_util::str_to_ulongArray(std::string & str,unsigned long *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(unsigned long)str_to_uint(*(strIt+i));
+}
+
+extern void string_util::str_to_floatArray(std::string & str,float *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size ("+string_util::int_to_str(splitted.size())+"!="+string_util::int_to_str(len)+")");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(float)str_to_float(*(strIt+i));
+}
+
+extern void string_util::str_to_doubleArray(std::string & str,double *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(double)str_to_float(*(strIt+i));
+}
+
+extern void string_util::str_to_ucharArray(std::string &str,unsigned char *array, const unsigned int len){
+  // break it up into a string vector
+  StrVec splitted=shrink_and_split(str);
+
+  if(splitted.size()!=len)
+    throw runtime_error("array and string not same size");
+
+  // turn each string into a short
+  StrVecIter strIt=splitted.begin();
+  for( unsigned int i=0 ; i<len ; i++ )
+    *(array+i)=(unsigned char)str_to_int(*(strIt+i));
+}
+
+/*
+ * This method takes a string as an argument and attempts to convert this 
+ * string into a vector of integers.  The string is in the form of a comma 
+ * separated list.  Each element in the list is a single integer or a range
+ * of integers specified by a starting value and ending value separated by
+ * a colon.  i.e. 1,2,4:7 translates to a vector that contains the values
+ * 1,2,4,5,6,7. Note that ranges must be increasing
+ */
+extern vector<int> string_util::int_list_str_to_intVect(std::string &intListStr){
+  vector<int> intListVect;
+  intListStr_to_intVec(intListStr,intListVect);
+  return intListVect;
+}
+
+extern string string_util::int_to_str(const int num){
+  char temp[20];
+  sprintf(temp,"%d",num);
+  return string(temp);
+}
+
+extern string string_util::intVec_to_str(const vector<int> &vec){
+
+  string result("[");
+  for( vector<int>::const_iterator it=vec.begin() ; it!=vec.end() ; it++ ){
+    result+=int_to_str(*it);
+    if(it+1!=vec.end())
+      result+=",";
+  }
+  result+="]";
+
+  return result;
+}
+
+extern std::string string_util::erase(const std::string &in_str,const std::string &match_str){
+  string result=in_str;
+  string::size_type match_size=match_str.size();
+  string::size_type index=0;
+
+  while(true)
+    {
+      index=result.find(match_str,index);
+      if(index==string::npos)
+        {
+          break;
+        }
+      result.erase(index,match_size);
+    }
+
+  return result;
+}
+
+extern string::size_type string_util::count_occur(const string &str, const string &ch)
+{
+  string::size_type count=0;
+  string::size_type index=0;
+
+  // infinite loop to make sure that the entire string is parsed.
+  while(true)
+    {
+      index=str.find(ch,index+1);
+      if(index==string::npos)
+        {
+          break;
+        }
+      count++;
+    }
+  return count;
+}
+
+// these were previously in string_util_ext.cpp from test_collist and FRM2
+
+
+/*
+ * split a line of numeric entrys using whitespace, commas, semicolons, ... as delimiter 
+ */
+extern std::vector<std::string> string_util::split_values(const string &str){
+	std::vector<std::string> result;
+	typedef std::string::size_type string_size;
+
+	string_size i=0;
+
+	while(i<str.size()){
+
+		// skip seperators at end of last word
+		while(i<str.size() && (isspace(str[i]) || (ispunct(str[i]) && (str[i]!='.' && str[i]!='-' && str[i]!='+' && str[i]!='\'' && str[i]!='\"')) )) {
+			i++;
+		}
+		// find end of "word"
+		string_size j=i;
+		//std::cout << "str["<<i<<"]: " << str[i] << std::endl;  
+		if (str[i] == '\'') {
+			while(j<str.size()) {
+				j++;
+				if (str[j]=='\'') {
+					j++;
+					break;
+				}
+			}
+		}
+		else if (str[i] == '\"') {
+			while(j<str.size()) {
+				j++;
+				if (str[j]=='\"') {
+					j++;
+					break;
+				}
+			}
+		}
+		else {
+			while(j<str.size() && !isspace(str[j]) && !( ispunct(str[j]) && str[j]!='.' && str[j]!='-' && str[j]!='+') ){
+				j++;
+			}
+		}
+
+		if(i!=j){
+			result.push_back(str.substr(i,j-i));
+			i=j;
+		}
+	}
+	
+	/*std::cout << "STARTTTTTTTTTTTTTTTTTTTTTTT: " <<std::endl;
+	for (std::vector<std::string>::iterator itt=result.begin(); itt!=result.end(); itt++) {
+		std::cout << "resulting vector: " << *itt << std::endl;
+	}*/
+	return result;
+}
+
+/*
+ * split a line of numeric entrys using whitespace, commas, semicolons, ... as delimiter 
+ */
+extern std::vector<int> string_util::split_ints(const std::string &str){
+  std::vector<int> result;
+  typedef std::string::size_type string_size;
+
+  string_size i=0;
+  while(i<str.size()){
+    // skip seperators at end of last word
+    while(i<str.size() && (isspace(str[i]) || (ispunct(str[i]) && str[i]!='.' && str[i]!='-') )) {
+      i++;
+	 }
+
+    // find end of "word"
+    string_size j=i;
+    while(j<str.size() && !isspace(str[j]) && !(ispunct(str[j]) && str[j]!='.' && str[i]!='-') ){
+      j++;
+    }
+
+    if(i!=j){
+      result.push_back(string_util::str_to_int(str.substr(i,j-i)));
+      i=j;
+    }
+  }
+
+  return result;
+}
+/*
+ * split a line of numeric entrys using whitespace, commas, semicolons, ... as delimiter 
+ */
+extern std::vector<unsigned int> string_util::split_uints(const std::string &str){
+  std::vector<unsigned int> result;
+  typedef std::string::size_type string_size;
+
+  string_size i=0;
+  while(i<str.size()){
+    // skip seperators at end of last word
+    while(i<str.size() && (isspace(str[i]) || (ispunct(str[i]) && str[i]!='.') )) {
+      i++;
+	 }
+
+    // find end of "word"
+    string_size j=i;
+    while(j<str.size() && !isspace(str[j]) && !(ispunct(str[j]) && str[j]!='.') ){
+      j++;
+    }
+
+    if(i!=j){
+      result.push_back(string_util::str_to_int(str.substr(i,j-i)));
+      i=j;
+    }
+  }
+
+  return result;
+}
+
+
+/*
+ * split a string into doubles using whitespace as delimiter 
+ */
+extern std::vector<double> string_util::split_doubles(const string &str){
+  std::vector<double> result;
+  typedef std::string::size_type string_size;
+  std::string tempstr;
+  
+  string_size i=0;
+
+  while(i<str.size()){
+    // skip seperators at end of last word
+    while(i<str.size() && isspace(str[i]) )
+      i++;
+
+    // find end of "word"
+    string_size j=i;
+    while(j<str.size() && !isspace(str[j])){
+      j++;
+    }
+
+    if(i!=j){
+		 tempstr = str.substr(i,j-i);
+		 
+		while (isspace(tempstr[0])){
+			tempstr = tempstr.substr(1);
+		}
+		while (isspace(tempstr[tempstr.size()-1])){
+			tempstr = tempstr.substr(0, tempstr.size()-1);
+		}
+		 
+      result.push_back(string_util::str_to_float(tempstr));
+      i=j;
+    }
+  }
+
+  return result;
+}
+
+/*
+ * split a string up using colon as delimiter 
+ */
+extern std::vector<std::string> string_util::split_colons(const string &str){
+  std::vector<std::string> result;
+  typedef std::string::size_type string_size;
+
+  string_size i=0;
+  while(i<str.size()){
+    // skip seperators at end of last word
+    while(i<str.size() && (str[i]==',') )
+      i++;
+
+    // find end of "word"
+    string_size j=i;
+    while(j<str.size() && str[j]!=','){
+      j++;
+    }
+
+    if(i!=j){
+      result.push_back(str.substr(i,j-i));
+      i=j;
+    }
+  }
+
+  return result;
+}
+
+/*
+ * split a string up using whitespace as delimiter 
+ */
+extern std::vector<std::string> string_util::split_whitespace(const string &str){
+  std::vector<std::string> result;
+  typedef std::string::size_type string_size;
+
+  string_size i=0;
+  while(i<str.size()){
+    // skip seperators at end of last word
+    while(i<str.size() && isspace(str[i]) )
+      i++;
+
+    // find end of "word"
+    string_size j=i;
+    while(j<str.size() && !isspace(str[j])){
+      j++;
+    }
+
+    if(i!=j){
+      result.push_back(str.substr(i,j-i));
+      i=j;
+    }
+  }
+
+  return result;
+}
+
+/*
+ *  strip punctuation characters in front of and at end of strings  
+ */
+extern std::vector<std::string> string_util::strip_punct(std::vector<std::string> &strvec){
+	std::vector<std::string> result;
+	typedef std::string::size_type string_size;
+
+	for (std::vector<std::string>::iterator it = strvec.begin(); it!=strvec.end(); it++) {
+		string_size i=0;
+	   std::string str = *it;
+		// skip punctuation characters in front of word
+		while (ispunct(str[i])){
+			str = str.substr(1);
+		}
+		// skip punctuation characters at end of word
+		while (ispunct(str[str.size()-1])){
+			str = str.substr(0, str.size()-1);
+		}
+		
+		if ((str.size()>0) && (isalpha(str[0]) || isdigit(str[0]))) {
+			result.push_back(str);
+		}
+	}
+	return result;
+}
+
+/*
+ *  strip punctuation characters in front of at end of strings  
+ */
+extern bool string_util::contains (std::string &str, std::string substr) {
+   unsigned int loc = str.find(substr, 0 );
+   if( loc != string::npos )
+     return true;
+   else
+     return false;	
+}
+
+extern std::string string_util::lower_str(std::string str) {
+	for(unsigned int i=0; i<str.size(); i++) {
+		char c = (char)tolower((char)str[i]);
+		str[i] = c;
+	}
+	return str;
+}
diff --git a/applications/NXtranslate/string_util.h b/applications/NXtranslate/string_util.h
new file mode 100644
index 0000000..201ae51
--- /dev/null
+++ b/applications/NXtranslate/string_util.h
@@ -0,0 +1,110 @@
+#ifndef __STRING_UTIL_H_GUARD
+#define __STRING_UTIL_H_GUARD
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+namespace string_util{
+  extern bool is_comma(char);
+  extern std::vector<std::string> split(const std::string &);
+  /**
+   * Returns true if the first argument starts with the second.
+   */
+  extern bool   starts_with(const std::string &, const std::string &);
+  extern std::string trim(const std::string &);
+  extern long   str_to_int(const std::string &);
+  extern long long  str_to_int64(const std::string &);
+  extern unsigned long  str_to_uint(const std::string &);
+  extern unsigned long long  str_to_uint64(const std::string &);
+  extern double str_to_float(const std::string &);
+  extern std::vector<std::string> string_to_path(const std::string &);
+  extern std::string int_to_str(const int);
+  extern std::vector<int> str_to_intVec(std::string &);
+  extern void str_to_ucharArray(std::string &,unsigned char *, const unsigned int);
+  extern void str_to_shortArray(std::string &,short *, const unsigned int);
+  extern void str_to_intArray(std::string &,int *, const unsigned int);
+  extern void str_to_int64Array(std::string &,long long *, const unsigned int);
+  extern void str_to_longArray(std::string &,long *, const unsigned int);
+  extern void str_to_ushortArray(std::string &,unsigned short *, const unsigned int);
+  extern void str_to_uintArray(std::string &,unsigned int *, const unsigned int);
+  extern void str_to_uint64Array(std::string &,unsigned long long *, const unsigned int);
+  extern void str_to_ulongArray(std::string &,unsigned long *, const unsigned int);
+  extern void str_to_floatArray(std::string &,float *, const unsigned int);
+  extern void str_to_doubleArray(std::string &,double *, const unsigned int);
+  extern std::vector<int> int_list_str_to_intVect(std::string &);
+  extern std::string intVec_to_str(const std::vector<int> &);
+  extern std::string erase(const std::string &in_str, const std::string &match_str);
+/**
+ * Count the number of occurences of the character occuring in the string.
+ *
+ * \param str the string to search through
+ * \param ch the character to look for
+ *
+ * \return The number of occurences
+ */
+  extern std::string::size_type count_occur(const std::string &str, const std::string &ch);
+/**
+ * Split the string based on supplied character.
+ *
+ * \param source
+ * \param split
+ */
+  extern std::vector<std::string> split(const std::string &source,const std::string &split);
+
+/*
+ * This method takes a string as an argument and attempts to convert this 
+ * string into a vector of integers.  The string is in the form of a comma 
+ * separated list.  Each element in the list is a single integer or a range
+ * of integers specified by a starting value and ending value separated by
+ * a colon.  i.e. 1,2,4:7 translates to a vector that contains the values
+ * 1,2,4,5,6,7. Note that ranges must be increasing
+ */
+  template <class T>
+  extern void intListStr_to_intVec(const std::string &intList,
+                                                       std::vector<T> &intVec){
+    
+    using std::string;
+    typedef string::size_type string_size;
+    typedef std::vector<string> StrVec;
+    static const string COLON=":";
+
+    using string_util::split;
+    using string_util::trim;
+    using string_util::str_to_int;
+    using string_util::int_to_str;
+
+    StrVec strVecList = split( intList );
+    for( StrVec::const_iterator it=strVecList.begin() ; it!=strVecList.end() ; it++ ){
+      string_size colon_pos = it->find(COLON);
+      if( colon_pos == string::npos ){     // only one integer
+        intVec.push_back(str_to_int(trim(*it)));
+      }else{                               // determine range
+        // convert end points to integers
+        long lowInt  = str_to_int(trim(it->substr(0,colon_pos)));
+        long highInt = str_to_int(trim(it->substr(colon_pos+1)));
+
+        // error check
+        if ( highInt < lowInt )
+          throw std::runtime_error("intList: Ranges must be increasing: "
+                             +int_to_str(lowInt)+">"+int_to_str(highInt)+"\n");
+
+        // add to the result vector
+        for( long j = lowInt; j <= highInt; j++)
+          intVec.push_back(j);
+      }
+    }
+  }
+
+// these were presiously in string_util_ext.h from test_collist and FRM2
+
+	extern std::vector<std::string> split_values(const std::string &str);
+	extern std::vector<unsigned int> split_uints(const std::string &str);
+	extern std::vector<int> split_ints(const std::string &str);
+	extern std::vector<double> split_doubles(const std::string &str);
+	extern std::vector<std::string> split_whitespace(const std::string &);
+	extern std::vector<std::string> split_colons(const std::string &);
+	extern std::vector<std::string> strip_punct(std::vector<std::string> &strvec);
+	extern bool contains(std::string &str, std::string substr);
+	extern std::string lower_str(std::string str);
+};
+#endif
diff --git a/applications/NXtranslate/test_SNS_3_10_5_linux.dat b/applications/NXtranslate/test_SNS_3_10_5_linux.dat
new file mode 100644
index 0000000..36bfc9d
Binary files /dev/null and b/applications/NXtranslate/test_SNS_3_10_5_linux.dat differ
diff --git a/applications/NXtranslate/test_SNS_nexus.dat b/applications/NXtranslate/test_SNS_nexus.dat
new file mode 100644
index 0000000..3e5e64c
Binary files /dev/null and b/applications/NXtranslate/test_SNS_nexus.dat differ
diff --git a/applications/NXtranslate/test_SNS_nexus.xml b/applications/NXtranslate/test_SNS_nexus.xml
new file mode 100644
index 0000000..d7ffd5e
--- /dev/null
+++ b/applications/NXtranslate/test_SNS_nexus.xml
@@ -0,0 +1,5 @@
+<NXroot NXS:source="test_SNS_nexus3_10_5.dat" NXS:mime_type="application/x-SNS-histogram">
+ <entry type="NXentry">
+ <entry_1D NXS:location=" [3,10,5][3,10,5]#((({pixelY|0,1}OR{pixelID|1,2,3,4,5,6,7})))OR{pixelX|1,3,1}OR{Tbin|1,2}"/>
+</entry>
+</NXroot>
diff --git a/applications/NXtranslate/test_SNS_nexus3_10_5.dat b/applications/NXtranslate/test_SNS_nexus3_10_5.dat
new file mode 100644
index 0000000..d20dcda
Binary files /dev/null and b/applications/NXtranslate/test_SNS_nexus3_10_5.dat differ
diff --git a/applications/NXtranslate/test_SNS_nexus_3_10_5.dat b/applications/NXtranslate/test_SNS_nexus_3_10_5.dat
new file mode 100644
index 0000000..8d4c1e2
Binary files /dev/null and b/applications/NXtranslate/test_SNS_nexus_3_10_5.dat differ
diff --git a/applications/NXtranslate/test_SNS_nexus_3_10_5_mac.dat b/applications/NXtranslate/test_SNS_nexus_3_10_5_mac.dat
new file mode 100644
index 0000000..8d4c1e2
Binary files /dev/null and b/applications/NXtranslate/test_SNS_nexus_3_10_5_mac.dat differ
diff --git a/applications/NXtranslate/test_SNS_nexus_3_10_5_swap.dat b/applications/NXtranslate/test_SNS_nexus_3_10_5_swap.dat
new file mode 100644
index 0000000..7e171d8
Binary files /dev/null and b/applications/NXtranslate/test_SNS_nexus_3_10_5_swap.dat differ
diff --git a/applications/NXtranslate/test_binary.nxt b/applications/NXtranslate/test_binary.nxt
new file mode 100644
index 0000000..0b0762e
--- /dev/null
+++ b/applications/NXtranslate/test_binary.nxt
@@ -0,0 +1,5 @@
+<NXroot>
+  <entry type="NXentry" NXS:mime_type="binary" NXS:source="test_SNS_3_10_5_linux.dat">
+    <int32 NXS:location="[3,10,5][0,0,0][3,10,5]"/>
+  </entry>
+</NXroot>
diff --git a/applications/NXtranslate/test_dynamic.c b/applications/NXtranslate/test_dynamic.c
new file mode 100644
index 0000000..1ad15c4
--- /dev/null
+++ b/applications/NXtranslate/test_dynamic.c
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ * 
+ * test/example program for NXtranslate DynamicRetriever class
+ * implements functions required by dynamic_retriever.h
+ *
+ * build shared library with 
+ *
+ *                 gcc -shared -o test_dynamic.so test_dynamic.c
+ *
+ * and then use
+ *                 "dynamic/test_dynamic.so"
+ *
+ * as the NXtranslate NXS:mime_type to activate it.
+ *
+ * Freddie Akeroyd, CCLRC ISIS Facility <F.A.Akeroyd at rl.ac.uk>
+ *
+ */
+#include <string.h>
+#include "napi.h"
+
+// this is called when a DynamicRetriever instance is created
+void* nxtinit(const char* source)
+{
+    return strdup(source); // this will be passed back as "ref" argument to 
+                           // other functions. It can be anything e.g. a 
+                           // file pointer or handle
+}
+
+// this is called when a DynamicRetriever instance is destroyed
+int nxtcleanup(void* ref)
+{
+    free(ref);
+    return 0;
+}
+
+// retrieves data from location specified in arg
+void* nxtgetdata(void* ref, const char* arg, int* data_type, int* dims_array, 
+              int* ndims, int* free_data)
+{
+    char* result;
+    result = strdup(arg);
+    *free_data = 1; // we want NXtranslate to call freedata() on "result" for us
+    *ndims = 1;
+    dims_array[0] = strlen(result);
+    *data_type = NX_CHAR;
+    return result;
+}
+
+// free up any memory returned by a previous "getdata" when we have
+// specified the "free_data" option
+int nxtfreedata(void* ref, void* arg)
+{
+    free(arg);
+    return 0;
+}
+
diff --git a/applications/NXtranslate/test_dynamic.xml b/applications/NXtranslate/test_dynamic.xml
new file mode 100644
index 0000000..3cbdf67
--- /dev/null
+++ b/applications/NXtranslate/test_dynamic.xml
@@ -0,0 +1,15 @@
+<!-- 
+     $Id$
+     Example of calling dynamic retriever "test_dynamic.so"
+-->
+<NXroot>
+<entry1 type="NXentry" NXS:source="source" NXS:mime_type="dynamic/test_dynamic.so">
+<title  NXS:location="header.runTitle" />
+<start_time NXS:location="header.startDateTime" />
+<end_time NXS:location="header.endDateTime" />
+<!-- NXuser  -->
+<userInfo type="NXuser">
+<name  NXS:location="header.userName" />
+</userInfo>
+</entry1>
+</NXroot>
diff --git a/applications/NXtranslate/test_ipns.xml b/applications/NXtranslate/test_ipns.xml
new file mode 100644
index 0000000..a0fde50
--- /dev/null
+++ b/applications/NXtranslate/test_ipns.xml
@@ -0,0 +1,31 @@
+<NXroot>
+<entry1 type="NXentry" NXS:source="fileName" NXS:mime_type="application/x-IPNS">
+<title  NXS:location="header.runTitle" />
+<start_time NXS:location="header.startDateTime" />
+<end_time NXS:location="header.endDateTime" />
+<!-- NXuser  -->
+<userInfo type="NXuser">
+<name  NXS:location="header.userName" />
+</userInfo>
+<!-- NXdetector  -->
+<bank1 type="NXdetector">
+<detector_number type="NX_INT32[7]" axis="NX_INT32:2" > 19 20 21 22 23 24 25 </detector_number>
+<time_of_flight NXS:location="time.ids[ 19 : 25]" axis="NX_INT32:1" />
+</bank1>
+<!-- NXdata  -->
+<data1 type="NXdata">
+<data NXS:location="data.ids[ 19 : 25]" signal="NX_INT32:1" long_name="Counts"/>
+<errors NXS:location="error.ids[ 19 : 25]"/>
+<NAPIlink target="/entry1/bank1/time_of_flight"/>
+<NAPIlink target="/entry1/bank1/detector_number"/>
+</data1>
+<!-- NXmonitor  -->
+<monitor1 type="NXmonitor">
+<data NXS:location="data.ids[ 1]" signal="NX_INT32:1" long_name="Counts"/>
+<errors NXS:location="error.ids[ 1 ]"/>
+<time_of_flight NXS:location="time.ids[ 1]" axis="NX_INT32:1" />
+</monitor1>
+
+</entry1>
+
+</NXroot>
diff --git a/applications/NXtranslate/test_loopy.nxt b/applications/NXtranslate/test_loopy.nxt
new file mode 100644
index 0000000..fadf292
--- /dev/null
+++ b/applications/NXtranslate/test_loopy.nxt
@@ -0,0 +1,5 @@
+<NXroot>
+  <entry type="NXentry" NXS:mime_type="loopy" NXS:source="bob">
+    <int32 NXS:location="INT32:0,1,10"/>
+  </entry>
+</NXroot>
diff --git a/applications/NXtranslate/test_nexus.xml b/applications/NXtranslate/test_nexus.xml
new file mode 100644
index 0000000..358ebfa
--- /dev/null
+++ b/applications/NXtranslate/test_nexus.xml
@@ -0,0 +1,15 @@
+<NXroot NXS:source="test_simple.nxs" NXS:mime_type="application/x-NeXus">
+  <entry_1D NXS:location="/entry1"/>
+  <entry_2D type="NXentry">
+    <note NXS:location="/entry1/note">
+       <description type="NX_CHAR">The functional form of the data
+             </description>
+    </note>
+    <parabola_2D type="NXdata">
+      <x axis="NX_INT16:2" NXS:location="/entry2/parabola_2D/x"/>
+      <y axis="NX_INT16:1" NXS:location="/entry2/parabola_2D/y"/>
+      <f_x_y type="NX_FLOAT64[3,4]" axes=""
+            NXS:location="/entry2/parabola_2D/f_x_y"/>
+    </parabola_2D>
+  </entry_2D>
+</NXroot>
diff --git a/applications/NXtranslate/test_nexus_macro.xml b/applications/NXtranslate/test_nexus_macro.xml
new file mode 100644
index 0000000..6843849
--- /dev/null
+++ b/applications/NXtranslate/test_nexus_macro.xml
@@ -0,0 +1,15 @@
+<NXroot NXS:source="FILE" NXS:mime_type="application/x-NeXus">
+  <entry_1D NXS:location="/entry1"/>
+  <entry_2D type="NXentry">
+    <note NXS:location="/entry1/note">
+       <description type="NX_CHAR">The functional form of the data
+             </description>
+    </note>
+    <parabola_2D type="NXdata">
+      <x axis="NX_INT16:2" NXS:location="/entry2/parabola_2D/x"/>
+      <y axis="NX_INT16:1" NXS:location="/entry2/parabola_2D/y"/>
+      <f_x_y type="NX_FLOAT64[3,4]" axes=""
+            NXS:location="/entry2/parabola_2D/f_x_y"/>
+    </parabola_2D>
+  </entry_2D>
+</NXroot>
diff --git a/applications/NXtranslate/test_opengenie.xml b/applications/NXtranslate/test_opengenie.xml
new file mode 100644
index 0000000..f7e3c71
--- /dev/null
+++ b/applications/NXtranslate/test_opengenie.xml
@@ -0,0 +1,113 @@
+<!-- 
+     $Id$
+     Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+     Example of calling dynamic OpenGENIE retriever "libnxgenie.so"
+     Note that you need to escape double quote (") characters
+     using XML escape sequences e.g.
+
+        GET("TITL") needs to be written as  GET("TITL")
+-->
+<NXroot>
+<entry1 type="NXentry" NXS:source="INPUT_FILE" NXS:mime_type="dynamic/libnxgenie.so">
+<title  NXS:location="GET("TITL")" />
+<definition url="http://www.nexus.anl.gov/xml/NXTOFRAW.xml" version="1.0">NeXus time of flight raw</definition>
+<definition_local url="http://www.isis.rl.ac.uk/xml/IXTOFRAW.xml" version="1.0">ISIS time of flight raw</definition_local>
+<good_frames NXS:location="(GET("IRPB"))[10]" />
+<raw_frames NXS:location="(GET("IRPB"))[11]" />
+<run_number NXS:location="GET("RUN")" />
+<program_name type="NX_CHAR" version="1.0">ICP1SEP89</program_name>
+<run_cycle type="NX_CHAR">05/3</run_cycle>
+<experiment_identifier NXS:location=""RB"+AS_STRING((GET("IRPB"))[22])" />
+<start_time NXS:location="GETDAT("START")" />
+<end_time NXS:location="GETDAT("END")" />
+<duration NXS:location="(GET("IRPB"))[13] * 1.0" units="second"/> <!-- or [1] -->
+<collection_time NXS:location="(GET("IRPB"))[13] * 1.0" units="second"/> <!-- or [1] -->
+<proton_charge NXS:location="(GET("RRPB"))[8]" units="uamp.hour" />
+<!-- raw_uamph NXS:location="(GET("RRPB"))[9]" -->
+<user type="NXuser">
+   <name NXS:location="(GET("USER"))[1]" />
+   <role>Principle Investigator</role>
+   <facility_user_id>00000</facility_user_id>
+</user>
+<sample type="NXsample">
+    <name>unknown</name>
+    <identifier>unknown</identifier>
+    <nature>unknown</nature>
+</sample>
+<instrument type="NXinstrument">
+   <!--name NXS:location="GET("NAME")" short_name="SHORT_NAME" /-->
+   <name NXS:location="GET("NAME")" short_name="HRP" />
+   <beamline>R55</beamline>
+   <bank1 type="NXdetector">
+     <stored>general</stored>
+     <data units="counts" axes="[detector_number,time_of_flight]" signal="NX_INT32:1" long_name="Detector Counts" NXS:location="GETDAT("CNT1")" />
+     <detector_number NXS:location="GETDAT:GANG("UDET")" />
+     <detector_number_unganged NXS:location="GETDAT("UDET")" />
+     <polar_angle units="degree" long_name="Polar angle /degrees" NXS:location="GETDAT:GANG("TTHE")" />
+     <polar_angle_unganged units="degree" long_name="Polar angle (unganged) /degrees" NXS:location="GETDAT("TTHE")" />
+     <azimuthal_angle units="degree" long_name="Azimuthal angle /degrees" NXS:location="GETDAT:GANG("UT01")" />
+     <azimuthal_angle_unganged units="degree" long_name="Azimuthal angle (unganged) /degrees" NXS:location="GETDAT("UT01")" />
+     <distance units="metre" NXS:location="GETDAT:GANG("LEN2")" />
+     <distance_unganged units="metre" NXS:location="GETDAT("LEN2")" />
+     <time_of_flight units="micro.second" long_name="Time of flight /us" NXS:location="GET("TIM1")" />
+     <time_of_flight_raw units="clock_pulse" long_name="Time of flight (raw) /us" frequency="NX_INT32:32000000" NXS:location="GET("TCB1")" />
+     <group_index units="degree" NXS:location="GETDAT("GROUP_INDEX")" />
+     <gang_count units="degree" NXS:location="GETDAT("GANG_COUNT")" />
+     <gang_index units="degree" NXS:location="GETDAT("GANG_INDEX")" />
+   </bank1>
+   <moderator type="NXmoderator">
+     <type>unknown</type>
+     <temperature units="kelvin" type="NX_FLOAT32">0</temperature>
+     <distance NXS:location="-(GET("RVPB"))[23]" units="metre" />
+   </moderator>
+   <source type="NXsource">
+     <name>ISIS</name>
+     <type>Pulsed Neutron Source</type>
+     <probe>neutrons</probe>
+     <frequency units="hertz" type="NX_INT32">50</frequency>
+     <period units="micro.second" type="NX_INT32">20000</period>
+   </source>
+   <detector_groups type="NXdetector_group">
+     <group_names>bank1</group_names>
+     <group_index type="NX_INT32[1]">1</group_index>
+     <group_parent type="NX_INT32[1]">0</group_parent>
+     <group_type>bank</group_type>
+   </detector_groups>
+</instrument>
+<bank1 type="NXdata">
+<NAPIlink target="/entry1/instrument/bank1/data" />
+<NAPIlink target="/entry1/instrument/bank1/time_of_flight" />
+<NAPIlink target="/entry1/instrument/bank1/detector_number" />
+</bank1>
+<monitor1 type="NXmonitor">
+  <range units="micro.second"></range>
+  <integral type="NX_FLOAT32"></integral>
+  <data units="counts" signal="NX_INT32:1" long_name="Monitor 1 Counts" axes="[time_of_flight]" NXS:location="GETDAT("MON",1)" />
+  <NAPIlink target="/entry1/instrument/bank1/time_of_flight" />
+  <monitor_number type="NX_INT32">1</monitor_number>
+  <detector_number NXS:location="GETDAT:GANG("MON_DET",1)" />
+  <detector_number_unganged NXS:location="GETDAT("MON_DET",1)" />
+  <distance units="metre" NXS:location="GETDAT:GANG("MON_DIST",1)" />
+</monitor1>
+<monitor2 type="NXmonitor">
+  <range units="micro.second"></range>
+  <integral type="NX_FLOAT32"></integral>
+  <data units="counts" signal="NX_INT32:1" long_name="Monitor 2 Counts" axes="[time_of_flight]" NXS:location="GETDAT("MON",2)" />
+  <NAPIlink target="/entry1/instrument/bank1/time_of_flight" />
+  <monitor_number type="NX_INT32">2</monitor_number>
+  <detector_number NXS:location="GETDAT:GANG("MON_DET",2)" />
+  <detector_number_unganged NXS:location="GETDAT("MON_DET",2)" />
+  <distance units="metre" NXS:location="GETDAT:GANG("MON_DIST",2)" />
+</monitor2>
+<monitor3 type="NXmonitor">
+  <range units="micro.second"></range>
+  <integral type="NX_FLOAT32"></integral>
+  <data units="counts" signal="NX_INT32:1" long_name="Monitor 3 Counts" axes="[time_of_flight]" NXS:location="GETDAT("MON",3)" />
+  <NAPIlink target="/entry1/instrument/bank1/time_of_flight" />
+  <monitor_number type="NX_INT32">3</monitor_number>
+  <detector_number NXS:location="GETDAT:GANG("MON_DET",3)" />
+  <detector_number_unganged NXS:location="GETDAT("MON_DET",3)" />
+  <distance units="metre" NXS:location="GETDAT:GANG("MON_DIST",3)" />
+</monitor3>
+</entry1>
+</NXroot>
diff --git a/applications/NXtranslate/test_simple.xml b/applications/NXtranslate/test_simple.xml
new file mode 100644
index 0000000..e0a318d
--- /dev/null
+++ b/applications/NXtranslate/test_simple.xml
@@ -0,0 +1,45 @@
+<NXroot>
+  <entry1 type="NXentry">
+    <note type="NXnote">
+      <author type="NX_CHAR">George User</author>
+      <type type="NX_CHAR">text/plain</type>
+      <data type="NX_CHAR">The data is a simple parabola, f(x)=x^2</data>
+    </note>
+    <parabola_1D type="NXdata">
+      <x type="NX_INT8[11]" axis="NX_INT16:1" units="number">
+                 0  1  2  3  4  5
+                 6  7  8  9  10
+      </x>
+      <f_x type="NX_INT16[11]" signal="NX_INT16:1" units="number">
+                 0    1    4    9   16   25
+                36   49   64   81  100
+      </f_x>
+    </parabola_1D>
+  </entry1>
+  <entry2 type="NXentry">
+    <note type="NXnote">
+      <author type="NX_CHAR">George User</author>
+      <type type="NX_CHAR">text/plain</type>
+      <data type="NX_CHAR">The data is a two dimensional parabola, f(x,y)=x^2+y^2</data>
+    </note>
+    <parabola_2D type="NXdata">
+      <x type="NX_FLOAT32[4]" axis="NX_INT16:1" units="number">
+               1.0  4.7  2.3  1.6
+      </x>
+      <y type="NX_FLOAT32[3]" axis="NX_INT16:2" units="number">
+               3.3  6.2  9.2
+      </y>
+      <f_x_y type="NX_FLOAT64[4,3]" signal="NX_INT16:1" axes="x,y"
+units="number">
+             11.89  32.98  16.18
+             13.45  39.44  60.53
+             43.73  41.00  85.64
+            106.73  89.93  87.20
+      </f_x_y>
+    </parabola_2D>
+  </entry2>
+  <copies type="NXentry">
+    <NAPIlink target="/entry2/parabola_2D/x"/>
+    <NAPIlink target="/entry2/parabola_2D"/>
+  </copies>
+</NXroot>
diff --git a/applications/NXtranslate/test_text_collist.xml b/applications/NXtranslate/test_text_collist.xml
new file mode 100644
index 0000000..b4f90cc
--- /dev/null
+++ b/applications/NXtranslate/test_text_collist.xml
@@ -0,0 +1,59 @@
+<NXroot creator="FRM2">
+	<entry type="NXentry" NXS:source="text_collist/mira.txt" NXS:mime_type="text/collist"> 
+		<start_time NXS:location="dict('created at'){ISO8601}"/>
+		
+		<local_contact type="NXuser">
+			<name type="NX_CHAR" NXS:location="dict('responsable'){NX_CHAR}"/>
+			<role type="NX_CHAR" NXS:location="dict('user'){NX_CHAR}"/>
+			<address type="NX_CHAR"/>
+			<telephone_number NXS:location="dict('phone'){NX_CHAR}"/>
+			<fax_number NXS:location="dict('fax'){NX_CHAR}"/>
+			<email type="NX_CHAR">robert.georgii at frm2.tum.de</email>
+		</local_contact>
+		
+		<sample type="NXsample"> 
+			<rotation_angle NXS:location="column('om'){NX_FLOAT64}"/> 
+		</sample> 
+		
+		<instrument type="NXinstrument"> 
+			<name NXS:location="dict('instrument'){NX_CHAR}"/>
+			<monochromator type="NXcrystal"> 
+				<wavelength type="NX_FLOAT64" units="Angstroms">2.0</wavelength> 
+			</monochromator> 
+			
+			<detector type="NXdetector"> 
+				<distance units="mm" type="NX_FLOAT64">15</distance> 
+				<azimuthal_angle units="degrees" type="NX_FLOAT64">0</azimuthal_angle> 
+				<polar_angle units="degrees" NXS:location="column('phi'){NX_FLOAT64}"/> 
+				<counts signal="1" axes="polar_angle" type="NX_INT32" NXS:location="column('mon2'){NX_INT32}"/>
+			</detector> 
+
+			<process_data type="NXprocess">
+				<scan_data type="NXnote">
+					<type type="NX_CHAR">text/plain</type>
+					<description type="NX_CHAR">provides some additional info for scan</description>
+					<data type="NX_CHAR" NXS:location="dict('filename'){NX_CHAR}"/>
+				</scan_data>
+			</process_data>
+		</instrument>
+		
+		<monitor type="NXmonitor"> 
+			<mode type="NX_CHAR">monitor</mode> 
+			<data units="counts" type="NX_INT32" NXS:location="column('mon1'){NX_INT32}"/> 
+		</monitor>	
+		
+		<timer type="NXmonitor"> 
+			<mode type="NX_CHAR">timer</mode> 
+			<timer_data units="seconds" NXS:location="column('time'){NX_INT32}"/> 
+		</timer> 
+		
+		<data type="NXdata"> 
+			<NAPIlink target="entry/sample/rotation_angle"/>  
+			<NAPIlink target="entry/instrument/detector/polar_angle"/>  
+			<NAPIlink target="entry/instrument/detector/counts"/>
+			<NAPIlink target="entry/timer/timer_data"/>  
+			<NAPIlink target="entry/monitor/data"/> 
+		</data> 
+	</entry>
+</NXroot>
+
diff --git a/applications/NXtranslate/test_text_plain.xml b/applications/NXtranslate/test_text_plain.xml
new file mode 100644
index 0000000..6b1e504
--- /dev/null
+++ b/applications/NXtranslate/test_text_plain.xml
@@ -0,0 +1,6 @@
+<NXroot>
+  <entry1 type="NXentry" NXS:source="test_simple.xml" NXS:mime_type="text/plain">
+    <text1 NXS:location="1"/>
+    <text2 NXS:location="0"/>
+  </entry1>
+</NXroot>
diff --git a/applications/NXtranslate/test_text_xml.xml b/applications/NXtranslate/test_text_xml.xml
new file mode 100644
index 0000000..b98a9ea
--- /dev/null
+++ b/applications/NXtranslate/test_text_xml.xml
@@ -0,0 +1,7 @@
+<NXroot>
+  <entry1 type="NXentry" NXS:source="test_simple.xml" NXS:mime_type="text/xml">
+    <text1 NXS:location="/NXroot/entry1/note/author"/>
+    <text2 NXS:location="INT8[11]:/NXroot/entry1/parabola_1D/x"/>
+    <text3 NXS:location="/NXroot/entry1/parabola_1D/x#units"/>
+  </entry1>
+</NXroot>
diff --git a/applications/NXtranslate/text_collist/CMakeLists.txt b/applications/NXtranslate/text_collist/CMakeLists.txt
new file mode 100644
index 0000000..b3db209
--- /dev/null
+++ b/applications/NXtranslate/text_collist/CMakeLists.txt
@@ -0,0 +1,33 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (TextCollist STATIC collist_retriever.cpp collist_retriever.h)
+
+
diff --git a/applications/NXtranslate/text_collist/Makefile.am b/applications/NXtranslate/text_collist/Makefile.am
new file mode 100644
index 0000000..4094795
--- /dev/null
+++ b/applications/NXtranslate/text_collist/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libTextCollist.la
+
+libTextCollist_la_SOURCES = \
+	collist_retriever.cpp collist_retriever.h
+
+EXTRA_DIST = mira.txt
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/text_collist/collist_retriever.cpp b/applications/NXtranslate/text_collist/collist_retriever.cpp
new file mode 100644
index 0000000..28517d3
--- /dev/null
+++ b/applications/NXtranslate/text_collist/collist_retriever.cpp
@@ -0,0 +1,735 @@
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <string>
+#include <cstring>
+#include <vector>
+#include <cctype>
+#include "collist_retriever.h"
+#include "../node.h"
+#include "../nexus_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+using std::isspace;
+using std::isdigit;
+using std::isalpha;
+
+class NXunits {
+	public:
+	static const std::string milliseconds;	
+	static const std::string seconds;		 
+	static const std::string degrees;	
+	static const std::string counts;	
+	// to be completed later
+};
+
+static const int BUFFER_SIZE=256;
+
+const std::string NXunits::milliseconds = "milliseconds";
+const std::string NXunits::seconds = "seconds";
+const std::string NXunits::degrees = "degrees";
+const std::string NXunits::counts = "counts";
+
+
+const std::string TextCollistRetriever::MIME_TYPE = "text/collist";
+const std::string TextCollistRetriever::COLUMN_TAG = "column";
+const std::string TextCollistRetriever::DICT_TAG = "dict";
+const std::string TextCollistRetriever::RANGE_OPEN_BRACKET="[";
+const std::string TextCollistRetriever::RANGE_CLOSE_BRACKET="]";
+const std::string TextCollistRetriever::RANGE_SEPARATOR=":";
+const std::string TextCollistRetriever::METHOD_OPEN_BRACKET="(";
+const std::string TextCollistRetriever::METHOD_CLOSE_BRACKET=")";
+const std::string TextCollistRetriever::TYPE_OPEN_BRACKET="{";
+const std::string TextCollistRetriever::TYPE_CLOSE_BRACKET="}";
+
+
+
+static unsigned int convert_type(std::string nxtype) {
+	if (nxtype =="NX_CHAR") {
+		return NX_CHAR;
+	}
+	else if (nxtype =="NX_BOOLEAN") {
+		return NX_UINT8;
+	}
+	else if (nxtype =="NX_INT8") {
+		return NX_INT8;
+	}
+	else if (nxtype =="NX_UINT8") {
+		return NX_UINT8;
+	}
+	else if (nxtype =="NX_INT16") {
+		return NX_INT16;
+	}
+	else if (nxtype =="NX_UINT16") {
+		return NX_UINT16;
+	}
+	else if (nxtype =="NX_INT32") {
+		return NX_INT32;
+	}
+	else if (nxtype =="NX_UINT32") {
+		return NX_UINT32;
+	}
+	else if (nxtype =="NX_FLOAT32") {
+		return NX_FLOAT32;
+	}
+	else if (nxtype =="NX_FLOAT32") {
+		return NX_FLOAT32;
+	}
+	else if (nxtype =="ISO8601") {
+		return NX_CHAR;
+	}
+	return NX_FLOAT64;
+}
+
+static void reset_file(ifstream &file){
+	file.clear();
+	file.seekg(0,std::ios::beg);
+	file.clear();
+}
+
+static string read_line(ifstream &file){
+  static char buffer[BUFFER_SIZE];
+  file.get(buffer,BUFFER_SIZE);
+  file.get();
+  return string(buffer);
+}
+
+static void skip_to_line(ifstream &file,int &cur_line, int new_line){
+   file.seekg(0,std::ios::beg);
+  if(new_line==cur_line){ // skip out early if possible
+    return;
+  }else if(new_line<cur_line){  // go to the beginning if necessary
+    file.seekg(0,std::ios::beg);
+    cur_line=0;
+  }
+
+  // scan down to the right place
+  while( (file.good()) && (cur_line<new_line) ){
+    string text=read_line(file);
+    //cout << "LINE" << cur_line << "[" << file.tellg() << "]:" << text << endl;
+    cur_line++;
+  }
+
+  if(!(file.good()))
+    throw invalid_argument("Could not reach line "
+                           +string_util::int_to_str(new_line));
+}
+
+
+std::string TextCollistRetriever::parse_method(std::string location){
+	unsigned int pos = 0;
+	static std::string sub_str;
+	
+	pos = location.find_first_of(TextCollistRetriever::METHOD_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(0, pos);
+		return sub_str;			
+	}
+	else {
+		pos = location.find_first_of(TextCollistRetriever::RANGE_OPEN_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = location.substr(0, pos);
+			return sub_str;			
+		}
+		else {
+			pos = location.find_first_of(TextCollistRetriever::TYPE_OPEN_BRACKET);
+			if (pos != std::string::npos) {
+				sub_str = location.substr(0, pos);
+				return sub_str;			
+			}
+		}
+	}
+	return location;
+}
+
+
+std::string TextCollistRetriever::parse_type(std::string location){
+	unsigned int pos = 0;
+	static std::string sub_str;
+	
+	pos = location.find_last_of(TextCollistRetriever::TYPE_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(pos);
+		sub_str = sub_str.substr(1);
+		pos = sub_str.find_first_of(TextCollistRetriever::TYPE_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			return sub_str;			
+		}
+	}
+	return "";
+}
+
+std::string TextCollistRetriever::parse_arg(std::string location){
+	// check if column
+	unsigned int start_pos = 0;
+	unsigned int end_pos = 0;
+	static std::string sub_str;
+	
+	if (location.find_first_of(TextCollistRetriever::COLUMN_TAG) != std::string::npos) {
+		start_pos = location.find_first_of(TextCollistRetriever::METHOD_OPEN_BRACKET, location.find_first_of(TextCollistRetriever::COLUMN_TAG));
+		if (start_pos != std::string::npos) {
+			sub_str = location.substr(start_pos);
+			sub_str = sub_str.substr(1);
+			sub_str = sub_str.substr(0, sub_str.size()-1);
+
+			// TODO: check if range brackets are to be extracted
+			// no need, they get cut automatically
+			
+			end_pos = sub_str.find_first_of(TextCollistRetriever::METHOD_CLOSE_BRACKET);
+			if (end_pos != std::string::npos) {
+				sub_str = sub_str.substr(0, end_pos);
+			}
+
+			// check if quotes have to be removed 
+			if (sub_str[0]=='\"' || sub_str[0] == '\'') {
+				sub_str = sub_str.substr(1);
+				sub_str = sub_str.substr(0, sub_str.size()-1);
+			}
+			return sub_str;
+		}
+	}
+	return "";
+}
+
+void TextCollistRetriever::parse_range(std::string location, int &x, int &y){
+	unsigned int pos = 0;
+	static std::string sub_str;
+	
+	pos = location.find_last_of(TextCollistRetriever::RANGE_OPEN_BRACKET);
+	if (pos != std::string::npos) {
+		sub_str = location.substr(pos);
+		pos = sub_str.find_first_of(TextCollistRetriever::RANGE_CLOSE_BRACKET);
+		if (pos != std::string::npos) {
+			sub_str = sub_str.substr(0,pos);
+			
+			pos = sub_str.find_first_of(TextCollistRetriever::RANGE_SEPARATOR);
+			if (pos != std::string::npos) {
+				x = string_util::str_to_int(sub_str.substr(0,pos));
+				y = string_util::str_to_int(sub_str.substr(pos));
+				return;
+			}
+			else {
+				// if no range separator is found -> go specified position to end of column
+				x = string_util::str_to_int(sub_str);
+				y = -1;
+				return;
+			}
+		}
+	}
+	x = -1;
+	y = -1;
+}
+
+bool TextCollistRetriever::isdata(std::string line) {
+	unsigned int i=0;
+	int digit_count = 0;
+	int alpha_count = 0;
+	int space_count = 0;
+	
+	while(i<line.size()){
+		if (isdigit(line[i])) {
+			digit_count++;
+		}
+		else if (isalpha(line[i])) {
+			alpha_count++;
+		}
+		else if (isspace(line[i])) {
+			space_count++;
+		}
+		i++;
+	}
+	// if alpha count is greater than 75 percent -> assume its a data row
+
+//cout << "percent: " << line.size()-space_count << " " << digit_count <<" " <<digit_count*100/(line.size()-space_count)<<endl;
+
+	if (digit_count*100/(line.size()-space_count) > 75) {
+		return true;
+	}
+	return false;
+}
+
+bool TextCollistRetriever::isunit(std::string line) {
+	unsigned int unit_count = 0;
+	std::vector<std::string> strings = string_util::split_whitespace(line);
+	strings = string_util::strip_punct(strings);
+	
+	for (std::vector<std::string>::iterator its=strings.begin(); its!=strings.end(); its++) {
+		std::string str_word = *its;
+		for (std::map<std::string, std::string>::iterator it = unit_strings.begin(); it != unit_strings.end(); it++) {
+			std::string str_unit= it->first;
+			if (str_word == str_unit) {
+				unit_count++;
+				break;
+			}
+		}
+	}
+	//std::cout << " unit_count: " << unit_count << std::endl;
+	if (unit_count > 1) {
+		return true;
+	}
+	return false;
+}
+
+
+void TextCollistRetriever::extract_headers(std::string line) {
+	headers = string_util::split_whitespace(line); 
+	headers = string_util::strip_punct(headers);
+}
+
+void TextCollistRetriever::extract_units(std::string line) {
+	units = string_util::split_whitespace(line);
+	units = string_util::strip_punct(units);
+}
+
+std::string TextCollistRetriever::extract_dictentry(std::ifstream &file, std::string arg, unsigned int nxtype) {
+	int i=0, j=0;
+	unsigned int k=0, l=0, u1=0, u2=0;
+	unsigned int pos=0, pos2=0;
+	std::string str="";
+	std::string ustr="";
+
+	reset_file(infile);
+	while (i<data_section) {
+		std::string line = read_line(infile);
+		//std::cout << "current line: " << line << std::endl;	
+
+		while (isspace(line[j])){
+			j++;
+		}
+		line = line.substr(j, line.size());
+		pos = line.find(arg);
+		if (pos != std::string::npos && pos<2) {
+			pos2 = line.find(":", pos);
+			if (pos2 != std::string::npos) {
+				str = line.substr(pos2+1);
+				
+				while(k<str.size() && (ispunct(str[k]) || isspace(str[k]))) {
+					k++;
+				}
+
+				l=str.size();
+				while(l>=k && (ispunct(str[l-1]) || isspace(str[l-1]))){
+					l--;
+				}
+				if (nxtype != NX_CHAR && l>=k) {
+					//scan for unit
+					if (isalpha((str[l-1]))) {
+						u2=l-1;
+						while(l>=k && (!isspace(str[l-1]))){
+							l--;
+						}
+						u1=l-1;
+						if (u1<u2) {
+							ustr = std::string("units:")+str.substr(u1+1,u2)+std::string(";value:");
+						}
+						if (l>=k) {
+							l--;
+						}
+					}
+				}
+				if(l!=k){
+					std::string word = str.substr(k,l-k);
+					if (word.size()>=2 && isalnum(word[0])) {
+						str=word;
+					}
+				}
+				break;
+			}
+		}
+		i++;
+	}
+	return ustr+str;
+}
+
+std::vector<double> TextCollistRetriever::extract_column(ifstream &file, std::string col_name, int from, int to)
+{
+	int count = 0;
+	int index = 0;
+	std::vector<double> values;
+	reset_file(infile);
+	int cur_line=0;
+	skip_to_line(infile, cur_line, data_section+((from<0)?0:from)); 
+	
+//cout << endl << "counting headers: " << *(headers.begin()) << endl;	
+
+	std::vector<std::string>::iterator it = headers.begin();
+	while (*it != col_name && it != headers.end()) {
+		it++;
+		index++;
+	}
+
+	std::string line = read_line(infile);
+
+	if (it== headers.end()) {
+		std::cout << "no column '"<< col_name << "' found in file ... filling with 0s" << std::endl;
+		while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+			if (!isdata(line)) {
+				break;
+			}
+			values.push_back(0);
+			count++;
+			line = read_line(infile);
+		}
+		return values;
+	}
+
+//cout << endl << "pushing data: " << to << " "<< count<<" "<< infile.good()<< endl;	
+	while ((infile.good()) && ((to>=0 && to<count) || (to<0))) {			
+		if (!isdata(line)) {
+			break;
+		}
+		try {
+			std::vector<std::string> string_values = string_util::split_values(line);
+	//cout << endl << "pushing data: " << (string_util::str_to_float(string_values.at(index))) << endl;	
+			double dbl_val = string_util::str_to_float(string_values.at(index));
+			values.push_back(dbl_val);
+		}
+		catch(...) {
+			cout << "exception in transforming column values " << endl;	
+					
+		}
+		count++;
+		line = read_line(infile);
+	}
+	return values;
+}
+
+
+int TextCollistRetriever::number_of_columns(std::string header_line) {
+	std::vector<std::string> entrys = string_util::split_whitespace(header_line);
+	entrys = string_util::strip_punct(entrys);
+	return entrys.size();
+}
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+TextCollistRetriever::TextCollistRetriever(const string &str): source(str),current_line(0){
+  //cout << "TextCollistRetriever(" << source << ")" << endl; // REMOVE
+
+  // open the file
+  infile.open(source.c_str());
+
+  // check that open was successful
+  if(! infile.is_open()) {
+    throw invalid_argument("Could not open file: "+source);
+  }
+
+	unit_strings["seconds"] = NXunits::seconds;
+	unit_strings["second"] 	= NXunits::seconds;
+	unit_strings["secs"] 	= NXunits::seconds;
+	unit_strings["sec"] 		= NXunits::seconds;
+	
+	unit_strings["deg"] 		= NXunits::degrees;
+	unit_strings["degs"] 	= NXunits::degrees;
+	unit_strings["degree"] 	= NXunits::degrees;
+	unit_strings["degrees"] = NXunits::degrees;
+	
+	unit_strings["cts"] 		= NXunits::counts;
+	unit_strings["counts"] 	= NXunits::counts;
+	unit_strings["count"] 	= NXunits::counts;
+	unit_strings["cnt"] 		= NXunits::counts;
+
+	this->number_of_cols = 0;
+	this->number_of_entrys = 0;
+	
+	int cur_line = 0;
+	std::string line = read_line(infile);
+	std::string prev_line="";
+	std::string prev_prev_line="";
+	
+ 	//std::cout << "current line: " << line << std::endl;
+	while (infile.good() && !isdata(line)) {
+		prev_prev_line = prev_line;
+		prev_line=line;
+		line = read_line(infile);
+		//std::cout << "current line: " << line << std::endl;
+		cur_line++;
+	}
+	//std::cout << "data line: " << line << std::endl;
+	header_section = cur_line-1;
+	// this is dangerous as it assumes the unit line to be present and always under the header line
+	// alternative: check if in header line is some occurence of unit string -> treat is as unit line
+	if (isunit(prev_line)) {
+//std::cout << "extracting units from: " << prev_line << std::endl;
+		extract_units(prev_line);
+//std::cout << "extracting headers from: " << prev_prev_line << std::endl;
+		extract_headers(prev_prev_line);
+	}
+	else {
+		extract_headers(prev_line);
+	}
+	
+	data_section = cur_line;
+	
+	/*int num_of_cols, num_of_cols2, num_of_cols3;
+	//std::cout << "compare data line 1: " << line << std::endl;
+	num_of_cols = number_of_columns(line);
+	if (isdata(line)) {
+		line = read_line(infile);
+	//std::cout << "compare data line 2: " << line << std::endl;
+		num_of_cols2 = number_of_columns(line);
+		if (isdata(line)) {
+			line = read_line(infile);
+	//std::cout << "compare data line 3: " << line << std::endl;
+			num_of_cols3 = number_of_columns(line);
+		}
+	}
+	if ((num_of_cols == num_of_cols2) && (num_of_cols == num_of_cols3)) {
+		number_of_cols = num_of_cols;
+		number_of_headers = std::min(number_of_cols, number_of_headers); 
+		number_of_cols = std::min(number_of_cols, number_of_headers);
+	}
+	else {
+  		//cout << "numbers of cols: " << num_of_cols <<" "<< num_of_cols2 <<" "<< num_of_cols3 << endl; 
+		printf("ERROR: number of columns must remain constant. check your ASCII file\n");
+	}*/
+
+}
+
+
+TextCollistRetriever::~TextCollistRetriever(){
+  //cout << "~TextCollistRetriever()" << endl;
+
+  // close the file
+  if(infile)
+    infile.close();
+}
+
+/**
+ * This is the method for retrieving data from a file. The whole
+ * tree will be written to the new file immediately after being
+ * called. Interpreting the string is left up to the implementing
+ * code.
+ */
+void TextCollistRetriever::getData(const string &location, tree<Node> &tr){
+	//cout << "TextCollistRetriever::getData(" << location << ",tree)" << endl; // REMOVE
+	// check that the argument is not an empty string
+	//printf("extracting...%s", location.c_str()); 
+	if(location.size()<=0) {
+		throw invalid_argument("cannot parse empty string");
+	}
+
+	// so far ... all locations must refer to a column name 
+	std::string method 	= parse_method(location);
+	std::string arg 		= parse_arg(location);
+	std::string nxtype 	= parse_type(location);
+	if (nxtype == "") {
+		// default type is NX_FLOAT64
+		nxtype = "NX_FLOAT64";
+	}
+	
+	// get range bounds if specified 
+	int from, to;
+	parse_range(location, from, to); 
+	
+	//cout << "location: " << method << "(\'" << arg << "\')" << "[" << from << "," << to << "]{" << nxtype <<"}" << endl << endl;	
+ 
+	if (method == TextCollistRetriever::COLUMN_TAG) { 
+		std::vector<double> values = extract_column(infile, arg, from, to);
+  		if (values.size() <= 0) {
+			// if we get no values, just dont create a node
+			std::cout << "creating an empty node, as we got no values" << std::endl;
+			// create an empty data node
+			int* empty_dims = new int[1];
+			empty_dims[0] = 1;
+			void *data;
+			if(NXmalloc(&data, 1, empty_dims, NX_INT32)!=NX_OK) {
+				throw runtime_error("NXmalloc failed");
+			}
+			*((int*)data)=0;
+			Node node(arg, data, 1, empty_dims, NX_INT32);
+			// put the node into the tree 
+			tr.insert(tr.begin(),node);
+			return;
+		}
+
+	
+		int nxrank = 1;
+		int* nxdims = new int[1];
+		nxdims[0] = values.size();
+
+		// allocate space for the data
+		void *data;
+		if(NXmalloc(&data, nxrank, nxdims, convert_type(nxtype))!=NX_OK) {
+			throw runtime_error("NXmalloc failed");
+		}
+
+		for( unsigned int i=0 ; i<values.size() ; i++ ) {
+			switch (convert_type(nxtype)) {
+				case NX_INT32: 
+					*(((int*)data)+i)=static_cast<int>(values.at(i));
+					break;
+				case NX_UINT32: 
+					*(((unsigned int*)data)+i)=static_cast<unsigned int>(values.at(i));
+					break;
+				case NX_INT16: 
+					*(((short*)data)+i)=static_cast<short>(values.at(i));
+					break;
+				case NX_UINT16: 
+					*(((unsigned short*)data)+i)=static_cast<unsigned short>(values.at(i));
+					break;
+				case NX_FLOAT64:
+					*(((double*)data)+i)=static_cast<double>(values.at(i));
+					break;
+				case NX_FLOAT32:
+					*(((float*)data)+i)=static_cast<float>(values.at(i));
+					break;
+					
+			}
+		}
+
+		//cout << endl << "info: " << ((double*)data)[0] << " "<<((double*)data)[1]<<" "<<((double*)data)[2]<< endl;	
+		// create a data node
+		Node node("empty", data, nxrank, nxdims, convert_type(nxtype));
+		// put the data in the node
+		tr.insert(tr.begin(),node);
+	}
+	else if (method == TextCollistRetriever::DICT_TAG) { 
+		std::string entry="";
+		std::string units="";
+		std::string raw_string = extract_dictentry(infile, arg, convert_type(nxtype));
+ 		//cout << "dict value: '" << raw_string << "'"<<std::endl;  
+  		if (raw_string.size() <= 0) {
+			// if we get no values, just dont create a node
+			std::cout << "creating an empty node, as we got no values" << std::endl;
+			// create an empty data node
+			int* empty_dims = new int[1];
+			empty_dims[0] = 1;
+			void *data;
+                        char *pPtr;
+
+			if(NXmalloc(&data, 1, empty_dims, NX_CHAR)!=NX_OK) {
+				throw runtime_error("NXmalloc failed");
+			}
+			pPtr = (char *)data;
+			strcpy(pPtr,"");
+			Node node(arg, data, 1, empty_dims, NX_CHAR);
+			// put the node into the tree 
+			tr.insert(tr.begin(),node);
+			return;
+		}
+		
+		
+		unsigned int pos = raw_string.find("value:");
+		if (pos != std::string::npos) {
+			entry = raw_string.substr(pos+6);
+		}
+		pos = raw_string.find("units:");
+		if (pos != std::string::npos) {
+			units = raw_string.substr(pos+6);
+			unsigned int pos2 = units.find(";", pos);
+			if (pos2 != std::string::npos) {
+				units = units.substr(0, pos2);
+				//std::cout << " units extracted: " << units <<  std::endl;
+			}
+		}
+		else {
+			entry = raw_string;
+		}
+		//std::cout << "value extracted: " << entry << std::endl;
+
+		int nxrank = 1;
+		int* nxdims = new int[1];
+		nxdims[0] = 1;
+
+		// allocate space for the data
+		void *data;
+		if(NXmalloc(&data, nxrank, nxdims, convert_type(nxtype))!=NX_OK) {
+			throw runtime_error("NXmalloc failed");
+		}
+			switch (convert_type(nxtype)) {
+				case NX_CHAR:
+					if (nxtype == "ISO8601") {
+						data = (char*)mira_datetime_2_iso(entry).c_str();
+					}
+					else {
+						data = (char*)entry.c_str();
+					}
+					nxdims[0] = entry.size();
+					break;
+				case NX_INT32: 
+					*((int*)data) = static_cast<int>(string_util::str_to_int(entry.c_str()));
+					break;
+				case NX_UINT32: 
+					*((unsigned int*)data) = static_cast<unsigned int>(string_util::str_to_int(entry.c_str()));
+					break;
+				case NX_INT16: 
+					*((short*)data) = static_cast<short>(string_util::str_to_int(entry.c_str()));
+					break;
+				case NX_UINT16: 
+					*((unsigned short*)data) = static_cast<unsigned short>(string_util::str_to_int(entry.c_str()));
+					break;
+				case NX_FLOAT64:
+					*((double*)data) = static_cast<double>(string_util::str_to_float(entry.c_str()));
+					break;
+				case NX_FLOAT32:
+					*((float*)data) = static_cast<float>(string_util::str_to_float(entry.c_str()));
+					break;
+			}
+
+		// create a data node
+		Node node("empty", data, nxrank, nxdims, convert_type(nxtype));
+		if (units!="" && convert_type(nxtype) != NX_CHAR) {
+			std::vector<Attr> attrs;
+			Attr attr("units", units.c_str(), units.size(), NX_CHAR);
+			attrs.push_back(attr);
+			node.update_attrs(attrs);
+		}
+		// put the node into the tree 
+		tr.insert(tr.begin(),node);
+		
+	}
+	else {
+		printf("unknown method !!");
+	}
+}
+
+
+std::string TextCollistRetriever::mira_datetime_2_iso(std::string &datetimestr) {
+	/* mira: 05/17/2005 03:13:37 */
+	/* iso: 2005-05-17 03:13:37 */
+	unsigned int pos, pos2;
+	std::string datestr, timestr;
+	std::string day="";
+	std::string month="";
+	std::string year="";
+	pos = datetimestr.find(" ");
+	if (pos != std::string::npos) {
+		datestr = datetimestr.substr(0, pos);
+		timestr = datetimestr.substr(pos+1);
+		
+		pos = datestr.find("/");
+		if (pos != std::string::npos) {
+			month = datestr.substr(0, pos);
+			pos2 = datestr.rfind("/");  
+			if (pos2 != std::string::npos) {
+				year = datestr.substr(pos2+1);
+				day = datestr.substr(0, pos2);
+				day = day.substr(pos+1);
+			}
+		}
+	}
+	//sample together new string
+	if (timestr!="" && day!="" && month!="" && year !="") {
+		datetimestr = year+"-"+month+"-"+day+" "+timestr;	
+	}
+	//std::cout << "year: " << year << ", month: " << month << ", day: "<< day << ", datetime:" << datetimestr <<  std::endl;
+	return datetimestr;
+}
+
+
+std::string TextCollistRetriever::toString() const{
+  return "["+MIME_TYPE+"] "+source;
+}
diff --git a/applications/NXtranslate/text_collist/collist_retriever.h b/applications/NXtranslate/text_collist/collist_retriever.h
new file mode 100644
index 0000000..1cffb21
--- /dev/null
+++ b/applications/NXtranslate/text_collist/collist_retriever.h
@@ -0,0 +1,61 @@
+#ifndef __TEXT_COLLIST_RETRIEVER
+#define __TEXT_COLLIST_RETRIEVER
+
+#include "../retriever.h"
+#include <fstream>
+#include <map>
+
+// this is not intended to be inherited from
+class TextCollistRetriever: public Retriever{
+ public:
+  TextCollistRetriever(const std::string &);
+  ~TextCollistRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  TextCollistRetriever(const TextCollistRetriever&);
+  TextCollistRetriever& operator=(const TextCollistRetriever&);
+  std::string source;
+
+protected:
+  int current_line;
+  std::ifstream infile;
+  int number_of_cols;
+  int number_of_headers;
+  int number_of_entrys;
+  int header_section;
+  int data_section;
+  std::vector<std::string> headers;
+  std::vector<std::string> units;
+  
+  void extract_headers(std::string line);
+  void extract_units(std::string line);
+
+  int number_of_columns(std::string line);
+  std::string extract_dictentry(std::ifstream &file, std::string arg, unsigned int nxtype);
+  std::vector<double> extract_column(std::ifstream &file, std::string col_name, int from=-1, int to=-1);
+  std::string parse_arg(std::string location);
+  std::string parse_method(std::string location);
+  std::string parse_type(std::string location);
+  void parse_range(std::string location, int &x, int &y);
+  
+  std::string mira_datetime_2_iso(std::string &timestr);
+  
+public: 
+  static bool isdata(std::string line);
+  bool isunit(std::string line);
+  static const std::string COLUMN_TAG;
+  static const std::string DICT_TAG;
+  static const std::string RANGE_OPEN_BRACKET;
+  static const std::string RANGE_CLOSE_BRACKET;
+  static const std::string RANGE_SEPARATOR;
+  static const std::string METHOD_OPEN_BRACKET;
+  static const std::string METHOD_CLOSE_BRACKET;
+  static const std::string TYPE_OPEN_BRACKET;
+  static const std::string TYPE_CLOSE_BRACKET;
+  std::map<std::string, std::string> unit_strings; 
+  
+
+};
+#endif
diff --git a/applications/NXtranslate/text_collist/mira.txt b/applications/NXtranslate/text_collist/mira.txt
new file mode 100644
index 0000000..f7ccfa5
--- /dev/null
+++ b/applications/NXtranslate/text_collist/mira.txt
@@ -0,0 +1,110 @@
+mira2:/data/2005 # cat mira_00000478
+filename     : 'mira_00000478'
+created at   : 05/17/2005 03:13:37
+installation : FRM2
+instrument   : MIRA
+user         : mira
+responsable  : Dr. Frankenstein 
+phone        : +49(0)29383933
+fax          : +49(0)30398773
+********* data section starts here
+*********************************************************
+instrument general setup at file creation:
+scan data:
+ single sided theta/twotheta scan:
+ from  0.000   90 steps of width  0.025
+om/phi; [ time, mon1, mon2, tube1, tube2 ]
+********* parameter log file section starts here
+    degree     degree ;  sec.      cts      cts      cts      cts
+*********************************************************
+       om        phi ;  time     mon1     mon2    tube1    tube2
+       0.0 0.031494140625 ; 250.0  4275725   488315        0        0
+0.0050048828125 0.031494140625 ; 250.0  4274579   498686        0        0
+0.0498046875 0.0928955078125 ; 250.0  4285891   603134        0        0
+0.074951171875 0.147583007812 ; 250.0  4277700   658966        0        0
+0.099853515625 0.192993164062 ; 250.0  4276559   715051        0        0
+     0.125 0.24560546875 ; 250.0  4279586   769965        0        0
+0.149780273438 0.2978515625 ; 250.0  4277632   821506        0        0
+0.174926757812 0.346557617188 ; 250.0  4280600   832281        0        0
+0.199829101562  0.3984375 ; 250.0  4269999   843837        0        0
+0.224975585938 0.448974609375 ; 250.0  4273874   931177        0        0
+0.249877929688 0.490600585938 ; 250.0  4277282   972020        0        0
+0.27490234375 0.547729492188 ; 250.0  4276014   989198        0        0
+0.2998046875 0.590576171875 ; 250.0  4263025   998680        0        0
+0.324951171875 0.64453125 ; 250.0  4269679  1005099        0        0
+0.349853515625 0.693969726562 ; 250.0  4274322  1004330        0        0
+0.374877929688 0.746704101562 ; 250.0  4283304  1006898        0        0
+0.399780273438 0.793579101562 ; 250.0  4277851  1004042        0        0
+0.425048828125 0.845703125 ; 250.0  4277594  1006896        0        0
+0.449829101562 0.897583007812 ; 250.0  4269086  1005051        0        0
+0.474853515625 0.947631835938 ; 250.0  4265005  1003856        0        0
+0.499877929688 0.996826171875 ; 250.0  4272178  1004025        0        0
+0.525024414062 1.0458984375 ; 250.0  4275815  1002250        0        0
+0.549926757812 1.09057617188 ; 250.0  4266241  1000968        0        0
+0.574951171875  1.1484375 ; 250.0  4274536  1001625        0        0
+0.599853515625 1.19750976562 ; 250.0  4262755  1000149        0        0
+0.625122070312 1.24987792969 ; 250.0  4274648  1003059        0        0
+0.64501953125 1.294921875 ; 250.0  4271390  1000382        0        0
+0.674926757812 1.34643554688 ; 250.0  4267090   998688        0        0
+0.699829101562 1.39770507812 ; 250.0  4270994   999878        0        0
+0.724975585938 1.44580078125 ; 250.0  4273929   999304        0        0
+0.749877929688 1.49182128906 ; 250.0  4268239   997403        0        0
+0.77490234375 1.54614257812 ; 250.0  4264580   993968        0        0
+0.7998046875 1.5927734375 ; 250.0  4282352   996910        0        0
+0.824951171875 1.6435546875 ; 250.0  4272204   995771        0        0
+0.849853515625 1.69323730469 ; 250.0  4267224   995298        0        0
+     0.875 1.744140625 ; 250.0  4265267   995201        0        0
+0.89990234375 1.79638671875 ; 250.0  4269139   996092        0        0
+0.925048828125 1.84094238281 ; 250.0  4267181   994677        0        0
+0.949951171875 1.8974609375 ; 250.0  4267200   997659        0        0
+0.974975585938 1.94287109375 ; 250.0  4268108   996698        0        0
+0.999877929688 1.99438476562 ; 250.0  4269018   994563        0        0
+1.02502441406 2.04772949219 ; 250.0  4268093   991316        0        0
+1.04992675781 2.09765625 ; 250.0  4270127   991166        0        0
+1.07495117188 2.14477539062 ; 250.0  4262664   988181        0        0
+1.09985351562 2.18835449219 ; 250.0  4255505   988139        0        0
+     1.125 2.24658203125 ; 250.0  4253231   986428        0        0
+1.14978027344 2.29675292969 ; 250.0  4256020   987368        0        0
+1.17492675781    2.34375 ; 250.0  4271147   984120        0        0
+1.19982910156 2.3955078125 ; 250.0  4272515   980439        0        0
+1.22497558594 2.44543457031 ; 250.0  4278236   979898        0        0
+1.24987792969 2.49780273438 ; 250.0  4273269   979854        0        0
+1.27490234375 2.54772949219 ; 250.0  4270865   977653        0        0
+1.2998046875 2.59497070312 ; 250.0  4272891   978129        0        0
+1.32495117188 2.64538574219 ; 250.0  4286365   974690        0        0
+1.34985351562 2.69372558594 ; 250.0  4279287   964834        0        0
+1.37487792969 2.74609375 ; 250.0  4275173   951996        0        0
+1.39978027344 2.79528808594 ; 250.0  4274118   932662        0        0
+1.42492675781 2.84594726562 ; 250.0  4273096   896469        0        0
+1.44982910156 2.89428710938 ; 250.0  4276390   833949        0        0
+1.47485351562 2.94470214844 ; 250.0  4271434   750554        0        0
+1.49987792969 2.98779296875 ; 250.0  4268945   649385        0        0
+1.52490234375 3.04748535156 ; 250.0  4274466   523717        0        0
+1.5498046875 3.09777832031 ; 250.0  4266729   422061        0        0
+1.57482910156 3.14453125 ; 250.0  4269190   339093        0        0
+1.59985351562 3.19555664062 ; 250.0  4271313   271210        0        0
+     1.625 3.24853515625 ; 250.0  4281439   252335        0        0
+1.64978027344 3.298828125 ; 250.0  4266888   221772        0        0
+1.67492675781 3.34655761719 ; 250.0  4270069   166294        0        0
+1.69995117188 3.39379882812 ; 250.0  4269655   132940        0        0
+1.72497558594 3.44750976562 ; 250.0  4268551    98834        0        0
+1.74987792969 3.494140625 ; 250.0  4263542    79026        0        0
+1.77490234375 3.53942871094 ; 250.0  4267556    93651        0        0
+1.7998046875 3.59680175781 ; 250.0  4267600   110052        0        0
+1.82495117188 3.64782714844 ; 250.0  4265438   116687        0        0
+1.84985351562 3.69360351562 ; 250.0  4268855   110571        0        0
+     1.875 3.74670410156 ; 250.0  4267518   100638        0        0
+1.89990234375 3.79565429688 ; 250.0  4258945    85478        0        0
+1.92504882812 3.845703125 ; 250.0  4270633    69993        0        0
+1.94995117188 3.89562988281 ; 250.0  4269804    60212        0        0
+1.97497558594 3.94665527344 ; 250.0  4271325    55796        0        0
+1.99987792969 3.99853515625 ; 250.0  4270954    56217        0        0
+2.02502441406 4.05004882812 ; 250.0  4269068    63673        0        0
+2.04992675781 4.05004882812 ; 250.0  4263556    74102        0        0
+2.07495117188 4.14343261719 ; 250.0  4268602    76975        0        0
+2.09985351562 4.193359375 ; 250.0  4264322    66247        0        0
+     2.125 4.24670410156 ; 250.0  4267896    50601        0        0
+2.14978027344 4.29272460938 ; 250.0  4265196    39494        0        0
+2.17492675781 4.34643554688 ; 250.0  4264335    39153        0        0
+2.19982910156 4.39270019531 ; 250.0  4271106    45081        0        0
+2.22497558594 4.44470214844 ; 250.0  4267013    49782        0        0
diff --git a/applications/NXtranslate/text_plain/CMakeLists.txt b/applications/NXtranslate/text_plain/CMakeLists.txt
new file mode 100644
index 0000000..10e2591
--- /dev/null
+++ b/applications/NXtranslate/text_plain/CMakeLists.txt
@@ -0,0 +1,32 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../)
+
+add_library (TextPlain STATIC retriever.cpp retriever.h)
+
diff --git a/applications/NXtranslate/text_plain/Makefile.am b/applications/NXtranslate/text_plain/Makefile.am
new file mode 100644
index 0000000..1595f40
--- /dev/null
+++ b/applications/NXtranslate/text_plain/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libTextPlain.la
+
+libTextPlain_la_SOURCES = \
+	retriever.cpp retriever.h
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/text_plain/retriever.cpp b/applications/NXtranslate/text_plain/retriever.cpp
new file mode 100644
index 0000000..3f874df
--- /dev/null
+++ b/applications/NXtranslate/text_plain/retriever.cpp
@@ -0,0 +1,107 @@
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include "retriever.h"
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+
+static const int BUFFER_SIZE=256;
+
+static string read_line(ifstream &file){
+  static char buffer[BUFFER_SIZE];
+  file.get(buffer,BUFFER_SIZE);
+  file.get();
+  return string(buffer);
+}
+
+static void skip_to_line(ifstream &file,int &cur_line, int new_line){
+  if(new_line==cur_line){ // skip out early if possible
+    return;
+  }else if(new_line<cur_line){  // go to the beginning if necessary
+    file.seekg(0,std::ios::beg);
+    cur_line=0;
+  }
+
+  // scan down to the right place
+  while( (file.good()) && (cur_line<new_line) ){
+    string text=read_line(file);
+    //cout << "LINE" << cur_line << "[" << file.tellg() << "]:" << text << endl;
+    cur_line++;
+  }
+
+  if(!(file.good()))
+    throw invalid_argument("Could not reach line "
+                           +string_util::int_to_str(new_line));
+}
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+TextPlainRetriever::TextPlainRetriever(const string &str): source(str),current_line(0){
+  //cout << "TextPlainRetriever(" << source << ")" << endl; // REMOVE
+
+  // open the file
+  infile.open(source.c_str());
+
+  // check that open was successful
+  if(!infile.is_open())
+    throw invalid_argument("Could not open file: "+source);
+}
+
+TextPlainRetriever::~TextPlainRetriever(){
+  //cout << "~TextPlainRetriever()" << endl;
+
+  // close the file
+  if(infile)
+    infile.close();
+}
+
+/**
+ * This is the method for retrieving data from a file. The whole
+ * tree will be written to the new file immediately after being
+ * called. Interpreting the string is left up to the implementing
+ * code.
+ */
+void TextPlainRetriever::getData(const string &location, tree<Node> &tr){
+  //cout << "TextPlainRetriever::getData(" << location << ",tree)" << endl; // REMOVE
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    throw invalid_argument("cannot parse empty string");
+
+  // check that the argument is an integer
+  int line_num=string_util::str_to_int(location);
+
+  // set stream to the line before
+  skip_to_line(infile,current_line,line_num);
+  // read the line and print it to the console
+  string text=read_line(infile);
+
+  // create an empty node
+  Node node("empty","empty");
+
+  // put the data in the node
+  vector<int> dims;
+  dims.push_back(text.size());
+  update_node_from_string(node,text,dims,Node::CHAR);
+  tr.insert(tr.begin(),node);
+}
+
+const string TextPlainRetriever::MIME_TYPE("text/plain");
+
+string TextPlainRetriever::toString() const{
+  return "["+MIME_TYPE+"] "+source;
+}
diff --git a/applications/NXtranslate/text_plain/retriever.h b/applications/NXtranslate/text_plain/retriever.h
new file mode 100644
index 0000000..2cfaf28
--- /dev/null
+++ b/applications/NXtranslate/text_plain/retriever.h
@@ -0,0 +1,22 @@
+#ifndef __TEXT_PLAIN_RETRIEVER_GUARD
+#define __TEXT_PLAIN_RETRIEVER_GUARD
+
+#include "../retriever.h"
+#include <fstream>
+
+// this is not intended to be inherited from
+class TextPlainRetriever: public Retriever{
+ public:
+  TextPlainRetriever(const std::string &);
+  ~TextPlainRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  TextPlainRetriever(const TextPlainRetriever&);
+  TextPlainRetriever& operator=(const TextPlainRetriever&);
+  std::string source;
+  int current_line;
+  std::ifstream infile;
+};
+#endif
diff --git a/applications/NXtranslate/text_xml/CMakeLists.txt b/applications/NXtranslate/text_xml/CMakeLists.txt
new file mode 100644
index 0000000..49c8344
--- /dev/null
+++ b/applications/NXtranslate/text_xml/CMakeLists.txt
@@ -0,0 +1,34 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(. ../ ${LIBXML2_INCLUDE_DIR})
+
+add_library (TextXML STATIC xml_retriever.cpp retriever.h
+                            xml_retriever_dom.cpp xml_retriever_dom.h
+                            void_copy.cpp void_copy.h)
+
diff --git a/applications/NXtranslate/text_xml/Makefile.am b/applications/NXtranslate/text_xml/Makefile.am
new file mode 100644
index 0000000..df5c286
--- /dev/null
+++ b/applications/NXtranslate/text_xml/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+# $Id$
+#
+# Copyright (c) 2004, P.F.Peterson <petersonpf at ornl.gov>
+#               Spallation Neutron Source at Oak Ridge National Laboratory
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# @configure_input@
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include @LIBXML2_CFLAGS@
+
+noinst_LTLIBRARIES = libTextXML.la
+
+libTextXML_la_SOURCES = \
+	xml_retriever.cpp retriever.h \
+        xml_retriever_dom.cpp xml_retriever_dom.h \
+        void_copy.cpp void_copy.h
+
+#EXTRA_DIST = CHANGES LICENSE README TODO
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtranslate/text_xml/retriever.h b/applications/NXtranslate/text_xml/retriever.h
new file mode 100644
index 0000000..8c43bd8
--- /dev/null
+++ b/applications/NXtranslate/text_xml/retriever.h
@@ -0,0 +1,24 @@
+#ifndef __TEXT_XML_RETRIEVER_GUARD
+#define __TEXT_XML_RETRIEVER_GUARD
+
+#include <libxml/parser.h>
+#include "../node.h"
+#include "../Ptr.h"
+#include "../retriever.h"
+#include "../tree.hh"
+
+// this is not intended to be inherited from
+class TextXmlRetriever: public Retriever{
+ public:
+  TextXmlRetriever(const std::string &);
+  ~TextXmlRetriever();
+  void getData(const std::string &, tree<Node> &);
+  std::string toString() const;
+  static const std::string MIME_TYPE;
+ private:
+  TextXmlRetriever(const TextXmlRetriever&);
+  TextXmlRetriever& operator=(const TextXmlRetriever&);
+  std::string source;
+  Ptr< tree<Node> > __tree;
+};
+#endif
diff --git a/applications/NXtranslate/text_xml/void_copy.cpp b/applications/NXtranslate/text_xml/void_copy.cpp
new file mode 100644
index 0000000..6a9c4ca
--- /dev/null
+++ b/applications/NXtranslate/text_xml/void_copy.cpp
@@ -0,0 +1,170 @@
+#include "void_copy.h"
+
+// NX_FLOAT32
+extern bool void_copy::from_float(const float* source, void *&copy, const int num_elem, const Node::NXtype type){
+  if(type==Node::FLOAT64){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((double *)copy)[i]=static_cast<double>(source[i]);
+    return true;
+  }else if(type==Node::FLOAT32){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((float *)copy)[i]=source[i];
+    return true;
+  }else if(type==Node::INT8){
+    // should do something
+  }else if(type==Node::INT16){
+    // should do something
+  }else if(type==Node::INT32){
+    // should do something
+  }else if(type==Node::UINT8){
+    // should do something
+  }else if(type==Node::UINT16){
+    // should do something
+  }else if(type==Node::UINT32){
+    // should do something
+  }
+
+  return false;
+}
+
+// NX_FLOAT64
+extern bool void_copy::from_double(const double* source, void *&copy, const int num_elem, const Node::NXtype type){
+  if(type==Node::FLOAT64){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((double *)copy)[i]=source[i];
+    return true;
+  }else if(type==Node::FLOAT32){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((float *)copy)[i]=static_cast<float>(source[i]);
+    return true;
+  }else if(type==Node::INT8){
+    // should do something
+  }else if(type==Node::INT16){
+    // should do something
+  }else if(type==Node::INT32){
+    // should do something
+  }else if(type==Node::UINT8){
+    // should do something
+  }else if(type==Node::UINT16){
+    // should do something
+  }else if(type==Node::UINT32){
+    // should do something
+  }
+
+  return false;
+}
+
+// NX_INT16
+extern bool void_copy::from_short(const short int* source, void *&copy, const int num_elem, const Node::NXtype type){
+  if(type==Node::FLOAT64){
+    // should do something
+  }else if(type==Node::FLOAT32){
+    // should do something
+  }else if(type==Node::INT8){
+    // should do something
+  }else if(type==Node::INT16){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((short int *)copy)[i]=source[i];
+    return true;
+  }else if(type==Node::INT32){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((int *)copy)[i]=static_cast<int>(source[i]);
+    return true;
+  }else if(type==Node::UINT8){
+    // should do something
+  }else if(type==Node::UINT16){
+    // should do something
+  }else if(type==Node::UINT32){
+    // should do something
+  }
+
+  return false;
+}
+
+// NX_INT32
+extern bool void_copy::from_int(const int* source, void *&copy, const int num_elem, const Node::NXtype type){
+  if(type==Node::FLOAT64){
+    // should do something
+  }else if(type==Node::FLOAT32){
+    // should do something
+  }else if(type==Node::INT8){
+    // should do something
+  }else if(type==Node::INT16){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((short int *)copy)[i]=static_cast<short int>(source[i]);
+    return true;
+  }else if(type==Node::INT32){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((int *)copy)[i]=source[i];
+    return true;
+  }else if(type==Node::UINT8){
+    // should do something
+  }else if(type==Node::UINT16){
+    // should do something
+  }else if(type==Node::UINT32){
+    // should do something
+  }
+
+  return false;
+}
+
+extern bool void_copy::from_long(const long int* source, void *&copy, const int num_elem, const Node::NXtype type){
+  return false;
+}
+
+// NX_UINT16
+extern bool void_copy::from_ushort(const unsigned short int* source, void *&copy, const int num_elem, const Node::NXtype type){
+  if(type==Node::FLOAT64){
+    // should do something
+  }else if(type==Node::FLOAT32){
+    // should do something
+  }else if(type==Node::INT8){
+    // should do something
+  }else if(type==Node::INT16){
+    // should do something
+  }else if(type==Node::INT32){
+    // should do something
+  }else if(type==Node::UINT8){
+    // should do something
+  }else if(type==Node::UINT16){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((unsigned short int *)copy)[i]=source[i];
+    return true;
+  }else if(type==Node::UINT32){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((unsigned int *)copy)[i]=static_cast<unsigned int>(source[i]);
+    return true;
+  }
+  return false;
+}
+
+// NX_UINT32
+extern bool void_copy::from_uint(const unsigned int* source, void *&copy, const int num_elem, const Node::NXtype type){
+  if(type==Node::FLOAT64){
+    // should do something
+  }else if(type==Node::FLOAT32){
+    // should do something
+  }else if(type==Node::INT8){
+    // should do something
+  }else if(type==Node::INT16){
+    // should do something
+  }else if(type==Node::INT32){
+    // should do something
+  }else if(type==Node::UINT8){
+    // should do something
+  }else if(type==Node::UINT16){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((unsigned short int *)copy)[i]=static_cast<unsigned short int>(source[i]);
+    return true;
+  }else if(type==Node::UINT32){
+    for(int i=0 ; i<num_elem ; i++ )
+      ((unsigned int *)copy)[i]=source[i];
+    return true;
+  }
+
+  return false;
+}
+
+extern bool void_copy::from_ulong(const unsigned long int* source, void *&copy, const int num_elem, const Node::NXtype type){
+  return false;
+}
diff --git a/applications/NXtranslate/text_xml/void_copy.h b/applications/NXtranslate/text_xml/void_copy.h
new file mode 100644
index 0000000..a17330b
--- /dev/null
+++ b/applications/NXtranslate/text_xml/void_copy.h
@@ -0,0 +1,30 @@
+#ifndef VOID_COPY_H
+#define VOID_COPY_H
+
+#include "../node.h"
+
+namespace void_copy{
+  // NX_FLOAT32
+  extern bool from_float(const float* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  // NX_FLOAT64
+  extern bool from_double(const double* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  // NX_INT16
+  extern bool from_short(const short int* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  // NX_INT32
+  extern bool from_int(const int* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  extern bool from_long(const long int* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  // NX_UINT16
+  extern bool from_ushort(const unsigned short int* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  // NX_UINT32
+  extern bool from_uint(const unsigned int* source, void *&copy, const int num_elem, const Node::NXtype type);
+
+  extern bool from_ulong(const unsigned long int* source, void *&copy, const int num_elem, const Node::NXtype type);
+}
+
+#endif
diff --git a/applications/NXtranslate/text_xml/xml_retriever.cpp b/applications/NXtranslate/text_xml/xml_retriever.cpp
new file mode 100644
index 0000000..a4623f0
--- /dev/null
+++ b/applications/NXtranslate/text_xml/xml_retriever.cpp
@@ -0,0 +1,362 @@
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <libxml/xmlmemory.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include "retriever.h"
+#include "xml_retriever_dom.h"
+#include "void_copy.h"
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "../tree.hh"
+
+using std::ifstream;
+using std::invalid_argument;
+using std::runtime_error;
+using std::string;
+using std::cout;
+using std::endl;
+using std::vector;
+using string_util::starts_with;
+
+typedef vector<string>     StringVec;
+typedef tree<Node>         NodeTree;
+typedef NodeTree::iterator NodeTreeIter;
+
+static string get_type(const string &location){
+  static const string CHAR("CHAR");
+  if(starts_with(location,CHAR))
+    return "NX_CHAR";
+
+  static const string INT8("INT8");
+  if(starts_with(location,INT8))
+    return "NX_INT8";
+
+  static const string INT16("INT16");
+  if(starts_with(location,INT16))
+    return "NX_INT16";
+
+  static const string INT32("INT32");
+  if(starts_with(location,INT32))
+    return "NX_INT32";
+
+  static const string UINT8("UINT8");
+  if(starts_with(location,UINT8))
+    return "NX_UINT8";
+
+  static const string UINT16("UINT16");
+  if(starts_with(location,UINT16))
+    return "NX_UINT16";
+
+  static const string UINT32("UINT32");
+  if(starts_with(location,UINT32))
+    return "NX_UINT32";
+
+  static const string FLOAT32("FLOAT32");
+  if(starts_with(location,FLOAT32))
+    return "NX_FLOAT32";
+
+  static const string FLOAT64("FLOAT64");
+  if(starts_with(location,FLOAT64))
+    return "NX_FLOAT64";
+
+  throw invalid_argument("Cannot determine type in location: "+location);
+}
+
+static bool is_right_square_bracket(const char c){
+  static const string RIGHT="]";
+  return find(RIGHT.begin(),RIGHT.end(),c)!=RIGHT.end();
+}
+
+static string get_dims(const string &location){
+  using std::find;
+  static const string LEFT("[");
+
+  if(!starts_with(location,LEFT))
+    return "";
+
+  string result="";
+  for(string::const_iterator it=location.begin() ; it!=location.end() ; it++ ){
+    result+=(*it);
+    if(is_right_square_bracket(*it))
+      break;
+  }
+
+  if(result.size()==location.size())
+    return "";
+  else
+    return result;
+}
+
+/**
+ * The factory will call the constructor with a string. The string
+ * specifies where to locate the data (e.g. a filename), but
+ * interpreting the string is left up to the implementing code.
+ */
+TextXmlRetriever::TextXmlRetriever(const string &str): source(str), __tree(new tree<Node>){
+
+  // fill tree
+  string warn=buildTree(str,*__tree);
+
+  // check that the document is not empty
+  if(__tree->size()<=0)
+    throw runtime_error("Empty document ["+source+"]");
+}
+
+TextXmlRetriever::~TextXmlRetriever(){
+  //cout << "~TextXmlRetriever()" << endl;
+  
+  // __tree does not need to be deleted
+}
+
+static Node getNode(Ptr<NodeTree> tr, const StringVec &path){
+  // set up iterators for dealing with the path
+  StringVec::const_iterator path_it=path.begin();
+  StringVec::const_iterator path_end=path.end();
+  
+  for( NodeTreeIter it=tr->begin() ; it!=tr->end() ;  ){
+    if(it->name()==(*path_it)){
+      path_it++;
+      if(path_it==path_end)
+        return *it;
+      it=tr->child(it,0);
+    }else{
+      it=tr->next_sibling(it);
+    }
+  }
+
+  // when the code gets here the path was not found
+  string error;
+  for( StringVec::const_iterator it=path.begin() ; it!=path_end ; it++ )
+    error+="/"+(*it);
+  throw runtime_error("PATH["+error+"] NOT FOUND IN FILE");
+}
+
+// determine if there is a call for an attribute (denoted by #)
+static string strip_attr(StringVec &path){
+  static string HASH("#");
+
+  // the attribute call can only be on the last part of the path
+  string last=*(path.end()-1);
+
+  // determine if it contains a hash
+  int start=last.find(HASH);
+  if(start<=0) return string();
+
+  // get the attribute out
+  string attr=last.substr(start+1,last.size());
+  last=last.erase(start,last.size());
+
+  // repair the path
+  path.pop_back();
+  path.push_back(last);
+
+  return attr;
+}
+
+/**
+ * Turns an attribute from a node into a node.
+ */
+static Node promoteAttribute(const Node &node, const string &name){
+  //cout << "promoteAttribute(" << node.name() << "," << name << ")" << endl;
+
+  int num_attr=node.num_attr();
+  for( int i=0 ; i<num_attr ; i++ ){
+    Attr attr(node.get_attr(i));
+
+    if(attr.name()==name){
+      int dims[1]={attr.length()};
+      Node result(name,attr.value(),1,dims,attr.type());
+      return result;
+    }
+  }
+
+  throw runtime_error("Attribute ["+name+"] not found");
+}
+
+static int getElementCount(const vector<int> &vec){
+  if(vec.size()<=0)
+    throw invalid_argument("Cannot get number of elements from empty dimension");
+
+  int tot=1;
+  for( vector<int>::const_iterator it=vec.begin() ; it!=vec.end() ; it++ ){
+    tot*=(*it);
+  }
+
+  return tot;
+}
+
+static Node convertFromString(const string &name, string &data, vector<int> &dims, Node::NXtype type){
+  static string DEF_TYPE="EMPTY";
+  Node result(name,DEF_TYPE);
+  update_node_from_string(result, data, dims, type);
+  return result;
+}
+
+static Node convertFromNumeric(const Node &node, vector<int> &dims, const string &type){
+  // get the name of the resulting node
+  string name=node.name();
+
+  // determine the numeric types
+  Node::NXtype source_type=node.int_type();
+  Node::NXtype copy_type=node_type(type);
+
+  // if the types match, just return the node given
+  if(source_type==copy_type)
+    return node;
+
+  // create the dimension and rank information
+  const int rank=dims.size();
+  std::vector<int> int_dims(rank);
+  int tot_num=1;
+  for( int i=0 ; i<rank ; i++ ){
+    int_dims[i]=dims[i];
+    tot_num*=dims[i];
+  }
+
+  // allocate space for the data array
+  void *value(NULL);
+  NXmalloc(&value,rank,&(int_dims[0]),copy_type);
+
+  // temporary variable stating whether or not the cast worked
+  bool worked=false;
+
+  // make the cast
+  if(source_type==Node::FLOAT32)
+    worked=void_copy::from_float(((float*)(node.data())),value,tot_num,copy_type);
+  else if(source_type==Node::FLOAT64)
+    worked=void_copy::from_double(((double*)(node.data())),value,tot_num,copy_type);
+  else if(source_type==Node::INT16)
+    worked=void_copy::from_short(((short int*)(node.data())),value,tot_num,copy_type);
+  else if(source_type==Node::INT32)
+    worked=void_copy::from_int(((int*)(node.data())),value,tot_num,copy_type);
+  else if(source_type==Node::UINT16)
+    worked=void_copy::from_ushort(((unsigned short int*)(node.data())),value,tot_num,copy_type);
+  else if(source_type==Node::UINT32)
+    worked=void_copy::from_uint(((unsigned int*)(node.data())),value,tot_num,copy_type);
+  // ---------- add code here to work with other types
+
+  // error out if the cast did not work
+  if(!worked){
+    NXfree(&value);
+    value=NULL;
+    throw runtime_error("Cannot convert "+node.type()+" to "+type);
+  }
+
+  // package up the result
+  Node result(name,"EMPTY");
+  result.set_data(value,rank,&(int_dims[0]),copy_type);
+
+  // free up the temporary memory
+  NXfree(&value);
+  value=NULL;
+
+  // return the result of the cast
+  return result;
+}
+
+static Node convertType(const Node &node, const string &type,string &str_dims){
+  // can not convert non-data
+  if(!node.is_data())
+    throw invalid_argument("Cannot convert non-data to data");
+
+  // convert type to integer
+  Node::NXtype int_type=node_type(type);
+  Node::NXtype node_int_type=node.int_type();
+
+  // move dimensions over to vector<int> that the functions expect
+  vector<int> dims=string_util::str_to_intVec(str_dims);
+
+  // convert from string
+  if(node_int_type==Node::CHAR){
+    // convert void pointer to string
+    string value((char *)node.data());
+
+    // do the actual conversion
+    return convertFromString(node.name(),value,dims,int_type);
+  }
+
+  // if they are already the same type, update the dimensions and return
+  if(int_type==node_int_type){
+    // change the dimensionality for numerics
+    Node result(node);
+    result.update_dims(dims);
+    return result;
+  }
+
+  // check that the number of elements is unchanged
+  int node_tot=getElementCount(node.dims());
+  int res_tot =getElementCount(dims);
+  if(node_tot!=res_tot)
+    throw runtime_error("Cannot change number of elements in a node");
+
+  // do the actual conversion
+  return convertFromNumeric(node,dims,type);
+}
+
+/**
+ * This is the method for retrieving data from a file. The whole
+ * tree will be written to the new file immediately after being
+ * called. Interpreting the string is left up to the implementing
+ * code.
+ */
+void TextXmlRetriever::getData(const string &location, tree<Node> &tr){
+  //  cout << "TextXmlRetriever::getData(" << location << ",tree)" << endl; // REMOVE
+  // check that the argument is not an empty string
+  if(location.size()<=0)
+    throw invalid_argument("cannot parse empty string");
+
+  // variables for the divided string version of the location
+  string str_path;
+  string type;
+  string str_dims;
+
+  // convert the location to a type and (string) path
+  if(starts_with(location,"/")){
+    str_path=location;
+    type="NX_CHAR";
+    str_dims="";
+  }else{
+    // get the type and remove it from the location
+    type=get_type(location);
+    str_path=location.substr(type.size()-3,location.size());
+    // get the dimensions and remove it from the location
+    str_dims=get_dims(str_path);
+    str_path=str_path.substr(str_dims.size(),str_path.size());
+    if(str_dims.empty())
+      str_dims="[1]";
+    // remove the separating colon
+    str_path=str_path.substr(1,str_path.size());
+  }
+  //std::cout << "TYPE=" << type << " DIMS=" << str_dims << " PATH=" << str_path << std::endl; // REMOVE
+
+  // split path up
+  StringVec path=string_util::string_to_path(str_path);
+
+  // get out the attribute
+  string attr=strip_attr(path);
+
+  // get the requested node
+  Node node=getNode(__tree,path);
+
+  // upgrade attributes to be a node, if requested
+  if(attr.size()>0){
+    node=promoteAttribute(node,attr);
+  }
+
+  // change the type of a node
+  if((node.type()!=type) && (str_dims.size()>0))
+    node=convertType(node,type,str_dims);
+
+  // put the node in the supplied tree to pass it back
+  tr.insert(tr.begin(),node);
+}
+
+const string TextXmlRetriever::MIME_TYPE("text/xml");
+
+string TextXmlRetriever::toString() const{
+  return "["+MIME_TYPE+"] "+source;
+}
diff --git a/applications/NXtranslate/text_xml/xml_retriever_dom.cpp b/applications/NXtranslate/text_xml/xml_retriever_dom.cpp
new file mode 100644
index 0000000..dcc56f4
--- /dev/null
+++ b/applications/NXtranslate/text_xml/xml_retriever_dom.cpp
@@ -0,0 +1,302 @@
+#include <iostream>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <stdarg.h>
+#include "../node.h"
+#include "../node_util.h"
+#include "../string_util.h"
+#include "../xml_util.h"
+#include "xml_retriever_dom.h"
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::invalid_argument;
+using std::string;
+using std::runtime_error;
+using std::vector;
+
+typedef struct{
+  int status; // 0 if everything is fine
+  string error_msg; // store message for error reporting
+  string char_data; // character data collected for current node
+  tree<Node>::iterator node; // current node being worked on
+  tree<Node> *tr; // a copy of the actual tree being filled
+}UserData;
+
+typedef tree<Node> TreeNode;
+typedef tree<Node>::iterator TreeNodeIter;
+
+// must be static to allow for producing meaningful error messages
+static xmlParserCtxtPtr context=NULL;
+
+static xmlEntityPtr my_getEntity(void *user_data, const xmlChar *name){
+  // let libxml2 do this for us
+  return xmlGetPredefinedEntity(name);
+}
+
+static void my_startDocument(void *user_data){
+  // there is no initialization to be done
+}
+
+static void my_endDocument(void *user_data){
+  // there is no cleanup to be done
+}
+
+/*
+ * This function exists only to make the code in startElement more
+ * readable. It pushes a node into the tree and moves around all of
+ * the appropriate accounting.
+ */
+static void insertNode(UserData *user_data,Node &node){
+  if(user_data->tr->size()<=0) // tree is empty, use a different command
+    user_data->node=user_data->tr->insert(user_data->tr->begin(),node);
+  else // add as a child of current node
+    user_data->node=user_data->tr->append_child(user_data->node,node);
+}
+
+static void my_startElement(void *user_data, const xmlChar *name,
+                                                       const xmlChar ** attrs){
+  static string DEF_TYPE("UNKNOWN_TYPE");
+  static string TYPE("type");
+
+  // convert the name to a string
+  string str_name=xml_util::xmlChar_to_str(name,-1);
+  // create a label for the element when writing out exceptions
+  string except_label="<"+str_name+">:";
+  // convert the attributes to a vector<string>
+  vector<string> str_attrs=xml_util::xmlattr_to_strvec(attrs);
+
+#ifdef DEBUG_XML_RETRIEVER_DOM
+  std::cout << "startElement(user_data," << str_name << ")" << std::endl;
+#endif
+
+  // create attributes
+  string type=DEF_TYPE;
+  vector<Attr> attr_list;
+  if(str_attrs.size()>=2){
+    for( vector<string>::iterator it=str_attrs.begin() ; it!=str_attrs.end() ; it+=2 ){
+      if(TYPE==(*it))
+        type=(*(it+1));
+      else
+        attr_list.push_back(make_attr(*it,*(it+1)));
+    }
+  }
+
+  Node node(str_name,type);
+  node.set_attrs(attr_list);
+  insertNode((UserData *)user_data,node);
+
+}
+
+static void closeNode(UserData *user_data){
+  user_data->node=user_data->tr->parent(user_data->node);
+}
+
+static void my_endElement(void *user_data, const xmlChar *name){
+#ifdef DEBUG_XML_RETRIEVER_DOM
+  std::cout << "endElement(" << name << ")" << std::endl;
+#endif
+  static string LEFT("[");
+  static string RIGHT("]");
+
+  if(((UserData *)user_data)->char_data.size()>0){
+    string str_type=((UserData *)user_data)->node->type();
+
+    Node::NXtype type=Node::CHAR;
+    vector<int> dims;
+    if(string_util::starts_with(str_type,"CHAR")){
+      // do nothing, this is the default value
+    }else if(str_type.substr(str_type.size()-1,str_type.size())==RIGHT){
+      int start=str_type.find(LEFT);
+      string str_dim=str_type.substr(start,str_type.size());
+      if(str_dim.size()>0){
+        dims=string_util::str_to_intVec(str_dim);
+      }else{
+        dims.push_back(1);
+      }
+      str_type=str_type.erase(start,str_type.size());
+               
+      if(!(string_util::starts_with(str_type,"NX_")))
+        str_type="NX_"+str_type;
+      type=node_type(str_type);
+    }
+
+    update_node_from_string(*(((UserData *)user_data)->node), 
+                            ((UserData *)user_data)->char_data,
+                            dims, type);
+
+  }
+
+  // purge character data
+  ((UserData *)user_data)->char_data.clear();
+
+  // close the node by moving pointers up to the parent
+  closeNode((UserData *)user_data);
+}
+
+static void my_characters(void *user_data, const xmlChar *ch, int len){
+  // convert the character array into something useful
+  string str=xml_util::xmlChar_to_str(ch,len);
+
+  // if the string is empty there is nothing to do
+  if(str.size()<=0) return;
+
+  // add the characters with a space between it and what was there
+  ((UserData *)user_data)->char_data+=str;
+
+#ifdef DEBUG_XML_RETRIEVER_DOM
+  std::cout << "characters: " << ((UserData *)user_data)->char_data
+            << std::endl;
+#endif
+
+}
+
+static void my_error(void *user_data, const char* msg, ...){
+  static const string SAX_ERROR="SAX_ERROR";
+
+  // get the rest of the arguments
+  va_list args;
+  va_start(args,msg);
+
+  // get the position of the error
+  int line=getLineNumber(context);
+  int col =getColumnNumber(context);
+
+  // print out the result
+  char str[70];
+  int num_out=vsprintf(str,msg,args);
+  cerr << SAX_ERROR << " [L" << line << " C" << col << "]: "<< str;
+
+  // clean up args
+  va_end(args);
+
+  // set the status to failure
+  ((UserData *)user_data)->status=-1;
+}
+
+static void my_fatalError(void *user_data, const char* msg, ...){
+  static const string FATAL_SAX_ERROR="FATAL_SAX_ERROR";
+
+  // get the rest of the arguments
+  va_list args;
+  va_start(args,msg);
+
+  // get the position of the error
+  int line=getLineNumber(context);
+  int col =getColumnNumber(context);
+
+  // print out the result
+  char str[70];
+  int num_out=vsprintf(str,msg,args);
+  cerr << FATAL_SAX_ERROR << " [L" << line << " C" << col << "]: "<< str;
+
+  // clean up args
+  va_end(args);
+
+  // set the status to failure
+  ((UserData *)user_data)->status=-1;
+}
+
+// contains all of the function pointers for dealing with parsing the file
+static xmlSAXHandler my_handler = {
+  NULL, // internalSubsetSAXFunc internalSubset;
+  NULL, // isStandaloneSAXFunc isStandalone;
+  NULL, // hasInternalSubsetSAXFunc hasInternalSubset;
+  NULL, // hasExternalSubsetSAXFunc hasExternalSubset;
+  NULL, // resolveEntitySAXFunc resolveEntity;
+  my_getEntity, // getEntitySAXFunc getEntity;
+  NULL, // entityDeclSAXFunc entityDecl;
+  NULL, // notationDeclSAXFunc notationDecl;
+  NULL, // attributeDeclSAXFunc attributeDecl;
+  NULL, // elementDeclSAXFunc elementDecl;
+  NULL, // unparsedEntityDeclSAXFunc unparsedEntityDecl;
+  NULL, // setDocumentLocatorSAXFunc setDocumentLocator;
+  my_startDocument, // startDocumentSAXFunc startDocument;
+  my_endDocument, // endDocumentSAXFunc endDocument;
+  my_startElement, // startElementSAXFunc startElement;
+  my_endElement, // endElementSAXFunc endElement;
+  NULL, // referenceSAXFunc reference;
+  my_characters, // charactersSAXFunc characters;
+  NULL, // ignorableWhitespaceSAXFunc ignorableWhitespace;
+  NULL, // processingInstructionSAXFunc processingInstruction;
+  NULL, // commentSAXFunc comment;
+  NULL, // warningSAXFunc warning;
+  my_error, // errorSAXFunc error;
+  my_fatalError, // fatalErrorSAXFunc fatalError;
+};
+
+static string parse_xml_file(const string &filename, TreeNode &tr){
+  // if necessary, create user data here
+  UserData user_data;
+  user_data.status=0;
+  user_data.error_msg=string();
+  user_data.char_data=string();
+  user_data.node=tr.begin();
+  user_data.tr=&tr;
+
+  // create context which is static so error messages can have line numbers
+  context=xmlCreateFileParserCtxt(filename.c_str());
+  context->sax=&my_handler;
+  context->userData=&user_data; // bind user data to context
+  int result=xmlParseDocument(context);
+
+  // return if the there was an error
+  if(result<0)
+    throw runtime_error("Error parsing document");
+  
+
+  context=NULL;
+  return string();
+}
+
+#ifdef DEBUG_XML_RETRIEVER_DOM
+void print_node(Node &node){
+  cout << "[" << node.is_data() << "]" << node.name() << ":" 
+       << node.type() << "  [";
+  int num=node.num_attr();
+  for( int i=0 ; i<num ; i++ ){
+    Attr attr=node.get_attr(i);
+    cout << attr.name() << ":" << attr.value();
+    if(i+1<num) cout << ",";
+  }
+  cout << "]"  << endl;
+}
+
+void print_tree(TreeNode &tr, TreeNodeIter it, TreeNodeIter end){
+  if(!tr.is_valid(it)) return;
+
+  int rootdepth=tr.depth(it);
+  while(it!=end){
+    for( int i=0 ; i<tr.depth(it)-rootdepth ; ++i)
+      cout << "  ";
+    print_node(*it);
+    //cout << it->name() << ":" << it->type() << endl;
+    ++it;
+  }
+}
+#endif
+
+extern std::string buildTree(const std::string &filename, tree<Node> &tr){
+#ifdef DEBUG_XML_RETRIEVER_DOM
+  cout << "buildTree(" << filename << ",tr)" << endl; // REMOVE
+#endif
+
+  // check that the filename is okay
+  if(filename.size()<=0)
+    throw invalid_argument("filename is empty");
+
+  // parse the file to build the tree
+  parse_xml_file(filename,tr);
+
+#ifdef DEBUG_XML_RETRIEVER_DOM
+  cout << "********** print tree(" << tr.size() << ")" << endl;
+  print_tree(tr,tr.begin(),tr.end());
+  cout << "********************" << endl;
+#endif
+
+  return string();
+}
diff --git a/applications/NXtranslate/text_xml/xml_retriever_dom.h b/applications/NXtranslate/text_xml/xml_retriever_dom.h
new file mode 100644
index 0000000..fe4c976
--- /dev/null
+++ b/applications/NXtranslate/text_xml/xml_retriever_dom.h
@@ -0,0 +1,15 @@
+#ifndef __XML_RETRIEVER_DOM_GUARD
+#define __XML_RETRIEVER_DOM_GUARD
+
+#include <string>
+#include "../tree.hh"
+#include "../node.h"
+
+/**
+ * This function takes the name of a file and converts it into a tree
+ * of nodes. The return string is empty unless warnings or recoverable
+ * errors were produced.
+ */
+extern std::string buildTree(const std::string &filename, tree<Node> &tr);
+
+#endif
diff --git a/applications/NXtranslate/tree.hh b/applications/NXtranslate/tree.hh
new file mode 100644
index 0000000..c9b569c
--- /dev/null
+++ b/applications/NXtranslate/tree.hh
@@ -0,0 +1,1921 @@
+/* 
+
+   $Id$
+
+   STL-like templated tree class.
+   Copyright (C) 2001  Kasper Peeters <k.peeters at damtp.cam.ac.uk>
+
+   See 
+  
+      http://www.damtp.cam.ac.uk/user/kp229/tree/
+
+   for more information and documentation. See the Changelog file for
+   other credits.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+   
+   TODO: - 'Move' members are long overdue; will hopefully be incorporated in the
+           next release.
+         - Fixed depth iterators do not iterate over the entire range if there
+           are 'holes' in the tree.
+         - If a range uses const iter_base& as end iterator, things will
+           inevitably go wrong, because upcast from iter_base to a non-sibling_iter
+           is incorrect. This upcast should be removed (and then all illegal uses
+           as previously in 'equal' will be flagged by the compiler). This requires
+           new copy constructors though.
+         - There's a bug in replace(sibling_iterator, ...) when the ranges
+           sit next to each other. Turned up in append_child(iter,iter)
+           but has been avoided now.
+         - "std::operator<" does not work correctly on our iterators, and for some
+           reason a globally defined template operator< did not get picked up. 
+           Using a comparison class now, but this should be investigated.
+*/
+
+#ifndef tree_hh_
+#define tree_hh_
+
+#include <cassert>
+#include <memory>
+#include <stdexcept>
+#include <iterator>
+#include <set>
+#include <cstddef>
+
+// HP-style construct/destroy have gone from the standard,
+// so here is a copy.
+
+namespace kp {
+
+template <class T1, class T2>
+inline void constructor(T1* p, T2& val) 
+   {
+   new ((void *) p) T1(val);
+   }
+
+template <class T1>
+inline void constructor(T1* p) 
+   {
+   new ((void *) p) T1;
+   }
+
+template <class T1>
+inline void destructor(T1* p)
+   {
+   p->~T1();
+   }
+
+};
+
+template<class T>
+class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8.
+   public:
+      tree_node_<T> *parent;
+      tree_node_<T> *first_child, *last_child;
+      tree_node_<T> *prev_sibling, *next_sibling;
+      T data;
+};
+
+template <class T, class tree_node_allocator = std::allocator<tree_node_<T> > >
+class tree {
+   protected:
+      typedef tree_node_<T> tree_node;
+   public:
+      typedef T value_type;
+
+      class iterator_base;
+      class pre_order_iterator;
+      class post_order_iterator;
+      class sibling_iterator;
+
+      tree();
+      tree(const T&);
+      tree(const iterator_base&);
+      tree(const tree<T, tree_node_allocator>&);
+      ~tree();
+      void operator=(const tree<T, tree_node_allocator>&);
+
+#ifdef __SGI_STL_PORT
+      class iterator_base : public stlport::bidirectional_iterator<T, ptrdiff_t> {
+#else
+      class iterator_base {
+#endif
+         public:
+            typedef T                               value_type;
+            typedef T*                              pointer;
+            typedef T&                              reference;
+            typedef size_t                          size_type;
+            typedef ptrdiff_t                       difference_type;
+            typedef std::bidirectional_iterator_tag iterator_category;
+
+            iterator_base();
+            iterator_base(tree_node *);
+
+            T&             operator*() const;
+            T*             operator->() const;
+
+            void         skip_children(); // do not iterate over children of this node
+            unsigned int number_of_children() const;
+
+            sibling_iterator begin() const;
+            sibling_iterator end() const;
+
+            tree_node *node;
+         protected:
+            bool skip_current_children_;
+      };
+
+      class pre_order_iterator : public iterator_base { 
+         public:
+            pre_order_iterator();
+            pre_order_iterator(tree_node *);
+            pre_order_iterator(const iterator_base&);
+            pre_order_iterator(const sibling_iterator&);
+
+            bool    operator==(const pre_order_iterator&) const;
+            bool    operator!=(const pre_order_iterator&) const;
+            pre_order_iterator&  operator++();
+            pre_order_iterator&  operator--();
+            pre_order_iterator   operator++(int);
+            pre_order_iterator   operator--(int);
+            pre_order_iterator&  operator+=(unsigned int);
+            pre_order_iterator&  operator-=(unsigned int);
+      };
+
+      class post_order_iterator : public iterator_base {
+         public:
+            post_order_iterator();
+            post_order_iterator(tree_node *);
+            post_order_iterator(const iterator_base&);
+            post_order_iterator(const sibling_iterator&);
+
+            bool    operator==(const post_order_iterator&) const;
+            bool    operator!=(const post_order_iterator&) const;
+            post_order_iterator&  operator++();
+            post_order_iterator&  operator--();
+            post_order_iterator   operator++(int);
+            post_order_iterator   operator--(int);
+            post_order_iterator&  operator+=(unsigned int);
+            post_order_iterator&  operator-=(unsigned int);
+
+            void descend_all();
+      };
+
+      typedef pre_order_iterator iterator;
+
+      class fixed_depth_iterator : public iterator_base {
+         public:
+            fixed_depth_iterator();
+            fixed_depth_iterator(tree_node *);
+            fixed_depth_iterator(const iterator_base&);
+            fixed_depth_iterator(const sibling_iterator&);
+            fixed_depth_iterator(const fixed_depth_iterator&);
+
+            bool    operator==(const fixed_depth_iterator&) const;
+            bool    operator!=(const fixed_depth_iterator&) const;
+            fixed_depth_iterator&  operator++();
+            fixed_depth_iterator&  operator--();
+            fixed_depth_iterator   operator++(int);
+            fixed_depth_iterator   operator--(int);
+            fixed_depth_iterator&  operator+=(unsigned int);
+            fixed_depth_iterator&  operator-=(unsigned int);
+
+            tree_node *first_parent_;
+         private:
+            void set_first_parent_();
+            void find_leftmost_parent_();
+      };
+
+      class sibling_iterator : public iterator_base {
+         public:
+            sibling_iterator();
+            sibling_iterator(tree_node *);
+            sibling_iterator(const sibling_iterator&);
+            sibling_iterator(const iterator_base&);
+
+            bool    operator==(const sibling_iterator&) const;
+            bool    operator!=(const sibling_iterator&) const;
+            sibling_iterator&  operator++();
+            sibling_iterator&  operator--();
+            sibling_iterator   operator++(int);
+            sibling_iterator   operator--(int);
+            sibling_iterator&  operator+=(unsigned int);
+            sibling_iterator&  operator-=(unsigned int);
+
+            tree_node *range_first() const;
+            tree_node *range_last() const;
+            tree_node *parent_;
+         private:
+            void set_parent_();
+      };
+
+      // begin/end of tree
+      pre_order_iterator   begin() const;
+      pre_order_iterator   end() const;
+      post_order_iterator  begin_post() const;
+      post_order_iterator  end_post() const;
+      fixed_depth_iterator begin_fixed(const iterator_base&, unsigned int) const;
+      fixed_depth_iterator end_fixed(const iterator_base&, unsigned int) const;
+      // begin/end of children of node
+      sibling_iterator     begin(const iterator_base&) const;
+      sibling_iterator     end(const iterator_base&) const;
+
+      template<typename iter> iter parent(iter) const;
+      sibling_iterator previous_sibling(const iterator_base&) const;
+      sibling_iterator next_sibling(const iterator_base&) const;
+
+      void     clear();
+      // erase element at position pointed to by iterator, increment iterator
+      template<typename iter> iter erase(iter);
+      // erase all children of the node pointed to by iterator
+      void     erase_children(const iterator_base&);
+
+      // insert node as last child of node pointed to by position (first one inserts empty node)
+      template<typename iter> iter append_child(iter position); 
+      template<typename iter> iter append_child(iter position, const T& x);
+      // the following two append nodes plus their children
+      template<typename iter> iter append_child(iter position, iter other_position);
+      template<typename iter> iter append_children(iter position, sibling_iterator from, sibling_iterator to);
+
+      // short-hand to insert topmost node in otherwise empty tree
+      pre_order_iterator set_head(const T& x);
+      // insert node as previous sibling of node pointed to by position
+      template<typename iter> iter insert(iter position, const T& x);
+      // specialisation: insert node as previous sibling of node pointed to by position
+      //pre_order_iterator insert(sibling_iterator position, const T& x);
+      sibling_iterator insert(sibling_iterator position, const T& x);
+      // insert node (with children) pointed to by subtree as previous sibling of node pointed to by position
+      template<typename iter> iter insert_subtree(iter position, const iterator_base& subtree);
+      // insert node as next sibling of node pointed to by position
+      template<typename iter> iter insert_after(iter position, const T& x);
+
+      // replace node at 'position' with other node (keeping same children); 'position' becomes invalid.
+      template<typename iter> iter replace(iter position, const T& x);
+      // replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above.
+      template<typename iter> iter replace(iter position, const iterator_base& from);
+      // replace string of siblings (plus their children) with copy of a new string (with children); see above
+      sibling_iterator replace(sibling_iterator orig_begin, sibling_iterator orig_end, 
+                               sibling_iterator new_begin,  sibling_iterator new_end); 
+
+      // move all children of node at 'position' to be siblings, returns position
+      template<typename iter> iter flatten(iter position);
+      // move nodes in range to be children of 'position'
+      template<typename iter> iter reparent(iter position, sibling_iterator begin, sibling_iterator end);
+      // ditto, the range being all children of the 'from' node
+      template<typename iter> iter reparent(iter position, iter from);
+
+      // new style move members, moving nodes plus children to a different 
+      template<typename iter> iter move_after(iter target, iter source);
+      template<typename iter> iter move_before(iter target, iter source);
+      template<typename iter> iter move_below(iter target, iter source);
+
+      // merge with other tree, creating new branches and leaves only if they are not already present
+      void     merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, 
+                     bool duplicate_leaves=false);
+      // sort (std::sort only moves values of nodes, this one moves children as well)
+      void     sort(sibling_iterator from, sibling_iterator to, bool deep=false);
+      template<class StrictWeakOrdering>
+      void     sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false);
+      // compare two ranges of nodes (compares nodes as well as tree structure)
+      template<typename iter>
+      bool     equal(const iter& one, const iter& two, const iter& three) const;
+      template<typename iter, class BinaryPredicate>
+      bool     equal(const iter& one, const iter& two, const iter& three, BinaryPredicate) const;
+      template<typename iter>
+      bool     equal_subtree(const iter& one, const iter& two) const;
+      template<typename iter, class BinaryPredicate>
+      bool     equal_subtree(const iter& one, const iter& two, BinaryPredicate) const;
+      // extract a new tree formed by the range of siblings plus all their children
+      tree     subtree(sibling_iterator from, sibling_iterator to) const;
+      void     subtree(tree&, sibling_iterator from, sibling_iterator to) const;
+      // exchange the node (plus subtree) with its sibling node (do nothing if no sibling present)
+      void     swap(sibling_iterator it);
+      // find a subtree
+//    template<class BinaryPredicate>
+//    iterator find_subtree(sibling_iterator, sibling_iterator, iterator from, iterator to, BinaryPredicate) const;
+      
+      // count the total number of nodes
+      int      size() const;
+      // check if tree is empty
+      bool     empty() const;
+      // compute the depth to the root
+      int      depth(const iterator_base&) const;
+      // count the number of children of node at position
+      unsigned int number_of_children(const iterator_base&) const;
+      // count the number of 'next' siblings of node at iterator
+      unsigned int number_of_siblings(const iterator_base&) const;
+      // determine whether node at position is in the subtrees with root in the range
+      bool     is_in_subtree(const iterator_base& position, const iterator_base& begin, 
+                             const iterator_base& end) const;
+      // determine whether the iterator is an 'end' iterator and thus not actually
+      // pointing to a node
+      bool     is_valid(const iterator_base&) const;
+
+      // determine the index of a node in the range of siblings to which it belongs.
+      unsigned int index(sibling_iterator it) const;
+      // inverse of 'index': return the n-th child of the node at position
+      sibling_iterator  child(const iterator_base& position, unsigned int) const;
+      
+      class iterator_base_less {
+         public:
+            bool operator()(const typename tree<T, tree_node_allocator>::iterator_base& one,
+                            const typename tree<T, tree_node_allocator>::iterator_base& two) const
+               {
+               return one.node < two.node;
+               }
+      };
+      tree_node *head, *feet;    // head/feet are always dummy; if an iterator points to them it is invalid
+   private:
+      tree_node_allocator alloc_;
+      void head_initialise_();
+      void copy_(const tree<T, tree_node_allocator>& other);
+      template<class StrictWeakOrdering>
+      class compare_nodes {
+         public:
+            bool operator()(const tree_node*, const tree_node *);
+      };
+};
+
+//template <class T, class tree_node_allocator>
+//class iterator_base_less {
+// public:
+//    bool operator()(const typename tree<T, tree_node_allocator>::iterator_base& one,
+//                  const typename tree<T, tree_node_allocator>::iterator_base& two) const
+//       {
+//       txtout << "operatorclass<" << one.node < two.node << std::endl;
+//       return one.node < two.node;
+//       }
+//};
+
+//template <class T, class tree_node_allocator>
+//bool operator<(const typename tree<T, tree_node_allocator>::iterator& one,
+//             const typename tree<T, tree_node_allocator>::iterator& two)
+// {
+// txtout << "operator< " << one.node < two.node << std::endl;
+// if(one.node < two.node) return true;
+// return false;
+// }
+
+template <class T, class tree_node_allocator>
+bool operator>(const typename tree<T, tree_node_allocator>::iterator_base& one,
+               const typename tree<T, tree_node_allocator>::iterator_base& two)
+   {
+   if(one.node > two.node) return true;
+   return false;
+   }
+
+
+
+// Tree
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::tree() 
+   {
+   head_initialise_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::tree(const T& x) 
+   {
+   head_initialise_();
+   set_head(x);
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::tree(const iterator_base& other)
+   {
+   head_initialise_();
+   set_head((*other));
+   replace(begin(), other);
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::~tree()
+   {
+   clear();
+   alloc_.deallocate(head,1);
+   alloc_.deallocate(feet,1);
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::head_initialise_() 
+   { 
+   head = alloc_.allocate(1,0); // MSVC does not have default second argument 
+   feet = alloc_.allocate(1,0);
+
+   head->parent=0;
+   head->first_child=0;
+   head->last_child=0;
+   head->prev_sibling=0; //head;
+   head->next_sibling=feet; //head;
+
+   feet->parent=0;
+   feet->first_child=0;
+   feet->last_child=0;
+   feet->prev_sibling=head;
+   feet->next_sibling=0;
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::operator=(const tree<T, tree_node_allocator>& other)
+   {
+   copy_(other);
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::tree(const tree<T, tree_node_allocator>& other)
+   {
+   head_initialise_();
+   copy_(other);
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::copy_(const tree<T, tree_node_allocator>& other) 
+   {
+   clear();
+   pre_order_iterator it=other.begin(), to=begin();
+   while(it!=other.end()) {
+      to=insert(to, (*it));
+      it.skip_children();
+      ++it;
+      }
+   to=begin();
+   it=other.begin();
+   while(it!=other.end()) {
+      to=replace(to, it);
+      to.skip_children();
+      it.skip_children();
+      ++to;
+      ++it;
+      }
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::clear()
+   {
+   if(head)
+      while(head->next_sibling!=feet)
+         erase(pre_order_iterator(head->next_sibling));
+   }
+
+template<class T, class tree_node_allocator> 
+void tree<T, tree_node_allocator>::erase_children(const iterator_base& it)
+   {
+   tree_node *cur=it.node->first_child;
+   tree_node *prev=0;
+
+   while(cur!=0) {
+      prev=cur;
+      cur=cur->next_sibling;
+      erase_children(pre_order_iterator(prev));
+      kp::destructor(&prev->data);
+      alloc_.deallocate(prev,1);
+      }
+   it.node->first_child=0;
+   it.node->last_child=0;
+   }
+
+template<class T, class tree_node_allocator> 
+template<class iter>
+iter tree<T, tree_node_allocator>::erase(iter it)
+   {
+   tree_node *cur=it.node;
+   assert(cur!=head);
+   iter ret=it;
+   ret.skip_children();
+   ++ret;
+   erase_children(it);
+   if(cur->prev_sibling==0) {
+      cur->parent->first_child=cur->next_sibling;
+      }
+   else {
+      cur->prev_sibling->next_sibling=cur->next_sibling;
+      }
+   if(cur->next_sibling==0) {
+      cur->parent->last_child=cur->prev_sibling;
+      }
+   else {
+      cur->next_sibling->prev_sibling=cur->prev_sibling;
+      }
+
+   kp::destructor(&cur->data);
+   alloc_.deallocate(cur,1);
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allocator>::begin() const
+   {
+   return pre_order_iterator(head->next_sibling);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allocator>::end() const
+   {
+   return pre_order_iterator(feet);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator tree<T, tree_node_allocator>::begin_post() const
+   {
+   tree_node *tmp=head->next_sibling;
+   if(tmp!=feet) {
+      while(tmp->first_child)
+         tmp=tmp->first_child;
+      }
+   return post_order_iterator(tmp);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator tree<T, tree_node_allocator>::end_post() const
+   {
+   return post_order_iterator(feet);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator tree<T, tree_node_allocator>::begin_fixed(const iterator_base& pos, unsigned int dp) const
+   {
+   tree_node *tmp=pos.node;
+   unsigned int curdepth=0;
+   while(curdepth<dp) { // go down one level
+      while(tmp->first_child==0) {
+         tmp=tmp->next_sibling;
+         if(tmp==0)
+            throw std::range_error("tree: begin_fixed out of range");
+         }
+      tmp=tmp->first_child;
+      ++curdepth;
+      }
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator tree<T, tree_node_allocator>::end_fixed(const iterator_base& pos, unsigned int dp) const
+   {
+   assert(1==0); // FIXME: not correct yet
+   tree_node *tmp=pos.node;
+   unsigned int curdepth=1;
+   while(curdepth<dp) { // go down one level
+      while(tmp->first_child==0) {
+         tmp=tmp->next_sibling;
+         if(tmp==0)
+            throw std::range_error("tree: end_fixed out of range");
+         }
+      tmp=tmp->first_child;
+      ++curdepth;
+      }
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::begin(const iterator_base& pos) const
+   {
+   if(pos.node->first_child==0) {
+      return end(pos);
+      }
+   return pos.node->first_child;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::end(const iterator_base& pos) const
+   {
+   sibling_iterator ret(0);
+   ret.parent_=pos.node;
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter>
+iter tree<T, tree_node_allocator>::parent(iter position) const
+   {
+   assert(position.node!=0);
+   return iter(position.node->parent);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::previous_sibling(const iterator_base& position) const
+   {
+   assert(position.node!=0);
+   return sibling_iterator(position.node->prev_sibling);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::next_sibling(const iterator_base& position) const
+   {
+   assert(position.node!=0);
+   if(position.node->next_sibling==0)
+      return end(pre_order_iterator(position.node->parent));
+   else
+      return sibling_iterator(position.node->next_sibling);
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter>
+iter tree<T, tree_node_allocator>::append_child(iter position)
+   {
+   assert(position.node!=head);
+
+   tree_node* tmp = alloc_.allocate(1,0);
+   kp::constructor(&tmp->data);
+   tmp->first_child=0;
+   tmp->last_child=0;
+
+   tmp->parent=position.node;
+   if(position.node->last_child!=0) {
+      position.node->last_child->next_sibling=tmp;
+      }
+   else {
+      position.node->first_child=tmp;
+      }
+   tmp->prev_sibling=position.node->last_child;
+   position.node->last_child=tmp;
+   tmp->next_sibling=0;
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::append_child(iter position, const T& x)
+   {
+   // If your program fails here you probably used 'append_child' to add the top
+   // node to an empty tree. From version 1.45 the top element should be added
+   // using 'insert'. See the documentation for further information, and sorry about
+   // the API change.
+   assert(position.node!=head);
+
+   tree_node* tmp = alloc_.allocate(1,0);
+   kp::constructor(&tmp->data, x);
+   tmp->first_child=0;
+   tmp->last_child=0;
+
+   tmp->parent=position.node;
+   if(position.node->last_child!=0) {
+      position.node->last_child->next_sibling=tmp;
+      }
+   else {
+      position.node->first_child=tmp;
+      }
+   tmp->prev_sibling=position.node->last_child;
+   position.node->last_child=tmp;
+   tmp->next_sibling=0;
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::append_child(iter position, iter other)
+   {
+   assert(position.node!=head);
+
+   sibling_iterator aargh=append_child(position, value_type());
+   return replace(aargh, other);
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::append_children(iter position, sibling_iterator from, sibling_iterator to)
+   {
+   iter ret=from;
+
+   while(from!=to) {
+      insert_subtree(position.end(), from);
+      ++from;
+      }
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allocator>::set_head(const T& x)
+   {
+   assert(head->next_sibling==feet);
+   return insert(iterator(feet), x);
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::insert(iter position, const T& x)
+   {
+   if(position.node==0) {
+      position.node=feet; // Backward compatibility: when calling insert on a null node,
+                          // insert before the feet.
+      }
+   tree_node* tmp = alloc_.allocate(1,0);
+   kp::constructor(&tmp->data, x);
+   tmp->first_child=0;
+   tmp->last_child=0;
+
+   tmp->parent=position.node->parent;
+   tmp->next_sibling=position.node;
+   tmp->prev_sibling=position.node->prev_sibling;
+   position.node->prev_sibling=tmp;
+
+   if(tmp->prev_sibling==0)
+      tmp->parent->first_child=tmp;
+   else
+      tmp->prev_sibling->next_sibling=tmp;
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::insert(sibling_iterator position, const T& x)
+   {
+   tree_node* tmp = alloc_.allocate(1,0);
+   kp::constructor(&tmp->data, x);
+   tmp->first_child=0;
+   tmp->last_child=0;
+
+   tmp->next_sibling=position.node;
+   if(position.node==0) { // iterator points to end of a subtree
+      tmp->parent=position.parent_;
+      tmp->prev_sibling=position.range_last();
+      tmp->parent->last_child=tmp;
+      }
+   else {
+      tmp->parent=position.node->parent;
+      tmp->prev_sibling=position.node->prev_sibling;
+      position.node->prev_sibling=tmp;
+      }
+
+   if(tmp->prev_sibling==0)
+      tmp->parent->first_child=tmp;
+   else
+      tmp->prev_sibling->next_sibling=tmp;
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::insert_after(iter position, const T& x)
+   {
+   tree_node* tmp = alloc_.allocate(1,0);
+   kp::constructor(&tmp->data, x);
+   tmp->first_child=0;
+   tmp->last_child=0;
+
+   tmp->parent=position.node->parent;
+   tmp->prev_sibling=position.node;
+   tmp->next_sibling=position.node->next_sibling;
+   position.node->next_sibling=tmp;
+
+   if(tmp->next_sibling==0) {
+      if(tmp->parent) // when adding nodes at the head, there is no parent
+         tmp->parent->last_child=tmp;
+      }
+   else {
+      tmp->next_sibling->prev_sibling=tmp;
+      }
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::insert_subtree(iter position, const iterator_base& subtree)
+   {
+   // insert dummy
+   iter it=insert(position, value_type());
+   // replace dummy with subtree
+   return replace(it, subtree);
+   }
+
+// template <class T, class tree_node_allocator>
+// template <class iter>
+// iter tree<T, tree_node_allocator>::insert_subtree(sibling_iterator position, iter subtree)
+//    {
+//    // insert dummy
+//    iter it(insert(position, value_type()));
+//    // replace dummy with subtree
+//    return replace(it, subtree);
+//    }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::replace(iter position, const T& x)
+   {
+   kp::destructor(&position.node->data);
+   kp::constructor(&position.node->data, x);
+   return position;
+   }
+
+template <class T, class tree_node_allocator>
+template <class iter>
+iter tree<T, tree_node_allocator>::replace(iter position, const iterator_base& from)
+   {
+   assert(position.node!=head);
+   tree_node *current_from=from.node;
+   tree_node *start_from=from.node;
+   tree_node *current_to  =position.node;
+
+   // replace the node at position with head of the replacement tree at from
+   erase_children(position);  
+   tree_node* tmp = alloc_.allocate(1,0);
+   kp::constructor(&tmp->data, (*from));
+   tmp->first_child=0;
+   tmp->last_child=0;
+   if(current_to->prev_sibling==0) {
+      current_to->parent->first_child=tmp;
+      }
+   else {
+      current_to->prev_sibling->next_sibling=tmp;
+      }
+   tmp->prev_sibling=current_to->prev_sibling;
+   if(current_to->next_sibling==0) {
+      current_to->parent->last_child=tmp;
+      }
+   else {
+      current_to->next_sibling->prev_sibling=tmp;
+      }
+   tmp->next_sibling=current_to->next_sibling;
+   tmp->parent=current_to->parent;
+   kp::destructor(&current_to->data);
+   alloc_.deallocate(current_to,1);
+   current_to=tmp;
+   
+   // only at this stage can we fix 'last'
+   tree_node *last=from.node->next_sibling;
+
+   pre_order_iterator toit=tmp;
+   // copy all children
+   do {
+      assert(current_from!=0);
+      if(current_from->first_child != 0) {
+         current_from=current_from->first_child;
+         toit=append_child(toit, current_from->data);
+         }
+      else {
+         while(current_from->next_sibling==0 && current_from!=start_from) {
+            current_from=current_from->parent;
+            toit=parent(toit);
+            assert(current_from!=0);
+            }
+         current_from=current_from->next_sibling;
+         if(current_from!=last) {
+            toit=append_child(parent(toit), current_from->data);
+            }
+         }
+      } while(current_from!=last);
+
+   return current_to;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::replace(
+   sibling_iterator orig_begin, 
+   sibling_iterator orig_end, 
+   sibling_iterator new_begin, 
+   sibling_iterator new_end)
+   {
+   tree_node *orig_first=orig_begin.node;
+   tree_node *new_first=new_begin.node;
+   tree_node *orig_last=orig_first;
+   while((++orig_begin)!=orig_end)
+      orig_last=orig_last->next_sibling;
+   tree_node *new_last=new_first;
+   while((++new_begin)!=new_end)
+      new_last=new_last->next_sibling;
+
+   // insert all siblings in new_first..new_last before orig_first
+   bool first=true;
+   pre_order_iterator ret;
+   while(1==1) {
+      pre_order_iterator tt=insert_subtree(pre_order_iterator(orig_first), pre_order_iterator(new_first));
+      if(first) {
+         ret=tt;
+         first=false;
+         }
+      if(new_first==new_last)
+         break;
+      new_first=new_first->next_sibling;
+      }
+
+   // erase old range of siblings
+   bool last=false;
+   tree_node *next=orig_first;
+   while(1==1) {
+      if(next==orig_last) 
+         last=true;
+      next=next->next_sibling;
+      erase((pre_order_iterator)orig_first);
+      if(last) 
+         break;
+      orig_first=next;
+      }
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter>
+iter tree<T, tree_node_allocator>::flatten(iter position)
+   {
+   if(position.node->first_child==0)
+      return position;
+
+   tree_node *tmp=position.node->first_child;
+   while(tmp) {
+      tmp->parent=position.node->parent;
+      tmp=tmp->next_sibling;
+      } 
+   if(position.node->next_sibling) {
+      position.node->last_child->next_sibling=position.node->next_sibling;
+      position.node->next_sibling->prev_sibling=position.node->last_child;
+      }
+   else {
+      position.node->parent->last_child=position.node->last_child;
+      }
+   position.node->next_sibling=position.node->first_child;
+   position.node->next_sibling->prev_sibling=position.node;
+   position.node->first_child=0;
+   position.node->last_child=0;
+
+   return position;
+   }
+
+
+template <class T, class tree_node_allocator>
+template <typename iter>
+iter tree<T, tree_node_allocator>::reparent(iter position, sibling_iterator begin, sibling_iterator end)
+   {
+   tree_node *first=begin.node;
+   tree_node *last=first;
+   if(begin==end) return begin;
+   // determine last node
+   while((++begin)!=end) {
+      last=last->next_sibling;
+      }
+   // move subtree
+   if(first->prev_sibling==0) {
+      first->parent->first_child=last->next_sibling;
+      }
+   else {
+      first->prev_sibling->next_sibling=last->next_sibling;
+      }
+   if(last->next_sibling==0) {
+      last->parent->last_child=first->prev_sibling;
+      }
+   else {
+      last->next_sibling->prev_sibling=first->prev_sibling;
+      }
+   if(position.node->first_child==0) {
+      position.node->first_child=first;
+      position.node->last_child=last;
+      first->prev_sibling=0;
+      }
+   else {
+      position.node->last_child->next_sibling=first;
+      first->prev_sibling=position.node->last_child;
+      position.node->last_child=last;
+      }
+   last->next_sibling=0;
+
+   tree_node *pos=first;
+   while(1==1) {
+      pos->parent=position.node;
+      if(pos==last) break;
+      pos=pos->next_sibling;
+      }
+
+   return first;
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter> iter tree<T, tree_node_allocator>::reparent(iter position, iter from)
+   {
+   if(from.node->first_child==0) return position;
+   return reparent(position, from.node->first_child, end(from));
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter> iter tree<T, tree_node_allocator>::move_before(iter target, iter source)
+   {
+   tree_node *dst=target.node;
+   tree_node *src=source.node;
+   assert(dst);
+   assert(src);
+
+   if(dst==src) return source;
+
+   // take src out of the tree
+   if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling;
+   else                     src->parent->first_child=src->next_sibling;
+   if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling;
+   else                     src->parent->last_child=src->prev_sibling;
+
+   // connect it to the new point
+   if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src;
+   else                     dst->parent->first_child=src;
+   src->prev_sibling=dst->prev_sibling;
+   dst->prev_sibling=src;
+   src->next_sibling=dst;
+   src->parent=dst->parent;
+   return src;
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::merge(sibling_iterator to1,   sibling_iterator to2,
+                                          sibling_iterator from1, sibling_iterator from2,
+                                          bool duplicate_leaves)
+   {
+   sibling_iterator fnd;
+   while(from1!=from2) {
+      if((fnd=std::find(to1, to2, (*from1))) != to2) { // element found
+         if(from1.begin()==from1.end()) { // full depth reached
+            if(duplicate_leaves)
+               append_child(parent(to1), (*from1));
+            }
+         else { // descend further
+            merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(), duplicate_leaves);
+            }
+         }
+      else { // element missing
+         insert_subtree(to2, from1);
+         }
+      ++from1;
+      }
+   }
+
+template <class T, class tree_node_allocator>
+template <class StrictWeakOrdering> 
+bool tree<T, tree_node_allocator>::compare_nodes<StrictWeakOrdering>::operator()(const tree_node *a, 
+                                                                                 const tree_node *b)
+   {
+   static StrictWeakOrdering comp;
+
+   return comp(a->data, b->data);
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::sort(sibling_iterator from, sibling_iterator to, bool deep)
+   {
+   std::less<T> comp;
+   sort(from, to, comp, deep);
+   }
+
+template <class T, class tree_node_allocator>
+template <class StrictWeakOrdering>
+void tree<T, tree_node_allocator>::sort(sibling_iterator from, sibling_iterator to, 
+                                        StrictWeakOrdering comp, bool deep)
+   {
+   if(from==to) return;
+   // make list of sorted nodes
+   // CHECK: if multiset stores equivalent nodes in the order in which they
+   // are inserted, then this routine should be called 'stable_sort'.
+   std::multiset<tree_node *, compare_nodes<StrictWeakOrdering> > nodes;
+   sibling_iterator it=from, it2=to;
+   while(it != to) {
+      nodes.insert(it.node);
+      ++it;
+      }
+   // reassemble
+   --it2;
+
+   // prev and next are the nodes before and after the sorted range
+   tree_node *prev=from.node->prev_sibling;
+   tree_node *next=it2.node->next_sibling;
+   typename std::multiset<tree_node *, compare_nodes<StrictWeakOrdering> >::iterator nit=nodes.begin(), eit=nodes.end();
+   if(prev==0) {
+      if((*nit)->parent!=0) // to catch "sorting the head" situations, when there is no parent
+         (*nit)->parent->first_child=(*nit);
+      }
+   else prev->next_sibling=(*nit);
+
+   --eit;
+   while(nit!=eit) {
+      (*nit)->prev_sibling=prev;
+      if(prev)
+         prev->next_sibling=(*nit);
+      prev=(*nit);
+      ++nit;
+      }
+   // prev now points to the last-but-one node in the sorted range
+   if(prev)
+      prev->next_sibling=(*eit);
+
+   // eit points to the last node in the sorted range.
+   (*eit)->next_sibling=next;
+   (*eit)->prev_sibling=prev; // missed in the loop above
+   if(next==0) {
+      if((*eit)->parent!=0) // to catch "sorting the head" situations, when there is no parent
+         (*eit)->parent->last_child=(*eit);
+      }
+   else next->prev_sibling=(*eit);
+
+   if(deep) {  // sort the children of each node too
+      sibling_iterator bcs(*nodes.begin());
+      sibling_iterator ecs(*eit);
+      ++ecs;
+      while(bcs!=ecs) {
+         sort(begin(bcs), end(bcs), comp, deep);
+         ++bcs;
+         }
+      }
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter>
+bool tree<T, tree_node_allocator>::equal(const iter& one_, const iter& two, const iter& three_) const
+   {
+   std::equal_to<T> comp;
+   return equal(one_, two, three_, comp);
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter>
+bool tree<T, tree_node_allocator>::equal_subtree(const iter& one_, const iter& two_) const
+   {
+   std::equal_to<T> comp;
+   return equal_subtree(one_, two_, comp);
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter, class BinaryPredicate>
+bool tree<T, tree_node_allocator>::equal(const iter& one_, const iter& two, const iter& three_, BinaryPredicate fun) const
+   {
+   pre_order_iterator one(one_), three(three_);
+
+// if(one==two && is_valid(three) && three.number_of_children()!=0)
+//    return false;
+   while(one!=two && is_valid(three)) {
+      if(!fun(*one,*three))
+         return false;
+      if(one.number_of_children()!=three.number_of_children()) 
+         return false;
+      ++one;
+      ++three;
+      }
+   return true;
+   }
+
+template <class T, class tree_node_allocator>
+template <typename iter, class BinaryPredicate>
+bool tree<T, tree_node_allocator>::equal_subtree(const iter& one_, const iter& two_, BinaryPredicate fun) const
+   {
+   pre_order_iterator one(one_), two(two_);
+
+   if(!fun(*one,*two)) return false;
+   if(number_of_children(one)!=number_of_children(two)) return false;
+   return equal(begin(one),end(one),begin(two),fun);
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator> tree<T, tree_node_allocator>::subtree(sibling_iterator from, sibling_iterator to) const
+   {
+   tree tmp;
+   tmp.set_head(value_type());
+   tmp.replace(tmp.begin(), tmp.end(), from, to);
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const
+   {
+   tmp.set_head(value_type());
+   tmp.replace(tmp.begin(), tmp.end(), from, to);
+   }
+
+template <class T, class tree_node_allocator>
+int tree<T, tree_node_allocator>::size() const
+   {
+   int i=0;
+   pre_order_iterator it=begin(), eit=end();
+   while(it!=eit) {
+      ++i;
+      ++it;
+      }
+   return i;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::empty() const
+   {
+   pre_order_iterator it=begin(), eit=end();
+   return (it==eit);
+   }
+
+template <class T, class tree_node_allocator>
+int tree<T, tree_node_allocator>::depth(const iterator_base& it) const
+   {
+   tree_node* pos=it.node;
+   assert(pos!=0);
+   int ret=0;
+   while(pos->parent!=0) {
+      pos=pos->parent;
+      ++ret;
+      }
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+unsigned int tree<T, tree_node_allocator>::number_of_children(const iterator_base& it) const
+   {
+   tree_node *pos=it.node->first_child;
+   if(pos==0) return 0;
+   
+   unsigned int ret=1;
+//   while(pos!=it.node->last_child) {
+//      ++ret;
+//      pos=pos->next_sibling;
+//      }
+   while((pos=pos->next_sibling))
+      ++ret;
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+unsigned int tree<T, tree_node_allocator>::number_of_siblings(const iterator_base& it) const
+   {
+   tree_node *pos=it.node;
+   unsigned int ret=1;
+   while(pos->next_sibling && pos->next_sibling!=head) {
+      ++ret;
+      pos=pos->next_sibling;
+      }
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::swap(sibling_iterator it)
+   {
+   tree_node *nxt=it.node->next_sibling;
+   if(nxt) {
+      if(it.node->prev_sibling)
+         it.node->prev_sibling->next_sibling=nxt;
+      else
+         it.node->parent->first_child=nxt;
+      nxt->prev_sibling=it.node->prev_sibling;
+      tree_node *nxtnxt=nxt->next_sibling;
+      if(nxtnxt)
+         nxtnxt->prev_sibling=it.node;
+      else
+         it.node->parent->last_child=it.node;
+      nxt->next_sibling=it.node;
+      it.node->prev_sibling=nxt;
+      it.node->next_sibling=nxtnxt;
+      }
+   }
+
+// template <class BinaryPredicate>
+// tree<T, tree_node_allocator>::iterator tree<T, tree_node_allocator>::find_subtree(
+//    sibling_iterator subfrom, sibling_iterator subto, iterator from, iterator to, 
+//    BinaryPredicate fun) const
+//    {
+//    assert(1==0); // this routine is not finished yet.
+//    while(from!=to) {
+//       if(fun(*subfrom, *from)) {
+//          
+//          }
+//       }
+//    return to;
+//    }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::is_in_subtree(const iterator_base& it, const iterator_base& begin, 
+                                                 const iterator_base& end) const
+   {
+   // FIXME: this should be optimised.
+   pre_order_iterator tmp=begin;
+   while(tmp!=end) {
+      if(tmp==it) return true;
+      ++tmp;
+      }
+   return false;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::is_valid(const iterator_base& it) const
+   {
+   if(it.node==0 || it.node==feet) return false;
+   else return true;
+   }
+
+template <class T, class tree_node_allocator>
+unsigned int tree<T, tree_node_allocator>::index(sibling_iterator it) const
+   {
+   unsigned int ind=0;
+   if(it.node->parent==0) {
+      while(it.node->prev_sibling!=head) {
+         it.node=it.node->prev_sibling;
+         ++ind;
+         }
+      }
+   else {
+      while(it.node->prev_sibling!=0) {
+         it.node=it.node->prev_sibling;
+         ++ind;
+         }
+      }
+   return ind;
+   }
+
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::child(const iterator_base& it, unsigned int num) const
+   {
+   tree_node *tmp=it.node->first_child;
+   while(num--) {
+      assert(tmp!=0);
+      tmp=tmp->next_sibling;
+      }
+   return tmp;
+   }
+
+
+
+
+// Iterator base
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::iterator_base::iterator_base()
+   : node(0), skip_current_children_(false)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::iterator_base::iterator_base(tree_node *tn)
+   : node(tn), skip_current_children_(false)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+T& tree<T, tree_node_allocator>::iterator_base::operator*() const
+   {
+   return node->data;
+   }
+
+template <class T, class tree_node_allocator>
+T* tree<T, tree_node_allocator>::iterator_base::operator->() const
+   {
+   return &(node->data);
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::post_order_iterator::operator!=(const post_order_iterator& other) const
+   {
+   if(other.node!=this->node) return true;
+   else return false;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::post_order_iterator::operator==(const post_order_iterator& other) const
+   {
+   if(other.node==this->node) return true;
+   else return false;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::pre_order_iterator::operator!=(const pre_order_iterator& other) const
+   {
+   if(other.node!=this->node) return true;
+   else return false;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::pre_order_iterator::operator==(const pre_order_iterator& other) const
+   {
+   if(other.node==this->node) return true;
+   else return false;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::sibling_iterator::operator!=(const sibling_iterator& other) const
+   {
+   if(other.node!=this->node) return true;
+   else return false;
+   }
+
+template <class T, class tree_node_allocator>
+bool tree<T, tree_node_allocator>::sibling_iterator::operator==(const sibling_iterator& other) const
+   {
+   if(other.node==this->node) return true;
+   else return false;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::iterator_base::begin() const
+   {
+   sibling_iterator ret(node->first_child);
+   ret.parent_=this->node;
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::iterator_base::end() const
+   {
+   sibling_iterator ret(0);
+   ret.parent_=node;
+   return ret;
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::iterator_base::skip_children()
+   {
+   skip_current_children_=true;
+   }
+
+template <class T, class tree_node_allocator>
+unsigned int tree<T, tree_node_allocator>::iterator_base::number_of_children() const
+   {
+   tree_node *pos=node->first_child;
+   if(pos==0) return 0;
+   
+   unsigned int ret=1;
+   while(pos!=node->last_child) {
+      ++ret;
+      pos=pos->next_sibling;
+      }
+   return ret;
+   }
+
+
+
+// Pre-order iterator
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::pre_order_iterator::pre_order_iterator() 
+   : iterator_base(0)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::pre_order_iterator::pre_order_iterator(tree_node *tn)
+   : iterator_base(tn)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::pre_order_iterator::pre_order_iterator(const iterator_base &other)
+   : iterator_base(other.node)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::pre_order_iterator::pre_order_iterator(const sibling_iterator& other)
+   : iterator_base(other.node)
+   {
+   if(this->node==0) {
+      if(other.range_last()!=0)
+         this->node=other.range_last();
+      else 
+         this->node=other.parent_;
+      this->skip_children();
+      ++(*this);
+      }
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator& tree<T, tree_node_allocator>::pre_order_iterator::operator++()
+   {
+   assert(this->node!=0);
+   if(!this->skip_current_children_ && this->node->first_child != 0) {
+      this->node=this->node->first_child;
+      }
+   else {
+      this->skip_current_children_=false;
+      while(this->node->next_sibling==0) {
+         this->node=this->node->parent;
+         if(this->node==0)
+            return *this;
+         }
+      this->node=this->node->next_sibling;
+      }
+   return *this;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator& tree<T, tree_node_allocator>::pre_order_iterator::operator--()
+   {
+   assert(this->node!=0);
+   if(this->node->prev_sibling) {
+      this->node=this->node->prev_sibling;
+      while(this->node->last_child)
+         this->node=this->node->last_child;
+      }
+   else {
+      this->node=this->node->parent;
+      if(this->node==0)
+         return *this;
+      }
+   return *this;
+}
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allocator>::pre_order_iterator::operator++(int n)
+   {
+   pre_order_iterator copy = *this;
+   ++(*this);
+   return copy;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator tree<T, tree_node_allocator>::pre_order_iterator::operator--(int n)
+{
+  pre_order_iterator copy = *this;
+  --(*this);
+  return copy;
+}
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator& tree<T, tree_node_allocator>::pre_order_iterator::operator+=(unsigned int num)
+   {
+   while(num>0) {
+      ++(*this);
+      --num;
+      }
+   return (*this);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::pre_order_iterator& tree<T, tree_node_allocator>::pre_order_iterator::operator-=(unsigned int num)
+   {
+   while(num>0) {
+      --(*this);
+      --num;
+      }
+   return (*this);
+   }
+
+
+
+// Post-order iterator
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::post_order_iterator::post_order_iterator() 
+   : iterator_base(0)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::post_order_iterator::post_order_iterator(tree_node *tn)
+   : iterator_base(tn)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::post_order_iterator::post_order_iterator(const iterator_base &other)
+   : iterator_base(other.node)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::post_order_iterator::post_order_iterator(const sibling_iterator& other)
+   : iterator_base(other.node)
+   {
+   if(this->node==0) {
+      if(other.range_last()!=0)
+         this->node=other.range_last();
+      else 
+         this->node=other.parent_;
+      this->skip_children();
+      ++(*this);
+      }
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator& tree<T, tree_node_allocator>::post_order_iterator::operator++()
+   {
+   assert(this->node!=0);
+   if(this->node->next_sibling==0) 
+      this->node=this->node->parent;
+   else {
+      this->node=this->node->next_sibling;
+      if(this->skip_current_children_) {
+         this->skip_current_children_=false;
+         }
+      else {
+         while(this->node->first_child)
+            this->node=this->node->first_child;
+         }
+      }
+   return *this;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator& tree<T, tree_node_allocator>::post_order_iterator::operator--()
+   {
+   assert(this->node!=0);
+   if(this->skip_current_children_ || this->node->last_child==0) {
+      this->skip_current_children_=false;
+      while(this->node->prev_sibling==0)
+         this->node=this->node->parent;
+      this->node=this->node->prev_sibling;
+      }
+   else {
+      this->node=this->node->last_child;
+      }
+   return *this;
+}
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator tree<T, tree_node_allocator>::post_order_iterator::operator++(int)
+   {
+   post_order_iterator copy = *this;
+   ++(*this);
+   return copy;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator tree<T, tree_node_allocator>::post_order_iterator::operator--(int)
+   {
+   post_order_iterator copy = *this;
+   --(*this);
+   return copy;
+   }
+
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator& tree<T, tree_node_allocator>::post_order_iterator::operator+=(unsigned int num)
+   {
+   while(num>0) {
+      ++(*this);
+      --num;
+      }
+   return (*this);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::post_order_iterator& tree<T, tree_node_allocator>::post_order_iterator::operator-=(unsigned int num)
+   {
+   while(num>0) {
+      --(*this);
+      --num;
+      }
+   return (*this);
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::post_order_iterator::descend_all()
+   {
+   assert(this->node!=0);
+   while(this->node->first_child)
+      this->node=this->node->first_child;
+   }
+
+
+// Fixed depth iterator
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::fixed_depth_iterator::fixed_depth_iterator()
+   : iterator_base()
+   {
+   set_first_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::fixed_depth_iterator::fixed_depth_iterator(tree_node *tn)
+   : iterator_base(tn)
+   {
+   set_first_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::fixed_depth_iterator::fixed_depth_iterator(const iterator_base& other)
+   : iterator_base(other.node)
+   {
+   set_first_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::fixed_depth_iterator::fixed_depth_iterator(const sibling_iterator& other)
+   : iterator_base(other.node), first_parent_(other.parent_)
+   {
+   find_leftmost_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::fixed_depth_iterator::fixed_depth_iterator(const fixed_depth_iterator& other)
+   : iterator_base(other.node), first_parent_(other.first_parent_)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::fixed_depth_iterator::set_first_parent_()
+   {
+   return; // FIXME: we do not use first_parent_ yet, and it actually needs some serious reworking if
+           // it is ever to work at the 'head' level.
+   first_parent_=0;
+   if(this->node==0) return;
+   if(this->node->parent!=0)
+      first_parent_=this->node->parent;
+   if(first_parent_)
+      find_leftmost_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::fixed_depth_iterator::find_leftmost_parent_()
+   {
+   return; // FIXME: see 'set_first_parent()'
+   tree_node *tmppar=first_parent_;
+   while(tmppar->prev_sibling) {
+      tmppar=tmppar->prev_sibling;
+      if(tmppar->first_child)
+         first_parent_=tmppar;
+      }
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator& tree<T, tree_node_allocator>::fixed_depth_iterator::operator++()
+   {
+   assert(this->node!=0);
+   if(this->node->next_sibling!=0) {
+      this->node=this->node->next_sibling;
+      assert(this->node!=0);
+      if(this->node->parent==0 && this->node->next_sibling==0) // feet element
+         this->node=0;
+      }
+   else {
+      tree_node *par=this->node->parent;
+      do {
+         par=par->next_sibling;
+         if(par==0) { // FIXME: need to keep track of this!
+            this->node=0;
+            return *this;
+            }
+         } while(par->first_child==0);
+      this->node=par->first_child;
+      }
+   return *this;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator& tree<T, tree_node_allocator>::fixed_depth_iterator::operator--()
+   {
+   assert(this->node!=0);
+   if(this->node->prev_sibling!=0) {
+      this->node=this->node->prev_sibling;
+      assert(this->node!=0);
+      if(this->node->parent==0 && this->node->prev_sibling==0) // head element
+         this->node=0;
+      }
+   else {
+      tree_node *par=this->node->parent;
+      do {
+         par=par->prev_sibling;
+         if(par==0) { // FIXME: need to keep track of this!
+            this->node=0;
+            return *this;
+            }
+         } while(par->last_child==0);
+      this->node=par->last_child;
+      }
+   return *this;
+}
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator tree<T, tree_node_allocator>::fixed_depth_iterator::operator++(int)
+   {
+   fixed_depth_iterator copy = *this;
+   ++(*this);
+   return copy;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator tree<T, tree_node_allocator>::fixed_depth_iterator::operator--(int)
+{
+  fixed_depth_iterator copy = *this;
+  --(*this);
+  return copy;
+}
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator& tree<T, tree_node_allocator>::fixed_depth_iterator::operator-=(unsigned int num)
+   {
+   while(num>0) {
+      --(*this);
+      --(num);
+      }
+   return (*this);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::fixed_depth_iterator& tree<T, tree_node_allocator>::fixed_depth_iterator::operator+=(unsigned int num)
+   {
+   while(num>0) {
+      ++(*this);
+      --(num);
+      }
+   return *this;
+   }
+
+// FIXME: add the other members of fixed_depth_iterator.
+
+
+// Sibling iterator
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::sibling_iterator::sibling_iterator() 
+   : iterator_base()
+   {
+   set_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::sibling_iterator::sibling_iterator(tree_node *tn)
+   : iterator_base(tn)
+   {
+   set_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::sibling_iterator::sibling_iterator(const iterator_base& other)
+   : iterator_base(other.node)
+   {
+   set_parent_();
+   }
+
+template <class T, class tree_node_allocator>
+tree<T, tree_node_allocator>::sibling_iterator::sibling_iterator(const sibling_iterator& other)
+   : iterator_base(other), parent_(other.parent_)
+   {
+   }
+
+template <class T, class tree_node_allocator>
+void tree<T, tree_node_allocator>::sibling_iterator::set_parent_()
+   {
+   parent_=0;
+   if(this->node==0) return;
+   if(this->node->parent!=0)
+      parent_=this->node->parent;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator& tree<T, tree_node_allocator>::sibling_iterator::operator++()
+   {
+   if(this->node)
+      this->node=this->node->next_sibling;
+   return *this;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator& tree<T, tree_node_allocator>::sibling_iterator::operator--()
+   {
+   if(this->node) this->node=this->node->prev_sibling;
+   else {
+      assert(parent_);
+      this->node=parent_->last_child;
+      }
+   return *this;
+}
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::sibling_iterator::operator++(int)
+   {
+   sibling_iterator copy = *this;
+   ++(*this);
+   return copy;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator tree<T, tree_node_allocator>::sibling_iterator::operator--(int)
+   {
+   sibling_iterator copy = *this;
+   --(*this);
+   return copy;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator& tree<T, tree_node_allocator>::sibling_iterator::operator+=(unsigned int num)
+   {
+   while(num>0) {
+      ++(*this);
+      --num;
+      }
+   return (*this);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::sibling_iterator& tree<T, tree_node_allocator>::sibling_iterator::operator-=(unsigned int num)
+   {
+   while(num>0) {
+      --(*this);
+      --num;
+      }
+   return (*this);
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::tree_node *tree<T, tree_node_allocator>::sibling_iterator::range_first() const
+   {
+   tree_node *tmp=parent_->first_child;
+   return tmp;
+   }
+
+template <class T, class tree_node_allocator>
+typename tree<T, tree_node_allocator>::tree_node *tree<T, tree_node_allocator>::sibling_iterator::range_last() const
+   {
+   return parent_->last_child;
+   }
+
+
+#endif
+
+// Local variables:
+// default-tab-width: 3
+// End:
diff --git a/applications/NXtranslate/xml_parser.cpp b/applications/NXtranslate/xml_parser.cpp
new file mode 100644
index 0000000..70500a1
--- /dev/null
+++ b/applications/NXtranslate/xml_parser.cpp
@@ -0,0 +1,601 @@
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <iostream>
+#include <string>
+#include <cstring>
+#include <algorithm>
+#include <stdarg.h>
+#include <stdexcept>
+#include <vector>
+#include "nexus_util.h"
+#include "node.h"
+#include "node_util.h"
+#include "retriever.h"
+#include "string_util.h"
+#include "xml_parser.h"
+#include "xml_util.h"
+#include "Ptr.h"
+#include "tree.hh"
+#include "nxtranslate_debug.h"
+#ifdef USE_TIMING
+#include <sstream>
+#endif
+
+// ----- start of declaring debug levels
+#ifdef DEBUG3_XML_PARSER
+#define DEBUG2_XML_PARSER
+#endif
+#ifdef DEBUG2_XML_PARSER
+#define DEBUG1_XML_PARSER
+#endif
+// ----- end of declaring debug levels
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::exception;
+using std::invalid_argument;
+using std::map;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+typedef vector<string> StrVector;
+typedef vector<Node> NodeVector;
+typedef NodeVector* NodeVectorP;
+typedef Ptr<Retriever> RetrieverPtr;
+typedef tree<Node> NodeTree;
+
+static const int    GROUP_STRING_LEN  = 128;
+static const unsigned int   MAX_NODE_DEPTH    = 20;
+static const string DEFAULT_MIME_TYPE = "NeXus";
+static const string MIME_TYPE         = "NXS:mime_type";
+static const string SOURCE            = "NXS:source";
+static const string LOCATION          = "NXS:location";
+static const string COMPRESSION       = "NXS:compression";
+static const string LINK              = "NAPIlink";
+static const string TARGET            = "target";
+static const string TYPE              = "type";
+static const string NAME              = "name";
+static const string NXROOT            = "NXroot";
+static const string EXCEPTION         = "EXCEPTION";
+static const string INVALID_ARGUMENT  = "INVALID ARGUMENT";
+static const string RUNTIME_ERROR     = "RUNTIME ERROR";
+
+typedef struct{
+  NXhandle *handle;       // output file handle
+  int status;             // status of parsing
+  bool is_link;           // whether the current node is a link
+  std::map<string,string> map; // store macros for replacement
+  vector<StrVector> loc_to_source; // mapping for links
+  NodeVector nodes;       // vector to current node listing
+  string char_data;       // character data collected for current node
+  vector<int> dims;       // dimensions of the array in current node
+  vector<string> mime_types; // vector of mime_types (for nesting)
+  vector<RetrieverPtr> retrievers; // vector of retrievers (for nesting)
+}UserData;
+
+#ifdef USE_TIMING
+static time_t start_time = time(NULL);
+static time_t intermediate_time = time(NULL);
+extern string print_time(const time_t & start,
+                         const  time_t & stop) {
+  double seconds = difftime(stop, start);
+  long minutes = static_cast<long>(seconds/60.);
+  seconds = seconds - 60. * static_cast<double>(minutes);
+  std::stringstream result;
+  result << minutes << "m" << seconds  << "s";
+  return result.str();
+}
+#endif
+
+// variable so the line and column numbers can be accessed
+static xmlParserCtxtPtr context;
+
+/*
+ * Single place for printing out error messages generated by
+ * exceptions. This does set the user_data.status to -1.
+ */
+static void print_error(UserData *user_data, const string &message){
+  user_data->status=-1;
+  cerr << message << endl;
+}
+
+/*
+ * Replace the key with the correct value in the map, if it exists.
+ */
+static void map_string(map<string,string> &map,string &key){
+  // check that the key is non-zero size
+  if(key.size()<=0) return;
+
+  typedef std::map<string,string>::const_iterator map_iter;
+  map_iter it=map.find(key);
+  if(it!=map.end())
+    key=it->second;
+}
+
+/* unused code
+static bool is_left(char c){
+  static const string LEFT="[";
+  return find(LEFT.begin(),LEFT.end(),c)!=LEFT.end();
+}
+
+static bool is_right(char c){
+  static const string RIGHT="]";
+  return find(RIGHT.begin(),RIGHT.end(),c)!=RIGHT.end();
+}
+
+static StrVector split_on_bracket(const string str){
+  typedef string::size_type string_size;
+
+  string_size i=0;
+  string_size j=0;
+
+  // find LEFT
+  while(i<str.size() && !is_left(str[i]))
+    i++;
+
+  j=i;
+  // find right
+  while(j<str.size() && !is_right(str[j]))
+    j++;
+
+  // create the result
+  StrVector result;
+  result.push_back(str.substr(0,i));
+  result.push_back(str.substr(i+1,j-i-1));
+  return result;
+}
+*/
+
+#ifdef DEBUG1_XML_PARSER
+static void print_strvec(const StrVector &vec){
+  // print out the string vector
+  cout << "[";
+  for( StrVector::const_iterator str=vec.begin() ; str!=vec.end() ; str++ ){
+    cout << *str;
+    if(str+1!=vec.end())
+      cout << ",";
+  }
+  cout << "]" << endl;
+}
+
+static void print_retrievervec(const vector<RetrieverPtr> &vec){
+  cout << "[";
+  for(vector<RetrieverPtr>::const_iterator it=vec.begin();it!=vec.end();it++){
+    cout << (*it)->toString(); // a pointer to a Ptr
+    if(it+1!=vec.end())
+      cout << ",";
+  }
+  cout << "]" << endl;
+}
+#endif
+
+
+static void my_startDocument(void *user_data){
+  //cout << "startDocument" << endl; // REMOVE
+}
+
+static void my_endDocument(void *user_data){
+  //cout << "endDocument" << endl; // REMOVE
+}
+
+static void my_characters(void *user_data, const xmlChar *ch, int len){
+#ifdef DEBUG3_XML_PARSER
+  std::cout << "characters" << std::endl;
+#endif
+  // convert to a string
+  string str=xml_util::xmlChar_to_str(ch,len);
+  // if it is empty just return
+  if(str.size()<=0) return;
+
+  // add the characters with a space between it and what was there
+  ((UserData *)user_data)->char_data+=str;
+}
+
+static void my_startElement(void *user_data, const xmlChar *name,
+                                                       const xmlChar ** attrs){
+#ifdef DEBUG1_XML_PARSER
+  std::cout << "startElement(" << name << ")" << std::endl;
+#endif
+  static const string LEFT  = "[";
+  static const string RIGHT = "]";
+
+  // convert the name to a string
+  string str_name=xml_util::xmlChar_to_str(name,-1);
+  // create a label for the element when writing out exceptions
+  string except_label="<"+str_name+">:";
+  // convert the attributes to a vector<string>
+  StrVector str_attrs=xml_util::xmlattr_to_strvec(attrs);
+
+  // check if it is a link
+  bool is_link=(str_name==LINK);
+
+  // check for "name", "type", "source", "mime_type", "location",
+  // "target", "compression" attributes
+  string source;
+  string mime_type;
+  string location;
+  string compression;
+  string type;
+  bool update_dims=false;
+  vector<Attr> node_attrs;
+  for( StrVector::iterator it=str_attrs.begin() ; it!=str_attrs.end() ; it+=2){
+    if( (*it==SOURCE) || (*it==MIME_TYPE) || (*it==LOCATION) || (*it==TYPE)
+        || ((*it==TARGET) && (is_link)) || (*it==NAME) || (*it==COMPRESSION) ){
+      if(*it==SOURCE){
+        source=*(it+1);
+      }else if(*it==MIME_TYPE){
+        mime_type=*(it+1);
+      }else if(*it==LOCATION){
+        location=*(it+1);
+      }else if(*it==COMPRESSION){
+        compression=*(it+1);
+      }else if(*it==NAME){
+        type=str_name;
+        str_name=*(it+1);
+      }else if(*it==TYPE){
+        type=*(it+1);
+        if(string_util::starts_with(type,"NX_CHAR")){
+          type="NX_CHAR";
+        }else if(type.substr(type.size()-1,type.size())==RIGHT){
+          int start=type.find(LEFT);
+          string dim=type.substr(start,type.size());
+          if(dim.size()>0){
+            ((UserData *)user_data)->dims=string_util::str_to_intVec(dim);
+            update_dims=true;
+          }else{
+            ((UserData *)user_data)->dims.clear();
+            ((UserData *)user_data)->dims.push_back(1);
+          }
+          type=type.erase(start,type.size());
+        }else{
+          ((UserData *)user_data)->dims.clear();
+          ((UserData *)user_data)->dims.push_back(1);
+        }
+      }else if((is_link) && (*it==TARGET)){ // working with a link
+        StrVector str_vec;
+        NodeVector node_vec=((UserData *)user_data)->nodes;
+        for( NodeVector::const_iterator node_it=node_vec.begin() ; node_it!=node_vec.end() ; node_it++ ){
+          if(node_it->name()!=NXROOT)
+            str_vec.push_back(node_it->name());
+        }
+        ((UserData *)user_data)->loc_to_source.push_back(str_vec);
+        ((UserData *)user_data)->loc_to_source.push_back(string_util::string_to_path(*(it+1)));
+        type=LINK;
+      }
+      str_attrs.erase(it,it+2);
+      it-=2;
+    }else{ // everything else is an attribute
+      try{
+        node_attrs.push_back(make_attr(*it,*(it+1)));
+      }catch(std::invalid_argument &e){
+        print_error(((UserData *)user_data),INVALID_ARGUMENT+except_label+e.what());
+      }
+    }
+  }
+  ((UserData *)user_data)->is_link=is_link;
+
+  // if type is not defined (and it is not root) it is a character array
+  if( (type.size()<=0) && (str_name!=NXROOT) )
+    type="NX_CHAR";
+
+  // map everything using the macro replacement
+  map_string(((UserData *)user_data)->map,source);
+  map_string(((UserData *)user_data)->map,mime_type);
+  map_string(((UserData *)user_data)->map,location);
+
+  // set the mime_type
+  if(mime_type.size()<=0){
+    if(((UserData *)user_data)->mime_types.size()<=0)
+      mime_type=DEFAULT_MIME_TYPE;
+    else
+      mime_type=*(((UserData *)user_data)->mime_types.rbegin());
+  }
+  ((UserData *)user_data)->mime_types.push_back(mime_type);
+
+  // confirm that maximum node depth is not exceded
+  if(((UserData *)user_data)->mime_types.size()>MAX_NODE_DEPTH)
+    throw runtime_error("Exceded maximum node depth");
+
+  // create a new retriever if necessary
+  RetrieverPtr retriever(NULL);
+  if(source.size()>0 && mime_type.size()>0){
+    try{
+      retriever=Retriever::getInstance(mime_type,source);
+    }catch(runtime_error &e){
+      print_error(((UserData *)user_data),RUNTIME_ERROR+except_label+e.what());
+    }catch(exception &e){
+      print_error(((UserData *)user_data),EXCEPTION+except_label+e.what());
+    }
+  }else if(((UserData *)user_data)->retrievers.size()>0){
+    retriever=*(((UserData *)user_data)->retrievers.rbegin());
+  }
+  ((UserData *)user_data)->retrievers.push_back(retriever);
+
+  // create a new node
+  bool node_from_retriever=false;
+  Node node(str_name,type);  // default
+  tree<Node> tree;
+  if(location.size()>0 && retriever){ // if there is a location and a retriever
+    if(!(((UserData *)user_data)->status)){
+      try{
+        retriever->getData(location,tree);
+		  if (tree.size() <=0) {
+			  node_from_retriever=false;
+		  }
+		  else {
+			  tree.begin()->set_name(str_name);
+			  if( (tree.begin()->is_data()) && update_dims )
+				 tree.begin()->update_dims(((UserData *)user_data)->dims);
+			  node=*(tree.begin());
+			  node_from_retriever=true;
+		  }
+      }catch(invalid_argument &e){
+        print_error(((UserData *)user_data),INVALID_ARGUMENT+except_label+e.what());
+      }catch(runtime_error &e){
+        print_error(((UserData *)user_data),RUNTIME_ERROR+except_label+e.what());
+      }catch(exception &e){
+        print_error(((UserData *)user_data),EXCEPTION+except_label+e.what());
+      }
+    }
+  }
+
+  // set the compression flag
+  if(!compression.empty()){
+    if(node_from_retriever){
+      for( NodeTree::iterator it=tree.begin() ; it!=tree.end() ; ++it ){
+        it->set_comp(compression);
+      }
+    }else{
+      node.set_comp(compression);
+    }
+  }
+
+  // mutate the attributes if necessary
+  if(node_attrs.size()>0) {
+    if(node_from_retriever) {
+      tree.begin()->update_attrs(node_attrs);
+    } else {
+      node.update_attrs(node_attrs);
+    }
+  }
+
+  // add the node to the end of the vector
+  ((UserData *)user_data)->nodes.push_back(node);
+
+  // check that the node is a group or data
+  if(!is_link){
+    if(node_from_retriever){
+      NXhandle *handle=((UserData *)user_data)->handle;
+      // write the data to the file
+      try{
+        nexus_util::make_data(handle,tree);
+        nexus_util::open(handle,node);
+      }catch(runtime_error &e){
+        print_error(((UserData *)user_data),RUNTIME_ERROR+except_label+e.what());
+      }catch(exception &e){
+        print_error(((UserData *)user_data),EXCEPTION+except_label+e.what());
+      }
+    }else if( !node.is_data()){  // create group and open it
+      NXhandle *handle=((UserData *)user_data)->handle;
+      nexus_util::open(handle,node);
+    }
+  }
+}
+
+static void my_endElement(void *user_data, const xmlChar *name){
+#ifdef DEBUG1_XML_PARSER
+  std::cout << "endElement(" << name << ")" << std::endl;
+#endif
+
+  // an alias for whether the current node is a link
+  bool is_link=((UserData *)user_data)->is_link;
+
+  // create a label for the element when writing out exceptions
+  string except_label="</"+xml_util::xmlChar_to_str(name,-1)+">";
+
+  // get an alias to the node, this uses the copy constructor
+  Node node=*(((UserData *)user_data)->nodes.rbegin());
+  // get an alias to the handle
+  NXhandle *handle=((UserData *)user_data)->handle;
+  
+  // deal with character data if necessary
+  ((UserData *)user_data)->char_data
+    =string_util::trim(((UserData *)user_data)->char_data);
+  if(((UserData *)user_data)->char_data.size()>0){
+    // update the node with the character value
+    try{
+      try{
+          update_node_from_string(node,((UserData *)user_data)->char_data,
+                               ((UserData *)user_data)->dims, node.int_type());
+      }catch(runtime_error &e){
+        print_error(((UserData *)user_data),RUNTIME_ERROR+": "+except_label
+                    +e.what());
+      }
+    }catch(invalid_argument &e){
+      print_error(((UserData *)user_data),
+                                   INVALID_ARGUMENT+":"+except_label+e.what());
+      return;
+    }
+
+    // clear out the dimensions value
+    ((UserData *)user_data)->dims.clear();
+    // clear out the character value
+    ((UserData *)user_data)->char_data="";
+
+    // write the data to the file
+    if(!is_link){
+      nexus_util::open(handle,node);
+      try{
+        nexus_util::make_data(handle,node);
+      }catch(runtime_error &e){
+        print_error(((UserData *)user_data),RUNTIME_ERROR+except_label+e.what());
+      }catch(exception &e){
+        print_error(((UserData *)user_data),EXCEPTION+except_label+e.what());
+      }
+    }
+  }
+  
+  // close the node
+  if(is_link)
+    ((UserData *)user_data)->is_link=false;
+  else
+    nexus_util::close(handle,node);
+
+  // pop the node off of the end of the vector
+  ((UserData *)user_data)->nodes.pop_back();
+  // pop the mime_type off of the end of the vector
+  ((UserData *)user_data)->mime_types.pop_back();
+  // pop the retriever off of the end of the vector
+  ((UserData *)user_data)->retrievers.pop_back();
+}
+
+static xmlEntityPtr my_getEntity(void *user_data, const xmlChar *name){
+  return xmlGetPredefinedEntity(name);
+}
+
+static void my_error(void *user_data, const char* msg, ...){
+  static const string SAX_ERROR="SAX_ERROR";
+
+  // get the rest of the arguments
+  va_list args;
+  va_start(args,msg);
+
+  // get the position of the error
+  int line=getLineNumber(context);
+  int col =getColumnNumber(context);
+
+  // print out the result
+  char str[70];
+  int num_out=vsprintf(str,msg,args);
+  cerr << SAX_ERROR << " [L" << line << " C" << col << "]: "<< str;
+
+  // clean up args
+  va_end(args);
+
+  // set the status to failure
+  ((UserData *)user_data)->status=-1;
+}
+
+static void my_fatalError(void *user_data, const char* msg, ...){
+  static const string FATAL_SAX_ERROR="FATAL_SAX_ERROR";
+
+  // get the rest of the arguments
+  va_list args;
+  va_start(args,msg);
+
+  // get the position of the error
+  int line=getLineNumber(context);
+  int col =getColumnNumber(context);
+
+  // print out the result
+  char str[70];
+  int num_out=vsprintf(str,msg,args);
+  cerr << FATAL_SAX_ERROR << " [L" << line << " C" << col << "]: "<< str;
+
+  // clean up args
+  va_end(args);
+
+  // set the status to failure
+  ((UserData *)user_data)->status=-1;
+}
+
+static xmlSAXHandler my_handler = {
+  NULL, // internalSubsetSAXFunc internalSubset;
+  NULL, // isStandaloneSAXFunc isStandalone;
+  NULL, // hasInternalSubsetSAXFunc hasInternalSubset;
+  NULL, // hasExternalSubsetSAXFunc hasExternalSubset;
+  NULL, // resolveEntitySAXFunc resolveEntity;
+  my_getEntity, // getEntitySAXFunc getEntity;
+  NULL, // entityDeclSAXFunc entityDecl;
+  NULL, // notationDeclSAXFunc notationDecl;
+  NULL, // attributeDeclSAXFunc attributeDecl;
+  NULL, // elementDeclSAXFunc elementDecl;
+  NULL, // unparsedEntityDeclSAXFunc unparsedEntityDecl;
+  NULL, // setDocumentLocatorSAXFunc setDocumentLocator;
+  my_startDocument, // startDocumentSAXFunc startDocument;
+  my_endDocument, // endDocumentSAXFunc endDocument;
+  my_startElement, // startElementSAXFunc startElement;
+  my_endElement, // endElementSAXFunc endElement;
+  NULL, // referenceSAXFunc reference;
+  my_characters, // charactersSAXFunc characters;
+  NULL, // ignorableWhitespaceSAXFunc ignorableWhitespace;
+  NULL, // processingInstructionSAXFunc processingInstruction;
+  NULL, // commentSAXFunc comment;
+  NULL, // warningSAXFunc warning;
+  my_error, // errorSAXFunc error;
+  my_fatalError, // fatalErrorSAXFunc fatalError;
+};
+
+static bool resolve_links(UserData *user_data){
+  // check that this function will do anything
+  if(user_data->loc_to_source.size()<=0) return false;
+
+  // convenience for less typing
+  typedef vector<StrVector>::const_iterator vec_iter;
+
+  // loop over links in map
+  for( vec_iter it=user_data->loc_to_source.begin() ; it!=user_data->loc_to_source.end() ; it+=2 ){
+    nexus_util::make_link(user_data->handle,*it,*(it+1));
+  }
+
+
+  // return that everything went well
+  return false;
+}
+
+extern bool xml_parser::parse_xml_file(const std::map<string,string> &map,
+                                       const string &filename,
+                                       NXhandle *handle,
+                                       const bool timing){
+#ifdef DEBUG3_XML_PARSER
+  std::cout << "xml_parser::parse_xml_file" << std::endl;
+#endif
+  // set up the user data for use in the parser
+  UserData user_data;
+  user_data.handle=handle;
+  user_data.status=0;
+  user_data.is_link=false;
+  user_data.map=map;
+  user_data.mime_types.reserve(MAX_NODE_DEPTH);
+  user_data.dims.reserve(25);
+  user_data.retrievers.reserve(MAX_NODE_DEPTH);
+
+  // parse the translation file (context needed to get positions in the file)
+  context=xmlCreateFileParserCtxt(filename.c_str());
+  context->sax=&my_handler;
+  context->userData=&user_data;
+  int result=xmlParseDocument(context);
+
+  // return if there was an error
+  if(user_data.status)
+    return user_data.status; // return the error
+  else if(result<0)
+    return true; // return generic error
+
+#ifdef USE_TIMING
+  if (timing) {
+    cout << print_time(intermediate_time) << " to add new information" << endl;
+    intermediate_time = time(NULL);
+  }
+#endif
+
+  // work on links
+  try{
+    resolve_links(&user_data);
+  }catch(runtime_error &e){ // deal with problems
+    cerr << RUNTIME_ERROR << ": " << e.what() << endl;
+    return true;
+  }
+  
+#ifdef USE_TIMING
+  if (timing) {
+    cout << print_time(intermediate_time) << " to create links" << endl;
+    intermediate_time = time(NULL);
+  }
+#endif
+
+  // return that everything went well
+  return false;
+}
diff --git a/applications/NXtranslate/xml_parser.h b/applications/NXtranslate/xml_parser.h
new file mode 100644
index 0000000..7155601
--- /dev/null
+++ b/applications/NXtranslate/xml_parser.h
@@ -0,0 +1,21 @@
+#ifndef __XML_PARSER_H_GUARD
+#define __XML_PARSER_H_GUARD
+
+#include <string>
+#include <napi.h>
+#include <map>
+
+#ifdef USE_TIMING
+#include <time.h>
+#include <string>
+extern std::string print_time(const time_t & start,
+                         const  time_t & stop = time(NULL));
+#endif
+
+
+namespace xml_parser{
+  extern bool parse_xml_file(const std::map<std::string,std::string>&map,
+                             const std::string &filename, NXhandle *handle,
+                             const bool timing);
+};
+#endif
diff --git a/applications/NXtranslate/xml_util.cpp b/applications/NXtranslate/xml_util.cpp
new file mode 100644
index 0000000..3db7e22
--- /dev/null
+++ b/applications/NXtranslate/xml_util.cpp
@@ -0,0 +1,33 @@
+#include "xml_util.h"
+#include "string_util.h"
+
+using std::string;
+using std::vector;
+
+/*
+ * If len<0 then just return the whole string
+ */
+extern string xml_util::xmlChar_to_str(const xmlChar *ch, int len){
+  string result((char *)ch);
+  if( (len>0) && ((unsigned int)len<result.size()) )
+    result.erase(result.begin()+len,result.end());
+
+  return result;
+  //  return string_util::trim(result);
+}
+
+extern vector<string> xml_util::xmlattr_to_strvec(const xmlChar* char_array[]){
+  vector<string> result;
+  int i=0;
+  while(true){
+    if((char_array+i)==NULL || *(char_array+i)==NULL)
+      break;
+    else{
+      string str=xml_util::xmlChar_to_str(*(char_array+i),-1);
+      result.push_back(str);
+    }
+    i++;
+  }
+
+  return result;
+}
diff --git a/applications/NXtranslate/xml_util.h b/applications/NXtranslate/xml_util.h
new file mode 100644
index 0000000..2a87a3b
--- /dev/null
+++ b/applications/NXtranslate/xml_util.h
@@ -0,0 +1,14 @@
+#ifndef __XML_UTIL_H_GUARD
+#define __XML_UTIL_H_GUARD
+
+#include <libxml/parser.h>
+#include <string>
+#include <vector>
+
+namespace xml_util{
+  extern std::string xmlChar_to_str(const xmlChar *ch, int len);
+  extern std::vector<std::string> 
+                              xmlattr_to_strvec(const xmlChar* char_array[]);
+}
+
+#endif
diff --git a/applications/NXtraverse/CMakeLists.txt b/applications/NXtraverse/CMakeLists.txt
new file mode 100644
index 0000000..926297f
--- /dev/null
+++ b/applications/NXtraverse/CMakeLists.txt
@@ -0,0 +1,43 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+include_directories(../../third_party ../../bindings/cpp)
+
+add_executable (nxtraverse nxtraverse.cpp main.cpp nxtraverse.h)
+
+target_link_libraries(nxtraverse
+                      NeXus_CPP_Shared_Library 
+                      ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK}
+                      ${DF_LINK} ${TERMCAP_LINK} ${HISTORY_LINK})
+
+install (TARGETS nxtraverse
+         RUNTIME DESTINATION bin COMPONENT Runtime
+         LIBRARY DESTINATION lib COMPONENT Runtime
+         ARCHIVE DESTINATION lib/nexus COMPONENT Development)
+
+
diff --git a/applications/NXtraverse/Makefile.am b/applications/NXtraverse/Makefile.am
new file mode 100644
index 0000000..c135183
--- /dev/null
+++ b/applications/NXtraverse/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1239 2009-04-15 14:37:08Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include 
+
+#EXTRA_DIST=SConscript
+
+
+bin_PROGRAMS = nxtraverse
+
+nxtraverse_SOURCES = nxtraverse.cpp main.cpp nxtraverse.h
+nxtraverse_LDADD = $(LIBNEXUS)
+nxtraverse_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ $(LDFLAGS)
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/NXtraverse/main.cpp b/applications/NXtraverse/main.cpp
new file mode 100644
index 0000000..a010f9e
--- /dev/null
+++ b/applications/NXtraverse/main.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2010, P. Vicente <pedro.vicente at space-research.org>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <iostream>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nxtraverse.h"
+
+
+using namespace std;
+
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: print usage
+ *
+ * Return: void
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void usage(void)
+{
+    cout << "Usage: nxtraverse -f <filename> [-h] [-r] [-a] [-n N] " << endl;
+    cout << endl;
+    cout <<  "[-f]    traverse file <filename>" << endl;
+    cout <<  "[-h]    print this usage message and exit" << endl;
+    cout <<  "[-r]    do not read data" << endl;
+    cout <<  "[-a]    do not read attributes" << endl;
+    cout <<  "[-n]    print only N number of elements; N defaults to 5, * for all elements" << endl;
+  
+
+}
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: main function
+ *
+ * Return: Success: 0, Failure: 1
+ *
+ * Comments:
+ *
+ *-------------------------------------------------------------------------
+ */
+int main(int argc, const char **argv)
+{
+    CNXTraverse  nxtraverse;
+    int        i;
+    const char *fname = NULL;
+
+  
+    if ( argc < 2 )
+    {
+        usage();
+        return 1;
+
+    }
+
+    for ( i = 1; i < argc; i++) 
+    {
+
+        //help
+
+        if (strcmp(argv[i], "-h") == 0) 
+        {
+            usage();
+            return 0;
+        }
+
+        //file name
+
+        else if (strcmp(argv[i], "-f") == 0) 
+        {
+
+            if ( argv[++i] == NULL )
+            {
+                usage();
+                return 1;
+            }
+
+            fname = argv[i]; 
+
+        }
+
+        //do not read data
+
+        else if (strcmp(argv[i], "-r") == 0) 
+        {
+
+            nxtraverse.options.read_data = 0; 
+
+        }
+
+        //do not read attributes
+
+        else if (strcmp(argv[i], "-a") == 0) 
+        {
+
+            nxtraverse.options.read_attr = 0; 
+
+        }
+
+        //number of elements to print
+
+        else if (strcmp(argv[i], "-n") == 0) 
+        {
+
+            if ( argv[++i] == NULL )
+            {
+                usage();
+                return 1;
+            }
+            if ( strcmp(argv[i], "*") == 0 )
+            {
+
+                nxtraverse.options.all = 1;
+
+            }
+            else
+            {
+                nxtraverse.options.nelmts = atol( argv[i] ); 
+            }
+
+        }
+
+    }
+
+    if ( fname == NULL )
+    {
+        usage();
+        return 1;
+
+    }
+
+    if ( nxtraverse.show_objects ( fname ) == NX_ERROR  )
+        return 1;
+
+    return 0;
+}
+
+
+
diff --git a/applications/NXtraverse/nxtraverse.cpp b/applications/NXtraverse/nxtraverse.cpp
new file mode 100644
index 0000000..c5558f3
--- /dev/null
+++ b/applications/NXtraverse/nxtraverse.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2010, P. Vicente <pedro.vicente at space-research.org>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nxtraverse.h"
+
+
+
+using namespace std;
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+//CNXTraverse class
+//constructor
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+CNXTraverse::CNXTraverse ()
+{
+
+    options.read_data = 1; //read data by default
+    options.read_attr = 1; //read attributes by default
+    options.nelmts    = 5; //default printed number of elements
+    options.all       = 0; //default: do not print all elements
+
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+//CNXTraverse
+//destructor
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+CNXTraverse::~CNXTraverse ()
+{
+
+}
+
+
+
+/*-------------------------------------------------------------------------
+* Function: show_objects
+*
+* Purpose: traverse a NeXus file and print all objects
+*
+*-------------------------------------------------------------------------
+*/
+
+int CNXTraverse::show_objects(const char* file_name)
+{
+    NXhandle handle;
+  
+   // open file to traverse
+   if  (NXopen ( file_name, NXACC_READ, &handle) != NX_OK) 
+   {
+      printf ("NX_ERROR: Can't open %s\n", file_name);
+      return NX_ERROR;
+   }
+
+
+    // traverse
+    if ( traverse( handle,  "/"  ) == NX_ERROR )
+        goto out;
+
+    //close file
+    if ( NXclose (&handle) != NX_OK) 
+        return NX_ERROR;
+
+    return NX_OK;
+
+    //out
+
+out:
+   
+    NXclose (&handle);
+ 
+    return NX_ERROR;;
+}
+
+
+
+/*-------------------------------------------------------------------------
+* Function: traverse
+*
+* Purpose: recursive function that traverses a NeXus file and prints all objects
+*
+*
+*-------------------------------------------------------------------------
+*/
+
+int CNXTraverse::traverse( NXhandle handle, const char *grp_name  )
+{
+
+    NXname name, nxclass;
+    int nxdataype;
+    int num_groups;
+    std::string path;
+
+    if ( NXinitgroupdir (handle) != NX_OK) 
+        return NX_ERROR;
+
+    if ( NXgetgroupinfo( handle, &num_groups, name, nxclass) != NX_OK )
+        return NX_ERROR;
+
+    for ( int i = 0; i < num_groups; i++ )
+    {
+
+        if ( NXgetnextentry ( handle, name, nxclass, &nxdataype) == NX_ERROR ) 
+            return NX_ERROR;
+
+        if (strcmp(nxclass,"SDS") == 0)
+        {
+
+            
+            path = grp_name;
+            path += "/";
+            path += name;
+
+            if ( options.read_data )
+            {
+                //do not print end line, data will be appended to this line
+                cout << path << "=";
+
+                if ( show_dataset( handle, name, path.c_str() ) == NX_ERROR ) 
+                    return NX_ERROR;
+            }
+            else
+            {
+
+                //print name and end line
+                cout << path << endl;
+
+            }
+           
+
+        }
+        else
+        {
+
+
+            path = grp_name;
+            if ( path !=  "/" )
+            path += "/";
+            path += name;
+
+
+            cout << path << endl;
+
+            if ( NXopengroup( handle, name, nxclass ) != NX_OK )
+                return NX_ERROR;
+
+            if ( traverse( handle, path.c_str() ) != NX_OK )
+                return NX_ERROR;
+
+            if ( NXclosegroup( handle ) != NX_OK )
+                return NX_ERROR;
+
+      
+        }
+
+
+
+    }
+    
+
+    return NX_OK;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+* Function: show_dataset
+*
+* Purpose: read, display NeXus dataset
+*
+*
+*-------------------------------------------------------------------------
+*/
+
+int CNXTraverse::show_dataset( NXhandle handle, const char* dset_name, const char* path)
+{
+    int      rank;
+    int      dims[NX_MAXRANK];
+    int      nxdataype;
+    void     *buf=NULL;
+    uint64_t nelmts;
+
+    if ( NXopendata ( handle, dset_name) != NX_OK) 
+        goto out;
+
+    if ( NXgetinfo ( handle, &rank, dims, &nxdataype) != NX_OK) 
+        goto out;
+
+    if ( NXmalloc( &buf, rank, dims, nxdataype) != NX_OK)
+        goto out;
+
+    if ( NXgetdata( handle, buf) != NX_OK)
+        goto out;
+
+    //get number of elements
+    nelmts = 1;
+    for ( int i = 0; i < rank; i++)
+    {
+        nelmts *= dims[i];
+    }
+
+    //print
+    if ( print_data( nxdataype, nelmts, buf ) != NX_OK )
+        goto out;
+
+    if ( options.read_attr )
+    {
+
+        if ( read_attr( handle, dset_name, path ) == NX_ERROR ) 
+            return NX_ERROR;
+
+    }
+
+
+    if ( NXclosedata( handle) != NX_OK) 
+        goto out;
+
+    if ( NXfree (&buf) != NX_OK) 
+        goto out;
+
+
+
+
+    return NX_OK;
+
+    //out
+
+out:
+
+    if ( buf != NULL )
+    {
+        NXfree (&buf);
+    }
+
+    cout << "cannot open/read dataset" << dset_name << endl;
+    return NX_ERROR;
+}
+
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: read_attr
+ *
+ * Purpose: read, print, a NeXus attribute 
+ *
+ *-------------------------------------------------------------------------
+ */
+
+int CNXTraverse::read_attr( NXhandle handle, const char* dset_name, const char* path )
+{
+    char attr_name[128];
+    int  nxdataype;
+    int  num_attr;
+    int  length;
+    void *buf=NULL;
+
+    if ( NXinitattrdir( handle ) != NX_OK)
+        goto out;
+
+    // find the number of attributes
+
+    if ( NXgetattrinfo( handle, &num_attr )!=NX_OK)
+        goto out;
+
+    for ( int i = 0 ; i < num_attr ; i++ )
+    {
+        if ( NXgetnextattr( handle, attr_name, &length, &nxdataype ) != NX_OK)
+            goto out;
+
+        //print the path in front of attribute name
+
+        cout << path << "#" << attr_name << "=";
+
+        //read attribute
+
+        if ( NXmalloc( &buf, 1, &length, nxdataype) != NX_OK)
+            goto out;
+
+        if ( NXgetattr( handle, attr_name, buf, &length, &nxdataype) != NX_OK)
+            goto out;
+
+        //print
+
+        if ( print_data( nxdataype, length, buf ) != NX_OK )
+            goto out;
+
+        if ( NXfree (&buf) != NX_OK) 
+            goto out;
+
+    }
+
+
+
+    return NX_OK;
+
+    //out
+
+out:
+
+    if ( buf != NULL )
+    {
+        NXfree (&buf);
+    }
+
+    cout << "cannot open/read attribute" << dset_name << endl;
+    return NX_ERROR;
+}
+
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_data
+ *
+ * Purpose: print void* BUF into stdout
+ *
+ *-------------------------------------------------------------------------
+ */
+
+int CNXTraverse::print_data( int nxdataype, uint64_t nelmts, void* buf )
+{
+    unsigned char      *ucbuf = (unsigned char *)buf;
+    char               *cbuf = (char *)buf;
+    char               *s;
+    int                more;
+    uint64_t           n;
+    uint64_t           i; 
+    float              tempfloat;
+    double             tempdouble;
+    unsigned char      tempuchar;
+    signed char        tempschar;
+    int                tempint;
+    unsigned int       tempuint;
+    short              tempshort;
+    unsigned short     tempushort;
+    long long          templlong;
+    unsigned long long tempullong;
+  
+
+     //how many elements to print
+    if ( options.all )
+    {
+        n = nelmts;
+        more = 0;
+    }
+    else
+    {
+        n = ( nelmts < options.nelmts) ? nelmts : options.nelmts;
+        more = ( nelmts < options.nelmts) ? 0 : 1;
+    }
+
+
+
+    switch ( nxdataype )
+    {
+    default:
+        assert(0);
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_CHAR
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_CHAR:
+
+        s = cbuf;
+        if (s == NULL) 
+        {
+
+
+        }
+        else 
+        {
+            for ( unsigned int j = 0; j < nelmts; j++) 
+            {
+
+                printf( "%c", s[j] ); 
+
+            }
+
+        }
+
+        break;
+
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_INT8
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_INT8:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(signed char);
+            memcpy(&tempschar, mem, sizeof(signed char));
+            printf( "%d ", tempschar ); 
+         
+
+        }
+        if ( more )
+            printf( "..."); 
+
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_UINT8
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_UINT8:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(unsigned char);
+            memcpy(&tempuchar, mem, sizeof(unsigned char));
+            printf( "%u ", tempuchar ); 
+           
+
+        }
+        if ( more )
+            printf( "..."); 
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_INT16
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_INT16:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(short);
+            memcpy(&tempshort, mem, sizeof(short));
+            printf( "%d ", tempshort ); 
+            
+
+        }
+        if ( more )
+            printf( "..."); 
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_UINT16
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_UINT16:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(unsigned short);
+            memcpy(&tempushort, mem, sizeof(unsigned short));
+            printf( "%u ", tempushort ); 
+           
+
+        }
+        if ( more )
+            printf( "..."); 
+
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_INT32
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_INT32:
+
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(int);
+            memcpy(&tempint, mem, sizeof(int));
+            printf( "%d ", tempint ); 
+           
+        }
+        if ( more )
+            printf( "..."); 
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_UINT32
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_UINT32:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(unsigned int);
+            memcpy(&tempuint, mem, sizeof(unsigned int));
+            printf( "%u ", tempuint ); 
+           
+
+        }
+        if ( more )
+            printf( "..."); 
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_INT64
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_INT64:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(long long) ;
+            memcpy(&templlong, mem, sizeof(long long));
+            printf( "%lld ", templlong ); 
+            
+
+        }
+        if ( more )
+            printf( "..."); 
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_UINT64
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_UINT64:
+
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(unsigned long long);
+            memcpy(&tempullong, mem, sizeof(unsigned long long));
+            printf( "%llu ", tempullong ); 
+          
+
+        }
+        if ( more )
+            printf( "..."); 
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_FLOAT32
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_FLOAT32:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(float);
+            memcpy(&tempfloat, mem, sizeof(float));
+            printf( "%g ", tempfloat ); 
+         
+
+        }
+        if ( more )
+            printf( "..."); 
+
+
+        break;
+
+        
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+        //NX_FLOAT64
+        /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    case NX_FLOAT64:
+
+        for (i = 0; i < n; i++) 
+        {
+            void* mem = ucbuf + i * sizeof(double);
+            memcpy(&tempdouble, mem, sizeof(double));
+            printf( "%g ", tempdouble ); 
+
+        }
+        if ( more )
+            printf( "..."); 
+
+
+
+        break;
+
+    }
+
+
+
+     //print end line for data
+    printf( "\n"); 
+
+    return NX_OK;
+
+
+}
+
+
diff --git a/applications/NXtraverse/nxtraverse.h b/applications/NXtraverse/nxtraverse.h
new file mode 100644
index 0000000..6444bdb
--- /dev/null
+++ b/applications/NXtraverse/nxtraverse.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010, P. Vicente <pedro.vicente at space-research.org>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#ifndef NX_TRAVERSE_H
+#define NX_TRAVERSE_H
+
+#include "napi.h"
+#include "napiconfig.h"
+
+
+//command line options
+typedef struct 
+{  
+    int      read_data;    //read data            
+    int      read_attr;    //read attributes
+    uint64_t nelmts;       //print number of elements
+    int      all;          //print all elements
+
+} nxtraverse_opt_t;
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+//CNXTraverse
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+class CNXTraverse
+{
+private:
+
+    //traverse file
+    int traverse( NXhandle handle, const char *grp_name  );
+
+    //print dataset
+    int show_dataset( NXhandle handle, const char* dset_name, const char* path);
+
+    //read dataset
+    int read_dataset( NXhandle handle );
+
+    //read attribute
+    int read_attr( NXhandle handle, const char* dset_name, const char* path );
+
+    //print data
+    int print_data( int nxdataype, uint64_t nelmts, void* buf );
+    
+public:
+    
+    CNXTraverse();
+    ~CNXTraverse();
+
+    //print objects
+    int show_objects(const char* file_name);
+
+    //command line options
+    nxtraverse_opt_t options; 
+    
+    
+
+};
+
+
+
+
+#endif //NX_TRAVERSE_H
diff --git a/applications/NXvalidate/CMakeLists.txt b/applications/NXvalidate/CMakeLists.txt
new file mode 100644
index 0000000..025a34f
--- /dev/null
+++ b/applications/NXvalidate/CMakeLists.txt
@@ -0,0 +1,63 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_subdirectory(cmdline)
+
+if (WIN32)
+    configure_file(nxvalidate.bat.in nxvalidate.bat @ONLY)
+	install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/nxvalidate.bat DESTINATION bin)
+else(WIN32)
+	configure_file(nxvalidate.in nxvalidate @ONLY)
+	install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/nxvalidate DESTINATION bin)
+endif(WIN32)
+
+if ( NOT (${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) )
+    add_custom_command(OUTPUT build.xml COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/build.xml . COMMENT "Creating build.xml")
+    add_custom_command(OUTPUT nbproject COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/nbproject nbproject COMMENT "Creating nbproject")
+    set_property(DIRECTORY . APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES build.xml nbproject)
+endif()
+
+add_custom_target(NXvalidate ALL COMMAND ${ANT_EXEC} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/build.xml ${CMAKE_CURRENT_BINARY_DIR}/nbproject)
+
+if (EXISTS ${CMAKE_CURRENT_BINARY_DIR}/dist/javadoc)
+install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist/javadoc DESTINATION ${NXDOCDIR}/java/nxvalidate
+         FILE_PERMISSIONS
+            OWNER_READ OWNER_EXECUTE OWNER_WRITE
+            GROUP_READ GROUP_EXECUTE 
+            WORLD_READ WORLD_EXECUTE
+         DIRECTORY_PERMISSIONS
+            OWNER_READ OWNER_EXECUTE OWNER_WRITE
+            GROUP_READ GROUP_EXECUTE 
+            WORLD_READ WORLD_EXECUTE)
+endif()
+
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/dist/NXvalidate.jar lib/jhall.jar lib/saxon9he.jar DESTINATION share/java/lib COMPONENT Runtime)
+
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/dist/NXvalidate.jar DESTINATION share/java COMPONENT Development)
+
+
diff --git a/applications/NXvalidate/Licence.txt b/applications/NXvalidate/Licence.txt
new file mode 100644
index 0000000..e69de29
diff --git a/applications/NXvalidate/Makefile.am b/applications/NXvalidate/Makefile.am
new file mode 100644
index 0000000..abd8f3b
--- /dev/null
+++ b/applications/NXvalidate/Makefile.am
@@ -0,0 +1,75 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1474 2010-05-09 15:30:02Z Freddie Akeroyd $
+#  
+#  Makefile for nxvalidate
+#
+#  Copyright (C) 2010 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+#====================================================================
+
+
+nxexampledir=$(NXEXAMPLEDIR)
+nxjavadocdir=$(NXDOCDIR)/java
+# jar file definitions
+javadir		= $(datadir)/java
+javalibdir		= $(javadir)/lib
+java_DATA = dist/NXvalidate.jar
+javalib_DATA = lib/saxon9he.jar lib/jhall.jar
+bin_SCRIPTS = nxvalidate
+man_MANS = nxvalidate.1
+
+#nxjavadoc_DATA = README.JNEXUS COPYING.NCSA
+
+EXTRA_DIST	= $(man_MANS) src lib build.xml manifest.mf $(srcdir)/nbproject/*
+
+dist/NXvalidate.jar ::
+	[ -r build.xml ] || ln -s $(srcdir)/build.xml .
+	[ -d nbproject ] || ln -s $(srcdir)/nbproject .
+	$(ANT_PROG)
+
+#apidoc : $(noinst_JAVA)
+#	test -d apidoc || mkdir apidoc
+#	$(JAVADOC) -d apidoc -windowtitle jnexus -doctitle jnexus -classpath . \
+#                      -sourcepath $(srcdir) org.nexusformat ncsa.hdf.hdflib
+
+#dist-hook :
+#	if test -d $(srcdir)/apidoc; then \
+#	    cp -r $(srcdir)/apidoc $(distdir); \
+#	fi
+
+install-data-local :
+	$(mkinstalldirs) $(DESTDIR)$(nxjavadocdir)
+	if test -d $(builddir)/dist/javadoc; then \
+	  cp -r $(builddir)/dist/javadoc $(DESTDIR)$(nxjavadocdir)/nxvalidate; \
+	  find $(DESTDIR)$(nxjavadocdir) -type f -exec chmod 0644 {} \; ;\
+	  find $(DESTDIR)$(nxjavadocdir) -type d -exec chmod 0755 {} \; ;\
+	fi
+
+clean-local :
+if HAVE_ANT
+	$(ANT_PROG) clean
+endif
+
+#uninstall-local :
+#	rm -fr $(DESTDIR)$(nxjavadocdir)/apidoc
+
diff --git a/applications/NXvalidate/Readme.txt b/applications/NXvalidate/Readme.txt
new file mode 100644
index 0000000..e69de29
diff --git a/applications/NXvalidate/build.xml b/applications/NXvalidate/build.xml
new file mode 100644
index 0000000..861a777
--- /dev/null
+++ b/applications/NXvalidate/build.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="NXvalidate" default="default" basedir=".">
+    <description>Builds, tests, and runs the project NXvalidate.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <echoproperties/>
+
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="NXvalidate-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
diff --git a/applications/NXvalidate/doc/help/index.html b/applications/NXvalidate/doc/help/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/applications/NXvalidate/install.xml b/applications/NXvalidate/install.xml
new file mode 100644
index 0000000..b181dab
--- /dev/null
+++ b/applications/NXvalidate/install.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
+
+<!-- 
+    A sample installation file.
+    Use it as a base for your own installers :-)
+    
+    To compile it :
+    - go in the bin directory where you installed IzPack
+    - call "compile ../sample/install.xml -b ../sample"
+-->
+
+<installation version="1.0">
+
+    <native type="izpack" name="ShellLink.dll"/>
+
+    <!-- 
+        The info section.
+        The meaning of the tags should be natural ...
+    -->
+    <info>
+        <appname>NXvalidate</appname>
+        <appversion>1.0 alpha</appversion>
+        <authors>
+            <author name="Stephen Rankin" email="stephen.rankin at stfc.ac.uk"/>
+            <author name="NeXus Team" email="nexus at nexusformat.org"/>
+        </authors>
+        <url>http://www.nexusformat.org</url>
+        <javaversion>1.6</javaversion>
+        <requiresjdk>no</requiresjdk>
+        <pack200/>
+        <summarylogfilepath>$INSTALL_PATH/installinfo/Summary.htm</summarylogfilepath>
+    </info>
+
+    <!-- 
+        The gui preferences indication. Sets the installer window to 640x480.
+        It will not be able to change the size.
+    -->
+    <guiprefs width="640" height="480" resizable="yes"/>
+
+    <!-- 
+        The locale section.
+        Asks here to include the English langpack.
+    -->
+    <locale>
+        <langpack iso3="eng"/>
+    </locale>
+
+    <!-- 
+        The resources section.
+        The ids must be these ones if you want to use the LicencePanel and/or
+        the InfoPanel.
+    -->
+    <resources>
+        <res id="LicencePanel.licence" src="Licence.txt"/>
+        <res id="InfoPanel.info" src="Readme.txt"/>
+        <res src="scripts/shortcutSpec.xml" id="shortcutSpec.xml"/>
+        <res src="scripts/Unix_shortcutSpec.xml" id="Unix_shortcutSpec.xml"/>
+    </resources>
+
+    <!-- 
+        The panels section. We indicate here which panels we want to use.
+        The order will be respected.
+    -->
+    <panels>
+        <panel classname="HelloPanel"/>
+        <panel classname="InfoPanel"/>
+        <panel classname="LicencePanel"/>
+        <panel classname="TargetPanel"/>
+        <panel classname="PacksPanel"/>
+        <panel classname="InstallPanel"/>
+        <panel classname="ShortcutPanel"/>
+        <panel classname="FinishPanel"/>
+    </panels>
+
+    <!-- 
+        The packs section.
+        We specify here our packs.
+    -->
+    <packs>
+        <pack name="Base" required="yes">
+            <description>The base files</description>
+            <file src="dist/lib" targetdir="$INSTALL_PATH"/>
+            <file src="dist/NXvalidate.jar" targetdir="$INSTALL_PATH"/>
+            <file src="Licence.txt" targetdir="$INSTALL_PATH"/>
+            <file os="unix" src="../NXconvert/nxconvert" targetdir="$INSTALL_PATH/bin"/>
+            <!--<file os="windows" src="../NXconvert/nxconvert.exe" targetdir="$INSTALL_PATH/bin"/>-->
+            <file src="src/org/nexusformat/nxvalidate/resources/nexus.png" targetdir="$INSTALL_PATH/share/icons"/>
+            <file src="src/org/nexusformat/nxvalidate/resources/nexus.ico" targetdir="$INSTALL_PATH/share/icons"/>
+            <file src="scripts/install_path" targetdir="$INSTALL_PATH"/>
+            <!-- The file will be parsed -->
+            <parsable targetfile="$INSTALL_PATH/install_path"/>
+        </pack>
+        <pack name="Docs" required="no">
+            <description>NXvalidate Tutorial and Documentation</description>
+            <file src="doc" targetdir="$INSTALL_PATH"/>
+            <file os="unix" src="../NXconvert/nxconvert.1" targetdir="$INSTALL_PATH/man"/>
+        </pack>
+    </packs>
+
+</installation>
diff --git a/applications/NXvalidate/lib/jhall.jar b/applications/NXvalidate/lib/jhall.jar
new file mode 100644
index 0000000..bea4ee0
Binary files /dev/null and b/applications/NXvalidate/lib/jhall.jar differ
diff --git a/applications/NXvalidate/lib/saxon9he.jar b/applications/NXvalidate/lib/saxon9he.jar
new file mode 100644
index 0000000..c3517b4
Binary files /dev/null and b/applications/NXvalidate/lib/saxon9he.jar differ
diff --git a/applications/NXvalidate/manifest.mf b/applications/NXvalidate/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/applications/NXvalidate/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/applications/NXvalidate/nbproject/build-impl.xml b/applications/NXvalidate/nbproject/build-impl.xml
new file mode 100644
index 0000000..c789059
--- /dev/null
+++ b/applications/NXvalidate/nbproject/build-impl.xml
@@ -0,0 +1,880 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - junit compilation
+  - junit execution
+  - junit debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="NXvalidate-impl">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <available file="${application.splash}" property="splashscreen.available"/>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available+splashscreen.available">
+            <and>
+                <istrue value="${manifest.available+main.class+mkdist.available}"/>
+                <istrue value="${splashscreen.available}"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class+mkdist.available}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class+mkdist.available+splashscreen.available">
+            <and>
+                <istrue value="${manifest.available+main.class+mkdist.available+splashscreen.available}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="have.tests">
+            <or/>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <property name="javac.fork" value="false"/>
+        <property name="jar.index" value="false"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="," property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <delete>
+                    <files includes="${javac.includes.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-junit">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <sequential>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}"/>
+                    <classpath>
+                        <path path="${run.test.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version "${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version "1.0"/>
+                <contains string="${version-output}" substring="java version "1.1"/>
+                <contains string="${version-output}" substring="java version "1.2"/>
+                <contains string="${version-output}" substring="java version "1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: NXvalidate was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-init-macrodef-copylibs" if="do.archive+manifest.available+main.class+mkdist.available+splashscreen.available" name="-do-jar-with-libraries-and-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <j2seproject3:copylibs>
+            <customize>
+                <attribute name="Main-Class" value="${main.class}"/>
+                <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+            </customize>
+        </j2seproject3:copylibs>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo>java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-init-macrodef-copylibs" if="do.archive+manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries" unless="splashscreen.available">
+        <j2seproject3:copylibs>
+            <customize>
+                <attribute name="Main-Class" value="${main.class}"/>
+            </customize>
+        </j2seproject3:copylibs>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo>java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries-and-splashscreen,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+            </fileset>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                JUNIT COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir=""/>
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir=""/>
+        <copy todir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="" srcdir=""/>
+        <copy todir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                JUNIT EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:junit testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:junit excludes="" includes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <!--
+                =======================
+                JUNIT DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
+        <delete file="${test.report.file}"/>
+        <mkdir dir="${build.test.results.dir}"/>
+        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
+            <customize>
+                <syspropertyset>
+                    <propertyref prefix="test-sys-prop."/>
+                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                </syspropertyset>
+                <arg value="${test.class}"/>
+                <arg value="showoutput=true"/>
+                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
+                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: NXvalidate was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <not>
+                <isset property="already.built.${call.subproject}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/applications/NXvalidate/nbproject/genfiles.properties b/applications/NXvalidate/nbproject/genfiles.properties
new file mode 100644
index 0000000..b677463
--- /dev/null
+++ b/applications/NXvalidate/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+nbbuild.xml.data.CRC32=a5620c1d
+nbbuild.xml.script.CRC32=b0c113a5
+nbbuild.xml.stylesheet.CRC32=28e38971 at 1.38.1.45
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=c3c43eb3
+nbproject/build-impl.xml.script.CRC32=ee9cbc11
+nbproject/build-impl.xml.stylesheet.CRC32=f33e10ff at 1.38.2.45
diff --git a/applications/NXvalidate/nbproject/org-netbeans-modules-java-j2seproject-copylibstask.jar b/applications/NXvalidate/nbproject/org-netbeans-modules-java-j2seproject-copylibstask.jar
new file mode 100644
index 0000000..619e57f
Binary files /dev/null and b/applications/NXvalidate/nbproject/org-netbeans-modules-java-j2seproject-copylibstask.jar differ
diff --git a/applications/NXvalidate/nbproject/project.properties b/applications/NXvalidate/nbproject/project.properties
new file mode 100644
index 0000000..360e515
--- /dev/null
+++ b/applications/NXvalidate/nbproject/project.properties
@@ -0,0 +1,76 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.run.all.processors=true
+application.title=NXvalidate
+application.vendor=ser65
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+buildfile=build.xml
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/NXvalidate.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+file.reference.jhall.jar=lib/jhall.jar
+file.reference.NXconvertpy-src=src
+file.reference.saxon9he.jar=lib/saxon9he.jar
+includes=**
+jar.compress=false
+javac.classpath=\
+    ${file.reference.saxon9he.jar}:\
+    ${file.reference.jhall.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.5
+javac.target=1.5
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}:\
+    ${libs.junit.classpath}:\
+    ${libs.junit_4.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=org.nexusformat.nxvalidate.NXvalidateFrame
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=${file.reference.NXconvertpy-src}
+libs.CopyLibs.classpath=${dist.dir}/../nbproject/org-netbeans-modules-java-j2seproject-copylibstask.jar
diff --git a/applications/NXvalidate/nbproject/project.xml b/applications/NXvalidate/nbproject/project.xml
new file mode 100644
index 0000000..6bce412
--- /dev/null
+++ b/applications/NXvalidate/nbproject/project.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>NXvalidate</name>
+            <source-roots>
+                <root id="src.dir"/>
+            </source-roots>
+            <test-roots/>
+        </data>
+    </configuration>
+</project>
diff --git a/applications/NXvalidate/nxvalidate.1 b/applications/NXvalidate/nxvalidate.1
new file mode 100644
index 0000000..ec21be0
--- /dev/null
+++ b/applications/NXvalidate/nxvalidate.1
@@ -0,0 +1,35 @@
+.TH NXVALIDATE 1 "October 2011"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxvalidate \- Validate a NeXus file
+.SH SYNOPSIS
+.B nxvalidate
+.SH DESCRIPTION
+.B nxvalidate
+will validate a nexus file against an application definition. It relies on nxconvert 
+being installed. For more information see the help information in the gui.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH SEE ALSO
+.BR nxconvert(1),
+.BR nxdir (1),
+.BR nxsummary (1),
+.BR nxtranslate (1),
+.BR http://www.nexusformat.org
+.SH AUTHOR
+.B nxvaldate
+was originally written by Freddie Akeroyd, Stuart Campbell, Peter Peterson, 
+and Stephen Rankin and may be used by others.
diff --git a/applications/NXvalidate/nxvalidate.bat.in b/applications/NXvalidate/nxvalidate.bat.in
new file mode 100644
index 0000000..9e5f83c
--- /dev/null
+++ b/applications/NXvalidate/nxvalidate.bat.in
@@ -0,0 +1,34 @@
+ at echo off
+REM #====================================================================
+REM #  NeXus - Neutron & X-ray Common Data Format
+REM #  
+REM #  $Id: nxbuild.in 1030 2008-07-15 15:16:49Z Freddie Akeroyd $
+REM #
+REM #  @configure_input@
+REM #  
+REM #  Script for running nxvalidate on windows
+REM #
+REM #  Copyright (C) 2010 Freddie Akeroyd
+REM #  
+REM #  This library is free software; you can redistribute it and/or
+REM #  modify it under the terms of the GNU Lesser General Public
+REM #  License as published by the Free Software Foundation; either
+REM #  version 2 of the License, or (at your option) any later version.
+REM # 
+REM #  This library is distributed in the hope that it will be useful,
+REM #  but WITHOUT ANY WARRANTY; without even the implied warranty of
+REM #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+REM #  Lesser General Public License for more details.
+REM # 
+REM #  You should have received a copy of the GNU Lesser General Public
+REM #  License along with this library; if not, write to the Free 
+REM #  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+REM #  MA  02111-1307  USA
+REM #             
+REM #  For further information, see <http://www.nexusformat.org>
+REM #
+REM #====================================================================
+set NXJAVADIR=%NEXUSDIR%\share\java
+set CLASSPATH=%NXJAVADIR%\jnexus.jar;%CLASSPATH%
+set PATH=%NEXUSDIR%\bin;%PATH%
+java -jar "%NXJAVADIR%\NXvalidate.jar" %*
diff --git a/applications/NXvalidate/nxvalidate.in b/applications/NXvalidate/nxvalidate.in
new file mode 100644
index 0000000..742f016
--- /dev/null
+++ b/applications/NXvalidate/nxvalidate.in
@@ -0,0 +1,48 @@
+#!/bin/sh
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: nxbuild.in 1030 2008-07-15 15:16:49Z Freddie Akeroyd $
+#
+#  @configure_input@
+#  
+#  Script for running nxvalidate
+#
+#  Copyright (C) 2010 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+bindir="@bindir@"
+sbindir="@sbindir@"
+libexecdir="@libexecdir@"
+datadir="@datadir@"
+datarootdir="@datarootdir@"
+libdir="@libdir@"
+infodir="@infodir@"
+mandir="@mandir@"
+includedir="@includedir@"
+javadir="@datadir@/java"
+#pkgdatadir=$(datadir)/@PACKAGE@
+#pkglibdir=$(libdir)/@PACKAGE@
+#pkgincludedir=$(includedir)/@PACKAGE@
+#top_builddir=..
+export PATH=${bindir}:${PATH} LD_LIBRARY_PATH=${libdir}:${LD_LIBRARY_PATH}
+java -jar ${javadir}/NXvalidate.jar $*
diff --git a/applications/NXvalidate/scripts/Unix_shortcutSpec.xml b/applications/NXvalidate/scripts/Unix_shortcutSpec.xml
new file mode 100644
index 0000000..7c6fa01
--- /dev/null
+++ b/applications/NXvalidate/scripts/Unix_shortcutSpec.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<shortcuts>
+
+  <programGroup defaultName="NXvalidate" location="applications"/>
+
+  <shortcut
+     name="NXvalidate"
+     programGroup="yes"
+     desktop="yes"
+     applications="no"
+     startMenu="yes"
+     startup="no"
+     target="$JAVA_HOME/bin/java"
+     commandLine="-jar "$INSTALL_PATH/NXvalidate.jar""
+     workingDirectory="$INSTALL_PATH"
+     description="NeXus tool to validate NeXus files - NXvalidate"
+     iconFile="$INSTALL_PATH/share/icons/nexus.png"
+     iconIndex="0"
+     type="Application"
+     encoding="UTF-8"
+     terminal="true"
+     KdeSubstUID="false"
+     initialState="normal"
+     TryExec="$JAVA_HOME/bin/java -jar "$INSTALL_PATH/NXvalidate.jar"">   
+     <createForPack name="Base"/>     
+   </shortcut>
+
+    <shortcut
+      name="NXvalidate Html Documentation"
+      programGroup="yes"
+      desktop="no"
+      applications="no"
+      startMenu="yes"
+      startup="no"
+      target="$INSTALL_PATH/bin/start.sh"
+      workingDirectory=""
+      commandLine="$INSTALL_PATH/doc/help/index.html"
+      initialState="noShow"
+      iconFile="help"
+      iconIndex="0"
+      url="$INSTALL_PATH/doc/help/index.html"
+      type="Application"
+      encoding="UTF-8"
+      createForAll="true"
+      Categories="Application;Development;"
+      description="This opens a WebBrowser to look into the NXvalidate (HTML) user documentation.">
+      <createForPack name="Docs"/>
+    </shortcut>
+
+    <shortcut
+      name="NXvalidate PDF Documentation"
+      programGroup="yes"
+      desktop="no"
+      applications="no"
+      startMenu="yes"
+      startup="no"
+      target="acroread"
+      workingDirectory=""
+      commandLine="$INSTALL_PATH/doc/nxvalidate.pdf"
+      initialState="noShow"
+      iconFile="acroread"
+      iconIndex="0"
+      type="Application"
+      encoding="UTF-8"
+      createForAll="true"
+      Categories="Application;Development;"
+      description="This opens Adobe (Acrobat) Reader (if available) to look into or print the NXvalidate (PDF) user documentation">
+      <createForPack name="Docs"/>
+    </shortcut>
+
+    <shortcut
+      name="NXvalidate Uninstaller"
+      programGroup="yes"
+      desktop="no"
+      applications="no"
+      startMenu="yes"
+      startup="no"
+      target="$JAVA_HOME/bin/java"
+      commandLine="-jar "$INSTALL_PATH/Uninstaller/uninstaller.jar""
+      initialState="noShow"
+      iconFile="trashcan_full"
+      iconIndex="0"
+      workingDirectory=""
+      type="Application"
+      encoding="UTF-8"
+      KdeSubstUID="true"
+      KdeUsername="root"
+      createForAll="false"
+      Categories="Application;Development;"
+      TryExec="$JAVA_HOME/bin/java -jar "$INSTALL_PATH/Uninstaller/uninstaller.jar""
+      description="This uninstalls NXvalidate">
+      <createForPack name="Base"/>
+    </shortcut>
+
+</shortcuts>
diff --git a/applications/NXvalidate/scripts/install_path b/applications/NXvalidate/scripts/install_path
new file mode 100644
index 0000000..9a46a64
--- /dev/null
+++ b/applications/NXvalidate/scripts/install_path
@@ -0,0 +1 @@
+$INSTALL_PATH
diff --git a/applications/NXvalidate/scripts/shortcutSpec.xml b/applications/NXvalidate/scripts/shortcutSpec.xml
new file mode 100644
index 0000000..be90fa4
--- /dev/null
+++ b/applications/NXvalidate/scripts/shortcutSpec.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+
+<shortcuts>
+
+  <skipIfNotSupported/>
+
+  <programGroup defaultName="NXvalidate" location="applications"/>
+    
+  <shortcut
+    name="NXvalidate"
+    programGroup="yes"
+    desktop="yes"
+    applications="no"
+    startMenu="no"
+    startup="no"
+    target="$JAVA_HOME/bin/java"
+    commandLine="-jar "$INSTALL_PATH/NXvalidate.jar""
+    description="NeXus tool to validate NeXus files - NXvalidate"
+    iconFile="$INSTALL_PATH/share/icons/nexus.ico"
+    iconIndex="0"
+    initialState="noShow">
+    <createForPack name="Base"/>
+   </shortcut>
+
+   <shortcut
+     name="NXvalidate Html Documentation"
+     programGroup="yes"
+     desktop="no"
+     applications="no"
+     startMenu="no"
+     startup="no"
+     target="$INSTALL_PATH\doc\help\index.html"
+     commandLine=""
+     description="This opens a WebBrowser to look into the NXvalidate (HTML) user documentation">
+     <createForPack name="Docs"/>
+    </shortcut>
+
+    <shortcut
+      name="NXvalidate PDF Documentation"
+      programGroup="yes"
+      desktop="no"
+      applications="no"
+      startMenu="no"
+      startup="no"
+      target="$INSTALL_PATH\doc\nxvalidate.pdf"
+      commandLine=""
+      iconFile="%SystemRoot%\system32\SHELL32.dll"
+      iconIndex="23"
+      description="This opens Adobe (Acrobat) Reader (if available) to look into or print the NXvalidate (PDF) user documentation">
+      <createForPack name="Docs"/>
+    </shortcut>
+    
+    <shortcut
+      name="NXvalidate Uninstaller"
+      programGroup="yes"
+      desktop="no"
+      applications="no"
+      startMenu="no"
+      startup="no"
+      target="$INSTALL_PATH\Uninstaller\uninstaller.jar"
+      commandLine=""
+      iconFile="%SystemRoot%\system32\SHELL32.dll"
+      iconIndex="31"
+      description="This uninstalls NXvalidate">
+      <createForPack name="Base"/>
+    </shortcut>
+
+</shortcuts>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/AboutDialog.form b/applications/NXvalidate/src/org/nexusformat/nxvalidate/AboutDialog.form
new file mode 100644
index 0000000..140b343
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/AboutDialog.form
@@ -0,0 +1,103 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" alignment="1" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="separate" max="-2" attributes="0"/>
+                          <Component id="jScrollPane2" pref="372" max="32767" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="1" attributes="0">
+                          <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace min="-2" pref="259" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                      <Component id="jScrollPane2" min="-2" pref="283" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace pref="28" max="32767" attributes="0"/>
+                  <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="jLabel1">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/org/nexusformat/nxvalidate/resources/nexus.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="http://www.nexusformat.org"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="jButton1">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="OK"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
+          </Events>
+        </Component>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JEditorPane" name="jEditorPane1">
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/AboutDialog.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/AboutDialog.java
new file mode 100644
index 0000000..0b58680
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/AboutDialog.java
@@ -0,0 +1,170 @@
+ /* NeXus - Neutron & X-ray Common Data Format
+  *
+  * NeXus file validation GUI tool.
+  *
+  * Copyright (C) 2010 Stephen Rankin
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  *
+  * For further information, see <http://www.nexusformat.org/>
+  *
+  * AboutDialog.java
+  *
+  * Created on 03-Sep-2010, 11:17:52
+  */
+
+package org.nexusformat.nxvalidate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author ser
+ */
+public class AboutDialog extends javax.swing.JDialog {
+
+    private InputStream aboutHTMLStream = null;
+    private URL aboutHTMLURL = null;
+
+    /** Creates new form AboutDialog */
+    public AboutDialog(java.awt.Frame parent, boolean modal) {
+        super(parent, modal);
+        initComponents();
+        setup();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanel1 = new javax.swing.JPanel();
+        jLabel1 = new javax.swing.JLabel();
+        jButton1 = new javax.swing.JButton();
+        jScrollPane2 = new javax.swing.JScrollPane();
+        jEditorPane1 = new javax.swing.JEditorPane();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+
+        jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/nexusformat/nxvalidate/resources/nexus.png"))); // NOI18N
+        jLabel1.setToolTipText("http://www.nexusformat.org");
+
+        jButton1.setText("OK");
+        jButton1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton1ActionPerformed(evt);
+            }
+        });
+
+        jScrollPane2.setViewportView(jEditorPane1);
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jLabel1)
+                        .addGap(18, 18, 18)
+                        .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE)
+                        .addContainerGap())
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                        .addComponent(jButton1)
+                        .addGap(259, 259, 259))))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel1)
+                    .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 283, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 28, Short.MAX_VALUE)
+                .addComponent(jButton1)
+                .addContainerGap())
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
+        if (evt.getSource() ==  jButton1) {
+
+            dispose();
+        }
+    }//GEN-LAST:event_jButton1ActionPerformed
+
+    /**
+    * @param args the command line arguments
+    */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                AboutDialog dialog = new AboutDialog(new javax.swing.JFrame(), true);
+                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
+                    public void windowClosing(java.awt.event.WindowEvent e) {
+                        System.exit(0);
+                    }
+                });
+                dialog.setVisible(true);
+            }
+        });
+    }
+
+    private void setup(){
+        try {
+            aboutHTMLStream =
+                    AboutDialog.class.getResourceAsStream("resources/about.html");
+            aboutHTMLURL = AboutDialog.class.getResource("resources/about.html");
+            jEditorPane1.setEditable(false);
+            //jEditorPane1.read(aboutHTMLStream, null);
+            jEditorPane1.setPage(aboutHTMLURL);
+            //jEditorPane1.
+        } catch (IOException ex) {
+            Logger.getLogger(AboutDialog.class.getName()).log(Level.SEVERE,
+                             "Failed to load about.html", ex);
+        }
+    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButton1;
+    private javax.swing.JEditorPane jEditorPane1;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JScrollPane jScrollPane2;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/AbstractNXSnode.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/AbstractNXSnode.java
new file mode 100644
index 0000000..f473d27
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/AbstractNXSnode.java
@@ -0,0 +1,42 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * AbstractNXSnode.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+abstract class AbstractNXSnode {
+    private String name;
+
+    AbstractNXSnode(final String name) {
+	this.name = name;
+    }
+
+    final protected void setName(final String name) {
+	this.name = name;
+    }
+
+    final public String getName() {
+	return this.name;
+    }
+}
\ No newline at end of file
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/Attribute.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/Attribute.java
new file mode 100644
index 0000000..5231d8f
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/Attribute.java
@@ -0,0 +1,46 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * Attribute.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.util.Vector;
+
+public class Attribute extends AbstractNXSnode {
+    private static final String ATTR = "ATTR:";
+    private String value;
+
+    public Attribute(final String name, final String value) {
+	super(name);
+	this.value = value;
+    }
+
+    public String getValue() {
+	return this.value;
+    }
+
+    public String toString() {
+	return ATTR + this.getName() + ":" + this.value;
+    }
+}
\ No newline at end of file
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/BulkLoadFilesFrame.form b/applications/NXvalidate/src/org/nexusformat/nxvalidate/BulkLoadFilesFrame.form
new file mode 100644
index 0000000..ed57e59
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/BulkLoadFilesFrame.form
@@ -0,0 +1,191 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.JFileChooser" name="jFileChooser1">
+    </Component>
+    <Component class="javax.swing.JOptionPane" name="problemOptionPane">
+    </Component>
+  </NonVisualComponents>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jSplitPane1" alignment="0" pref="672" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jSplitPane1" alignment="1" pref="534" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+      <Properties>
+        <Property name="orientation" type="int" value="0"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <Properties>
+            <Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="top"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="loadNXDCButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                              <Component id="nxdcFileNameTextField" min="-2" pref="549" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="1">
+                              <Component id="loadDataFilesButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" pref="92" max="-2" attributes="0"/>
+                              <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="32767" attributes="0"/>
+                              <Component id="cancelButton" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" pref="33" max="-2" attributes="0"/>
+                              <Component id="validateButton" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace pref="17" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="loadNXDCButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="nxdcFileNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="loadDataFilesButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="validateButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jCheckBox1" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="loadNXDCButton">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Load NXDL"/>
+                <Property name="actionCommand" type="java.lang.String" value="Load NXDL"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadNXDCButtonActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="loadDataFilesButton">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Load Data Files"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadDataFilesButtonActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JTextField" name="nxdcFileNameTextField">
+            </Component>
+            <Component class="javax.swing.JButton" name="validateButton">
+              <Properties>
+                <Property name="label" type="java.lang.String" value="Validate"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="validateButtonActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="cancelButton">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Cancel"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JCheckBox" name="jCheckBox1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Load files only."/>
+                <Property name="toolTipText" type="java.lang.String" value="Load files only, do not validate."/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jCheckBox1ActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="right"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTable" name="jTable1">
+              <Properties>
+                <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
+                  <Table columnCount="2" rowCount="1">
+                    <Column editable="true" title="Include" type="java.lang.Boolean"/>
+                    <Column editable="true" title="File Name" type="java.lang.String"/>
+                  </Table>
+                </Property>
+                <Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
+                  <TableColumnModel selectionModel="0">
+                    <Column maxWidth="60" minWidth="60" prefWidth="60" resizable="true">
+                      <Title/>
+                      <Editor/>
+                      <Renderer/>
+                    </Column>
+                    <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
+                      <Title/>
+                      <Editor/>
+                      <Renderer/>
+                    </Column>
+                  </TableColumnModel>
+                </Property>
+                <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
+                  <TableHeader reorderingAllowed="true" resizingAllowed="true"/>
+                </Property>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/BulkLoadFilesFrame.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/BulkLoadFilesFrame.java
new file mode 100644
index 0000000..5cd88b9
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/BulkLoadFilesFrame.java
@@ -0,0 +1,409 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * BulkLoadFilesFrame.java
+ *
+ * Created on 10-Aug-2010, 15:32:56
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.table.DefaultTableModel;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class BulkLoadFilesFrame extends javax.swing.JFrame {
+
+    private File nxdlFile = null;
+    private ArrayList<String> dataFileList = null;
+    private FileActions fileLoadingActions = null;
+    private boolean badFiles = false;
+    private ResourceBundle bundle = null;
+    private ArrayList<String> dataFileSelectedList = null;
+    private CheckNexusFileType check = null;
+
+    /** Creates new form BulkLoadFilesFrame */
+    public BulkLoadFilesFrame(FileActions fileLoadingActions) {
+        initComponents();
+        this.fileLoadingActions = fileLoadingActions;
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+        check = new CheckNexusFileType();
+
+    }
+
+    public BulkLoadFilesFrame() {
+        initComponents();
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+        check = new CheckNexusFileType();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jFileChooser1 = new javax.swing.JFileChooser();
+        problemOptionPane = new javax.swing.JOptionPane();
+        jSplitPane1 = new javax.swing.JSplitPane();
+        jPanel1 = new javax.swing.JPanel();
+        loadNXDCButton = new javax.swing.JButton();
+        loadDataFilesButton = new javax.swing.JButton();
+        nxdcFileNameTextField = new javax.swing.JTextField();
+        validateButton = new javax.swing.JButton();
+        cancelButton = new javax.swing.JButton();
+        jCheckBox1 = new javax.swing.JCheckBox();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTable1 = new javax.swing.JTable();
+
+        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
+
+        jPanel1.setVerifyInputWhenFocusTarget(false);
+
+        loadNXDCButton.setText("Load NXDL");
+        loadNXDCButton.setActionCommand("Load NXDL");
+        loadNXDCButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                loadNXDCButtonActionPerformed(evt);
+            }
+        });
+
+        loadDataFilesButton.setText("Load Data Files");
+        loadDataFilesButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                loadDataFilesButtonActionPerformed(evt);
+            }
+        });
+
+        validateButton.setLabel("Validate");
+        validateButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                validateButtonActionPerformed(evt);
+            }
+        });
+
+        cancelButton.setText("Cancel");
+        cancelButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                cancelButtonActionPerformed(evt);
+            }
+        });
+
+        jCheckBox1.setText("Load files only.");
+        jCheckBox1.setToolTipText("Load files only, do not validate.");
+        jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jCheckBox1ActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(loadNXDCButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(nxdcFileNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 549, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(loadDataFilesButton)
+                        .addGap(92, 92, 92)
+                        .addComponent(jCheckBox1)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(cancelButton)
+                        .addGap(33, 33, 33)
+                        .addComponent(validateButton)))
+                .addContainerGap(17, Short.MAX_VALUE))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(loadNXDCButton)
+                    .addComponent(nxdcFileNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addGap(18, 18, 18)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(loadDataFilesButton)
+                    .addComponent(validateButton)
+                    .addComponent(cancelButton)
+                    .addComponent(jCheckBox1))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jSplitPane1.setTopComponent(jPanel1);
+
+        jTable1.setModel(new javax.swing.table.DefaultTableModel(
+            new Object [][] {
+                {null, null}
+            },
+            new String [] {
+                "Include", "File Name"
+            }
+        ) {
+            Class[] types = new Class [] {
+                java.lang.Boolean.class, java.lang.String.class
+            };
+
+            public Class getColumnClass(int columnIndex) {
+                return types [columnIndex];
+            }
+        });
+        jScrollPane1.setViewportView(jTable1);
+        jTable1.getColumnModel().getColumn(0).setMinWidth(60);
+        jTable1.getColumnModel().getColumn(0).setPreferredWidth(60);
+        jTable1.getColumnModel().getColumn(0).setMaxWidth(60);
+
+        jSplitPane1.setRightComponent(jScrollPane1);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void loadNXDCButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadNXDCButtonActionPerformed
+        if (evt.getSource() == loadNXDCButton) {
+
+            jFileChooser1.setMultiSelectionEnabled(false);
+            jFileChooser1.setFileSelectionMode(jFileChooser1.FILES_ONLY);
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+                nxdlFile = jFileChooser1.getSelectedFile();
+
+                if(check.checkNXDLFile(nxdlFile)){
+
+                    nxdcFileNameTextField.setText(nxdlFile.getAbsolutePath());
+                    nxdcFileNameTextField.setToolTipText(nxdlFile.getAbsolutePath());
+
+                } else{
+                    nxdlFile = null;
+                    problemOptionPane.showMessageDialog(this,
+                        bundle.getString("notNXDLFileMessage"));
+                }
+
+               
+            } else {
+                nxdlFile = null;
+            }
+
+        }
+    }//GEN-LAST:event_loadNXDCButtonActionPerformed
+
+    private void loadDataFilesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadDataFilesButtonActionPerformed
+        if (evt.getSource() == loadDataFilesButton) {
+
+            dataFileList = new ArrayList<String>();
+
+            File[] dataFiles = null;
+            jFileChooser1.setMultiSelectionEnabled(true);
+            jFileChooser1.setFileSelectionMode(jFileChooser1.FILES_AND_DIRECTORIES);
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+                try {
+                    dataFiles = jFileChooser1.getSelectedFiles();
+                    fileLoadingActions.setDataFiles(dataFiles);
+                    fileLoadingActions.setWhich(3);
+                    fileLoadingActions.bulkCheck();
+                    dataFileList = fileLoadingActions.getDataFileList();
+                    updateTable();
+                } catch (FileNotFoundException ex) {
+                    Logger.getLogger(BulkLoadFilesFrame.class.getName()).log(Level.SEVERE, null, ex);
+                } catch (IOException ex) {
+                    Logger.getLogger(BulkLoadFilesFrame.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            } else {
+                dataFiles = null;
+            }
+
+        }
+    }//GEN-LAST:event_loadDataFilesButtonActionPerformed
+
+    private void updateTable() throws FileNotFoundException, IOException {
+
+        DefaultTableModel tableModel = new DefaultTableModel(new Object[][]{
+                    {null, null}
+                },
+                new String[]{
+                    "Include", "File Name"
+                }) {
+
+            Class[] types = new Class[]{
+                java.lang.Boolean.class, java.lang.String.class
+            };
+
+            public Class getColumnClass(int columnIndex) {
+                return types[columnIndex];
+            }
+        };
+
+        tableModel.removeRow(0);
+
+        Boolean useIt = new Boolean(true);
+        Object[] row = new Object[2];
+        for (int i = 0; i < dataFileList.size(); ++i) {
+            row[1] = dataFileList.get(i);
+            if (check.checkNexusFile(new File(dataFileList.get(i)))) {
+                row[0] = new Boolean(true);
+            } else {
+                row[0] = new Boolean(false);
+                badFiles = true;
+            }
+
+            tableModel.addRow(row);
+        }
+
+        jTable1.setModel(tableModel);
+        jTable1.getColumnModel().getColumn(0).setMinWidth(60);
+        jTable1.getColumnModel().getColumn(0).setPreferredWidth(60);
+        jTable1.getColumnModel().getColumn(0).setMaxWidth(60);
+
+        if (badFiles) {
+            problemOptionPane.showMessageDialog(this,
+                    bundle.getString("filesNotNexusError"));
+        }
+
+    }
+
+    private void validateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_validateButtonActionPerformed
+
+        if (evt.getSource() == validateButton) {
+
+            if (nxdlFile == null) {
+                problemOptionPane.showMessageDialog(this,
+                        bundle.getString("openSchemaFileMessage"));
+                return;
+            }
+
+            if (fileLoadingActions.getNXConvertFile() == null) {
+                problemOptionPane.showMessageDialog(this,
+                        bundle.getString("noConvertCommandFound"));
+                return;
+            }
+
+
+            Boolean checked = null;
+            dataFileSelectedList = new ArrayList<String>();
+
+            int rows = jTable1.getModel().getRowCount();
+
+            for (int i = 0; i < rows; ++i) {
+                checked = (Boolean) jTable1.getModel().getValueAt(i, 0);
+
+                if (checked) {
+                    dataFileSelectedList.add((String) jTable1.getModel().getValueAt(i, 1));
+                }
+
+            }
+
+            if (jCheckBox1.isSelected()) {
+
+                fileLoadingActions.setWhich(4);
+                fileLoadingActions.setNXDLFile(nxdlFile);
+                fileLoadingActions.setDataFileList(dataFileSelectedList);
+
+                (new Thread(fileLoadingActions)).start();
+
+            } else {
+
+                fileLoadingActions.setWhich(5);
+                fileLoadingActions.setNXDLFile(nxdlFile);
+                fileLoadingActions.setDataFileList(dataFileSelectedList);
+
+                (new Thread(fileLoadingActions)).start();
+
+            }
+        }
+    }//GEN-LAST:event_validateButtonActionPerformed
+
+    private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBox1ActionPerformed
+
+        if (evt.getSource() == jCheckBox1) {
+
+            if (jCheckBox1.isSelected()) {
+                validateButton.setText("Load");
+            } else {
+                validateButton.setText("Validate");
+            }
+        }
+
+    }//GEN-LAST:event_jCheckBox1ActionPerformed
+
+    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
+        if (evt.getSource() == cancelButton) {
+            this.setVisible(false);
+        }
+    }//GEN-LAST:event_cancelButtonActionPerformed
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+
+            public void run() {
+                new BulkLoadFilesFrame().setVisible(true);
+            }
+        });
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton cancelButton;
+    private javax.swing.JCheckBox jCheckBox1;
+    private javax.swing.JFileChooser jFileChooser1;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JSplitPane jSplitPane1;
+    private javax.swing.JTable jTable1;
+    private javax.swing.JButton loadDataFilesButton;
+    private javax.swing.JButton loadNXDCButton;
+    private javax.swing.JTextField nxdcFileNameTextField;
+    private javax.swing.JOptionPane problemOptionPane;
+    private javax.swing.JButton validateButton;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/CheckNexusFileType.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/CheckNexusFileType.java
new file mode 100644
index 0000000..dbcea5a
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/CheckNexusFileType.java
@@ -0,0 +1,245 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * CheckNexusFileType.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.MalformedURLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class CheckNexusFileType {
+
+    private DocumentBuilderFactory factory = null;
+    private DocumentBuilder builder = null;
+
+    public CheckNexusFileType() {
+        factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        try {
+            builder = factory.newDocumentBuilder();
+        } catch (ParserConfigurationException ex) {
+            Logger.getLogger(CheckNexusFileType.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        }
+    }
+
+    /**
+     * Checks to see if a file is a HDF/Nexus file and returns true if it is.
+     * The method checks for HDF4, HDF5 and Nexus XML files.
+     * @param file the input file to check.
+     * @return boolean which is true if the file is a HDF/Nexus file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public boolean checkNexusFile(File file) {
+        try {
+            if (checkHDF5(file)) {
+                return true;
+            } else if (checkHDF4(file)) {
+                return true;
+            } else if (checkNexusXML(file)) {
+                return true;
+            }
+        } catch (FileNotFoundException ex) {
+            Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (IOException ex) {
+            Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return false;
+    }
+
+    /**
+     * Checks to see if a file is a HDF5 file and returns true if it is.
+     * @param file the input file to check.
+     * @return boolean which is true if the file is a HDF5 file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public boolean checkHDF5(File file) throws FileNotFoundException,
+                                               IOException {
+
+        byte[] b = new byte[7];
+        FileInputStream stream = new FileInputStream(file);
+        stream.read(b);
+        stream.close();
+        if (b[0] != -119) {
+            return false;
+        } else if (b[1] != 72) {
+            return false;
+        } else if (b[2] != 68) {
+            return false;
+        } else if (b[3] != 70) {
+            return false;
+        } else if (b[4] != 13) {
+            return false;
+        } else if (b[5] != 10) {
+            return false;
+        } else if (b[6] != 26) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Checks to see if a file is a HDF4 file and returns true if it is.
+     * @param file the input file to check.
+     * @return boolean which is true if the file is a HDF4 file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public boolean checkHDF4(File file) throws FileNotFoundException,
+                                               IOException {
+
+        byte[] b = new byte[4];
+        FileInputStream stream = new FileInputStream(file);
+        stream.read(b);
+        stream.close();
+        if (b[0] != 14) {
+            return false;
+        } else if (b[1] != 3) {
+            return false;
+        } else if (b[2] != 19) {
+            return false;
+        } else if (b[3] != 1) {
+            return false;
+        }
+
+        return true;
+
+    }
+
+    /**
+     * Checks to see if a file is a Nexus XML file and returns true if it is.
+     * @param file the input file to check.
+     * @return boolean which is true if the file is a Nexus XML file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private boolean checkNexusXML(File file) {
+
+        boolean result = false;
+
+        try {
+            Document resultsDoc = builder.parse(file);
+            if (resultsDoc.getDocumentElement().getNodeName().equals("NXroot")) {
+                result = true;
+            }
+        } catch (SAXException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "SAXException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (MalformedByteSequenceException ex) {
+           // Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "MalformedByteSequenceException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (ConnectException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "ConnectException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (MalformedURLException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "MalformedURLException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (FileNotFoundException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "FileNotFoundException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (IOException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+             //       "IOException: " + file.getAbsolutePath(), ex);
+            return result;
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Checks to see if a file is a Nexus definition file and returns true if
+     * it is.
+     * @param file the input file to check.
+     * @return boolean which is true if the file is a Nexus definition file.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public boolean checkNXDLFile(File file) {
+
+        boolean result = false;
+
+        try {
+            Document resultsDoc = builder.parse(file);
+            if (resultsDoc.getDocumentElement().getNodeName().equals("definition")) {
+                result = true;
+            }
+            if (resultsDoc.getDocumentElement().getNodeName().equals("definitions")) {
+                result = true;
+            }
+        } catch (SAXException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "SAXException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (MalformedByteSequenceException ex) {
+           // Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "MalformedByteSequenceException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (ConnectException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "ConnectException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (MalformedURLException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "MalformedURLException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (FileNotFoundException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+            //        "FileNotFoundException: " + file.getAbsolutePath(), ex);
+            return result;
+        } catch (IOException ex) {
+            //Logger.getLogger(CheckNexusFileType.class.getName()).log(Level.INFO,
+             //       "IOException: " + file.getAbsolutePath(), ex);
+            return result;
+        }
+
+        return result;
+
+    }
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/FileActions.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/FileActions.java
new file mode 100644
index 0000000..2c7e2e1
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/FileActions.java
@@ -0,0 +1,418 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * FileActions.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JOptionPane;
+import javax.swing.JTree;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.nexusformat.nxvalidate.exceptions.NXvalidateException;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class FileActions implements Runnable {
+
+    private File nxsFile = null;
+    private File nxdlFile = null;
+    private File reducedFile = null;
+    private File resultsFile = null;
+    private String nxconvertCommand = null;
+    private File saveDirectory = null;
+    private DocumentBuilderFactory factory = null;
+    private DocumentBuilder builder = null;
+    private NXReducedToTree domTree = null;
+    private NXNodeMapper root = null;
+    private int which = 1;
+    private TreeUtils treeUtils = null;
+    private ValidatorUtils validator = null;
+    private Document reducedDoc = null;
+    private Document resultsDoc = null;
+    private JTree jTree = null;
+    private boolean validateResult = false;
+    private ResourceBundle bundle = null;
+    private JOptionPane dialogReportProblem;
+    private NXvalidateFrame frame = null;
+    private File[] dataFiles = null;
+    private ArrayList<String> dataFileList = null;
+    private ArrayList<String> badDataFileList = null;
+    private boolean conversionFail = false;
+    private boolean isNotBulk = false;
+
+    public FileActions(NXvalidateFrame frame, JTree jTree,
+            DocumentBuilder builder, NXReducedToTree domTree,
+            NXNodeMapper root) {
+
+        this.domTree = domTree;
+        this.root = root;
+        this.builder = builder;
+        this.frame = frame;
+        this.jTree = jTree;
+
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+        dialogReportProblem = new JOptionPane();
+
+        treeUtils = new TreeUtils();
+    }
+
+    public void setWhich(int which) {
+        this.which = which;
+    }
+
+    public void setNXSFile(File nxsFile) {
+        this.nxsFile = nxsFile;
+    }
+
+    public void setNXDLFile(File nxdlFile) {
+        this.nxdlFile = nxdlFile;
+    }
+
+    public void setNXConvertFile(String nxconvertCommand) {
+        this.nxconvertCommand = nxconvertCommand;
+    }
+
+    public String getNXConvertFile() {
+        return nxconvertCommand;
+    }
+
+    public void setReducedFile(File reducedFile) {
+        this.reducedFile = reducedFile;
+    }
+
+    public void setResultsDoc(Document resultsDoc) {
+        this.resultsDoc = resultsDoc;
+    }
+
+    public void setReducedDoc(Document reducedDoc) {
+        this.reducedDoc = reducedDoc;
+    }
+
+    public void setDataFiles(File[] dataFiles) {
+        this.dataFiles = dataFiles;
+    }
+
+    public boolean getValidateResult() {
+        return validateResult;
+    }
+
+    public ArrayList<String> getDataFileList() {
+        return dataFileList;
+    }
+
+    public void setDataFileList(ArrayList<String> dataFileList) {
+        this.dataFileList = dataFileList;
+    }
+
+    public File getSaveDirectory() {
+        return saveDirectory;
+    }
+
+    public void setSaveDirectory(File saveDirectory) {
+        this.saveDirectory = saveDirectory;
+    }
+
+    public boolean getConversionResult() {
+        return conversionFail;
+    }
+
+    public ArrayList<String> getBadDataFileList() {
+        return badDataFileList;
+    }
+
+    public void validateFile() {
+
+        try {
+
+            //Validation has already been done so we reset the tree
+            //before doing the validation again.
+            if (resultsDoc != null) {
+                SVRLNodeFilter filter = new SVRLNodeFilter();
+                filter.setFilterDocument(resultsDoc);
+                filter.setDocument(reducedDoc);
+                filter.resetNodes();
+            }
+
+            //Do the validation.
+            if (nxconvertCommand != null) {
+                validator = new ValidatorUtils(nxsFile,nxconvertCommand);
+            } else {
+                dialogReportProblem.showMessageDialog(
+                        frame,
+                        "Problem Validating file, nxconvert command is not set.");
+            }
+            validator.setSchematron(nxdlFile);
+            validator.setReduced(reducedFile);
+            resultsFile = validator.validate();
+
+            SVRLNodeFilter filter = new SVRLNodeFilter();
+
+            resultsDoc = builder.parse(resultsFile);
+            filter.setFilterDocument(resultsDoc);
+            filter.setDocument(reducedDoc);
+            filter.getBadNodeList();
+
+            treeUtils.setResultsDoc(jTree, resultsDoc);
+            treeUtils.setResultsFile(jTree, resultsFile);
+
+            treeUtils.setValidated(jTree, resultsFile);
+
+            //domTree.updateTree();
+            Logger.getLogger(NXvalidateFrame.class.getName()).log(
+                    Level.INFO, "Finished Validating.");
+
+            if(isNotBulk){
+                dialogReportProblem.showMessageDialog(
+                    frame,
+                    bundle.getString("validationCompleteMessage"));
+            }
+        } catch (NXvalidateException ex) {
+            dialogReportProblem.showMessageDialog(
+                        frame,
+                        "Problem Validating file: " + nxsFile);
+            Logger.getLogger(FileActions.class.getName()).log(
+                    Level.WARNING, null, ex);
+        } catch (SAXException ex) {
+            dialogReportProblem.showMessageDialog(
+                        frame,
+                        "Problem Validating file: " + nxsFile);
+            Logger.getLogger(FileActions.class.getName()).log(
+                    Level.WARNING, null, ex);
+        } catch (IOException ex) {
+            dialogReportProblem.showMessageDialog(
+                        frame,
+                        "Problem Validating file: " + nxsFile);
+            Logger.getLogger(FileActions.class.getName()).log(
+                    Level.WARNING, null, ex);
+        } catch (Exception ex) {
+            dialogReportProblem.showMessageDialog(
+                        frame,
+                        "Problem Validating file: " + nxsFile);
+            Logger.getLogger(FileActions.class.getName()).log(
+                    Level.WARNING, null, ex);
+        }
+
+    }
+
+    public void loadFile() {
+
+        try {
+
+            //Reduce the file with NXConvert.
+            NXconvert convert = new NXconvert(nxsFile, true, nxconvertCommand);
+            File reducedFile = convert.convert();
+            
+            if(reducedFile==null){
+                return;
+            }
+
+            //Display reduced file
+            Document document = builder.parse(reducedFile);
+            document.setUserData("file", nxsFile, null);
+            NXNodeMapper node = new NXNodeMapper(
+                    document, true, nxsFile);
+            node.setReducedDoc(document);
+            this.reducedDoc = document;
+            
+            if (nxdlFile != null) {
+                node.setNXDLFile(nxdlFile);
+            }
+            this.reducedFile = reducedFile;
+            node.setReducedFile(reducedFile);
+            node.setRoot(root);
+            root.insert(node,0);
+            //domTree.updateTree();
+
+            
+        } catch (NXvalidateException ex) {
+            conversionFail = true;
+            badDataFileList.add(nxsFile.getAbsolutePath());
+        } catch (InterruptedException ex) {
+            Logger.getLogger(
+                    FileActions.class.getName()).log(Level.SEVERE,
+                    null, ex);
+        } catch (SAXException ex) {
+            Logger.getLogger(
+                    FileActions.class.getName()).log(Level.SEVERE,
+                    null, ex);
+        } catch (IOException ex) {
+            Logger.getLogger(
+                    FileActions.class.getName()).log(Level.SEVERE,
+                    null, ex);
+        }
+    }
+
+    private ArrayList<String> getSubFiles(String file) {
+
+        ArrayList<String> fileList = new ArrayList<String>();
+
+        File tmpFile = new File(file);
+
+        String[] files = tmpFile.list();
+
+        if (files == null) {
+            return fileList;
+        }
+
+        for (int i = 0; i < files.length; ++i) {
+            if (new File(tmpFile.getAbsolutePath() + tmpFile.separator + files[i]).isDirectory()) {
+                fileList.addAll(getSubFiles(tmpFile.getAbsolutePath() + tmpFile.separator + files[i]));
+            } else {
+                fileList.add(tmpFile.getAbsolutePath() + tmpFile.separator + files[i]);
+            }
+        }
+
+        return fileList;
+    }
+
+    public void bulkCheck() {
+
+        if (dataFiles != null) {
+
+            dataFileList = new ArrayList<String>();
+
+            for (int i = 0; i < dataFiles.length; ++i) {
+
+                if (dataFiles[i].isDirectory()) {
+                    dataFileList.addAll(getSubFiles(dataFiles[i].getAbsolutePath()));
+                } else {
+                    dataFileList.add(dataFiles[i].getAbsolutePath());
+                }
+
+            }
+            this.dataFileList = dataFileList;
+        }
+
+    }
+
+    public void bulkLoad() {
+        //Do conversion for each selected file.
+        badDataFileList = new ArrayList<String>();
+        if (dataFileList != null) {
+            for (int i = 0; i < dataFileList.size(); ++i) {
+                nxsFile = new File(dataFileList.get(i));
+                loadFile();
+            }
+            domTree.updateTree();
+        }
+    }
+
+    public void bulkValidate() {
+
+        //Do Conversion and validation.
+        badDataFileList = new ArrayList<String>();
+        if (dataFileList != null) {
+            for (int i = 0; i < dataFileList.size(); ++i) {
+                nxsFile = new File(dataFileList.get(i));
+                loadFile();
+                validateFile();
+            }
+            domTree.updateTree();
+            dialogReportProblem.showMessageDialog(
+                    frame,
+                    bundle.getString("validationCompleteMessage"));
+        }
+
+    }
+
+    private void copy(File src, File dst) throws IOException {
+        InputStream in = new FileInputStream(src);
+        OutputStream out = new FileOutputStream(dst);
+
+        byte[] buf = new byte[1024];
+        int len;
+        while ((len = in.read(buf)) > 0) {
+            out.write(buf, 0, len);
+        }
+        in.close();
+        out.close();
+    }
+
+    public void saveResults(File directory){
+
+        NXNodeMapper tmpNode = null;
+        File tmpReduced = null;
+        File tmpResults = null;
+        Enumeration children = root.children();
+        
+        while(children.hasMoreElements()){
+
+            tmpNode = (NXNodeMapper)children.nextElement();
+            
+            if(tmpNode.getReducedFile()!=null){
+
+                tmpReduced = new File(directory.getAbsolutePath() +
+                        directory.separator + tmpNode.getReducedFile().getName());
+                tmpResults = new File(directory.getAbsolutePath() +
+                        directory.separator + tmpNode.getResultsFile().getName());
+                try{
+                    copy(tmpNode.getReducedFile(),tmpReduced);
+                    copy(tmpNode.getResultsFile(),tmpResults);
+                } catch (IOException ex) {
+                    Logger.getLogger(
+                    FileActions.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
+        }
+    }
+
+    public void run() {
+
+        if (which == 1) {
+            isNotBulk = true;
+            loadFile();
+            domTree.updateTree();
+            isNotBulk = false;
+        } else if (which == 2) {
+            isNotBulk = true;
+            validateFile();
+            domTree.updateTree();
+            isNotBulk = false;
+        } else if (which == 3) {
+            bulkCheck();
+        } else if (which == 4) {
+            bulkLoad();
+        }else if (which == 5) {
+            bulkValidate();
+        } else if (which == 6) {
+            saveResults(saveDirectory);
+        }
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/Logger.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/Logger.java
new file mode 100644
index 0000000..3a2f42a
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/Logger.java
@@ -0,0 +1,94 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * Logger.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.util.Vector;
+
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+final class Logger {
+	private static final Logger logger = new Logger();
+
+	private static int loggingLevel;
+	private static Vector<ChangeListener> listeners
+	 							= new Vector<ChangeListener>();
+	private static boolean hasListeners = false;
+	
+	public static final int TRACE = 0;
+	public static final int DEBUG = 1;
+	public static final int INFO = 2;
+	public static final int WARN = 3;
+	public static final int ERROR = 4;
+
+	private Logger() {
+		loggingLevel = INFO;
+	}
+
+	public static void addListener(final ChangeListener listener) {
+		if (listener == null)
+			return;
+		listeners.add(listener);
+		hasListeners = true;
+	}
+
+	public static void setLevel(final int level) {
+		loggingLevel = level;
+	}
+
+	static Logger getInstance() {
+		return logger;
+	}
+
+	private void println(final String message, final int level) {
+		if (level >= loggingLevel) {
+			if (hasListeners) {
+				ChangeEvent event = new ChangeEvent(message);
+				for (ChangeListener listener : listeners) {
+					listener.stateChanged(event);
+				}
+			} else {
+				System.out.println(message);
+			}
+		}
+	}
+
+	public void trace(final String message) {
+		this.println(message, TRACE);
+	}
+	public void debug(final String message) {
+		this.println(message, DEBUG);
+	}
+	public void info(final String message) {
+		this.println(message, INFO);
+	}
+	public void warn(final String message) {
+		this.println(message, WARN);
+	}
+	public void error(final String message) {
+		this.println(message, ERROR);
+	}
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXLoadFilesDialog.form b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXLoadFilesDialog.form
new file mode 100644
index 0000000..e2132bc
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXLoadFilesDialog.form
@@ -0,0 +1,169 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.JFileChooser" name="jFileChooser1">
+    </Component>
+    <Component class="javax.swing.JOptionPane" name="messageOptionPane">
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Open Files"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" alignment="1" min="-2" max="-2" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.CompoundBorderInfo">
+            <CompoundBorder>
+              <Border PropertyName="outside" info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="5"/>
+              </Border>
+              <Border PropertyName="inside" info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
+                <BevelBorder/>
+              </Border>
+            </CompoundBorder>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" alignment="0" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="nxsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="nxdlLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                              <Component id="nxdcTextField" alignment="0" max="32767" attributes="1"/>
+                              <Component id="nxsTextField" alignment="0" pref="421" max="32767" attributes="1"/>
+                          </Group>
+                      </Group>
+                      <Component id="cancelButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="1" attributes="0">
+                      <Component id="openButton1" alignment="1" min="-2" max="-2" attributes="0"/>
+                      <Component id="openButton2" alignment="1" min="-2" max="-2" attributes="0"/>
+                      <Component id="OKButton" alignment="1" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="nxsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="nxsTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="openButton1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="nxdlLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="nxdcTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="openButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="OKButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="nxsLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Load NXS:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JTextField" name="nxsTextField">
+          <Properties>
+            <Property name="editable" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="openButton1">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Open"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButton1ActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="nxdlLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Load NXDL:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JTextField" name="nxdcTextField">
+          <Properties>
+            <Property name="editable" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="openButton2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Open"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButton2ActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="cancelButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="CANCEL"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="OKButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="OK"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="OKButtonActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXLoadFilesDialog.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXLoadFilesDialog.java
new file mode 100644
index 0000000..a453782
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXLoadFilesDialog.java
@@ -0,0 +1,281 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXLoadFilesDialog.java
+ *
+ * Created on 16-Jun-2010, 11:56:31
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class NXLoadFilesDialog extends javax.swing.JDialog {
+
+    private File nxs = null;
+    private File nxdl = null;
+    private boolean OKButtonUsed = false;
+    private CheckNexusFileType check = null;
+    private ResourceBundle bundle = null;
+    /** Creates new form NXLoadFilesDialog */
+    public NXLoadFilesDialog(java.awt.Frame parent, boolean modal) {
+        super(parent, modal);
+        initComponents();
+        check = new CheckNexusFileType();
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jFileChooser1 = new javax.swing.JFileChooser();
+        messageOptionPane = new javax.swing.JOptionPane();
+        jPanel1 = new javax.swing.JPanel();
+        nxsLabel = new javax.swing.JLabel();
+        nxsTextField = new javax.swing.JTextField();
+        openButton1 = new javax.swing.JButton();
+        nxdlLabel = new javax.swing.JLabel();
+        nxdcTextField = new javax.swing.JTextField();
+        openButton2 = new javax.swing.JButton();
+        cancelButton = new javax.swing.JButton();
+        OKButton = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Open Files");
+        setResizable(false);
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5), javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)));
+
+        nxsLabel.setText("Load NXS:");
+
+        nxsTextField.setEditable(false);
+
+        openButton1.setText("Open");
+        openButton1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                openButton1ActionPerformed(evt);
+            }
+        });
+
+        nxdlLabel.setText("Load NXDL:");
+
+        nxdcTextField.setEditable(false);
+
+        openButton2.setText("Open");
+        openButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                openButton2ActionPerformed(evt);
+            }
+        });
+
+        cancelButton.setText("CANCEL");
+        cancelButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                cancelButtonActionPerformed(evt);
+            }
+        });
+
+        OKButton.setText("OK");
+        OKButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                OKButtonActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(nxsLabel)
+                            .addComponent(nxdlLabel))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                            .addComponent(nxdcTextField)
+                            .addComponent(nxsTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 421, Short.MAX_VALUE)))
+                    .addComponent(cancelButton))
+                .addGap(15, 15, 15)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(openButton1)
+                    .addComponent(openButton2)
+                    .addComponent(OKButton))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(nxsLabel)
+                    .addComponent(nxsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(openButton1))
+                .addGap(28, 28, 28)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(nxdlLabel)
+                    .addComponent(nxdcTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(openButton2))
+                .addGap(27, 27, 27)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(cancelButton)
+                    .addComponent(OKButton))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void openButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButton1ActionPerformed
+
+        if (evt.getSource() == openButton1) {
+
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+                nxs = jFileChooser1.getSelectedFile();
+
+                if(check.checkNexusFile(nxs)){
+                    nxsTextField.setText(nxs.getAbsolutePath());
+                    nxsTextField.setToolTipText(nxs.getAbsolutePath());
+                } else{
+                    nxs = null;
+                    messageOptionPane.showMessageDialog(this,
+                        bundle.getString("notNXDLFileMessage"));
+                }
+
+                
+            } else {
+                nxs = null;
+            }
+
+        }
+}//GEN-LAST:event_openButton1ActionPerformed
+
+    private void openButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButton2ActionPerformed
+
+        if (evt.getSource() == openButton2) {
+
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+                nxdl = jFileChooser1.getSelectedFile();
+
+                if(check.checkNXDLFile(nxdl)){
+                    nxdcTextField.setText(nxdl.getAbsolutePath());
+                    nxdcTextField.setToolTipText(nxdl.getAbsolutePath());
+                } else{
+                    nxdl = null;
+                    messageOptionPane.showMessageDialog(this,
+                        bundle.getString("notNXDLFileMessage"));
+                }
+                
+                
+            } else {
+                nxdl = null;
+            }
+
+        }
+}//GEN-LAST:event_openButton2ActionPerformed
+
+    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
+        if (evt.getSource() == cancelButton) {
+            OKButtonUsed = false;
+            this.setVisible(false);
+        }
+}//GEN-LAST:event_cancelButtonActionPerformed
+
+    private void OKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OKButtonActionPerformed
+        if (evt.getSource() == OKButton) {
+            OKButtonUsed = true;
+            this.setVisible(false);
+        }
+    }//GEN-LAST:event_OKButtonActionPerformed
+
+    public File getNXSFile() {
+        return nxs;
+    }
+
+    public File getNXDLFile() {
+        return nxdl;
+    }
+
+    public boolean OKButtonUsed() {
+        return OKButtonUsed;
+    }
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+
+            public void run() {
+                NXLoadFilesDialog dialog = new NXLoadFilesDialog(new javax.swing.JFrame(), true);
+                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
+
+                    public void windowClosing(java.awt.event.WindowEvent e) {
+                        System.exit(0);
+                    }
+                });
+                dialog.setVisible(true);
+            }
+        });
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton OKButton;
+    private javax.swing.JButton cancelButton;
+    private javax.swing.JFileChooser jFileChooser1;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JOptionPane messageOptionPane;
+    private javax.swing.JTextField nxdcTextField;
+    private javax.swing.JLabel nxdlLabel;
+    private javax.swing.JLabel nxsLabel;
+    private javax.swing.JTextField nxsTextField;
+    private javax.swing.JButton openButton1;
+    private javax.swing.JButton openButton2;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXNodeMapper.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXNodeMapper.java
new file mode 100644
index 0000000..b87d5c4
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXNodeMapper.java
@@ -0,0 +1,945 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXNodeMapper.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreeNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class NXNodeMapper implements MutableTreeNode {
+
+    private Node domNode = null;
+    private String nodeName = null;
+    private boolean isRoot = false;
+    private boolean isLeaf = false;
+    private boolean isDocument = false;
+    private boolean allowsChildren = false;
+    private ArrayList<NXNodeMapper> documents = null;
+    static final int ELEMENT_TYPE = Node.ELEMENT_NODE;
+    private int childCount = 0;
+    private ArrayList<Node> children = null;
+    private NXNodeMapper root = null;
+    private File nxsFile = null;
+    private File nxdlFile = null;
+    private File reducedFile = null;
+    private File resultsFile = null;
+    private Document reducedDoc = null;
+    private Document resultsDoc = null;
+    private boolean badNode = false;
+    private boolean warnNode = false;
+    private boolean validatedNode = false;
+    private Object userObject = null;
+
+    // Construct an Adapter node from a DOM node
+    public NXNodeMapper(Node node, boolean isDocument, File nxsFile) {
+
+        this.isDocument = isDocument;
+        domNode = node;
+
+        allowsChildren = true;
+        if (node.getNodeType() != ELEMENT_TYPE) {
+            isLeaf = true;
+        }
+
+        this.nxsFile = nxsFile;
+        nodeName = nxsFile.getAbsolutePath();
+        children = getElements();
+    }
+
+    // Construct an Adapter node from a DOM node
+    public NXNodeMapper(Node node, boolean isDocument, String nodeName) {
+
+        this.isDocument = isDocument;
+        domNode = node;
+
+        allowsChildren = true;
+        if (node.getNodeType() != ELEMENT_TYPE) {
+            isLeaf = true;
+        }
+
+        this.nodeName = nodeName;
+        children = getElements();
+    }
+
+    public NXNodeMapper(String nodeName) {
+        this.nodeName = nodeName;
+        isRoot = true;
+        allowsChildren = true;
+        documents = new ArrayList<NXNodeMapper>();
+    }
+
+    /**
+     * Check to see if this node is the root node.
+     * @return true is it is the root node, false otherwise.
+     */
+    public boolean isRoot() {
+        return isRoot;
+    }
+
+    /**
+     * Check to see if this node is a document, i.e the list of nodes directly
+     * under the root node that are the open NXS documents.
+     *
+     * @return true if the node is a document node.
+     */
+    public boolean isDocument() {
+        return isDocument;
+    }
+
+    /**
+     * Set the flag that says that this node is a documents node i.e. one of the
+     * list of nodes directly under the root node that are the open NXS documents.
+     * @param isDocument a flag which is true if the node is a document node.
+     */
+    public void setDocument(boolean isDocument) {
+        this.isDocument = isDocument;
+    }
+
+    /**
+     * Set the root node that this node belongs to.
+     * @param root the root node.
+     */
+    public void setRoot(NXNodeMapper root) {
+        this.root = root;
+    }
+
+    /**
+     * Get the NXS file belonging to the root node. Any other node should return
+     * null
+     * @return the NXS file as a File object.
+     */
+    public File getNXSFile() {
+        return nxsFile;
+    }
+
+    /**
+     * Get the NXDL file belonging to the root node. Any other node should return
+     * null
+     * @return the NXDL file as a File object.
+     */
+    public File getNXDLFile() {
+        return nxdlFile;
+    }
+
+    /**
+     * Set the NXDL file belonging to the root node. Should not be set.
+     * @param nxdlFile the NXDL file as a File object.
+     */
+    public void setNXDLFile(File nxdlFile) {
+        this.nxdlFile = nxdlFile;
+    }
+
+    /**
+     * Get the resultant file produced after NXConvert has been run on the
+     * NXS file
+     * (reduced to XML).
+     * @return the NXConvert reduced file.
+     */
+    public File getReducedFile() {
+        return reducedFile;
+    }
+
+    /**
+     * Set the resultant file produced after NXConvert has been run on the
+     * NXS file.
+     * @param reducedFile the NXConvert reduced file.
+     */
+    public void setReducedFile(File reducedFile) {
+        this.reducedFile = reducedFile;
+    }
+
+    /**
+     * Get the resultant file produced after the validation procedure has been
+     * performed.
+     * @return the validation results file.
+     */
+    public File getResultsFile() {
+        return resultsFile;
+    }
+
+    /**
+     * Get the resultant file produced after the validation procedure has been
+     * performed.
+     * @param resultsFile the validation results file.
+     */
+    public void setResultsFile(File resultsFile) {
+        this.resultsFile = resultsFile;
+    }
+
+    /**
+     * Get the resultant DOM document produced after the validation procedure
+     * has been performed.
+     * @return the validation results DOM document.
+     */
+    public Document getResultsDoc() {
+        return resultsDoc;
+    }
+
+    /**
+     * Get the resultant DOM document produced after the validation procedure
+     * has been performed.
+     * @param resultsDoc the validation results DOM document.
+     */
+    public void setResultsDoc(Document resultsDoc) {
+        this.resultsDoc = resultsDoc;
+    }
+
+    /**
+     * Initially the Nexus file is converted to a reduced (all data removed)
+     * XML document via the Nexus convert command. This method gets the
+     * W3C DOM document of the reduced XML file.
+     * @return the W3C DOM document of the reduced XML file.
+     */
+    public Document getReducedDoc() {
+        return reducedDoc;
+    }
+
+    /**
+     * Initially the Nexus file is converted to a reduced (all data removed)
+     * XML document via the Nexus convert command. This method sets the
+     * W3C DOM document of the reduced XML file.
+     * @param reducedDoc the W3C DOM document of the reduced XML file.
+     */
+    public void setReducedDoc(Document reducedDoc) {
+        this.reducedDoc = reducedDoc;
+    }
+
+    /**
+     * If a node in the reduced XML document fails one of the schematron tests
+     * then the node can be marked as a bad node with a boolean flag. The flag
+     * is set to true if the node failed one of the tests.
+     * @param badNode true if the node failed one of the schematron tests.
+     */
+    public void setBadNode(boolean badNode) {
+        domNode.setUserData("bad", new Boolean(badNode),null);
+        this.badNode = badNode;
+    }
+
+    /**
+     * If a node in the reduced XML document fails one of the schematron tests
+     * then the node can be marked as a bad node with a boolean flag. The flag
+     * is set to true if the node failed one of the tests.
+     * @return true if the node failed one of the schematron tests.
+     */
+    public boolean getBadNode() {
+        checkBadNode();
+        return badNode;
+    }
+
+    /**
+     * If a node in the reduced XML document fails one of the schematron report tests
+     * then the node can be marked as a warning node with a boolean flag. The flag
+     * is set to true if the node failed one of the tests.
+     * @param warnNode true if the node failed one of the schematron tests.
+     */
+    public void setWarnNode(boolean warnNode) {
+        domNode.setUserData("warn", new Boolean(warnNode),null);
+        this.warnNode = warnNode;
+    }
+
+    /**
+     * If a node in the reduced XML document fails one of the schematron report tests
+     * then the node can be marked as a warning node with a boolean flag. The flag
+     * is set to true if the node failed one of the tests.
+     * @return true if the node failed one of the schematron tests.
+     */
+    public boolean getWarnNode() {
+        checkWarnNode();
+        return warnNode;
+    }
+
+    /**
+     * If a node has been validated then we can indicate the fact with a boolean flag. The flag
+     * is set to true if the node has been validated.
+     * @param validatedNode true if the node has been validated.
+     */
+    public void setValidatedNode(boolean validatedNode) {
+        domNode.setUserData("validated", new Boolean(validatedNode),null);
+        this.validatedNode = validatedNode;
+    }
+
+    /**
+     * If a node has been validated then we can indicate the fact with a boolean flag. The flag
+     * is set to true if the node has been validated.
+     * @return true if the node failed one of the schematron tests.
+     */
+    public boolean getValidatedNode() {
+        checkValidatedNode();
+        return validatedNode;
+    }
+
+    /**
+     * Get the W3C DOM node corresponding to this tree node.
+     * @return the W3C DOM node corresponding to this tree node.
+     */
+    public Node getDomNode() {
+        return domNode;
+    }
+
+    /**
+     * A convenience method to force the checking if a node is bad
+     * (failed schematron tests). Sets the flag to indicate the node is bad.
+     */
+    public void checkBadNode() {
+        if (!isRoot) {
+            Boolean bad = (Boolean) domNode.getUserData("bad");
+            if (bad != null) {
+                this.badNode = bad.booleanValue();
+            }
+        }
+    }
+
+    /**
+     * A convenience method to force the checking if a node has warnings
+     * . Sets the flag to indicate the node has warnings.
+     */
+    public void checkWarnNode() {
+        if (!isRoot) {
+            Boolean warn = (Boolean) domNode.getUserData("warn");
+            if (warn != null) {
+                this.warnNode = warn.booleanValue();
+            }
+        }
+    }
+
+    /**
+     * A convenience method to force the checking if a node has been validated
+     * . Sets the flag to indicate the node has warnings.
+     */
+    public void checkValidatedNode() {
+        if (!isRoot) {
+            Boolean validated = (Boolean) domNode.getUserData("validated");
+            if (validated != null) {
+                this.validatedNode = validated.booleanValue();
+            }
+        }
+    }
+
+    /**
+     * A method to check to see if any of a nodes children are bad.
+     * @return true if there are any bad children
+     *
+     */
+    public boolean checkBadChildren() {
+
+        boolean result = false;
+        Boolean bad;
+
+
+        if (!isRoot) {
+
+            for (int i = 0; i < domNode.getChildNodes().getLength(); i++) {
+                Node node = domNode.getChildNodes().item(i);
+                bad = (Boolean) node.getUserData("bad");
+                if (bad != null) {
+                    result = true;
+                }
+
+                // Now let's check the grandkids... and beyond...
+                bad = (Boolean) checkChildren(node);
+                if (bad) {
+                    result = true;
+                }
+            }
+
+        }
+        return result;
+    }
+
+    /**
+     * Recursive method used by checkBadChildren() to recursively check down
+     * the tree.
+     * @param node
+     * @return true if a child anywhere in the tree is bad!
+     */
+    private boolean checkChildren(Node node) {
+        boolean result = false;
+        for (int i = 0; i < node.getChildNodes().getLength(); i++) {
+            Node tmpNode = node.getChildNodes().item(i);
+            if (tmpNode.hasChildNodes()) {
+                checkChildren(tmpNode);
+            }
+            Boolean bad = (Boolean) tmpNode.getUserData("bad");
+            if (bad != null) {
+                result = true;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Resets the various properties of a node, i.e flag to indicate that it
+     * is a bad node, the text for the tests that failed etc.
+     */
+    public void resetNode() {
+
+        badNode = false;
+        domNode.setUserData("texts", null, null);
+        domNode.setUserData("tests", null, null);
+        domNode.setUserData("diags", null, null);
+        domNode.setUserData("diagatts", null, null);
+        domNode.setUserData("bad", new Boolean(false), null);
+    }
+
+    /**
+     * This is a list of text strings which correspond to the error message
+     * results of the schematron tests.
+     * @return list of text strings corresponding to the schematron test results.
+     */
+    public ArrayList<String> getNodeTexts() {
+        if (!isRoot) {
+            return (ArrayList<String>) domNode.getUserData("texts");
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * This is a list of text strings which correspond to the schematron
+     * test descriptions.
+     * @return list of text strings corresponding to the schematron test
+     *         descriptions.
+     */
+    public ArrayList<String> getNodeTests() {
+        if (!isRoot) {
+            return (ArrayList<String>) domNode.getUserData("tests");
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * This is a list of text strings which correspond to the schematron
+     * diagnostic errors.
+     * @return list of text strings corresponding to the schematron
+     *         diagnostic errors.
+     */
+    public ArrayList<String> getNodeDiags() {
+        if (!isRoot) {
+            return (ArrayList<String>) domNode.getUserData("diags");
+        } else {
+            return null;
+        }
+    }
+
+    public ArrayList<String> getNodeDiagAtts() {
+        if (!isRoot) {
+            return (ArrayList<String>) domNode.getUserData("diagatts");
+        } else {
+            return null;
+        }
+    }
+
+    // Return the node name
+    @Override
+    public String toString() {
+        return nodeName;
+    }
+
+    public int getIndex(TreeNode child1) {
+
+        NXNodeMapper child = (NXNodeMapper) child1;
+        int count = getChildCount();
+        if (isRoot) {
+
+            if (documents.contains(child)) {
+
+                return documents.indexOf(child);
+            }
+
+        } else {
+            for (int i = 0; i
+                    < count; i++) {
+                NXNodeMapper n = this.getChildAt(i);
+
+                if (child.domNode == n.domNode) {
+                    return i;
+                }
+            }
+        }
+        return -1; // Should never get here.
+    }
+
+    public NXNodeMapper getChildAt(int searchIndex) {
+
+        if (isRoot) {
+
+            return documents.get(searchIndex);
+
+        } else {
+            //Note: JTree index is zero-based.
+            Node node = domNode.getChildNodes().item(searchIndex);
+
+            // Return Nth displayable node
+            int elementNodeIndex = 0;
+
+
+
+            for (int i = 0; i
+                    < domNode.getChildNodes().getLength(); i++) {
+                node = domNode.getChildNodes().item(i);
+
+                if ((node.getNodeType() == ELEMENT_TYPE)
+                        && (elementNodeIndex++ == searchIndex)) {
+                    break;
+                }
+            }
+            return new NXNodeMapper(node, false, node.getNodeName());
+        }
+
+    }
+
+    public int getChildCount() {
+
+        if (isRoot) {
+
+            return documents.size();
+
+
+
+        }
+
+        return childCount;
+
+
+
+    }
+
+    public Enumeration children() {
+        return new children();
+
+    }
+
+    public boolean isLeaf() {
+        return isLeaf;
+    }
+
+    public boolean getAllowsChildren() {
+        return allowsChildren;
+    }
+
+    public TreeNode getParent() {
+
+        if (isRoot) {
+            return null;
+        } else if (isDocument) {
+
+            return root;
+
+        } else if (domNode.getParentNode() != null) {
+
+            if (domNode.getParentNode().getNodeType() == domNode.DOCUMENT_NODE) {
+
+                Document doc = (Document) domNode.getParentNode();
+
+                return new NXNodeMapper(domNode.getParentNode(), true,
+                        ((File) doc.getUserData("file")).getAbsolutePath());
+
+            } else {
+
+                return new NXNodeMapper(domNode.getParentNode(), false,
+                        domNode.getParentNode().getNodeName());
+            }
+        } else {
+            return null;
+        }
+
+    }
+
+    public NXNodeMapper getRoot() {
+
+        if(domNode==null){
+             return null;
+        }
+
+        Node tempNode = domNode.getParentNode();
+
+        boolean gotRoot = false;
+        NXNodeMapper rootNode = null;
+
+        if (isRoot) {
+            return null;
+        } else if (isDocument) {
+
+            return this;
+
+        } else if (tempNode != null) {
+
+            while(!gotRoot){
+
+                if (tempNode.getNodeType() == domNode.DOCUMENT_NODE) {
+
+                    Document doc = (Document) tempNode;
+
+                    rootNode = new NXNodeMapper(tempNode, true,
+                        ((File) doc.getUserData("file")).getAbsolutePath());
+                    gotRoot = true;
+                }
+                else{
+                    tempNode = tempNode.getParentNode();
+                }
+            }
+
+        } else {
+            return null;
+        }
+
+        return rootNode;
+
+    }
+
+    /**
+     * Each node of the reduced XML document may have attributes associated
+     * with it, this method provides a list of the attributes. Each string
+     * contains the attribute name and the value.
+     * @return a list of the attributes and their values.
+     */
+    public String[] getAttributeList() {
+
+        if (isRoot) {
+            return new String[0];
+
+
+        }
+
+        ArrayList<String> atts = new ArrayList<String>();
+
+
+
+        if (domNode.hasAttributes()) {
+
+            NamedNodeMap att = domNode.getAttributes();
+
+
+            int na = domNode.getAttributes().getLength();
+
+
+
+            for (int i = 0; i
+                    < na;
+                    ++i) {
+                atts.add(att.item(i).getNodeName() + " = "
+                        + att.item(i).getNodeValue());
+
+
+            }
+
+        }
+        return atts.toArray(new String[0]);
+    }
+
+    /**
+     * Each node of the reduced XML document may have a value associated with it.
+     * This method returns that value as a string.
+     * @return the value of the XML node.
+     */
+    public String getValue() {
+
+        if (isRoot) {
+            return "";
+
+
+        }
+
+        if (domNode.getNodeType() == ELEMENT_TYPE) {
+            return getTextValue(domNode);
+
+
+        }
+
+        if (domNode.getTextContent() != null) {
+            return domNode.getTextContent().trim();
+
+
+        }
+
+        return "";
+
+
+
+    }
+
+    private ArrayList<Node> getElements() {
+
+        ArrayList<Node> nodes = new ArrayList<Node>();
+
+
+
+        for (int i = 0; i
+                < domNode.getChildNodes().getLength(); i++) {
+            Node node = domNode.getChildNodes().item(i);
+
+
+
+            if (node.getNodeType() == ELEMENT_TYPE) {
+                nodes.add(node);
+
+
+                ++childCount;
+
+
+            }
+        }
+        return nodes;
+
+
+    }
+
+    private String getTextValue(Node node) {
+
+        if (node.hasChildNodes()) {
+
+            NodeList nodes = node.getChildNodes();
+
+
+
+            for (int i = 0; i
+                    < nodes.getLength();
+                    ++i) {
+                if (nodes.item(i).getNodeType() == Node.TEXT_NODE) {
+                    return nodes.item(i).getTextContent().trim();
+
+
+                }
+            }
+
+        }
+        return "";
+
+
+    }
+
+    /**
+     * Returns a list of nodes that represent the Nexus documents that are open
+     * i.e. that have been reduced.
+     * @return a list of Nexus document nodes.
+     */
+    public ArrayList<NXNodeMapper> getOpenNodes() {
+        return documents;
+    }
+
+    /**
+     * Removes the list of nodes that represent the Nexus documents that are
+     * open i.e. that have been reduced.
+     */
+    public void removeAllNodes() {
+        documents.clear();
+    }
+
+
+    /**
+     * Check to see if the node has any vary bad kids, return true if it has.
+     * @return true if the kids are bad.
+     */
+    public boolean hasBadChildren(){
+        TreeUtils treeUtils = new TreeUtils();
+        return treeUtils.hasBadChildren(this);
+    }
+
+
+    /**
+     * A class that represents the child nodes of a node from a
+     * reduced document. The child nodes are represented as an enumeration.
+     */
+    private class children implements Enumeration {
+
+        private int count = 0;
+        private boolean more = true;
+        private Node node = null;
+        private NXNodeMapper nxNode = null;
+
+        public boolean hasMoreElements() {
+
+            if (isRoot) {
+
+                if (documents == null) {
+                    more = false;
+                    return more;
+                }
+
+                if (count < documents.size()) {
+                    more = true;
+                } else {
+                    more = false;
+                }
+            } else {
+
+                if (children == null) {
+                    more = false;
+                    return more;
+                }
+
+                if (count < children.size()) {
+                    more = true;
+                } else {
+                    more = false;
+                }
+
+            }
+            return more;
+        }
+
+        public Object nextElement() {
+
+            if (isRoot) {
+
+                if (count < documents.size()) {
+                    nxNode = documents.get(count);
+                    count++;
+                    return nxNode;
+                } else {
+                    throw new NoSuchElementException();
+                }
+
+            } else {
+
+                if (count < children.size()) {
+                    node = children.get(count);
+                    count++;
+                    return new NXNodeMapper(node, false, node.getNodeName());
+                } else {
+                    throw new NoSuchElementException();
+                }
+
+            }
+        }
+    }
+
+    public void insert(MutableTreeNode child, int index) {
+
+        NXNodeMapper childNode = (NXNodeMapper) child;
+
+
+
+        if (isRoot) {
+            documents.add(index, childNode);
+
+
+        } else {
+            NodeList list = domNode.getChildNodes();
+
+
+
+            for (int i = 0; i
+                    < list.getLength();
+                    ++i) {
+                if (i == index) {
+                    domNode.insertBefore(childNode.domNode, list.item(i));
+
+
+                }
+            }
+        }
+    }
+
+    public void remove(int index) {
+        if (isRoot) {
+
+            documents.remove(index);
+
+
+
+        } else {
+
+            NodeList list = domNode.getChildNodes();
+
+
+
+            for (int i = 0; i
+                    < list.getLength();
+                    ++i) {
+                if (i == index) {
+                    domNode.removeChild(list.item(index));
+
+
+                }
+            }
+
+        }
+    }
+
+    public void remove(MutableTreeNode node) {
+
+        NXNodeMapper childNode = (NXNodeMapper) node;
+
+
+
+        if (isRoot) {
+            documents.remove((NXNodeMapper) node);
+
+
+        } else {
+            NodeList list = domNode.getChildNodes();
+
+
+
+            for (int i = 0; i
+                    < list.getLength();
+                    ++i) {
+                if (list.item(i).isSameNode(childNode.domNode)) {
+                    domNode.removeChild(childNode.domNode);
+
+
+                }
+            }
+        }
+    }
+
+    public void removeFromParent() {
+        if (isRoot) {
+            return;
+
+
+        } else {
+            NXNodeMapper parentNode = (NXNodeMapper) getParent();
+            parentNode.remove(this);
+
+
+        }
+    }
+
+    public void setParent(MutableTreeNode newParent) {
+    }
+
+    public void setUserObject(Object object) {
+
+        userObject = object;
+
+
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXReducedToTree.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXReducedToTree.java
new file mode 100644
index 0000000..2577935
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXReducedToTree.java
@@ -0,0 +1,179 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXReducedToTree.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Vector;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import org.nexusformat.nxvalidate.exceptions.NXvalidateException;
+import org.w3c.dom.Document;
+
+
+/**
+ * This maps the NX Reduced XML Document (as a DOM document) to
+ * a JTree model.
+ * @author Stephen Rankin
+ */
+public class NXReducedToTree extends DefaultTreeModel {
+
+    private Vector listenerList = new Vector();
+    private NXNodeMapper root = null;
+
+    public NXReducedToTree(TreeNode root) {
+        super(root);
+        this.root = (NXNodeMapper) root;
+    }
+
+    public void updateTree() {
+
+        TreeModelEvent evt = new TreeModelEvent(this,
+                new Object[]{root});
+        fireTreeStructureChanged(evt);
+    }
+
+    @Override
+    public Object getRoot() {
+
+        return root;
+
+    }
+
+    @Override
+    public boolean isLeaf(Object aNode) {
+        // Determines whether the icon shows up to the left.
+        // Return true for any node with no children
+        NXNodeMapper node = (NXNodeMapper) aNode;
+
+        if (node.getChildCount() > 0) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int getChildCount(Object parent) {
+
+        NXNodeMapper node = (NXNodeMapper) parent;
+        return node.getChildCount();
+
+    }
+
+    @Override
+    public Object getChild(Object parent, int index) {
+
+        NXNodeMapper node = (NXNodeMapper) parent;
+        return node.getChildAt(index);
+
+    }
+
+    @Override
+    public int getIndexOfChild(Object parent, Object child) {
+
+        NXNodeMapper node = (NXNodeMapper) parent;
+        return node.getIndex((NXNodeMapper) child);
+
+    }
+
+    @Override
+    public void valueForPathChanged(TreePath path, Object newValue) {
+    }
+
+    @Override
+    public void addTreeModelListener(TreeModelListener listener) {
+
+        if ((listener != null) && !listenerList.contains(listener)) {
+            listenerList.addElement(listener);
+        }
+
+    }
+
+    @Override
+    public void removeTreeModelListener(TreeModelListener listener) {
+
+        if (listener != null) {
+            listenerList.removeElement(listener);
+        }
+
+    }
+
+    public void fireTreeNodesChanged(TreeModelEvent e) {
+
+        Enumeration listeners = listenerList.elements();
+
+        while (listeners.hasMoreElements()) {
+            TreeModelListener listener =
+                    (TreeModelListener) listeners.nextElement();
+            listener.treeNodesChanged(e);
+        }
+
+
+    }
+
+    public void fireTreeNodesInserted(TreeModelEvent e) {
+
+        Enumeration listeners = listenerList.elements();
+
+        while (listeners.hasMoreElements()) {
+            TreeModelListener listener =
+                    (TreeModelListener) listeners.nextElement();
+            listener.treeNodesInserted(e);
+        }
+
+
+    }
+
+    public void fireTreeNodesRemoved(TreeModelEvent e) {
+
+        Enumeration listeners = listenerList.elements();
+
+        while (listeners.hasMoreElements()) {
+            TreeModelListener listener =
+                    (TreeModelListener) listeners.nextElement();
+            listener.treeNodesRemoved(e);
+        }
+
+
+    }
+
+    public void fireTreeStructureChanged(TreeModelEvent e) {
+
+        Enumeration listeners = listenerList.elements();
+
+        while (listeners.hasMoreElements()) {
+            TreeModelListener listener =
+                    (TreeModelListener) listeners.nextElement();
+            listener.treeStructureChanged(e);
+        }
+
+
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSettingsDialog.form b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSettingsDialog.form
new file mode 100644
index 0000000..876224d
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSettingsDialog.form
@@ -0,0 +1,137 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.JFileChooser" name="jFileChooser1">
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Open Files"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jPanel1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.CompoundBorderInfo">
+            <CompoundBorder>
+              <Border PropertyName="outside" info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="5"/>
+              </Border>
+              <Border PropertyName="inside" info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
+                <BevelBorder/>
+              </Border>
+            </CompoundBorder>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="1" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="1" attributes="0">
+                      <Group type="102" alignment="1" attributes="0">
+                          <Component id="cancelButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace pref="655" max="32767" attributes="0"/>
+                          <Component id="OKButton" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="1" attributes="0">
+                          <Component id="nxdcLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="nxdcTextField" pref="479" max="32767" attributes="1"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="openButton2" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="nxdcLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="nxdcTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="openButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="OKButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="nxdcLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Location of nxconvert binary file:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JTextField" name="nxdcTextField">
+        </Component>
+        <Component class="javax.swing.JButton" name="openButton2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Open"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButton2ActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="cancelButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="CANCEL"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="OKButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="OK"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="OKButtonActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSettingsDialog.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSettingsDialog.java
new file mode 100644
index 0000000..485565f
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSettingsDialog.java
@@ -0,0 +1,217 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXLoadFilesDialog.java
+ *
+ * Created on 16-Jun-2010, 11:56:31
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class NXSettingsDialog extends javax.swing.JDialog {
+
+    
+    private String nxconvert = null;
+    private boolean OKButtonUsed = false;
+    /** Creates new form NXLoadFilesDialog */
+    public NXSettingsDialog(java.awt.Frame parent, boolean modal) {
+        super(parent, modal);
+        initComponents();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jFileChooser1 = new javax.swing.JFileChooser();
+        jPanel1 = new javax.swing.JPanel();
+        nxdcLabel = new javax.swing.JLabel();
+        nxdcTextField = new javax.swing.JTextField();
+        openButton2 = new javax.swing.JButton();
+        cancelButton = new javax.swing.JButton();
+        OKButton = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Open Files");
+        setResizable(false);
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5), javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)));
+
+        nxdcLabel.setText("Location of nxconvert binary file:");
+
+        openButton2.setText("Open");
+        openButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                openButton2ActionPerformed(evt);
+            }
+        });
+
+        cancelButton.setText("CANCEL");
+        cancelButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                cancelButtonActionPerformed(evt);
+            }
+        });
+
+        OKButton.setText("OK");
+        OKButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                OKButtonActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(cancelButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 655, Short.MAX_VALUE)
+                        .addComponent(OKButton))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(nxdcLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(nxdcTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 479, Short.MAX_VALUE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(openButton2)))
+                .addGap(23, 23, 23))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addGap(10, 10, 10)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(nxdcLabel)
+                    .addComponent(nxdcTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(openButton2))
+                .addGap(18, 18, 18)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(OKButton)
+                    .addComponent(cancelButton))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void openButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButton2ActionPerformed
+
+        if(evt.getSource() == openButton2){
+
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+                nxconvert = jFileChooser1.getSelectedFile().getAbsolutePath();
+                nxdcTextField.setText(nxconvert);
+                nxdcTextField.setToolTipText(nxconvert);
+            } else {
+                nxconvert = null;
+            }
+
+        }
+}//GEN-LAST:event_openButton2ActionPerformed
+
+    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
+        if(evt.getSource() == cancelButton){
+            OKButtonUsed = false;
+            this.setVisible(false);
+        }
+}//GEN-LAST:event_cancelButtonActionPerformed
+
+    private void OKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OKButtonActionPerformed
+
+        if(evt.getSource() == OKButton){
+            OKButtonUsed = true;
+            nxconvert = nxdcTextField.getText();
+            this.setVisible(false);
+        }
+    }//GEN-LAST:event_OKButtonActionPerformed
+
+    
+    public String getNXConvertFile(){
+        return nxconvert;
+    }
+
+    public void setNXConvertCommand(String nxconvert){
+        nxconvert = nxconvert;
+        nxdcTextField.setText(nxconvert);
+    }
+
+    public boolean OKButtonUsed(){
+        return OKButtonUsed;
+    }
+
+    /**
+    * @param args the command line arguments
+    */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                NXSettingsDialog dialog = new NXSettingsDialog(new javax.swing.JFrame(), true);
+                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
+                    public void windowClosing(java.awt.event.WindowEvent e) {
+                        System.exit(0);
+                    }
+                });
+                dialog.setVisible(true);
+            }
+        });
+    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton OKButton;
+    private javax.swing.JButton cancelButton;
+    private javax.swing.JFileChooser jFileChooser1;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JLabel nxdcLabel;
+    private javax.swing.JTextField nxdcTextField;
+    private javax.swing.JButton openButton2;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSnode.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSnode.java
new file mode 100644
index 0000000..93fb082
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXSnode.java
@@ -0,0 +1,340 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXSnode.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.util.ArrayList;
+import java.util.Vector;
+
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+class NXSnode extends AbstractNXSnode implements TreeModel {
+
+    private static final String PADDING = "  ";
+    private static final String NXROOT = "NXroot";
+    private static final String TYPE = "NAPItype";
+    private static final String LINK = "NAPIlink";
+    private static final String SDS = "SDS";
+    private static final Logger LOG = Logger.getInstance();
+    private String name;
+    private String nxclass;
+    private ArrayList<AbstractNXSnode> children;
+    private ArrayList<SVRLitem> svrl;
+
+    NXSnode() {
+        super(NXROOT);
+        this.nxclass = "";
+        this.children = new ArrayList<AbstractNXSnode>();
+        this.svrl = new ArrayList<SVRLitem>();
+    }
+
+    NXSnode(final Node node) {
+        this();
+        this.nxclass = node.getNodeName();
+        this.setAttrs(node.getAttributes());
+
+        NodeList nodes = node.getChildNodes();
+        int size = nodes.getLength();
+        for (int i = 0; i < size; i++) {
+            this.addChild(nodes.item(i));
+        }
+    }
+
+    ArrayList<SVRLitem> addSVRL(final Node svrl) {
+        // generate a list of xml error nodes
+        ArrayList<Node> errors = new ArrayList<Node>();
+        addSVRL(svrl, errors);
+
+        // convert it to java classes
+        ArrayList<SVRLitem> items = new ArrayList<SVRLitem>();
+        for (Node node : errors) {
+            items.add(new SVRLitem(node));
+        }
+
+        // find the appropriate nodes to attach it to
+        NXSnode nxsnode;
+        for (SVRLitem item : items) {
+            nxsnode = getNode(this, item.getLocationArray(), 1);
+            nxsnode.svrl.add(item);
+        }
+
+        return items;
+    }
+
+    private static NXSnode getNode(NXSnode parent, ArrayList<String> location,
+            int depth) {
+        // chop up this part of the path to be useful
+        if (location.size() <= depth) {
+            return parent;
+        }
+        String partPath = location.get(depth);
+        int left = partPath.indexOf("[");
+        int right = partPath.indexOf("]", left);
+        String name = partPath.substring(0, left);
+        int index = Integer.parseInt(partPath.substring(left + 1, right)) - 1;
+        LOG.debug("Looking for " + name + "[" + index + "]");
+
+        // get the options - only works with NXSnodes
+        ArrayList<NXSnode> choices = new ArrayList<NXSnode>();
+        NXSnode temp;
+        for (AbstractNXSnode child : parent.children) {
+            if (child instanceof NXSnode) {
+                temp = (NXSnode) child;
+                if (equals(temp.getType(), name)) {
+                    choices.add(temp);
+                } else if (equals(temp.getName(), name)) {
+                    choices.add(temp);
+                }
+            }
+        }
+
+        // pick which one to return
+        int numChoice = choices.size();
+        LOG.debug("Found " + numChoice + " options");
+        if ((numChoice <= 0) || (numChoice < index)) {
+            return parent;
+        }
+        if (depth >= location.size()) {
+            return choices.get(index);
+        } else {
+            return getNode(choices.get(index), location, depth + 1);
+        }
+    }
+
+    private static boolean equals(final String left, final String right) {
+        if (left == null) {
+            return false;
+        }
+        if (right == null) {
+            return false;
+        }
+        return left.equals(right);
+    }
+
+    private static void addSVRL(final Node node, final ArrayList<Node> errors) {
+        if (SVRLitem.hasLocation(node)) {
+            errors.add(node);
+            return;
+        }
+        NodeList nodes = node.getChildNodes();
+        int size = nodes.getLength();
+        for (int i = 0; i < size; i++) {
+            addSVRL(nodes.item(i), errors);
+        }
+    }
+
+    private void setAttrs(final NamedNodeMap attrs) {
+        if (attrs == null) {
+            return;
+        }
+        int size = attrs.getLength();
+        Node attr;
+        for (int i = 0; i < size; i++) {
+            attr = attrs.item(i);
+            this.setAttr(attr.getNodeName(), attr.getNodeValue());
+        }
+    }
+
+    void setAttr(final String name, final String value) {
+        if (name.equals("name")) {
+            this.setName(value);
+            return;
+        } else if (name.equals(TYPE)) {
+            this.setName(this.nxclass);
+            this.nxclass = SDS;
+            return;
+        }
+        this.children.add(0, new Attribute(name, value));
+    }
+
+    private void addChild(final Node node) {
+        if (node == null) {
+            return;
+        }
+        int type = node.getNodeType();
+        if (type != Node.ELEMENT_NODE) {
+            return;
+        }
+        this.children.add(new NXSnode(node));
+    }
+
+    String getType() {
+        return this.nxclass;
+    }
+
+    boolean hasError() {
+        return (this.svrl.size() > 0);
+    }
+
+    private String getAttrValue(final String name) {
+        int size = this.children.size();
+        AbstractNXSnode node;
+        for (int i = 0; i < size; i++) {
+            node = this.children.get(i);
+            if (node instanceof NXSnode) {
+                return "";
+            } else if (this.children.get(i).getName().equals(name)) {
+                return ((Attribute) node).getValue();
+            }
+        }
+        return "";
+    }
+
+    public String toString() {
+        String result;
+        if (NXROOT.equals(this.getName()) || NXROOT.equals(this.nxclass)) {
+            result = NXROOT;
+        } else if (LINK.equals(this.getName())) {
+            result = this.getName() + ":target=" + this.getAttrValue("target");
+        } else if (SDS.equals(this.nxclass)) {
+            result = this.getName() + ":" + TYPE + "=" + this.getAttrValue(TYPE);
+        } else {
+            result = this.getName() + ":" + this.nxclass;
+        }
+        if (this.hasError()) {
+            return result + "*";
+        } else {
+            return result;
+        }
+    }
+
+    public void printTree() {
+        this.printTree("");
+    }
+
+    private void printTree(String padding) {
+        System.out.println(padding + this.toString());
+        padding += PADDING;
+        for (AbstractNXSnode node : this.children) {
+            if (node instanceof NXSnode) // don't bother with attributes
+            {
+                ((NXSnode) node).printTree(padding);
+            }
+        }
+    }
+
+    public boolean equals(final Object other) {
+        // do the simple checks
+        if (this == other) {
+            return true;
+        }
+        if (other == null) {
+            return false;
+        }
+        if (!(other instanceof NXSnode)) {
+            return false;
+        }
+
+        // cast and do deep comparison
+        NXSnode temp = (NXSnode) other;
+        if (!this.getName().equals(temp.getName())) {
+            return false;
+        }
+        if (!this.nxclass.equals(temp.nxclass)) {
+            return false;
+        }
+        if (!this.children.equals(temp.children)) {
+            return false;
+        }
+        if (!this.svrl.equals(temp.svrl)) {
+            return false;
+        }
+
+        // this far must be ok
+        return true;
+    }
+
+    private static NXSnode toNXSnode(final Object object) {
+        if (object == null) {
+            throw new Error("Cannot convert null object to NXSnode");
+        }
+        if (!(object instanceof NXSnode)) {
+            throw new Error("Cannot convert \"" + object + "\"  to NXSnode");
+        }
+        return (NXSnode) object;
+    }
+
+    // ---------------- TreeModel requirements
+    @Override
+    public void addTreeModelListener(TreeModelListener l) {
+        // TODO Auto-generated method stub
+    }
+
+    public Object getChild(Object parent, int index) {
+        if (parent instanceof NXSnode) {
+            return ((NXSnode) parent).children.get(index);
+        } else {
+            return null;
+        }
+    }
+
+    public int getChildCount(Object parent) {
+        NXSnode temp = toNXSnode(parent);
+        return temp.children.size();
+    }
+
+    public int getIndexOfChild(Object parent, Object child) {
+        if (parent == null) {
+            return -1;
+        }
+        if (child == null) {
+            return -1;
+        }
+        NXSnode myParent = toNXSnode(parent);
+        if (child instanceof AbstractNXSnode) {
+            return myParent.children.indexOf((AbstractNXSnode) child);
+        } else {
+            return -1;
+        }
+    }
+
+    public Object getRoot() {
+        return this;
+    }
+
+    public boolean isLeaf(final Object node) {
+        if (node instanceof NXSnode) {
+            return (((NXSnode) node).children.size() <= 0);
+        } else {
+            return true;
+        }
+    }
+
+    @Override
+    public void removeTreeModelListener(TreeModelListener l) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void valueForPathChanged(TreePath path, Object newValue) {
+        // TODO Auto-generated method stub
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXTreeRenderer.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXTreeRenderer.java
new file mode 100644
index 0000000..bca3010
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXTreeRenderer.java
@@ -0,0 +1,76 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXTreeRenderer.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.awt.Component;
+import javax.swing.Icon;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+/**
+ *
+ * @author Stephen rankin
+ */
+public class NXTreeRenderer extends DefaultTreeCellRenderer {
+
+    Icon errorIcon;
+
+    public NXTreeRenderer(Icon icon) {
+        errorIcon = icon;
+    }
+
+    public Component getTreeCellRendererComponent(
+            JTree tree,
+            Object value,
+            boolean sel,
+            boolean expanded,
+            boolean leaf,
+            int row,
+            boolean hasFocus) {
+
+        super.getTreeCellRendererComponent(
+                tree, value, sel,
+                expanded, leaf, row,
+                hasFocus);
+        
+        if (isErrorNode(value)) {
+            setIcon(errorIcon);
+            setToolTipText("This Element has an Error.");
+        } else {
+            setToolTipText(null); //no tool tip
+        }
+
+        return this;
+    }
+
+
+
+    protected boolean isErrorNode(Object value) {
+        
+        return false;
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXValidateDialog.form b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXValidateDialog.form
new file mode 100644
index 0000000..c05408e
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXValidateDialog.form
@@ -0,0 +1,140 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.JFileChooser" name="jFileChooser1">
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Open Files"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jPanel1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.CompoundBorderInfo">
+            <CompoundBorder>
+              <Border PropertyName="outside" info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="5"/>
+              </Border>
+              <Border PropertyName="inside" info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
+                <BevelBorder/>
+              </Border>
+            </CompoundBorder>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="1" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="1" attributes="0">
+                      <Group type="102" alignment="1" attributes="0">
+                          <Component id="cancelButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace pref="482" max="32767" attributes="0"/>
+                          <Component id="OKButton" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="1" attributes="0">
+                          <Component id="nxdcLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="nxdcTextField" pref="470" max="32767" attributes="1"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="openButton2" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="nxdcLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="nxdcTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="openButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="OKButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="nxdcLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Load NXDC:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JTextField" name="nxdcTextField">
+          <Properties>
+            <Property name="editable" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="openButton2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Open"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButton2ActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="cancelButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="CANCEL"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="OKButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Validate"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="OKButtonActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXValidateDialog.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXValidateDialog.java
new file mode 100644
index 0000000..9acf321
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXValidateDialog.java
@@ -0,0 +1,218 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXLoadFilesDialog.java
+ *
+ * Created on 16-Jun-2010, 11:56:31
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+
+/**
+ *
+ * @author ser65
+ */
+public class NXValidateDialog extends javax.swing.JDialog {
+
+    private File nxs = null;
+    private File nxdl = null;
+    private boolean OKButtonUsed = false;
+    /** Creates new form NXLoadFilesDialog */
+    public NXValidateDialog(java.awt.Frame parent, boolean modal) {
+        super(parent, modal);
+        initComponents();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jFileChooser1 = new javax.swing.JFileChooser();
+        jPanel1 = new javax.swing.JPanel();
+        nxdcLabel = new javax.swing.JLabel();
+        nxdcTextField = new javax.swing.JTextField();
+        openButton2 = new javax.swing.JButton();
+        cancelButton = new javax.swing.JButton();
+        OKButton = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Open Files");
+        setResizable(false);
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5), javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)));
+
+        nxdcLabel.setText("Load NXDC:");
+
+        nxdcTextField.setEditable(false);
+
+        openButton2.setText("Open");
+        openButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                openButton2ActionPerformed(evt);
+            }
+        });
+
+        cancelButton.setText("CANCEL");
+        cancelButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                cancelButtonActionPerformed(evt);
+            }
+        });
+
+        OKButton.setText("Validate");
+        OKButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                OKButtonActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(cancelButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 482, Short.MAX_VALUE)
+                        .addComponent(OKButton))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(nxdcLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(nxdcTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 470, Short.MAX_VALUE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(openButton2)))
+                .addGap(23, 23, 23))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addGap(10, 10, 10)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(nxdcLabel)
+                    .addComponent(nxdcTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(openButton2))
+                .addGap(18, 18, 18)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(OKButton)
+                    .addComponent(cancelButton))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void openButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButton2ActionPerformed
+
+        if(evt.getSource() == openButton2){
+
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+                nxdl = jFileChooser1.getSelectedFile();
+                nxdcTextField.setText(nxdl.getAbsolutePath());
+                nxdcTextField.setToolTipText(nxdl.getAbsolutePath());
+            } else {
+                nxdl = null;
+            }
+
+        }
+}//GEN-LAST:event_openButton2ActionPerformed
+
+    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
+        if(evt.getSource() == cancelButton){
+            OKButtonUsed = false;
+            this.setVisible(false);
+        }
+}//GEN-LAST:event_cancelButtonActionPerformed
+
+    private void OKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OKButtonActionPerformed
+
+        if(evt.getSource() == OKButton){
+            OKButtonUsed = true;
+            this.setVisible(false);
+        }
+    }//GEN-LAST:event_OKButtonActionPerformed
+
+    
+    public File getNXDLFile(){
+        return nxdl;
+    }
+
+    public void setNXDLFile(File file){
+        nxdl = file;
+        nxdcTextField.setText(nxdl.getAbsolutePath());
+    }
+
+    public boolean OKButtonUsed(){
+        return OKButtonUsed;
+    }
+
+    /**
+    * @param args the command line arguments
+    */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                NXValidateDialog dialog = new NXValidateDialog(new javax.swing.JFrame(), true);
+                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
+                    public void windowClosing(java.awt.event.WindowEvent e) {
+                        System.exit(0);
+                    }
+                });
+                dialog.setVisible(true);
+            }
+        });
+    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton OKButton;
+    private javax.swing.JButton cancelButton;
+    private javax.swing.JFileChooser jFileChooser1;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JLabel nxdcLabel;
+    private javax.swing.JTextField nxdcTextField;
+    private javax.swing.JButton openButton2;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXconvert.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXconvert.java
new file mode 100644
index 0000000..d717b14
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXconvert.java
@@ -0,0 +1,120 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXconvert.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.nexusformat.nxvalidate.exceptions.NXvalidateException;
+
+public class NXconvert {
+
+    private static final String NXCONVERT = "nxconvert";
+    private static final String EXTENSION = ".reduced";
+    private File rawfile;
+    private File redfile;
+    private NXproperties props = null;
+    private String convertCommand = null;
+
+    public NXconvert(final File rawfile, final boolean keepTemp,
+            final String convertCommand)
+            throws IOException, InterruptedException {
+
+        this.rawfile = rawfile;
+        redfile = File.createTempFile(rawfile.getName() + ".",
+                EXTENSION);
+        if (!keepTemp) {
+            redfile.deleteOnExit();
+        }
+
+        this.convertCommand = convertCommand;
+
+        props = new NXproperties();
+
+    }
+
+    private void printStd(final String command, final String out,
+            final String err) {
+
+        Logger.getLogger(NXconvert.class.getName()).log(Level.INFO, command);
+        Logger.getLogger(NXconvert.class.getName()).log(Level.INFO, out);
+        Logger.getLogger(NXconvert.class.getName()).log(Level.WARNING, err);
+
+    }
+
+    public File convert() throws IOException, InterruptedException, NXvalidateException {
+
+        Logger.getLogger(NXconvert.class.getName()).log(
+                Level.INFO, "Creating " + redfile.getAbsolutePath());
+
+        String command = "";
+        if(convertCommand!=null){
+            command = convertCommand +
+                " -d " + this.rawfile + " " + redfile;;
+        }
+        else{
+            return null;
+        }
+
+        // execute the command
+        Runtime rt = Runtime.getRuntime();
+        Process proc = rt.exec(command);
+
+        // get the output and error
+        StreamGobbler out = new StreamGobbler(proc.getInputStream(), "OUTPUT");
+        StreamGobbler err = new StreamGobbler(proc.getErrorStream(), "ERROR");
+        out.start();
+        err.start();
+        int exitValue = proc.waitFor();
+
+        // cleanup and return result
+        printStd(command, out.getOutput(), err.getOutput());
+        if (exitValue != 0) {
+            StringBuilder buffer = new StringBuilder("Execute command \"");
+            buffer.append(command);
+            buffer.append("\" failed. Returned ");
+            buffer.append(exitValue);
+            throw new NXvalidateException(buffer.toString());
+        }
+        return redfile;
+    }
+
+    public static void main(String[] args) {
+        
+        if (args.length != 1) {
+            Logger.getLogger(NXconvert.class.getName()).log(Level.SEVERE,
+                    "You must specify one input file");
+            return;
+        }
+        try {
+            NXconvert convert = new NXconvert(new File(args[0]), false, args[1]);
+            convert.convert();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXproperties.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXproperties.java
new file mode 100644
index 0000000..54c34c2
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXproperties.java
@@ -0,0 +1,113 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXproperties.java
+ *
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class NXproperties {
+
+    private ResourceBundle classpathProps = null;
+    private ResourceBundle userProps = null;
+    private Properties systemProps = null;
+    private String userHome = null;
+
+    public NXproperties() throws MalformedURLException
+    {
+
+       classpathProps  =
+               ResourceBundle.getBundle("org/nexusformat/nxvalidate/resources/nxvalidate");
+
+       systemProps = System.getProperties();
+
+       //First we see if there is a user specific prop file.
+       userHome = systemProps.getProperty("user.home");
+
+       String propsFileName =
+               userHome + File.pathSeparator + ".NXvalidate.properties";
+
+       File propsFile = new File(propsFileName);
+
+       URL resourceURL = null;
+
+       if(propsFile.exists()){
+
+           try {
+
+               resourceURL = propsFile.getParentFile().toURI().toURL();
+
+           } catch (MalformedURLException e) {
+
+              throw e;
+           }
+
+           URLClassLoader urlLoader =
+                   new URLClassLoader(new java.net.URL[]{resourceURL});
+
+           userProps = ResourceBundle.getBundle(".NXvalidate.properties",
+                java.util.Locale.getDefault(), urlLoader );
+
+       }
+
+    }
+
+    public String getProperty(String name){
+
+        String prop = null;
+
+        //If we are using the user props
+        if(userProps != null)
+        {
+
+            if(userProps.containsKey(name))
+            {
+                prop = userProps.getString(name);
+            }
+            
+        }
+        //If we are using the default props.
+        else if(prop == null)
+        {
+            if(classpathProps.containsKey(name))
+            {
+                prop = classpathProps.getString(name);
+            }
+        }
+
+        return prop;
+
+    }
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXschematron.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXschematron.java
new file mode 100644
index 0000000..2fc6087
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXschematron.java
@@ -0,0 +1,213 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXschematron.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import org.nexusformat.nxvalidate.resources.XSLTResolver;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+public class NXschematron {
+
+    private File reducedNeXusFile;
+    private File schematronFile;
+    private File inputNexusFile;
+    private boolean keepTemp;
+    private InputStream dsdlIncludeXSLTStream = null;
+    private InputStream abstractExpandXSLTStream = null;
+    private InputStream svrlForXslt2XSLTStream = null;
+    private InputStream nxdl2schXSLTStream = null;
+    //protected String schematronxslt[] = new String[]{"iso_dsdl_include.xsl",
+    //    "iso_abstract_expand.xsl", "iso_svrl_for_xslt2.xsl"};
+
+    public NXschematron(File inputNexusFile, File reducedNeXusFile, File schematronFile,
+            final boolean keepTemp) {
+
+        this.reducedNeXusFile = reducedNeXusFile;
+        this.schematronFile = schematronFile;
+        this.inputNexusFile = inputNexusFile;
+        this.keepTemp = keepTemp;
+
+        // The Schematron files...
+        dsdlIncludeXSLTStream =
+                NXschematron.class.getResourceAsStream(
+                "resources/iso_dsdl_include.xsl");
+        abstractExpandXSLTStream =
+                NXschematron.class.getResourceAsStream(
+                "resources/iso_abstract_expand.xsl");
+        svrlForXslt2XSLTStream =
+                NXschematron.class.getResourceAsStream(
+                "resources/iso_svrl_for_xslt2.xsl");
+        //XSLT for NXDL to sch
+        nxdl2schXSLTStream =
+                NXschematron.class.getResourceAsStream(
+                "resources/xslt/nxdl2sch.xsl");
+
+    }
+
+    /**
+     * Transform an XML file to something else given an XSLT transformation.
+     * @param inputFilename the XML input file name.
+     * @param xslFilename the xslt file name.
+     * @param outputFilename the filename to store the results
+     *        of the transformation.
+     * @throws TransformerException
+     */
+    public static void TransformoMatic(String inputFilename,
+            String xslFilename, String outputFilename)
+            throws TransformerException {
+        TransformoMatic(new File(inputFilename), new File(xslFilename),
+                new File(outputFilename));
+    }
+
+    /**
+     * Transform an XML file to something else given an XSLT transformation.
+     * @param inputFile the XML input file
+     * @param xslFile the xslt file.
+     * @param outputFile the result of the transformation.
+     * @throws TransformerException
+     */
+    public static void TransformoMatic(File inputFile, File xslFile,
+            File outputFile) throws TransformerException {
+
+        // Create an instance of the transform factory
+        TransformerFactory myFactory = TransformerFactory.newInstance(
+                "net.sf.saxon.TransformerFactoryImpl", null);
+        myFactory.setURIResolver(new XSLTResolver());
+        // Create a transformer for the xsl stylesheet
+        Transformer transformer = myFactory.newTransformer(new StreamSource(
+                xslFile));
+        transformer.setParameter("generate-paths", "yes");
+        transformer.setURIResolver(new XSLTResolver());
+        // Do the transform
+        transformer.transform(new StreamSource(inputFile), new StreamResult(
+                outputFile));
+
+    }
+
+    public static void TransformoMatic(InputStream inputFileStream,
+            InputStream xslFileStream, OutputStream outputFileStream)
+            throws TransformerException {
+
+        // Create an instance of the transform factory
+        TransformerFactory myFactory = TransformerFactory.newInstance(
+                "net.sf.saxon.TransformerFactoryImpl", null);
+
+        myFactory.setURIResolver(new XSLTResolver());
+        // Create a transformer for the xsl stylesheet
+        Transformer transformer = myFactory.newTransformer(new StreamSource(
+                xslFileStream));
+        
+        transformer.setParameter("generate-paths", "yes");
+        transformer.setURIResolver(new XSLTResolver());
+        // Do the transform
+        transformer.transform(new StreamSource(inputFileStream),
+                new StreamResult(outputFileStream));
+
+    }
+
+    File validate() throws IOException, TransformerException {
+        return validate(reducedNeXusFile, schematronFile);
+    }
+
+    File validate(File reducedNeXusFile, File schematronFile) throws
+            IOException, TransformerException {
+
+        // Step 0
+        File schematron0 = File.createTempFile("nxdlFile", ".step0");
+        if (!this.keepTemp) {
+            schematron0.deleteOnExit();
+        }
+        TransformoMatic(new FileInputStream(schematronFile), nxdl2schXSLTStream,
+                new FileOutputStream(schematron0));
+
+        // Step 1
+        File schematron1 = File.createTempFile("schematron", ".step1");
+        if (!this.keepTemp) {
+            schematron1.deleteOnExit();
+        }
+        TransformoMatic(new FileInputStream(schematron0), dsdlIncludeXSLTStream,
+                new FileOutputStream(schematron1));
+
+        // Step 2
+        File schematron2 = File.createTempFile("schematron", ".step2");
+        if (!this.keepTemp) {
+            schematron2.deleteOnExit();
+        }
+        TransformoMatic(new FileInputStream(schematron1),
+                abstractExpandXSLTStream,
+                new FileOutputStream(schematron2));
+
+        // Step 3
+        File schemaFile = File.createTempFile("schema", ".xslt");
+        if (!this.keepTemp) {
+            schemaFile.deleteOnExit();
+        }
+        TransformoMatic(new FileInputStream(schematron2),svrlForXslt2XSLTStream,
+                new FileOutputStream(schemaFile));
+
+        // Now lets validate the actual reduced file.
+        //File resultsFile = File.createTempFile(inputNexusFile.getName() + ".result", ".xml");
+
+        //File resultsFile = File.createTempFile(inputNexusFile.getName(). + ".result", ".xml");
+
+        File resultsFile = new File(reducedNeXusFile.getName().replaceAll(".reduced", "") + ".result");
+
+        if (!this.keepTemp) {
+            resultsFile.deleteOnExit();
+        }
+        TransformoMatic(new FileInputStream(reducedNeXusFile),
+                new FileInputStream(schemaFile),
+                new FileOutputStream(resultsFile));
+
+        // Return the filename
+        return resultsFile;
+    }
+
+    public static void main(String[] args) {
+        if (args.length != 3) {
+            System.out.println("Must specify three input files");
+            return;
+        }
+        try {
+            NXschematron sch = new NXschematron(new File(args[0]),
+                    new File(args[1]), new File(args[2]), false);
+            File results = sch.validate();
+            System.out.println(results.getAbsolutePath());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidate.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidate.java
new file mode 100644
index 0000000..5157132
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidate.java
@@ -0,0 +1,257 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXvalidate.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class NXvalidate {
+
+    static final String VERSION = "0.1 alpha";
+    private ArrayList<File> files;
+    private File schematronFile;
+    private boolean keepTemp;
+    private boolean convertNxs;
+    private int verbose;
+    private ArrayList<Report> reports;
+    private File reduced = null;
+
+    NXvalidate() {
+        files = new ArrayList<File>();
+        this.schematronFile = null;
+        this.keepTemp = false;
+        this.convertNxs = true;
+        this.verbose = 0;
+        this.reports = new ArrayList<Report>();
+    }
+
+    public ArrayList<Report> getReports() {
+        return reports;
+    }
+
+    public ArrayList<File> getFilenames() {
+        return files;
+    }
+
+    public void setFilenames(ArrayList<String> filenames) {
+        this.files = files;
+    }
+
+    public void setNXSFile(File file) {
+        files.add(file);
+    }
+
+    public File getSchematron() {
+        return schematronFile;
+    }
+
+    public void setSchematron(File schematronFile) {
+        this.schematronFile = schematronFile;
+    }
+
+    public boolean isKeepTemp() {
+        return keepTemp;
+    }
+
+    public void setKeepTemp(boolean keepTemp) {
+        this.keepTemp = keepTemp;
+    }
+
+    public boolean isConvertNxs() {
+        return convertNxs;
+    }
+
+    public void setConvertNxs(boolean convertNxs) {
+        this.convertNxs = convertNxs;
+    }
+
+    public int getVerbose() {
+        return verbose;
+    }
+
+    public void setVerbose(int verbose) {
+        this.verbose = verbose;
+    }
+
+    public static String getVersion() {
+        return VERSION;
+    }
+
+    public File getReduced() {
+        return reduced;
+    }
+
+    public File setReduced(File reduced) {
+        return this.reduced = reduced;
+    }
+
+    void parseArgs(final String[] args) {
+        // check that the help and version arguments aren't specified
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equals("-h") || args[i].equals("--help")) {
+                this.printHelp(2);
+                System.exit(0);
+            }
+            if (args[i].equals("--version")) {
+                this.printVersion();
+                System.exit(0);
+            }
+        }
+
+        // go through the arguments for real
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equals("-v") || args[i].equals("--verbose")) {
+                this.verbose += 1;
+            } else if (args[i].equals("-k") || args[i].equals("--keep")) {
+                this.keepTemp = true;
+            } else if (args[i].equals("-d") || args[i].equals("--dfn")) {
+                schematronFile = new File(args[i + 1]);
+                i++;
+            } else if (args[i].equals("--noconvert")) {
+                this.convertNxs = false;
+            } else {
+                files.add(new File(args[i]));
+            }
+        }
+       
+
+        // confirm that the manditory arguments are there
+        if (this.files.size() <= 0) {
+            System.out.println("Must specify at least one nexus file");
+            this.printHelp(0);
+            System.exit(-1);
+        }
+        if (!schematronFile.exists()) {
+            System.out.println("Must specify a schematron file");
+            this.printHelp(0);
+            System.exit(-1);
+        }
+    }
+
+    
+
+    void process() {
+        if (this.verbose > 0) {
+            System.out.println("Running NXvalidate (version:" + VERSION + ")");
+        }
+        int size = this.files.size();
+        for (int i = 0; i < size; i++) {
+            this.process(this.files.get(i));
+        }
+    }
+
+    private static File toAbsFile(final String filename) {
+        File file = new File(filename);
+        return file;
+    }
+
+    private File process(final File file) throws Error {
+
+        File result = null;
+
+        if (convertNxs) {
+            try {
+                NXconvert converter = new NXconvert(file, keepTemp,null);
+                reduced = converter.convert();
+            } catch (Exception e) {
+                Logger.getLogger(NXvalidate.class.getName()).log(Level.SEVERE,
+                        "While converting \"" + file +
+                        "\" to reduced xml format",e);
+                throw new Error("While converting \"" + file +
+                        "\" to reduced xml format", e);
+            }
+        }
+
+        if (reduced != null && schematronFile !=null) {
+            
+            // create the validation setup
+            NXschematron schematron = new NXschematron(file,reduced,
+                    schematronFile, keepTemp);
+
+            try {
+                result = schematron.validate();
+            } catch (Exception e) {
+                Logger.getLogger(NXvalidate.class.getName()).log(Level.SEVERE,
+                        "While creating validation report",e);
+                throw new Error("While creating validation report", e);
+            }
+
+            // create the report
+            Report report = null;
+            try {
+                report = new Report(reduced, result);
+            } catch (Exception e) {
+                Logger.getLogger(NXvalidate.class.getName()).log(Level.SEVERE,
+                        "While generating the report object",e);
+                throw new Error("While generating the report object", e);
+            }
+
+            // Add to vector of reports (one for each input file)
+            reports.add(report);
+
+            report.printTree();
+            int numErrors = report.numErrors();
+            if (numErrors > 0) {
+                report.printReport();
+            }
+
+        }
+        return result;
+    }
+
+    private void printVersion() {
+        System.out.println("NXvalidate version " + VERSION);
+    }
+
+    private void printHelp(final int level) {
+        System.out.println("usage: nxvalidate [options] <nxsfile>");
+        if (level <= 0) {
+            return;
+        }
+
+        System.out.println();
+        System.out.println("Validate nexus files against the nexus definitions");
+        this.printVersion();
+        if (level <= 1) {
+            return;
+        }
+
+        System.out.println();
+        System.out.println("-h, --help    print this help information");
+        System.out.println("-v, --verbose increase verbose printing");
+        System.out.println("-d, --dfn     specify the definition file");
+        System.out.println("-k, --keep    keep temporary files");
+        System.out.println("--noconvert   do not reduce the nexus file");
+    }
+
+    public static void main(String[] args) {
+        NXvalidate validate = new NXvalidate();
+        validate.parseArgs(args);
+        validate.process();
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateBasicGui.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateBasicGui.java
new file mode 100644
index 0000000..79faaa7
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateBasicGui.java
@@ -0,0 +1,380 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXvalidateBasicGui.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import org.nexusformat.nxvalidate.filter.SchematronFilter;
+import org.nexusformat.nxvalidate.filter.XmlFilter;
+import org.nexusformat.nxvalidate.filter.NeXusFilter;
+import org.nexusformat.nxvalidate.filter.HdfFilter;
+import org.nexusformat.nxvalidate.filter.AllNeXusFilter;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Vector;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.ToolTipManager;
+import javax.swing.UIManager;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+public class NXvalidateBasicGui extends JPanel implements ActionListener {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -2935498610579762249L;
+    static private final String newline = "\n";
+    JButton browseFileButton;
+    JButton validateButton;
+    JLabel filenameLabel;
+    JTextField filenameText;
+    JLabel nxdlLabel;
+    JButton browseNxdlButton;
+    JTextField nxdlText;
+    JTextArea log;
+    JTree tree;
+    JFileChooser fc;
+    JFileChooser nxdlChooser;
+    String reducedNeXusFilename;
+    String schematronFilename = "schematron.sch";
+    File rawFile = null;
+    File schematronFile = null;
+    NXconvert converter;
+    NXschematron schematron;
+    ArrayList<Report> reports;
+    NXvalidate validator;
+
+    public NXvalidateBasicGui() {
+        super(new GridBagLayout());
+
+        GridBagConstraints c = new GridBagConstraints();
+
+        // Create the log first, because the action listeners
+        // need to refer to it.
+        log = new JTextArea(5, 20);
+        log.setMargin(new Insets(5, 5, 5, 5));
+        log.setEditable(false);
+        JScrollPane logScrollPane = new JScrollPane(log);
+
+        // Create a nexus file chooser
+        fc = new JFileChooser();
+
+        fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+        NeXusFilter nxsFilter = new NeXusFilter();
+        this.fc.addChoosableFileFilter(nxsFilter);
+        this.fc.addChoosableFileFilter(new AllNeXusFilter());
+        this.fc.addChoosableFileFilter(new HdfFilter());
+        this.fc.addChoosableFileFilter(new XmlFilter());
+        this.fc.setFileFilter(nxsFilter);
+
+        // set the default definition filename
+        this.setDefaultDefinition();
+
+        // create a definition file chooser
+        this.nxdlChooser = new JFileChooser();
+        nxdlChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+        nxdlChooser.setSelectedFile(new File(this.schematronFilename));
+        this.nxdlChooser.addChoosableFileFilter(new SchematronFilter());
+
+        // ----- nexus file loading
+        // Create the filename label
+        filenameLabel = new JLabel("NXS File:");
+
+        // Create the filename text field
+        filenameText = new JTextField(30);
+        filenameText.setToolTipText("The NeXus file to validate");
+
+        // Create the open button.
+        browseFileButton = new JButton("Browse...");
+        browseFileButton.addActionListener(this);
+
+        // ----- nxdl file loading
+        // Create the filename label
+        nxdlLabel = new JLabel("NXDL File:");
+
+        // Create the text field
+        nxdlText = new JTextField(30);
+        nxdlText.setToolTipText("The definition to validate against");
+        nxdlText.setText(this.schematronFilename);
+
+        // create the browse button
+        browseNxdlButton = new JButton("Browse...");
+        browseNxdlButton.addActionListener(this);
+
+        // ----- the big validate button
+        // Create the validation button.
+        validateButton = new JButton("Perform Validation");
+        validateButton.setToolTipText("Perform Validation");
+        validateButton.addActionListener(this);
+
+        // Create the tree view
+        tree = new JTree(new NXSnode());
+
+        DefaultTreeCellRenderer rend1 = new DefaultTreeCellRenderer();
+        // IconAndTipRenderer rend2 = new
+        // IconAndTipRenderer(rend1.getOpenIcon(),
+        // rend1.getClosedIcon(), rend1.getLeafIcon());
+        // tree.setCellRenderer(rend2);
+        ToolTipManager.sharedInstance().registerComponent(tree);
+
+        // Add the buttons and the log to this panel.
+
+        // nxs input
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridy = 0;
+        c.gridx = 0;
+        c.weightx = 0.5;
+        c.insets = new Insets(0, 10, 0, 0);
+        add(filenameLabel, c);
+
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 0, 0, 0);
+        c.gridy = 0;
+        c.gridx = 1;
+        c.weightx = 0.5;
+        add(filenameText, c);
+
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridy = 0;
+        c.gridx = 2;
+        c.weightx = 0.5;
+        add(browseFileButton, c);
+
+        // nxdl input
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridy = 1;
+        c.gridx = 0;
+        c.weightx = 0.5;
+        c.insets = new Insets(0, 10, 0, 0);
+        add(nxdlLabel, c);
+
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 0, 0, 0);
+        c.gridy = 1;
+        c.gridx = 1;
+        c.weightx = 0.5;
+        add(nxdlText, c);
+
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridy = 1;
+        c.gridx = 2;
+        c.weightx = 0.5;
+        add(browseNxdlButton, c);
+
+        // validate button
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridy = 2;
+        c.gridx = 0;
+        c.weightx = 1.0;
+        c.gridwidth = 3;
+        add(validateButton, c);
+
+		c.fill = GridBagConstraints.BOTH;
+		c.weightx = 1.0;
+		c.weighty = 1.0;
+		c.gridy = 3;
+		add(new JScrollPane(tree), c);
+
+		c.fill = GridBagConstraints.HORIZONTAL;
+		c.weightx = 0.0;
+		c.weighty = 0.0;
+		c.gridy = 4;
+		add(logScrollPane, c);
+	}
+
+    private void setDefaultDefinition() {
+        schematronFile = new File(this.schematronFilename);
+    }
+
+    public TreeModel parseXML(String filename) throws Exception {
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        XMLIconTreeHandler handler = new XMLIconTreeHandler();
+        SAXParser saxParser = factory.newSAXParser();
+        saxParser.parse(new File(filename), handler);
+        return new DefaultTreeModel(handler.getRoot());
+    }
+
+    public void actionPerformed(ActionEvent e) {
+
+        if (e.getSource() == browseFileButton) { // Handle open button action.
+            int returnVal = fc.showOpenDialog(NXvalidateBasicGui.this);
+
+            if (returnVal == JFileChooser.APPROVE_OPTION) {
+                File file = fc.getSelectedFile();
+                // Set the text box value to show the selected filename.
+                rawFile = file;
+                log.append("Selected NeXus File: " + file.getName() + "." + newline);
+                // TODO move code to make the reduced file here (and also after
+                // the filename has been typed).
+            } else {
+                log.append("Browse nexus cancelled by user." + newline);
+            }
+            log.setCaretPosition(log.getDocument().getLength());
+
+        } else if (e.getSource() == browseNxdlButton) {
+            int returnVal = nxdlChooser.showOpenDialog(NXvalidateBasicGui.this);
+            if (returnVal == JFileChooser.APPROVE_OPTION) {
+                File file = nxdlChooser.getSelectedFile();
+                nxdlText.setText(file.getAbsolutePath());
+                schematronFile = file;
+                log.append("Selected Definition File: " + file.getName() + "." + newline);
+            } else {
+                log.append("Browse definition cancelled by user." + newline);
+            }
+        } else if (e.getSource() == validateButton) { // Handle save button action.
+            // Do the validation
+            try {
+
+                validator = new NXvalidate();
+                validator.setNXSFile(rawFile);
+                validator.setConvertNxs(true);
+                validator.setSchematron(schematronFile);
+                validator.setKeepTemp(true);
+                validator.process();
+
+                // Get the reports
+                reports = validator.getReports();
+
+                // As we only have the ability to pass 1 file at the
+                // moment through the GUI - we will throw an exception
+                // if we have more than one report.
+
+                if (this.reports.size() > 1) {
+                    throw new Exception(
+                            "We only sent a single file to be processed, but have received multiple reports back.");
+                }
+                if (this.reports.size() < 1) {
+                    throw new Exception(
+                            "Failed to generate a report for " + filenameText.getText());
+                }
+
+                // converter = new NXconvert(filenameText.getText(), true);
+                // log.append("Converting NeXus file into reduced format."
+                // + newline);
+                // reducedNeXusFilename = converter.convert();
+                // // log.append(filenameText.getText() + " ==> "
+                // // + reducedNeXusFilename + newline);
+                // log.append("Finished making reduced file." + newline);
+                //
+                // // Update tree
+                // tree.setModel(this.parseXML(reducedNeXusFilename));
+                //
+                // // create the validation setup
+                // log.append("Validating against " + schematronFile + "."
+                // + newline);
+                // schematron = new NXschematron(reducedNeXusFilename,
+                // schematronFile, true);
+                // String result = schematron.validate();
+                //
+                //
+                // // create the report
+                // report = new Report(reducedNeXusFilename, result);
+                // log.append("There were " + report.numErrors() +
+                // " errors found."
+                // + newline);
+                // // log.append(report.getReport() + newline);
+                //
+
+                log.append("Finished Validating." + newline);
+                Report report = reports.get(0);
+                tree.setModel(report.getTree());
+
+                log.append("There were " + report.numErrors() + " errors found."
+                           + newline);
+
+                ArrayList<SVRLitem> messages = report.getReport();
+
+                Iterator i = messages.iterator();
+                while (i.hasNext()) {
+                    log.append("->" + i.next() + newline);
+                }
+
+            } catch (Throwable e1) {
+                log.append(e1.getMessage() + newline);
+                e1.printStackTrace();
+            }
+
+            log.setCaretPosition(log.getDocument().getLength());
+        }
+    }
+
+    // /** Returns an ImageIcon, or null if the path was invalid. */
+    // protected static ImageIcon createImageIcon(String path) {
+    // java.net.URL imgURL = NXvalidateBasicGui.class.getResource(path);
+    // if (imgURL != null) {
+    // return new ImageIcon(imgURL);
+    // } else {
+    // System.err.println("Couldn't find file: " + path);
+    // return null;
+    // }
+    // }
+    /**
+     * Create the GUI and show it. For thread safety, this method should be
+     * invoked from the event dispatch thread.
+     */
+    private static void createAndShowGUI() {
+        // Create and set up the window.
+        JFrame frame = new JFrame("NeXus Validation Tool");
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        // Add content to the window.
+        frame.add(new NXvalidateBasicGui());
+
+        // Display the window.
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    public static void main(String[] args) {
+        // Schedule a job for the event dispatch thread:
+        // creating and showing this application's GUI.
+        SwingUtilities.invokeLater(new Runnable() {
+
+            public void run() {
+                // Turn off metal's use of bold fonts
+                UIManager.put("swing.boldMetal", Boolean.FALSE);
+                createAndShowGUI();
+            }
+        });
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateFrame.form b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateFrame.form
new file mode 100644
index 0000000..3b27a65
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateFrame.form
@@ -0,0 +1,278 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.7" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.JOptionPane" name="dialogReportProblem">
+    </Component>
+    <Container class="javax.swing.JPopupMenu" name="treePopupMenu">
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
+        <Property name="useNullLayout" type="boolean" value="true"/>
+      </Layout>
+      <SubComponents>
+        <MenuItem class="javax.swing.JMenuItem" name="closeFileMenuItem">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Close File"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeFileMenuItemActionPerformed"/>
+          </Events>
+        </MenuItem>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JFileChooser" name="jFileChooser1">
+    </Component>
+    <Menu class="javax.swing.JMenuBar" name="jMenuBar1">
+      <SubComponents>
+        <Menu class="javax.swing.JMenu" name="fileMenu">
+          <Properties>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="org/nexusformat/nxvalidate/resources/nxvalidate.properties" key="fileMenuItem" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
+            </Property>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="openFilesMenuItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+F"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Open Files"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openFilesMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator4">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="saveMenuItem">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Save Results"/>
+                <Property name="toolTipText" type="java.lang.String" value="Save results to files."/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="saveMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator7">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="closeAllMenuItem">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Close All Files"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeAllMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator5">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="exitAppMenuItem">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Exit"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="exitAppMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="toolsMenu">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Tools"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="validateSelectedMenuItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+V"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Validate Selected"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="validateSelectedMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator2">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="filterMenuItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+G"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Show Failed Nodes"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="filterMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator1">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="bulkMenuItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+B"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Bulk Validation"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bulkMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator3">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="settingsMenuItem">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Settings"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="settingsMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="helpMenu">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Help"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="helpMenuItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+H"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Help Content"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator6">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="aboutMenuItem">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="About"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="aboutMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+      </SubComponents>
+    </Menu>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+      <ResourceString bundle="org/nexusformat/nxvalidate/resources/nxvalidate.properties" key="applicationTitle" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
+    </Property>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[400, 400]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="menuBar" type="java.lang.String" value="jMenuBar1"/>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel2">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.CompoundBorderInfo">
+            <CompoundBorder>
+              <Border PropertyName="outside" info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="5"/>
+              </Border>
+              <Border PropertyName="inside" info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
+                <BevelBorder bevelType="1"/>
+              </Border>
+            </CompoundBorder>
+          </Border>
+        </Property>
+        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[130, 130]"/>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="jSplitPane1" alignment="0" pref="386" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="jSplitPane1" alignment="0" pref="259" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+          <Properties>
+            <Property name="dividerLocation" type="int" value="200"/>
+            <Property name="continuousLayout" type="boolean" value="true"/>
+          </Properties>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+                  <JSplitPaneConstraints position="left"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JTree" name="jTree1">
+                  <Properties>
+                    <Property name="model" type="javax.swing.tree.TreeModel" editor="org.netbeans.modules.form.editors2.TreeModelEditor">
+                      <TreeModel code="NXS Files"/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="valueChanged" listener="javax.swing.event.TreeSelectionListener" parameters="javax.swing.event.TreeSelectionEvent" handler="jTree1ValueChanged"/>
+                  </Events>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+                  <JSplitPaneConstraints position="right"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JTextPane" name="jTextPane1">
+                </Component>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateFrame.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateFrame.java
new file mode 100644
index 0000000..e80a1fa
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateFrame.java
@@ -0,0 +1,693 @@
+ /* NeXus - Neutron & X-ray Common Data Format
+  *
+  * NeXus file validation GUI tool.
+  *
+  * Copyright (C) 2010 Stephen Rankin
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  *
+  * For further information, see <http://www.nexusformat.org/>
+  *
+  * NXvalidateFrame.java
+  *
+  * Created on 02-Jun-2010, 14:17:04
+  */
+
+package org.nexusformat.nxvalidate;
+
+import java.awt.Dialog.ModalityType;
+import java.awt.event.MouseListener;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.help.CSH;
+import javax.help.HelpBroker;
+import javax.help.HelpSet;
+import javax.swing.JOptionPane;
+import javax.swing.JTextArea;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.w3c.dom.Document;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class NXvalidateFrame extends javax.swing.JFrame {
+
+    private DocumentBuilderFactory factory = null;
+    private DocumentBuilder builder = null;
+    private NXReducedToTree domTree = null;
+    private NXNodeMapper root = null;
+    private ResourceBundle bundle = null;
+    private File nxsFile = null;
+    private File nxdlFile = null;
+    private File reducedFile = null;
+    private File resultsFile = null;
+    private TreeUtils treeUtils = null;
+    private UserSettings settings = null;
+    private String nxconvertCommand = null;
+    private File saveDirectory = null;
+    private boolean foundNXconvert = false;
+    private MouseListener popupListener = null;
+    private TextPaneStyle txtStyle = null;
+    private FileActions fileLoadingActions = null;
+    private HelpBroker hb = null;
+
+    /** Creates new form NXvalidateFrame */
+    public NXvalidateFrame() {
+        initComponents();
+        setup();
+    }
+
+    private void setup() {
+
+        factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+
+        root = new NXNodeMapper("Files");
+
+        domTree = new NXReducedToTree(root);
+        jTree1.setModel(domTree);
+
+        try {
+            builder = factory.newDocumentBuilder();
+        } catch (ParserConfigurationException ex) {
+            Logger.getLogger(
+                    NXvalidateFrame.class.getName()).log(Level.SEVERE, null, ex);
+        }
+
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+
+        treeUtils = new TreeUtils();
+
+        XMLTreeRenderer rend = new XMLTreeRenderer(
+                "resources/nexus32x32.png", "resources/bad.png",
+                "resources/good.png", "resources/warn.png",
+                "resources/peg-e.png", "resources/info.png",
+                "resources/info-good.png", "resources/info-bad.png",
+                "resources/info-warn.png");
+
+        jTree1.setCellRenderer(rend);
+
+        settings = new UserSettings();
+
+        try {
+            settings.loadUserSettings();
+            nxconvertCommand = settings.getNXconvert();
+
+            if (!settings.foundNXconvert()) {
+                displayErrorMessage(
+                        bundle.getString("nxconvertMissingError"));
+                foundNXconvert = false;
+            } else {
+                foundNXconvert = true;
+            }
+        } catch (FileNotFoundException ex) {
+            Logger.getLogger(
+                    NXvalidateFrame.class.getName()).log(Level.SEVERE,
+                    "The settings file cannot be found.", ex);
+        } catch (IOException ex) {
+            Logger.getLogger(
+                    NXvalidateFrame.class.getName()).log(Level.SEVERE,
+                    "The settings file IO error.", ex);
+        }
+
+        popupListener = new PopupListener(treePopupMenu);
+        jTree1.addMouseListener(popupListener);
+
+        txtStyle = new TextPaneStyle(jTextPane1);
+
+        fileLoadingActions = new FileActions(this, jTree1, builder, domTree, root);
+
+        String helpHS = "help/jhelpset.hs";
+        HelpSet  hs = null;
+
+        try {
+            hs = new HelpSet(null, this.getClass().getResource(helpHS));
+        } catch (Exception ex) {
+            Logger.getLogger(
+                    NXvalidateFrame.class.getName()).log(Level.SEVERE,
+                    "The setting help file IO error.", ex);
+            return;
+        }
+        // Create a HelpBroker object:
+        hb = hs.createHelpBroker();
+
+        helpMenuItem.addActionListener(new CSH.DisplayHelpFromSource( hb ));
+
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        dialogReportProblem = new javax.swing.JOptionPane();
+        treePopupMenu = new javax.swing.JPopupMenu();
+        closeFileMenuItem = new javax.swing.JMenuItem();
+        jFileChooser1 = new javax.swing.JFileChooser();
+        jPanel2 = new javax.swing.JPanel();
+        jSplitPane1 = new javax.swing.JSplitPane();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTree1 = new javax.swing.JTree();
+        jScrollPane2 = new javax.swing.JScrollPane();
+        jTextPane1 = new javax.swing.JTextPane();
+        jMenuBar1 = new javax.swing.JMenuBar();
+        fileMenu = new javax.swing.JMenu();
+        openFilesMenuItem = new javax.swing.JMenuItem();
+        jSeparator4 = new javax.swing.JPopupMenu.Separator();
+        saveMenuItem = new javax.swing.JMenuItem();
+        jSeparator7 = new javax.swing.JPopupMenu.Separator();
+        closeAllMenuItem = new javax.swing.JMenuItem();
+        jSeparator5 = new javax.swing.JPopupMenu.Separator();
+        exitAppMenuItem = new javax.swing.JMenuItem();
+        toolsMenu = new javax.swing.JMenu();
+        validateSelectedMenuItem = new javax.swing.JMenuItem();
+        jSeparator2 = new javax.swing.JPopupMenu.Separator();
+        filterMenuItem = new javax.swing.JMenuItem();
+        jSeparator1 = new javax.swing.JPopupMenu.Separator();
+        bulkMenuItem = new javax.swing.JMenuItem();
+        jSeparator3 = new javax.swing.JPopupMenu.Separator();
+        settingsMenuItem = new javax.swing.JMenuItem();
+        helpMenu = new javax.swing.JMenu();
+        helpMenuItem = new javax.swing.JMenuItem();
+        jSeparator6 = new javax.swing.JPopupMenu.Separator();
+        aboutMenuItem = new javax.swing.JMenuItem();
+
+        closeFileMenuItem.setText("Close File");
+        closeFileMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                closeFileMenuItemActionPerformed(evt);
+            }
+        });
+        treePopupMenu.add(closeFileMenuItem);
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/nexusformat/nxvalidate/resources/nxvalidate"); // NOI18N
+        setTitle(bundle.getString("applicationTitle")); // NOI18N
+        setMinimumSize(new java.awt.Dimension(400, 400));
+
+        jPanel2.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5), javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED)));
+        jPanel2.setPreferredSize(new java.awt.Dimension(130, 130));
+
+        jSplitPane1.setDividerLocation(200);
+        jSplitPane1.setContinuousLayout(true);
+
+        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("NXS Files");
+        jTree1.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
+        jTree1.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
+            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
+                jTree1ValueChanged(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jTree1);
+
+        jSplitPane1.setLeftComponent(jScrollPane1);
+
+        jScrollPane2.setViewportView(jTextPane1);
+
+        jSplitPane1.setRightComponent(jScrollPane2);
+
+        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 386, Short.MAX_VALUE)
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
+        );
+
+        getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);
+
+        fileMenu.setText(bundle.getString("fileMenuItem")); // NOI18N
+
+        openFilesMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.CTRL_MASK));
+        openFilesMenuItem.setText("Open Files");
+        openFilesMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                openFilesMenuItemActionPerformed(evt);
+            }
+        });
+        fileMenu.add(openFilesMenuItem);
+        fileMenu.add(jSeparator4);
+
+        saveMenuItem.setText("Save Results");
+        saveMenuItem.setToolTipText("Save results to files.");
+        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                saveMenuItemActionPerformed(evt);
+            }
+        });
+        fileMenu.add(saveMenuItem);
+        fileMenu.add(jSeparator7);
+
+        closeAllMenuItem.setText("Close All Files");
+        closeAllMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                closeAllMenuItemActionPerformed(evt);
+            }
+        });
+        fileMenu.add(closeAllMenuItem);
+        fileMenu.add(jSeparator5);
+
+        exitAppMenuItem.setText("Exit");
+        exitAppMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                exitAppMenuItemActionPerformed(evt);
+            }
+        });
+        fileMenu.add(exitAppMenuItem);
+
+        jMenuBar1.add(fileMenu);
+
+        toolsMenu.setText("Tools");
+
+        validateSelectedMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, java.awt.event.InputEvent.CTRL_MASK));
+        validateSelectedMenuItem.setText("Validate Selected");
+        validateSelectedMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                validateSelectedMenuItemActionPerformed(evt);
+            }
+        });
+        toolsMenu.add(validateSelectedMenuItem);
+        toolsMenu.add(jSeparator2);
+
+        filterMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, java.awt.event.InputEvent.CTRL_MASK));
+        filterMenuItem.setText("Show Failed Nodes");
+        filterMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                filterMenuItemActionPerformed(evt);
+            }
+        });
+        toolsMenu.add(filterMenuItem);
+        toolsMenu.add(jSeparator1);
+
+        bulkMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_B, java.awt.event.InputEvent.CTRL_MASK));
+        bulkMenuItem.setText("Bulk Validation");
+        bulkMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                bulkMenuItemActionPerformed(evt);
+            }
+        });
+        toolsMenu.add(bulkMenuItem);
+        toolsMenu.add(jSeparator3);
+
+        settingsMenuItem.setText("Settings");
+        settingsMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                settingsMenuItemActionPerformed(evt);
+            }
+        });
+        toolsMenu.add(settingsMenuItem);
+
+        jMenuBar1.add(toolsMenu);
+
+        helpMenu.setText("Help");
+
+        helpMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_H, java.awt.event.InputEvent.CTRL_MASK));
+        helpMenuItem.setText("Help Content");
+        helpMenu.add(helpMenuItem);
+        helpMenu.add(jSeparator6);
+
+        aboutMenuItem.setText("About");
+        aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                aboutMenuItemActionPerformed(evt);
+            }
+        });
+        helpMenu.add(aboutMenuItem);
+
+        jMenuBar1.add(helpMenu);
+
+        setJMenuBar(jMenuBar1);
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    public void displayErrorMessage(String message) {
+
+        JTextArea ta = new JTextArea(message);
+        ta.setEditable(false);
+        ta.setWrapStyleWord(true);
+        ta.setLineWrap(true);
+        ta.setSize(200, 100);
+        dialogReportProblem.showMessageDialog(this, ta);
+
+    }
+
+    private boolean loadOpenFilesDialog() {
+
+        NXLoadFilesDialog loadFile = new NXLoadFilesDialog(this, true);
+        loadFile.setModalityType(ModalityType.APPLICATION_MODAL);
+        loadFile.setVisible(true);
+        nxsFile = loadFile.getNXSFile();
+        nxdlFile = loadFile.getNXDLFile();
+        return loadFile.OKButtonUsed();
+
+    }
+
+    private boolean saveResultsFilesDialog() {
+
+        NXLoadFilesDialog loadFile = new NXLoadFilesDialog(this, true);
+        loadFile.setModalityType(ModalityType.APPLICATION_MODAL);
+        loadFile.setVisible(true);
+        nxsFile = loadFile.getNXSFile();
+        nxdlFile = loadFile.getNXDLFile();
+        return loadFile.OKButtonUsed();
+
+    }
+
+    private boolean loadValidatFileDialog() {
+
+        NXValidateDialog loadValidate = new NXValidateDialog(this, true);
+        loadValidate.setModalityType(ModalityType.APPLICATION_MODAL);
+        if (nxdlFile != null) {
+            loadValidate.setNXDLFile(nxdlFile);
+        }
+        loadValidate.setVisible(true);
+        nxdlFile = loadValidate.getNXDLFile();
+        return loadValidate.OKButtonUsed();
+
+    }
+
+    private boolean loadSettingsFileDialog() {
+
+        NXSettingsDialog loadSettings = new NXSettingsDialog(this, true);
+        loadSettings.setModalityType(ModalityType.APPLICATION_MODAL);
+        if (nxconvertCommand != null) {
+            loadSettings.setNXConvertCommand(nxconvertCommand);
+        }
+        loadSettings.setVisible(true);
+        nxconvertCommand = loadSettings.getNXConvertFile();
+        return loadSettings.OKButtonUsed();
+
+    }
+
+    private void openFilesMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFilesMenuItemActionPerformed
+
+        if (evt.getSource() == openFilesMenuItem) {
+            if (!foundNXconvert) {
+                displayErrorMessage(
+                        bundle.getString("nxconvertMissingError"));
+                return;
+            }
+
+            boolean result = loadOpenFilesDialog();
+
+            if (result) {
+                if (nxsFile != null) {
+                    fileLoadingActions.setWhich(1);
+                    fileLoadingActions.setNXSFile(nxsFile);
+                    fileLoadingActions.setNXConvertFile(nxconvertCommand);
+                    fileLoadingActions.setNXDLFile(nxdlFile);
+                    (new Thread(fileLoadingActions)).start();
+                } else {
+                    dialogReportProblem.showMessageDialog(this,
+                            bundle.getString("openNexusFileMessage"));
+                }
+            }
+        }
+
+    }//GEN-LAST:event_openFilesMenuItemActionPerformed
+
+    private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_jTree1ValueChanged
+
+        if (evt.getSource() == jTree1) {
+            if (jTree1.getSelectionPath() != null) {
+                NXNodeMapper node =
+                        (NXNodeMapper) jTree1.getSelectionPath().getLastPathComponent();
+                txtStyle.updateTextPane(node);
+            }
+        }
+
+    }//GEN-LAST:event_jTree1ValueChanged
+
+    private void validateSelectedMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_validateSelectedMenuItemActionPerformed
+
+        if (evt.getSource() == validateSelectedMenuItem) {
+
+            //Nothing selected in tree
+            if (jTree1.isSelectionEmpty()) {
+                return;
+            }
+
+            //Root node selected in tree
+            TreePath selected = jTree1.getSelectionPath();
+            int size = selected.getPath().length;
+            NXNodeMapper endNode = (NXNodeMapper) selected.getPath()[size - 1];
+            if (endNode.isRoot()) {
+                return;
+            }
+
+            //No nxconvert binary found.
+            if (!foundNXconvert) {
+                displayErrorMessage(
+                        bundle.getString("nxconvertMissingError"));
+                return;
+            }
+
+            Document reducedDoc = null;
+            Document resultsDoc = null;
+
+            //Check to see if the reduction and validation have not already
+            //been done, i.e. the files and documents already exist for the
+            //current selected tree.
+            if (treeUtils.getNXDLFile(jTree1) != null) {
+                nxdlFile = treeUtils.getNXDLFile(jTree1);
+            }
+
+            if (treeUtils.getReducedFile(jTree1) != null) {
+                reducedFile = treeUtils.getReducedFile(jTree1);
+                reducedDoc = treeUtils.getReducedDoc(jTree1);
+            }
+
+            if (treeUtils.getResultsFile(jTree1) != null) {
+                resultsFile = treeUtils.getResultsFile(jTree1);
+                resultsDoc = treeUtils.getResultsDoc(jTree1);
+            }
+
+            //Show the validate file dialog.
+            boolean result = loadValidatFileDialog();
+
+            if (result) {
+                if (nxdlFile != null) {
+
+                    fileLoadingActions.setWhich(2);
+                    fileLoadingActions.setNXSFile(nxsFile);
+                    fileLoadingActions.setNXConvertFile(nxconvertCommand);
+                    fileLoadingActions.setNXDLFile(nxdlFile);
+                    fileLoadingActions.setReducedFile(reducedFile);
+                    fileLoadingActions.setReducedDoc(reducedDoc);
+                    fileLoadingActions.setResultsDoc(resultsDoc);
+
+                    Thread thread = new Thread(fileLoadingActions);
+
+                    thread.start();
+
+                } else {
+                    dialogReportProblem.showMessageDialog(this,
+                            bundle.getString("openSchemaFileMessage"));
+                }
+            }
+        }
+
+    }//GEN-LAST:event_validateSelectedMenuItemActionPerformed
+
+    private void settingsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_settingsMenuItemActionPerformed
+
+        if (evt.getSource() == settingsMenuItem) {
+
+            boolean result = loadSettingsFileDialog();
+
+            if (result) {
+                if (nxconvertCommand != null) {
+                    
+                    settings.setNXconvert(nxconvertCommand);
+                    settings.saveUserSettings();
+                    foundNXconvert = settings.foundNXconvert();
+                }
+            }
+
+            if (!foundNXconvert) {
+                displayErrorMessage(
+                        bundle.getString("nxconvertMissingError"));
+                return;
+            }
+
+        }
+
+    }//GEN-LAST:event_settingsMenuItemActionPerformed
+
+    private void closeFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeFileMenuItemActionPerformed
+
+        if (evt.getSource() == closeFileMenuItem) {
+
+            NXNodeMapper node = treeUtils.getBaseNode(jTree1);
+            if (node != null) {
+                if (!node.isRoot()) {
+                    root.remove(node);
+                    domTree.removeNodeFromParent((MutableTreeNode) node);
+                    domTree.updateTree();
+                }
+            }
+
+        }
+    }//GEN-LAST:event_closeFileMenuItemActionPerformed
+
+    private void exitAppMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitAppMenuItemActionPerformed
+        if (evt.getSource() == exitAppMenuItem) {
+            this.dispose();
+        }
+    }//GEN-LAST:event_exitAppMenuItemActionPerformed
+
+    private void closeAllMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeAllMenuItemActionPerformed
+        if (evt.getSource() == closeAllMenuItem) {
+
+            int result = dialogReportProblem.showConfirmDialog(this,
+                    bundle.getString("closeAllWarningMessage"), null,
+                    JOptionPane.OK_CANCEL_OPTION);
+
+            if (result == 0) {
+                ArrayList<NXNodeMapper> nodes = root.getOpenNodes();
+                for (int i = 0; i < nodes.size(); ++i) {
+                    domTree.removeNodeFromParent((MutableTreeNode) nodes.get(i));
+                }
+                root.removeAllNodes();
+                domTree.updateTree();
+            }
+        }
+    }//GEN-LAST:event_closeAllMenuItemActionPerformed
+
+    private void bulkMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bulkMenuItemActionPerformed
+
+        if (evt.getSource() == bulkMenuItem) {
+
+            fileLoadingActions.setNXConvertFile(nxconvertCommand);
+            BulkLoadFilesFrame bulk = new BulkLoadFilesFrame(fileLoadingActions);
+            bulk.setVisible(true);
+
+        }
+
+    }//GEN-LAST:event_bulkMenuItemActionPerformed
+
+    private void filterMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filterMenuItemActionPerformed
+
+        if (evt.getSource() == filterMenuItem) {
+            treeUtils.hideGoodNodes(jTree1);
+        }
+
+    }//GEN-LAST:event_filterMenuItemActionPerformed
+
+    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed
+       if (evt.getSource() == saveMenuItem) {
+
+            jFileChooser1.setMultiSelectionEnabled(false);
+            jFileChooser1.setFileSelectionMode(jFileChooser1.DIRECTORIES_ONLY);
+            jFileChooser1.setApproveButtonText("Save");
+            int returnVal = jFileChooser1.showOpenDialog(this);
+
+            if (returnVal == jFileChooser1.APPROVE_OPTION) {
+
+                saveDirectory = jFileChooser1.getSelectedFile();
+
+                if(!saveDirectory.exists()){
+                    saveDirectory.mkdir();
+                }
+
+                fileLoadingActions.setSaveDirectory(saveDirectory);
+                fileLoadingActions.setWhich(6);
+                Thread thread = new Thread(fileLoadingActions);
+                thread.start();
+
+                dialogReportProblem.showMessageDialog(
+                    this,
+                    bundle.getString("savedResultsMessage"));
+
+            } else {
+                saveDirectory = null;
+            }
+
+        }
+    }//GEN-LAST:event_saveMenuItemActionPerformed
+
+    private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed
+        if (evt.getSource() ==  aboutMenuItem) {
+            AboutDialog about = new AboutDialog(this,true);
+            about.setVisible(true);
+        }
+    }//GEN-LAST:event_aboutMenuItemActionPerformed
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+
+            public void run() {
+                new NXvalidateFrame().setVisible(true);
+            }
+        });
+
+
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JMenuItem aboutMenuItem;
+    private javax.swing.JMenuItem bulkMenuItem;
+    private javax.swing.JMenuItem closeAllMenuItem;
+    private javax.swing.JMenuItem closeFileMenuItem;
+    private javax.swing.JOptionPane dialogReportProblem;
+    private javax.swing.JMenuItem exitAppMenuItem;
+    private javax.swing.JMenu fileMenu;
+    private javax.swing.JMenuItem filterMenuItem;
+    private javax.swing.JMenu helpMenu;
+    private javax.swing.JMenuItem helpMenuItem;
+    private javax.swing.JFileChooser jFileChooser1;
+    private javax.swing.JMenuBar jMenuBar1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JScrollPane jScrollPane2;
+    private javax.swing.JPopupMenu.Separator jSeparator1;
+    private javax.swing.JPopupMenu.Separator jSeparator2;
+    private javax.swing.JPopupMenu.Separator jSeparator3;
+    private javax.swing.JPopupMenu.Separator jSeparator4;
+    private javax.swing.JPopupMenu.Separator jSeparator5;
+    private javax.swing.JPopupMenu.Separator jSeparator6;
+    private javax.swing.JPopupMenu.Separator jSeparator7;
+    private javax.swing.JSplitPane jSplitPane1;
+    private javax.swing.JTextPane jTextPane1;
+    private javax.swing.JTree jTree1;
+    private javax.swing.JMenuItem openFilesMenuItem;
+    private javax.swing.JMenuItem saveMenuItem;
+    private javax.swing.JMenuItem settingsMenuItem;
+    private javax.swing.JMenu toolsMenu;
+    private javax.swing.JPopupMenu treePopupMenu;
+    private javax.swing.JMenuItem validateSelectedMenuItem;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateGuiTree.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateGuiTree.java
new file mode 100644
index 0000000..06bd5e3
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NXvalidateGuiTree.java
@@ -0,0 +1,177 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXvalidateGuiTree.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeCellRenderer;
+
+import org.xml.sax.Attributes;
+
+public class NXvalidateGuiTree {
+
+    public static class ITag implements IconAndTipCarrier {
+
+        private String name;
+        private String data;
+        private Attributes attr;
+        private Icon icon;
+        private String tipText;
+
+        public ITag(String n, Attributes a) {
+            name = n;
+            attr = a;
+            for (int i = 0; i < attr.getLength(); i++) {
+                String aname = attr.getQName(i);
+                String value = attr.getValue(i);
+                if (aname.equals("icon")) {
+                    tipText = value;
+                    icon = new ImageIcon(value);
+                    break;
+                }
+            }
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Attributes getAttributes() {
+            return attr;
+        }
+
+        public void setData(String d) {
+            data = d;
+        }
+
+        public String getData() {
+            return data;
+        }
+
+        public String getToolTipText() {
+            return tipText;
+        }
+
+        public Icon getIcon() {
+            return icon;
+        }
+
+        public void addData(String d) {
+            if (data == null) {
+                setData(d);
+            } else {
+                data += d;
+            }
+        }
+
+        public String getAttributesAsString() {
+            StringBuffer buf = new StringBuffer(256);
+            for (int i = 0; i < attr.getLength(); i++) {
+                buf.append(attr.getQName(i));
+                buf.append("=\"");
+                buf.append(attr.getValue(i));
+                buf.append("\"");
+            }
+            return buf.toString();
+        }
+
+        public String toString() {
+            String a = getAttributesAsString();
+            return name + ": " + a + (data == null ? "" : " (" + data + ")");
+        }
+    }
+}
+
+interface IconAndTipCarrier {
+
+    public Icon getIcon();
+
+    public String getToolTipText();
+}
+
+class IconAndTipRenderer extends JLabel implements TreeCellRenderer {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -6749045036022861743L;
+    Color backColor = new Color(0xFF, 0xCC, 0xFF);
+    Icon openIcon, closedIcon, leafIcon;
+    String tipText = "";
+
+    public IconAndTipRenderer(Icon open, Icon closed, Icon leaf) {
+        openIcon = open;
+        closedIcon = closed;
+        leafIcon = leaf;
+        setBackground(backColor);
+        setForeground(Color.black);
+    }
+
+    public Component getTreeCellRendererComponent(JTree tree, Object value,
+            boolean selected, boolean expanded, boolean leaf, int row,
+            boolean hasFocus) {
+        setText(value.toString());
+        if (selected) {
+            setOpaque(true);
+        } else {
+            setOpaque(false);
+        }
+
+        IconAndTipCarrier itc = null;
+        if (value instanceof DefaultMutableTreeNode) {
+            Object uo = ((DefaultMutableTreeNode) value).getUserObject();
+            if (uo instanceof IconAndTipCarrier) {
+                itc = (IconAndTipCarrier) uo;
+            }
+        } else if (value instanceof IconAndTipCarrier) {
+            itc = (IconAndTipCarrier) value;
+        }
+        if ((itc != null) && (itc.getIcon() != null)) {
+            setIcon(itc.getIcon());
+            tipText = itc.getToolTipText();
+        } else {
+            tipText = " ";
+            if (expanded) {
+                setIcon(openIcon);
+            } else if (leaf) {
+                setIcon(leafIcon);
+            } else {
+                setIcon(closedIcon);
+            }
+        }
+        return this;
+    }
+
+    public String getToolTipText() {
+        return tipText;
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/NodeFilterInterface.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NodeFilterInterface.java
new file mode 100644
index 0000000..8e18d53
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/NodeFilterInterface.java
@@ -0,0 +1,72 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NodeFilterInterface.java
+ *
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.util.ArrayList;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * An interface which represents the concept that the elements in an XML
+ * Document can be good or bad after they have been validated against some
+ * criteria defined in the implementation.
+ * @author Stephen Rankin
+ */
+public interface NodeFilterInterface {
+
+    /**
+     * Sets a DOM document (filter document) that contains a list of nodes
+     * that have failed any validation tests, for example, the SVRL file.
+     * @param filterDoc a DOM document.
+     */
+    public void setFilterDocument(Document filterDoc);
+
+    /**
+     * Sets the document to which to apply the filter.
+     * @param doc a DOM document.
+     */
+    public void setDocument(Document doc);
+
+    /**
+     * A list of nodes which are bad.
+     * @return the list of bad nodes
+     */
+    public ArrayList<Node> getBadNodeList();
+
+    /**
+     * A list of nodes which have a warning.
+     * @return
+     */
+    public ArrayList<Node> getWarnNodeList();
+    
+    /**
+     * Reset the nodes to indicate that they are now good nodes, i.e.
+     * resets them back to their original state.
+     */
+    public void resetNodes();
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/OSValidator.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/OSValidator.java
new file mode 100644
index 0000000..2a05e1d
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/OSValidator.java
@@ -0,0 +1,58 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * OSValidator.java
+ *
+ */
+
+package org.nexusformat.nxvalidate;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class OSValidator{
+
+	public boolean isWindows(){
+
+		String os = System.getProperty("os.name").toLowerCase();
+		//windows
+	    return (os.indexOf( "win" ) >= 0);
+
+	}
+
+	public boolean isMac(){
+
+		String os = System.getProperty("os.name").toLowerCase();
+		//Mac
+	    return (os.indexOf( "mac" ) >= 0);
+
+	}
+
+	public boolean isUnix(){
+
+		String os = System.getProperty("os.name").toLowerCase();
+		//linux or unix
+	    return (os.indexOf( "nix") >=0 || os.indexOf( "nux") >=0);
+
+	}
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/PopupListener.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/PopupListener.java
new file mode 100644
index 0000000..fd3f545
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/PopupListener.java
@@ -0,0 +1,58 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * PopupListener.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.JPopupMenu;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class PopupListener extends MouseAdapter {
+
+    private JPopupMenu popup;
+
+    public PopupListener(JPopupMenu popup) {
+        this.popup = popup;
+    }
+
+    public void mousePressed(MouseEvent e) {
+        maybeShowPopup(e);
+    }
+
+    public void mouseReleased(MouseEvent e) {
+        maybeShowPopup(e);
+    }
+
+    private void maybeShowPopup(MouseEvent e) {
+        if (e.isPopupTrigger()) {
+            popup.show(e.getComponent(),
+                    e.getX(), e.getY());
+        }
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/Report.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/Report.java
new file mode 100644
index 0000000..49cfcdb
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/Report.java
@@ -0,0 +1,114 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * Report.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+class Report {
+
+    NXSnode report;
+    ArrayList<SVRLitem> errors;
+    private static String NXROOT = "NXroot";
+    private static String SVRLROOT = "svrl:schematron-output";
+
+    Report(final File reduced, final File reportFile)
+            throws ParserConfigurationException, SAXException, IOException {
+
+        // parse the reduced file and turn it into a node tree
+        Document redDoc = parse(reduced);
+        report = new NXSnode(getNXroot(redDoc));
+
+        // add the svrl report to the reduced
+        Document svrlDoc = parse(reportFile);
+        this.errors = this.report.addSVRL(getSVRLroot(svrlDoc));
+    }
+
+    public int numErrors() {
+        return this.errors.size();
+    }
+
+    public ArrayList<SVRLitem> getReport() {
+        return this.errors;
+    }
+
+    public void printReport() {
+        int size = this.numErrors();
+        for (int i = 0; i < size; i++) {
+            System.out.println(this.errors.get(i));
+            if (i + 1 < size) {
+                System.out.println("----------");
+            }
+        }
+    }
+
+    public NXSnode getTree() {
+        return this.report;
+    }
+
+    public void printTree() {
+        this.report.printTree();
+    }
+
+    static private Node getNXroot(final Document doc) {
+        NodeList nodes = doc.getElementsByTagName(NXROOT);
+        int size = nodes.getLength();
+        if (size == 1) {
+            return nodes.item(0);
+        }
+        throw new Error(
+                "Failed to find one " + NXROOT + " (found " + size + ")");
+    }
+
+    static private Node getSVRLroot(final Document doc) {
+        NodeList nodes = doc.getElementsByTagName(SVRLROOT);
+        int size = nodes.getLength();
+        if (size == 1) {
+            return nodes.item(0);
+        }
+        throw new Error(
+                "Failed to find one " + SVRLROOT + " (found " + size + ")");
+    }
+
+    static private Document parse(final File file)
+            throws ParserConfigurationException, SAXException, IOException {
+        
+        DocumentBuilder builder =
+                DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        return builder.parse(file);
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/SVRLNodeFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/SVRLNodeFilter.java
new file mode 100644
index 0000000..9d01861
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/SVRLNodeFilter.java
@@ -0,0 +1,381 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * SVRLNodeFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import org.nexusformat.nxvalidate.exceptions.NXvalidateException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Implementation of NodeFilterInterface which filters out elements in a NEXUS
+ * reduced file if they have failed the validation tests.
+ * 
+ * @author Stephen Rankin
+ */
+public class SVRLNodeFilter implements NodeFilterInterface {
+
+    private Document filterDoc = null;
+    private Document doc = null;
+    private ArrayList<Node> nodes = null;
+    private ArrayList<Node> badNodes = null;
+    private ArrayList<Node> warnNodes = null;
+
+    public SVRLNodeFilter() {
+        nodes = new ArrayList<Node>();
+        badNodes = new ArrayList<Node>();
+        warnNodes = new ArrayList<Node>();
+    }
+
+    /**
+     * Sets a DOM document (filter document) that contains a list of nodes
+     * that have failed any validation tests, for example, the SVRL file.
+     * @param filterDoc a DOM document.
+     */
+    public void setFilterDocument(Document filterDoc) {
+
+        this.filterDoc = filterDoc;
+
+    }
+
+    /**
+     * Sets the document to which to apply the filter. The document in this case
+     * is the reduced NeXus file.
+     * @param doc a DOM document.
+     */
+    public void setDocument(Document doc) {
+
+        this.doc = doc;
+
+    }
+
+    /**
+     * A list of nodes which are bad.
+     * @return the list of bad nodes
+     */
+    public ArrayList<Node> getBadNodeList() {
+        try {
+
+            getXPathList();
+
+        } catch (NXvalidateException ex) {
+            Logger.getLogger(SVRLNodeFilter.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        } catch (XPathExpressionException ex) {
+            Logger.getLogger(SVRLNodeFilter.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        }
+        return badNodes;
+    }
+
+    /**
+     * A list of nodes which have a warning.
+     * @return
+     */
+    public ArrayList<Node> getWarnNodeList(){
+        try {
+
+            getXPathList();
+
+        } catch (NXvalidateException ex) {
+            Logger.getLogger(SVRLNodeFilter.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        } catch (XPathExpressionException ex) {
+            Logger.getLogger(SVRLNodeFilter.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        }
+        return warnNodes;
+    }
+
+    /**
+     * Reset the nodes to indicate that they are now good nodes, i.e.
+     * resets them back to a pre-validated state.
+     */
+    public void resetNodes() {
+        try {
+
+            resetNodes(0);
+            resetNodes(1);
+
+        } catch (NXvalidateException ex) {
+            Logger.getLogger(SVRLNodeFilter.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        } catch (XPathExpressionException ex) {
+            Logger.getLogger(SVRLNodeFilter.class.getName()).log(
+                    Level.SEVERE, null, ex);
+        }
+
+    }
+
+
+    private void resetNodes(int type) throws NXvalidateException,
+            XPathExpressionException {
+
+        NodeList failed = null;
+        String location = null;
+        Element element = null;
+        XPathFactory factory = XPathFactory.newInstance();
+        NodeList nodeList = null;
+
+        if (filterDoc != null) {
+            if (filterDoc.hasChildNodes()) {
+
+                //Get the xml elements svrl:failed-assert and
+                //svrl:successful-report from the XML
+                //validation results file.
+                if(type == 0){
+                    failed = filterDoc.getElementsByTagName("svrl:failed-assert");
+                }
+                else if(type == 1){
+                    failed = filterDoc.getElementsByTagName("svrl:successful-report");
+                }
+                if (failed.getLength() > 0) {
+
+                    for (int i = 0; i < failed.getLength(); ++i) {
+
+                        element = (Element) failed.item(i);
+
+                        if (element.hasChildNodes()) {
+
+                            //Each svrl:failed-assert element has child element
+                            //location which specifies the XPATH location of the
+                            //bad nodes.
+                            location = element.getAttribute("location");
+                            XPath xpath = factory.newXPath();
+                            location = location.replaceAll(
+                                    "\\[namespace-uri\\(\\)="
+                                    + "'http://definition.nexusformat.org/"
+                                    + "schema/3.1'\\]", "");
+                            XPathExpression expr = xpath.compile(location);
+
+                            Object result = expr.evaluate(doc,
+                                    XPathConstants.NODESET);
+                            nodeList = (NodeList) result;
+
+                            //Set the node back to its original state.
+                            for (int j = 0; j < nodeList.getLength(); j++) {
+                                
+                                nodeList.item(j).setUserData("validated", null, null);
+                                
+                                if(type == 0){
+                                    nodeList.item(j).setUserData("bad", null, null);
+                                }
+                                else if(type == 1){
+                                    nodeList.item(j).setUserData("warn", null, null);
+                                }
+
+                                nodeList.item(j).setUserData(
+                                        "tests", null, null);
+                                nodeList.item(j).setUserData(
+                                        "texts", null, null);
+                                nodeList.item(j).setUserData(
+                                        "diags", null, null);
+                                nodeList.item(j).setUserData(
+                                        "diagatts", null, null);
+                            }
+
+                        }
+
+                    }
+
+                }
+
+            }
+
+        }
+
+    }
+
+    private void getReportingNode(int type, NodeList nodeListInput) throws NXvalidateException,
+            XPathExpressionException {
+
+        
+        String location = null;
+        String test = null;
+        String text = null;
+        String diag = null;
+        String diagAtt = null;
+        ArrayList<String> tests = null;
+        ArrayList<String> texts = null;
+        ArrayList<String> diags = null;
+        ArrayList<String> diagAtts = null;
+        Element element = null;
+        XPathFactory factory = XPathFactory.newInstance();
+        NodeList nodeList = null;
+
+        //Loop through the nodes and get
+        //the test, text diagnostic and diagnostic attribute.
+        for (int i = 0; i < nodeListInput.getLength(); ++i) {
+
+            test = null;
+            text = null;
+            diag = null;
+            diagAtt = null;
+
+            element = (Element) nodeListInput.item(i);
+
+            if (element.hasChildNodes()) {
+
+                //Each element has child element
+                //location which specifies the XPATH location of the
+                //bad nodes.
+                location = element.getAttribute("location");
+                test = element.getAttribute("test");
+                if (element.getElementsByTagName("svrl:text").getLength() > 0) {
+                    text = element.getElementsByTagName(
+                            "svrl:text").item(0).getTextContent().trim();
+                }
+
+                if (element.getElementsByTagName(
+                        "svrl:diagnostic-reference").getLength() > 0) {
+
+                    diag = element.getElementsByTagName(
+                            "svrl:diagnostic-reference").item(0).getTextContent().trim();
+
+                    diagAtt = ((Element) element.getElementsByTagName(
+                            "svrl:diagnostic-reference").item(0)).getAttribute("diagnostic");
+                }
+
+                XPath xpath = factory.newXPath();
+                location = location.replaceAll(
+                        "\\[namespace-uri\\(\\)="
+                        + "'http://definition.nexusformat.org/"
+                        + "schema/3.1'\\]", "");
+                XPathExpression expr = xpath.compile(location);
+
+                Object result = expr.evaluate(doc,
+                        XPathConstants.NODESET);
+                nodeList = (NodeList) result;
+
+                for (int j = 0; j < nodeList.getLength(); j++) {
+
+                    nodeList.item(j).setUserData("validated", new Boolean(true), null);
+                    if(type == 0){
+                        nodeList.item(j).setUserData("bad", new Boolean(true), null);
+                        badNodes.add(nodeList.item(j));
+                    }
+                    else if(type == 1){
+                        nodeList.item(j).setUserData("warn", new Boolean(true), null);
+                        warnNodes.add(nodeList.item(j));
+                    }
+
+                    if (nodeList.item(j).getUserData("tests")
+                            != null && test != null) {
+                        tests = (ArrayList<String>) nodeList.item(j).getUserData(
+                                "tests");
+                        tests.add(test);
+                    } else {
+                        tests = new ArrayList<String>();
+                        tests.add(test);
+                    }
+
+                    if (nodeList.item(j).getUserData("texts")
+                            != null && text != null) {
+                        texts = (ArrayList<String>) nodeList.item(j).getUserData(
+                                "texts");
+                        texts.add(text);
+                    } else {
+                        texts = new ArrayList<String>();
+                        texts.add(text);
+                    }
+
+                    if (nodeList.item(j).getUserData("diags")
+                            != null && diag != null) {
+                        diags = (ArrayList<String>) nodeList.item(j).getUserData(
+                                "diags");
+                        diags.add(diag);
+                    } else {
+                        diags = new ArrayList<String>();
+                        diags.add(diag);
+                    }
+
+                    if (nodeList.item(j).getUserData("diagatts")
+                            != null && diagAtt != null) {
+                        diagAtts = (ArrayList<String>) nodeList.item(j).getUserData(
+                                "diagatts");
+                        diagAtts.add(diagAtt);
+                    } else {
+                        diagAtts = new ArrayList<String>();
+                        diagAtts.add(diagAtt);
+                    }
+
+                    nodeList.item(j).setUserData(
+                            "tests", tests, null);
+                    nodeList.item(j).setUserData(
+                            "texts", texts, null);
+                    nodeList.item(j).setUserData(
+                            "diags", diags, null);
+                    nodeList.item(j).setUserData(
+                            "diagatts", diagAtts, null);
+                    
+                    nodes.add(nodeList.item(j));
+                }
+
+            }
+
+        }
+
+
+    }
+
+    private void getXPathList() throws NXvalidateException, XPathExpressionException {
+
+        NodeList list = null;
+        
+        if (filterDoc != null) {
+            if (filterDoc.hasChildNodes()) {
+
+                //Get the xml elements svrl:failed-assert from the XML
+                //validation results file.
+                list = filterDoc.getElementsByTagName("svrl:failed-assert");
+
+                if (list.getLength() > 0) {
+                    getReportingNode(0, list);
+                }
+
+                //Get the xml elements successful-report from the XML
+                //validation results file.
+                list = filterDoc.getElementsByTagName("svrl:successful-report");
+
+                if (list.getLength() > 0) {
+                     getReportingNode(1, list);
+                }
+
+            }
+
+        }
+
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/SVRLitem.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/SVRLitem.java
new file mode 100644
index 0000000..b41add2
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/SVRLitem.java
@@ -0,0 +1,178 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * SVRLitem.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.util.ArrayList;
+import java.util.Vector;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class SVRLitem {
+	private static String NS_START = "[namespace-uri";
+	private static String NS_STOP = "']";
+	
+	private String[] location;
+	private String xpath_str;
+	private String type;
+	private String test;
+	private String message;
+
+	public SVRLitem(final Node node) {
+		this.setLocation(node);
+		this.setType(node.getNodeName());
+		this.setAttrs(node.getAttributes());
+		this.setMessage(node);
+	}
+
+	public String toString() {
+		StringBuilder buffer = new StringBuilder();
+		buffer.append(this.test + " failed at " + this.getLocation());
+		if (this.message.length() > 0) {
+			buffer.append("\n");
+			buffer.append(this.message);
+		}
+		return buffer.toString();
+	}
+
+	ArrayList<String> getLocationArray() {
+		ArrayList<String> result = new ArrayList<String>();
+		for (int i = 0; i < this.location.length; i++) {
+			result.add(this.location[i]);
+		}
+		return result;
+	}
+
+	public String getLocation() {
+		StringBuilder buffer = new StringBuilder();
+		for (String item: this.location) {
+			buffer.append("/");
+			buffer.append(item);
+		}
+		return buffer.toString();
+	}
+
+	public String getType() {
+		return this.type;
+	}
+
+	public String getTest() {
+		return this.test;
+	}
+	
+	public String getMessage() {
+		return this.message;
+	}
+
+	private void setType(final String type) {
+		if (type.equals("svrl:failed-assert")) {
+			this.type = "failed assert";
+		} else {
+			throw new Error("Do not understand type " + type);
+		}
+	}
+
+	private void setAttrs(final NamedNodeMap attrs) {
+		Node attr;
+		// get the test name
+		attr = attrs.getNamedItem("test");
+		if (attr != null) {
+			this.test = attr.getNodeValue();
+		}
+	}
+	private void setMessage(final Node node) {
+		if (node.getNodeName().equals("svrl:text")) {
+			NodeList nodes = node.getChildNodes();
+			int size = nodes.getLength();
+			if (size == 0) {
+				this.message = "";
+			} else if(size == 1) {
+				this.message = nodes.item(0).getNodeValue();
+				this.message = this.message.trim();
+			} else {
+				throw new Error("Expected only 1 node, found "
+						+ nodes.getLength());
+			}
+		} else {
+			NodeList nodes = node.getChildNodes();
+			int size = nodes.getLength();
+			Node temp;
+			for (int i = 0; i < size; i++) {
+				temp = nodes.item(i);
+				if (temp.getNodeName().equals("svrl:text")) {
+					this.setMessage(temp);
+					return;
+				}
+			}
+		}
+	}
+
+	private void setLocation(final Node node) {
+		// deal with the root splitting
+		this.xpath_str = getLocation(node);
+		String temp = this.xpath_str.substring(3);
+		this.location = temp.split("/\\*:");
+
+		// trim out the namespace junk
+		for (int i = 0; i < this.location.length; i++) {
+			this.location[i] = removeNS(this.location[i]);
+		}
+	}
+	static private String removeNS(final String orig) {
+		int left = orig.indexOf(NS_START);
+		int right = orig.indexOf(NS_STOP, left + 1);
+
+		return orig.substring(0, left)
+		       + orig.substring(right + NS_STOP.length());
+	}
+
+	public static boolean hasLocation(final Node candidate) {
+		if (candidate.getNodeType() != Node.ELEMENT_NODE) {
+			return false;
+		}
+		String location = getLocation(candidate);
+		if (location == null) {
+			return false;
+		}
+		if (location.length() <= 0) {
+			return false;
+		}
+		return true;
+	}
+
+	public static String getLocation(final Node node) {
+		NamedNodeMap attrs = node.getAttributes();
+		Node attr = attrs.getNamedItem("location");
+		if (attr == null) {
+			return "";
+		}
+		else {
+			return attr.getNodeValue();
+		}
+	}
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/StreamGobbler.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/StreamGobbler.java
new file mode 100644
index 0000000..8fb1130
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/StreamGobbler.java
@@ -0,0 +1,86 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * StreamGobbler.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * Thread for consuming streams.
+ */
+public final class StreamGobbler extends Thread {
+  /** The stream that will be read from in the thread. */
+  private InputStream stream;
+
+  /** A label for the stream. */
+  private String type;
+
+  /** Everything written to the stream. */
+  private StringBuffer buffer;
+
+  /**
+   * @param stream The stream to consume.
+   * @param type The type of the stream.
+   */
+  public StreamGobbler(final InputStream stream, final String type) {
+    this.stream = stream;
+    this.type = type;
+    this.buffer = new StringBuffer();
+  }
+
+  /**
+   * @return The type of the stream.
+   */
+  public String getType() {
+    return this.type;
+  }
+
+  /** {@inheritDoc} */
+  public void run() {
+    try {
+      InputStreamReader isr = new InputStreamReader(this.stream);
+      BufferedReader br = new BufferedReader(isr);
+      String line = null;
+      while ((line = br.readLine()) != null) {
+        buffer.append(line);
+        buffer.append("\n");
+      }
+    }
+    catch (IOException ioe) {
+      ioe.printStackTrace();
+    }
+
+  }
+
+  /**
+   * @return Everything that was written to the stream.
+   */
+  public String getOutput() {
+    return buffer.toString();
+  }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/TextPaneStyle.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/TextPaneStyle.java
new file mode 100644
index 0000000..e527e0b
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/TextPaneStyle.java
@@ -0,0 +1,227 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * TextPaneStyle.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.awt.Color;
+import java.util.logging.Level;
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+import javax.swing.text.StyledDocument;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class TextPaneStyle {
+
+    private JTextPane pane = null;
+
+    public TextPaneStyle(JTextPane pane) {
+        this.pane = pane;
+    }
+
+    private void printValidationErrors(NXNodeMapper node, StyledDocument doc,
+            int type) throws BadLocationException {
+
+        String newline = "\n";
+
+        doc.insertString(doc.getLength(), newline + newline,
+                    doc.getStyle("heading"));
+
+        if(type == 0){
+            doc.insertString(doc.getLength(), "Validation Tests:" +
+                         newline + newline, doc.getStyle("heading"));
+        }
+        else{
+            doc.insertString(doc.getLength(), "Warning Tests:" +
+                         newline + newline, doc.getStyle("heading"));
+        }
+
+        if (node.getNodeTests() != null) {
+            for (int i = 0; i < node.getNodeTests().size(); ++i) {
+                doc.insertString(doc.getLength(),
+                        node.getNodeTests().get(i), doc.getStyle("bold"));
+                doc.insertString(doc.getLength(),
+                        newline + newline, doc.getStyle("heading"));
+            }
+        }
+
+        if(type == 0){
+            doc.insertString(doc.getLength(), "Validation Errors:" +
+                newline + newline, doc.getStyle("errorheading"));
+        }
+        else{
+            doc.insertString(doc.getLength(), "Warning Errors:" +
+                newline + newline, doc.getStyle("warningheading"));
+        }
+
+        if (node.getNodeTexts() != null) {
+            for (int i = 0; i < node.getNodeTexts().size(); ++i) {
+               
+                if(type == 0){
+                    doc.insertString(doc.getLength(),
+                        node.getNodeTexts().get(i), doc.getStyle("error"));
+                }
+                else{
+                    doc.insertString(doc.getLength(),
+                        node.getNodeTexts().get(i), doc.getStyle("warning"));
+                }
+
+                doc.insertString(doc.getLength(),
+                        newline + newline, doc.getStyle("heading"));
+            }
+        }
+
+        if(type == 0){
+            doc.insertString(doc.getLength(), "Diagnostic Errors:" +
+                newline + newline, doc.getStyle("errorheading"));
+        }
+        else{
+            doc.insertString(doc.getLength(), "Diagnostic Errors:" +
+                newline + newline, doc.getStyle("warningheading"));
+        }
+
+        if (node.getNodeDiags() != null) {
+            for (int i = 0; i < node.getNodeDiags().size(); ++i) {
+
+                if(type == 0){
+                    doc.insertString(doc.getLength(),
+                        node.getNodeDiags().get(i), doc.getStyle("error"));
+                }
+                else{
+                    doc.insertString(doc.getLength(),
+                        node.getNodeDiags().get(i), doc.getStyle("warning"));
+                }
+                
+                doc.insertString(doc.getLength(),
+                        newline + newline, doc.getStyle("heading"));
+            }
+        }
+
+    }
+
+    public void updateTextPane(NXNodeMapper node) {
+
+        String newline = "\n";
+
+        StyledDocument doc = pane.getStyledDocument();
+
+        addStylesToDocument(doc);
+        String[] atts = node.getAttributeList();
+
+        try {
+
+            doc.remove(0, doc.getLength());
+
+            doc.insertString(0, node.toString()
+                    + newline + newline, doc.getStyle("title"));
+
+            doc.insertString(doc.getLength(), "Attributes:"
+                    + newline + newline, doc.getStyle("heading"));
+
+            for (int i = 0; i
+                    < atts.length; i++) {
+                doc.insertString(doc.getLength(),
+                        "@ " + atts[i] + newline, doc.getStyle("bold"));
+            }
+
+            doc.insertString(doc.getLength(), newline + newline,
+                    doc.getStyle("heading"));
+
+            doc.insertString(doc.getLength(), "Node Value:"
+                    + newline + newline, doc.getStyle("heading"));
+
+            doc.insertString(doc.getLength(),
+                    node.getValue(), doc.getStyle("bold"));
+
+            if(node.getBadNode()){
+                printValidationErrors(node, doc, 0);
+            }
+            else if(node.getWarnNode()){
+                printValidationErrors(node, doc, 1);
+            }
+
+        } catch (BadLocationException ex) {
+            Logger.getLogger(TextPaneStyle.class.getName()).log(Level.SEVERE,
+                    null, ex);
+        }
+
+    }
+
+    private void addStylesToDocument(StyledDocument doc) {
+
+        //Initialize some styles.
+        Style def = StyleContext.getDefaultStyleContext().
+                getStyle(StyleContext.DEFAULT_STYLE);
+
+        Style regular = doc.addStyle("regular", def);
+        StyleConstants.setFontFamily(def, "SansSerif");
+
+        Style s = doc.addStyle("italic", regular);
+        StyleConstants.setItalic(s, true);
+
+        s = doc.addStyle("bold", regular);
+        StyleConstants.setBold(s, true);
+
+        s = doc.addStyle("small", regular);
+        StyleConstants.setFontSize(s, 10);
+
+        s = doc.addStyle("large", regular);
+        StyleConstants.setFontSize(s, 16);
+
+        s = doc.addStyle("heading", regular);
+        StyleConstants.setFontSize(s, 16);
+        StyleConstants.setBold(s, true);
+
+        s = doc.addStyle("title", regular);
+        StyleConstants.setFontSize(s, 24);
+        StyleConstants.setBold(s, true);
+
+        s = doc.addStyle("errorheading", regular);
+        StyleConstants.setFontSize(s, 16);
+        StyleConstants.setBold(s, true);
+        StyleConstants.setForeground(s, Color.red);
+
+        s = doc.addStyle("error", regular);
+        StyleConstants.setBold(s, true);
+        StyleConstants.setForeground(s, Color.red);
+
+        s = doc.addStyle("warningheading", regular);
+        StyleConstants.setFontSize(s, 16);
+        StyleConstants.setBold(s, true);
+        StyleConstants.setForeground(s, Color.BLUE);
+
+        s = doc.addStyle("warning", regular);
+        StyleConstants.setBold(s, true);
+        StyleConstants.setForeground(s, Color.BLUE);
+
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/TreeUtils.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/TreeUtils.java
new file mode 100644
index 0000000..9812c8c
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/TreeUtils.java
@@ -0,0 +1,293 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * TreeUtils.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import javax.swing.JTree;
+import javax.swing.tree.TreePath;
+import org.w3c.dom.Document;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class TreeUtils {
+
+
+
+
+    public void hideGoodNodes(JTree tree){
+
+        if (tree.isSelectionEmpty()) {
+            return;
+        }
+
+        ArrayList<NXNodeMapper> nodes = new ArrayList<NXNodeMapper>();
+        ArrayList<TreePath> paths = new ArrayList<TreePath>();
+        NXNodeMapper baseNode = getBaseNode(tree);
+
+        if (baseNode==null) {
+            return;
+        }
+
+        Enumeration children = baseNode.children();
+        NXNodeMapper tmpNode = null;
+
+        NXNodeMapper parent = null;
+        TreePath path = null;
+        ArrayList<NXNodeMapper> tmpPath = null;
+        ArrayList<NXNodeMapper> tmpPath2 = null;
+        nodes.add(baseNode);
+
+        while (children.hasMoreElements()) {
+
+            tmpNode = (NXNodeMapper)children.nextElement();
+            nodes.add(tmpNode);
+            nodes.addAll(getSubNodes(tmpNode));
+
+        }
+
+        for (int i = 0; i < nodes.size(); ++i) {
+           
+           nodes.get(i).checkBadNode();
+           
+           if(nodes.get(i).getBadNode()){
+
+               tmpPath = new ArrayList<NXNodeMapper>();
+               //tmpPath.add(nodes.get(i));
+
+               parent = (NXNodeMapper)nodes.get(i).getParent();
+
+               while(!parent.toString().equals(baseNode.toString()) && parent!=null){
+                   tmpPath.add(parent);
+                   parent = (NXNodeMapper)parent.getParent();
+               }
+               tmpPath.add(baseNode);
+               tmpPath.add((NXNodeMapper)baseNode.getParent());
+               
+               tmpPath2 = new ArrayList<NXNodeMapper>();
+               
+               int number = tmpPath.size() -1;
+               for(int j = 0; j < tmpPath.size();++j){
+                   tmpPath2.add(tmpPath.get(number -j));
+               }
+
+               paths.add(new TreePath(tmpPath2.toArray()));
+               tree.expandPath(new TreePath(tmpPath2.toArray()));
+           }
+        }
+
+    }
+
+    private ArrayList<NXNodeMapper> getSubNodes(NXNodeMapper node){
+
+        ArrayList<NXNodeMapper> nodes = new ArrayList<NXNodeMapper>();
+        NXNodeMapper tmpNode = null;
+
+        Enumeration children = node.children();
+
+        while (children.hasMoreElements()) {
+            
+            tmpNode = (NXNodeMapper)children.nextElement();
+            nodes.add(tmpNode);
+            nodes.addAll(getSubNodes(tmpNode));
+            
+        }
+
+        return nodes;
+
+    }
+
+    public boolean hasBadChildren(NXNodeMapper node){
+
+        ArrayList<NXNodeMapper> subNodes = getSubNodes(node);
+        boolean bad = false;
+        for(int i = 0;i<subNodes.size();++i){
+            if(subNodes.get(i).getBadNode()){
+                bad = true;
+                break;
+            }
+        }
+        return bad;
+    }
+
+    public void showGoodNodes(JTree tree){
+
+        if (tree.isSelectionEmpty()) {
+            return;
+        }
+
+        NXNodeMapper baseNode = getBaseNode(tree);
+        NXNodeMapper node = null;
+
+        int rows = tree.getRowCount();
+
+        for (int i = 0; i < rows; ++i) {
+            node = (NXNodeMapper) tree.getPathForRow(i).getLastPathComponent();
+            System.out.println("Node Name: " + node.toString());
+        }
+
+    }
+
+    public String getTreePath(JTree tree) {
+
+        if (tree.isSelectionEmpty()) {
+            return null;
+        }
+
+        TreePath treePath = tree.getSelectionPath().getParentPath();
+        NXNodeMapper node =
+                (NXNodeMapper) tree.getSelectionPath().getLastPathComponent();
+
+        String path = "";
+        NXNodeMapper tmpNode = null;
+        Object[] nodes = treePath.getPath();
+
+        for (int i = 0; i < treePath.getPathCount(); ++i) {
+            tmpNode = (NXNodeMapper) nodes[i];
+            path = path + "/" + tmpNode.toString();
+        }
+
+        path = path + "/" + node.toString();
+
+        return path;
+
+    }
+
+    public NXNodeMapper getBaseNode(JTree tree) {
+        if (getRootNode(tree) != null) {
+            return getRootNode(tree);
+        } else {
+            return null;
+        }
+    }
+
+    public File getNXDLFile(JTree tree) {
+        if (getRootNode(tree) != null) {
+            return getRootNode(tree).getNXDLFile();
+        } else {
+            return null;
+        }
+    }
+
+    public File getReducedFile(JTree tree) {
+        if (getRootNode(tree) != null) {
+            return getRootNode(tree).getReducedFile();
+        } else {
+            return null;
+        }
+    }
+
+    public Document getReducedDoc(JTree tree) {
+        if (getRootNode(tree) != null) {
+            return getRootNode(tree).getReducedDoc();
+        } else {
+            return null;
+        }
+    }
+
+    public Document getResultsDoc(JTree tree) {
+        if (getRootNode(tree) != null) {
+            return getRootNode(tree).getResultsDoc();
+        } else {
+            return null;
+        }
+    }
+
+    public File getResultsFile(JTree tree) {
+        if (getRootNode(tree) != null) {
+            return getRootNode(tree).getResultsFile();
+        } else {
+            return null;
+        }
+    }
+
+    public void setNXDLFile(JTree tree, File file) {
+        if (getRootNode(tree) != null) {
+            getRootNode(tree).setNXDLFile(file);
+        }
+    }
+
+    public void setReducedFile(JTree tree, File file) {
+        if (getRootNode(tree) != null) {
+            getRootNode(tree).setReducedFile(file);
+        }
+    }
+
+    public void setReducedDoc(JTree tree, Document doc) {
+        if (getRootNode(tree) != null) {
+            getRootNode(tree).setReducedDoc(doc);
+        }
+    }
+
+    public void setResultsDoc(JTree tree, Document doc) {
+        if (getRootNode(tree) != null) {
+            getRootNode(tree).setResultsDoc(doc);
+        }
+    }
+
+    public void setResultsFile(JTree tree, File file) {
+        if (getRootNode(tree) != null) {
+            getRootNode(tree).setResultsFile(file);
+        }
+    }
+
+    public void setValidated(JTree tree, File file) {
+        NXNodeMapper tmpNode = getRootNode(tree);
+        if (tmpNode != null) {
+            if(tmpNode.getResultsFile().equals(file)){
+                tmpNode.setValidatedNode(true);
+            }
+        }
+    }
+    
+    private NXNodeMapper getRootNode(JTree tree) {
+        if (tree.isSelectionEmpty()) {
+            return null;
+        }
+
+        TreePath treePath = tree.getSelectionPath().getParentPath();
+
+        if(treePath==null){
+             return null;
+        }
+
+        NXNodeMapper tmpNode = null;
+        Object[] nodes = treePath.getPath();
+        if (nodes.length > 1) {
+            tmpNode = (NXNodeMapper) nodes[1];
+        } else if (nodes.length == 1) {
+            tmpNode =
+                    (NXNodeMapper) tree.getSelectionPath().getLastPathComponent();
+        } else {
+            return null;
+        }
+        return tmpNode;
+    }
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/UserSettings.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/UserSettings.java
new file mode 100644
index 0000000..6611f5c
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/UserSettings.java
@@ -0,0 +1,208 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * UserSettings.java
+ *
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import javax.swing.JOptionPane;
+import java.util.logging.Logger;
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class UserSettings {
+
+    private Properties props = null;
+    private String nxconvertCommand = null;
+    private ResourceBundle bundle = null;
+    private boolean foundNXconvert = false;
+
+    
+    public UserSettings(){
+        props = new Properties();
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+    }
+
+    public void loadUserSettings() throws FileNotFoundException, IOException {
+
+        props = new Properties();
+
+        Map<String, String> env = System.getenv();
+        for (String envName : env.keySet()) {
+            System.out.format("%s=%s%n", envName, env.get(envName));
+        }
+
+        File settings = new File(System.getProperty("user.home")
+                + System.getProperty("file.separator")
+                + ".nxvalidate.properties");
+
+        if (settings.exists()) {
+            props.load(new FileInputStream(settings));
+            if (props.getProperty("nxconvert") != null) {
+                
+                if(chechExists(props.getProperty("nxconvert"))){
+                    nxconvertCommand = props.getProperty("nxconvert");
+                    foundNXconvert = true;
+                }
+                else{
+                    defaultNXconvert();
+                }
+            }
+            else{
+                defaultNXconvert();
+            }
+        } else {
+            settings.createNewFile();
+            defaultNXconvert();
+        }
+
+    }
+
+    public void saveUserSettings() {
+
+        File settings = new File(System.getProperty("user.home")
+                + System.getProperty("file.separator") + ".nxvalidate.properties");
+        try {
+            if (settings.exists()) {
+
+                props.setProperty("nxconvert", nxconvertCommand);
+                props.store(new FileOutputStream(settings), "NXvalidate");
+
+            } else {
+                settings.createNewFile();
+                props.setProperty("nxconvert", nxconvertCommand);
+                props.store(new FileOutputStream(settings), "NXvalidate");
+
+            }
+        } catch (FileNotFoundException ex) {
+            Logger.getLogger(
+                    NXvalidateFrame.class.getName()).log(Level.SEVERE,
+                    "saveUserSettings(): The settings file cannot be found.", ex);
+        } catch (IOException ex) {
+            Logger.getLogger(
+                    NXvalidateFrame.class.getName()).log(Level.SEVERE,
+                    "saveUserSettings(): The settings file IO error.", ex);
+        }
+    }
+
+    public String getNXconvert(){
+        return nxconvertCommand;
+    }
+
+    public void setNXconvert(String nxconvertCommand){
+        this.nxconvertCommand = nxconvertCommand;
+        if(testPath(nxconvertCommand)){
+            foundNXconvert = true;
+        }
+        else{
+            foundNXconvert = false;
+        }
+    }
+
+    public boolean foundNXconvert(){
+        return foundNXconvert;
+    }
+
+    private void defaultNXconvert(){
+        OSValidator os = new OSValidator();
+
+        if(os.isWindows()){
+            nxconvertCommand = bundle.getString("defaultWindowsNXconvert");
+        } else if(os.isMac()){
+            nxconvertCommand = bundle.getString("defaultMacNXconvert");
+        } else if(os.isUnix()){
+            nxconvertCommand = bundle.getString("defaultUNIXNXconvert");
+            if(!chechExists(nxconvertCommand)){
+                nxconvertCommand = bundle.getString("defaultUNIXNXconvert2");
+            }
+        }
+
+        if(!chechExists(nxconvertCommand)){
+            nxconvertCommand = "nxconvert";
+        }
+
+        if(testPath(nxconvertCommand)){
+            System.out.println("defaultNXconvert foundNXconvert:" + foundNXconvert);
+            foundNXconvert = true;
+        }
+
+    }
+
+    private boolean chechExists(String filename){
+
+        File file = null;
+        boolean exists = false;
+        if(filename!=null){
+
+            if(!filename.equals("")){
+                file = new File(filename);
+            }
+            else{
+                return false;
+            }
+
+            if(file.exists()){
+                exists = true;
+            }
+            
+        }
+        return exists;
+
+    }
+
+    private boolean testPath(String path){
+
+        boolean result = false;
+
+        if(path == null){
+            return result;
+        }
+        if(path.equals("")){
+            return result;
+        }
+        
+        try {
+            // execute the command
+            Runtime rt = Runtime.getRuntime();
+            Process proc = rt.exec(path + " --help");
+            result = true;
+            return result;
+        } catch (IOException ex) {
+            return result;
+        }
+
+    }
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/ValidatorUtils.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/ValidatorUtils.java
new file mode 100644
index 0000000..6482bb2
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/ValidatorUtils.java
@@ -0,0 +1,175 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * ValidatorUtils.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.io.File;
+import org.nexusformat.nxvalidate.exceptions.NXvalidateException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A class the wraps the conversion and validation processes.
+ * @author Stephen Rankin
+ */
+public class ValidatorUtils {
+
+    private File reduced = null;
+    private File nxsFile = null;
+    private boolean keepTemp = false;
+    private File schematronFile = null;
+    private boolean convertNxs = false;
+    private String nxconvertCommand = null;
+
+
+    public ValidatorUtils(File nxsFile, String nxconvertCommand) {
+
+        this.nxconvertCommand = nxconvertCommand;
+        this.nxsFile = nxsFile;
+    }
+
+    /**
+     * Set the File object pointing to the reduced NEXUS file.
+     *
+     * @param reduced the reduced NEXUS File object.
+     */
+    public void setReduced(File reduced) {
+        this.reduced = reduced;
+    }
+
+    /**
+     *
+     * Get the File object pointing to the reduced NEXUS file.
+     *
+     * @return the reduced NEXUS File object.
+     */
+    public File getReduced() {
+        return reduced;
+    }
+
+    /**
+     * Set the File object pointing to the NEXUS file.
+     *
+     * @param nxsFile the NEXUS File object.
+     */
+    public void setNXS(File nxsFile) {
+        this.nxsFile = nxsFile;
+    }
+
+    /**
+     *
+     * Get the File object pointing to the NEXUS file.
+     *
+     * @return the NEXUS File object.
+     */
+    public File getNXS() {
+        return nxsFile;
+    }
+
+    /**
+     * Set the File object pointing to the Schematron file that contains the
+     * rules for checking the reduced document.
+     *
+     * @param schematronFile the Schematron File object.
+     */
+    public void setSchematron(File schematronFile) {
+        this.schematronFile = schematronFile;
+    }
+
+    /**
+     * Get the File object pointing to the Schematron file that contains the
+     * rules for checking the reduced document.
+     *
+     * @return the Schematron File object.
+     */
+    public File getSchematron() {
+        return schematronFile;
+    }
+
+    /**
+     * Set a flag that indicates that the conversion of a NEXUS file 
+     * to a reduced document should be performed (true).
+     *
+     * @param convertNxs the conversion flag.
+     */
+    public void doConversion(boolean convertNxs) {
+        this.convertNxs = convertNxs;
+    }
+
+    /**
+     * Set a flag that indicates that the temporary files
+     * (such as the reduced document and the validation results)
+     * should be kept (true).
+     *
+     * @param keepTemp the keep temp files flag.
+     */
+    public void setKeepTemp(boolean keepTemp) {
+        this.keepTemp = keepTemp;
+    }
+
+    /**
+     * This methods performs the validation using the NEXUS (or reduced) file
+     * and the Schematron file. The returned file is the results file.
+     * @return the results file as a File object.
+     * @throws NXvalidateException
+     */
+    public File validate() throws NXvalidateException {
+
+        File result = null;
+
+        //Do the conversion to the reduced format.
+        if (convertNxs && nxsFile != null) {
+            try {
+                NXconvert converter = new NXconvert(nxsFile, keepTemp, nxconvertCommand);
+                reduced = converter.convert();
+            } catch (Exception e) {
+                Logger.getLogger(ValidatorUtils.class.getName()).log(Level.SEVERE,
+                        "While converting \"" + nxsFile
+                        + "\" to reduced xml format");
+                throw new NXvalidateException("While converting \"" + nxsFile
+                        + "\" to reduced xml format");
+            }
+        }
+
+        //Do the validation.
+        if (reduced != null && schematronFile != null) {
+
+            // create the validation setup
+            NXschematron schematron = new NXschematron(nxsFile, reduced,
+                    schematronFile, keepTemp);
+
+            try {
+                result = schematron.validate();
+            } catch (Exception e) {
+                Logger.getLogger(ValidatorUtils.class.getName()).log(Level.SEVERE,
+                        "While creating validation report");
+                throw new NXvalidateException("While creating validation report", e);
+            }
+        }
+
+        return result;
+
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/XMLIconTreeHandler.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/XMLIconTreeHandler.java
new file mode 100644
index 0000000..20aaeea
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/XMLIconTreeHandler.java
@@ -0,0 +1,74 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * XMLIconTreeHandler.java
+ *
+ */
+
+package org.nexusformat.nxvalidate;
+
+import java.util.ResourceBundle;
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import org.nexusformat.nxvalidate.NXvalidateGuiTree.ITag;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class XMLIconTreeHandler extends DefaultHandler {
+
+    private DefaultMutableTreeNode root, currentNode;
+    private ResourceBundle bundle = null;
+
+    public DefaultMutableTreeNode getRoot() {
+        return root;
+    }
+
+    @Override
+    public void startElement(String namespaceURI, String lName, String qName,
+            Attributes attrs) throws SAXException {
+        String eName = lName;
+        if ("".equals(eName)) {
+            eName = qName;
+        }
+        ITag t = new ITag(eName, attrs);
+        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(t);
+        if (currentNode == null) {
+            root = newNode;
+        } else {
+            currentNode.add(newNode);
+        }
+        currentNode = newNode;
+    }
+
+    @Override
+    public void endElement(String namespaceURI, String sName, String qName)
+            throws SAXException {
+        currentNode = (DefaultMutableTreeNode) currentNode.getParent();
+    }
+
+    @Override
+    public void characters(char buf[], int offset, int len) throws SAXException {
+        String s = new String(buf, offset, len).trim();
+        ((ITag) currentNode.getUserObject()).addData(s);
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/XMLTreeRenderer.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/XMLTreeRenderer.java
new file mode 100644
index 0000000..1c9836f
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/XMLTreeRenderer.java
@@ -0,0 +1,187 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * XMLTreeRenderer.java
+ *
+ */
+package org.nexusformat.nxvalidate;
+
+import java.awt.Component;
+import java.util.ResourceBundle;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JTree;
+import javax.swing.plaf.basic.BasicTreeUI;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+/**
+ * We need to modify the tree representing the reduced document when
+ * nodes are found to be bad (validation fails on them). the bad nodes
+ * are marked with a red cross icon and a tool tip is added to the node.
+ * 
+ * @author Stephen Rankin
+ */
+public class XMLTreeRenderer extends DefaultTreeCellRenderer {
+
+    private String badPath = "";
+    private String goodPath = "";
+    private String warnPath = "";
+    private String rootPath = "";
+    private String newPath = "";
+    private String infoPath = "";
+    private String infoGoodPath = "";
+    private String infoBadPath = "";
+    private String infoWarnPath = "";
+
+    private ResourceBundle bundle = null;
+    private JTree tree = null;
+    /**
+     * Setup a tree renderer with custom icons.
+     * @param path the relative path to the image icon.
+     */
+    public XMLTreeRenderer(String rootPath, String badPath,
+                           String goodPath, String warnPath,
+                           String newPath, String infoPath,
+                           String infoGoodPath, String infoBadPath,
+                           String infoWarnPath) {
+        this.badPath = badPath;
+        this.goodPath = goodPath;
+        this.warnPath = warnPath;
+        this.rootPath = rootPath;
+        this.newPath = newPath;
+        this.infoPath = infoPath;
+        this.infoGoodPath = infoGoodPath;
+        this.infoBadPath = infoBadPath;
+        this.infoWarnPath = infoWarnPath;
+        bundle = ResourceBundle.getBundle(
+                "org/nexusformat/nxvalidate/resources/nxvalidate");
+    }
+
+    @Override
+    public Component getTreeCellRendererComponent(
+            JTree tree,
+            Object value,
+            boolean sel,
+            boolean expanded,
+            boolean leaf,
+            int row,
+            boolean hasFocus) {
+
+        super.getTreeCellRendererComponent(
+                tree, value, sel,
+                expanded, leaf, row,
+                hasFocus);
+
+        boolean validated = false;
+        this.tree = tree;
+
+        //Add the bad node error icon and tool tip text.
+        NXNodeMapper node = (NXNodeMapper) value;
+
+        if(node.getRoot()!=null){
+            validated = node.getRoot().getValidatedNode();
+        }
+        else{
+            validated = node.getValidatedNode();
+        }
+        
+        if(node.hasBadChildren()){
+
+        }
+
+        /*boolean badKids = node.checkBadChildren();
+        if (badKids) {
+            setIcon(createImageIcon("resources/dialog-warning.png", "warningIcon"));
+        }*/
+        if (node.getBadNode() && node.hasBadChildren()) {
+            setIcon(createImageIcon(infoBadPath, "errorIcon"));
+        }
+        else if(node.getBadNode() && !node.hasBadChildren()) {
+            setIcon(createImageIcon(badPath, "errorIcon"));
+        }
+        else if(node.getWarnNode() && node.hasBadChildren()){
+            setIcon(createImageIcon(infoWarnPath, "warnIcon"));
+        }
+        else if(node.getWarnNode() && !node.hasBadChildren()){
+            setIcon(createImageIcon(warnPath, "warnIcon"));
+        }
+        else if (node.isRoot()){
+            setIcon(createImageIcon(rootPath, "rootIcon"));
+        }
+        else if(!validated){
+            setIcon(createImageIcon(newPath, "newIcon"));
+        }
+        else if(node.isDocument() && node.hasBadChildren()){
+            setIcon(createImageIcon(infoPath, "infoIcon"));
+        }
+        else{
+            if(node.hasBadChildren()) {
+                setIcon(createImageIcon(infoGoodPath, "goodIcon"));
+            }
+            else{
+                setIcon(createImageIcon(goodPath, "goodIcon"));
+            }
+        }
+        
+        return this;
+    }
+
+    /**
+     * sets the icon for the handle of an expanded node.
+     *
+     * Note: this will only succeed if the current ui delegate is
+     * a BasicTreeUI otherwise it will do nothing.
+     *
+     * @param expanded
+     */
+    public void setExpandedIcon(Icon expanded) {
+        if (tree.getUI() instanceof BasicTreeUI) {
+            ((BasicTreeUI) tree.getUI()).setExpandedIcon(expanded);
+        }
+    }
+
+    /**
+     * sets the icon for the handel of a collapsed node.
+     *
+     * Note: this will only succeed if the current ui delegate is
+     * a BasicTreeUI otherwise it will do nothing.
+     *
+     * @param collapsed
+     */
+    public void setCollapsedIcon(Icon collapsed) {
+        if (tree.getUI() instanceof BasicTreeUI) {
+            ((BasicTreeUI) tree.getUI()).setCollapsedIcon(collapsed);
+        }
+    }
+
+    /** Returns an ImageIcon, or null if the path was invalid. */
+    protected ImageIcon createImageIcon(String path,
+            String description) {
+        java.net.URL imgURL = getClass().getResource(path);
+        if (imgURL != null) {
+            return new ImageIcon(imgURL, description);
+        } else {
+            System.err.println("Couldn't find file: " + path);
+            return null;
+        }
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/exceptions/NXvalidateException.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/exceptions/NXvalidateException.java
new file mode 100644
index 0000000..af39dc8
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/exceptions/NXvalidateException.java
@@ -0,0 +1,58 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXvalidateException.java
+ *
+ */
+
+package org.nexusformat.nxvalidate.exceptions;
+
+/**
+ *
+ * @author Stephen Rankin
+ */
+public class NXvalidateException extends Exception {
+
+    /**
+     * Creates a new instance of <code>NXvalidateException</code> without detail message.
+     */
+    public NXvalidateException() {
+    }
+
+
+    /**
+     * Constructs an instance of <code>NXvalidateException</code> with the specified detail message.
+     * @param msg the detail message.
+     */
+    public NXvalidateException(String msg) {
+        super(msg);
+    }
+
+    public NXvalidateException(String msg, Throwable cause) {
+        super(msg,cause);
+    }
+
+    public NXvalidateException(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/AllNeXusFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/AllNeXusFilter.java
new file mode 100644
index 0000000..11c80e7
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/AllNeXusFilter.java
@@ -0,0 +1,68 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * AllNeXusFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import org.nexusformat.nxvalidate.*;
+import java.io.File;
+import java.util.Vector;
+import javax.swing.filechooser.FileFilter;
+
+public class AllNeXusFilter extends FileFilter implements java.io.FileFilter {
+	private Vector<FileFilter> filters;
+	private String description;
+
+	public AllNeXusFilter() {
+		this.filters = new Vector<FileFilter>();
+		this.filters.add(new NeXusFilter());
+		this.filters.add(new HdfFilter());
+		this.filters.add(new XmlFilter());
+		
+		this.description = "";
+		int numFilters = this.filters.size();
+		for (int i = 0; i < numFilters; i++) {
+		    this.description += this.filters.get(i).getDescription();
+		    if ((i + 1) < numFilters) {
+		        this.description += ", ";
+		    }
+		}
+	}
+
+	@Override
+	public boolean accept(File pathname) {
+		for (FileFilter filter : this.filters) {
+			if (filter.accept(pathname)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+    @Override
+    public String getDescription() {
+        return this.description;
+    }
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/ExtensionFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/ExtensionFilter.java
new file mode 100644
index 0000000..9483ef6
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/ExtensionFilter.java
@@ -0,0 +1,63 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * ExtensionFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import java.io.File;
+import java.io.FileFilter;
+
+public class ExtensionFilter extends javax.swing.filechooser.FileFilter
+                                     implements FileFilter {
+	private String extension;
+	private boolean withDirectories;
+
+	ExtensionFilter(final String extension) {
+		this(extension, true);
+	}
+
+	ExtensionFilter(final String extension, final boolean withDirectories) {
+		if (extension == null) {
+			throw new Error("Cannot filter null extension");
+		}
+		if (extension.length() <= 0) {
+			throw new Error("Cannot filter empty extension");
+		}
+		this.extension = extension;
+		this.withDirectories = withDirectories;
+	}
+
+	/** {@inheritDoc} */
+	public final boolean accept(File pathname) {
+		if (pathname.isDirectory()) {
+			return this.withDirectories;
+		}
+		return (pathname.getName().endsWith(this.extension));
+	}
+
+    @Override
+    public String getDescription() {
+        return "*" + this.extension;
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/HdfFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/HdfFilter.java
new file mode 100644
index 0000000..e4bd406
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/HdfFilter.java
@@ -0,0 +1,60 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * HdfFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import java.io.File;
+import javax.swing.filechooser.FileFilter;
+
+public class HdfFilter extends FileFilter implements java.io.FileFilter {
+	public HdfFilter() {
+	}
+
+	@Override
+	public boolean accept(File pathname) {
+		if (pathname.isDirectory()) {
+			return true;
+		}
+		String name = pathname.getName();
+		if (name.endsWith(".hdf")) {
+			return true;
+		} else if (name.endsWith(".hdf5")) {
+			return true;
+		} else if (name.endsWith(".h5")) {
+			return true;
+		} else if (name.endsWith(".hdf4")) {
+			return true;
+		} else if (name.endsWith(".hd4")) {
+			return true;
+		}
+		return false;
+	}
+
+    @Override
+    public String getDescription() {
+        return "*.hdf, *.hdf4, *.hdf5, *.h4, *.h5";
+    }
+	
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/NXDLfilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/NXDLfilter.java
new file mode 100644
index 0000000..91e830c
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/NXDLfilter.java
@@ -0,0 +1,36 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NXDLfilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import org.nexusformat.nxvalidate.filter.ExtensionFilter;
+
+public class NXDLfilter extends ExtensionFilter {
+	public static final String EXTENSION = ".nxdl.xml";
+
+	public NXDLfilter() {
+		super(EXTENSION);
+	}
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/NeXusFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/NeXusFilter.java
new file mode 100644
index 0000000..1a06476
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/NeXusFilter.java
@@ -0,0 +1,39 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * NeXusFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import org.nexusformat.nxvalidate.filter.ExtensionFilter;
+import java.io.FileFilter;
+import java.util.Vector;
+
+public class NeXusFilter extends ExtensionFilter {
+	public static final String EXTENSION = ".nxs";
+	
+	public NeXusFilter() {
+		super(EXTENSION);
+	}
+
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/SchematronFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/SchematronFilter.java
new file mode 100644
index 0000000..6001b7b
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/SchematronFilter.java
@@ -0,0 +1,36 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * SchematronFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import org.nexusformat.nxvalidate.filter.ExtensionFilter;
+
+public class SchematronFilter extends ExtensionFilter {
+	public static final String EXTENSION = ".sch";
+
+	public SchematronFilter() {
+		super(EXTENSION);
+	}
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/XmlFilter.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/XmlFilter.java
new file mode 100644
index 0000000..8d83fc6
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/filter/XmlFilter.java
@@ -0,0 +1,36 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Nexus Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * XmlFilter.java
+ *
+ */
+package org.nexusformat.nxvalidate.filter;
+
+import org.nexusformat.nxvalidate.filter.ExtensionFilter;
+
+public class XmlFilter extends ExtensionFilter {
+	public static final String EXTENSION = ".xml";
+
+	public XmlFilter() {
+		super(EXTENSION);
+	}
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help.xml b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help.xml
new file mode 100644
index 0000000..9798ac0
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help.xml
@@ -0,0 +1,297 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+
+<!-- -->
+<book>
+  <bookinfo>
+    <title>NXvalidate 1.0alpha - NeXus File Validator Tool.</title> 
+ 
+  </bookinfo>
+  <chapter>
+    <title>Introduction</title>
+<screenshot>
+        <screeninfo>100x200x256</screeninfo>
+        <graphic fileref="nexus.png"></graphic>
+    </screenshot>
+    <section>
+      <title>What is NXvalidate for?</title>
+
+      <para>
+      NXvalidate is a tools that allows the validation of NeXus files for their
+      correctness with respect to content for a given data model. Each data
+      model is specified in a NeXus Definition Language (NXDL) file and contains
+      assertions that define what and what should not be in a NeXus file.
+      For example, a NeXus file with a definition called NXgisas (grazing
+      incidence small angle diffractometer GISAS for either x-ray or neutrons)
+      defines a metadata element (key value pair) called integral (total
+      integral monitor counts) whose data type is NX_INT (an integer). Knowing
+      the type allows validation of the value in the data to ensure it is the
+      appropriate data type.
+      </para>
+      <para>
+      NXvalidate can validate single data files or multiple data files, the
+      results are displayed in a friendly way and errors found in the file are
+      highlighted to the user.
+      </para>
+
+   </section>
+
+   <section>
+       <title>NXvalidate Main Features</title>
+
+       <orderedlist>
+          <listitem>Opens NeXus files in HDF4/5 or XML format. </listitem>
+          <listitem>Validates a single NeXus file against a user selected NXDL description. </listitem>
+          <listitem>Allows batch validation of a selection of NeXus files. </listitem>
+          <listitem>File structure displayed as a tree. </listitem>
+          <listitem>Metadata content of the file is displayed. </listitem>
+          <listitem>Results of the validation and the errors are displayed. </listitem>
+          <listitem>Results of the validation can be saved. </listitem>
+          <listitem>Integrated help and tutorial. </listitem>
+       </orderedlist>
+
+   </section>
+
+  <!--<section>
+       <title>TODO for V1.0</title>
+
+       <orderedlist>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       </orderedlist>
+
+   </section>-->
+
+  <!--<section>
+       <title>Future Development</title>
+
+       <orderedlist>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       <listitem></listitem>
+       </orderedlist>
+
+   </section>-->
+ 
+   <section>
+       <title>Requirements for the NXvalidate Application</title>
+       <para>NXvalidate GUI is written in the Java language using the Java 2
+             Standard Edition version 1.6 and should run on any J2SE 1.6 system.
+             This means it can be run on a wide range of platforms, without
+             requiring any recompilation. If you don't have Java installed,
+             or have an unsuitable version, you can obtain it for Linux, Solaris
+             and MS Windows from
+             <ulink url="http://java.sun.com/javase/downloads/index.jsp"><citetitle>Sun's web site</citetitle></ulink>.
+             J2SE Runtime Environments (sometimes called JVM or Java Virtual
+             Machines) for other platforms may be available from operating
+             system vendors; in particular NXvalidate is known to run (though
+             not currently exhaustively tested) on MacOS X
+             <ulink url="http://developer.apple.com/java/download/"><citetitle>(see here)</citetitle></ulink>.
+             Note Various open-source Java implementations (GNU's gij,
+             OpenJDK-based implementations) tend not to work well, if at all.
+
+             Unfortunately, the NXvalidate GUI requires NXconvert to convert the
+             NeXus files to a reduced XML format. NXconvert is a native binary
+             application which means that if the native binary is not available
+             for your system then the NXvalidate GUI will not work. NXconvert is
+             available from here
+             <ulink url="http://www.nexusformat.org/Download"><citetitle>NeXus Format Tools Download</citetitle></ulink>.
+
+       </para>
+   </section>
+
+   <section>
+       <title>Downloading the NXvalidate JAR File</title>
+       <para>The most convenient form for downloading is to pick up a single
+             installer Jar file containing the required classes:
+       </para>
+       <orderedlist>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-v1.0alpha.jar (MB)</citetitle></ulink> - NXvalidate application installer (no NXconvert)</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-v1.0alpha-win32.jar (MB)</citetitle></ulink> - NXvalidate application installer with Windows 32bit NXconvert.</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-v1.0alpha-win64.jar (MB)</citetitle></ulink> - NXvalidate application installer with Windows 64bit NXconvert.</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-v1.0alpha-lnx64.jar (MB)</citetitle></ulink> - NXvalidate application installer with Linux 64bit NXconvert.</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-v1.0alpha-lnx32.jar (MB)</citetitle></ulink> - NXvalidate application installer with Linux 32bit NXconvert.</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-doc-v1.0alpha.zip (MB)</citetitle></ulink> - Javadocs API documentation.</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-Tutorial.zip (MB)</citetitle></ulink> - this tutorial (also included as help in the application.)</listitem>
+       <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>NXvalidate-all-v1.0alpha-source.zip (MB)</citetitle></ulink> - the source code for NXvalidate.</listitem>
+       </orderedlist>
+       <para>(Note: if you try to download these directly your browser may say
+              something about a failed security check. Make sure that you save
+              it to a file, for instance by using shift-click in Netscape).
+       </para>
+   </section>
+
+   <section>
+        <title>Installing NXvalidate</title>
+        <para>Run the jar file file that you downloaded above with the java
+              command (J2SE Runtime Environment). In Windows this can be
+              achieved by double clicking on the file from Windows Explorer as
+              long as the J2SE Runtime Environment has been installed correctly.
+              For Linux systems you need to open a terminal and run the command
+              "java -jar NXvalidate-v1.0alpha-lnx64.jar" or "java -jar
+              NXvalidate-v1.0alpha-lnx32.jar" for 64 or 32 bit systems
+              respectively. Once you run the file follow the prompts on the
+              installation GUI to complete the installation.
+        </para>
+   </section>
+
+     <section>
+         <title>Building from Source.</title>
+
+         <para>TODO</para>
+     </section>
+
+     <section>
+
+        <title>Running the NXvalidate GUI</title>
+
+         <para>
+             If you selected to create menu and desktop items during installation
+             then on Windows you can select to start the application from the
+             Start menu, i.e. Start->All Programs->NXvalidate->NXvalidate. On
+             Linux you can select it from the Applications menu, i.e.
+             Applications->NXvalidate->NXvalidate. On both systems, if you
+             selected to install desktop icons then you will be double-click on
+             the icon to start the application.
+         </para>
+
+         <para>
+             
+         </para>
+
+         <para>Alternatively you can start NXvalidate from the command line
+               by moving to its installation directory and issuing the
+               command:
+         </para>
+
+         <orderedlist>
+             <listitem>java -jar NXvalidate-v1.0alpha.jar</listitem>
+         </orderedlist>
+
+     </section>
+
+     <section>
+
+         <title>Example</title>
+
+         <para>An example can be downloaded here:</para>
+
+         <orderedlist>
+         <listitem><ulink url="http://www.nexusformat.org/Download"><citetitle>example.zip (MB)</citetitle></ulink> - Example (used in this tutorial).</listitem>
+         </orderedlist>
+
+         <para>This example can be opened with NXvalidate.
+         </para>
+
+         <para>To use the example unzip the zip file which should give you
+               two files:
+         </para>
+
+         <orderedlist>
+             <listitem>NXmonopd.hdf - the data file.</listitem>
+             <listitem>NXmonopd.nxdl.xml - the NXDL definition file.</listitem>
+         </orderedlist>
+
+         <para>These two files can be opened with the NXvalidate GUI.</para>
+         
+
+<figure id="shot01">
+    <title>NXvalidate when first opened.</title>
+    <screenshot>
+        <!--<screeninfo>640x480x256</screeninfo>-->
+        <graphic fileref="NexusFileValidationTool_001.png"></graphic>
+    </screenshot>
+</figure>
+
+     </section>
+
+  </chapter>
+
+  <chapter>
+    <title>Tutorial</title>
+
+      <section>
+        <title>Opening NeXus and NXDL Files</title>
+
+        <para>Click on the File menu and then select Open Files <link linkend='shot02'>Figure 2.1
+              </link>
+        </para>
+
+<figure id="shot02">
+    <title>Open Files</title>
+<screenshot>
+    <!--<screeninfo>640x480x256</screeninfo>-->
+    <graphic fileref="NexusFileValidationTool_002.png"></graphic>
+</screenshot>
+</figure>
+
+<para>You should now see the window shown in here <link linkend='shot03'>
+      Figure 2.2</link>
+</para>
+
+<figure id="shot03">
+    <title>Open Files Window</title>
+<screenshot>
+    <!--<screeninfo>640x480x256</screeninfo>-->
+    <graphic fileref="OpenFiles_003.png"></graphic>
+</screenshot>
+</figure>
+
+        <para>We need to, as a minimum, select a NeXus file, but we can also
+              optionaly select a NXDL definition file at this point too. In this
+              case we shal select both files. To open the NeXus file click on
+              Open button next to the the "Load NXS" line which will show the Open
+              file dialog as shown in <link linkend='shot04'>Figure 2.3</link>.
+              You can use the dialog to open the NXmonopd.hdf file (or any
+              other NeXus file ). In a similar way you can select the
+              definition file (NXmonopd.nxdl.xml) by clicking on the Open button
+              next to the "Load NXDL" line.
+        </para>
+
+<figure id="shot04">
+    <title>Selecting the NeXus File</title>
+<screenshot>
+    <!--<screeninfo>640x480x256</screeninfo>-->
+    <graphic fileref="Open_004.png"></graphic>
+</screenshot>
+</figure>
+
+        <para>After selecting the two files you sould have something that looks
+              like <link linkend='shot05'>Figure 2.4</link>.
+        </para>
+
+<figure id="shot05">
+    <title>Selected NeXus Files</title>
+<screenshot>
+    <!--<screeninfo>640x480x256</screeninfo>-->
+    <graphic fileref="Open_Files_005.png"></graphic>
+</screenshot>
+</figure>
+
+        <para>Next click OK and you should see the window in <link linkend='shot06'>Figure 2.5</link>.</para>
+
+<figure id="shot06">
+    <title>A New Open NeXus File</title>
+<screenshot>
+    <!--<screeninfo>640x480x256</screeninfo>-->
+    <graphic fileref="NexusFileValidationTool_006.png"></graphic>
+</screenshot>
+</figure>     
+
+      </section>
+
+  </chapter>
+
+</book>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_001.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_001.png
new file mode 100644
index 0000000..5e82773
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_001.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_002.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_002.png
new file mode 100644
index 0000000..242f901
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_002.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_006.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_006.png
new file mode 100644
index 0000000..5b06bba
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/NexusFileValidationTool_006.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/Open Files_005.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/Open Files_005.png
new file mode 100644
index 0000000..1d71179
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/Open Files_005.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/OpenFiles_003.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/OpenFiles_003.png
new file mode 100644
index 0000000..cee7637
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/OpenFiles_003.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/Open_004.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/Open_004.png
new file mode 100644
index 0000000..d9ba93f
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/Open_004.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01.html
new file mode 100644
index 0000000..ef6cb21
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01.html
@@ -0,0 +1,16 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Chapter�1.�Introduction</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="prev" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="next" href="ch01s02. [...]
+      NXvalidate is a tools that allows the validation of NeXus files for their
+      correctness with respect to content for a given data model. Each data
+      model is specified in a NeXus Definition Language (NXDL) file and contains
+      assertions that define what and what should not be in a NeXus file.
+      For example, a NeXus file with a definition called NXgisas (grazing
+      incidence small angle diffractometer GISAS for either x-ray or neutrons)
+      defines a metadata element (key value pair) called integral (total
+      integral monitor counts) whose data type is NX_INT (an integer). Knowing
+      the type allows validation of the value in the data to ensure it is the
+      appropriate data type.
+      </p><p>
+      NXvalidate can validate single data files or multiple data files, the
+      results are displayed in a friendly way and errors found in the file are
+      highlighted to the user.
+      </p></div></div></body></html>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s02.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s02.html
new file mode 100644
index 0000000..1ae1d56
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s02.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>NXvalidate Main Features</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01.html" title="Chapter�1.�Introduction"><link rel="next" href="ch01s03.html" title="Requirements for the NXvalidata Applic [...]
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s03.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s03.html
new file mode 100644
index 0000000..bc71af3
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s03.html
@@ -0,0 +1,23 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Requirements for the NXvalidata Application</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01s02.html" title="NXvalidate Main Features"><link rel="next" href="ch01s04.html" title="Downloading the [...]
+             Standard Edition version 1.6 and should run on any J2SE 1.6 system.
+             This means it can be run on a wide range of platforms, without
+             requiring any recompilation. If you don't have Java installed,
+             or have an unsuitable version, you can obtain it for Linux, Solaris
+             and MS Windows from
+             <a class="ulink" href="http://java.sun.com/javase/downloads/index.jsp" target="_top"><em class="citetitle">Sun's web site</em></a>.
+             J2SE Runtime Environments (sometimes called JVM or Java Virtual
+             Machines) for other platforms may be available from operating
+             system vendors; in particular NXvalidata is known to run (though
+             not currently exhaustively tested) on MacOS X
+             <a class="ulink" href="http://developer.apple.com/java/download/" target="_top"><em class="citetitle">(see here)</em></a>.
+             Note Various open-source Java implementations (GNU's gij,
+             OpenJDK-based implementations) tend not to work well, if at all.
+
+             Unfortunately, the NXvalidate GUI requires NXconvert to convert the
+             NeXus files to a reduced XML format. NXconvert is a native binary
+             application which means that if the native binary is not available
+             for your system then the NXvalidate GUI will not work. NXconvert is
+             available from here
+             <a class="ulink" href="http://www.nexusformat.org/Download" target="_top"><em class="citetitle">NeXus Format Tools Download</em></a>.
+
+       </p></div></body></html>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s04.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s04.html
new file mode 100644
index 0000000..2c3d2a4
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s04.html
@@ -0,0 +1,6 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Downloading the NXvalidate JAR File</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01s03.html" title="Requirements for the NXvalidata Application"><link rel="next" href="ch01s05.html" title="Inst [...]
+             installer Jar file containing the required classes:
+       </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><a class="ulink" href="http://www.nexusformat.org/Download" target="_top"><em class="citetitle">NXvalidate-v1.0alpha.jar (MB)</em></a> - NXvalidate application installer (no NXconvert)</li><li class="listitem"><a class="ulink" href="http://www.nexusformat.org/Download" target="_top"><em class="citetitle">NXvalidate-v1.0alpha-win32.jar (MB)</em></a> - NXvalidate application installer with Windows 32b [...]
+              something about a failed security check. Make sure that you save
+              it to a file, for instance by using shift-click in Netscape).
+       </p></div></body></html>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s05.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s05.html
new file mode 100644
index 0000000..2363a8f
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s05.html
@@ -0,0 +1,10 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Installing NXvalidate</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01s04.html" title="Downloading the NXvalidate JAR File"><link rel="next" href="ch01s06.html" title="Building from Source."></h [...]
+              command (J2SE Runtime Environment). In Windows this can be
+              achieved by double clicking on the file from Windows Explorer as
+              long as the J2SE Runtime Environment has been installed correctly.
+              For Linux systems you need to open a terminal and run the command
+              "java -jar NXvalidate-v1.0alpha-lnx64.jar" or "java -jar
+              NXvalidate-v1.0alpha-lnx32.jar" for 64 or 32 bit systems
+              respectively. Once you run the file follow the prompts on the
+              installation GUI to complete the installation.
+        </p></div></body></html>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s06.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s06.html
new file mode 100644
index 0000000..fe10690
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s06.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Building from Source.</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01s05.html" title="Installing NXvalidate"><link rel="next" href="ch01s07.html" title="Running the NXvalidate GUI"></head><body [...]
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s07.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s07.html
new file mode 100644
index 0000000..4a24616
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s07.html
@@ -0,0 +1,14 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Running the NXvalidate GUI</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01s06.html" title="Building from Source."><link rel="next" href="ch01s08.html" title="Example"></head><body bgcolor="whit [...]
+             If you selected to create menu and desktop items during installation
+             then on Windows you can select to start the application from the
+             Start menu, i.e. Start->All Programs->NXvalidate->NXvalidate. On
+             Linux you can select it from the Applications menu, i.e.
+             Applications->NXvalidate->NXvalidate. On both systems, if you
+             selected to install desktop icons then you will be double-click on
+             the icon to start the application.
+         </p><p>
+             
+         </p><p>Alternatively you can start NXvalidate from the command line
+               by moving to its installation directory and issuing the
+               command:
+         </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">java -jar NXvalidate-v1.0alpha.jar</li></ol></div></div></body></html>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s08.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s08.html
new file mode 100644
index 0000000..149bbb8
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch01s08.html
@@ -0,0 +1,4 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Example</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="ch01.html" title="Chapter�1.�Introduction"><link rel="prev" href="ch01s07.html" title="Running the NXvalidate GUI"><link rel="next" href="ch02.html" title="Chapter�2.�Tutorial"></head><body bgcolor="white" te [...]
+         </p><p>To use the example unzip the zip file which should give you
+               two files:
+         </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">NXmonopd.hdf - the data file.</li><li class="listitem">NXmonopd.nxdl.xml - the NXDL definition file.</li></ol></div><p>These two files can be opened with the NXvalidate GUI.</p><div class="figure"><a name="shot01"></a><p class="title"><b>Figure�1.1.�NXvalidate when first opened.</b></p><div class="figure-contents"><div class="screenshot"><div><img src="NexusFileValidationTool_001.png" alt="NXvalid [...]
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch02.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch02.html
new file mode 100644
index 0000000..c7c0b34
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/ch02.html
@@ -0,0 +1,16 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Chapter�2.�Tutorial</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="up" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="prev" href="ch01s08.html" title="Example"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" a [...]
+              </a>
+        </p><div class="figure"><a name="shot02"></a><p class="title"><b>Figure�2.1.�Open Files</b></p><div class="figure-contents"><div class="screenshot"><div><img src="NexusFileValidationTool_002.png" alt="Open Files"></div></div></div></div><br class="figure-break"><p>You should now see the window shown in here <a class="link" href="ch02.html#shot03" title="Figure�2.2.�Open Files Window">
+      Figure 2.2</a>
+</p><div class="figure"><a name="shot03"></a><p class="title"><b>Figure�2.2.�Open Files Window</b></p><div class="figure-contents"><div class="screenshot"><div><img src="OpenFiles_003.png" alt="Open Files Window"></div></div></div></div><br class="figure-break"><p>We need to, as a minimum, select a NeXus file, but we can also
+              optionaly select a NXDL definition file at this point too. In this
+              case we shal select both files. To open the NeXus file click on
+              Open button next to the the "Load NXS" line which will show the Open
+              file dialog as shown in <a class="link" href="ch02.html#shot04" title="Figure�2.3.�Selecting the NeXus File">Figure 2.3</a>.
+              You can use the dialog to open the NXmonopd.hdf file (or any
+              other NeXus file ). In a similar way you can select the
+              definition file (NXmonopd.nxdl.xml) by clicking on the Open button
+              next to the "Load NXDL" line.
+        </p><div class="figure"><a name="shot04"></a><p class="title"><b>Figure�2.3.�Selecting the NeXus File</b></p><div class="figure-contents"><div class="screenshot"><div><img src="Open_004.png" alt="Selecting the NeXus File"></div></div></div></div><br class="figure-break"><p>After selecting the two files you sould have something that looks
+              like <a class="link" href="ch02.html#shot05" title="Figure�2.4.�Selected NeXus Files">Figure 2.4</a>.
+        </p><div class="figure"><a name="shot05"></a><p class="title"><b>Figure�2.4.�Selected NeXus Files</b></p><div class="figure-contents"><div class="screenshot"><div><img src="Open_Files_005.png" alt="Selected NeXus Files"></div></div></div></div><br class="figure-break"><p>Next click OK and you should see the window in <a class="link" href="ch02.html#shot06" title="Figure�2.5.�A New Open NeXus File">Figure 2.5</a>.</p><div class="figure"><a name="shot06"></a><p class="title"><b>Fig [...]
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/index.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/index.html
new file mode 100644
index 0000000..12409c5
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/index.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>NXvalidata 1.0alpha - NeXus File Validator Tool.</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="NXvalidata 1.0alpha - NeXus File Validator Tool."><link rel="next" href="ch01.html" title="Chapter�1.�Introduction"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="NXvalida [...]
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpidx.xml b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpidx.xml
new file mode 100644
index 0000000..b5f74ee
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpidx.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
+<!DOCTYPE index PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Index Version 1.0//EN" "http://java.sun.com/products/javahelp/index_1_0.dtd">
+<index version="1.0"/>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpmap.jhm b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpmap.jhm
new file mode 100644
index 0000000..8a2b624
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpmap.jhm
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
+<!DOCTYPE map PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN" "http://java.sun.com/products/javahelp/map_1_0.dtd">
+<map version="1.0">
+  <mapID target="id469492" url="index.html"/>
+  <mapID target="id469511" url="ch01.html"/>
+  <mapID target="id469536" url="ch01.html#id469536"/>
+  <mapID target="id439043" url="ch01s02.html"/>
+  <mapID target="id439090" url="ch01s03.html"/>
+  <mapID target="id438595" url="ch01s04.html"/>
+  <mapID target="id442277" url="ch01s05.html"/>
+  <mapID target="id442293" url="ch01s06.html"/>
+  <mapID target="id442304" url="ch01s07.html"/>
+  <mapID target="id438820" url="ch01s08.html"/>
+  <mapID target="shot01" url="ch01s08.html#shot01"/>
+  <mapID target="id439430" url="ch02.html"/>
+  <mapID target="id439436" url="ch02.html#id439436"/>
+  <mapID target="shot02" url="ch02.html#shot02"/>
+  <mapID target="shot03" url="ch02.html#shot03"/>
+  <mapID target="shot04" url="ch02.html#shot04"/>
+  <mapID target="shot05" url="ch02.html#shot05"/>
+  <mapID target="shot06" url="ch02.html#shot06"/>
+</map>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpset.hs b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpset.hs
new file mode 100644
index 0000000..9f971b2
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelpset.hs
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
+<!DOCTYPE helpset PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 1.0//EN" "http://java.sun.com/products/javahelp/helpset_1_0.dtd">
+<helpset version="1.0">
+  <title>NXvalidate 1.0alpha - NeXus File Validator Tool.</title>
+  <maps>
+    <homeID>top</homeID>
+    <mapref location="jhelpmap.jhm"/>
+  </maps>
+  <view>
+    <name>TOC</name>
+    <label>Table Of Contents</label>
+    <type>javax.help.TOCView</type>
+    <data>jhelptoc.xml</data>
+  </view>
+  <view>
+    <name>Index</name>
+    <label>Index</label>
+    <type>javax.help.IndexView</type>
+    <data>jhelpidx.xml</data>
+  </view>
+  <view>
+    <name>Search</name>
+    <label>Search</label>
+    <type>javax.help.SearchView</type>
+    <data engine="com.sun.java.help.search.DefaultSearchEngine">JavaHelpSearch</data>
+  </view>
+</helpset>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelptoc.xml b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelptoc.xml
new file mode 100644
index 0000000..9401d11
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/help/jhelptoc.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
+<!DOCTYPE toc PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 1.0//EN" "http://java.sun.com/products/javahelp/toc_1_0.dtd">
+<toc version="1.0">
+  <tocitem target="id469492" text="NXvalidate 1.0alpha - NeXus File Validator Tool.">
+    <tocitem target="id469511" text="Introduction">
+      <tocitem target="id469536" text="What is NXvalidate for?"/>
+      <tocitem target="id439043" text="NXvalidate Main Features"/>
+      <tocitem target="id439090" text="Requirements for the NXvalidata Application"/>
+      <tocitem target="id438595" text="Downloading the NXvalidate JAR File"/>
+      <tocitem target="id442277" text="Installing NXvalidate"/>
+      <tocitem target="id442293" text="Building from Source."/>
+      <tocitem target="id442304" text="Running the NXvalidate GUI"/>
+      <tocitem target="id438820" text="Example"/>
+    </tocitem>
+    <tocitem target="id439430" text="Tutorial">
+      <tocitem target="id439436" text="Opening"/>
+    </tocitem>
+  </tocitem>
+</toc>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_001.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_001.png
new file mode 100644
index 0000000..5e82773
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_001.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_002.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_002.png
new file mode 100644
index 0000000..242f901
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_002.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_006.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_006.png
new file mode 100644
index 0000000..5b06bba
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/NexusFileValidationTool_006.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/Open Files_005.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/Open Files_005.png
new file mode 100644
index 0000000..1d71179
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/Open Files_005.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/OpenFiles_003.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/OpenFiles_003.png
new file mode 100644
index 0000000..cee7637
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/OpenFiles_003.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/Open_004.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/Open_004.png
new file mode 100644
index 0000000..d9ba93f
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/Open_004.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/XSLTResolver.java b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/XSLTResolver.java
new file mode 100644
index 0000000..d6fb71c
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/XSLTResolver.java
@@ -0,0 +1,81 @@
+/* NeXus - Neutron & X-ray Common Data Format
+ *
+ * NeXus file validation GUI tool.
+ *
+ * Copyright (C) 2010 Stephen Rankin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For further information, see <http://www.nexusformat.org/>
+ *
+ * XSLTResolver.java
+ *
+ */
+package org.nexusformat.nxvalidate.resources;
+
+/**
+ * A copy from http://www.jezuk.co.uk/cgi-bin/view/jez?id=2260
+ * @author Stephen Rankin
+ */
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.stream.StreamSource;
+import java.io.InputStream;
+import java.net.URI;
+
+public class XSLTResolver implements URIResolver {
+
+    public Source resolve(String href, String base)
+            throws TransformerException {
+        String newHref = null;
+
+        if(href==null){
+            return null;
+        }
+        else if(href.equals("")){
+
+            try {
+                URI uri = new URI(base);
+                String[] path = uri.getPath().split("/");
+                newHref = path[path.length-1];
+                System.out.println("newHref: " + newHref);
+            } catch (URISyntaxException ex) {
+                Logger.getLogger(XSLTResolver.class.getName()).log(Level.SEVERE, null, ex);
+
+            }
+            return null;
+
+        }
+        
+        try
+        {
+            if(newHref != null){
+                InputStream is = XSLTResolver.class.getResourceAsStream(newHref);
+                return new StreamSource(is, newHref);
+            }
+            else{
+                InputStream is = XSLTResolver.class.getResourceAsStream(href);
+                return new StreamSource(is, href);
+            }
+        }
+        catch (Exception ex) {
+            throw new TransformerException(ex);
+        }
+    }
+}
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/about.html b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/about.html
new file mode 100644
index 0000000..36424ed
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/about.html
@@ -0,0 +1,31 @@
+<html>
+<body>
+    <h1>NXvalidate - NeXus file validation GUI tool.</h1>
+
+    <h2>NeXus - Neutron & X-ray Common Data Format</h2>
+
+    <h3>Copyright (C) 2010 NeXus Team</h3>
+
+    <h3>Authors: Stephen Rankin, Stuart Campbell, Peter Peterson & Freddie Akeroyd</h3>
+
+    <p>This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2 of the License, or (at your option) any later version.
+    </p>
+
+    <p>This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+    </p>
+
+    <p>You should have received a copy of the GNU Lesser General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+    </p>
+
+    <p>For further information, see <a href="http://www.nexusformat.org/">http://www.nexusformat.org</a></p>
+
+</body>
+</html>
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-caution.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-caution.png
new file mode 100644
index 0000000..ecdc0f9
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-caution.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-important.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-important.png
new file mode 100644
index 0000000..cc85f53
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-important.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-warning.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-warning.png
new file mode 100644
index 0000000..ecdc0f9
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/admon-warning.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/bad.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/bad.png
new file mode 100644
index 0000000..217e33b
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/bad.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/caution.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/caution.png
new file mode 100644
index 0000000..5b7809c
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/caution.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/checkmark.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/checkmark.png
new file mode 100644
index 0000000..38ed573
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/checkmark.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/dialog-warning.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/dialog-warning.png
new file mode 100644
index 0000000..219432c
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/dialog-warning.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/good.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/good.png
new file mode 100644
index 0000000..fb4362c
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/good.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/hand.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/hand.png
new file mode 100644
index 0000000..4da3c88
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/hand.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-.png
new file mode 100644
index 0000000..c14afc5
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-bad.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-bad.png
new file mode 100644
index 0000000..055c93d
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-bad.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-good.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-good.png
new file mode 100644
index 0000000..14455f0
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-good.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-warn.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-warn.png
new file mode 100644
index 0000000..9b08266
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info-warn.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info.png
new file mode 100644
index 0000000..6aed445
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/info.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/isis-background.bmp b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/isis-background.bmp
new file mode 100755
index 0000000..8ea1406
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/isis-background.bmp differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_abstract_expand.xsl b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_abstract_expand.xsl
new file mode 100644
index 0000000..9c98f73
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_abstract_expand.xsl
@@ -0,0 +1,296 @@
+<?xml version="1.0" encoding="UTF-8"?><?xar XSLT?>
+
+<!-- 
+     OVERVIEW - iso_abstract_expand.xsl
+     
+	    This is a preprocessor for ISO Schematron, which implements abstract patterns. 
+	    It also 
+	       	* extracts a particular schema using an ID, where there are multiple 
+	    schemas, such as when they are embedded in the same NVDL script 
+	    	* experimentally, allows parameter recognition and substitution inside
+	    	text as well as @context, @test, & @select.
+		
+		
+		This should be used after iso-dsdl-include.xsl and before the skeleton or
+		meta-stylesheet (e.g. iso-svrl.xsl) . It only requires XSLT 1.
+		 
+		Each kind of inclusion can be turned off (or on) on the command line.
+		 
+-->
+<!-- 
+  VERSION INFORMATION
+  2008-09-18 RJ
+  		* move out param test from iso:schema template  to work with XSLT 1. (Noah Fontes)
+  		
+  2008-07-29 RJ 
+  		* Create.  Pull out as distinct XSL in its own namespace from old iso_pre_pro.xsl
+  		* Put everything in private namespace
+  		* Rewrite replace_substring named template so that copyright is clear
+  	
+  2008-07-24 RJ
+       * correct abstract patterns so for correct names: param/@name and
+     param/@value
+    
+  2007-01-12  RJ 
+     * Use ISO namespace
+     * Use pattern/@id not  pattern/@name 
+     * Add Oliver Becker's suggests from old Schematron-love-in list for <copy> 
+     * Add XT -ism?
+  2003 RJ
+     * Original written for old namespace
+     * http://www.topologi.com/resources/iso-pre-pro.xsl
+-->	
+<!--
+ LEGAL INFORMATION
+ 
+ Copyright (c) 2000-2008 Rick Jelliffe and Academia Sinica Computing Center, Taiwan
+
+ This software is provided 'as-is', without any express or implied warranty. 
+ In no event will the authors be held liable for any damages arising from 
+ the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose, 
+ including commercial applications, and to alter it and redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not claim
+ that you wrote the original software. If you use this software in a product, 
+ an acknowledgment in the product documentation would be appreciated but is 
+ not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be 
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+-->
+<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" 
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+    xmlns:iso="http://purl.oclc.org/dsdl/schematron"  
+    xmlns:nvdl="http://purl.oclc.org/dsdl/nvdl"  
+    
+  
+    xmlns:iae="http://www.schematron.com/namespace/iae" 
+     
+      >
+	
+	<xslt:param name="schema-id"></xslt:param>
+	
+	
+	<!-- Driver for the mode -->
+	<xsl:template match="/">
+  		<xsl:apply-templates select="." mode="iae:go" />
+	</xsl:template> 
+	
+	
+	<!-- ================================================================================== -->
+	<!-- Normal processing rules                                                            -->
+	<!-- ================================================================================== -->
+	<!-- Output only the selected schema --> 
+	<xslt:template match="iso:schema" >
+	    <xsl:if test="string-length($schema-id) =0 or @id= $schema-id ">
+	    	<xslt:copy>
+				<xslt:copy-of select="@*" />
+				<xslt:apply-templates  mode="iae:go" /> 
+			</xslt:copy>
+		</xsl:if>
+	</xslt:template>
+	
+ 
+	<!-- Strip out any foreign elements above the Schematron schema .
+		-->
+	<xslt:template match="*[not(ancestor-or-self::iso:*)]"     mode="iae:go"  >
+	   <xslt:apply-templates  mode="iae:go" />
+	</xslt:template>
+	   
+	
+	<!-- ================================================================================== -->
+	<!-- Handle Schematron abstract pattern preprocessing                                   -->
+	<!-- abstract-to-real calls
+			do-pattern calls 
+				macro-expand calls 
+					multi-macro-expand
+						replace-substring                                                   -->
+	<!-- ================================================================================== -->
+	
+	<!--
+		Abstract patterns allow you to say, for example
+		
+		<pattern name="htmlTable" is-a="table">
+			<param name="row" value="html:tr"/>
+			<param name="cell" value="html:td" />
+			<param name="table" value="html:table" />
+		</pattern>
+		
+		For a good introduction, see Uche Ogbujii's article for IBM DeveloperWorks
+		"Discover the flexibility of Schematron abstract patterns"
+		  http://www-128.ibm.com/developerworks/xml/library/x-stron.html
+		However, note that ISO Schematron uses @name and @value attributes on
+		the iso:param element, and @id not @name on the pattern element.
+		
+	-->
+	
+	<!-- Suppress declarations of abstract patterns -->
+	<xslt:template match="iso:pattern[@abstract='true']"  mode="iae:go"  >
+		<xslt:comment>Suppressed abstract pattern <xslt:value-of select="@id"/> was here</xslt:comment>	
+	</xslt:template> 
+	
+	
+	<!-- Suppress uses of abstract patterns -->
+	<xslt:template match="iso:pattern[@is-a]"  mode="iae:go" >
+			
+		<xslt:comment>Start pattern based on abstract <xslt:value-of select="@is-a"/></xslt:comment>
+		
+		<xslt:call-template name="iae:abstract-to-real" >
+			<xslt:with-param name="caller" select="@id" />
+			<xslt:with-param name="is-a" select="@is-a" />
+		</xslt:call-template>
+			
+	</xslt:template>
+	 
+	 
+	
+	<!-- output everything else unchanged -->
+	<xslt:template match="*" priority="-1"  mode="iae:go" >
+	    <xslt:copy>
+			<xslt:copy-of select="@*" />
+			<xslt:apply-templates mode="iae:go"/> 
+		</xslt:copy>
+	</xslt:template>
+	
+	<!-- Templates for macro expansion of abstract patterns -->
+	<!-- Sets up the initial conditions for the recursive call -->
+	<xslt:template name="iae:macro-expand">
+		<xslt:param name="caller"/>
+		<xslt:param name="text" />
+		<xslt:call-template name="iae:multi-macro-expand">
+			<xslt:with-param name="caller" select="$caller"/>
+			<xslt:with-param name="text" select="$text"/>
+			<xslt:with-param name="paramNumber" select="1"/>
+		</xslt:call-template>
+		
+	</xslt:template>
+	
+	<!-- Template to replace the current parameter and then
+	   recurse to replace subsequent parameters. -->
+	    
+	<xslt:template name="iae:multi-macro-expand">
+		<xslt:param name="caller"/>
+		<xslt:param name="text" />
+		<xslt:param name="paramNumber" />
+
+		
+		<xslt:choose>
+			<xslt:when test="//iso:pattern[@id=$caller]/iso:param[ $paramNumber]">
+
+				<xslt:call-template name="iae:multi-macro-expand">
+					<xslt:with-param name="caller" select="$caller"/>	
+					<xslt:with-param name="paramNumber" select="$paramNumber + 1"/>		
+					<xslt:with-param name="text" >
+						<xslt:call-template name="iae:replace-substring">
+							<xslt:with-param name="original" select="$text"/>
+							<xslt:with-param name="substring"
+							select="concat('$', //iso:pattern[@id=$caller]/iso:param[ $paramNumber ]/@name)"/>
+							<xslt:with-param name="replacement"
+								select="//iso:pattern[@id=$caller]/iso:param[ $paramNumber ]/@value"/>			
+						</xslt:call-template>
+					</xslt:with-param>						
+				</xslt:call-template>
+			</xslt:when>
+			<xslt:otherwise><xslt:value-of select="$text" /></xslt:otherwise>		
+		
+		</xslt:choose>
+	</xslt:template>
+	
+	
+	<!-- generate the real pattern from an abstract pattern + parameters-->
+	<xslt:template name="iae:abstract-to-real" >
+		<xslt:param name="caller"/>
+		<xslt:param name="is-a" />
+		<xslt:for-each select="//iso:pattern[@id= $is-a]">
+		<xslt:copy>
+		
+		    <xslt:choose>
+		      <xslt:when test=" string-length( $caller ) = 0">
+		      <xslt:attribute name="id"><xslt:value-of select="concat( generate-id(.) , $is-a)" /></xslt:attribute>
+		      </xslt:when>
+		      <xslt:otherwise>
+				<xslt:attribute name="id"><xslt:value-of select="$caller" /></xslt:attribute>
+		      </xslt:otherwise>
+		    </xslt:choose> 
+			
+			<xslt:apply-templates select="*|text()" mode="iae:do-pattern"    >
+				<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
+			</xslt:apply-templates>	
+			
+		</xslt:copy>
+		</xslt:for-each>
+	</xslt:template>
+		
+	
+	<!-- Generate a non-abstract pattern -->
+	<xslt:template mode="iae:do-pattern" match="*">
+		<xslt:param name="caller"/>
+		<xslt:copy>
+			<xslt:for-each select="@*[name()='test' or name()='context' or name()='select']">
+				<xslt:attribute name="{name()}">
+				<xslt:call-template name="iae:macro-expand">
+						<xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
+						<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
+					</xslt:call-template>
+				</xslt:attribute>
+			</xslt:for-each>	
+			<xslt:copy-of select="@*[name()!='test'][name()!='context'][name()!='select']" />
+			<xsl:for-each select="node()">
+				<xsl:choose>
+				    <!-- Experiment: replace macros in text as well, to allow parameterized assertions
+				        and so on, without having to have spurious <iso:value-of> calls and multiple
+				        delimiting -->
+					<xsl:when test="self::text()">	
+						<xslt:call-template name="iae:macro-expand">
+							<xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
+							<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
+						</xslt:call-template>
+					</xsl:when>
+					<xsl:otherwise>
+						<xslt:apply-templates select="." mode="iae:do-pattern">
+							<xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
+						</xslt:apply-templates>		
+					</xsl:otherwise>
+				</xsl:choose>
+			</xsl:for-each>			
+		</xslt:copy>
+	</xslt:template>
+	
+	<!-- UTILITIES --> 
+	<!-- Simple version of replace-substring function -->
+	<xslt:template name="iae:replace-substring">
+		<xslt:param name="original" />    
+		<xslt:param name="substring" />   
+		<xslt:param name="replacement" select="''"/>
+		
+  <xsl:choose>
+    <xsl:when test="not($original)" /> 
+    <xsl:when test="not(string($substring))">
+      <xsl:value-of select="$original" />
+    </xsl:when> 
+        <xsl:when test="contains($original, $substring)">
+          <xsl:variable name="before" select="substring-before($original, $substring)" />
+          <xsl:variable name="after" select="substring-after($original, $substring)" />
+          
+          <xsl:value-of select="$before" />
+          <xsl:value-of select="$replacement" />
+          <!-- recursion -->
+          <xsl:call-template name="iae:replace-substring">
+            <xsl:with-param name="original" select="$after" />
+            <xsl:with-param name="substring" select="$substring" />
+            <xsl:with-param name="replacement" select="$replacement" /> 
+            </xsl:call-template>
+        </xsl:when>
+        <xsl:otherwise>
+        	<!-- no substitution -->
+        	<xsl:value-of select="$original" />
+        </xsl:otherwise>
+      </xsl:choose> 
+</xslt:template>
+
+</xslt:stylesheet>
\ No newline at end of file
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_dsdl_include.xsl b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_dsdl_include.xsl
new file mode 100644
index 0000000..c879e07
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_dsdl_include.xsl
@@ -0,0 +1,1160 @@
+<?xml version="1.0" encoding="UTF-8"?><?xar XSLT?>
+
+<!-- 
+     OVERVIEW : iso_dsdl_include.xsl
+     
+	    This is an inclusion preprocessor for the non-smart text inclusions
+	    of ISO DSDL. It handles 
+	    	<relax:extRef> for ISO RELAX NG
+	    	<sch:include>  for ISO Schematron and Schematron 1.n
+	    	<sch:extends>  for 2009 draft ISO Schematron
+	    	<xi:xinclude>  simple W3C XIncludes for ISO NVRL and DSRL 
+	    	<crdl:ref>     for draft ISO CRDL
+	    	<dtll:include> for draft ISO DTLL
+	    	<* @xlink:href> for simple W3C XLink 1.1 embedded links
+	    	
+		 
+		This should be the first in any chain of processing. It only requires
+		XSLT 1. Each kind of inclusion can be turned off (or on) on the command line.
+		
+		Ids in fragment identifiers or xpointers will be sought in the following
+		order:
+		    * @xml:id
+		    * id() for typed schemas (e.g. from DTD) [NOTE: XInclude does not support this]
+		    * untyped @id 
+		    
+	The proposed behaviour for the update to ISO Schematron has been implemented. If an
+	include points to an element with the same name as the parent, then that element's
+	contents will be included. This supports the merge style of inclusion.    
+	
+	When an inclusion is made, it is preceded by a PI with target DSDL_INCLUDE_START
+	and the href and closed by a PI with target DSDL_INCLUDE_START and the href. This is
+	to allow better location of problems, though only to the file level. 
+	
+	Limitations:
+	* No rebasing: relative paths will be interpreted based on the initial document's
+	path, not the including document. (Severe limitation!)
+	* No checking for circular references
+	* Not full xpointers: only ID matching
+	* <relax:include> not implemented 
+	* XInclude handling of xml:base and xml:lang not implemented   
+-->
+<!-- 
+  VERSION INFORMATION
+	2009-02-25 
+	* Update DSDL namespace to use schematron.com
+	* Tested with SAXON9, Xalan 2.7.1, IE7, 
+	* IE does not like multiple variables in same template with same name: rename.   
+	2008-09-18
+	* Remove new behaviour for include, because it conflicts with existing usage [KH]
+	* Add extends[@href] element with that merge functionality
+	* Generate PIs to notate source of inclusions for potential better diagnostics
+	
+	2008-09-16
+	* Fix for XSLT1
+	
+	2008-08-28
+	* New behaviour for schematron includes: if the pointed to element is the same as the current,
+	include the children.
+	
+	2008-08-20
+	* Fix bug: in XSLT1 cannot do $document/id('x') but need to use for-each
+	
+	2008-08-04
+	* Add support for inclusions in old namespace  
+	
+	2008-08-03
+	* Fix wrong param name include-relaxng & include-crdl (KH, PH)
+	* Allow inclusion of XSLT and XHTML (KH)
+	* Fix inclusion of fragments (KH)
+	
+	2008-07-25
+	* Add selectable input parameter
+	
+	2008-07-24  
+	* RJ New
+-->
+<!--
+	LEGAL INFORMATION
+	
+	Copyright (c) 2008 Rick Jelliffe 
+	
+	This software is provided 'as-is', without any express or implied warranty. 
+	In no event will the authors be held liable for any damages arising from 
+	the use of this software.
+	
+	Permission is granted to anyone to use this software for any purpose, 
+	including commercial applications, and to alter it and redistribute it freely,
+	subject to the following restrictions:
+	
+	1. The origin of this software must not be misrepresented; you must not claim
+	that you wrote the original software. If you use this software in a product, 
+	an acknowledgment in the product documentation would be appreciated but is 
+	not required.
+	
+	2. Altered source versions must be plainly marked as such, and must not be 
+	misrepresented as being the original software.
+	
+	3. This notice may not be removed or altered from any source distribution.
+-->
+<xslt:stylesheet version="1.0"
+	xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:iso="http://purl.oclc.org/dsdl/schematron"
+	xmlns:nvdl="http://purl.oclc.org/dsdl/nvdl"
+	xmlns:xhtml="http://www.w3.org/1999/xhtml"
+	xmlns:schold="http://www.ascc.net/xml/schematron"
+	xmlns:crdl="http://purl.oclc.org/dsdl/crepdl/ns/structure/1.0"
+	xmlns:xi="http://www.w3.org/2001/XInclude"
+	xmlns:dtll="http://www.jenitennison.com/datatypes"
+	xmlns:dsdl="http://www.schematron.com/namespace/dsdl"
+	xmlns:relax="http://relaxng.org/ns/structure/1.0"
+	xmlns:xlink="http://www.w3.org/1999/xlink">
+	<!-- Note: The URL for the dsdl namespace is not official -->
+
+
+	<xsl:param name="include-schematron">true</xsl:param>
+	<xsl:param name="include-crdl">true</xsl:param>
+	<xsl:param name="include-xinclude">true</xsl:param>
+	<xsl:param name="include-dtll">true</xsl:param>
+	<xsl:param name="include-relaxng">true</xsl:param>
+	<xsl:param name="include-xlink">true</xsl:param>
+
+	<xsl:template match="/">
+		<xsl:apply-templates select="." mode="dsdl:go" />
+	</xsl:template>
+
+	<!-- output everything else unchanged -->
+	<xslt:template match="node()" priority="-1" mode="dsdl:go">
+		<xslt:copy>
+			<xslt:copy-of select="@*" />
+			<xslt:apply-templates mode="dsdl:go" />
+		</xslt:copy>
+	</xslt:template>
+
+
+
+	<!-- =========================================================== -->
+	<!-- ISO/IEC 19757 - DSDL Document Schema Definition Languages   -->
+	<!-- Part 2 - Regular grammar-based validation - RELAX NG        -->
+	<!-- This only implements relax:extRef not relax:include which   -->
+	<!-- is complex.                                                 -->
+	<!-- =========================================================== -->
+	<xslt:template match="relax:extRef" mode="dsdl:go">
+
+
+		<!-- Insert subschema -->
+
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@href, '#')" />
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+		<xsl:choose>
+			<xsl:when test="not( $include-relaxng = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in RELAX NG extRef
+							include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+						<xslt:apply-templates mode="dsdl:go"
+							select="//*[@xml:id= $fragment-id ] | id( $fragment-id) | //*[@id= $fragment-id ]" />
+					</xslt:when>
+
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use a for-each so that the id() function works correctly on the external document -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select="$theDocument_1//*[@xml:id= $fragment-id ]        
+                  |  id( $fragment-id)          
+              | $theDocument_1//*[@id= $fragment-id ]" />
+							<xsl:if test="not($theFragment_1)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@href" />
+								</xsl:message>
+							</xsl:if>
+							<xsl:apply-templates
+								select=" $theFragment_1[1]" mode="dsdl:go" />
+						</xsl:for-each>
+					</xsl:when>
+
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/*" />
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<xsl:if test="not($theFragment_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to locate id attribute: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<xsl:apply-templates select="$theFragment_2 "
+							mode="dsdl:go" />
+					</xsl:otherwise>
+				</xsl:choose>
+
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xslt:template>
+
+
+
+	<!-- =========================================================== -->
+	<!-- ISO/IEC 19757 - DSDL Document Schema Definition Languages   -->
+	<!-- Part 3 - Rule-based validation - Schematron                 -->
+	<!-- =========================================================== -->
+
+
+	<!-- Extend the URI syntax to allow # references -->
+	<!-- Add experimental support for simple containers like  /xxx:xxx/iso:pattern to allow better includes -->
+	<xsl:template match="iso:include" mode="dsdl:go">
+
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@href, '#')" />
+
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+
+		<xsl:choose>
+			<xsl:when test="not( $include-schematron = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in Schematron include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+						<xslt:apply-templates mode="dsdl:go"
+							select="//iso:*[@xml:id= $fragment-id ] 
+              	 |id( $fragment-id)
+              	 | //iso:*[@id= $fragment-id ]" />
+					</xslt:when>
+
+					<!-- case where there is a fragment in another document (should be an iso: element) -->
+					<!-- There are three cases for includes with fragment:
+						0) No href file or no matching id - error!
+						1) REMOVED
+						
+						2) The linked-to element is sch:schema however the parent of the include
+						is not a schema. In this case, it is an error. (Actually, it should
+						be an error for other kinds of containment problems, but we won't
+						check for them in this version.)
+						
+						3) Otherwise, include the pointed-to element
+					-->
+
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="originalParent" select=".." />
+
+						<!-- case 0 -->
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use for-each to rebase id() to external document -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select=" $theDocument_1//iso:*[@xml:id= $fragment-id ] |
+              	 		id($fragment-id) |
+              			$theDocument_1//iso:*[@id= $fragment-id ]" />
+
+
+							<xsl:choose>
+								<!-- case 0 -->
+								<xsl:when test="not($theFragment_1)">
+									<xsl:message terminate="no">
+										<xsl:text>Unable to locate id attribute: </xsl:text>
+										<xsl:value-of select="@href" />
+									</xsl:message>
+								</xsl:when>
+
+
+								<!-- case 1 REMOVED -->
+
+								<!-- case 2 -->
+								<xsl:when
+									test=" $theFragment_1/self::iso:schema ">
+									<xsl:message>
+										Schema error: Use include to
+										include fragments, not a whole
+										schema
+									</xsl:message>
+								</xsl:when>
+
+								<!-- case 3 -->
+								<xsl:otherwise>
+									<xsl:apply-templates
+										select=" $theFragment_1[1]" mode="dsdl:go" />
+								</xsl:otherwise>
+							</xsl:choose>
+						</xsl:for-each>
+					</xsl:when>
+
+					<!-- Case where there is no ID so we include the whole document -->
+					<!-- Experimental addition: include fragments of children -->
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/iso:*" />
+						<xsl:variable name="theContainedFragments"
+							select="$theDocument_2/*/iso:* | $theDocument_2/*/xsl:* | $theDocument_2/*/xhtml:*" />
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<!-- There are three cases for includes:
+							0) No text specified- error!
+							
+							1) REMOVED
+							
+							2) The linked-to element is sch:schema however the parent of the include
+							is not a schema. In this case, it is an error. (Actually, it should
+							be an error for other kinds of containment problems, but we won't
+							check for them in this version.)
+							
+							3) Otherwise, include the pointed-to element
+						-->
+						<xsl:choose>
+							<!-- case 0 -->
+							<xsl:when
+								test="not($theFragment_2) and not ($theContainedFragments)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@href" />
+								</xsl:message>
+							</xsl:when>
+
+							<!-- case 1 removed -->
+
+							<!-- case 2 -->
+							<xsl:when
+								test=" $theFragment_2/self::iso:schema or $theContainedFragments/self::iso:schema">
+								<xsl:message>
+									Schema error: Use include to include
+									fragments, not a whole schema
+								</xsl:message>
+							</xsl:when>
+
+							<!-- If this were XLST 2, we could use  
+								if ($theFragment) then $theFragment else $theContainedFragments
+								here (thanks to KN)
+							-->
+							<!-- case 3 -->
+							<xsl:otherwise>
+								<xsl:apply-templates
+									select="$theFragment_2 " mode="dsdl:go" />
+							</xsl:otherwise>
+						</xsl:choose>
+					</xsl:otherwise>
+				</xsl:choose>
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xsl:template>
+
+
+	<!-- WARNING   sch:extends[@href] is experimental and non standard  -->
+	<!-- Basically, it adds the children of the selected element, not the element itself.  -->
+	<xsl:template match="iso:extends[@href]" mode="dsdl:go">
+
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@href, '#')" />
+
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+
+		<xsl:choose>
+			<xsl:when test="not( $include-schematron = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in Schematron include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+						<xslt:apply-templates mode="dsdl:go"
+							select="//iso:*[@xml:id= $fragment-id ]/* 
+              	 |id( $fragment-id)/*
+              	 | //iso:*[@id= $fragment-id ]/*" />
+					</xslt:when>
+
+					<!-- case where there is a fragment in another document (should be an iso: element) -->
+					<!-- There are three cases for includes with fragment:
+						0) No href file or no matching id - error!
+						1) REMOVED
+						
+						2) REMOVED
+						
+						3) Otherwise, include the pointed-to element
+					-->
+
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="originalParent" select=".." />
+
+						<!-- case 0 -->
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use for-each to rebase id() to external document -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select=" $theDocument_1//iso:*[@xml:id= $fragment-id ] |
+              	 		id($fragment-id) |
+              			$theDocument_1//iso:*[@id= $fragment-id ]" />
+
+
+							<xsl:choose>
+								<!-- case 0 -->
+								<xsl:when test="not($theFragment_1)">
+									<xsl:message terminate="no">
+										<xsl:text>Unable to locate id attribute: </xsl:text>
+										<xsl:value-of select="@href" />
+									</xsl:message>
+								</xsl:when>
+
+
+								<!-- case 1 REMOVED -->
+
+								<!-- case 2 REMOVED -->
+
+
+								<!-- case 3 -->
+								<xsl:otherwise>
+
+									<xsl:apply-templates
+										select=" $theFragment_1[1]/*" mode="dsdl:go" />
+								</xsl:otherwise>
+							</xsl:choose>
+						</xsl:for-each>
+					</xsl:when>
+
+					<!-- Case where there is no ID so we include the whole document -->
+					<!-- Experimental addition: include fragments of children -->
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/iso:*" />
+						<xsl:variable name="theContainedFragments"
+							select="$theDocument_2/*/iso:* | $theDocument_2/*/xsl:* | $theDocument_2/*/xhtml:*" />
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<!-- There are three cases for includes:
+							0) No text specified- error!
+							
+							1) REMOVED
+							
+							2) REMOVED
+							
+							3) Otherwise, include the pointed-to element
+						-->
+						<xsl:choose>
+							<!-- case 0 -->
+							<xsl:when
+								test="not($theFragment_2) and not ($theContainedFragments)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@href" />
+								</xsl:message>
+							</xsl:when>
+
+							<!-- case 1 removed -->
+
+							<!-- case 2 removed -->
+
+							<!-- If this were XLST 2, we could use  
+								if ($theFragment) then $theFragment else $theContainedFragments
+								here (thanks to KN)
+							-->
+							<!-- case 3 -->
+							<xsl:otherwise>
+								<xsl:apply-templates
+									select="$theFragment_2/* " mode="dsdl:go" />
+							</xsl:otherwise>
+						</xsl:choose>
+					</xsl:otherwise>
+				</xsl:choose>
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xsl:template>
+
+
+
+	<!-- =========================================================== -->
+	<!-- Handle Schematron 1.6 inclusions: clone of ISO code above   -->
+	<!-- =========================================================== -->
+
+
+	<!-- Extend the URI syntax to allow # references -->
+	<!-- Add experimental support for simple containers like  /xxx:xxx/schold:pattern to allow better includes -->
+	<xsl:template match="schold:include" mode="dsdl:go">
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@href, '#')" />
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+
+		<xsl:choose>
+			<xsl:when test="not( $include-schematron = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in Schematron include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+						<xslt:apply-templates mode="dsdl:go"
+							select="//schold:*[@xml:id= $fragment-id ] 
+              	 |id( $fragment-id)
+              	 | //schold:*[@id= $fragment-id ]" />
+					</xslt:when>
+
+					<!-- case where there is a fragment in another document (should be an iso: element) -->
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use for-each to rebase id() to $theDocument -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select=" $theDocument_1//schold:*[@xml:id= $fragment-id ] |
+              	id($fragment-id) |
+              	$theDocument_1//schold:*[@id= $fragment-id ]" />
+							<xsl:if
+								test=" $theFragment_1/self::schold:schema ">
+								<xsl:message>
+									Schema error: Use include to include
+									fragments, not a whole schema
+								</xsl:message>
+							</xsl:if>
+							<xsl:if test="not($theFragment_1)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@href" />
+								</xsl:message>
+							</xsl:if>
+							<xsl:apply-templates
+								select=" $theFragment_1[1]" mode="dsdl:go" />
+						</xsl:for-each>
+					</xsl:when>
+
+					<!-- Case where there is no ID so we include the whole document -->
+					<!-- Experimental addition: include fragments of children -->
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/iso:*" />
+						<xsl:variable name="theContainedFragments"
+							select="$theDocument_2/*/schold:* | $theDocument_2/*/xsl:* | $theDocument_2/*/xhtml:*" />
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<xsl:if
+							test=" $theFragment_2/self::schold:schema or $theContainedFragments/self::schold:schema">
+							<xsl:message>
+								Schema error: Use include to include
+								fragments, not a whole schema
+							</xsl:message>
+						</xsl:if>
+						<xsl:if
+							test="not($theFragment_2) and not ($theContainedFragments)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to locate id attribute: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- If this were XLST 2, we could use  
+							if ($theFragment) then $theFragment else $theContainedFragments
+							here (thanks to KN)
+						-->
+						<xsl:choose>
+							<xsl:when test=" $theFragment_2 ">
+								<xsl:apply-templates
+									select="$theFragment_2 " mode="dsdl:go" />
+							</xsl:when>
+							<xsl:otherwise>
+								<!-- WARNING!  EXPERIMENTAL! Use at your own risk. This may be discontinued! -->
+								<xsl:apply-templates
+									select="  $theContainedFragments " mode="dsdl:go" />
+							</xsl:otherwise>
+						</xsl:choose>
+					</xsl:otherwise>
+				</xsl:choose>
+
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xsl:template>
+	<!-- =========================================================== -->
+	<!-- ISO/IEC 19757 - DSDL Document Schema Definition Languages   -->
+	<!-- Part 5 - DataType Library Language - DTLL                   -->
+	<!-- Committee Draft  Experimental support only                  -->
+	<!-- The <include> element may well be replaced by XInclude in   -->
+	<!-- any final version.                                          -->
+	<!-- =========================================================== -->
+	<xslt:template match="dtll:include" mode="dsdl:go">
+		<!-- Insert subschema -->
+
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@href, '#')" />
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+		<xsl:choose>
+			<xsl:when test="not( $include-dtll = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in DTLL include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+						<xslt:apply-templates mode="dsdl:go"
+							select="//*[@xml:id= $fragment-id ] | id( $fragment-id) 
+              	| //*[@id= $fragment-id ]" />
+					</xslt:when>
+
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use for-each to rebase id() to $theDocument -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select="$theDocument_1//*[@xml:id= $fragment-id ]
+               | id( $fragment-id ) 
+               | $theDocument_1//*[@id= $fragment-id ]" />
+							<xsl:if test="not($theFragment_1)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@href" />
+								</xsl:message>
+							</xsl:if>
+							<xsl:apply-templates
+								select=" $theFragment_1[1]" mode="dsdl:go" />
+						</xsl:for-each>
+					</xsl:when>
+
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/*" />
+
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<xsl:if test="not($theFragment_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to locate id attribute: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<xsl:apply-templates select="$theFragment_2 "
+							mode="dsdl:go" />
+					</xsl:otherwise>
+				</xsl:choose>
+
+			</xsl:otherwise>
+		</xsl:choose>
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xslt:template>
+
+	<!-- =========================================================== -->
+	<!-- ISO/IEC 19757 - DSDL Document Schema Definition Languages   -->
+	<!-- Part 7 - Character Repertoire Description Language - CRDL   -->
+	<!-- Final Committee Draft 2008-01-11 Experimental support only  -->
+	<!-- =========================================================== -->
+	<xslt:template match="crdl:ref" mode="dsdl:go">
+		<!-- Insert subschema -->
+
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@href, '#')" />
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+		<xsl:choose>
+			<xsl:when test="not( $include-crdl = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in CRDL include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+
+						<xslt:apply-templates mode="dsdl:go"
+							select="//*[@xml:id= $fragment-id ] | id( $fragment-id)
+              	| //*[@id= $fragment-id ]" />
+					</xslt:when>
+
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use for-each to rebase id() to $theDocument -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select="$theDocument_1//*[@xml:id= $fragment-id ]
+               | id( $fragment-id )
+               | $theDocument_1//*[@id= $fragment-id ]" />
+
+							<xsl:if test="not($theFragment_1)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@href" />
+								</xsl:message>
+							</xsl:if>
+							<xsl:apply-templates select=" $theFragment_1 "
+								mode="dsdl:go" />
+						</xsl:for-each>
+					</xsl:when>
+
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/*" />
+
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+						<xsl:if test="not($theFragment_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to locate id attribute: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<xsl:apply-templates select="$theFragment_2"
+							mode="dsdl:go" />
+					</xsl:otherwise>
+				</xsl:choose>
+
+			</xsl:otherwise>
+		</xsl:choose>
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xslt:template>
+
+
+	<!-- =========================================================== -->
+	<!-- ISO/IEC 19757 - DSDL Document Schema Definition Languages   -->
+	<!-- Part 4 - Namespace-based Validation Dispatching Language - NVDL -->
+	<!-- Note: This does not include schemas referenced for          -->
+	<!-- validation, it merely handles any simple XIncludes          -->
+	<!-- =========================================================== -->
+	<!-- ISO/IEC 19757 - DSDL Document Schema Definition Languages   -->
+	<!-- Part 8 - Document Schema Renaming Language - DSRL           -->
+	<!-- Note: Final? Committee Draft   Experimental support only    -->
+	<!-- =========================================================== -->
+	<!-- XInclude support for id based references only, with 1 level -->
+	<!-- of fallback.                                                -->
+	<!-- =========================================================== -->
+
+	<xslt:template mode="dsdl:go"
+		match="xi:include[@href][not(@parseType) or @parseType ='xml']">
+		<!-- Simple inclusions only here -->
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+		<xsl:choose>
+			<xsl:when test="not( $include-xinclude = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:choose>
+
+					<xsl:when test="contains( @href, '#')">
+						<xsl:message terminate="yes">
+							Fatal error: Xinclude href contains fragment
+							identifier #
+						</xsl:message>
+					</xsl:when>
+
+
+					<xsl:when test="contains( @xpointer, '(')">
+						<xsl:message terminate="yes">
+							Fatal error: Sorry, this software only
+							supports simple ids in XInclude xpointers
+						</xsl:message>
+					</xsl:when>
+
+					<xsl:when
+						test="string-length( @href ) = 0 and string-length( @xpointer ) = 0">
+
+						<xsl:message terminate="yes">
+							Fatal Error: Impossible URL in XInclude
+							include
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when test="string-length( @href ) = 0">
+
+						<xslt:apply-templates mode="dsdl:go"
+							select="//*[@xml:id= current()/@xpointer  ] | id( @xpointer)
+              	| //*[@id= current()/@xpointer  ]" />
+					</xslt:when>
+
+					<xsl:when
+						test="string-length( @xpointer ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( @href,/ )" />
+						<xsl:variable name="theFragment_1"
+							select="$theDocument_1//*[@xml:id= current()/@xpointer  ]
+             
+              | $theDocument_1//*[@id= current()/@xpointer  ]" />
+						<!-- removed
+							| $theDocument_1/id( @xpointer)
+							because it requires rebasing in XSLT1 and that would mess up the use of current()
+						-->
+
+
+						<!-- Allow one level of fallback, to another XInclude -->
+						<xsl:if test="not($theDocument_1)">
+							<xsl:choose>
+								<xsl:when test="xi:fallback">
+									<xsl:variable name="theDocument_2"
+										select="document( xi:fallback[1]/xi:include[not(@parseType)
+                    	 or @parseType='xml']/@href,/ )" />
+									<xsl:variable name="theFragment_2"
+										select="$theDocument_2//*[@xml:id= current()/xi:fallback[1]/xi:include/@xpointer  ]
+              				| $theDocument_2//*[@id= current()/xi:fallback[1]/xi:include/@xpointer  ]" />
+									<!-- removed 
+										| $theDocument_2/id( xi:fallback[1]/xi:include/@xpointer)
+										because it id() would need rebasing in XSLT1 and that would mess up use of current()
+									-->
+
+									<xsl:if
+										test="not($theDocument_2)">
+
+										<xsl:message terminate="no">
+											<xsl:text>Unable to open referenced included file and fallback
+									file: </xsl:text>
+											<xsl:value-of
+												select="@href" />
+										</xsl:message>
+									</xsl:if>
+								</xsl:when>
+								<xsl:otherwise>
+									<xsl:message terminate="no">
+										<xsl:text>Unable to open referenced included file: </xsl:text>
+										<xsl:value-of select="@href" />
+									</xsl:message>
+								</xsl:otherwise>
+							</xsl:choose>
+						</xsl:if>
+						<xsl:apply-templates select=" $theFragment_1"
+							mode="dsdl:go" />
+					</xsl:when>
+
+					<!-- Document but no fragment specified -->
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_3"
+							select="document( @href,/ )" />
+						<xsl:variable name="theFragment_3"
+							select="$theDocument_3/*" />
+
+						<xsl:if test="not($theDocument_3)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@href" />
+							</xsl:message>
+						</xsl:if>
+
+						<xsl:apply-templates select="$theFragment_3 "
+							mode="dsdl:go" />
+					</xsl:otherwise>
+				</xsl:choose>
+
+			</xsl:otherwise>
+		</xsl:choose>
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@href" />
+		</xsl:processing-instruction>
+	</xslt:template>
+
+	<!-- =========================================================== -->
+	<!-- W3C XLink 1.1 embedded simple links                        -->
+	<!-- =========================================================== -->
+	<xslt:template
+		match="*[@xlink:href][not(parent::*[@xlink:type='complex'])]
+	           [not(@xlink:type) or (@xlink:type='simple')]
+	           [@xlink:show='embed']
+	           [not(@xlink:actuate) or (@xlink:actuate='onLoad')]"
+		mode="dsdl:go" priority="1">
+
+		<xsl:variable name="document-uri"
+			select="substring-before(concat(@xlink:href,'#'), '#')" />
+		<xsl:variable name="fragment-id"
+			select="substring-after(@xlink:href, '#')" />
+		<xsl:processing-instruction name="DSDL_INCLUDE_START">
+			<xsl:value-of select="@xlink:href" />
+		</xsl:processing-instruction>
+		<xsl:choose>
+			<xsl:when test="not( $include-xlink = 'true' )">
+				<xslt:copy>
+					<xslt:copy-of select="@*" />
+					<xslt:apply-templates mode="dsdl:go" />
+				</xslt:copy>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:choose>
+
+					<xsl:when
+						test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0">
+						<xsl:message>
+							Error: Impossible URL in XLink embedding
+							link
+						</xsl:message>
+					</xsl:when>
+
+					<!-- this case is when there is in embedded schema in the same document elsewhere -->
+					<xslt:when
+						test="string-length( $document-uri ) = 0">
+						<xslt:apply-templates mode="dsdl:go"
+							select="//*[@xml:id= $fragment-id ] | id( $fragment-id) 
+              	| //*[@id= $fragment-id ]" />
+					</xslt:when>
+
+					<xsl:when
+						test="string-length( $fragment-id ) > 0">
+						<xsl:variable name="theDocument_1"
+							select="document( $document-uri,/ )" />
+						<xsl:if test="not($theDocument_1)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@xlink:href" />
+							</xsl:message>
+						</xsl:if>
+						<!-- use for-each to rebase id() to $theDocument -->
+						<xsl:for-each select="$theDocument_1">
+							<xsl:variable name="theFragment_1"
+								select="$theDocument_1//*[@xml:id= $fragment-id ]
+               | id( $fragment-id ) 
+               | $theDocument_1//*[@id= $fragment-id ]" />
+							<xsl:if test="not($theFragment_1)">
+								<xsl:message terminate="no">
+									<xsl:text>Unable to locate id attribute: </xsl:text>
+									<xsl:value-of select="@xlink:href" />
+								</xsl:message>
+							</xsl:if>
+							<xsl:apply-templates
+								select=" $theFragment_1[1]" mode="dsdl:go" />
+						</xsl:for-each>
+					</xsl:when>
+
+					<xsl:otherwise>
+						<xsl:variable name="theDocument_2"
+							select="document( $document-uri,/ )" />
+						<xsl:variable name="theFragment_2"
+							select="$theDocument_2/*" />
+
+						<xsl:if test="not($theDocument_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to open referenced included file: </xsl:text>
+								<xsl:value-of select="@xlink:href" />
+							</xsl:message>
+						</xsl:if>
+
+						<xsl:if test="not($theFragment_2)">
+							<xsl:message terminate="no">
+								<xsl:text>Unable to locate id attribute: </xsl:text>
+								<xsl:value-of select="@xlink:href" />
+							</xsl:message>
+						</xsl:if>
+						<xsl:apply-templates select="$theFragment_2 "
+							mode="dsdl:go" />
+					</xsl:otherwise>
+				</xsl:choose>
+
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<xsl:processing-instruction name="DSDL_INCLUDE_END">
+			<xsl:value-of select="@xlink:href" />
+		</xsl:processing-instruction>
+	</xslt:template>
+
+
+</xslt:stylesheet>
\ No newline at end of file
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_schematron_message_xslt2.xsl b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_schematron_message_xslt2.xsl
new file mode 100644
index 0000000..36082cc
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_schematron_message_xslt2.xsl
@@ -0,0 +1,55 @@
+<?xml version="1.0" ?><?xar XSLT?>
+<!-- Implmentation for the Schematron XML Schema Language.
+	http://www.ascc.net/xml/resource/schematron/schematron.html
+ 
+ Copyright (c) 2000,2001 Rick Jelliffe and Academia Sinica Computing Center, Taiwan
+
+ This software is provided 'as-is', without any express or implied warranty. 
+ In no event will the authors be held liable for any damages arising from 
+ the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose, 
+ including commercial applications, and to alter it and redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not claim
+ that you wrote the original software. If you use this software in a product, 
+ an acknowledgment in the product documentation would be appreciated but is 
+ not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be 
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+-->
+
+<!-- Schematron message -->
+
+<xsl:stylesheet
+   version="2.0"
+   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+   xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias">
+
+<xsl:import href="iso_schematron_skeleton_for_saxon.xsl"/>
+
+<xsl:template name="process-prolog">
+   <axsl:output method="text" />
+</xsl:template>
+
+<!-- use default rule for process-root:  copy contens / ignore title -->
+<!-- use default rule for process-pattern: ignore name and see -->
+<!-- use default rule for process-name:  output name -->
+<!-- use default rule for process-assert and process-report:
+     call process-message -->
+
+<xsl:template name="process-message">
+   <xsl:param name="pattern" />
+   <xsl:param name="role" />
+   <axsl:message>
+      <xsl:apply-templates mode="text"  
+      /> (<xsl:value-of select="$pattern" />
+      <xsl:if test="$role"> / <xsl:value-of select="$role" />
+      </xsl:if>)</axsl:message>
+</xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_schematron_skeleton_for_saxon.xsl b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_schematron_skeleton_for_saxon.xsl
new file mode 100644
index 0000000..c915054
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_schematron_skeleton_for_saxon.xsl
@@ -0,0 +1,2244 @@
+<?xml version="1.0"?><?xar XSLT?>
+
+<!-- 
+   OVERVIEW
+   
+   ASCC/Schematron.com Skeleton Module for ISO Schematron (for XSLT2 systems)
+   
+   ISO Schematron is a language for making assertion about the presence or absense
+   of patterns in XML documents. It is typically used for as a schema language, or
+   to augment existing schema languages, and to check business rules. It is very
+   powerful, yet quite simple: a developer only need know XPath and about five other
+   elements.
+   
+   This is an open source implementation of ISO Schematron in XSLT. Although ISO does
+   not allow reference implementations which might compete with the text of the
+   standard, this code has been compiled by Rick Jelliffe, inventor of Schematron
+   and editor of the ISO standard; so developers can certainly use it as an 
+   unofficial reference implementation for clarification. 
+   
+   This implementation is based on one by Oliver Becker. API documentation is 
+   available separately; try www.schematron.com for this. Funding for this
+   stylesheet over the years has come from Topologi Pty. Ltd., Geotempo Ltd.,
+   and ASCC, Tapei.
+   
+   There are two versions of this skeleton: one is tailored for XSLT1 processors
+   and the other is tailored for XSLT2 processors. Future versions of the
+   XSLT2 skeleton may support more features than that the XSLT 1 skeleton.
+-->
+<!--
+   TIPS
+      
+   A tip for new users of Schematron: make your assertions contain positive messages
+   about what is expected, rather than error messages. For example, use the form
+   "An X should have a Y, because Z". 
+   
+   Another tip is that Schematron provides an
+   element <iso:ns> for declaring the namespaces and prefixes used in Xpaths in 
+   attribute values; it does not extend the XML Namespaces mechanism: if a name
+   in an XPath has a prefix, there must be an <iso:ns> element for that prefix; if
+   a name in an XPath does not have a prefix, it is always in no namespace.
+   
+   A tip for implementers of Schematron, either using this API or re-implementing it:
+   make the value of the diagnostics, flags and richer features available if possible;
+   Schematron has many of the optional richer features which, if implemented, provide
+   a compelling alternative approach to validation and business-rules checking compared
+   to other schema languages and programs. 
+   
+   If you create your own meta-stylesheet to override this one, it is a
+   good idea to have both in the same directory and to run the stylesheet
+   from that directory, as many XSLT implementations have ideosyncratic
+   handling of URLs: keep it simple.
+-->
+ 
+
+<!--
+  INVOCATION INFORMATION
+  
+  The following parameters are available
+  
+    phase           NMTOKEN | "#ALL" (default) Select the phase for validation
+    allow-foreign   "true" | "false" (default)   Pass non-Schematron elements to the generated stylesheet 
+    sch.exslt.imports semi-colon delimited string of filenames for some EXSLT implementations  
+    message-newline "true" (default) | "false"   Generate an extra newline at the end of messages 
+    debug	    "true" | "false" (default)  Debug mode lets compilation continue despite problems
+    attributes "true" | "false"  (Autodetecting) Use only when the schema has no attributes as the context nodes
+    only-child-elements "true" | "false" (Autodetecting) Use only when the schema has no comments
+    or PI  as the context nodes
+    langCode		ISO language code      language for skeleton errors, if available
+  
+  The following parameters can be specified as Schematron variables in diagnostics, assertions and so on.
+    fileNameParameter string	  
+    fileDirParameter string				
+    archiveNameParameter string	  In case of ZIP files
+    archiveDirParameter string	  In case of ZIP files	 
+    
+ Experimental: USE AT YOUR OWN RISK   
+    visit-text "true" "false"   Also visist text nodes for context. WARNING: NON_STARDARD.
+    select-contents '' | 'key' | '//'   Select different implementation strategies
+ 
+ Conventions: Meta-stylesheets that override this may use the following parameters
+    generate-paths=true|false   generate the @location attribute with XPaths
+    full-path-notation = 1|2|3  select the notation for the full paths: 1=computer, 2=human, 3=obsolescent
+    diagnose= yes | no    Add the diagnostics to the assertion test in reports
+    terminate= yes | no   Terminate on the first failed assertion or successful report
+ 
+-->
+
+<!-- 
+  XSLT VERSION SUPPORT
+
+  XSLT 1:
+     A schema using the standard XSLT 1 query binding will have a /schema/@queryBinding='xslt' or 
+     nothing.
+
+       * Note: XT does not implement key() and will die if given it. 
+       * Add all formal parameters to default templates
+       * Fix missing apply-templates from process-ns and add params back
+
+  EXSLT:  Experimental support
+     A schema using the EXSLT query binding will have a /schema/@queryBinding='exslt'.
+     It is built on XSLT 1. After experience is gained, this binding is expected to be 
+     formalized as part of ISO Schematron, which currently reserves the "exslt" name for this purpose.
+
+     Some EXSLT engines have the extra functions built-in. For these, there is no need to
+     provide library locations. For engines that require the functions, either hard code
+     them in this script or provide them on the command-line argument.
+      
+  XSLT 2:   Experimental support
+     A schema using the XSLT 2 query binding will have a /schema/@queryBinding='xslt2'.
+     This binding is expected to be formalized as part of ISO
+     Schematron, which currently reserves the "xslt2" name for this purpose.
+     The xsl:import-schema, xsl:key and xsl:function elements are allowed as top elements. 
+     
+  XPATH:    Experimental support
+     A schema using the XPATH query binding will have a /schema/@queryBinding='xpath'.
+     It can run with XSLT 1 and is a strict superset of default ISO Schematron. After
+     experience is gained, this binding is expected to be formalized as part of ISO
+     Schematron, which currently reserves the "xpath" name for this purpose.
+
+     The intent of this query binding is to support minimal non-XSLT implementations of 
+     Schematron that use simple XPath APIs. These not only have fewer functions available
+     than the XSLT version of XPath, but some of them do not support variables. 
+     Consequently, in this binding, the <let> element and command-line variables passed
+     to the schema should not be used? 
+     The xsl:import-schema element is not allowed.
+     
+-->
+<!--
+   PROCESS INFORMATION
+   
+   This stylesheet compiles a Schematron schema (*.sch) into XSLT code (*.xsl). 
+   The generated XSLT code can then be run against an XML file (*.xml, etc) and
+   will produce validation results.
+   
+   The output of validation results is performed using named templates (process-*). 
+   These can be overridden easily by making a new XSLT stylesheet that imports this 
+   stylesheet but has its own version of the relevant process-* templates. Several
+   of these invoking stylesheets are available: "iso_svrl.xsl", for example generates
+   ISO Schematron Validation Report Language format results.
+   
+   In this version of the stylesheet, the ISO feature called "abstract patterns" is
+   implemented using macro processing: a prior XSLT stage to which converts uses
+   of abstract patterns into normal patterns. If you do not use abstract patterns,
+   it is not necessary to preprocess the schema.
+   
+   To summarize, a basic process flow for some commandline processor is like this:
+     XSLT -input=xxx.sch  -output=xxx.xsl  -stylesheet=iso_schematron_skeleton.xsl
+     XSLT -input=document.xml  -output=xxx-document.results  -stylesheet=xxx.xsl
+   
+   iso_svrl.xslt is an implementation of Schematron that can use this skeleton and
+   generate ISO SVRL reports. A process flow for some commandline processor would
+   be like this:
+     XSLT -input=xxx.sch  -output=xxx.xsl  -stylesheet=iso_svrl.xsl
+     XSLT -input=document.xml  -output=xxx-document.results  -stylesheet=xxx.xsl
+     
+   It is not impossible that ultimately a third stage, to handle macro-preprocessing
+   and inclusion, might be necessary. (The trade-off is in making this XSLT more
+   complex compared to making the outer process more complex.)
+             
+  This version has been developed to work with 
+     Saxon 8 
+  For versions for XSLT 1 processors, see www.xml.com
+
+ Please note that if you are using SAXON and JAXP, then you should use 
+  System.setProperty("javax.xml.transform.TransformerFactory",
+                          "net.sf.saxon.TransformerFactoryImpl");
+ rather than 
+  System.setProperty("javax.xml.xpath.TransformerFactory",
+                           "net.sf.saxon.TransformerFactoryImpl");
+ which is does not work, at least for the versions of SAXON we tried.
+-->
+<!--
+ LEGAL INFORMATION
+ 
+ Copyright (c) 2000-2008 Rick Jelliffe and Academia Sinica Computing Center, Taiwan
+
+ This software is provided 'as-is', without any express or implied warranty. 
+ In no event will the authors be held liable for any damages arising from 
+ the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose, 
+ including commercial applications, and to alter it and redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not claim
+ that you wrote the original software. If you use this software in a product, 
+ an acknowledgment in the product documentation would be appreciated but is 
+ not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be 
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+-->
+<!--
+  VERSION INFORMATION
+     2009-05-10 RJ
+     	* Fix up incorrect use of tunnel
+     2009-02-25 RJ
+        * Fix up variable names so none are used twice in same template
+      2009-02-19
+        * RJ add experimental support for pattern/@documents 
+        This takes an XPath that returns a sequence of strings, treats them as 
+        relative URI references, and goes through these. It may need to be expanded
+        to allow absolute paths.
+    2008-09-19 RJ
+        * Add mode schematron-select-full-path and param full-path-notation 
+        
+   2008-08-19
+   		* RJ Add experimental property element.
+   		This acts like the diagnostics element. An attribute rule/@properties,
+   		assert/@properties and report/@properties can contain a list of ids
+   		which reference a /schema/proporties/property/@id. This is a property
+   		which will be carried over to the output, eg SVRL. It can have @name,
+   		and the value is @value or the contents. Properties on rules are 
+   		properties regardless of validation: they should apply to the subject
+   		element. Properties on asserts and reports only make it through in the
+   		negative case, at the moment, so they are really just a place to hold
+   		structured info, eg. for diagnostics. The properties mechanism addresses
+   		a bother with Schematron, that you have to post-process the document to
+    	get any kind of structured data that might be nice in the output report. 
+   		 
+   		
+   2008-08-14
+   		* RJ move all messages into localization strings, add langCode parameter, 
+   		named template to call external file in same directory as this xslt.
+   		The file should be called sch-message-$langCode.xhtml ($langCode example "en")
+  
+   2008-08-11
+   		* TT report/@flag was missing
+   2008-08-06
+   		* TT Top-level lets need to be implemented using xsl:param not xsl:variable
+   		* TT xsl:param/@select must have XPath or not be specified
+   		
+   2008-08-04 
+   		* RJ add saxon namespace to output to allow extension functions
+   Version: 2008-07-28
+   		* KH schematron-get-full-path-3 has [index] even on top step
+   Version: 2008-07-24
+   		* RJ clean out commented out namespace handling code 
+   		* RJ allow schema/@queryBinding='xpath2' and warn if variables are
+   		used
+   		
+   Version: 2008-07-14 update for XSLT2 and inclusion experiments
+   		* RJ Clean up zero-length fragment test on include
+   		* RJ Add experimental support for include containers
+   		* RJ Add support for xsl:import-schema (request Paul Hermans)
+   		* RJ Add support for xsl:function
+   		* RJ For path generation, test for //iso:schema not just /iso:schema, for potential embedded Schematron support
+   		* RJ Don't generate double error messages for old namespace elements
+   		* RJ Experimental iso:rule/iso:title just kept as comment (bigger request Uche Ogbuji)
+   		* RJ Fix bug that prevented including patterns in this (report Roger
+   	Costello)
+   Version: 2007-10-17
+     Forked out version just to support SAXON 8 and potentially other XSLT2 processors.
+       * RJ use xsl:namespace element
+       * RJ use schold as namespace for old schematron, to prevent SAXON complaining
+         when validating the Schematron schema for Schematron
+       * RJ fix FULL-PATH for attributes
+
+   Version: 2007-07-19
+     Accept most changes in David Carlisle's fork, but continue as XSLT1 script: 
+    	http://dpcarlisle.blogspot.com/search/label/schematron
+    	* DPC Remove "optimize" parameter
+    	* DPC Add autodetecting optimize parameter attribute to skip checking attribute
+    	context
+    	* DPC Add autodetecting optimize parameter only-child-elements turn off checking for 
+    	comments and PIs
+    	* DPC (Experimental: NON_STANDARD DANGER!) Add param visit-text to viist text
+    	nodes too for context 
+    	* DPC Fix inclusion syntax to allow #
+    	* DPC Priorities count up from 1000 not down from 4000 to allow more rules
+        * RJ Add new template for titles of schemas, with existing behaviour.  
+        Override process-schema-title for custom processing of title
+    		
+    
+   Version: 2007-04-04
+   	* RJ debug mode param
+	* RJ alter mixed test to only test mixed branches, so the same document
+	could have old and new namespaces schemas in it, but each schema must
+	be distinct, just so as not to overconstrain things.
+   	* KH zero-length include/@href is fatal error, but allow debug mode
+	* SB add hint on SAXON and JAXP
+	* DC generate-full-path-1 generates XLST1 code by default
+   Version: 2007-03-05
+      	* AS Typo for EXSLT randome, improve comment
+      	* KH get-schematron-full-path-2 needs to apply to attributes too
+      	* DP document policy on extensions better
+      	* DC use copy-of not copy for foreign elements
+      	* DC add generate-path-2
+      	* DC don't try to apply templates to attribute axis on attribute nodes, to
+      	stop SAXON warning.
+      	* RJ improve reporting of typos 
+   
+   Version: 2007-02-08
+   		* KH Schematron fullpath implementation: @* handled twice and / missing
+   		* KH Change stylesheetbody from named template to mode to allow implementers more flexibility.
+   		  Move process-ns to outside the stylesheet body.
+   		* DP, FG, fix handling of xslt:key
+   		* FG no iso:title/@class
+   		* Experimental optimization 'visit-no-attributes'
+   		* KH Experimental added schematron-get-full-path-2 which gives prefixed version for humans
+ 		* DC Move stylesheet/@version generation to after namespace handling
+ 		* DC, FG EXSLT namespace handling code
+ 		* FG add ref and commented code from FG's page on namespaces
+ 		* Start adding normalize-space() to parameter code
+ 		* Add a space between diagnostics
+   		   		 
+   Version: 2007-01-22
+   	* DP change = ($start) to = $start and =($phase) to =$phase 
+   	to run under Saxon 8.8j
+	* FG better title section using ( @id | iso:title)[last()]
+	* Default query language binding is "xslt" not "xslt1"
+  
+   Version: 2007-01-19
+   		* Simplify message newline code
+   		* Remove termination and xpath appending to message options: 
+   		   factor out as  iso_schematron_terminator.xsl
+   		* Comment out XSLT2 namespace fix temporarily
+  
+   Version: 2007-01-18 (First beta candidate for comment)
+          * DC remove xml:space="preserve"
+          * FG improve comment on import statement
+          * DC improve comments on invocation section
+          * Add exploratory support for iso:schema[@queryBinding='xpath']
+             by allowing it and warning as lets are found
+          * Be strict about queryBinding spelling errors
+          * Extra comments on the different queryBindings
+          * KH Add option "message-paths" to generate XPath from output 
+          * KH Add option "terminate" to halt with an error after the first assertion
+          * KH refactor paths in schematron-full-path
+          * Improve (?) namespace handling: no dummy attributes for prefix "xsl" generated
+   
+   Version: 2007-01-15
+          * FG fix for calling templates
+          * Add formal parameters to default templates: may help XSLT 2
+          * Fix get-schematron-full-path
+          * Include skeleton1-6 is commented out by default
+
+   Version:2007-01-12 (Pre-beta release to Schematron-love-in maillist)
+           * Add many extra parameters to the process-* calls, so that almost
+           all the information in the schema can be provided to client programs.
+           Also, rearrange the parameters to fit in with the ISO schema, which
+           has "rich" and "linkable" attribute groups.
+           * Warn on diagnostics with no ID once only
+           * Improved path reporting, to handle for namespaces
+           * Add process-title dummy template for API
+           * Add command-line parameter allow-foreign (true|false) to suppress
+            warnings one foreign elements and pass them through to the generated
+            stylesheet
+           * remove legacy templates for the old ASCC namespace and no namespace, 
+              and use an import statement instead. Much cleaner now!
+           * patterns use @id not @name
+           * titles can contain sub-elements
+           * start change iso:rule to allow attributes, PIs and comments 
+           * the default process-* for inline elements add a leading and trailing 
+             space, to reduce the chance of concatenation.
+           * add comments to make the generated code clearer
+           
+   Version:2006-11-07 (ISO: first release private to schematron-love-in maillist for review)
+           * Duplicate pattern templates, for handling ISO namespace
+           * Add priority onto default and paragraph templates
+           * Add namespace checks
+           * Handle key in xsl namespace not iso
+           * Add include
+           * Improve namespace handling
+           * Preliminary XSLT2 and EXSLT support
+	       * Refactor iso:schema for clarity
+
+    Version: 2003-05-26 
+    	    * Fix bug with key 
+    Version: 2003-04-16
+    	   * handle 1.6 let expressions
+    	   * make key use XSLT names, and allow anywhere
+    Version: 2001-06-13
+           * same skeleton now supports namespace or no namespace
+           * parameters to handlers updated for all 1.5 attributes 
+           * diagnostic hints supported: command-line option diagnose=yes|no
+           * phases supported: command-line option phase=#ALL|...
+           * abstract rules
+           * compile-time error messages  
+	   * add utility routine generate-id-from-path
+          
+    Contributors: Rick Jelliffe (original), Oliver Becker (architecture, XSLT2), 
+             Miloslav Nic (diagnostic, phase, options), Ludwig Svenonius (abstract)
+             Uche Ogbuji (misc. bug fixes), Jim Ancona (SAXON workaround),
+	 	     Francis Norton (generate-id-from-path), Robert Leftwich, Bryan Rasmussen,
+             Dave Pawson (include, fallback), Florent Georges (namespaces, exslt, attribute
+             context), Benoit Maisonny (attribute context), John Dumps (process-message newline),
+             Cliff Stanford (diagnostics and other newlines)
+
+    
+      
+    
+    KNOWN TYPICAL LIMITATIONS:
+      * Don't use <iso:ns prefix="xsl" .../> with a namespace other than the standard
+      XSLT one. This would be a bizarre thing to do anyway. 
+      * Don't use other prefixes for the XSLT namespace either; some implementations will
+      not handle it correctly.
+     
+     EXTENSIONS:
+      ISO Schematron is designed as a framework with some standard query language
+      bindings. If you need to support other features, please do so safely by making
+      up your own @queryLanguage name: this makes it clear that your schema requires
+      special features. For example, default ISO Schematron does not support user
+      defined functions; so if you want to use the user defined function feature
+      in XSLT, you need to have a schema with some queryBinding attribute name like
+      "XSLT-with-my-functions" or whatever.
+-->
+
+
+
+
+<xsl:stylesheet  
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+	xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" 
+    xmlns:schold="http://www.ascc.net/xml/schematron"
+    xmlns:iso="http://purl.oclc.org/dsdl/schematron" 
+    xmlns:exsl="http://exslt.org/common" 
+    xmlns:xhtml="http://www.w3.org/1999/xhtml" 
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"
+    extension-element-prefixes="exsl"
+    version="2.0"
+	 >
+<!-- This program implements ISO Schematron, except for abstract patterns 
+which require a preprocess.
+-->
+  
+
+<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
+
+
+<!-- Category: top-level-element -->
+<xsl:output method="xml" omit-xml-declaration="no" standalone="yes"  indent="yes"/>
+
+
+
+<xsl:param name="phase">
+   <xsl:choose>   
+    <xsl:when test="//iso:schema/@defaultPhase">
+      <xsl:value-of select="//iso:schema/@defaultPhase"/>
+    </xsl:when>
+    <xsl:otherwise>#ALL</xsl:otherwise>
+  </xsl:choose>
+</xsl:param>
+
+<xsl:param name="allow-foreign">false</xsl:param>
+
+<xsl:param name="message-newline">true</xsl:param>
+
+<!-- DPC set to true if contexts should be checked on attribute nodes
+         defaults to true if there is any possibility that a context could match an attribute,
+         err on the side if caution, a context of *[.='@'] would cause this param to defualt to true
+         even though @ is in a string
+-->
+<xsl:param name="attributes">
+  <xsl:choose>
+    <xsl:when test="//iso:rule[contains(@context,'@') or contains(@context,'attribute')]">true</xsl:when>
+    <xsl:otherwise>false</xsl:otherwise>
+  </xsl:choose>
+</xsl:param>
+
+<!-- DPC set to true if contexts should be checked on just elements in the child axis
+         defaults to true if there is any possibility that a context could match an comment or PI
+         err on the side if caution, a context of *[.='('] would cause this param to defualt to true
+         even though ( is in a string, but node() comment() and processing-instruction()  all have a (
+-->
+<xsl:param name="only-child-elements">
+  <xsl:choose>
+    <xsl:when test="//iso:rule[contains(@context,'(')]">true</xsl:when>
+    <xsl:otherwise>false</xsl:otherwise>
+  </xsl:choose>
+</xsl:param>
+
+<!-- DPC set to true if contexts should be checked on text nodes nodes (if only-child-elements is false)
+         THIS IS NON CONFORMANT BEHAVIOUR JUST FOR DISCUSSION OF A POSSIBLE CHANGE TO THE
+         SPECIFICATION. THIS PARAM SHOULD GO IF THE FINAL DECISION IS THAT THE SPEC DOES NOT CHANGE.
+	 Always defaults to false
+-->
+<xsl:param name="visit-text" select="'false'"/>
+
+<!-- DPC
+  When selecting contexts the specified behaviour is
+    @*|node()[not(self::text())]
+    The automatic settings may use
+      node()[not(self::text())]
+      @*|*
+      *
+  instead for schema for which they are equivalent.
+  If the params are set explictly the above may be used, and also either if
+      @*
+      @*|node()
+   in all cases the result may not be equivalent, for example if you specify no attributes and the schema 
+   does have attribute contexts they will be silently ignored.
+
+  after testing it turns out that
+  node()[not(self::text())] is slower in saxon than *|comment()|processing-instruction() 
+  which I find a bit surprising but anyway I'll use the longr faster version.
+-->
+<xsl:variable name="context-xpath">
+  <xsl:if test="$attributes='true'">@*|</xsl:if>
+  <xsl:choose>
+    <xsl:when test="$only-child-elements='true'">*</xsl:when>
+    <xsl:when test="$visit-text='true'">node()</xsl:when>
+    <xsl:otherwise>*|comment()|processing-instruction()</xsl:otherwise>
+  </xsl:choose>
+</xsl:variable>
+
+<!-- DPC if this is set to 
+    '' use recursive templates to iterate over document tree,
+    'key' select  all contexts with a key rather than walking the tree explictly in each mode
+    '//' select all contexts with // a key rather than walking the tree explictly in each mode (XSLT2 only)
+-->
+<xsl:param name="select-contexts" select="''"/>
+
+
+<!-- e.g. saxon file.xml file.xsl "sch.exslt.imports=.../string.xsl;.../math.xsl" -->
+<xsl:param name="sch.exslt.imports"/>
+
+<xsl:param name="debug">false</xsl:param>
+
+<!-- Set the language code for messages -->
+<xsl:param name="langCode">default</xsl:param>
+
+<!-- Set the default for schematron-select-full-path, i.e. the notation for svrl's @location-->
+<xsl:param name="full-path-notation">1</xsl:param>
+
+<!-- Simple namespace check -->
+<xsl:template match="/">
+    <xsl:if  test="//schold:*[ancestor::iso:* or descendant::iso:*]">
+    
+	<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">1</xsl:with-param></xsl:call-template></xsl:message>
+ 
+    </xsl:if>
+
+    <xsl:apply-templates />
+</xsl:template>
+
+
+<!-- ============================================================== -->
+<!-- ISO SCHEMATRON SCHEMA ELEMENT  -->
+<!-- Not handled: Abstract patterns. A pre-processor is assumed. -->
+<!-- ============================================================== -->
+
+<!-- SCHEMA -->
+<!-- Default uses XSLT 1 -->
+<xsl:template match="iso:schema[not(@queryBinding) or @queryBinding='xslt' 
+     or @queryBinding='xslt1' or @queryBinding='XSLT' or @queryBinding='XSLT1'
+     or @queryBinding='xpath']">
+     <xsl:if test="
+	     @queryBinding='xslt1' or @queryBinding='XSLT' or @queryBinding='XSLT1'">
+	     <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">2</xsl:with-param></xsl:call-template></xsl:message>
+	</xsl:if>
+	<axsl:stylesheet>
+	    <xsl:apply-templates 
+		select="iso:ns" />
+
+	    <!-- Handle the namespaces before the version attribute: reported to help SAXON -->
+	    <xsl:attribute name="version">1.0</xsl:attribute>
+	    
+		<xsl:apply-templates select="." mode="stylesheetbody"/>
+		<!-- was xsl:call-template name="stylesheetbody"/ -->
+	</axsl:stylesheet>
+</xsl:template>
+
+<!-- Using EXSLT with all modeles (except function module: not applicable) -->
+<xsl:template match="iso:schema[@queryBinding='exslt']" priority="10">
+    <xsl:comment>This XSLT was automatically generated from a Schematron schema.</xsl:comment>
+	<axsl:stylesheet
+ 	  	xmlns:date="http://exslt.org/dates-and-times"
+ 	  	xmlns:dyn="http://exslt.org/dynamic"
+		xmlns:exsl="http://exslt.org/common"
+		xmlns:math="http://exslt.org/math"
+   		xmlns:random="http://exslt.org/random"
+  		xmlns:regexp="http://exslt.org/regular-expressions"
+   		xmlns:set="http://exslt.org/sets"
+   		xmlns:str="http://exslt.org/strings"
+   		extension-element-prefixes="date dyn exsl math random regexp set str" >
+	
+        <xsl:apply-templates
+		select="iso:ns" />
+	    <!-- Handle the namespaces before the version attribute: reported to help SAXON -->
+	    <xsl:attribute name="version">1.0</xsl:attribute>
+	    
+	    <xsl:apply-templates select="." mode="stylesheetbody"/>
+		<!-- was xsl:call-template name="stylesheetbody"/ -->
+	</axsl:stylesheet>
+</xsl:template>
+
+<!-- Using XSLT 2 -->
+<xsl:template 
+	match="iso:schema[@queryBinding='xslt2' or @queryBinding ='xpath2']" 
+	priority="10">
+	<axsl:stylesheet
+	   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+	   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
+	   xmlns:saxon="http://saxon.sf.net/" 
+	   >
+        <xsl:apply-templates 
+		select="iso:ns" />
+	    <!-- Handle the namespaces before the version attribute: reported to help SAXON -->
+	    <xsl:attribute name="version">2.0</xsl:attribute>
+	    
+		<xsl:apply-templates select="." mode="stylesheetbody"/>
+		<!-- was xsl:call-template name="stylesheetbody"/ -->
+	</axsl:stylesheet>
+</xsl:template>
+
+
+<!-- Default uses XSLT 1 -->
+<xsl:template match="iso:schema" priority="-1">
+	<xsl:message terminate="yes" ><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">3a</xsl:with-param></xsl:call-template>
+	<xsl:value-of select="@queryBinding"/>
+	<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">3b</xsl:with-param></xsl:call-template></xsl:message>        
+</xsl:template>
+
+<xsl:template match="*" mode="stylesheetbody">
+	<!--xsl:template name="stylesheetbody"-->
+    <xsl:comment>Implementers: please note that overriding process-prolog or process-root is 
+    the preferred method for meta-stylesheets to use where possible. </xsl:comment><xsl:text>
</xsl:text>
+ 
+    <!-- These parameters may contain strings with the name and directory of the file being
+   validated. For convenience, if the caller only has the information in a single string,
+   that string could be put in fileDirParameter. The archives parameters are available
+   for ZIP archives.
+	-->
+    
+	<axsl:param name="archiveDirParameter" />
+	<axsl:param name="archiveNameParameter" />
+	<axsl:param name="fileNameParameter"  />
+	<axsl:param name="fileDirParameter" /> 
+    <xsl:call-template name="iso:exslt.add.imports" />
+       
+    <axsl:variable name="document-uri"><axsl:value-of select="document-uri(/)" /></axsl:variable>
+    <xsl:text>

</xsl:text><xsl:comment>PHASES</xsl:comment><xsl:text>
</xsl:text>
+	<xsl:call-template name="handle-phase"/> 
+    <xsl:text>

</xsl:text><xsl:comment>PROLOG</xsl:comment><xsl:text>
</xsl:text>
+	<xsl:call-template name="process-prolog"/> 
+    <xsl:text>

</xsl:text><xsl:comment>XSD TYPES FOR XSLT2</xsl:comment><xsl:text>
</xsl:text>
+	<xsl:apply-templates mode="do-types"   select="xsl:import-schema"/>
+    <xsl:text>

</xsl:text><xsl:comment>KEYS AND FUNCTIONS</xsl:comment><xsl:text>
</xsl:text>
+	<xsl:apply-templates mode="do-keys"   select="xsl:key | xsl:function "/>
+    <xsl:text>

</xsl:text><xsl:comment>DEFAULT RULES</xsl:comment><xsl:text>
</xsl:text>
+    <xsl:call-template name="generate-default-rules" />
+    <xsl:text>

</xsl:text><xsl:comment>SCHEMA SETUP</xsl:comment><xsl:text>
</xsl:text>
+    <xsl:call-template name="handle-root"/>
+    <xsl:text>

</xsl:text><xsl:comment>SCHEMATRON PATTERNS</xsl:comment><xsl:text>
</xsl:text>
+ 
+	<xsl:apply-templates select="*[not(self::iso:ns)] " />
+</xsl:template>
+ 
+    <xsl:template name="iso:exslt.add.imports">
+      <xsl:param name="imports" select="$sch.exslt.imports"/>
+      <xsl:choose>
+        <xsl:when test="contains($imports, ';')">
+          <axsl:import href="{ substring-before($imports, ';') }"/>
+          <xsl:call-template name="iso:exslt.add.imports">
+            <xsl:with-param name="imports"  select="substring-after($imports, ';')"/>
+          </xsl:call-template>
+        </xsl:when>
+        <xsl:when test="$imports">
+          <axsl:import href="{ $imports }"/>
+        </xsl:when>
+      </xsl:choose>
+    </xsl:template>
+
+<xsl:template name="handle-phase" >
+    <!-- This just tests that the phase exists -->
+	<xsl:if test="not(normalize-space( $phase ) = '#ALL')">
+	  <xsl:if test="not(iso:phase[@id = normalize-space( $phase )])">
+		  <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">4a</xsl:with-param></xsl:call-template>
+		  <xsl:value-of select="normalize-space( $phase )"/>
+		  <xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">4b</xsl:with-param></xsl:call-template></xsl:message>
+	  </xsl:if>
+     </xsl:if>
+</xsl:template>
+
+<xsl:template name="generate-default-rules">
+		<xsl:text>

</xsl:text>
+		<xsl:comment>MODE: SCHEMATRON-SELECT-FULL-PATH</xsl:comment><xsl:text>
</xsl:text>
+		<xsl:comment>This mode can be used to generate an ugly though full XPath for locators</xsl:comment><xsl:text>
</xsl:text>
+   		<axsl:template match="*" mode="schematron-select-full-path">
+   			<xsl:choose>
+   				<xsl:when test=" $full-path-notation = '1' ">
+   					<!-- Use for computers, but rather unreadable for humans -->
+					<axsl:apply-templates select="." mode="schematron-get-full-path"/>
+				</xsl:when>
+   				<xsl:when test=" $full-path-notation = '2' ">
+   					<!-- Use for humans, but no good for paths unless namespaces are known out-of-band -->
+					<axsl:apply-templates select="." mode="schematron-get-full-path-2"/>
+				</xsl:when>
+   				<xsl:when test=" $full-path-notation = '3' "> 
+   					<!-- Obsolescent. Use for humans, but no good for paths unless namespaces are known out-of-band -->
+					<axsl:apply-templates select="." mode="schematron-get-full-path-3"/>
+				</xsl:when>
+
+                   <xsl:otherwise >
+                       <!-- Use for computers, but rather unreadable for humans -->
+                    <axsl:apply-templates select="." mode="schematron-get-full-path"/>
+                </xsl:otherwise>
+			</xsl:choose>
+		</axsl:template>
+	
+
+		<xsl:text>

</xsl:text>
+		<xsl:comment>MODE: SCHEMATRON-FULL-PATH</xsl:comment><xsl:text>
</xsl:text>
+		<xsl:comment>This mode can be used to generate an ugly though full XPath for locators</xsl:comment><xsl:text>
</xsl:text>
+   		<axsl:template match="*" mode="schematron-get-full-path">
+			<axsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
+			<xsl:choose>
+				<xsl:when test="//iso:schema[@queryBinding='xslt2']">
+					<!-- XSLT2 syntax -->
+			<axsl:text>/</axsl:text>		
+			<axsl:choose>
+      			<axsl:when test="namespace-uri()=''"><axsl:value-of select="name()"/></axsl:when>
+      			<axsl:otherwise>
+      				<axsl:text>*:</axsl:text>
+      				<axsl:value-of select="local-name()"/>
+      				<axsl:text>[namespace-uri()='</axsl:text>
+      				<axsl:value-of select="namespace-uri()"/>
+      				<axsl:text>']</axsl:text>
+      			</axsl:otherwise>
+    		</axsl:choose>
+    		<axsl:variable name="preceding" select=
+    		"count(preceding-sibling::*[local-name()=local-name(current())
+	  		                             and namespace-uri() = namespace-uri(current())])" />
+			<axsl:text>[</axsl:text>
+	  		<axsl:value-of select="1+ $preceding"/>
+	  		<axsl:text>]</axsl:text>
+		</xsl:when>
+
+		<xsl:otherwise>
+			<!-- XSLT1 syntax -->
+
+			<axsl:text>/</axsl:text>
+			<axsl:choose>
+			<axsl:when test="namespace-uri()=''">
+			<axsl:value-of select="name()"/>
+			<axsl:variable name="p_1" select="1+
+			count(preceding-sibling::*[name()=name(current())])" />
+		<axsl:if test="$p_1>1 or following-sibling::*[name()=name(current())]">
+		  <xsl:text/>[<axsl:value-of select="$p_1"/>]<xsl:text/>
+		</axsl:if>
+		</axsl:when>
+		<axsl:otherwise>
+		<axsl:text>*[local-name()='</axsl:text>
+		<axsl:value-of select="local-name()"/>
+		<axsl:text>']</axsl:text>
+		<axsl:variable name="p_2" select="1+
+		count(preceding-sibling::*[local-name()=local-name(current())])" />
+		<axsl:if test="$p_2>1 or following-sibling::*[local-name()=local-name(current())]">
+		  <xsl:text/>[<axsl:value-of select="$p_2"/>]<xsl:text/>
+		</axsl:if>
+		</axsl:otherwise>
+		</axsl:choose> 
+		</xsl:otherwise>
+
+	</xsl:choose>
+       	 	</axsl:template>
+       	 	
+       	 	
+		<axsl:template match="@*" mode="schematron-get-full-path">
+			<xsl:choose>
+				<xsl:when test="//iso:schema[@queryBinding='xslt2']">
+					<!-- XSLT2 syntax -->
+			<axsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
+      		<axsl:text>/</axsl:text>
+			<axsl:choose>
+      			<axsl:when test="namespace-uri()=''">@<axsl:value-of select="name()"/></axsl:when>
+      			<axsl:otherwise>
+      				<axsl:text>@*[local-name()='</axsl:text>
+      				<axsl:value-of select="local-name()"/>
+      				<axsl:text>' and namespace-uri()='</axsl:text>
+      				<axsl:value-of select="namespace-uri()"/>
+      				<axsl:text>']</axsl:text>
+      			</axsl:otherwise>
+    		</axsl:choose>
+	</xsl:when>
+
+		<xsl:otherwise>
+			<!-- XSLT1 syntax -->
+		<axsl:text>/</axsl:text>
+		<axsl:choose>
+		<axsl:when test="namespace-uri()=''">@<axsl:value-of
+		select="name()"/></axsl:when>
+		<axsl:otherwise>
+		<axsl:text>@*[local-name()='</axsl:text>
+		<axsl:value-of select="local-name()"/>
+		<axsl:text>' and namespace-uri()='</axsl:text>
+		<axsl:value-of select="namespace-uri()"/>
+		<axsl:text>']</axsl:text>
+		</axsl:otherwise>
+		</axsl:choose> 
+
+			</xsl:otherwise>
+			</xsl:choose>
+		</axsl:template>
+	
+	<xsl:text>

</xsl:text>
+	
+	<xsl:comment>MODE: SCHEMATRON-FULL-PATH-2</xsl:comment>
+	<xsl:text>
</xsl:text>
+	<xsl:comment>This mode can be used to generate prefixed XPath for humans</xsl:comment>
+	<xsl:text>
</xsl:text>
+	<!--simplify the error messages by using the namespace prefixes of the
+     instance rather than the generic namespace-uri-styled qualification-->
+	<axsl:template match="node() | @*" mode="schematron-get-full-path-2">
+	<!--report the element hierarchy-->
+		<axsl:for-each select="ancestor-or-self::*">
+			<axsl:text>/</axsl:text>
+			<axsl:value-of select="name(.)"/>
+			<axsl:if test="preceding-sibling::*[name(.)=name(current())]">
+				<axsl:text>[</axsl:text>
+				<axsl:value-of
+					select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
+				<axsl:text>]</axsl:text>
+			</axsl:if>
+		</axsl:for-each>
+		<!--report the attribute-->
+		<axsl:if test="not(self::*)">
+			<axsl:text/>/@<axsl:value-of select="name(.)"/>
+		</axsl:if>
+	</axsl:template>
+
+
+	<xsl:comment>MODE: SCHEMATRON-FULL-PATH-3</xsl:comment>
+	
+	<xsl:text>
</xsl:text>
+	<xsl:comment>This mode can be used to generate prefixed XPath for humans 
+	(Top-level element has index)</xsl:comment>
+	<xsl:text>
</xsl:text>
+	<!--simplify the error messages by using the namespace prefixes of the
+     instance rather than the generic namespace-uri-styled qualification-->
+	<axsl:template match="node() | @*" mode="schematron-get-full-path-3">
+	<!--report the element hierarchy-->
+		<axsl:for-each select="ancestor-or-self::*">
+			<axsl:text>/</axsl:text>
+			<axsl:value-of select="name(.)"/>
+			<axsl:if test="parent::*">
+				<axsl:text>[</axsl:text>
+				<axsl:value-of
+					select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
+				<axsl:text>]</axsl:text>
+			</axsl:if>
+		</axsl:for-each>
+		<!--report the attribute-->
+		<axsl:if test="not(self::*)">
+			<axsl:text/>/@<axsl:value-of select="name(.)"/>
+		</axsl:if>
+	</axsl:template>
+
+		<xsl:text>

</xsl:text>
+		<xsl:comment>MODE: GENERATE-ID-FROM-PATH </xsl:comment><xsl:text>
</xsl:text>
+		<!-- repeatable-id maker derived from Francis Norton's. -->
+		<!-- use this if you need generate ids in separate passes,
+		     because generate-id() is not guaranteed to produce the same
+		     results each time. These ids are not XML names but closer to paths. -->
+		<axsl:template match="/" mode="generate-id-from-path"/>
+		<axsl:template match="text()" mode="generate-id-from-path">
+			<axsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
+			<axsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')"/>
+		</axsl:template>
+		<axsl:template match="comment()" mode="generate-id-from-path">
+			<axsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
+			<axsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')"/>
+		</axsl:template>
+		<axsl:template match="processing-instruction()" mode="generate-id-from-path">
+			<axsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
+			<axsl:value-of 
+			select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')"/>
+		</axsl:template>
+		<axsl:template match="@*" mode="generate-id-from-path">
+			<axsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
+			<axsl:value-of select="concat('.@', name())"/>
+		</axsl:template>
+		<axsl:template match="*" mode="generate-id-from-path" priority="-0.5">
+			<axsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
+			<axsl:text>.</axsl:text>
+<!--
+			<axsl:choose>
+				<axsl:when test="count(. | ../namespace::*) = count(../namespace::*)">
+					<axsl:value-of select="concat('.namespace::-',1+count(namespace::*),'-')"/>
+				</axsl:when>
+				<axsl:otherwise>
+-->
+				<axsl:value-of 
+				select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')"/>
+<!--
+				</axsl:otherwise>
+			</axsl:choose>
+-->
+		</axsl:template>
+		
+		
+		<xsl:text>

</xsl:text>
+		<xsl:comment>MODE: GENERATE-ID-2 </xsl:comment><xsl:text>
</xsl:text>
+		<!-- repeatable-id maker from David Carlisle. -->
+		<!-- use this if you need generate IDs in separate passes,
+		     because generate-id() is not guaranteed to produce the same
+		     results each time. These IDs are well-formed XML NMTOKENS -->
+	<axsl:template match="/" mode="generate-id-2">U</axsl:template>
+
+	<axsl:template match="*" mode="generate-id-2" priority="2">
+		<axsl:text>U</axsl:text>
+		<axsl:number level="multiple" count="*"/>
+	</axsl:template>
+
+	<axsl:template match="node()" mode="generate-id-2">
+		<axsl:text>U.</axsl:text>
+		<axsl:number level="multiple" count="*"/>
+		<axsl:text>n</axsl:text>
+		<axsl:number count="node()"/>
+	</axsl:template>
+
+	<axsl:template match="@*" mode="generate-id-2">
+		<axsl:text>U.</axsl:text>
+		<axsl:number level="multiple" count="*"/>
+		<axsl:text>_</axsl:text>
+		<axsl:value-of select="string-length(local-name(.))"/>
+		<axsl:text>_</axsl:text>
+		<axsl:value-of select="translate(name(),':','.')"/>
+	</axsl:template> 
+		
+
+		<xsl:comment>Strip characters</xsl:comment>
+		<axsl:template match="text()" priority="-1" />
+			
+  </xsl:template>
+
+ <xsl:template name="handle-root">
+		<!-- Process the top-level element -->
+		<axsl:template match="/">
+			<xsl:call-template name="process-root">
+				<xsl:with-param 	
+				name="title" select="(@id | iso:title)[last()]"/>
+				<xsl:with-param name="version" select="'iso'" />
+				<xsl:with-param name="schemaVersion" select="@schemaVersion" />
+				<xsl:with-param name="queryBinding" select="@queryBinding" />
+				<xsl:with-param name="contents">
+					<xsl:apply-templates mode="do-all-patterns"/>
+				</xsl:with-param>
+				
+				<!-- "Rich" properties -->
+				<xsl:with-param name="fpi" select="@fpi"/>
+				<xsl:with-param name="icon" select="@icon"/>
+				<xsl:with-param name="id" select="@id"/>
+				<xsl:with-param name="lang" select="@xml:lang"/>
+				<xsl:with-param name="see" select="@see" />
+				<xsl:with-param name="space" select="@xml:space" />
+			</xsl:call-template>
+		</axsl:template>
+ 
+      
+</xsl:template>
+
+<!-- ============================================================== -->
+<!-- ISO SCHEMATRON ELEMENTS -->
+<!-- ============================================================== -->
+
+	<!-- ISO ACTIVE -->
+	<xsl:template match="iso:active">
+                <xsl:if test="not(@pattern)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">5</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+
+                <xsl:if test="not(../../iso:pattern[@id = current()/@pattern])
+                and not(../../iso:include)">
+                           <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">6a</xsl:with-param></xsl:call-template>
+                           <xsl:value-of select="@pattern"/>
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">6b</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+        </xsl:template>
+
+	<!-- ISO ASSERT and REPORT -->
+	<xsl:template match="iso:assert">
+  
+                <xsl:if test="not(@test)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">7</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+        <xsl:text>

		</xsl:text>
+		<xsl:comment>ASSERT <xsl:value-of select="@role" /> </xsl:comment><xsl:text>
</xsl:text>      
+	
+		<axsl:choose>
+			<axsl:when test="{@test}"/>
+			<axsl:otherwise>
+				<xsl:call-template name="process-assert">
+					<xsl:with-param name="test" select="normalize-space(@test)" />
+					<xsl:with-param name="diagnostics" select="@diagnostics"/>
+					<xsl:with-param name="flag" select="@flag"/>
+					
+					<xsl:with-param name="properties" select="@properties" />
+					
+					<!-- "Rich" properties -->
+					<xsl:with-param name="fpi" select="@fpi"/>
+					<xsl:with-param name="icon" select="@icon"/>
+					<xsl:with-param name="id" select="@id"/>
+					<xsl:with-param name="lang" select="@xml:lang"/>
+					<xsl:with-param name="see" select="@see" />
+					<xsl:with-param name="space" select="@xml:space" />
+					
+					<!-- "Linking" properties -->
+					<xsl:with-param name="role" select="@role" />
+					<xsl:with-param name="subject" select="@subject" />
+					 
+				</xsl:call-template>
+ 			 
+ 			
+			</axsl:otherwise>
+		</axsl:choose>
+	</xsl:template>
+	<xsl:template match="iso:report">
+		 
+                <xsl:if test="not(@test)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">8</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+                
+        <xsl:text>

		</xsl:text>
+		<xsl:comment>REPORT <xsl:value-of select="@role" /> </xsl:comment><xsl:text>
</xsl:text>      
+	
+		<axsl:if test="{@test}">
+		
+			<xsl:call-template name="process-report">
+				<xsl:with-param name="test" select="normalize-space(@test)" />
+				<xsl:with-param name="diagnostics" select="@diagnostics"/>
+					<xsl:with-param name="flag" select="@flag"/>
+				
+					<xsl:with-param name="properties" select="@properties" />
+					<!-- "Rich" properties -->
+					<xsl:with-param name="fpi" select="@fpi"/>
+					<xsl:with-param name="icon" select="@icon"/>
+					<xsl:with-param name="id" select="@id"/>
+					<xsl:with-param name="lang" select="@xml:lang"/>
+					<xsl:with-param name="see" select="@see" />
+					<xsl:with-param name="space" select="@xml:space" />
+					
+					<!-- "Linking" properties -->
+					<xsl:with-param name="role" select="@role" />
+					<xsl:with-param name="subject" select="@subject" />
+			</xsl:call-template>
+			 
+		</axsl:if>
+	</xsl:template>
+
+
+	<!-- ISO DIAGNOSTIC -->
+	<!-- We use a mode here to maintain backwards compatability, instead of adding it
+	     to the other mode.
+	-->
+	<xsl:template match="iso:diagnostic" mode="check-diagnostics">
+              <xsl:if test="not(@id)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">9</xsl:with-param></xsl:call-template></xsl:message>
+               </xsl:if>
+    </xsl:template>
+    
+    <xsl:template match="iso:diagnostic"  >
+                <xsl:call-template name="process-diagnostic">
+                
+					<!-- "Rich" properties -->
+					<xsl:with-param name="fpi" select="@fpi"/>
+					<xsl:with-param name="icon" select="@icon"/>
+					<xsl:with-param name="id" select="@id"/>
+					<xsl:with-param name="lang" select="@xml:lang"/>
+					<xsl:with-param name="see" select="@see" />
+					<xsl:with-param name="space" select="@xml:space" />
+               </xsl:call-template>
+                
+        </xsl:template>
+
+	<!-- ISO DIAGNOSTICS -->
+	<xsl:template match="iso:diagnostics" >
+		<xsl:apply-templates mode="check-diagnostics" select="*" />
+	</xsl:template>
+
+	<!-- ISO DIR -->
+	<xsl:template match="iso:dir"  mode="text" >
+		<xsl:call-template name="process-dir">
+			<xsl:with-param name="value" select="@value"/>
+		</xsl:call-template>
+	</xsl:template>
+
+	<!-- ISO EMPH -->
+	<xsl:template match="iso:emph"  mode="text">
+	 
+		<xsl:call-template name="process-emph"/> 
+
+	</xsl:template>
+
+	<!-- ISO EXTENDS -->
+	<xsl:template match="iso:extends">
+		<xsl:if test="not(@rule)">
+                   <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">10</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+     		<xsl:if test="not(//iso:rule[@abstract='true'][@id= current()/@rule] )">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">11a</xsl:with-param></xsl:call-template>
+                    <xsl:value-of select="@rule"/>
+                    <xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">11b</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+	        <xsl:call-template name="IamEmpty" />
+
+  		<xsl:if test="//iso:rule[@id=current()/@rule]">
+    			<xsl:apply-templates select="//iso:rule[@id=current()/@rule]"
+				mode="extends"/>
+  		</xsl:if>
+
+	</xsl:template>
+
+	<!-- KEY: ISO has no KEY -->
+	<!-- NOTE: 
+	     Key has had a checkered history. Schematron 1.0 allowed it in certain places, but
+	     users came up with a different location, which has now been adopted. 
+	     
+	     XT, the early XSLT processor, did not implement key and died when it was present. 
+	     So there are some versions of the Schematron skeleton for XT that strip out all
+	     key elements.
+	     
+	     Xalan (e.g. Xalan4C 1.0 and a Xalan4J) also had a funny. A fix involved making 
+	     a top-level parameter called $hiddenKey and then using that instead of matching
+	     "key". This has been removed.
+	     
+	     Keys and functions are the same mode, to allow their declaration to be mixed up.
+	-->
+	<xsl:template  match="xsl:key" mode="do-keys" >
+	     <xsl:if test="not(@name)">
+              <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">12</xsl:with-param></xsl:call-template></xsl:message>
+         </xsl:if>
+                <xsl:if test="not(@path) and not(@use)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">13</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>         
+	     <xsl:choose>
+	     	<xsl:when test="parent::iso:rule ">
+	        <xsl:call-template name="IamEmpty" />
+	       <xsl:choose>
+	       	<xsl:when test="@path">
+				<axsl:key match="{../@context}" name="{@name}" use="{@path}"/>
+			</xsl:when>
+			<xsl:otherwise>
+							<axsl:key match="{../@context}" name="{@name}" use="{@use}"/>
+			</xsl:otherwise>
+			</xsl:choose>	
+		</xsl:when>
+		<xsl:otherwise>
+                <xsl:if test="not(@match) ">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">14</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>   		
+			<axsl:key>
+      			<xsl:copy-of select="@*"/>
+    		</axsl:key>	
+		</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+
+	<xsl:template match="xsl:key "  /><!-- swallow -->
+
+	<xsl:template match="iso:key "  >
+		<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">15</xsl:with-param></xsl:call-template></xsl:message>
+    </xsl:template>
+
+  <!-- XSL FUNCTION -->
+  <xsl:template  match="xsl:function" mode="do-keys" >
+	     <xsl:if test="not(@name)">
+              <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">16</xsl:with-param></xsl:call-template></xsl:message>
+         </xsl:if>      
+	     <xsl:copy-of select="."/>
+  </xsl:template>
+
+	<xsl:template match="xsl:function "  /><!-- swallow -->
+
+	<xsl:template match="iso:function "  >
+		<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">17</xsl:with-param></xsl:call-template></xsl:message>
+    </xsl:template>
+
+
+   <!-- ISO INCLUDE -->
+   <!-- This is only a fallback. Include really needs to have been done before this as a separate pass.-->
+
+   <xsl:template match="iso:include[not(normalize-space(@href))]"
+	   priority="1">
+	<xsl:if test=" $debug = 'false' ">
+		<xsl:message terminate="yes"><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">18</xsl:with-param></xsl:call-template></xsl:message>
+	</xsl:if>
+
+   </xsl:template>
+
+   <!-- Extend the URI syntax to allow # refererences -->
+   <!-- Note that XSLT2 actually already allows # references, but we override them because it
+   looks unreliable -->
+   <xsl:template match="iso:include">
+       <xsl:variable name="document-uri" select="substring-before(concat(@href,'#'), '#')"/>
+       <xsl:variable name="fragment-id" select="substring-after(@href, '#')"/>
+       
+       <xsl:choose> 
+          
+          <xsl:when test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0" >
+          	<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">19</xsl:with-param></xsl:call-template></xsl:message>
+          </xsl:when> 
+          
+          <xsl:when test="string-length( $fragment-id ) > 0">
+              <xsl:variable name="theDocument_1" select="document( $document-uri,/ )" />
+              <xsl:variable name="theFragment_1" select="$theDocument_1//iso:*[@id= $fragment-id]" />
+              <xsl:if test="not($theDocument_1)">
+				<xsl:message terminate="no">
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">20a</xsl:with-param></xsl:call-template>
+					<xsl:value-of select="@href"/>
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">20b</xsl:with-param></xsl:call-template>
+				</xsl:message>
+			</xsl:if>
+              <xsl:if test=" $theFragment_1/self::iso:schema ">
+                 <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">21</xsl:with-param></xsl:call-template></xsl:message>
+              </xsl:if>
+              <xsl:apply-templates select=" $theFragment_1"/>
+		   </xsl:when>
+		  
+		   <xsl:otherwise>
+		   	  <!-- Import the top-level element if it is in schematron namespace,
+		   	  or its children otherwise, to allow a simple containment mechanism. -->
+              <xsl:variable name="theDocument_2" select="document( $document-uri,/ )" />
+              <xsl:variable name="theFragment_2" select="$theDocument_2/iso:*" />
+              <xsl:variable name="theContainedFragments" select="$theDocument_2/*/iso:*" />
+              <xsl:if test="not($theDocument_2)">
+				<xsl:message terminate="no">
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">20a</xsl:with-param></xsl:call-template>
+					<xsl:value-of select="@href"/>
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">20b</xsl:with-param></xsl:call-template>
+				</xsl:message>
+			</xsl:if>
+              <xsl:if test=" $theFragment_2/self::iso:schema or $theContainedFragments/self::iso:schema">
+                 <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">21</xsl:with-param></xsl:call-template></xsl:message>
+              </xsl:if>
+       		<xsl:apply-templates select="$theFragment_2 | $theContainedFragments "/>
+       	   </xsl:otherwise>
+       </xsl:choose>
+   </xsl:template>
+   
+   <!-- This is to handle the particular case of including patterns -->  
+   <xsl:template match="iso:include" mode="do-all-patterns">
+       <xsl:variable name="document-uri" select="substring-before(concat(@href,'#'), '#')"/>
+       <xsl:variable name="fragment-id" select="substring-after(@href, '#')"/>
+ 
+       <xsl:choose> 
+          
+          <xsl:when test="string-length( $document-uri ) = 0 and string-length( $fragment-id ) = 0" >
+          	<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">19</xsl:with-param></xsl:call-template></xsl:message>
+          </xsl:when> 
+          
+          <xsl:when test="string-length( $fragment-id ) > 0">
+              <xsl:variable name="theDocument_1" select="document( $document-uri,/ )" />
+              <xsl:variable name="theFragment_1" select="$theDocument_1//iso:*[@id= $fragment-id ]" />
+              <xsl:if test=" $theFragment_1/self::iso:schema ">
+                 <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">21</xsl:with-param></xsl:call-template></xsl:message>
+              </xsl:if>
+              <xsl:apply-templates select=" $theFragment_1" mode="do-all-patterns"/>
+		   </xsl:when>
+		  
+		   <xsl:otherwise>
+		   	  <!-- Import the top-level element if it is in schematron namespace,
+		   	  or its children otherwise, to allow a simple containment mechanism. -->
+              <xsl:variable name="theDocument_2" select="document( $document-uri,/ )" />
+              <xsl:variable name="theFragment_2" select="$theDocument_2/iso:*" />
+              <xsl:variable name="theContainedFragments" select="$theDocument_2/*/iso:*" />
+              <xsl:if test=" $theFragment_2/self::iso:schema or $theContainedFragments/self::iso:schema">
+                 <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">21</xsl:with-param></xsl:call-template></xsl:message>
+              </xsl:if>
+       		<xsl:apply-templates select="$theFragment_2 | $theContainedFragments "
+       		mode="do-all-patterns" />
+       	   </xsl:otherwise>
+       </xsl:choose>
+   </xsl:template>
+   
+	
+	<!-- XSL IMPORT-SCHEMA -->
+	<!-- Importing an XSD schema allows the variour type operations to be available. -->
+	<xsl:template  match="xsl:import-schema" mode="do-types" >	 
+		<xsl:choose>
+		  <xsl:when test="ancestor::iso:schema[@queryBinding='xslt2']">
+		  	<xsl:copy-of select="." />
+		  </xsl:when>
+		<xsl:otherwise>
+			<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">22</xsl:with-param></xsl:call-template></xsl:message>
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>  
+		   
+	<!-- swallow -->	   
+    <xsl:template match="xsl:import-schema" />
+ 
+	<xsl:template match="iso:import-schema "  >
+		<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">23</xsl:with-param></xsl:call-template></xsl:message>
+    </xsl:template>
+ 
+	<!-- ISO LET -->
+	<xsl:template match="iso:let" >
+	  <xsl:if test="ancestor::iso:schema[@queryBinding='xpath']">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">24</xsl:with-param></xsl:call-template></xsl:message>
+       </xsl:if>
+	  <xsl:if test="ancestor::iso:schema[@queryBinding='xpath2']">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">25</xsl:with-param></xsl:call-template></xsl:message>
+       </xsl:if>
+       
+       <!-- lets at the top-level are implemented as parameters -->
+       	<xsl:choose>
+       		<xsl:when test="parent::iso:schema">
+       			<!-- it is an error to have an empty param/@select because an XPath is expected -->
+	      		 <axsl:param name="{@name}" select="{@value}">
+	      		 		<xsl:if test="string-length(@value) > 0">
+	      		 			<xsl:attribute name="select"><xsl:value-of select="@value"/></xsl:attribute>
+	      		 		</xsl:if>
+	      		 </axsl:param> 
+       		</xsl:when>
+       		<xsl:otherwise>
+				<axsl:variable name="{@name}" select="{@value}"/>
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>	
+
+	<!-- ISO NAME -->
+	<xsl:template match="iso:name" mode="text">
+	
+		<xsl:if test="@path">
+			<xsl:call-template name="process-name">
+				<xsl:with-param name="name" select="concat('name(', at path,')')"/>
+			</xsl:call-template>
+		</xsl:if>
+		<xsl:if test="not(@path)">
+			<xsl:call-template name="process-name">
+				<xsl:with-param name="name" select="'name(.)'"/>
+			</xsl:call-template>
+		</xsl:if>
+	    <xsl:call-template name="IamEmpty" />
+	</xsl:template>
+
+	<!-- ISO NS -->
+	<!-- Namespace handling is XSLT is quite tricky and implementation dependent -->
+	<xsl:template match="iso:ns">
+ 		<xsl:call-template name="handle-namespace" />
+	</xsl:template>
+
+    <!-- This template is just to provide the API hook -->
+	<xsl:template match="iso:ns"  mode="do-all-patterns" >
+               <xsl:if test="not(@uri)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">26</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+               <xsl:if test="not(@prefix)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">27</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+	        <xsl:call-template name="IamEmpty" />
+		<xsl:call-template name="process-ns" >
+			<xsl:with-param name="prefix" select="@prefix"/>
+			<xsl:with-param name="uri" select="@uri"/>
+		</xsl:call-template>
+	</xsl:template>
+
+	<!-- ISO P -->
+	<xsl:template match="iso:schema/iso:p " mode="do-schema-p" >
+		<xsl:call-template name="process-p">
+			<xsl:with-param name="class" select="@class"/>
+			<xsl:with-param name="icon" select="@icon"/>
+			<xsl:with-param name="id" select="@id"/>
+			<xsl:with-param name="lang" select="@xml:lang"/>
+		</xsl:call-template>
+	</xsl:template>
+	<xsl:template match="iso:pattern/iso:p " mode="do-pattern-p" >
+		<xsl:call-template name="process-p">
+			<xsl:with-param name="class" select="@class"/>
+			<xsl:with-param name="icon" select="@icon"/>
+			<xsl:with-param name="id" select="@id"/>
+			<xsl:with-param name="lang" select="@xml:lang"/>
+		</xsl:call-template>
+	</xsl:template>
+	
+    <!-- Currently, iso:p in other position are not passed through to the API -->
+	<xsl:template match="iso:phase/iso:p" />
+	<xsl:template match="iso:p " priority="-1" />
+ 
+	<!-- ISO PATTERN -->
+	<xsl:template match="iso:pattern" mode="do-all-patterns">
+	<xsl:if test="($phase = '#ALL') 
+	or (../iso:phase[@id= $phase]/iso:active[@pattern= current()/@id])">
+
+ 		<!-- Extension to allow validation in multiple documents -->  
+ 		<xsl:choose>
+		      	<xsl:when test="string-length(normalize-space(@documents))=0" >
+				    <xsl:call-template name="handle-pattern" />
+	 	       	</xsl:when>
+ 		    	<xsl:otherwise>  
+ 		    	<axsl:variable name="thePath"
+ 		    		select="{@documents}" 
+ 		    		as="xs:string*"  /> 
+ 		    	
+				<axsl:for-each  select="$thePath">  
+					<axsl:choose>
+						<axsl:when test="starts-with( ., 'http:') or starts-with(., 'file:' )
+						   or starts-with(., '/')"><!-- try as absolute path -->
+		  					<axsl:for-each select="document(.)"> 
+		    					<xsl:call-template name="handle-pattern"  />
+							</axsl:for-each>
+						</axsl:when>
+						<axsl:otherwise><!-- is relative path -->
+		  					<axsl:for-each select="document(concat( $document-uri , '/../', .))"> 
+		    					<xsl:call-template name="handle-pattern"  />
+							</axsl:for-each>
+						</axsl:otherwise>
+				  </axsl:choose>		
+				</axsl:for-each>
+			</xsl:otherwise>
+		</xsl:choose>	
+     </xsl:if>
+
+   </xsl:template>
+   
+   <xsl:template name="handle-pattern">
+		<xsl:call-template name="process-pattern">
+			<!-- the following select statement assumes that
+			@id | iso:title returns node-set in document order:
+			we want the title if it is there, otherwise the @id attribute -->
+			<xsl:with-param name="name" select="(@id | iso:title )[last()]"/>
+			<xsl:with-param name="is-a" select="''"/>
+			
+					<!-- "Rich" properties -->
+					<xsl:with-param name="fpi" select="@fpi"/>
+					<xsl:with-param name="icon" select="@icon"/>
+					<xsl:with-param name="id" select="@id"/>
+					<xsl:with-param name="lang" select="@xml:lang"/>
+					<xsl:with-param name="see" select="@see" />
+					<xsl:with-param name="space" select="@xml:space" />
+		</xsl:call-template>
+		<xsl:choose>
+		  <!--  Use the key method -->
+		  <xsl:when test="$select-contexts='key'">
+		    <axsl:apply-templates select="key('M','M{count(preceding-sibling::*)}')" mode="M{count(preceding-sibling::*)}"/>
+		  </xsl:when>
+		  
+		  <!-- Use the // method -->
+		  <xsl:when test="$select-contexts='//'">
+		    <xsl:choose>
+			  	<xsl:when test="@document">
+			    	<!-- External document -->
+		    		<axsl:for-each select="{@document}">
+					<!-- same code as next block, but run from different context -->		    		
+		    		<axsl:apply-templates mode="M{count(preceding-sibling::*)}" >
+		      			<xsl:attribute name="select"> 
+							<xsl:text>//(</xsl:text>
+							<xsl:for-each select="iso:rule/@context">
+			  					<xsl:text>(</xsl:text>
+			  					<xsl:value-of select="."/>
+			  					<xsl:text>)</xsl:text>
+			  					<xsl:if test="position()!=last()">|</xsl:if>
+							</xsl:for-each>
+							<xsl:text>)</xsl:text>
+							<xsl:if test="$visit-text='false'">[not(self::text())]</xsl:if>
+		      			</xsl:attribute>
+		    		</axsl:apply-templates>
+		    		</axsl:for-each>
+		  		</xsl:when>
+
+		  		<xsl:otherwise>
+		    		<axsl:apply-templates mode="M{count(preceding-sibling::*)}" >
+		      			<xsl:attribute name="select"> 
+							<xsl:text>//(</xsl:text>
+							<xsl:for-each select="iso:rule/@context">
+			  					<xsl:text>(</xsl:text>
+			  					<xsl:value-of select="."/>
+			  					<xsl:text>)</xsl:text>
+			  					<xsl:if test="position()!=last()">|</xsl:if>
+							</xsl:for-each>
+							<xsl:text>)</xsl:text>
+							<xsl:if test="$visit-text='false'">[not(self::text())]</xsl:if>
+		      			</xsl:attribute>
+		    		</axsl:apply-templates>
+		    	</xsl:otherwise>
+		    </xsl:choose>
+		  </xsl:when>
+		  
+		  <!-- Use complete tree traversal -->
+		  <xsl:when test="@document">
+		    <!-- External document -->
+		    <axsl:for-each select="{@document}">
+		    	<axsl:apply-templates select="." mode="M{count(preceding-sibling::*)}"/>
+		    </axsl:for-each>
+		  </xsl:when>
+		  <xsl:otherwise>
+		    <axsl:apply-templates select="/" mode="M{count(preceding-sibling::*)}"/>
+		  </xsl:otherwise>
+		</xsl:choose>
+        <!--/xsl:if-->
+	</xsl:template>
+	
+	<xsl:template match="iso:pattern[@abstract='true']">
+    
+             <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">28</xsl:with-param></xsl:call-template></xsl:message>
+    </xsl:template>
+
+    <!-- Here is the template for the normal case of patterns -->
+	<xsl:template match="iso:pattern[not(@abstract='true')]">
+    
+      <xsl:if test="($phase = '#ALL') 
+	          or (../iso:phase[@id= $phase]/iso:active[@pattern= current()/@id])">
+		<xsl:text>

</xsl:text>
+		<xsl:comment>PATTERN <xsl:value-of select="@id" /> <xsl:value-of select="iso:title" /> </xsl:comment><xsl:text>
</xsl:text>      
+		<xsl:apply-templates />
+		
+		<!-- DPC select-contexts test -->
+		<xsl:if test="not($select-contexts)">
+		  <axsl:template match="text()" priority="-1" mode="M{count(preceding-sibling::*)}">
+		    <!-- strip characters -->
+		  </axsl:template>
+		  
+		  <!-- DPC introduce context-xpath variable -->
+		  <axsl:template match="@*|node()"
+				 priority="-2"
+				 mode="M{ count(preceding-sibling::*) }">
+		    <axsl:apply-templates select="{$context-xpath}" mode="M{count(preceding-sibling::*)}"/>
+		  </axsl:template>
+		</xsl:if>
+      </xsl:if>
+	</xsl:template>
+
+	<!-- ISO PHASE -->
+	<xsl:template match="iso:phase" >
+                <xsl:if test="not(@id)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">29</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+		  <xsl:apply-templates/>
+	</xsl:template>
+	
+	
+	<!-- PROPERTY Experiemental -->
+	<!-- We use a mode here to maintain backwards compatability, instead of adding it
+	     to the other mode.
+	-->
+	<xsl:template match="iso:property" mode="check-property">
+              <xsl:if test="not(@id)">
+                    <xsl:message>No property found with that ID</xsl:message>
+               </xsl:if>
+    </xsl:template>
+    
+    <xsl:template match="iso:property"  >
+                <xsl:call-template name="process-property">
+                
+					<xsl:with-param name="id" select="@id"/>
+					
+					<xsl:with-param name="name"  select="@name"/>
+					<xsl:with-param name="value" select="@value" />
+					<xsl:with-param name="contents" select="*|text()" />
+				</xsl:call-template>   
+            
+        </xsl:template>
+
+	<!-- PROPERTIES  experimental extension -->
+	<xsl:template match="iso:properties" >
+		 <xsl:apply-templates mode="check-properties" select="property" /> 
+	</xsl:template>
+	
+	
+
+	<!-- ISO RULE -->
+	<xsl:template match="iso:rule[not(@abstract='true')] ">
+                <xsl:if test="not(@context)">
+                    <xsl:message ><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">30</xsl:with-param></xsl:call-template></xsl:message>
+                    <xsl:message terminate="yes" />
+                </xsl:if>
+        <xsl:text>

	</xsl:text>
+		<xsl:comment>RULE <xsl:value-of select="@id" /> </xsl:comment><xsl:text>
</xsl:text>   
+        <xsl:if test="iso:title">
+		    <xsl:comment><xsl:value-of select="iso:title" /></xsl:comment>
+		  </xsl:if>
+		<!-- DPC select-contexts -->
+		<xsl:if test="$select-contexts='key'">
+		    <axsl:key name="M"
+			      match="{@context}" 
+			      use="'M{count(../preceding-sibling::*)}'"/>
+		</xsl:if>
+   
+	
+<!-- DPC priorities count up from 1000 not down from 4000 (templates in same priority order as before) -->
+		<axsl:template match="{@context}"
+		priority="{1000 + count(following-sibling::*)}" mode="M{count(../preceding-sibling::*)}">
+		 
+			<xsl:call-template name="process-rule">
+				<xsl:with-param name="context" select="@context"/>
+				
+					<xsl:with-param name="properties" select="@properties" />
+					
+					<!-- "Rich" properties -->
+					<xsl:with-param name="fpi" select="@fpi"/>
+					<xsl:with-param name="icon" select="@icon"/>
+					<xsl:with-param name="id" select="@id"/>
+					<xsl:with-param name="lang" select="@xml:lang"/>
+					<xsl:with-param name="see" select="@see" />
+					<xsl:with-param name="space" select="@xml:space" />
+					
+					<!-- "Linking" properties -->
+					<xsl:with-param name="role" select="@role" />
+					<xsl:with-param name="subject" select="@subject" />
+			</xsl:call-template>
+			 
+				
+			<xsl:apply-templates/>
+			<!-- DPC introduce context-xpath and select-contexts variables -->
+			<xsl:if test="not($select-contexts)">
+			  <axsl:apply-templates select="{$context-xpath}" mode="M{count(../preceding-sibling::*)}"/>
+			</xsl:if>
+		</axsl:template>
+	</xsl:template>
+
+
+	<!-- ISO ABSTRACT RULE -->
+	<xsl:template match="iso:rule[@abstract='true'] " >
+		<xsl:if test=" not(@id)">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">31</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+ 		<xsl:if test="@context">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">32</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+	</xsl:template>
+
+	<xsl:template match="iso:rule[@abstract='true']"
+		mode="extends" >
+                <xsl:if test="@context">
+                    <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">33</xsl:with-param></xsl:call-template></xsl:message>
+                </xsl:if>
+			<xsl:apply-templates/>
+	</xsl:template>
+
+	<!-- ISO SPAN -->
+	<xsl:template match="iso:span" mode="text">
+		<xsl:call-template name="process-span">
+			<xsl:with-param name="class" select="@class"/>
+		</xsl:call-template>
+	</xsl:template>
+
+	<!-- ISO TITLE -->
+	
+	<xsl:template match="iso:schema/iso:title"  priority="1">
+	     <xsl:call-template name="process-schema-title" />
+	</xsl:template>
+ 
+	
+	<xsl:template match="iso:title" >
+	     <xsl:call-template name="process-title" />
+	</xsl:template>
+ 
+
+	<!-- ISO VALUE-OF -->
+	<xsl:template match="iso:value-of" mode="text" >
+        <xsl:if test="not(@select)">
+            <xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">34</xsl:with-param></xsl:call-template></xsl:message>
+        </xsl:if>
+	    <xsl:call-template name="IamEmpty" />
+	         
+		<xsl:choose>
+			<xsl:when test="@select">
+				<xsl:call-template name="process-value-of">
+					<xsl:with-param name="select" select="@select"/>  
+				</xsl:call-template>
+			</xsl:when>
+			<xsl:otherwise >
+				<xsl:call-template name="process-value-of">
+					<xsl:with-param name="select" select="'.'"/>
+				</xsl:call-template>
+			</xsl:otherwise>
+        </xsl:choose> 
+        
+	</xsl:template>
+
+
+<!-- ============================================================== -->
+<!-- DEFAULT TEXT HANDLING  -->
+<!-- ============================================================== -->
+	<xsl:template match="text()" priority="-1" mode="do-keys">
+		<!-- strip characters -->
+	</xsl:template>
+	<xsl:template match="text()" priority="-1" mode="do-all-patterns">
+		<!-- strip characters -->
+	</xsl:template>
+        <xsl:template match="text()" priority="-1" mode="do-schema-p">
+		<!-- strip characters -->
+	</xsl:template>
+        <xsl:template match="text()" priority="-1" mode="do-pattern-p">
+		<!-- strip characters -->
+	</xsl:template>
+	
+	<xsl:template match="text()" priority="-1">
+		<!-- Strip characters -->
+	</xsl:template>
+	
+	<xsl:template match="text()" mode="text">
+		<xsl:value-of select="."/>
+	</xsl:template>
+
+	<xsl:template match="text()" mode="inline-text">
+		<xsl:value-of select="."/>
+	</xsl:template>
+
+<!-- ============================================================== -->
+<!-- UTILITY TEMPLATES -->
+<!-- ============================================================== -->
+<xsl:template name="IamEmpty">
+	<xsl:if test="count( * )">
+		<xsl:message>
+			<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">35a</xsl:with-param></xsl:call-template>
+			<xsl:value-of select="name(.)"/>
+			<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">35b</xsl:with-param></xsl:call-template>
+		</xsl:message>
+	</xsl:if>
+</xsl:template>
+
+<xsl:template name="diagnosticsSplit">
+  <!-- Process at the current point the first of the <diagnostic> elements
+       referred to parameter str, and then recurse -->
+  <xsl:param name="str"/>
+  <xsl:variable name="start">
+    <xsl:choose>
+      <xsl:when test="contains($str,' ')">
+	<xsl:value-of  select="substring-before($str,' ')"/>
+      </xsl:when>
+      <xsl:otherwise><xsl:value-of select="$str"/></xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="end">
+    <xsl:if test="contains($str,' ')">
+      <xsl:value-of select="substring-after($str,' ')"/>
+    </xsl:if>
+  </xsl:variable>
+
+  <!-- This works with all namespaces -->
+  <xsl:if test="not(string-length(normalize-space($start)) = 0)
+  		and not(//iso:diagnostic[@id = $start])
+		and not(//schold:diagnostic[@id = $start]) 
+		and not(//diagnostic[@id = $start])">
+	<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">36a</xsl:with-param></xsl:call-template>
+	<xsl:value-of select="string($start)"/>
+	<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">36b</xsl:with-param></xsl:call-template></xsl:message>
+  </xsl:if>
+
+  <xsl:if test="string-length(normalize-space($start)) > 0">
+     <xsl:text> </xsl:text>
+     <xsl:apply-templates 
+        select="//iso:diagnostic[@id = $start ]
+        	| //schold:diagnostic[@id = $start ] 
+            | //diagnostic[@id= $start ]"/>
+  </xsl:if>
+
+  <xsl:if test="not($end='')">
+    <xsl:call-template name="diagnosticsSplit">
+      <xsl:with-param name="str" select="$end"/>
+    </xsl:call-template>
+  </xsl:if>
+</xsl:template>
+
+
+
+<xsl:template name="propertiesSplit">
+  <!-- Process at the current point the first of the <property> elements
+       referred to parameter str, and then recurse -->
+  <xsl:param name="str"/>
+  <xsl:variable name="start">
+    <xsl:choose>
+      <xsl:when test="contains($str,' ')">
+	<xsl:value-of  select="substring-before($str,' ')"/>
+      </xsl:when>
+      <xsl:otherwise><xsl:value-of select="$str"/></xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="end">
+    <xsl:if test="contains($str,' ')">
+      <xsl:value-of select="substring-after($str,' ')"/>
+    </xsl:if>
+  </xsl:variable>
+
+  <!-- This works with all namespaces -->
+  <xsl:if test="not(string-length(normalize-space($start)) = 0)
+  		and not(//iso:property[@id = $start])">
+	<xsl:message><xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">36a</xsl:with-param></xsl:call-template>
+	<xsl:value-of select="string($start)"/>
+	<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">36b</xsl:with-param></xsl:call-template></xsl:message>
+  </xsl:if>
+
+  <xsl:if test="string-length(normalize-space($start)) > 0">
+     <xsl:text> </xsl:text>
+     <xsl:apply-templates 
+        select="//iso:property[@id = $start ] "/>
+  </xsl:if>
+
+  <xsl:if test="not($end='')">
+    <xsl:call-template name="propertiesSplit">
+      <xsl:with-param name="str" select="$end"/>
+    </xsl:call-template>
+  </xsl:if>
+</xsl:template>
+
+
+<!-- It would be nice to use this but xsl:namespace does not
+  allow a fallback -->
+<!--xsl:template name="handle-namespace" version="2.0">
+   <xsl:namespace name="{@prefix}" select="@uri">
+</xsl:template-->
+
+<xsl:template name="handle-namespace">
+       <!-- experimental code from http://eccnet.eccnet.com/pipermail/schematron-love-in/2006-June/000104.html -->
+       <!-- Handle namespaces differently for exslt systems,   and default, only using XSLT1 syntax -->
+       <!-- For more info see  http://fgeorges.blogspot.com/2007/01/creating-namespace-nodes-in-xslt-10.html -->
+       <xsl:choose>
+   	<!-- The following code workds for XSLT2 -->
+         <xsl:when test="element-available('xsl:namespace')">
+             <xsl:namespace name="{@prefix}" select="@uri" />
+	 </xsl:when>
+ 
+	 <xsl:when use-when="not(element-available('xsl:namespace'))" 
+		   test="function-available('exsl:node-set')">
+           <xsl:variable name="ns-dummy-elements">
+             <xsl:element name="{@prefix}:dummy" namespace="{@uri}"/>
+           </xsl:variable>
+       	   <xsl:variable name="p" select="@prefix"/>
+           <xsl:copy-of select="exsl:node-set($ns-dummy-elements)
+                                  /*/namespace::*[local-name()=$p]"/>
+         </xsl:when>
+
+	<!-- end XSLT2 code -->
+
+        
+        <xsl:when test="@prefix = 'xsl' ">
+           <!-- Do not generate dummy attributes with the xsl: prefix, as these
+                are errors against XSLT, because we presume that the output
+                stylesheet uses the xsl prefix. In any case, there would already
+                be a namespace declaration for the XSLT namespace generated
+                automatically, presumably using "xsl:".
+           -->
+        </xsl:when>
+        
+        <xsl:when test="@uri = 'http://www.w3.org/1999/XSL/Transform'">
+          <xsl:message terminate="yes">
+            <xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">37a</xsl:with-param></xsl:call-template>
+            <xsl:value-of select="system-property('xsl:vendor')"/>
+            <xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">37b</xsl:with-param></xsl:call-template>
+          </xsl:message>
+        </xsl:when>
+
+        <xsl:otherwise>
+          <xsl:attribute name="{concat(@prefix,':dummy-for-xmlns')}" namespace="{@uri}" />
+           
+        </xsl:otherwise>
+      </xsl:choose>
+
+
+</xsl:template>
+
+<!-- ============================================================== -->
+<!-- UNEXPECTED ELEMENTS -->
+<!-- ============================================================== -->
+
+	<xsl:template match="iso:*"  priority="-2">
+	   <xsl:message>
+			<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">38a</xsl:with-param></xsl:call-template>
+			<xsl:value-of select="name(.)"/>
+			<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">38b</xsl:with-param></xsl:call-template>
+		</xsl:message>
+	</xsl:template>
+	
+	
+	<!-- Swallow old namespace elements: there is an upfront test for them elsewhere -->
+	<xsl:template match="schold:*"  priority="-2" />
+	 
+	<xsl:template match="*"  priority="-3">
+	    <xsl:choose>
+	       <xsl:when test=" $allow-foreign = 'false' ">
+				<xsl:message>
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">39a</xsl:with-param></xsl:call-template>
+					<xsl:value-of select="name(.)"/>
+					<xsl:call-template name="outputLocalizedMessage" ><xsl:with-param name="number">39b</xsl:with-param></xsl:call-template>
+				</xsl:message>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:copy-of select="." />
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+	
+	<xsl:template match="iso:*" mode="text" priority="-2" />
+	<xsl:template match="*" mode="text" priority="-3">
+	    <xsl:if test=" not( $allow-foreign = 'false') "> 
+				<xsl:copy-of select="." />
+		</xsl:if>
+	</xsl:template>
+
+<!-- ============================================================== -->
+<!-- DEFAULT NAMED TEMPLATES -->
+<!-- These are the actions that are performed unless overridden -->
+<!-- ============================================================== -->
+ 
+	<xsl:template name="process-prolog"/>
+	<!-- no params -->
+
+	<xsl:template name="process-root">
+		<xsl:param name="contents"/>
+		<xsl:param name="id" />
+		<xsl:param name="version" />
+		<xsl:param name="schemaVersion" />
+		<xsl:param name="queryBinding" />
+		<xsl:param name="title" />
+
+
+		<!-- "Rich" parameters -->
+		<xsl:param name="fpi" />
+		<xsl:param name="icon" />
+		<xsl:param name="lang" />
+		<xsl:param name="see" />
+		<xsl:param name="space" />
+
+		<xsl:copy-of select="$contents"/>
+	</xsl:template>
+
+	<xsl:template name="process-assert">
+
+		<xsl:param name="test"/>
+		<xsl:param name="diagnostics" />
+		<xsl:param name="id" />
+		<xsl:param name="flag" />
+		<xsl:param name="properties" />
+
+           	<!-- "Linkable" parameters -->
+		<xsl:param name="role"/>
+		<xsl:param name="subject"/>
+
+		<!-- "Rich" parameters -->
+		<xsl:param name="fpi" />
+		<xsl:param name="icon" />
+		<xsl:param name="lang" />
+		<xsl:param name="see" />
+		<xsl:param name="space" />
+
+
+		<xsl:call-template name="process-message">
+			<xsl:with-param name="pattern" select="$test"/>
+			<xsl:with-param name="role" select="$role"/>
+		</xsl:call-template>
+		
+		
+	</xsl:template>
+
+	<xsl:template name="process-report">
+		<xsl:param name="test"/>
+		<xsl:param name="diagnostics" />
+		<xsl:param name="id" />
+		<xsl:param name="flag" />
+		<xsl:param name="properties" />
+
+           	<!-- "Linkable" parameters -->
+		<xsl:param name="role"/>
+		<xsl:param name="subject"/>
+
+		<!-- "Rich" parameters -->
+		<xsl:param name="fpi" />
+		<xsl:param name="icon" /> 
+		<xsl:param name="lang" />
+		<xsl:param name="see" />
+		<xsl:param name="space" />
+
+		<xsl:call-template name="process-message">
+			<xsl:with-param name="pattern" select="$test"/>
+			<xsl:with-param name="role" select="$role"/>
+		</xsl:call-template>
+	</xsl:template>
+
+	<xsl:template name="process-diagnostic">
+		<xsl:param name="id" />
+
+		<!-- "Rich" parameters -->
+		<xsl:param name="fpi" />
+		<xsl:param name="icon" />
+		<xsl:param name="lang" />
+		<xsl:param name="see" />
+		<xsl:param name="space" />
+		
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="text"/>
+		<axsl:text> </axsl:text>
+	</xsl:template>
+
+	<xsl:template name="process-dir">
+      	<xsl:param name="value" />
+
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="inline-text"/>
+		<axsl:text> </axsl:text>
+	</xsl:template>
+
+	<xsl:template name="process-emph"> 
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="inline-text"/>
+		<axsl:text> </axsl:text>
+	</xsl:template>
+	
+	<xsl:template name="process-name">
+		<xsl:param name="name"/>
+		
+		<!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<axsl:value-of select="{$name}"/>
+		<axsl:text> </axsl:text>
+		
+    </xsl:template>
+
+	<xsl:template name="process-ns" >
+	<!-- Note that process-ns is for reporting. The iso:ns elements are 
+	     independently used in the iso:schema template to provide namespace bindings -->
+		<xsl:param name="prefix"/>
+		<xsl:param name="uri" />
+      </xsl:template>
+
+	<xsl:template name="process-p">
+		<xsl:param name="id" />
+		<xsl:param name="class" />
+		<xsl:param name="icon" />
+		<xsl:param name="lang" />
+      </xsl:template>
+
+	<xsl:template name="process-pattern">
+		<xsl:param name="id" />
+		<xsl:param name="name" />
+		<xsl:param name="is-a" />
+
+		<!-- "Rich" parameters -->
+		<xsl:param name="fpi" />
+		<xsl:param name="icon" />
+		<xsl:param name="lang" />
+		<xsl:param name="see" />
+		<xsl:param name="space" />
+      </xsl:template>
+      
+
+	<xsl:template name="process-rule">
+		<xsl:param name="context" />
+
+		<xsl:param name="id" />
+		<xsl:param name="flag" />
+		<xsl:param name="properties" />
+
+           	<!-- "Linkable" parameters -->
+		<xsl:param name="role"/>
+		<xsl:param name="subject"/>
+  
+		<!-- "Rich" parameters -->
+		<xsl:param name="fpi" />
+		<xsl:param name="icon" />
+		<xsl:param name="lang" />
+		<xsl:param name="see" />
+		<xsl:param name="space" />
+      </xsl:template>
+
+	<xsl:template name="process-span" >
+		<xsl:param name="class" />
+
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="inline-text"/>
+		<axsl:text> </axsl:text>		
+	</xsl:template>
+
+	<xsl:template name="process-title" >
+		<xsl:param name="class" />
+	   <xsl:call-template name="process-p">
+	      <xsl:with-param  name="class">title</xsl:with-param>
+	   </xsl:call-template>
+	</xsl:template>
+		
+	<xsl:template name="process-schema-title" >
+		<xsl:param name="class" />
+	   <xsl:call-template name="process-title">
+	      <xsl:with-param  name="class">schema-title</xsl:with-param>
+	   </xsl:call-template>
+	</xsl:template>
+
+	<xsl:template name="process-value-of">
+		<xsl:param name="select"/>
+		
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<axsl:value-of select="{$select}"/>
+		<axsl:text> </axsl:text>
+	</xsl:template>
+
+	<!-- default output action: the simplest customization is to just override this -->
+	<xsl:template name="process-message">
+		<xsl:param name="pattern" />
+            <xsl:param name="role" />
+
+		<xsl:apply-templates mode="text"/>	
+		 <xsl:if test=" $message-newline = 'true'" >
+			<axsl:value-of  select="string('
')"/>
+		</xsl:if>
+		
+	</xsl:template>
+	
+	
+	<!-- ===================================================== -->
+	<!-- Extension API: default rules 			               -->
+	<!-- This allows the transmission of extra attributes on   -->
+	<!-- rules, asserts, reports, diagnostics.                 -->
+	<!-- ===================================================== -->
+	
+ 
+
+	<xsl:template name="process-property">
+		<xsl:param name="id" />
+		
+		<xsl:param name="name"/>
+		<xsl:param name="value"/>
+		<xsl:param name="contents"/>
+		  
+	</xsl:template>
+	
+	
+	<!-- ===================================================== -->
+	<!-- Localization 						                  -->
+	<!-- ===================================================== -->
+	<!--
+		All messages generated by the skeleton during processing are localized.
+		(This does not apply to the text that comes from Schematron schemas
+		themselves, of course. Nor does it apply to messages in metastylesheets.)
+		
+		Stylesheets have a parameter $langCode which can be used to select the
+		language code (e.g. from the command line)
+		
+		The default value of $langCode is "default". When this is used, the
+		message text is taken from the strings below. We use XHTML, to provide
+		the namespace. 
+		
+		If the $langCode is somethign else, then the XSLT engine will try to
+		find a file called  sch-messages-$langCode.xhtml in the same directory
+		as this stylesheet. Expect a fatal error if the file does not exist.
+		
+		The file should contain XHTML elements, with the text translated.
+		The strings are located by using ids on each xhtml:p element.
+		The ids are formed by sch-message-$number-$langCode such as  
+		sch-message-1-en
+		
+		If there is no match in a localization file for a message, then the
+		default will be used. This allows this XSLT to be developed with new
+		messages added without requiring that any localization files be updated.
+		
+		In many cases, there are actually two localization strings per message.
+		This happens whenever a message has an embedded value that is dynamically
+		generated (using <value-of>). Having two strings, preceding and following,
+		allows the translator to make idiomatic error messages. When there are
+		two message for a single message, they have numbers like 30a and 30b: 
+		translators should check the reference to them in the XSLT above to
+		see what the dynamically generated information is.  
+	-->
+	<xsl:template name="outputLocalizedMessage">
+		<xsl:param name="number" />  
+		 
+		<xsl:choose>
+		   <xsl:when test="string-length( $langCode ) = 0 or $langCode = 'default'" > 	   	 
+				<xsl:value-of select='document("iso_schematron_skeleton_for_saxon.xsl")//xhtml:p[@id=concat("sch-message-", $number)]/text()' />
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:variable name="localizationDocumentFilename" >
+					<xsl:value-of select="concat('sch-messages-', $langCode, '.xhtml')" />
+				</xsl:variable>
+				<xsl:variable name="theLocalizedMessage" >
+					<xsl:value-of select=
+				'document( $localizationDocumentFilename, /)//xhtml:p[@id=concat("sch-message-", $number, "-", $langCode)]/text()' />
+				</xsl:variable>
+				
+				<xsl:choose>
+					<!-- if we found any external message with that id, use it -->
+					<xsl:when test=" string-length($theLocalizedMessage) > 0">
+						<xsl:value-of select="$theLocalizedMessage" />
+					</xsl:when>
+					<xsl:otherwise>
+						<!-- otherwise use the default strings -->		
+						<xsl:value-of select='document("")//xhtml:p[@id=concat("sch-message-", $number)]/text()' />
+					</xsl:otherwise>
+				</xsl:choose>	
+				
+				 
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+	
+<xhtml:div class="ErrorMessages">	
+	<!-- Where the error message contains dynamic information, the message has been split into an "a" and a "b" section.
+	     This has been done even when the English does not require it, in order to accomodate different language grammars
+	     that might position the dynamic information differently.
+	-->
+	<xhtml:p id="sch-message-1">Schema error: Schematron elements in old and new namespaces found</xhtml:p>
+	<xhtml:p id="sch-message-2">Schema error: in the queryBinding attribute, use 'xslt'</xhtml:p>
+	<xhtml:p id="sch-message-3a">Fail: This implementation of ISO Schematron does not work with schemas using the query language </xhtml:p>
+	<xhtml:p id="sch-message-3b"/>
+	<xhtml:p id="sch-message-4a">Phase Error: no phase has been defined with name </xhtml:p>
+	<xhtml:p id="sch-message-4b" />
+	<xhtml:p id="sch-message-5">Markup Error: no pattern attribute in <active></xhtml:p>
+	<xhtml:p id="sch-message-6a">Reference Error: the pattern  "</xhtml:p>
+	<xhtml:p id="sch-message-6b">" has been activated but is not declared</xhtml:p>
+	<xhtml:p id="sch-message-7">Markup Error: no test attribute in <assert</xhtml:p>
+	<xhtml:p id="sch-message-8">Markup Error: no test attribute in <report></xhtml:p>
+	<xhtml:p id="sch-message-9">Markup Error: no id attribute in <diagnostic></xhtml:p>
+	<xhtml:p id="sch-message-10">Markup Error: no rule attribute in <extends></xhtml:p>				   
+	<xhtml:p id="sch-message-11a">Reference Error: the abstract rule  "</xhtml:p>
+	<xhtml:p id="sch-message-11b">" has been referenced but is not declared</xhtml:p>				
+	<xhtml:p id="sch-message-12">Markup Error: no name attribute in <key></xhtml:p>
+	<xhtml:p id="sch-message-13">Markup Error: no path or use attribute in <key></xhtml:p>
+	<xhtml:p id="sch-message-14">Markup Error: no path or use attribute in <key></xhtml:p>
+	<xhtml:p id="sch-message-15">Schema error: The key element is not in the ISO Schematron namespace. Use the XSLT namespace.</xhtml:p>
+	<xhtml:p id="sch-message-16">Markup Error: no name attribute in <function></xhtml:p>
+	<xhtml:p id="sch-message-17">Schema error: The function element is not in the ISO Schematron namespace. Use the XSLT namespace.</xhtml:p>
+	<xhtml:p id="sch-message-18">Schema error: Empty href= attribute for include directive.</xhtml:p>
+	<xhtml:p id="sch-message-19">Error: Impossible URL in Schematron include</xhtml:p>
+	<xhtml:p id="sch-message-20a">Unable to open referenced included file: </xhtml:p>
+	<xhtml:p id="sch-message-20b" />
+	<xhtml:p id="sch-message-21">Schema error: Use include to include fragments, not a whole schema</xhtml:p>
+	<xhtml:p id="sch-message-22">Schema error: XSD schemas may only be imported if you are using the 'xslt2' query language binding</xhtml:p>
+	<xhtml:p id="sch-message-23">Schema error: The import-schema element is not available in the ISO Schematron namespace. Use the XSLT namespace.</xhtml:p>
+	<xhtml:p id="sch-message-24">Warning: Variables should not be used with the "xpath" query language binding.</xhtml:p>
+	<xhtml:p id="sch-message-25">Warning: Variables should not be used with the "xpath2" query language binding.</xhtml:p>
+	<xhtml:p id="sch-message-26">Markup Error: no uri attribute in <ns></xhtml:p>
+	<xhtml:p id="sch-message-27">Markup Error: no prefix attribute in <ns></xhtml:p>
+	<xhtml:p id="sch-message-28">Schema implementation error: This schema has abstract patterns, yet they are supposed to be preprocessed out already</xhtml:p>
+    <xhtml:p id="sch-message-29">Markup Error: no id attribute in <phase></xhtml:p>
+    <xhtml:p id="sch-message-30">Markup Error: no context attribute in <rule></xhtml:p>
+    <xhtml:p id="sch-message-31">Markup Error: no id attribute on abstract <rule></xhtml:p>
+    <xhtml:p id="sch-message-32">Markup Error: (2) context attribute on abstract <rule></xhtml:p>
+    <xhtml:p id="sch-message-33">Markup Error: context attribute on abstract <rule></xhtml:p>
+    <xhtml:p id="sch-message-34">Markup Error: no select attribute in <value-of></xhtml:p>
+    <xhtml:p id="sch-message-35a">Warning: </xhtml:p>
+	<xhtml:p id="sch-message-35b"> must not contain any child elements</xhtml:p>
+    <xhtml:p id="sch-message-36a">Reference error: A diagnostic "</xhtml:p>
+	<xhtml:p id="sch-message-36b">" has been referenced but is not declared</xhtml:p>
+	<xhtml:p id="sch-message-37a">Using the XSLT namespace with a prefix other than "xsl" in Schematron rules is not supported in this processor:</xhtml:p>
+    <xhtml:p id="sch-message-37b" />
+    <xhtml:p id="sch-message-38a">Error: unrecognized element in ISO Schematron namespace: check spelling and capitalization</xhtml:p>
+	<xhtml:p id="sch-message-38b" />
+	<xhtml:p id="sch-message-39a">Warning: unrecognized element </xhtml:p>
+	<xhtml:p id="sch-message-39b" />
+ </xhtml:div>
+</xsl:stylesheet>
+
+
+
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_svrl_for_xslt2.xsl b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_svrl_for_xslt2.xsl
new file mode 100644
index 0000000..b49cc84
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/iso_svrl_for_xslt2.xsl
@@ -0,0 +1,665 @@
+<?xml version="1.0" ?>
+<!-- 
+   ISO_SVRL.xsl   
+
+   Implementation of Schematron Validation Report Language from ISO Schematron
+   ISO/IEC 19757 Document Schema Definition Languages (DSDL) 
+     Part 3: Rule-based validation  Schematron 
+     Annex D: Schematron Validation Report Language 
+
+  This ISO Standard is available free as a Publicly Available Specification in PDF from ISO.
+  Also see www.schematron.com for drafts and other information.
+
+  This implementation of SVRL is designed to run with the "Skeleton" implementation 
+  of Schematron which Oliver Becker devised. The skeleton code provides a 
+  Schematron implementation but with named templates for handling all output; 
+  the skeleton provides basic templates for output using this API, but client
+  validators can be written to import the skeleton and override the default output
+  templates as required. (In order to understand this, you must understand that
+  a named template such as "process-assert" in this XSLT stylesheet overrides and
+  replaces any template with the same name in the imported skeleton XSLT file.)
+
+  The other important thing to understand in this code is that there are different
+  versions of the Schematron skeleton. These track the development of Schematron through
+  Schematron 1.5, Schematron 1.6 and now ISO Schematron. One only skeleton must be
+  imported. The code has templates for the different skeletons commented out for 
+  convenience. ISO Schematron has a different namespace than Schematron 1.5 and 1.6;
+  so the ISO Schematron skeleton has been written itself with an optional import
+  statement to in turn import the Schematron 1.6 skeleton. This will allow you to 
+  validate with schemas from either namespace.
+  
+
+  History: 
+    2009-03-18
+    	* Fix atrribute with space "see " which generates wrong name in some processors
+    	* rename allow-foreign to allow-rich
+  
+    2009-02-19
+    	* RJ add experimental non-standard attribute active-pattern/@document which says which
+    	document is being validated from that point to the next similar. This is to cope with the
+    	experimental multi-document validation in the XSLT2 skeleton.
+    2008-08-19
+  		* RJ Experimental: Handle property elements. NOTE: signature change for process-assert,
+  		process-report and process-rule to add property.
+  	2008-08-11
+   		* RJ Fix attribute/@select which saxon allows  in XSLT 1
+   2008-08-07
+    	* RJ Add output-encoding attribute to specify final encoding to use
+    	* Alter allow-foreign functionality so that Schematron span, emph and dir elements make 
+    	  it to the output, for better formatting and because span can be used to mark up
+    	  semantically interesting information embedded in diagnostics, which reduces the
+    	  need to extend SVRL itself
+    	* Diagnostic-reference had an invalid attribute @id that duplicated @diagnostic: removed
+  	2008-08-06
+    	* RJ Fix invalid output:  svrl:diagnostic-reference is not contained in an svrl:text
+    	* Output comment to SVRL file giving filename if available (from command-line parameter)
+  	2008-08-04
+  		* RJ move sch: prefix to schold: prefix to prevent confusion (we want people to
+  		be able to switch from old namespace to new namespace without changing the
+  		sch: prefix, so it is better to keep that prefix completely out of the XSLT)
+  		* Extra signature fixes (PH)
+    2008-08-03
+    	* Repair missing class parameter on process-p
+    2008-07-31
+    	* Update skeleton names
+    2007-04-03 
+    	* Add option generate-fired-rule (RG)
+    2007-02-07
+    	* Prefer true|false for parameters. But allow yes|no on some old for compatability
+    	* DP Diagnostics output to svrl:text. Diagnosis put out after assertion text.
+      	* Removed non-SVRL elements and attributes: better handled as an extra layer that invokes this one
+      	* Add more formal parameters
+      	* Correct confusion between $schemaVersion and $queryBinding
+     	* Indent
+     	* Validate against RNC schemas for XSLT 1 and 2 (with regex tests removed)
+     	* Validate output with UniversalTest.sch against RNC schema for ISO SVRL
+    	
+    2007-02-01
+       	* DP. Update formal parameters of overriding named templates to handle more attributes.
+       	* DP. Refactor handling of rich and linkable parameters to a named template.
+
+    2007-01-22
+    	* DP change svrl:ns to svrl:ns-in-attribute-value
+		* Change default when no queryBinding from "unknown" to "xslt"
+	
+    2007-01-18:
+     	* Improve documentation
+     	* KH Add command-line options to generate paths or not 
+       	* Use axsl:attribute rather than xsl:attribute to shut XSLT2 up
+       	* Add extra command-line options to pass to the iso_schematron_skeleton
+  
+    2006-12-01: iso_svrl.xsl Rick Jelliffe, 
+          * update namespace, 
+          * update phase handling,
+          * add flag param to process-assert and process-report & @ flag on output
+  
+    2001: Conformance1-5.xsl Rick Jelliffe, 
+          * Created, using the skeleton code contributed by Oliver Becker
+-->
+<!--
+ Derived from Conformance1-5.xsl.
+
+ Copyright (c) 2001, 2006 Rick Jelliffe and Academia Sinica Computing Center, Taiwan
+
+ This software is provided 'as-is', without any express or implied warranty. 
+ In no event will the authors be held liable for any damages arising from 
+ the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose, 
+ including commercial applications, and to alter it and redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not claim
+ that you wrote the original software. If you use this software in a product, 
+ an acknowledgment in the product documentation would be appreciated but is 
+ not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be 
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+-->
+
+<!-- Ideas nabbed from schematrons by Francis N., Miloslav N. and David C. -->
+
+<!-- The command-line parameters are:
+  			phase           NMTOKEN | "#ALL" (default) Select the phase for validation
+    		allow-foreign   "true" | "false" (default)   Pass non-Schematron elements and rich markup to the generated stylesheet 
+            diagnose= true | false|yes|no    Add the diagnostics to the assertion test in reports (yes|no are obsolete)
+            property= true | false           Experimental: Add properties to the assertion test in reports  
+            generate-paths=true|false|yes|no   generate the @location attribute with XPaths (yes|no are obsolete)
+            sch.exslt.imports semi-colon delimited string of filenames for some EXSLT implementations          
+   		 optimize        "visit-no-attributes"     Use only when the schema has no attributes as the context nodes
+		 generate-fired-rule "true"(default) | "false"  Generate fired-rule elements
+            
+-->
+
+<xsl:stylesheet
+   version="1.0"
+   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+   xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
+   xmlns:schold="http://www.ascc.net/xml/schematron" 
+   xmlns:iso="http://purl.oclc.org/dsdl/schematron"
+   xmlns:svrl="http://purl.oclc.org/dsdl/svrl" 
+    
+>
+
+<!-- Select the import statement and adjust the path as 
+   necessary for your system.
+-->
+<xsl:import href="iso_schematron_skeleton_for_saxon.xsl"/>
+ 
+ <!--
+<xsl:import href="iso_schematron_skeleton_for_xslt1.xsl"/>
+ 
+<xsl:import href="iso_schematron_skeleton.xsl"/>
+<xsl:import href="skeleton1-5.xsl"/>
+<xsl:import href="skeleton1-6.xsl"/>
+-->
+
+<xsl:param name="diagnose">true</xsl:param>
+<xsl:param name="property">true</xsl:param>
+<xsl:param name="phase">
+	<xsl:choose>
+		<!-- Handle Schematron 1.5 and 1.6 phases -->
+		<xsl:when test="//schold:schema/@defaultPhase">
+			<xsl:value-of select="//schold:schema/@defaultPhase"/>
+		</xsl:when>
+		<!-- Handle ISO Schematron phases -->
+		<xsl:when test="//iso:schema/@defaultPhase">
+			<xsl:value-of select="//iso:schema/@defaultPhase"/>
+		</xsl:when>
+		<xsl:otherwise>#ALL</xsl:otherwise>
+	</xsl:choose>
+</xsl:param>
+<xsl:param name="allow-foreign">false</xsl:param>
+<xsl:param name="generate-paths">true</xsl:param>
+<xsl:param name="generate-fired-rule">true</xsl:param>
+<xsl:param name="optimize" />
+<!-- e.g. saxon file.xml file.xsl "sch.exslt.imports=.../string.xsl;.../math.xsl" -->
+<xsl:param name="sch.exslt.imports" />
+
+<!-- Set the language code for messages -->
+<xsl:param name="langCode">default</xsl:param>
+ 
+<xsl:param name="output-encoding"/>
+
+<!-- Set the default for schematron-select-full-path, i.e. the notation for svrl's @location-->
+<xsl:param name="full-path-notation">1</xsl:param>
+
+
+
+<!-- Experimental: If this file called, then must be generating svrl -->
+<xsl:variable name="svrlTest" select="true()" />
+
+  
+ 
+<!-- ================================================================ -->
+
+<xsl:template name="process-prolog">
+	<axsl:output method="xml" omit-xml-declaration="no" standalone="yes"
+		indent="yes">
+		<xsl:if test=" string-length($output-encoding) > 0">
+			<xsl:attribute name="encoding"><xsl:value-of select=" $output-encoding" /></xsl:attribute>
+		</xsl:if>
+    </axsl:output>
+     
+</xsl:template>
+
+<!-- Overrides skeleton.xsl -->
+<xsl:template name="process-root">
+	<xsl:param name="title"/>
+	<xsl:param name="contents" />
+	<xsl:param name="queryBinding" >xslt1</xsl:param>
+	<xsl:param name="schemaVersion" />
+	<xsl:param name="id" />
+	<xsl:param name="version"/>
+	<!-- "Rich" parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	
+	<svrl:schematron-output title="{$title}" schemaVersion="{$schemaVersion}" >
+		<xsl:if test=" string-length( normalize-space( $phase )) > 0 and 
+		not( normalize-space( $phase ) = '#ALL') ">
+			<axsl:attribute name="phase">
+				<xsl:value-of select=" $phase " />
+			</axsl:attribute>
+		</xsl:if> 
+		
+		 <axsl:comment><axsl:value-of select="$archiveDirParameter"/>  &#xA0;
+		 <axsl:value-of select="$archiveNameParameter"/> &#xA0;
+		 <axsl:value-of select="$fileNameParameter"/> &#xA0;
+		 <axsl:value-of select="$fileDirParameter"/></axsl:comment> 
+		 
+		
+		<xsl:apply-templates mode="do-schema-p" />
+		<xsl:copy-of select="$contents" />
+	</svrl:schematron-output>
+</xsl:template>
+
+
+<xsl:template name="process-assert">
+	<xsl:param name="test"/>
+	<xsl:param name="diagnostics" />
+	<xsl:param name="properties" />
+	<xsl:param name="id" />
+	<xsl:param name="flag" />
+	<!-- "Linkable" parameters -->
+	<xsl:param name="role"/>
+	<xsl:param name="subject"/>
+	<!-- "Rich" parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	<svrl:failed-assert test="{$test}" >
+		<xsl:if test="string-length( $id ) > 0">
+			<axsl:attribute name="id">
+				<xsl:value-of select=" $id " />
+			</axsl:attribute>
+		</xsl:if>
+		<xsl:if test=" string-length( $flag ) > 0">
+			<axsl:attribute name="flag">
+				<xsl:value-of select=" $flag " />
+			</axsl:attribute>
+		</xsl:if>
+		<!-- Process rich attributes.  -->
+		<xsl:call-template name="richParms">
+			<xsl:with-param name="fpi" select="$fpi"/>
+			<xsl:with-param name="icon" select="$icon"/>
+			<xsl:with-param name="lang" select="$lang"/>
+			<xsl:with-param name="see" select="$see" />
+			<xsl:with-param name="space" select="$space" />
+		</xsl:call-template>
+		<xsl:call-template name='linkableParms'>
+			<xsl:with-param name="role" select="$role" />
+			<xsl:with-param name="subject" select="$subject"/>
+		</xsl:call-template>
+		<xsl:if test=" $generate-paths = 'true' or $generate-paths= 'yes' ">
+			<!-- true/false is the new way -->
+			<axsl:attribute name="location">
+				<axsl:apply-templates select="." mode="schematron-select-full-path"/>
+			</axsl:attribute>
+		</xsl:if>
+		  
+		<svrl:text>
+			<xsl:apply-templates mode="text" />
+	
+		</svrl:text>
+		    <xsl:if test="$diagnose = 'yes' or $diagnose= 'true' ">
+			<!-- true/false is the new way -->
+				<xsl:call-template name="diagnosticsSplit">
+					<xsl:with-param name="str" select="$diagnostics"/>
+				</xsl:call-template>
+			</xsl:if>
+			
+			
+		    <xsl:if test="$property= 'yes' or $property= 'true' ">
+			<!-- true/false is the new way -->
+				<xsl:call-template name="propertiesSplit">
+					<xsl:with-param name="str" select="$properties"/>
+				</xsl:call-template>
+			</xsl:if>
+			
+	</svrl:failed-assert>
+</xsl:template>
+
+<xsl:template name="process-report">
+	<xsl:param name="id"/>
+	<xsl:param name="test"/>
+	<xsl:param name="diagnostics"/>
+	<xsl:param name="flag" />
+	<xsl:param name="properties"/>
+	<!-- "Linkable" parameters -->
+	<xsl:param name="role"/>
+	<xsl:param name="subject"/>
+	<!-- "Rich" parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	<svrl:successful-report test="{$test}" >
+		<xsl:if test=" string-length( $id ) > 0">
+			<axsl:attribute name="id">
+				<xsl:value-of select=" $id " />
+			</axsl:attribute>
+		</xsl:if>
+		<xsl:if test=" string-length( $flag ) > 0">
+			<axsl:attribute name="flag">
+				<xsl:value-of select=" $flag " />
+			</axsl:attribute>
+		</xsl:if>
+		
+		<!-- Process rich attributes.  -->
+		<xsl:call-template name="richParms">
+			<xsl:with-param name="fpi" select="$fpi"/>
+			<xsl:with-param name="icon" select="$icon"/>
+			<xsl:with-param name="lang" select="$lang"/>
+			<xsl:with-param name="see" select="$see" />
+			<xsl:with-param name="space" select="$space" />
+		</xsl:call-template>
+		<xsl:call-template name='linkableParms'>
+			<xsl:with-param name="role" select="$role" />
+			<xsl:with-param name="subject" select="$subject"/>
+		</xsl:call-template>
+		<xsl:if test=" $generate-paths = 'yes' or $generate-paths = 'true' ">
+			<!-- true/false is the new way -->
+			<axsl:attribute name="location">
+				<axsl:apply-templates select="." mode="schematron-select-full-path"/>
+			</axsl:attribute>
+		</xsl:if>
+	 
+		<svrl:text>
+			<xsl:apply-templates mode="text" />
+
+		</svrl:text>
+			<xsl:if test="$diagnose = 'yes' or $diagnose='true' ">
+			<!-- true/false is the new way -->
+				<xsl:call-template name="diagnosticsSplit">
+					<xsl:with-param name="str" select="$diagnostics"/>
+				</xsl:call-template>
+			</xsl:if>
+			
+			
+			<xsl:if test="$property = 'yes' or $property='true' ">
+			<!-- true/false is the new way -->
+				<xsl:call-template name="propertiesSplit">
+					<xsl:with-param name="str" select="$properties"/>
+				</xsl:call-template>
+			</xsl:if>
+			 
+			
+	</svrl:successful-report>
+</xsl:template>
+
+
+
+
+<xsl:template name="process-diagnostic">
+	<xsl:param name="id"/>
+	<!-- Rich parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	<svrl:diagnostic-reference diagnostic="{$id}" >
+		<!--xsl:if test="string($id)">
+			<xsl:attribute name="id">
+				<xsl:value-of select="$id"/>
+			</xsl:attribute>
+		</xsl:if-->
+		<xsl:call-template name="richParms">
+			<xsl:with-param name="fpi" select="$fpi"/>
+			<xsl:with-param name="icon" select="$icon"/>
+			<xsl:with-param name="lang" select="$lang"/>
+			<xsl:with-param name="see" select="$see" />
+			<xsl:with-param name="space" select="$space" />
+		</xsl:call-template> 
+<xsl:text>
+</xsl:text>
+ 
+		<xsl:apply-templates mode="text"/>
+		 
+	</svrl:diagnostic-reference>
+</xsl:template>
+
+
+    <!-- Overrides skeleton -->
+	<xsl:template name="process-dir" >
+		<xsl:param name="value" />
+        <xsl:choose>
+        	<xsl:when test=" $allow-foreign = 'true'">
+        		<xsl:copy-of select="."/>
+        	</xsl:when>
+       
+        <xsl:otherwise>
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="inline-text"/>
+		<axsl:text> </axsl:text>
+		</xsl:otherwise>
+		 </xsl:choose>		
+	</xsl:template>
+	
+	
+    <!-- Overrides skeleton -->
+	<xsl:template name="process-emph" >
+		<xsl:param name="class" />
+        <xsl:choose>
+        	<xsl:when test=" $allow-foreign = 'true'">
+        		<xsl:copy-of select="."/>
+        	</xsl:when> 
+        <xsl:otherwise>
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="inline-text"/>
+		<axsl:text> </axsl:text>
+		</xsl:otherwise>
+	 	</xsl:choose>	
+	</xsl:template>
+
+<xsl:template name="process-rule">
+	<xsl:param name="id"/>
+	<xsl:param name="context"/>
+	<xsl:param name="flag"/>
+	<xsl:param name="properties" />
+	<!-- "Linkable" parameters -->
+	<xsl:param name="role"/>
+	<xsl:param name="subject"/>
+	<!-- "Rich" parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	<xsl:if test=" $generate-fired-rule = 'true'">
+	<svrl:fired-rule context="{$context}" >
+		<xsl:if test=" string( $id )">
+			<xsl:attribute name="id">
+				<xsl:value-of select=" $id " />
+			</xsl:attribute>
+		</xsl:if>
+		<xsl:if test=" string-length( $role ) > 0">
+			<xsl:attribute name="role">
+				<xsl:value-of select=" $role " />
+			</xsl:attribute>
+		</xsl:if>
+		<!-- Process rich attributes.  -->
+		<xsl:call-template name="richParms">
+			<xsl:with-param name="fpi" select="$fpi"/>
+			<xsl:with-param name="icon" select="$icon"/>
+			<xsl:with-param name="lang" select="$lang"/>
+			<xsl:with-param name="see" select="$see" />
+			<xsl:with-param name="space" select="$space" />
+		</xsl:call-template>
+		
+		
+		    <xsl:if test="$property= 'yes' or $property= 'true' ">
+			<!-- true/false is the new way -->
+				<xsl:call-template name="propertiesSplit">
+					<xsl:with-param name="str" select="$properties"/>
+				</xsl:call-template>
+			</xsl:if>
+		
+	</svrl:fired-rule>
+</xsl:if>
+</xsl:template>
+
+<xsl:template name="process-ns">
+	<xsl:param name="prefix"/>
+	<xsl:param name="uri"/>
+	<svrl:ns-prefix-in-attribute-values uri="{$uri}" prefix="{$prefix}" />
+</xsl:template>
+
+<xsl:template name="process-p"> 
+	<xsl:param name="icon"/>
+	<xsl:param name="class"/>
+	<xsl:param name="id"/>
+	<xsl:param name="lang"/>
+	 
+	<svrl:text> 
+		<xsl:apply-templates mode="text"/>
+	</svrl:text>
+</xsl:template>
+
+<xsl:template name="process-pattern">
+	<xsl:param name="name"/>
+	<xsl:param name="id"/>
+	<xsl:param name="is-a"/>
+	
+	<!-- "Rich" parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	<svrl:active-pattern >
+	    <axsl:attribute name="document">
+	    	<axsl:value-of select="document-uri(/)" />
+	    </axsl:attribute><!-- If XSLT1 remove this -->
+		<xsl:if test=" string( $id )">
+			<axsl:attribute name="id">
+				<xsl:value-of select=" $id " />
+			</axsl:attribute>
+		</xsl:if>
+		<xsl:if test=" string( $name )">
+			<axsl:attribute name="name">
+				<xsl:value-of select=" $name " />
+			</axsl:attribute>
+		</xsl:if> 
+		 
+		<xsl:call-template name='richParms'>
+			<xsl:with-param name="fpi" select="$fpi"/>
+			<xsl:with-param name="icon" select="$icon"/>
+			<xsl:with-param name="lang" select="$lang"/>
+			<xsl:with-param name="see" select="$see" />
+			<xsl:with-param name="space" select="$space" />
+		</xsl:call-template>
+		
+		<!-- ?? report that this screws up iso:title processing  -->
+		<xsl:apply-templates mode="do-pattern-p"/>
+		<!-- ?? Seems that this apply-templates is never triggered DP -->
+		<axsl:apply-templates />
+	</svrl:active-pattern>
+</xsl:template>
+
+<!-- Overrides skeleton -->
+<xsl:template name="process-message" > 
+	<xsl:param name="pattern"/>
+	<xsl:param name="role"/>
+</xsl:template>
+
+
+    <!-- Overrides skeleton -->
+	<xsl:template name="process-span" >
+		<xsl:param name="class" />
+        <xsl:choose>
+        	<xsl:when test=" $allow-foreign = 'true'">
+        		<xsl:copy-of select="."/>
+        	</xsl:when> 
+        <xsl:otherwise>
+	    <!-- We generate too much whitespace rather than risking concatenation -->
+		<axsl:text> </axsl:text>
+		<xsl:apply-templates mode="inline-text"/>
+		<axsl:text> </axsl:text>
+		</xsl:otherwise>
+	 	</xsl:choose>	
+	</xsl:template>
+
+<!-- =========================================================================== -->
+<!-- processing rich parameters. -->
+<xsl:template name='richParms'>
+	<!-- "Rich" parameters -->
+	<xsl:param name="fpi" />
+	<xsl:param name="icon" />
+	<xsl:param name="lang" />
+	<xsl:param name="see" />
+	<xsl:param name="space" />
+	<!-- Process rich attributes.  -->
+	<xsl:if  test=" $allow-foreign = 'true'">
+	<xsl:if test="string($fpi)"> 
+		<axsl:attribute name="fpi">
+			<xsl:value-of select="$fpi "/>
+		</axsl:attribute>
+	</xsl:if>
+	<xsl:if test="string($icon)"> 
+		<axsl:attribute name="icon">
+			<xsl:value-of select="$icon"/>
+		</axsl:attribute>
+	</xsl:if>
+	<xsl:if test="string($see)"> 
+		<axsl:attribute name="see">
+			<xsl:value-of select="$see" />
+		</axsl:attribute>
+	</xsl:if>
+	</xsl:if>
+	<xsl:if test="string($space)">
+		<axsl:attribute name="xml:space">
+			<xsl:value-of select="$space"/>
+		</axsl:attribute>
+	</xsl:if>
+	<xsl:if test="string($lang)">
+		<axsl:attribute name="xml:lang">
+			<xsl:value-of select="$lang"/>
+		</axsl:attribute>
+	</xsl:if>
+</xsl:template>
+
+<!-- processing linkable parameters. -->
+<xsl:template name='linkableParms'>
+	<xsl:param name="role"/>
+	<xsl:param name="subject"/>
+	
+	<!-- ISO SVRL has a role attribute to match the Schematron role attribute -->
+	<xsl:if test=" string($role )">
+		<axsl:attribute name="role">
+			<xsl:value-of select=" $role " />
+		</axsl:attribute>
+	</xsl:if>
+	<!-- ISO SVRL does not have a subject attribute to match the Schematron subject attribute.
+       Instead, the Schematron subject attribute is folded into the location attribute -->
+</xsl:template>
+
+
+
+	<!-- ===================================================== -->
+	<!-- Extension API:              			               -->
+	<!-- This allows the transmission of extra attributes on   -->
+	<!-- rules, asserts, reports, diagnostics.                 -->
+	<!-- ===================================================== -->
+
+
+<!-- Overrides skeleton EXPERIMENTAL -->
+<!-- The $contents is for static contents, the $value is for dynamic contents -->
+<xsl:template name="process-property">
+	<xsl:param name="id"/>
+	<xsl:param name="name"/>
+	<xsl:param name="value"/>
+	<xsl:param name="contents"/>
+	
+	<svrl:property id="{$id}" >  
+		<xsl:if test="$name">
+			<xsl:attribute name="name"><xsl:value-of select="$name"/></xsl:attribute>
+		</xsl:if>
+		
+		<xsl:if test="$value">
+			<xsl:attribute name="value"><xsl:value-of select="$value"/></xsl:attribute>
+		</xsl:if>
+		
+		<xsl:if test="$contents">
+			<xsl:copy-of select="$contents"/>
+		</xsl:if> 
+		
+	</svrl:property>
+</xsl:template>
+
+
+</xsl:stylesheet>
+
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/messagedlg_warning.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/messagedlg_warning.png
new file mode 100644
index 0000000..56bbe5c
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/messagedlg_warning.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus.ico b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus.ico
new file mode 100644
index 0000000..28b3098
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus.ico differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus.png
new file mode 100644
index 0000000..e4abb5d
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus16x16.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus16x16.png
new file mode 100644
index 0000000..f422811
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus16x16.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus32x32.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus32x32.png
new file mode 100644
index 0000000..2a30ebe
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus32x32.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus64x64.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus64x64.png
new file mode 100644
index 0000000..1061cdd
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nexus64x64.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nxvalidate.properties b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nxvalidate.properties
new file mode 100644
index 0000000..d2775fe
--- /dev/null
+++ b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/nxvalidate.properties
@@ -0,0 +1,26 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+browseButtonText=Browse
+validationButtonText=Perform Validation
+rootNodeText=NXroot
+nxsFileLabel=NXS File
+nxdlFileLabel=NXDL File
+nxconvert=nxconvert
+openNexusFileMessage=You need to select a Nexus file to open.
+fileMenuItem=File
+openSchemaFileMessage=You need to select an NXDL file to open.
+applicationTitle=NeXus File Validation Tool
+validationCompleteMessage=Validation Complete
+elementError=This is an element with an error, please check.
+defaultUNIXNXconvert=nxconvert
+defaultWindowsNXconvert=
+defaultMacNXconvert=nxconvert
+nxconvertMissingError=Could not find nxconvert so the application will not work! Please check the settings and set the location of the nxconvert command.
+noConvertCommandFound=No nxconvert command found, cannot validate.
+defaultUNIXNXconvert2=/usr/bin/nxconvert
+closeAllWarningMessage=Are you sure you want to close all files?
+filesNotNexusError=Some files have been detected as not being Nexus/HDF files and have been unchecked in the include column.
+savedResultsMessage=Results have been saved.
+notNXDLFileMessage=File is not a NXDL file, please select a NXDL file.
+notNexusFileMessage=File is not a Nexus file, please select a Nexus file.
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/peg-e.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/peg-e.png
new file mode 100644
index 0000000..71359f8
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/peg-e.png differ
diff --git a/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/warn.png b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/warn.png
new file mode 100644
index 0000000..70b94e2
Binary files /dev/null and b/applications/NXvalidate/src/org/nexusformat/nxvalidate/resources/warn.png differ
diff --git a/applications/NXvalidate/xslt2lib.py b/applications/NXvalidate/xslt2lib.py
new file mode 100644
index 0000000..5b14451
--- /dev/null
+++ b/applications/NXvalidate/xslt2lib.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+NXCONVERT = "nxconvert"
+XSLTPROC = "java -jar saxon9he.jar"
+
+def getSourceDir():
+  """Returns the location of the source code."""
+  import os
+  import sys
+  script = os.path.abspath(sys.argv[0])
+  if os.path.islink(script):
+    script = os.path.realpath(script)
+  return os.path.dirname(script)
+
+def run(cmd, **kwargs):
+  """Execute the supplied command and return the tuple (return value,
+  stdout)"""
+  shell = kwargs.get("shell", True)
+
+  import subprocess as sub
+  proc = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.STDOUT, shell=shell)
+  (stdout, stderr) = proc.communicate()
+  return_code = proc.wait()
+  return (return_code, stdout)
+
+def nxconvert(definition=None, input=None, output=None, verbose=0):
+  command = "%s -d %s %s" % (NXCONVERT, input, output)
+  (code, stdout) = run(command)
+  if verbose > 1 or code != 0:
+    print command
+    print stdout
+  if code != 0:
+    raise RuntimeError(NXCONVERT + " returned " + str(code))
+  
+
+def process(xml=None, xslt=None, output=None, verbose=0):
+  if xml is None:
+    raise Exception("xml file is None")
+  if xslt is None:
+    raise Exception("xslt file is None")
+  command = "%s %s %s > %s" % (XSLTPROC, xml, xslt, output)
+  print command
+  (code, stdout) = run(command)
+  if verbose > 1 or code != 0:
+    print command
+    print stdout
+  if code != 0:
+    raise RuntimeError(XSLTPROC + " returned " + str(code))
+
+def schematron2xslt(schematron=None, xslt=None, verbose=0):
+
+  source_dir = getSourceDir()
+  import os
+  xslt1 = os.path.join(source_dir, "iso_dsdl_include.xsl")
+  xslt2 = os.path.join(source_dir, "iso_abstract_expand.xsl")
+  xslt3 = os.path.join(source_dir, "iso_svrl_for_xslt2.xsl")
+
+
+  (path, name) = os.path.split(schematron)
+  schematron1 = name + ".step1"
+  schematron2 = name + ".step2"
+
+  process(schematron, xslt1, schematron1, verbose)
+  process(schematron1, xslt2, schematron2, verbose)
+  process(schematron2, xslt3, xslt, verbose)
+  
+  "xslt -stylesheet theSchema.xsl  myDocument.xml > myResult.xml"
+
+if __name__ == "__main__":
+  import os
+  doc_root = "~/sandpit/NeXus/definitions/trunk/"
+  VERBOSE = 1
+
+  nexus = os.path.join(doc_root, "test/NXmonopd.hdf")
+  reduced = "reducednexus"
+  nxconvert("NXmonopd", nexus, reduced, VERBOSE)
+
+  schematron = os.path.join(doc_root, "test/schematron.sch")
+  schematron2xslt(schematron, "schema.xslt", VERBOSE)
+
+  # bang the files together
+  process(reduced, "schema.xslt", "results", VERBOSE)
+  
\ No newline at end of file
diff --git a/applications/SConscript b/applications/SConscript
new file mode 100644
index 0000000..c176371
--- /dev/null
+++ b/applications/SConscript
@@ -0,0 +1,66 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 961 2007-09-04 12:31:49Z Freddie Akeroyd $
+#
+#  Top level scons file for coordinating NeXus build
+#  
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+#====================================================================
+
+import os
+import platform
+import sys
+import re
+import shutil
+from socket import gethostname
+
+import nexus_scons_utils
+
+Import('env')
+myenv = env.Clone()
+myenv.Append(CPPPATH=['#/include'])
+shared_list = env['SHARED_LIST']
+static_list = env['STATIC_LIST']
+libList = env['MYLIBLIST']
+libDirList = env['MYLIBDIRLIST']
+shlibList = env['MYSHLIBLIST']
+shlibDirList = env['MYSHLIBDIRLIST']
+
+myenv_dynamic = myenv.Clone()
+myenv_dynamic.Append(LIBS=shlibList)
+myenv_dynamic.Append(LIBPATH=shlibDirList)
+myenv_dynamic.Append(LIBPATH='#Bin/Shared')
+shared = myenv_dynamic.Program('nxbrowse',['NXbrowse.c'],PDB='nxbrowse.pdb')
+#shared = myenv_dynamic.Program('nxconvert',['nxconvert.c','nxconvert_common.c'],PDB='nxconvert.pdb')
+#shared = myenv_dynamic.Program('nxvalidate',['nxvalidate.c','nxconvert_common.c'],PDB='nxvalidate.pdb')
+
+myenv_static = myenv.Clone()
+myenv_static.Append(LIBS=libList)
+myenv_static.Append(LIBPATH=libDirList)
+myenv_static.Append(LIBPATH='#Bin/Static')
+#myenv_static.Append(LINKFLAGS=['-static'])
+static = myenv_static.Program('nxbrowse_static', ['NXbrowse.c'], PDB='nxbrowse_static.pdb')
+#static = myenv_static.Program('nxconvert_static',['nxconvert.c','nxconvert_common.c'],PDB='nxconvert_static.pdb')
+#static = myenv_static.Program('nxvalidate_static',['nxvalidate.c','nxconvert_common.c'],PDB='nxvalidate_static.pdb')
+
+retval = { 'shared': shared, 'static' : static }
+Return('retval')
diff --git a/applications/nxdiff b/applications/nxdiff
new file mode 100755
index 0000000..71bb9fa
--- /dev/null
+++ b/applications/nxdiff
@@ -0,0 +1,716 @@
+#!/usr/bin/env python
+VERSION = "1.4.3"
+
+import nxs
+import numpy
+import math
+import os
+import sys
+
+NAN = float("nan")
+
+class NXSdata:
+    def __init__(self, nxs, path, **kwargs):
+        nxs.openpath(path)
+        (self.dims, self.type) = nxs.getinfo()
+        if len(self.dims) == 1:
+            self.dims=self.dims[0]
+        self.attrs = nxs.getattrs()
+        self.data = nxs.getdata()
+
+def getDiffSym(diffType, format):
+    sumMap = {Diff.SAME:Diff.SAME, Diff.NEWLEFT:'-', Diff.NEWRIGHT:'+',
+              Diff.DIFF:Diff.DIFF, Diff.UNKNOWN:Diff.UNKNOWN}
+    if format == "unified":
+        return sumMap[diffType]
+    else:
+        return diffType
+
+def getPercentDiff(left, right, nandiff=float("nan")):
+    # find the difference (absolute)
+    diffs = left-right
+    combine = numpy.fabs(left) + numpy.fabs(right)
+
+    # do the percent part
+    diffs = 100. * numpy.fabs(diffs/left)
+    try:
+        diffs[0]
+        return diffs
+    except IndexError:
+        return [diffs]
+
+class Diff:
+    SAME     = " "
+    NEWLEFT  = "<"
+    NEWRIGHT = ">"
+    DIFF     = "|"
+    UNKNOWN  = "?"
+    def __init__(self, path, **kwargs):
+        self.path = path
+        try:
+            left = kwargs["left"]
+        except KeyError:
+            left = None
+        try:
+            right = kwargs["right"]
+        except KeyError:
+            right = None
+        try:
+            self.rightpath = kwargs["rightpath"]
+        except KeyError:
+            self.rightpath = None
+        try:
+            epsilon = kwargs["epsilon"]
+        except KeyError:
+            epsilon = 0.0000001
+        temp = self.path.split(" ")
+        if len(temp) == 2:
+            (self.summary, self.path) = temp
+        try:
+            self.summary = kwargs["diff"]
+            if self.summary == "<" or self.summary == "-":
+                self.summary = Diff.NEWLEFT
+            elif self.summary == ">" or self.summary == "+":
+                self.summary = Diff.NEWRIGHT
+            else:
+                raise "Do not understand diff \"%s\"" % self.summary
+        except KeyError:
+            self.summary = Diff.UNKNOWN
+        try:
+            self.setFormat(kwargs["format"])
+        except KeyError:
+            self.setFormat("standard")
+        self.details = []
+        if self.summary != Diff.UNKNOWN:
+            return
+
+        self.__cmpData(left, right, self.rightpath, epsilon)
+        if len(self.details) > 0:
+            self.summary = Diff.DIFF
+        else:
+            self.summary = Diff.SAME
+
+    def __shortPath(self):
+        mypath= self.path.split("/")
+        mypath = [item.split(":")[0] for item in mypath]
+        return '/'.join(mypath)
+
+    def __str__(self):
+        result = "%s %s" % (getDiffSym(self.summary, self.__format), \
+                            self.__shortPath())
+        if self.summary == Diff.DIFF:
+            result += " " + " ".join(self.details)
+        return result
+
+    def __cmpData(self, left, right, rightpath, epsilon):
+        left = left.getData(self.path)
+        if rightpath is not None:
+            right = right.getData(rightpath)
+        else:
+            right = right.getData(self.path)
+
+        if left.type != right.type:
+            # /entry/raw_frames changed from int32 to uint64. Also see below.
+            if (self.path.find("raw_frames") != -1 and left.type == "int32" \
+                and right.type == "uint64") or (self.path.find("raw_frames") != -1 \
+                and left.type == "uint64" and right.type == "int32"):
+                pass
+            # See below
+            elif (left.type == "float32" and right.type == "float64") or \
+            (left.type == "float64" and right.type == "float32"):
+                pass
+            else:
+                self.details.append("TYPE MISMATCH: %s != %s" \
+                                % (left.type, right.type))
+        if left.attrs != right.attrs:
+            self.details.append("ATTRIBUTES MISMATCH: %s != %s" % \
+                                (left.attrs, right.attrs))
+        if left.type == "CHAR" or left.type == "char" \
+               or right.type =="CHAR" or right.type == "char":
+            if left.data != right.data:
+                self.details.append("DATA MISMATCH: %s != %s" % \
+                                    (left.data, right.data))
+            return
+        if not numpy.alltrue(left.dims == right.dims):
+            self.details.append("DIMENSION MISMATCH: %s != %s" \
+                                % (left.dims, right.dims))
+            return
+        else:
+            try:
+                if left.data.dtype != right.data.dtype:
+                    # Display /entry/raw_frames after changed from int32 to uint64.
+                    if (self.path.find("raw_frames") != -1 and left.type == "int32" \
+                        and right.type == "uint64") or (self.path.find("raw_frames") != -1 \
+                        and left.type == "uint64" and right.type == "int32"):
+                        self.details.append("IGNORED TYPE MISMATCH: %s != %s" \
+                                   % (left.type, right.type))
+                        self.details.append("LEFT DATA: " + str(left.data))
+                        self.details.append("RIGHT DATA: " + str(right.data))
+                    elif (left.type == "float32" and right.type == "float64") or \
+                        (left.type == "float64" and right.type == "float32"):
+                        # cast float32 to float64
+                        if left.type == "float32":
+                            if (left.dims == 1):
+                                if (abs(abs(numpy.float64(left.data)) - abs(right.data)) <= \
+                                    max(abs(numpy.float64(left.data)), abs(right.data)) * epsilon):
+                                    # equal within precision epsilon
+                                    pass
+                                else:
+                                    self.details.append("DATA MISMATCH: %s %s != %s %s" \
+                                        % (left.data, left.type, right.data, right.type))
+                            else:
+                                for i in range (left.dims):
+                                    if (abs(abs(numpy.float64(left.data[i])) - abs(right.data[i])) <= \
+                                        max(abs(numpy.float64(left.data[i])), abs(right.data[i])) * epsilon):
+                                        # equal within precision epsilon
+                                        pass
+                                    else:
+                                        self.details.append("DATA MISMATCH: %s %s != %s %s" \
+                                            % (left.data[i], left.type, right.data[i], right.type))
+                        if right.type == "float32":
+                            if (left.dims == 1):
+                                if (abs(abs(left.data) - abs(numpy.float64(right.data))) <= \
+                                    max(abs(left.data), abs(numpy.float64(right.data))) * epsilon):
+                                    # equal within precision epsilon
+                                    pass
+                                else:
+                                    self.details.append("DATA MISMATCH: %s %s != %s %s" \
+                                        % (left.data, left.type, right.data, right.type))
+                            else:
+                                for i in range (left.dims):
+                                    if (abs(abs(left.data[i]) - abs(numpy.float64(right.data[i]))) <= \
+                                        max(abs(left.data[i]), abs(numpy.float64(right.data[i]))) * epsilon):
+                                        # equal within precision epsilon
+                                        pass
+                                    else:
+                                        self.details.append("DATA MISMATCH: %s %s != %s %s" \
+                                            % (left.data[i], left.type, right.data[i], right.type))
+                    else:
+                        self.details.append("DATA MISMATCH: %s != %s" \
+                                        % (left.data.dtype.name, \
+                                           right.data.dtype.name))
+                    return
+            except TypeError:
+                pass
+            except AttributeError:
+                pass
+
+        # special case when the array is only nans
+        if numpy.alltrue(numpy.isnan(left.data)) and \
+           numpy.alltrue(numpy.isnan(right.data)):
+            return
+
+        if numpy.alltrue(left.data == right.data):
+            return
+        else:
+            if left.data.size == 1 and right.data.size == 1:
+                self.details.append("DATA MISMATCH %s != %s" \
+                                    % (str(left.data), str(right.data)))
+                return
+            diffs = getPercentDiff(left.data, right.data)
+            if numpy.nanmax(diffs) <= 0.:
+                return
+            stats = getStats(diffs)
+            self.details.append("MISMATCH [min%s,max%s,med%s,avg%s,dev%s]" \
+                                % (stats[0], stats[1], stats[2], stats[3],
+                                   stats[4]))
+    def setFormat(self, format):
+        if format == "unified":
+            self.__format = "unified"
+        else:
+            self.__format = "standard"
+
+class NXSfile:
+    def __init__(self, name, **kwargs):
+        try:
+            self.__ignorelinks = kwargs["ignorelinks"]
+        except KeyError:
+            self.__ignorelinks = False
+        try:
+            self.__ignorenotes = kwargs["ignorenotes"]
+        except KeyError:
+            self.__ignorenotes = False
+        try:
+            self.__ignorets = kwargs["ignorets"]
+        except KeyError:
+            self.__ignorets = False
+        try:
+            self.__retype = kwargs["retype"]
+        except KeyError:
+            self.__retype = []
+        try:
+            self.__epsilon = kwargs["epsilon"]
+        except KeyError:
+            self.__epsilon = 0.0000001
+        try:
+            self.__ignorerunnumber = kwargs["ignorerunnumber"]
+        except KeyError:
+            self.__ignorerunnumber = False
+        self.name = os.path.abspath(name)
+        self.__initPaths()
+
+    def __initPaths(self, **kwargs):
+        self.__paths = []
+        self.__nxs = nxs.open(self.name)
+        self.__paths = self.__getPaths()
+        self.__paths.sort()
+        while '/' in self.__paths:
+            del self.__paths[self.__paths.index('/')]
+
+    def __getPaths(self, **kwargs):
+        result = []
+        #result.append(self.__nxs.longpath) # add the groups to the tree
+        parent = self.__nxs.longpath.split('/')[-1]
+        listing = self.__nxs.getentries()
+        for name in listing.keys():
+            nxclass = listing[name]
+            if nxclass == "SDS":
+                if self.__ignorenotes and parent.endswith("NXnote"):
+                    if name == "author" or name == "date":
+                        continue
+                elif self.__ignorets and name == "SNStranslation_service":
+                    continue
+                elif self.__ignorerunnumber and (name == "entry_identifier" \
+                    or name == "run_number"):
+                    continue
+                self.__nxs.opendata(name)
+                attrs = self.__nxs.getattrs()
+                longpath = self.__nxs.longpath
+                shortpath = self.__nxs.path
+                self.__nxs.closedata()
+                if self.__ignorelinks and attrs.has_key("target"):
+                    target = attrs["target"]
+                    if target != shortpath:
+                        continue
+                result.append(longpath)
+            else:
+                self.__nxs.opengroup(name,nxclass)
+                result.extend(self.__getPaths())
+                self.__nxs.closegroup()
+        return result
+
+    def __str__(self):
+        return self.name
+
+    def __eq__(self, other):
+        """This provides only the simplest of cases for comparing equality"""
+        return self.name == other.name
+
+    def __getMissing(self, left, right):
+        result = filter(lambda a, right=right:not a in right, left)
+        return result
+
+    def __removeDuplicate(self, item, array):
+        if item not in array:
+            return
+        index = array.index(item)
+        try:
+            while True:
+                index = array.index(item, index+1)
+                del array[index]
+        except ValueError:
+            pass
+        
+    def cmpPaths(self, other, **kwargs):
+        result = []
+        if self.__paths == other.__paths:
+            diffPaths = self.__paths[:]
+        else:
+            # find what one has that the other is missing
+            missingOther = self.__getMissing(self.__paths, other.__paths)
+            missingSelf = self.__getMissing(other.__paths, self.__paths)
+
+            # merge the results
+            diffPaths = self.__paths[:]
+            diffPaths.extend(other.__paths)
+            diffPaths.sort()
+            for path in diffPaths:
+                self.__removeDuplicate(path, diffPaths)
+
+            number = len(self.__retype)
+            #print number
+            # handle retype
+            if number > 0:
+                lnames = []
+                rnames = []
+                for item in self.__retype:
+                    if item.find("=") != -1:
+                        # TODO: add check for "NX*" if limit to type only
+                        (lname, rname) = item.split("=")
+                        lnames.append(lname)
+                        rnames.append(rname)
+                #print lnames
+                #print rnames
+                for path in missingSelf[:]:
+                    otherpath = path
+                    for i in range(number):
+                        if path.find(rnames[i]) != -1:
+                            otherpath = otherpath.replace(rnames[i], lnames[i])
+                    #print otherpath
+                    if otherpath in missingOther:
+                    # Found corresponding path, otherwise do nothing
+                        #print "Found " + otherpath + " in missingOther"
+                        result.append(Diff(otherpath, left=self, right=other, rightpath=path, epsilon=self.__epsilon))
+                        missingSelf.remove(path)
+                        missingOther.remove(otherpath)
+                        diffPaths.remove(path)
+                        diffPaths.remove(otherpath)
+                for path in missingOther[:]:
+                    otherpath = path
+                    for i in range(number):
+                        if path.find(lnames[i]) != -1:
+                            otherpath = otherpath.replace(lnames[i], rnames[i])
+                    #print otherpath
+                    if otherpath in missingSelf:
+                    # Found corresponding path, otherwise do nothing
+                        #print "Found " + otherpath + " in missingSelf"
+                        result.append(Diff(path, left=self, right=other, rightpath=otherpath, epsilon=self.__epsilon))
+                        missingSelf.remove(otherpath)
+                        missingOther.remove(path)
+                        diffPaths.remove(path)
+                        diffPaths.remove(otherpath)
+
+            for path in missingSelf:
+                index = diffPaths.index(path)
+                diffPaths[index] = "> %s" % diffPaths[index]
+            for path in missingOther:
+                index = diffPaths.index(path)
+                diffPaths[index] = "< %s" % diffPaths[index]
+
+        for path in diffPaths:
+            if path.startswith("<") or path.startswith(">"):
+                result.append(Diff(path, diff=path[0]))
+            else:
+                result.append(Diff(path, left=self, right=other, epsilon=self.__epsilon))
+
+        return result
+
+    def getData(self, path, **kwargs):
+        return NXSdata(self.__nxs, path)
+
+def isNaN(x):
+    if x * 1.0 < x:
+        return True
+    return (x == 1.0) and (x == 2.0)
+
+def removeNaN(array):
+    hasnans = numpy.isnan(array)
+    indices = numpy.where(hasnans == True)[0]
+    if len(indices) <= 0:
+        return array
+    return numpy.delete(array, indices.tolist())
+    try:
+        len(myarray)
+        return myarray
+    except TypeError:
+        return [myarray]
+
+def getStats(array, **kwargs):
+    myarray = numpy.copy(array)
+    myarray = myarray.ravel()
+    origLength = myarray.size
+    myarray = removeNaN(myarray)
+    myarray.sort()
+    length = myarray.size
+    if length ==0 and length < origLength:
+        avg = NAN
+        minimum = NAN
+        maximum  = NAN
+        median = NAN
+        stddev = NAN
+    else:
+        avg = numpy.average(myarray)
+        minimum = numpy.nanmin(myarray)
+        maximum = numpy.nanmax(myarray)
+        median = myarray[(length/2)-1]
+        stddev = myarray.std()
+    result = map(lambda x: "%.2f%%" % x,
+                 (minimum, maximum, median, avg, stddev))
+    result.append(origLength) # add the number of elements
+    result.append(origLength - length) # number of NaNs found
+    return result
+
+def cmpData(left, right, path, **kwargs):
+    left = left.getData(path)
+    right = right.getData(path)
+    if left.type != right.type:
+        return "TYPE MISMATCH: %s != %s" % (left.type, right.type)
+    if left.dims != right.dims:
+        return "DIMENSION MISMATCH: %s != %s" % (left.dims, right.dims)
+    if left.attrs != right.attrs:
+        return "ATTRIBUTES MISMATCH: %s != %s" % (left.attrs, right.attrs)
+    if left.type == "CHAR":
+        if left.data == right.data:
+            return ""
+        else:
+            return "DATA MISMATCH: %s != %s" % (left.data, right.data)
+    if utils.vector_is_equals(left.data, right.data):
+        return ""
+    else:
+        diffs = []
+        import math
+        for i in range(len(left.data)):
+            diffs.append(math.fabs((left.data[i]-right.data[i])/left.data[i]))
+        stats = getStats(diffs)
+        return "MISMATCH [min%s,max%s,med%s,avg%s,dev%s]" \
+               % (stats[0], stats[1], stats[2], stats[3], stats[4])
+
+def delinearIndex(linear, dims):
+    length = len(dims)
+    if length == 1:
+        return linear
+    elif length == 2:
+        index = [0,0]
+        index[1] = linear % dims[1]
+        index[0] = (linear - index[1])/dims[1]
+        return tuple(index)
+    else:
+        raise "Do not know how to deal with dimension " + length
+
+def printDataDiff(left, right, diff, **kwargs):
+    # determine the symbols for right and left
+    try:
+        format = kwargs["format"]
+    except KeyError:
+        format = "standard"
+    leftSym = getDiffSym(Diff.NEWLEFT, format)
+    rightSym = getDiffSym(Diff.NEWRIGHT, format)
+
+    # get the data
+    left = left.getData(diff.path)
+    # use diff.rightpath for --retype
+    if diff.rightpath is not None:
+        right = right.getData(diff.rightpath)
+    else:
+        right = right.getData(diff.path)
+
+    # the dimensions of the data
+    leftLength = 1
+    try:
+        for dim in left.dims:
+            leftLength *= dim
+    except TypeError:
+        leftLength *= left.dims
+    rightLength = 1
+    try:
+        for dim in right.dims:
+            rightLength *= dim
+    except TypeError:
+        rightLength *= right.dims
+
+    # the threshold for printing values
+    try:
+        threshold = kwargs["threshold"]
+    except KeyError:
+        threshold = None
+
+    try:
+        shownandiffs = kwargs["shownandiffs"]
+    except KeyError:
+        shownandiffs = False
+
+    # how many items to show
+    if not threshold:
+        try:
+            numItems = kwargs["numitems"]
+        except KeyError:
+            numItems = 0
+        if numItems < 0:
+            pass
+        elif numItems == 0:
+            leftLength = 10
+            rightLength = 10
+        else:
+            leftLength = numItems
+            rightLength = numItems
+
+
+    # print out type and dims
+    if (left.type == right.type) and (left.dims == right.dims):
+        print left.type, left.dims
+    else:
+        print leftSym, left.type, left.dims
+        print rightSym, right.type, right.dims
+
+    if left.attrs == right.attrs:
+        print left.attrs
+    else:
+        print leftSym, left.attrs
+        print rightSym, right.attrs
+
+    if threshold is None:
+        try:
+            print leftSym, left.data.__str__(last=leftLength)
+        except TypeError:
+            print str(left.data)
+        try:
+            print rightSym, right.data.__str__(last=rightLength)
+        except TypeError:
+            print str(right.data)
+    else:
+        nanIndices = []
+        changeInfo = []
+        length = min(leftLength, rightLength)
+        myDiff = getPercentDiff(left.data, right.data)
+        myDiff.ravel()
+        for i in xrange(myDiff.size):
+            index = delinearIndex(i, left.dims)
+            if isNaN(myDiff):
+                nanIndices.append(index)
+            elif myDiff > threshold:
+                changeInfo.append((index, myDiff, left.data[i], right.data[i]))
+        print "%d values changed between number and NaN" % len(nanIndices)
+        print "%d values changed more than %.2f%%" % (len(changeInfo),
+                                                    threshold)
+        if shownandiffs and len(nanIndices) > 0:
+            print "Indices changed between number and NaN:", nanIndices
+        if len(changeInfo) > 0:
+            print "%10s  %5s  %10s  %10s" % ("index", "%diff", "left", "right")
+            for item in changeInfo:
+                print "%10s  %5.2f  %10f  %10f" % item
+
+if __name__ == "__main__":
+    import optparse
+
+    info = []
+    info.append("This utility compares two files that are readable by the ")
+    info.append("NeXus API.")
+
+    info.append("In the difference the '<' or '-' symbol means that the ")
+    info.append("field exists in the left file but not the right.")
+    info.append("'>' or '+' symbol means that the field exists in the right ")
+    info.append("file but not the left.")
+    info.append("'|' symbol means that the field has changed between the ")
+    info.append("two files.")
+
+    parser = optparse.OptionParser("usage %prog [options] <left> <right>",
+                                   None, optparse.Option, VERSION, 'error',
+                                   " ".join(info))
+    parser.add_option("-v", "--verbose", action="count", dest="verbose",
+                      help="Enable verbose print statements", default=0)
+    parser.add_option("-q", "--brief", action="store_true", dest="quiet",
+                      help="Disable verbose print statements")
+    parser.add_option("-u", "", action="store_true", dest="unifieddiff",
+                      help="Use the unified output format.")
+    parser.add_option("-s", "--report-identical-files", action="store_true",
+                      dest="reportidenticalfiles",
+                      help="Report when two files are the same.")
+    parser.add_option("-S", "--suppress-common-lines", action="store_true",
+                      dest="suppresscommon", help="Do not output common lines")
+    parser.add_option("", "--show-values", action="store_true",
+                      dest="showvalues",
+                      help="Show the values of arrays that do not match")
+    parser.add_option("", "--num-values", dest="numvalues",
+                      help="Set the number of values to show in "
+                      + "\"--show-values\" mode. If not specified the default "
+                      + "is ten (10). To show all values specify minus one "
+                      + "(-1).")
+    parser.add_option("", "--show-percent", dest="threshold",
+                      help="Set a threshold for the minimum percentage "
+                      + "difference shown in values. This turns on "
+                      + "\"--show-values\" mode and overrides "
+                      + "\"--num-values\".")
+    parser.add_option("", "--show-nan-diffs", dest="shownandiffs",
+                      action="store_true",
+                      help="Whether or not to show the indices that changed "
+                      + "to nan when using \"--show-percent\" mode.")
+    parser.add_option("-L", "--ignore-links", dest="ignorelinks",
+                      action="store_true",
+                      help="Only compare the original copy of links")
+    parser.add_option("", "--ignore-note-meta", dest="ignorenotes",
+                      action="store_true",
+                      help="Ignore the author and date fields in notes")
+    parser.add_option("", "--ignore-ts", dest="ignorets", action="store_true",
+                      help="Ignore differences in the version of ts used")
+    parser.add_option("", "--retype", dest="retype", action="append", help="Ignore "
+                      + "differences after renaming. Please be consistent." +
+                      "Usage: --retype leftname1=rightname1  --retype leftname2=rightname2 ...")
+    parser.add_option("", "--compareFloat32Float64", dest="epsilon", action="store",
+                      type="float", default=0.0000001, help = "Set the precision (float) for "
+                      + "relative epsilon comparison. The default is 0.0000001.")
+    parser.add_option("", "--ignore-run-number", dest="ignorerunnumber", action="store_true",
+                                        help="Ignore differences of /entry/entry_identifier and "
+                                        + "/entry/run_number.")
+    parser.set_defaults(verbose=False)
+    parser.set_defaults(ignorelinks=False)
+    parser.set_defaults(numvalues=None)
+    parser.set_defaults(threshold=None)
+    parser.set_defaults(shownandiffs=False)
+    parser.set_defaults(ignorenotes=False)
+    parser.set_defaults(ignorets=False)
+    parser.set_defaults(retype=[])
+    parser.set_defaults(ignorerunnumber=False)
+    # parse and fix values
+    (options, args) = parser.parse_args()
+    if options.quiet:
+        options.verbose = -1
+    if options.unifieddiff:
+        format = "unified"
+    else:
+        format = "standard"
+    if options.numvalues is not None:
+        options.showvalues = True
+        options.numvalues = int(options.numvalues)
+    else:
+        options.numvalues = 0
+    if options.threshold is not None:
+        options.showvalues = True
+        options.threshold = float(options.threshold)
+    if len(args) != 2:
+        parser.error("Must compare two files")
+    else:
+        left = NXSfile(args[0], ignorelinks=options.ignorelinks,
+                       ignorenotes=options.ignorenotes,
+                       ignorets=options.ignorets,
+                       retype=options.retype, epsilon=options.epsilon,
+                       ignorerunnumber=options.ignorerunnumber)
+        right = NXSfile(args[1], ignorelinks=options.ignorelinks,
+                        ignorenotes=options.ignorenotes,
+                        ignorets=options.ignorets,
+                        retype=options.retype, epsilon=options.epsilon,
+                        ignorerunnumber=options.ignorerunnumber)
+
+    # direct comparison of the two files
+    if left == right:
+        if options.reportidenticalfiles:
+            print "Files %s and %s are identical" % (left, right)
+        sys.exit()
+
+    # create the full diff
+    diffs = left.cmpPaths(right)
+
+    # determine if there were differences
+    different = False
+    for diff in diffs:
+        if len(diff.summary) > 0:
+            different = True
+
+    # take the easy way out if quiet or identical
+    if not different:
+        if options.reportidenticalfiles:
+            print "Files %s and %s are identical" % (left, right)
+        sys.exit()
+    elif options.verbose == -1:
+        print "Files %s and %s differ" % (left, right)
+        sys.exit()
+
+    # remove common lines if requestsed
+    if options.suppresscommon:
+        indices = range(len(diffs))
+        indices.reverse()
+        for i in indices:
+            if diffs[i].summary == Diff.SAME:
+                del diffs[i]
+
+    # reformat the diff
+    for diff in diffs:
+        diff.setFormat(format)
+
+    # print out the result
+    for diff in diffs:
+        print diff
+        if options.showvalues and diff.summary == Diff.DIFF:
+            printDataDiff(left, right, diff, format=format,
+                          numitems=options.numvalues,
+                          threshold=options.threshold,
+                          shownandiffs=options.shownandiffs)
diff --git a/applications/nxdiff.1 b/applications/nxdiff.1
new file mode 100644
index 0000000..f58e066
--- /dev/null
+++ b/applications/nxdiff.1
@@ -0,0 +1,96 @@
+.TH NXDIFF 1 "November 2012"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+nxdiff \- compare two NeXus files
+.SH SYNOPSIS
+.B nxdiff
+[options] [\fIleft\fP] [-o|--append \fIright\fP]
+.SH DESCRIPTION
+The
+.B nxdiff
+utility compares two files that are readable by the  NeXus API. In the
+difference the '<' or '-' symbol means that the  field exists in the left file
+but not the right. '>' or '+' symbol means that the field exists in the right
+file but not the left. '|' symbol means that the field has changed between the
+two files.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.SH OPTIONS
+The following options are supported
+.TP
+.B --version
+show the version number and exit
+.TP
+.B -h|--help
+show the help message and exit
+.TP
+.B -v|--verbose
+Enable verbose print statements
+.TP
+.B -q|--brief
+Disable verbose print statements
+.TP
+.B -u
+Use the unified output format.
+.TP
+.B -s|--report-identical-files
+Report when two files are the same.
+.TP
+.B -S|--suppress-common-lines
+Do not output common lines
+.TP
+.B --show-values
+Show the values of arrays that do not match
+.TP
+.B --num-values=NUMVALUES
+Set the number of values to show in "--show-values" mode. If not specified the default is ten (10). To show all values specify minus one (-1).
+.TP
+.B --show-percent=THRESHOLD
+Set a threshold for the minimum percentage difference shown in values. This turns on "--show-values" mode and overrides "--num-values".
+.TP
+.B --show-nan-diffs
+Whether or not to show the indices that changed to nan when using "--show-percent" mode.
+.TP
+.B -L|--ignore-links
+Only compare the original copy of links
+.TP
+.B --ignore-note-meta
+Ignore the author and date fields in notes
+.TP
+.B --ignore-ts
+Ignore differences in the version of ts used
+.B --retype
+Ignore differences after renaming. Please be consistent. Usage: --retype leftname1=rightname1  --retype leftname2=rightname2 ...
+.B --compareFloat32Float64=PRECISION
+Set the precision (float) for relative epsilon comparison. The default is 0.0000001.
+.B --ignore-run-number
+Ignore differences of /entry/entry_identifier and /entry/run_number.
+.SH SEE ALSO
+.BR nxconvert(1),
+.BR nxdir (1),
+.BR nxtranslate (1),
+.BR http://www.nexusformat.org
+.SH AUTHOR
+.B nxdiff
+was originally written by Peter Peterson 
+.nh
+<petersonpf at ornl.gov>
+.hy
+and may be used by others. Modified by Marie Yao
+.nh
+<yaox at ornl.gov>
+.hy
+in December 2012.
diff --git a/applications/nxingest/.nxs b/applications/nxingest/.nxs
new file mode 100644
index 0000000..b1a9ca4
--- /dev/null
+++ b/applications/nxingest/.nxs
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<icat version="1.0 RC6" xsi:noNamespaceSchemaLocation="icatXSD.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<study>
+<name>_2007</name>
+<purpose>Group all Investigation per instrument and per year.</purpose>
+<status>ONGOING</status>
+<study_creation_date>2007-10-15T10:26:23</study_creation_date>
+<investigation trusted="false">
+<inv_number>0</inv_number>
+<visit_id>1</visit_id>
+<title>mon pos 2.0</title>
+<inv_type>EXPERIMENT</inv_type>
+<keyword>
+<name>mon</name></keyword>
+<keyword>
+<name>pos</name></keyword>
+<keyword>
+<name>2.0</name></keyword>
+<dataset>
+<name>Default</name>
+<dataset_type>EXPERIMENT_RAW</dataset_type>
+<dataset_status>COMPLETE</dataset_status>
+<description> Title =mon pos 2.0 Note =</description>
+<sample>
+<instance>0</instance>
+<safety_information>No information available.</safety_information></sample>
+<datafile>
+<name>SRF76670.nxs</name>
+<location>file:///mnt/isisdata/NDX/instrument/data/test_data/Neutron/SRF76670.nxs</location>
+<description>mon pos 2.0</description>
+<datafile_version>1.0</datafile_version>
+<datafile_version_comment>First version</datafile_version_comment>
+<datafile_format>NeXus</datafile_format>
+<datafile_format_version>2.1.0</datafile_format_version>
+<datafile_create_time>2007-10-11T10:25:45</datafile_create_time>
+<datafile_modify_time>2007-10-11T10:27:23</datafile_modify_time>
+<file_size>36963</file_size>
+<parameter>
+<name>run_number</name>
+<numeric_value>76670</numeric_value>
+<units>N/A</units>
+<description>Run Number</description></parameter>
+<parameter>
+<name>nexus_version</name>
+<string_value>2.1.0</string_value>
+<units>N/A</units>
+<description>NeXus version used to create the file.</description></parameter>
+<parameter>
+<name>hdf_version</name>
+<string_value>NCSA HDF Version 4.1 Release 5, November 5, 2001</string_value>
+<units>N/A</units>
+<description>HDF Version used to create the file.</description></parameter>
+<parameter>
+<name>program_name</name>
+<string_value>ICP</string_value>
+<units>N/A</units>
+<description>Name of creating program.</description></parameter>
+<parameter>
+<name>program_version</name>
+<string_value>v1</string_value>
+<units>N/A</units>
+<description>version of creating program.</description></parameter>
+<parameter>
+<name>start_date</name>
+<string_value>2007-10-11 10:25:45+0000</string_value>
+<units>yyyy-MM-dd HH:mm:ss</units>
+<description>Start Time of the dataset.</description></parameter>
+<parameter>
+<name>finish_date</name>
+<string_value>2007-10-11 10:27:23+0000</string_value>
+<units>yyyy-MM-dd HH:mm:ss</units>
+<description>Start Time of the dataset.</description></parameter>
+<parameter>
+<name>run_duration</name>
+<numeric_value>98</numeric_value>
+<units>seconds</units>
+<description>Calculated duration.</description></parameter>
+<parameter>
+<name>data_avg_counts</name>
+<numeric_value>4</numeric_value>
+<units>counts</units>
+<description>Average of number of counts in histogram_data_1.</description></parameter>
+<parameter>
+<name>data_std_counts</name>
+<numeric_value>151.295</numeric_value>
+<units>counts</units>
+<description>Standard deviation of number of counts in histogram_data_1.</description></parameter>
+<parameter>
+<name>histogram_resolution</name>
+<numeric_value>20000</numeric_value>
+<units>picoseconds</units>
+<description>Histogram resolution. set to 0 if not applicable.</description></parameter></datafile></dataset></investigation></study></icat>
diff --git a/applications/nxingest/CMakeLists.txt b/applications/nxingest/CMakeLists.txt
new file mode 100644
index 0000000..36dfa6f
--- /dev/null
+++ b/applications/nxingest/CMakeLists.txt
@@ -0,0 +1,44 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_executable (nxingest nxingest_main.cpp nxingest_utils.cpp
+                         nxingest_debug.cpp nxingest_nexus.cpp
+                         nxingest_parse.cpp nxingest_time.cpp
+                         nxingest_debug.h nxingest.h nxingest_main.h
+                         nxingest_nexus.h nxingest_parse.h
+                         nxingest_time.h nxingest_utils.h)
+
+include_directories(${MXML_INCLUDE_DIRS})
+
+target_link_libraries(nxingest NeXus_Shared_Library ${READLINE_LINK} ${M_LINK} ${DL_LINK}
+                      ${PTHREAD_LINK} ${DF_LINK} ${TERMCAP_LINK} ${HISTORY_LINK})
+
+
+install (TARGETS nxingest DESTINATION bin COMPONENT Runtime)
+install (FILES nxingest.txt gpl.txt DESTINATION ${NXDOCDIR}/nxingest COMPONENT Documentation)
+
diff --git a/applications/nxingest/Makefile.am b/applications/nxingest/Makefile.am
new file mode 100644
index 0000000..d77253e
--- /dev/null
+++ b/applications/nxingest/Makefile.am
@@ -0,0 +1,18 @@
+## Process this file with automake to produce Makefile.in
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include $(XML_CPPFLAGS)
+
+bin_PROGRAMS = nxingest
+nxingestdocdir = $(NXDOCDIR)/nxingest
+nxingestdoc_DATA = nxingest.txt gpl.txt
+
+nxingest_SOURCES = nxingest_main.cpp nxingest_utils.cpp \
+   nxingest_debug.cpp nxingest_nexus.cpp nxingest_parse.cpp nxingest_time.cpp \
+   nxingest_debug.h nxingest.h nxingest_main.h nxingest_nexus.h \
+   nxingest_parse.h nxingest_time.h nxingest_utils.h
+nxingest_LDADD = $(LIBNEXUS)
+nxingest_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+EXTRA_DIST=nxingest.txt gpl.txt
+
+include $(top_srcdir)/build_rules.am
diff --git a/applications/nxingest/gpl.txt b/applications/nxingest/gpl.txt
new file mode 100644
index 0000000..e37680c
--- /dev/null
+++ b/applications/nxingest/gpl.txt
@@ -0,0 +1,280 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
diff --git a/applications/nxingest/nxingest.h b/applications/nxingest/nxingest.h
new file mode 100644
index 0000000..c17543f
--- /dev/null
+++ b/applications/nxingest/nxingest.h
@@ -0,0 +1,98 @@
+/* =============================================================================
+  File Name : 	nxingest.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+
+		Version 1.1		13/06/2007		Remove trailing white space around string. 
+		
+		Version 1.2		16/08/2007		
+			Bug correction: if the string is too short for the expected transformation, 
+			an out of bound exception would have been raised by substr  
+					
+		Version 1.3		31/08/2007		
+			Bug correction in test. (Logical OR and not bitwise OR)
+			Add a filesize calculation function. 
+
+		Version 1.4		04/09/2007	
+			The parameters will not be created if there is no value attached to it. 
+
+		Version 1.5		5/09/2007
+			To avoid wrapping the xml document, 
+			set constnty 'MXML_WRAP' to a high value in mxml.h (under linux) or 
+			under windows, add function mxmlSetWrapMargin(0);
+
+		Version 1.6		06/09/2007	
+			Bug correction. Connected to changes of version 1.4. 
+			Bug Correction. Difference of path between linux / and windows \
+		
+		Version 1.7		12/09/2007
+			Bug correction in parseMix function when parseSpecial return a null string.	
+					
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+
+#ifndef _NXING_HEADER_
+#define _NXING_HEADER_
+
+#include <iostream>
+#include <stdlib.h>
+#include <cstring>
+#include <cstdio>
+#include <cmath>
+#include <ctime>
+#include "napi.h"
+#include "mxml.h"
+
+
+#define NXING_OK					NX_OK
+#define NXING_ERR_BASE_DEBUG		-1000
+#define NXING_ERR_BASE_UTILS		-2000
+#define NXING_ERR_BASE_MAIN 		-3000
+#define NXING_ERR_BASE_PARSE		-4000
+#define NXING_ERR_BASE_NEXUS		-5000
+
+#define NXING_SHORT_SIZE	64
+#define NXING_MED_SIZE		256
+#define NXING_BIG_SIZE		1024
+#define NXING_HUGE_SIZE		3999
+#define NXING_MAX_DIM		32
+
+
+// #define NXING_ERR					-1000
+// #define NXING_NOVAL					-1101
+// #define NXING_INVALID_DATATYPE		-1102
+// #define NXING_WRONG_INPUT			-1105
+// #define NXING_ERR_INVALID_DATATYPE	-1106
+// #define NXING_ERR_NO_TBL_TYPE		-1107
+// #define NXING_UNEXPECTED_PARAM_VALUE -1108
+// #define NXING_ERR_WRONG_INPUT		-1001
+// #define NXING_ERR_CANT_OPEN_PARAM	-1002
+// #define NXING_ERR_CANT_OPEN_OUTPUT	-1003
+// #define NXING_ERR_CANT_OPEN_NEXUS	-1004
+// #define NXING_ERR_NEXUS				-2000
+
+
+using namespace std;
+ 
+
+
+#endif 
diff --git a/applications/nxingest/nxingest.txt b/applications/nxingest/nxingest.txt
new file mode 100644
index 0000000..344c664
--- /dev/null
+++ b/applications/nxingest/nxingest.txt
@@ -0,0 +1,325 @@
+
+NAME	
+	nxingest - 1.4
+		
+USAGE
+	nxingest mapping_file nexus_file [output_file]
+	
+DESCRIPTION
+	nxingest extract the metadata from a NeXus file to create an XML file 
+	according to a mapping file. 
+	
+	The mapping file will defines the structure (names and hierarchy) and 
+	content (from the NeXus file, from the mapping file or from the current time)
+	of the oputput file. See below for a description of the maping file.
+	
+	This tool use the NeXus api so any of the supported format (HDF4, HDF5 
+	and XML) can be read. 
+	
+	The output file parameter is optional. if not present nxingest will write 
+	the results into output.xml	
+	
+	To be accepted by ICAT, the output XML should match the ICAT3 XML schema.
+	See http://nile.dl.ac.uk/trac/isis/browser/Software/icat_xsd/icatXSD.xsd 
+	NB: This work is ongoing; the schema hasn't been released yet.   
+	 
+	This tool use the NeXus api so any of the supported format (HDF4, HDF5 
+	and XML) can be read. 
+	
+	nxingest can retrive metadata from the neXus file, from the mapping file 
+	(fix parameter). it can also retrive the actual time. 
+	
+	If the metadata is a date or time, nxingest may modify it to extract only 
+	part of the data (e.g. the year) or reformat it to have consistant dates 
+	into ICAT.      
+	
+	NeXus syntax.
+	-------------
+	NeXus Data is divided in different classes that hold data sets. The data 
+	sets may hold any type of data from a single byte to unlimited dimension 
+	arrays. The data sets and the classes may also have attributes.
+	
+	To collect data from a neXus file, you have to build the path to the data 
+	you want.
+	
+	- Simple dataset (singular string or number)
+	The path is the name of the different classes separated by '/'the last name 
+	is the name of the dataset.
+	e.g. /run/title
+	
+	- Attribute (singular string or number)
+	The attribute name is separated from the dataset by a '.'
+	e.g. /run/data.units
+	
+	- Arrays
+	Most of the data will be stored as multi dimensional arrays. We may want to 
+	extract particular information from the data. 
+		- Specific value from an array
+		A null or positive number between square brackets after the data set 
+		name. nxingest consider all dataset an uni-dimension.  
+		e.g. /run/data_array[3] 
+		
+		- Derived value
+		nxingest may derived a few value from an array. To express that, you 
+		have to put the name of the derived parameter between square brackets. 
+		Available values are : 
+			[AVG] Average
+			[STD] Standard Deviation
+			[MIN] Minimum Value
+			[MAX] Maximum Value
+			[SUM] Sum of all values
+		e.g. /run/sample/temperature_log/value[AVG]	
+		
+	- Generic classes
+	NeXus defined generic classes type that user can name freely. nxingest can 
+	use some of these to generalise the mapping files for similar instrument. 
+	By Writing the class type under rounded brackets like {NXentry} the program 
+	will substitue it with the actual class name from the current file. 
+	This is currenlty only available for {NXentry}, {NXinstrument} and {NXuser}
+	e.g. /{NXentry}/{NXinstrument}/source/name
+	is equivalent to  
+		/run/MUSR/source/name
+		/entry_0/I18/source/name
+	Also there may be more than 1 user define in a NeXus file. nxingest will 
+	loop over each of them if the mapping include a special node 'user_tbl'.   
+
+	Mapping File
+	------------
+	The mapping file is an xml document that will control the execution of 
+	nxingest, defining the structure and content of the output of nxingest.  
+	
+	nxingest will scan the mapping file analysing all the element nodes it find.  
+	
+	There are 3 major types of node : 
+	
+	1) Table node that define the hierarchy of the output document.
+		e.g. the mapping : 	<icat type="tbl">
+								<study type="tbl">
+									<investigation type="tbl" trusted="false">
+		is mapped into : 	<icat>
+								<study>
+									<investigation  trusted="false">		
+	1') User Table node is a specific case where the node is scan several time 
+	according to the number of {NXuser} type classes are present in the neXus 
+	file. at each iteration, nxingest will replace the string {NXuser} by the 
+	correct name found in the file.								
+	e.g. the mapping :		<investigation type="tbl">
+								<user type="user_tbl"> ... </user>
+		is mapped into : 	<investigation>
+								<user> ... </user>
+								<user> ... </user>
+								<user> ... </user>
+								
+	2) 'Tag' node which define a simple metadata record. It has 2 child node 
+		that contain the name of the output element and 
+		e.g. the mapping : 	<record>
+								<icat_name>name</icat_name>
+								<value type="nexus"> path_to_metadata </value>
+							</record>
+		is mapped into : 	<name> metadata_from_nexus_file </name
+		
+	3) Parameter node define one row of one of the ICAT PARAMETER table. 
+	   The different column names are defined so we only have to extract the 
+	   necessary metadata.	
+	   It should be possible to perform the same task with only the node type 
+	   1 and 2 but this simplify the presentation. After all, the aim is to 
+	   create an document that can be ingested into ICAT3 and this 
+		e.g. the mapping : 	<parameter type="param_str">
+								<icat_name> hdf5_version </icat_name>
+								<value type="nexus"> /.HDF5_Version </value>
+								<description type="fix"> HDF5 Version used in \
+								             creating the file. </description>
+							</parameter>
+		is mapped into : 	<parameter>
+								<name> hdf5_version </name>
+								<string_value> 3.5 </string_value>
+								<description> HDF5 Version used in creating the\
+								              file. </description>
+							</parameter>
+		
+
+	Metadata Sources
+	----------------
+	the source of the metadata is defined by nodes of type 'fix', 'nexus', 
+	'special' and 'mix'. if the type is special. the begining of the text will 
+	contain a modifier (fix:, nexus:, time:or sys: ) The value is then the text 
+	without the modifier. 
+	
+	1) Fix string from the mapping file itself. 
+		- Node type fix		
+		- Node type : special; modifier fix:
+		
+	2) From the NeXus file.
+		- Node type nexus		
+		- Node type : special; modifier nexus:	
+		- Node type : special; modifier time:nexus(...)	 See below.
+
+	3) Time	
+		- Node type : special; modifier time:	
+		Time can be expressed in multiple format, so the the value after the 
+		modifier will be composed in 3 parts : 
+			time:source ; input_format; output format
+		
+		- The source can be 'now' for the current time or 'nexus()' with the path 
+		  to the time string between the parenthesis.
+		- input and output format are optional. The s/w expect an integer. 
+		  Currently the possible values are 
+				0		'2007-05-23T12:48:05'	(default)
+				1		'2007-05-23 12:48:05'	
+				2		'2007-05-23'
+				3		'12:48:05'
+				4		'20070523'
+				5		'200705'
+				6		'2007'
+				7		'23/05/2007'
+	4) System
+		- sys:filename gives the filename of the NeXus file. 
+		- sys:location gives the path of the NeXus file.
+		- sys:size gives the size in bytes of the NeXus file.
+	
+	5) Mix of all 3. 
+		- Node type : mix; 
+		To combine several sources, several modifiers used with node type 
+		'special' are used separated with '|'.
+		e.g. <value type="mix"> nexus:/{NXentry}/{NXinstrument}.short_name | 
+		                        fix:_ | time:now ; 0 ; 5 </value>
+		should create something like : 'MUSR_2007' 
+		
+		
+	
+EXAMPLE	
+	
+	Here is an example of the minimal xml document that can be accepted by ICAT.
+	
+		<?xml version="1.0" encoding="ISO-8859-1"?>
+		<icat version="1.0 RC6">
+			<study>
+				<investigation>
+					<inv_number>000001</inv_number>
+					<visit_id>01</visit_id>
+					<instrument>MUSR</instrument>
+					<investigator>
+						<user_id>ll56</user_id>
+						<role>tester, developer</role>
+					</investigator>
+					<dataset>
+						<name>test-1</name>
+						<dataset_type>EXPERIMENT_RAW</dataset_type>
+						<datafile>
+							<name>file_01</name>
+							<location>/test/inv_1/file_01.jpg</location>
+						</datafile>
+					</dataset>
+				</investigation>
+			</study>
+		</icat>
+	
+	And the mapping file to create such document. 
+	
+		<?xml version="1.0" encoding="ISO-8859-1"?>
+		<icat type="tbl">
+			<study type="tbl">
+				<investigation type="tbl">
+					<record>
+						<icat_name>inv_number</icat_name>
+						<value type="nexus"> path_to_metadata </value>
+					</record>
+					<record>
+						<icat_name>visit_id</icat_name>
+						<value type="fix"> 1 </value>
+					</record>
+					<record>
+						<icat_name>instrument</icat_name>
+						<value type="nexus"> path_to_metadata </value>
+					</record>
+					<investigator type="tbl">
+						<record>
+							<icat_name>user_id</icat_name>
+							<value type="nexus"> path_to_metadata </value>
+						</record>
+						<record>
+							<icat_name>role</icat_name>
+							<value type="nexus"> path_to_metadata </value>
+						</record>
+					</investigator>
+					<dataset type="tbl">
+						<record>
+							<icat_name>name</icat_name>
+							<value type="nexus"> path_to_metadata </value>
+						</record>
+						<record>
+							<icat_name>dataset_type</icat_name>
+							<value type="fix"> EXPERIMENT_RAW </value>
+						</record>					
+						<datafile type="tbl">
+						<record>
+							<icat_name>name</icat_name>
+							<value type="nexus"> path_to_metadata </value>
+						</record>
+						<record>
+							<icat_name>location</icat_name>
+							<value type="nexus"> path_to_metadata </value>
+						</record>
+						</datafile>
+					</dataset>
+				</investigation>
+			</study>
+		</icat>
+	
+	
+KNOWN ISSUES
+	No test of Ingestion into ICAT has been done so far. 
+	
+	Error handling and logging should be improved. 
+	
+	The list of time format is relatively limited, it should be expanded. 
+	
+	Only the columns NAME, UNITS, STRING_VALUE or NUMERIC_VALUE and DESCRIPTION
+	from the parameter table can be filled at the moment. the column RANGE_TOP, 
+	RANGE_BOTTOM and ERROR are currently ignored.  	
+
+HISTORY
+		Version 1.0		05/06/2007		First version. 
+
+		Version 1.1		13/06/2007		Remove trailing white space around string. 
+		
+		Version 1.2		16/08/2007		
+			Bug correction: if the string is too short for the expected transformation, 
+			an out of bound exception would have been raised by substr  
+					
+		Version 1.3		31/08/2007		
+			Bug correction in test. (Logical OR and not bitwise OR)
+			Add a filesize calculation function. 
+
+		Version 1.4		04/09/2007	
+			The parameters will not be created if there is no value attached to them. 
+					
+DEPENDANCIES
+
+	- NeXux Library. 
+	- mxml library version 2.2.2 
+		You may have to change the MXML_WRAP constant in mxml.h to a much 
+		higher value to avoid carriage return to appear in the xml document. 
+
+AUTHOR
+	Laurent Lerusse
+		Science and Technology Facility Council
+		e-Science Center - Data Management Group
+		e-mail : l.lerusse at stfc.ac.uk
+
+COPYRIGHT
+    nxingest 1.4 - extraction of metadata from NeXus files into a xml document
+    Copyright (C) 2007  STFC e-Science Center
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+	
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\ No newline at end of file
diff --git a/applications/nxingest/nxingest_debug.cpp b/applications/nxingest/nxingest_debug.cpp
new file mode 100644
index 0000000..0e2e57e
--- /dev/null
+++ b/applications/nxingest/nxingest_debug.cpp
@@ -0,0 +1,101 @@
+/* =============================================================================
+  File Name : 	nxingest_debug.cpp
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+   Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#include "nxingest_debug.h"
+
+int Log::level = NXING_VERBOSE;
+
+/* ***********************************************
+
+	Function : Constructor and Destructor
+	
+	Description :  
+		
+*********************************************** */
+Log::Log()
+{
+	source[0] 	= 0;
+	msg1[0]	= 0;
+	msg2[0]	= 0;
+	msg3[0]	= 0;
+	error		= NXING_OK;
+}
+
+Log::~Log()
+{
+	;
+}
+
+/* ***********************************************
+
+	Function : Constructor and Destructor
+	
+	Description :  
+		
+*********************************************** */
+Log& Log::set( const char* src, const char* msg_1, const char* msg_2, const char* msg_3, const int status)
+{
+	strncpy(source, src, NXING_BIG_SIZE);
+	if(strlen(src) >= NXING_BIG_SIZE) source[NXING_BIG_SIZE-1] = 0;
+	strncpy(msg1, msg_1, NXING_BIG_SIZE);
+	if(strlen(msg1) >= NXING_BIG_SIZE) msg1[NXING_BIG_SIZE-1] = 0;
+	strncpy(msg2, msg_2, NXING_BIG_SIZE);
+	if(strlen(msg2) >= NXING_BIG_SIZE) msg2[NXING_BIG_SIZE-1] = 0;	
+	strncpy(msg1, msg_1, NXING_BIG_SIZE);
+	if(strlen(msg3) >= NXING_BIG_SIZE) msg3[NXING_BIG_SIZE-1] = 0;	
+	error = status;
+	return *this;
+}
+
+int& Log::getStatus(){return error;}
+
+void Log::printLevel(int lvl)
+{
+	if(level >= lvl)
+	{
+		if(lvl == NXING_LOG_ERROR) cout << NXING_ERROR_PRECURSOR;
+		else if(lvl == NXING_LOG_WARNING) cout << NXING_WARNING_PRECURSOR;
+		else if(lvl == NXING_LOG_DEBUG) cout << NXING_DEBUG_PRECURSOR;
+		else cout << NXING_LOG_PRECURSOR;
+		print(); 
+	}
+	return;
+}
+
+void Log::print()
+{
+	cout << source << "\t" ;
+	if(strlen(msg1) > 0) cout <<"'" << msg1 << "'\t" ;
+	if(strlen(msg2) > 0) cout <<"'" << msg2 << "'\t" ;
+	if(strlen(msg3) > 0) cout <<"'" << msg3 << "'\t" ;
+	if(error != NXING_OK)
+	{ 
+		cout << "\t status = " << error ;
+	}
+	cout << endl; 
+	return;
+}
+
diff --git a/applications/nxingest/nxingest_debug.h b/applications/nxingest/nxingest_debug.h
new file mode 100644
index 0000000..add0779
--- /dev/null
+++ b/applications/nxingest/nxingest_debug.h
@@ -0,0 +1,68 @@
+/* =============================================================================
+  File Name : 	nxingest_debug.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+
+#ifndef _NXING_DEBUG_HEADER_
+#define _NXING_DEBUG_HEADER_
+
+#include "nxingest.h"
+
+#define NXING_LOG_ERROR			00
+#define NXING_LOG_WARNING		01
+#define NXING_LOG_IMPORTANT		10	
+#define NXING_LOG_NORMAL		11
+#define NXING_LOG_DETAIL		12
+#define NXING_LOG_ALL			15	
+#define NXING_LOG_DEBUG			20
+
+#define NXING_VERBOSE		NXING_LOG_NORMAL
+
+#define NXING_ERROR_PRECURSOR 	"Error : "
+#define NXING_WARNING_PRECURSOR "Warn  : "
+#define NXING_LOG_PRECURSOR     "Log   : "
+#define NXING_DEBUG_PRECURSOR   "Debug : "
+
+
+class Log
+{
+	private	:
+		static int level;
+		char source[NXING_BIG_SIZE];
+		char msg1[NXING_BIG_SIZE];
+		char msg2[NXING_BIG_SIZE];
+		char msg3[NXING_BIG_SIZE];
+		int error;
+	
+	public	:
+		Log();
+		~Log();
+		Log&  set(const char*, const char* = "", const char* = "", const char* = "", const int = NXING_OK);
+		int&    getStatus();
+		void	print();
+		void	printLevel(int);
+};
+#endif 
+
diff --git a/applications/nxingest/nxingest_main.cpp b/applications/nxingest/nxingest_main.cpp
new file mode 100644
index 0000000..ae00432
--- /dev/null
+++ b/applications/nxingest/nxingest_main.cpp
@@ -0,0 +1,164 @@
+/* =============================================================================
+  File Name : 	nxingest_main.cpp
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		Version 1.1		13/08/2007
+			Windows compatibility : Remove stpttime function from Date class. 
+			Modify some Declaration in NeXus class.
+
+		Version 1.5		5/09/2007
+			To avoid wrapping the xml document, 
+			set constnty 'MXML_WRAP' to a high value in mxml.h (under linux) or 
+			under windows, add function mxmlSetWrapMargin(0);
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#include "nxingest_main.h"
+
+  /*
+     * 'whitespace_cb()' - Let the mxmlSaveFile() function know when to insert
+     *                     newlines and tabs...
+     */
+
+    const char *                            /* O - Whitespace string or NULL */
+    whitespace_cb(mxml_node_t *node,        /* I - Element node */
+        	  int         where)        /* I - Open or close tag? */
+{
+	if (strncmp(node->value.element.name, "?xml", 4) == 0)
+		return(NULL);
+	if (where == MXML_WS_BEFORE_OPEN )
+		return ("\n");
+	if (where == MXML_WS_AFTER_OPEN )
+		return (NULL);
+	if (where == MXML_WS_BEFORE_CLOSE )
+		return (NULL);
+	if (where == MXML_WS_AFTER_CLOSE )
+		return (NULL);
+	return (NULL);
+}
+
+int main (int argc, char *argv[])
+{
+	Log log;
+	FILE *inFp = 0;
+	FILE *outFp = 0; 
+	mxml_node_t 	*outTree = 0;	// hold the xml input to ICAT
+	mxml_node_t 	*inTree = 0;	// Hold the parameter list
+	try
+	{
+		// Check if my assumption of type size are correct. 
+		// ************************************************
+
+		if(sizeof(short) != 2 || sizeof(int) != 4 )
+			log.set("Compiler Test", "The integer sizes are not as expected", "(short 2 bytes; int 4 bytes)").printLevel(NXING_LOG_WARNING);
+		if(sizeof(float) != 4 ||sizeof(double) != 8)
+			log.set("Compiler Test", "The float sizes are not as expected", "(float 4 bytes; double 8 bytes)").printLevel(NXING_LOG_WARNING);
+
+		char mappingFl[NXING_BIG_SIZE] = "";	
+		char nexusFl[NXING_BIG_SIZE]   = "";
+		char outputFl[NXING_BIG_SIZE]  = "";	
+		
+		if(argc < 3)
+		{
+			throw log.set("main", "Not enough input parameters!", "Needs 2 input files, mapping file and the NeXus file.", "And one output file.", NXING_ERR_WRONG_INPUT);
+		}
+		else 
+		{
+			if(argv[1] != 0) strcpy(mappingFl, argv[1]);	
+			if(argv[2] != 0) strcpy(nexusFl, argv[2]);
+			if(argv[3] != 0) strcpy(outputFl, argv[3]);
+			else strcpy(outputFl, "output.xml");	
+		}
+		log.set("main", "input - mapping", mappingFl).printLevel(NXING_LOG_NORMAL);
+		log.set("main", "input - nexus  ", nexusFl).printLevel(NXING_LOG_NORMAL);
+		log.set("main", "input - output ", outputFl).printLevel(NXING_LOG_NORMAL);
+		
+		
+		// Read input XML Parameters. 
+		// **************************'
+#ifndef MXML_WRAP
+		mxmlSetWrapMargin(0);
+#endif
+		inFp = fopen(mappingFl, "r");
+		if( inFp == 0 ) throw log.set("main", "Can't open the parameter file!", mappingFl, "", NXING_ERR_CANT_OPEN_PARAM);
+		mxml_node_t 	*inNode;	// hold the node to read from.
+		inTree = mxmlLoadFile(NULL, inFp, MXML_TEXT_CALLBACK);
+		fclose(inFp);
+		inFp = 0;
+		if(inTree != 0) log.set("main", "The mapping file has been read!", mappingFl).printLevel(NXING_LOG_ALL);
+
+		
+		// Create XML output to ICAT. 
+		// **************************
+		outFp = fopen(outputFl, "w");
+		if( outFp == 0 ) throw log.set("main", "Can't open the output file!", outputFl, "", NXING_ERR_CANT_OPEN_OUTPUT);
+	
+		if(inTree->type == MXML_ELEMENT  && (strncmp(inTree->value.element.name, "?xml", 4) == 0)){	
+			outTree = mxmlNewElement(MXML_NO_PARENT,  inTree->value.element.name);
+		}
+		
+		log.set("main", "Output Created, first tag added!", inTree->value.element.name).printLevel(NXING_LOG_DEBUG);
+		//
+
+		// Open the neXus file.
+		// ********************
+		NxClass nx(nexusFl);
+		//if(nx.isNotOK) throw log.set("Can't open the neXus file!", nexusFl, nx.status);
+		log.set("main", "NeX�s file read!", nexusFl, "", nx.status).printLevel(NXING_LOG_DEBUG);
+
+		/*
+	 	 * Parse the parameter file, read the neXus file and populate the XML output. 
+		 */
+		 log.set("main", "Parsing the mapping file!").printLevel(NXING_LOG_DEBUG);
+		 inNode = mxmlWalkNext(inTree, inTree, MXML_DESCEND);
+		 parseXml(inNode, inTree, &outTree, nx);
+
+	
+		/* 
+		 * Save the output file
+		 */  	
+		mxmlSaveFile(outTree, outFp, whitespace_cb); 
+		log.set("main", "Output file Saved!", outputFl).printLevel(NXING_LOG_DEBUG);
+
+		/* 
+		 * Close the files
+		 */
+		fclose(outFp);
+		/*
+	     * Delete the xml Trees
+	     */
+		mxmlDelete(inTree);
+	 	mxmlDelete(outTree);
+		exit(0);
+	}
+	catch(Log log)
+	{
+		log.printLevel(NXING_LOG_ERROR);
+		if(inFp  != 0) fclose(inFp);		
+		if(outFp != 0) fclose(outFp);
+		
+		if(inTree  != 0) mxmlDelete(inTree);
+	 	if(outTree != 0) mxmlDelete(outTree);
+		exit(0);
+	}	
+}
+	
diff --git a/applications/nxingest/nxingest_main.h b/applications/nxingest/nxingest_main.h
new file mode 100644
index 0000000..346e3a5
--- /dev/null
+++ b/applications/nxingest/nxingest_main.h
@@ -0,0 +1,39 @@
+/* =============================================================================
+  File Name : 	nxingest_main.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#ifndef _NXING_MAIN_HEADER_
+#define _NXING_MAIN_HEADER_
+
+#include "nxingest.h"
+#include "nxingest_debug.h"
+#include "nxingest_utils.h"
+#include "nxingest_parse.h"
+
+#define NXING_ERR_WRONG_INPUT		NXING_ERR_BASE_MAIN -1
+#define NXING_ERR_CANT_OPEN_PARAM	NXING_ERR_BASE_MAIN -2
+#define NXING_ERR_CANT_OPEN_OUTPUT	NXING_ERR_BASE_MAIN -3
+
+#endif
\ No newline at end of file
diff --git a/applications/nxingest/nxingest_nexus.cpp b/applications/nxingest/nxingest_nexus.cpp
new file mode 100644
index 0000000..52ee964
--- /dev/null
+++ b/applications/nxingest/nxingest_nexus.cpp
@@ -0,0 +1,408 @@
+/* =============================================================================
+  File Name : 	nxingest_nexus.cpp
+  Version   : 	1.3
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		
+			First version. 
+
+		Version 1.1		13/08/2007		
+			Replace the uint and ushort by unsigned int and unsigned short.
+			Declare loop variable before switch. (Windows portability)    
+
+		Version 1.3		31/08/2007		
+			Bug correction in test. (Logical OR and not bitwise OR)
+			Add a filesize calculation function. 
+
+		Version 1.9		08/09/2007		
+			Make sure that the location string will use the linxu separator '/'
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#include "nxingest_nexus.h"
+
+// Enumeration for the different calculation available for arrays. 
+// Positives number are used for specific value of the array. 
+enum Calculation { Direct = 0, Avg = -1, Min = -2, Max = -3, Std = -4, Sum = -5};
+
+// *****************************************************************************
+//	Function : NxClass Constructor
+//		
+//		The constructor will initialise the class by opening the NeXus file and 
+//		Searching for the class name for the class NXentry, NXinstrument and 
+//		NXuser. More than 1 NXuser class may be present.
+// 
+// *****************************************************************************
+ 
+NxClass::NxClass(const char* filename)
+{
+	Log log;
+	numUsers = 0;
+	currentUser = -1;
+	status = NXING_OK;
+	try
+	{		
+		status = NXopen (filename, NXACC_READ, &nxFp );
+		if( status != NXING_OK ) throw log.set("NxClass", "Can't open the neXus file!", filename, "", NXING_ERR_BASE_NEXUS-status);
+		char nx_name[NX_MAXNAMELEN];
+		char nx_group[NX_MAXNAMELEN];
+		int data_type;
+		
+		// Find the NXentry and open the group
+		status = NXinitgroupdir(nxFp);
+		while( (status = NXgetnextentry (nxFp, nx_name, nx_group, &data_type)) == NXING_OK && strcmp(nx_group, "NXentry") != 0 ){;}
+		if(strcmp(nx_group, "NXentry") == 0) strcpy(entry, nx_name);
+		status = NXopengroup(nxFp, nx_name, nx_group);
+		if( status != NXING_OK ) throw log.set("NxClass", "Can't open the neXus group!", nx_name, nx_group, NXING_ERR_BASE_NEXUS-status);
+
+		// Find the NXuser and NXinstrument class 
+		status = NXinitgroupdir(nxFp);
+		while( (status = NXgetnextentry (nxFp, nx_name, nx_group, &data_type)) == NXING_OK)
+		{
+			if(strcmp(nx_group, "NXinstrument") == 0) 
+			{
+				strcpy(inst, nx_name);
+			}
+			if(strcmp(nx_group, "NXuser") == 0)  
+			{
+				strcpy(users[numUsers], nx_name);
+				numUsers++;
+				currentUser = 0;
+			}
+		}
+		char str[NXING_MED_SIZE];
+		sprintf(str, "%d Users found!",numUsers); 
+		log.set("NxClass", entry, inst, str).printLevel(NXING_LOG_DEBUG);
+		status = NXING_OK;
+		return;
+	}
+	catch(Log log)
+	{
+		log.printLevel(NXING_LOG_ERROR);
+		return;
+	}
+}
+
+NxClass::~NxClass()
+{
+	numUsers = 0;
+	currentUser = -1;
+	return;
+}
+
+// *****************************************************************************
+//	Function : NxClass::readTag
+//		
+//		The function will parse the input NeXus path to replace the NXentry, 
+//		NXinstrument and NXuser by their proper value. 
+//		After that it will check if it need to read 
+//		- an attribute (separated from the path with a '.') or 
+//		- an array (which ends with [i], [AVG], [STD], [MIN] or [MAX])
+//		Read the data and ask the function buff2str to transform it into 
+//		a string that the function will return. 
+// 
+// *****************************************************************************
+char* NxClass::readTag(char *input, char *value, int user)
+{
+	Log log;
+	try 
+	{
+		if(user != -1 && (user >= 0 && user < numUsers)) currentUser = user;
+			
+		// Replace the {NXentry}, {NXinstrument} and {NXuser} 
+		// by their values read at initialisation.
+		// Store the modified string into nx_name
+		// ***************************************************
+		char nx_name[NXING_BIG_SIZE] = "";
+		char *pch = strtok (input,"{}");
+		while (pch != NULL)
+		{
+			if(strcmp(pch, "NXentry") == 0) strcat(nx_name, entry);
+			else if(strcmp(pch, "NXinstrument") == 0 ) strcat(nx_name, inst);
+			else if(strcmp(pch, "NXuser") == 0) strcat(nx_name, users[currentUser]);
+			else strcat(nx_name, pch);
+			pch = strtok (NULL, "{}");
+			
+		}
+		while(nx_name[strlen(nx_name)-1] == ' ') nx_name[strlen(nx_name)-1] = 0;
+		log.set("readTag","Path transformed into", nx_name).printLevel(NXING_LOG_DEBUG);
+
+		// Some declaration
+		unsigned int nd = 0;				// Position of special character
+		int length = 0;			
+		int rank = 1;						// Number of dimension of the data
+		int dim[NXING_MAX_DIM];				// size of each dimension
+		int data_type;						// data type
+		char nexus_path[NXING_BIG_SIZE] = ""; // String to hold the neXus path while it is split in its different part.
+		char name[NXING_MED_SIZE] = "";		// string to hold the name of the various attribute while looking for the type of the attribute.
+		char *vector = 0;					// End of the neXus path that describe what to do with array data.
+		char *attr_name;					// Name of the attribute to be read
+		void * buff;						// Buffer to store the data from the neXus API.
+		
+		status = NXING_OK;
+		
+		// check if it is an attribute. (presence of '.')
+		// ****************************
+		
+		if((nd = strcspn(nx_name, ".") ) < strlen(nx_name)) 
+		{
+			strncpy(nexus_path, nx_name, nd);
+			nexus_path[nd] = 0;
+			attr_name = &nx_name[nd+1];
+			status = NXopenpath(nxFp, nexus_path);
+			if(status != NXING_OK) 
+				throw log.set( "readTag", "Can't open the path to element", nexus_path, attr_name);
+			status = NXinitattrdir (nxFp);
+			while( ((status = NXgetnextattr (nxFp, name, &length, &data_type)) == NXING_OK) && (strcmp(name, attr_name) != 0 ));
+			if(status != NXING_OK) 
+				throw log.set("readTag", "No attribute with the following name found!", attr_name);
+			else 
+			{
+				dim[0] = length+2;
+				status = NXmalloc (&buff, 1, dim, data_type);
+				if(status != NXING_OK) throw log.set("readTag", "Can't allocate the buffer", nexus_path, attr_name ,NXING_ERR_BASE_NEXUS-status);
+				status = NXgetattr (nxFp, attr_name, buff, &dim[0], &data_type);
+				if(status != NXING_OK) throw log.set("readTag", "Can't read the attribute", attr_name, "",NXING_ERR_BASE_NEXUS-status);
+			}
+		}
+		else
+		{			
+			// Check if is is an element part of an array (presence of '[]' or [x]
+			if((nd = strcspn(nx_name, "[") ) < strlen(nx_name))
+			{
+				strncpy(nexus_path, nx_name, nd);
+				nexus_path[nd] = 0;
+				vector = &nx_name[nd];
+			}
+			else
+			{
+				strcpy(nexus_path,nx_name);
+				vector = &nx_name[strlen(nx_name)];
+			}
+			log.set("readTag", "Get Data ", nexus_path, vector).printLevel(NXING_LOG_DEBUG);
+			status = NXopenpath(nxFp, nexus_path);
+			if(status != NXING_OK) throw log.set( "readTag", "Can't open the path to element", nexus_path, "");
+			status = NXgetinfo (nxFp, &rank, dim, &data_type);
+			if(status != NXING_OK) throw log.set("readTag", "Can't collect the info on element", nexus_path, "",NXING_ERR_BASE_NEXUS-status);
+			status = NXmalloc (&buff, rank, dim, data_type);
+			if(status != NXING_OK) throw log.set("readTag", "Can't allocate the buffer", nexus_path, "",NXING_ERR_BASE_NEXUS-status);
+			status = NXgetdata (nxFp, buff); 
+			if(status != NXING_OK) throw log.set("readTag", "Can't get the data", nexus_path, "",NXING_ERR_BASE_NEXUS-status);
+		}
+		value = buff2str(buff,  rank, dim, data_type, vector, value);
+		log.set("readTag", nx_name, "Return", value).printLevel(NXING_LOG_DEBUG);
+
+		return value;
+	}	
+	catch(Log log)
+	{
+		log.printLevel(NXING_LOG_WARNING);
+		status = NXING_OK;
+		return 0;
+	}
+}
+char* NxClass::getLocation(char *value)
+{
+	NXinquirefile(nxFp, value, NXING_MED_SIZE); 
+	char keys[] = "\\";
+	int i= strcspn (value,keys);
+	while(i < strlen(value))
+	{
+		value[i] = '/';
+		i = strcspn (value,keys);
+	}
+	return value;
+}
+
+
+// *****************************************************************************
+//	Function : NxClass::buff2str
+//		
+//		The function will parse the data buffer according to the content of 
+//		vector and return a string.
+//		if data_type is NX_CHAR, return the string.
+//		if vector is empty, transform the buffer into a number.
+//		else transform the buffer into an array of double and apply the 
+//		calculation. [AVG] Average, [STD] Standard Deviation, 
+//		[MIN]/[MAX] Minimum/Maximum value.
+//
+// *****************************************************************************
+char* NxClass::buff2str(void* buff, int rank, int dim[], int data_type, char* vector, char* value)
+{
+	Log log;
+	try 
+	{
+		// If type NX_CHAR, return the buffer
+		// **********************************
+		if(data_type == NX_CHAR)
+		{
+			strcpy( value, (char*) buff);
+			return value;
+		}
+		int vec = 0;
+		// Parse the vector to check what has to be done with the buffer
+		// **************************************************************
+		if(vector == 0  || strlen(vector) == 0) vec = Direct;	
+		else if ( strcmp(vector, "[]") == 0 || strcmp(vector, "[AVR]") == 0 ) vec = Avg; // Average
+		else if (  strcmp(vector, "[MIN]") == 0) vec = Min;		// Min value
+		else if (  strcmp(vector, "[MAX]") == 0) vec = Max;		// Max value
+		else if (  strcmp(vector, "[STD]") == 0) vec = Std;		// Standard Deviation
+		else if (  strcmp(vector, "[SUM]") == 0) vec = Sum;		// Sum of all values
+		else 
+		{
+			vector[strlen(vector)-1] = 0;
+			vec = atoi(&vector[1]); 
+		}	
+		// Single Value
+		// ************
+		if(vec >= 0)
+		{
+			switch(data_type)
+			{
+				case NX_INT8	:
+					sprintf( value, "%d", (int)((char*) buff)[vec]);
+					break;			
+				case NX_INT16	:
+					sprintf( value, "%d", ((short*) buff)[vec]);
+					break;
+				case NX_INT32	:
+					sprintf( value, "%d", ((long*) buff)[vec]);
+					break;
+				case NX_UINT16	:
+					sprintf( value, "%d", ((unsigned short*) buff)[vec]);
+					break;
+				case NX_UINT32	:
+					sprintf( value, "%d", ((unsigned int*) buff)[vec]);
+					break;
+				case NX_FLOAT32	:
+					sprintf( value, "%f", ((float*) buff)[vec]);
+					break;
+				case NX_FLOAT64	:
+					sprintf( value, "%f", ((double*) buff)[vec]);
+					break;
+				default	:
+					break;
+			}	
+			return(value);
+		} 
+		// Array from which a value need to be extracted
+		// *********************************************
+		else if (vec < Direct)
+		{
+			// Don't need to look for multi-dimension array. 
+			// All data is 1 dimension only.
+			// **********************************************
+			long num_val = dim[0];
+			for(int i =1; i< rank; i++) num_val *= dim[i];
+			if(num_val <= 0) { 
+				throw log.set("buff2str", "The number of value of the array is null or negative.", "", "" ,NXING_ERR_NEGATIVE_NUMVAL);
+			}		// Big mistake
+			double *dblBuff  = new double[num_val];
+			// Transform the array of unknown type into an array of double
+			// ***********************************************************
+			int i = 0;
+			switch(data_type)
+			{
+				case NX_INT8	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((char*) buff)[i];
+					break;			
+				case NX_INT16	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((short*) buff)[i];
+					break;			
+				case NX_INT32	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((long*) buff)[i];
+					break;			
+				case NX_UINT16	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((unsigned short*) buff)[i];
+					break;			
+				case NX_UINT32	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((unsigned int*) buff)[i];
+					break;
+				case NX_FLOAT32	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((float*) buff)[i];
+					break;		
+				case NX_FLOAT64	:
+					for( i = 0; i< num_val; i++)
+						dblBuff[i] = (double) ((double*) buff)[i];
+					break;		
+				default	:
+					break;
+			}
+			// Perform the caclulations.
+			// *************************
+			double num_value = 0.0;
+			double avrg = 0.0;	
+			int j = 0;			
+			switch (vec){
+				case Avg :
+					for( j = 0; j< num_val; j++) num_value +=  dblBuff[j];
+					num_value /= (double)num_val;
+					break; 
+					
+				case Std :
+					for( j = 0; j< num_val; j++) avrg +=  dblBuff[j];
+					avrg /= (double)num_val;
+					num_value = 0;
+					for( j = 0; j< num_val; j++) num_value +=  pow((avrg - dblBuff[j]),2);
+						num_value = sqrt(num_value/(double)num_val);				
+					break; 
+					
+				case Min : 
+					num_value = dblBuff[0];
+					for( j = 1; j< num_val; j++) 
+						if( dblBuff[j] < num_value)
+							num_value = dblBuff[j];				
+						break; 
+					
+				case Max :
+					num_value = dblBuff[0];
+					for( j = 1; j< num_val; j++) 
+						if( dblBuff[j] > num_value) 
+							num_value = dblBuff[j];
+						break; 				
+				case Sum :
+					for( j = 0; j< num_val; j++) num_value +=  dblBuff[j];
+					break; 
+					
+				default : 
+					break; 
+			}
+			if((vec == Min || vec == Max || vec == Sum ) && (data_type == NX_INT8 || data_type == NX_INT16 || data_type == NX_INT32 || data_type == NX_UINT16 || data_type == NX_UINT32))
+				sprintf( value, "%ld", (long) num_value);
+			else 
+				sprintf( value, "%g", num_value);
+			return(value);
+		}
+		return(value);
+	}	
+	catch(Log log)
+	{
+		log.printLevel(NXING_LOG_ERROR);
+		return 0;
+	}
+	
+}
+
diff --git a/applications/nxingest/nxingest_nexus.h b/applications/nxingest/nxingest_nexus.h
new file mode 100644
index 0000000..295299b
--- /dev/null
+++ b/applications/nxingest/nxingest_nexus.h
@@ -0,0 +1,69 @@
+/* =============================================================================
+  File Name : 	nxingest_nexus.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#ifndef _NXING_NEXUS_HEADER_
+#define _NXING_NEXUS_HEADER_
+
+#include "nxingest.h"
+#include "nxingest_debug.h"
+#include "nxingest_utils.h"
+
+#define		NXING_MAX_USERS		64
+
+#define		NXING_ERR_NEGATIVE_NUMVAL	NXING_ERR_BASE_NEXUS - 100
+
+class NxClass
+{
+	private:
+		NXhandle	nxFp;
+		char entry[NX_MAXNAMELEN];					// Replace {NXentry}
+		char inst[NX_MAXNAMELEN];					// Replace {NXinstrument}
+		char users[NXING_MAX_USERS][NX_MAXNAMELEN];	// Replace {NXuser}
+		int numUsers;
+		int currentUser;
+		
+	public : 
+		int status;
+	
+	public:
+		NxClass(const char* filename); 
+		~NxClass();
+		char* readTag(char *input, char *value, int user);
+		char* getLocation(char *value);
+
+		int maxUsers(){return numUsers;};
+		int user(){return currentUser;};
+		int nextUser(){ if((currentUser+1)<numUsers) { return (++currentUser); } else { return -1; } };
+		int setUser(int u = 0){ if(u>=0 && u < numUsers) { currentUser = u; return currentUser; } else { return -1;} };
+		bool isOK(){ if(status == NXING_OK) return true; else return false; }
+		bool isNotOK(){ if(status != NXING_OK) return true; else return false; }
+
+	private:
+		char* buff2str(void* buff, int rank, int dim[], int data_type, char* vector, char* value);
+
+};
+
+#endif
diff --git a/applications/nxingest/nxingest_parse.cpp b/applications/nxingest/nxingest_parse.cpp
new file mode 100644
index 0000000..c0d0906
--- /dev/null
+++ b/applications/nxingest/nxingest_parse.cpp
@@ -0,0 +1,499 @@
+/* =============================================================================
+  File Name : 	nxingest_parse.cpp
+  Version   : 	1.8
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+		Version 1.1		13/06/2007		Remove trailing white space around string. 
+		
+		Version 1.3		31/08/2007		
+			Bug correction in test. (Logical OR and not bitwise OR)
+			Add a filesize calculation function. 
+
+		Version 1.4		04/09/2007	
+			The parameters will not be created if there is no value attached to it. 
+			
+		Version 1.6		06/09/2007	
+			Bug correction. Connected to changes of version 1.4. 
+			Bug Correction. Difference of path between linux / and windows \
+		
+		Version 1.7		12/09/2007
+			Bug correction in parseMix function when parseSpecial return a null string.
+		
+		Version 1.8		12/09/2007
+			Add the capability to split a string according to ' ', ',' and ';' 
+			to store it in several tag with the same name e.g. keyword. 
+			The mapping is like that : 
+				<keyword type="keyword_tag">
+					<icat_name> name </icat_name>
+					<value type="mix">  nexus:/{NXentry}/title | fix: , | nexus:/{NXentry}/notes </value>
+				</keyword>			
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#include "nxingest_parse.h"
+
+enum param_type { STR, NUM};
+// *****************************************************************************
+//	Function : parseXml
+//		
+//		This function will parse the mapping file to find the different elements.
+//		It may be the name of a sub table, the user tables that need to be 
+//		parsed once for each user in the neXus file. a tag or a parameter.
+//		The tag and the parameters are the element which will be holding the 
+//		metadata. 
+// 
+// *****************************************************************************
+
+mxml_node_t *parseXml(mxml_node_t *inNode, mxml_node_t *topNode, mxml_node_t **outNode, NxClass nx)
+{
+	
+	Log log;
+	mxml_node_t 	*inNextNode = 0;
+	mxml_node_t 	*outNextNode;
+	mxml_node_t 	*userInNode;
+	mxml_node_t 	**userOutNode;
+
+	int type_descent = MXML_DESCEND;		
+	const char 		*type;
+		
+	while( (inNode = mxmlWalkNext(inNode, topNode, type_descent)) != NULL )
+	{
+		inNextNode = inNode; // Get the last inNode to pass back to the calling function
+		if(inNode->type == MXML_ELEMENT)
+		{
+			type_descent = MXML_DESCEND;
+
+			type = mxmlElementGetAttr(inNode, "type");
+			if(type != 0) 
+			{	
+				log.set("parseXml", "Found element : ", inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+				if(strcmp(type, "tbl") == 0 ) // Simple table.
+				{
+					log.set("parseXml", "Get new table", inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+					outNextNode = mxmlNewElement(*outNode, inNode->value.element.name );
+					// add the attributes of the input node : 
+					if(inNode->value.element.num_attrs > 1)
+						for(int i = 0; i< inNode->value.element.num_attrs; i++)
+							if(strcmp(inNode->value.element.attrs[i].name, "type") != 0)
+								mxmlElementSetAttr(outNextNode, inNode->value.element.attrs[i].name, inNode->value.element.attrs[i].value);
+					inNode = parseXml(inNode, inNode, &outNextNode, nx);
+				} 
+				else if(strcmp(type, "user_tbl") == 0 )	// User table. There may be several user. Need to loop over the different NXusers.
+				{
+					userInNode = inNode;
+					userOutNode = outNode;
+					do{
+						userInNode = inNode;
+
+						log.set("parseXml", type, "Start", inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+						outNextNode = mxmlNewElement(*userOutNode, userInNode->value.element.name );
+						if(userInNode->value.element.num_attrs > 1)
+							for(int i = 0; i< userInNode->value.element.num_attrs; i++)
+								if(strcmp(userInNode->value.element.attrs[i].name, "type") != 0)
+									mxmlElementSetAttr(outNextNode, userInNode->value.element.attrs[i].name, userInNode->value.element.attrs[i].value);
+
+						log.set("parseXml", type, "Element added",userInNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+						parseXml(userInNode, topNode, &outNextNode, nx);
+						log.set("parseXml", type, "Parsed", inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+
+					}while(nx.nextUser() != -1); 
+					inNode = mxmlWalkNext(inNode, topNode, MXML_NO_DESCEND); 
+				}
+				else if(strcmp(type, "keyword_tag") == 0 ) // simple Tag record
+				{
+					log.set("parseXml", type, "Read",inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+					inNode = readKeyword(inNode, outNode, nx);
+					type_descent = MXML_NO_DESCEND;
+				}
+				else if(strcmp(type, "tag") == 0 ) // simple Tag record
+				{
+					log.set("parseXml", type, "Read",inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+					inNode = readRecord(inNode, outNode, nx);
+					type_descent = MXML_NO_DESCEND;
+				}
+				else if(strcmp(type, "param_str") == 0 ) // Parameter with a string value
+				{
+					log.set("parseXml", type, "Read", inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+					inNode = readParam(inNode, outNode, nx, STR);
+					type_descent = MXML_NO_DESCEND;
+				}
+				else if(strcmp(type, "param_num") == 0 ) // Parameter with a numeric value
+				{
+					log.set("parseXml", type, "Read",inNode->value.element.name).printLevel(NXING_LOG_DEBUG);
+					inNode = readParam(inNode, outNode, nx, NUM);
+					type_descent = MXML_NO_DESCEND;
+
+				}
+			}
+		}
+		if(inNode->type == MXML_TEXT && strlen(inNode->value.text.string) > 0)
+		{
+			log.set("parseXml", "Unexpected text (may be comments)", inNode->value.text.string).printLevel(NXING_LOG_DEBUG);
+		}
+	}
+	return (inNextNode);
+}
+
+// *****************************************************************************
+//	Function : readRecord
+//		
+//		This function will read a Tag that will end up as <name> value </name>
+//		where name is the icat_name value from the mapping file and value
+//		either the default value or the value from the neXus file 
+//		or a special value (still to be implemented).
+// 
+// *****************************************************************************
+mxml_node_t * readRecord(mxml_node_t *inNode, mxml_node_t **outNode, NxClass nx)
+{
+	// Check that this is the correct inNode for the function. 
+	Log log;
+	mxml_node_t 	*inNextNode = inNode;
+	mxml_node_t 	*topNode	= inNode;
+	mxml_node_t 	*nextNode;
+	char name[NXING_BIG_SIZE]  = "";
+	char value[NXING_BIG_SIZE] = "";
+
+	// 
+	while( (inNode = mxmlWalkNext(inNode, topNode, MXML_DESCEND)) != NULL )
+	{
+		if(inNode->type == MXML_ELEMENT)
+		{
+			if(strcmp(inNode->value.element.name, "icat_name") == 0) 
+			{				
+				log.set("readRecord", "ICAT name",mxmlGetItem(inNode, name)).printLevel(NXING_LOG_DEBUG);
+				mxmlGetItem(inNode, name);
+				log.set("readRecord", "ICAT name",name).printLevel(NXING_LOG_DEBUG);
+			} 
+			else if(strcmp(inNode->value.element.name, "value") == 0) 
+			{
+				getValue(inNode, nx, value);
+			}
+		}
+	}
+	if(strlen(name) > 0 && strlen(value) > 0)
+	{
+		nextNode = mxmlNewElement(*outNode, name );	
+		mxmlNewText( nextNode, 0, value);
+	}
+	
+	return inNextNode;
+}
+mxml_node_t * readKeyword(mxml_node_t *inNode, mxml_node_t **outNode, NxClass nx)
+{
+	// Check that this is the correct inNode for the function. 
+	Log log;
+	mxml_node_t 	*inNextNode = inNode;
+	mxml_node_t 	*topNode	= inNode;
+	mxml_node_t 	*nextNode;
+	char name[NXING_BIG_SIZE]  = "";
+	char value[NXING_BIG_SIZE] = "";
+	char keywordStr[NXING_BIG_SIZE] = "";
+	char keys[] = " ,;";
+
+	// 
+	strcpy(keywordStr , inNode->value.element.name);
+	
+	while( (inNode = mxmlWalkNext(inNode, topNode, MXML_DESCEND)) != NULL )
+	{
+		if(inNode->type == MXML_ELEMENT)
+		{
+			if(strcmp(inNode->value.element.name, "icat_name") == 0) 
+			{				
+				log.set("readRecord", "ICAT name",mxmlGetItem(inNode, name)).printLevel(NXING_LOG_DEBUG);
+				mxmlGetItem(inNode, name);
+				log.set("readRecord", "ICAT name",name).printLevel(NXING_LOG_DEBUG);
+			} 
+			else if(strcmp(inNode->value.element.name, "value") == 0) 
+			{
+				getValue(inNode, nx, value);
+			}
+		}
+	}
+	
+	if(strlen(name) > 0 && strlen(value) > 0)
+	{
+		char* str;
+		char* nextStr;
+		int i = 0;
+		nextStr = &value[0];
+		do
+		{
+			str = nextStr;
+			i = strcspn (str,keys);
+			if(i < strlen(str)) 
+			{
+				nextStr = &str[i+1];
+				str[i] = 0;
+			}	
+			else 
+				nextStr = 0;
+			if(strlen(str) > 0 && strcmp(str, "=") != 0)
+			{	
+				nextNode = mxmlNewElement(*outNode, keywordStr );	
+				nextNode = mxmlNewElement(nextNode, name );	
+				mxmlNewText( nextNode, 0, str);
+			}
+		} while( nextStr != 0 );
+	}
+	return inNextNode;
+}
+
+
+// *****************************************************************************
+//	Function : readParam
+//		
+//		This function will read a Tag that will end up as 
+//		<parameter>
+//			<name> icat_name </name>
+//			<string_value|numeric_value> value </string_value|numeric_value>
+//			<units>	value_units	</units>
+//			<description>	value_description	</description>
+//		where name is the icat_name value from the mapping file and value
+//		either the default value or the value from the neXus file 
+//		or a special value (still to be implemented).
+// 
+// *****************************************************************************
+mxml_node_t * readParam(mxml_node_t *inNode, mxml_node_t **outNode, NxClass nx, int paramType)
+{
+	// Check that this is the correct inNode for the function. 
+	Log log;
+	mxml_node_t 	*inNextNode = inNode;
+	mxml_node_t 	*topNode	= inNode;
+	mxml_node_t 	*paramNode;
+	mxml_node_t 	*nextNode;
+	char str[NXING_BIG_SIZE] = "";
+	char* buff = 0;
+	
+	string name;
+	string value;
+	string units;
+	string description;
+	
+	while( (inNode = mxmlWalkNext(inNode, topNode, MXML_DESCEND)) != NULL )
+	{
+		if(inNode->type == MXML_ELEMENT)
+		{
+			if(strcmp(inNode->value.element.name, "icat_name") == 0) 
+			{				
+				log.set("readParam", "ICAT name", mxmlGetItem(inNode, str)).printLevel(NXING_LOG_DEBUG);
+				buff = mxmlGetItem(inNode, str);					
+				if(buff != 0) name = buff;
+				else name = "";			} 
+			else if(strcmp(inNode->value.element.name, "value") == 0) 
+			{
+				log.set("readParam", "Value ", mxmlGetItem(inNode, str)).printLevel(NXING_LOG_DEBUG);
+				buff = getValue(inNode, nx, str);
+				if(buff != 0) value = buff;
+				else value = "";
+			}
+			else if(strcmp(inNode->value.element.name, "units") == 0) 
+			{
+				log.set("readParam", "Units", mxmlGetItem(inNode, str)).printLevel(NXING_LOG_DEBUG);
+				buff = getValue(inNode, nx, str);
+				if(buff != 0) units = buff;
+				else units = "";
+			} 
+			else if(strcmp(inNode->value.element.name, "description") == 0) 
+			{
+				log.set("readParam", "Description", mxmlGetItem(inNode, str)).printLevel(NXING_LOG_DEBUG);
+				buff = getValue(inNode, nx, str);
+				if(buff != 0) description = buff;
+				else description = "";
+			} 
+		}
+	}
+	if(value.size() > 0 && name.size() > 0) 
+	{ 
+		paramNode = mxmlNewElement(*outNode, "parameter" );	
+
+		// Name
+		nextNode = mxmlNewElement(paramNode, "name" );
+		mxmlNewText( nextNode, 0, name.c_str());
+		// Value
+		if(paramType == STR)
+			nextNode = mxmlNewElement(paramNode, "string_value" );	
+		else 
+			nextNode = mxmlNewElement(paramNode, "numeric_value" );	
+		mxmlNewText( nextNode, 0, value.c_str());
+		// Units	
+		nextNode = mxmlNewElement(paramNode, "units" );	
+		if(units.size() > 0)
+			mxmlNewText( nextNode, 0, units.c_str());
+		else
+			mxmlNewText( nextNode, 0, "N/A");
+		// Description
+		if(description.size() > 0)
+		{
+			nextNode = mxmlNewElement(paramNode, "description" );	
+			mxmlNewText( nextNode, 0, description.c_str());
+		}
+	}
+	return inNextNode;
+}
+// *****************************************************************************
+//	Function : getValue
+//		
+// *****************************************************************************
+char* getValue(mxml_node_t *inNode, NxClass nx, char* str)
+{
+	char buff[NXING_BIG_SIZE] = "";
+	const char *type;
+	type = mxmlElementGetAttr(inNode, "type");
+	if(strncmp(type, "nexus", 5) == 0) 
+		str = nx.readTag(mxmlGetItem(inNode, (char*)buff), str, -1) ;
+	else if(strncmp(type, "fix", 3) == 0) 
+		str = mxmlGetItem(inNode, str) ;
+	else if(strncmp(type, "special", 6) == 0) 
+		str = parseSpecial( mxmlGetItem(inNode, buff), str , nx) ;
+	else if(strncmp(type, "mix", 3) == 0) 
+		str =  parseMix( mxmlGetItem(inNode, buff), str , nx);
+	else strcpy(str, "Unknown type");
+	// Remove trailing white spaces.
+	while(str != 0 && str[strlen(str)-1] == ' ') str[strlen(str)-1] = 0;
+	return str;
+}
+
+// *****************************************************************************
+//	Function : parseSpecial
+//		
+// *****************************************************************************
+char* parseSpecial(char* in, char* str, NxClass nx)
+{
+	Log log;
+	char buff[NXING_MED_SIZE];
+	try 
+	{
+		if(strncmp(in, "time:", 5) == 0)
+		{
+			Time tt;
+			char * pch;
+			char timeCntr[3][NXING_MED_SIZE] = { "", "0", "0"};
+			int i=0;
+			pch = strtok (&in[5],"; ");
+			while (pch != NULL)
+			{
+				if(i<3) strncpy(timeCntr[i], pch, NXING_MED_SIZE);
+				i++;
+				pch = strtok (NULL, ";");
+			}
+			int inType = atoi(timeCntr[1]);		// Type in which the time is read
+			int outType = atoi(timeCntr[2]);	// Time in which the time is written
+
+			if(strcmp(timeCntr[0], "now") == 0)
+			{
+				str = tt.now().getTime(str, inType);
+			}
+			else if(strncmp(timeCntr[0], "nexus(", 6) == 0)
+			{
+				timeCntr[0][strlen(timeCntr[0])-1] = 0;
+				char * nxStr = 0;
+				nxStr = nx.readTag(&timeCntr[0][6], (char*)buff, -1);
+				if( nxStr != 0)
+					str = tt.set(nxStr, inType).getTime(str, outType);
+				else
+					str = 0;
+			}
+
+		}
+		else if (strncmp(in, "fix:", 4) == 0)
+		{
+			return(&in[4]);
+		}
+		else if (strncmp(in, "nexus:", 6) == 0)
+		{
+			str = nx.readTag(&in[6], str, -1);
+		}
+		else if (strncmp(in, "sys:", 4) == 0)
+		{
+			if(strncmp(&in[4], "filename", 8) == 0)
+			{
+				string location = nx.getLocation(str);;
+				size_t found = location.find_last_of("/\\");
+				if(found == string::npos) found = 0;
+				strcpy(str, location.substr(found+1).c_str());
+			}
+			else if(strncmp(&in[4], "location", 8) == 0)
+			{
+				str = nx.getLocation(str);
+			}
+			else if(strncmp(&in[4], "size", 4) == 0)
+			{
+				str = nx.getLocation(str);
+				long fSize = fileSize(str);
+				sprintf( str, "%ld", fSize);
+			}			
+		}
+		else
+			str = 0;
+		
+		return str;
+	}	
+	catch(Log log)
+	{
+		log.printLevel(NXING_LOG_ERROR);
+		return 0;
+	}
+}
+
+
+
+// *****************************************************************************
+//	Function : parseMix
+//		
+//		This function will read a Tag that will end up as 
+//		<parameter>
+//			<name> icat_name </name>
+//			<string_value|numeric_value> value </string_value|numeric_value>
+//			<units>	value_units	</units>
+//			<description>	value_description	</description>
+//		where name is the icat_name value from the mapping file and value
+//		either the default value or the value from the neXus file 
+//		or a special value (still to be implemented).
+// 
+// *****************************************************************************
+char* parseMix(char* in, char* str, NxClass nx)
+{
+	Log log;
+	char *buff = new char[NXING_MED_SIZE];
+	char hardpch[32][NXING_MED_SIZE];
+	int numMix = 0;
+	strcpy(str, "");
+	char * pch = new char[NXING_BIG_SIZE];
+	pch = strtok (in, "|");
+	numMix = 0;
+	while (pch != NULL)
+	{
+		while(pch[0] != 0 && pch[0] == ' ') pch = &pch[1];
+		while(strlen(pch) > 0 && pch[strlen(pch)-1] == ' ') pch[strlen(pch)-1] = 0;
+		strcpy(hardpch[numMix], pch);
+		numMix++;
+		pch = strtok (NULL, "|");
+	}
+	for(int i = 0 ; i < numMix; i++)
+	{
+		buff = parseSpecial(hardpch[i], (char*)buff, nx);
+		if(buff != 0 )
+			strcat(str, buff);
+	}
+	return str;
+}
+
+
diff --git a/applications/nxingest/nxingest_parse.h b/applications/nxingest/nxingest_parse.h
new file mode 100644
index 0000000..f4534a8
--- /dev/null
+++ b/applications/nxingest/nxingest_parse.h
@@ -0,0 +1,51 @@
+/* =============================================================================
+  File Name : 	nxingest_parse.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#ifndef _NXING_PARSE_HEADER_
+#define _NXING_PARSE_HEADER_
+
+#include "nxingest.h"
+#include "nxingest_debug.h"
+#include "nxingest_utils.h"
+#include "nxingest_time.h"
+
+#include "nxingest_nexus.h"
+#define NXING_UNEXPECTED_PARAM_VALUE	NXING_ERR_BASE_PARSE -1
+
+mxml_node_t *parseXml(mxml_node_t *inNode, mxml_node_t *topNode, mxml_node_t **outNode, NxClass nx);
+
+mxml_node_t * readRecord(mxml_node_t *inNode, mxml_node_t **outNode, NxClass nx);
+
+mxml_node_t * readKeyword(mxml_node_t *inNode, mxml_node_t **outNode, NxClass nx);
+
+mxml_node_t * readParam(mxml_node_t *inNode, mxml_node_t **outNode, NxClass nx, int paramType);
+
+char* parseMix(char* in, char* str, NxClass nx);
+char* parseSpecial(char* in, char* str, NxClass nx);
+
+char* getValue(mxml_node_t *inNode, NxClass nx, char* str);
+
+#endif
diff --git a/applications/nxingest/nxingest_time.cpp b/applications/nxingest/nxingest_time.cpp
new file mode 100644
index 0000000..fecd56f
--- /dev/null
+++ b/applications/nxingest/nxingest_time.cpp
@@ -0,0 +1,240 @@
+/* =============================================================================
+  File Name : 	nxingest_time.cpp
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		
+			First version. 
+			
+		Version 1.1		13/08/2007		
+			Replace the strptime function because it is not available under windows.  
+			  
+		Version 1.2		16/08/2007		
+			Bug correction: if the string is too short for the expected transformation, 
+			an out of bound exception would have been raised by substr    
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+
+#include "nxingest_time.h"
+
+
+
+
+// *****************************************************************************
+//	Function : 		Time();
+// *****************************************************************************
+Time::Time()
+{
+	
+	strcpy(format[IS08601],  "%Y-%m-%dT%H:%M:%S");	// ISO8601		'2007-05-23T12:48:05'
+	strcpy(format[MUON_CREA],  "%Y-%m-%d %H:%M:%S+0000");	// MUON_CREA		'2007-05-23 12:48:05+0000'
+
+	strcpy(format[ISO_Date], "%Y-%m-%d");			// ISO_Date		'2007-05-23'
+	strcpy(format[ISO_Time], "%H:%M:%S");			// ISO_Time		'12:48:05'
+	strcpy(format[CMP_Date], "%Y%m%d");				// CMP_Date		'20070523'
+	strcpy(format[CMP_YM],   "%Y%m");				// CMP_YM		'200705'
+	strcpy(format[CMP_Year], "%Y");					// CMP_Year		'2007'
+	strcpy(format[NRM_Date], "%d/%m/%Y");			// NRM_Date		'23/05/2007'
+	return;
+}
+// *****************************************************************************
+//	Function : 		~Time();
+// *****************************************************************************
+Time::~Time()
+{
+	return;
+}
+
+// *****************************************************************************
+//	Function : 		Time& defCustomTime(char* ct);
+// *****************************************************************************
+
+Time& Time::defCustomTime(char* ct)
+{
+	if(ct != 0) strncpy(format[Custom],  ct, NXING_MED_SIZE);
+	return *this;
+}
+
+// *****************************************************************************
+//	Function : 		Time& set(char* t, int timeType);
+//	strcpy(format[IS08601],  "%Y-%m-%dT%H:%M:%S");	// ISO8601		'2007-05-23T12:48:05'
+//	strcpy(format[MUON_CREA],  "%Y-%m-%d %H:%M:%S+0000");	// MUON_CREA		'2007-05-23 12:48:05+0000'
+
+//	strcpy(format[ISO_Date], "%Y-%m-%d");			// ISO_Date		'2007-05-23'
+//	strcpy(format[ISO_Time], "%H:%M:%S");			// ISO_Time		'12:48:05'
+//	strcpy(format[CMP_Date], "%Y%m%d");				// CMP_Date		'20070523'
+//	strcpy(format[CMP_YM],   "%Y%m");				// CMP_YM		'200705'
+//	strcpy(format[CMP_Year], "%Y");					// CMP_Year		'2007'
+//	strcpy(format[NRM_Date], "%d/%m/%Y");			// NRM_Date		'23/05/2007'
+// *****************************************************************************
+Time&	Time::set( char* tt, int timeType)
+{
+	now();
+	string time = tt;
+	tm.tm_year  = 2000  - 1900; // year since 1900
+	tm.tm_mon   = 07	-1; // mon from 0 - 11
+	tm.tm_mday  = 01;
+	tm.tm_hour  = 00;
+	tm.tm_min   = 00;
+	tm.tm_sec   = 00;
+	tm.tm_isdst = -1;
+	if( ((timeType == IS08601 || timeType == MUON_CREA) && time.size() < 19) ||
+	    ((timeType == ISO_Date || timeType == NRM_Date) && time.size() < 10) ||
+		((timeType == ISO_Time || timeType == CMP_Date) && time.size() <  8) ||
+		 (timeType == CMP_YM   && time.size() < 6) || (timeType == CMP_Year && time.size() < 4) )
+		return *this; // string too short, exception may be raised by substr
+		
+	switch(timeType)
+	{ 
+		case IS08601 :
+		case MUON_CREA :
+			tm.tm_year  = atoi(time.substr( 0, 4).c_str()) -1900;
+			tm.tm_mon   = atoi(time.substr( 5, 2).c_str()) -1;
+			tm.tm_mday  = atoi(time.substr( 8, 2).c_str());
+			tm.tm_hour  = atoi(time.substr(11, 2).c_str());
+			tm.tm_min   = atoi(time.substr(14, 2).c_str());
+			tm.tm_sec   = atoi(time.substr(17, 2).c_str());
+			
+			break;
+			
+		case ISO_Date :
+			tm.tm_year  = atoi(time.substr( 0, 4).c_str()) -1900;
+			tm.tm_mon   = atoi(time.substr( 5, 2).c_str()) -1;
+			tm.tm_mday  = atoi(time.substr( 8, 2).c_str());
+			break;
+			
+		case ISO_Time :
+			tm.tm_hour  = atoi(time.substr(0, 2).c_str());
+			tm.tm_min   = atoi(time.substr(3, 2).c_str());
+			tm.tm_sec   = atoi(time.substr(6, 2).c_str());
+			break;
+
+		case CMP_Date :
+			tm.tm_mday  = atoi(time.substr( 6, 2).c_str());
+		case CMP_YM :
+			tm.tm_mon   = atoi(time.substr( 4, 2).c_str()) -1;		
+		case CMP_Year :
+			tm.tm_year  = atoi(time.substr( 0, 4).c_str()) -1900;
+			break;
+			
+		case NRM_Date :
+			tm.tm_year  = atoi(time.substr( 6, 4).c_str())-1900;
+			tm.tm_mon   = atoi(time.substr( 3, 2).c_str()) -1;
+			tm.tm_mday  = atoi(time.substr( 0, 2).c_str());
+			break;
+	}
+	return *this;		
+}
+
+// *****************************************************************************
+//	Function : 		Time& set(double sec, char* d = 0, int timeType = 0);
+// *****************************************************************************
+Time& Time::set(double sec, char* d, int timeType)
+{
+	Time date;
+	if(d != 0) date.set(d, timeType);
+	else date.now();
+	time_t tt = date.getMidnight();
+	tt += (time_t) sec;
+	struct tm* tmPtr = localtime(&tt);
+	tm = *tmPtr;
+	return *this;		
+}
+
+// *****************************************************************************
+//	Function : 		Time& set(time_t tt);
+// *****************************************************************************
+Time& Time::set(time_t tt)
+{
+	struct tm* tmPtr = localtime(&tt);
+	tm = *tmPtr;
+	return *this;
+}
+
+// *****************************************************************************
+//	Function : 		Time& now();
+// *****************************************************************************
+Time& Time::now()
+{
+	time_t tt = time (NULL);
+	struct tm* tmPtr =  localtime(&tt);
+	tm = *tmPtr;
+	return *this;
+}
+
+// *****************************************************************************
+//	Function : 		char* getTime( char* buff, int timeType);
+// *****************************************************************************
+char* Time::getTime( char* buff, int timeType)
+{
+	
+	int timeLength = NXING_MED_SIZE;
+	if(timeType == Custom && strlen(format[Custom]) <= 0) return buff;
+	
+	if(timeType >= 0 )
+	{
+		strftime( buff, timeLength, format[timeType], &tm);	
+	}
+	else if(timeType == unix_t || timeType == secInDay )
+	{
+		int t = this->getTime(timeType);	
+		sprintf(buff, "%d", t);
+	}
+	else
+	{
+		strcpy(buff, "");
+	}
+	return buff;
+}
+
+// *****************************************************************************
+//	Function : 		time_t getTime(int timeType);
+// *****************************************************************************
+time_t Time::getTime(int timeType)
+{
+	if(timeType >= 0)
+		return -1;	
+	time_t tt = mktime(&tm);	
+	if(timeType == secInDay)
+	{
+		tt -= this->getMidnight();
+	}
+	return tt;
+}
+
+// *****************************************************************************
+//	Function : 		time_t getTime(int timeType);
+// *****************************************************************************
+time_t Time::getMidnight()
+{
+	struct tm tm_midnight;
+	time_t tt_midnight = 0;
+	tm_midnight.tm_year  = tm.tm_year;
+	tm_midnight.tm_mon   = tm.tm_mon;
+	tm_midnight.tm_mday  = tm.tm_mday;
+	tm_midnight.tm_isdst = tm.tm_isdst;
+	tm_midnight.tm_sec  = 0;
+	tm_midnight.tm_hour = 0;
+	tm_midnight.tm_min  = 0;
+	
+	tt_midnight = mktime(&tm_midnight);	
+	return tt_midnight;
+}
\ No newline at end of file
diff --git a/applications/nxingest/nxingest_time.h b/applications/nxingest/nxingest_time.h
new file mode 100644
index 0000000..39997ab
--- /dev/null
+++ b/applications/nxingest/nxingest_time.h
@@ -0,0 +1,61 @@
+/* =============================================================================
+  File Name : 	nxingest_time.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#ifndef _NXING_TIME_HEADER_
+#define _NXING_TIME_HEADER_
+
+#include <string>
+#include "nxingest.h"
+#include "nxingest_debug.h"
+#include "nxingest_utils.h"
+
+enum timeType { IS08601 = 0,  MUON_CREA, ISO_Date, ISO_Time, CMP_Date, CMP_YM, CMP_Year, NRM_Date, Custom, unix_t = -1, secInDay = -2 };
+
+class Time
+{
+	private:
+		char timeStr[NXING_MED_SIZE];
+		struct tm tm;
+		char format[Custom+1][NXING_MED_SIZE] ;
+		
+	 public : 
+		Time();
+		~Time();
+		Time&  set(char* t, int timeType);
+		Time&  set(double sec, char* d = 0, int timeType = 0);
+		Time&  set(time_t tt);
+		Time&  now();
+		Time&  defCustomTime(char* ct);
+		char*  getTime( char* buff, int timeType);
+		time_t getTime(int timeType);
+		time_t getMidnight();
+
+};
+
+#endif
+
+
+
diff --git a/applications/nxingest/nxingest_utils.cpp b/applications/nxingest/nxingest_utils.cpp
new file mode 100644
index 0000000..370a3a6
--- /dev/null
+++ b/applications/nxingest/nxingest_utils.cpp
@@ -0,0 +1,98 @@
+/* =============================================================================
+  File Name : 	nxingest_utils.cpp
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+		Version 1.3		31/08/2007		
+			Bug correction in test. (Logical OR and not bitwise OR)
+			Add a filesize calculation function. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#include "nxingest_utils.h"
+
+/*	Version using stat.h which is not portable. 
+
+	long fileSize( const string &fname ) 
+	{ 
+	  struct stat fileStat; 
+	  int err = stat( fname.c_str(), &fileStat ); 
+	  if (0 != err) return 0; 
+	  return fileStat.st_size; 
+	}
+*/
+
+#include <fstream>
+long fileSize( const string &fname ) 
+{ 
+/* 
+ Function taken from : http://www.codeproject.com/file/filesize.asp
+ Reported pitfals : 
+    * The file size may be bigger than can be represented by an int.
+    * The size of the file may be larger than what is reported. 
+*/
+  std::ifstream f;
+  f.open(fname.c_str(), std::ios_base::binary | std::ios_base::in);
+  if (!f.good() || f.eof() || !f.is_open()) { return 0; }
+  f.seekg(0, std::ios_base::beg);
+  std::ifstream::pos_type begin_pos = f.tellg();
+  f.seekg(0, std::ios_base::end);
+  return static_cast<int>(f.tellg() - begin_pos);
+}
+
+
+
+// *****************************************************************************
+//	Function : mxmlGetItem
+//		
+//		The function will read the text of an xml tag and return it. 
+//		If a string is provided, multiple word will be concatenated 
+//		before returning the string.
+//
+// *****************************************************************************
+char* mxmlGetItem(mxml_node_t *node, char* str){
+	mxml_node_t 	*topNode;
+	topNode = node;	
+	
+	strcpy(str, "");
+	while( (node = mxmlWalkNext(node, topNode, MXML_DESCEND)) != NULL  && node->type == MXML_TEXT)
+	{
+		strcat(str, node->value.text.string);
+		strcat(str, " ");
+	}
+	while(strlen(str) > 0 && str[strlen(str)-1] == ' ')
+		str[strlen(str)-1] = 0;
+	return str;
+}
+
+char* mxmlGetItem(mxml_node_t *node){
+	mxml_node_t 	*topNode;
+	topNode = node;	
+	while( (node = mxmlWalkNext(node, topNode, MXML_DESCEND)) != NULL )
+	{
+		if(node->type == MXML_TEXT && strlen(node->value.text.string) > 0)
+		{
+			return node->value.text.string; 
+		}
+	}
+	return 0;
+}
diff --git a/applications/nxingest/nxingest_utils.h b/applications/nxingest/nxingest_utils.h
new file mode 100644
index 0000000..f476b61
--- /dev/null
+++ b/applications/nxingest/nxingest_utils.h
@@ -0,0 +1,60 @@
+/* =============================================================================
+  File Name : 	nxingest_utils.h
+  Version   : 	1.7
+  Component : 	nxingest
+  Developer : 	Laurent Lerusse 
+				e-Science Center - Facility Support - Data Management Group
+				       
+  Purpose   : 	nxingest extract the metadata from a NeXus file to create an 
+				XML file according to a mapping file. 
+
+  Revision History : 
+		Version 1.0		05/06/2007		First version. 
+		
+		Version 1.3		31/08/2007		
+			Bug correction in test. (Logical OR and not bitwise OR)
+			Add a filesize calculation function. 
+		
+  Copyright : 
+		nxingest  - extraction of metadata from NeXus files into a xml document.
+		Copyright (C) 2007  STFC e-Science Center
+		
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; version 2 of the License.
+	
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+============================================================================= */
+#ifndef _NXING_UTILS_HEADER_
+#define _NXING_UTILS_HEADER_
+
+#include "nxingest.h"
+#include "nxingest_debug.h"
+#include "nxingest_nexus.h"
+
+#include <sys/types.h> 
+#include <sys/stat.h> 
+
+#define NXING_ERR_TOO_LONG			NXING_ERR_BASE_UTILS -1
+#define NXING_ERR_INVALID_INPUTS	NXING_ERR_BASE_UTILS -2
+
+long fileSize( const string &fname ); 
+
+char* mxmlGetItem(mxml_node_t *node, char* str);
+char* mxmlGetItem(mxml_node_t *node);
+
+inline float f_rand(float a = 1.)
+{
+	return (a * 2.0 * (.5 - ( (float)rand()/(float)RAND_MAX ) ) );
+}
+
+inline float abs_rand(float a = 1.)
+{
+	return (a * (float)rand()/(float)RAND_MAX );
+}
+
+
+#endif 
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..5891c09
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+rm -fr autom4te.cache
+
+PACKAGE_RELEASE=""
+NEXUS_VERSION=""
+NEXUS_RELEASE=""
+while getopts "p:r:v:" opt; do
+  case $opt in
+    p)
+	PACKAGE_RELEASE="$OPTARG"
+	;;
+    v)
+	NEXUS_VERSION="$OPTARG"
+	;;
+    r)
+	NEXUS_RELEASE="$OPTARG"
+	;;
+    \?)
+	echo "Invalid option: -$OPTARG" >&2
+	;;
+  esac
+done
+if test ! -z "$PACKAGE_RELEASE"; then
+    echo "Setting package release to $PACKAGE_RELEASE"
+    mv configure.ac configure.ac.$$
+    sed -e "s/^m4_define.*PACKAGE_REL.*/m4_define\([PACKAGE_REL],[$PACKAGE_RELEASE]\)dnl/" < configure.ac.$$ > configure.ac
+    rm -f configure.ac.$$
+fi
+if test ! -z "$NEXUS_VERSION"; then
+    echo "Setting NeXus version to $NEXUS_VERSION"
+    mv configure.ac configure.ac.$$
+    sed -e "s/^m4_define.*NEXUS_VERSION.*/m4_define\([NEXUS_VERSION],[$NEXUS_VERSION]\)dnl/" < configure.ac.$$ > configure.ac
+    rm -f configure.ac.$$
+fi
+if test ! -z "$NEXUS_RELEASE"; then
+    echo "Setting NeXus release to $NEXUS_RELEASE"
+    mv configure.ac configure.ac.$$
+    sed -e "s/^m4_define.*NEXUS_REL.*/m4_define\([NEXUS_REL],[$NEXUS_RELEASE]\)dnl/" < configure.ac.$$ > configure.ac
+    rm -f configure.ac.$$
+fi
+
+for libtoolize in glibtoolize libtoolize ; do 
+	LIBTOOLIZE=`which $libtoolize 2>/dev/null`
+	if test "$LIBTOOLIZE" ; then
+		break;
+	fi
+done
+LIBTOOLIZE="$libtoolize --force --copy --automake"
+
+# set up environment variables with the correct
+# version of autoconf and automake - this also needs
+# to be done in configure.ac to maintain consistancy
+. ./autoversion.sh
+
+touch AUTHORS NEWS README
+rm -f ChangeLog
+
+# Discover what version of autoconf we are using.
+autoconfversion=`$AUTOCONF --version | head -n 1`
+automakeversion=`$AUTOMAKE --version | head -n 1`
+libtoolversion=`$LIBTOOLIZE --version | head -n 1`
+
+echo "Using $autoconfversion"
+echo "Using $automakeversion"
+echo "Using $libtoolversion"
+case $autoconfversion in
+    *2.6*)
+	;;
+    *2.7*)
+	;;
+    *)
+	echo "This autoconf version is not supported by NeXus."
+	echo "NeXus only supports autoconf 2.61 and above"
+	echo "You may download it from ftp://ftp.gnu.org/gnu/autoconf"
+	exit
+	;;
+esac
+
+case $automakeversion in
+    *1.[4-9]*)
+	;;
+    *1.1[0-9]*)
+	;;
+    *)
+	echo "This automake version is not supported by NeXus."
+	echo "NeXus only supports automake 1.4 and above"
+	echo "You may download it from ftp://ftp.gnu.org/gnu/automake"
+	exit
+	;;
+esac
+
+case $libtoolversion in
+    *1.[456]*)
+	;;
+    *[2-9].*)
+	;;
+    *)
+	echo "This libtool version is not supported by NeXus."
+	echo "NeXus only supports libtool 1.4 and above"
+	echo "You may download it from ftp://ftp.gnu.org/gnu/libtool"
+	exit
+	;;
+esac
+
+echo -n "Locating GNU m4... "
+GNUM4=
+for prog in $M4 gm4 gnum4 m4; do
+	# continue if $prog generates error (e.g. does not exist)
+	( $prog --version ) < /dev/null > /dev/null 2>&1
+	if test $? -ne 0 ; then continue; fi
+
+	# /dev/null input prevents a hang of the script for some m4 compilers (e.g. on FreeBSD)
+	case `$prog --version < /dev/null 2>&1` in
+	*GNU*)	GNUM4=$prog
+		break ;;
+	esac
+done
+if test x$GNUM4 = x ; then
+	echo "not found."
+	exit
+else
+	echo `which $GNUM4`
+fi
+
+# 
+if { test ! -d config ; } ; then 
+	mkdir config ; 
+else 
+	rm -rf config/* ;  
+fi
+
+# Prepare the use of libtool
+if ( $LIBTOOLIZE --version ) < /dev/null > /dev/null 2>&1 ; then
+	echo "Preparing the use of libtool ..."
+	$LIBTOOLIZE
+	if { test -r ltmain.sh ; } ; then mv ltmain.sh config/ ; fi 
+	echo "done."
+else
+	echo "libtoolize not found -- aborting"
+	exit
+fi
+
+# Generate the Makefiles and configure files
+if ( $ACLOCAL --version ) < /dev/null > /dev/null 2>&1; then
+	echo "Building macros..."
+	$ACLOCAL
+	echo "done."
+else
+	echo "aclocal not found -- aborting"
+	exit
+fi
+
+if ( $AUTOHEADER --version ) < /dev/null > /dev/null 2>&1; then
+	echo "Building config header template..."
+	$AUTOHEADER 
+	echo "done."
+else
+	echo "autoheader not found -- aborting"
+	exit
+fi
+
+if ( $AUTOMAKE --version ) < /dev/null > /dev/null 2>&1; then
+	echo "Building Makefile templates..."
+	$AUTOMAKE
+	echo "done."
+else
+	echo "automake not found -- aborting"
+	exit
+fi
+
+if ( $AUTOCONF --version ) < /dev/null > /dev/null 2>&1; then
+	echo "Building configure..."
+	$AUTOCONF
+	echo "done."
+else
+	echo "autoconf not found -- aborting"
+	exit
+fi
+
diff --git a/autoversion.sh b/autoversion.sh
new file mode 100755
index 0000000..0fddf2b
--- /dev/null
+++ b/autoversion.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+for automake in automake-1.12 automake-1.11 automake-1.10 automake-1.9 automake-1.8 automake-1.7 automake-1.6 automake-1.5 automake-1.4 automake ; do
+	AUTOMAKE=`which $automake 2>/dev/null |  grep -v '^no'`
+	if test "$AUTOMAKE" ; then
+		break;
+	fi
+done
+AUTOMAKE="$automake -a -c"
+case $automake in
+	automake-*)
+		version=`echo $automake | cut -f2 -d'-'`
+		ACLOCAL="aclocal-$version";;
+	*)
+		ACLOCAL="aclocal";
+esac
+	
+for autoconf in autoconf-2.61 autoconf ; do 
+	AUTOCONF=`which $autoconf 2>/dev/null | grep -v '^no'`
+	if test "$AUTOCONF" ; then
+		break;
+	fi
+done
+AUTOCONF="$autoconf"
+case $autoconf in
+	autoconf-*)
+		version=`echo $autoconf | cut -f2 -d'-'`
+		AUTOHEADER="autoheader-$version";;
+	*)
+		AUTOHEADER="autoheader";;
+esac
+
+export AUTOMAKE ACLOCAL AUTOCONF AUTOHEADER
+
diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt
new file mode 100644
index 0000000..9cbd271
--- /dev/null
+++ b/bindings/CMakeLists.txt
@@ -0,0 +1,42 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+# Recurse into the subdirectories.
+add_subdirectory (cpp)
+if (BUILD_FORTRAN_BINDINGS AND CMAKE_Fortran_COMPILER_WORKS)
+    add_subdirectory (f77)
+    add_subdirectory (f90)
+endif ()
+#add_subdirectory (idl)
+if (NOT(Java_JAVAC_EXECUTABLE MATCHES NOTFOUND))
+    add_subdirectory (java)
+endif ()
+#add_subdirectory (matlab)
+if (PYTHONINTERP_FOUND)
+    add_subdirectory (python)
+endif (PYTHONINTERP_FOUND)
+#add_subdirectory (swig)
diff --git a/bindings/Makefile.am b/bindings/Makefile.am
new file mode 100644
index 0000000..601f17e
--- /dev/null
+++ b/bindings/Makefile.am
@@ -0,0 +1,53 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#
+#  Makefile for coordinating the generation of language bindings
+#  
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+if HAVE_CPP
+CPPSUB = cpp
+endif
+if HAVE_F77
+F77SUB = f77
+endif
+if HAVE_F90
+F90SUB = f90
+endif
+if HAVE_JAVAC
+JAVASUB = java
+endif
+if HAVE_SWIG
+SWIGSUB = swig
+endif
+if HAVE_IDL
+IDLSUB = idl
+endif
+if HAVE_PYTHON
+PYSUB = python
+endif
+if HAVE_MATLAB
+MATSUB = matlab
+endif
+SUBDIRS = $(CPPSUB) $(F77SUB) $(F90SUB) $(JAVASUB) $(SWIGSUB) $(IDLSUB) $(PYSUB) # $(MATSUB)
diff --git a/bindings/cpp/CMakeLists.txt b/bindings/cpp/CMakeLists.txt
new file mode 100644
index 0000000..f8b613c
--- /dev/null
+++ b/bindings/cpp/CMakeLists.txt
@@ -0,0 +1,77 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_definitions(-DIN_NEXUS_CPP_LIBRARY=1 ${NX_CPP})
+
+#Make NeXus CPP Bindings Static Library
+
+set (HEADERS NeXusFile.hpp NeXusException.hpp NeXusStream.hpp)
+set (SOURCES NeXusFile.hpp NeXusFile.cpp NeXusException.hpp NeXusException.cpp NeXusStream.hpp NeXusStream.cpp)
+
+set_property(SOURCE ${SOURCES} APPEND PROPERTY COMPILE_FLAGS ${NX_CFLAGS})
+
+add_library (NeXus_CPP_Static_Library STATIC ${HEADERS} ${SOURCES})
+
+set_target_properties(NeXus_CPP_Static_Library PROPERTIES OUTPUT_NAME NeXusCPPStatic)
+
+target_link_libraries(NeXus_CPP_Static_Library NeXus_Static_Library 
+					${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+#Make NeXus CPP Bindings Shared Library
+
+add_library (NeXus_CPP_Shared_Library SHARED ${HEADERS} ${SOURCES})
+
+#Note - library version needs to be got from somewhere?
+# may want to use DEBUG_OUTPUT_NAME and RELEASE_OUTPUT_NAME
+# of define CMAKE_DEBUG_POSTFIX globally
+if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    set_target_properties(NeXus_CPP_Shared_Library PROPERTIES OUTPUT_NAME libNeXusCPP-0
+                      VERSION 1.0 SOVERSION 4 )
+else(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    set_target_properties(NeXus_CPP_Shared_Library PROPERTIES OUTPUT_NAME NeXusCPP
+                      VERSION 1.0 SOVERSION 4)
+endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+
+target_link_libraries(NeXus_CPP_Shared_Library NeXus_Shared_Library 
+                       ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+install (TARGETS NeXus_CPP_Static_Library NeXus_CPP_Shared_Library
+         RUNTIME DESTINATION bin COMPONENT Runtime
+         LIBRARY DESTINATION lib COMPONENT Runtime
+         ARCHIVE DESTINATION lib/nexus COMPONENT Development)
+
+INSTALL (FILES ${HEADERS} DESTINATION ${NX_INCLUDE}/ COMPONENT Development)
+
+#if(WIN32)
+#install_pdb (NeXus_CPP_Shared_Library)
+#endif()
+
+
+
diff --git a/bindings/cpp/Makefile.am b/bindings/cpp/Makefile.am
new file mode 100644
index 0000000..1072925
--- /dev/null
+++ b/bindings/cpp/Makefile.am
@@ -0,0 +1,67 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 598 2005-08-19 16:19:15Z faa59 $
+#  
+#  Makefile for NeXus C++ bindings
+#
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see http://www.nexusformat.org/
+#
+#====================================================================
+####################### Subversion Reposity details ########################
+# Repository Location     $HeadURL$
+# Revision of last commit $LastChangedRevision$ 
+# Date of last commit     $LastChangedDate$
+# Author of last commit   $LastChangedBy$
+############################################################################
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+lib_LTLIBRARIES=libNeXusCPP.la
+
+# nxincludedir=$(includedir)/nexus
+nxincludedir=$(pkgincludedir)
+nxinclude_HEADERS=NeXusFile.hpp NeXusException.hpp NeXusStream.hpp
+
+libNeXusCPP_la_SOURCES=NeXusFile.hpp NeXusFile.cpp NeXusException.hpp NeXusException.cpp NeXusStream.hpp NeXusStream.cpp
+libNeXusCPP_la_LIBADD=$(LIBNEXUS)
+libNeXusCPP_la_LDFLAGS=@SHARED_LDFLAGS@ -version-info $(NXLTVERSINFO) -L$(top_builddir)/src/.libs
+
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -DIN_NEXUS_CPP_LIBRARY=1
+
+if MINGW_MSYS
+MINGW_CXXFLAGS=-Wl,--export-all-symbols
+msimplibdir = ${libdir}
+libNeXusCPP.def: libNeXusCPP.la
+	pexports .libs/libNeXusCPP-0.dll > libNeXusCPP.def
+if HAVE_MS_LIB
+msimplib_DATA = libNeXusCPP.dll.lib libNeXusCPP.dll.exp libNeXusCPP.def
+libNeXusCPP.dll.exp: libNeXusCPP.dll.lib
+libNeXusCPP.dll.lib: libNeXusCPP.def
+	rm -f libNeXusCPP.dll.lib libNeXusCPP.dll.exp
+	$(MS_LIB) /MACHINE:I386 /DEF:libNeXusCPP.def /OUT:libNeXusCPP.dll.lib
+else
+msimplib_DATA = libNeXusCPP.def
+endif
+endif
+
+AM_CXXFLAGS=-prefer-pic $(MINGW_CXXFLAGS)
+CLEANFILES=libNeXusCPP.def libNeXusCPP.dll.lib libNeXusCPP.dll.exp
+
+include $(top_srcdir)/build_rules.am
diff --git a/bindings/cpp/NeXusException.cpp b/bindings/cpp/NeXusException.cpp
new file mode 100644
index 0000000..23df649
--- /dev/null
+++ b/bindings/cpp/NeXusException.cpp
@@ -0,0 +1,30 @@
+#include "napiconfig.h"
+#include "NeXusFile.hpp"
+#include "NeXusException.hpp"
+
+/**
+ * \file NeXusException.cpp
+ * The implementation of the NeXus::Exception class
+ */
+
+namespace NeXus
+{
+
+Exception::Exception(const std::string& msg, const int status) :
+  std::runtime_error(msg) {
+ this->m_what = msg;
+ this->m_status = status;
+}
+
+const char* Exception::what() const throw() {
+  return this->m_what.c_str();
+}
+
+int Exception::status() throw() {
+  return this->m_status;
+}
+
+Exception::~Exception() throw() {
+}
+
+}
diff --git a/bindings/cpp/NeXusException.hpp b/bindings/cpp/NeXusException.hpp
new file mode 100644
index 0000000..96fa937
--- /dev/null
+++ b/bindings/cpp/NeXusException.hpp
@@ -0,0 +1,50 @@
+#ifndef NEXUSEXCEPTION_HPP
+#define NEXUSEXCEPTION_HPP 1
+
+#include <string>
+#include <stdexcept>
+
+/**
+ * \file NeXusException.hpp
+ * Header for a base NeXus::Exception
+ * \ingroup cpp_main
+ */
+
+namespace NeXus{
+
+  /**
+   * Class that provides for a standard NeXus exception
+   * \ingroup cpp_core
+   */
+
+  class NXDLL_EXPORT Exception : public std::runtime_error
+  {
+  public:
+    /**
+     * Create a new NeXus::Exception
+     *
+     * \param msg the string to pass a the error message
+     * \param status 
+     */
+    Exception(const std::string& msg = "GENERIC ERROR", const int status = 0);
+    /**
+     * Get the message associated with the exception
+     *
+     * \return the message associated with the exception
+     */
+    virtual const char* what() const throw();
+    /** 
+     * Get the status associated with the exception
+     *
+     * \return the status value associated with the exception
+     */
+    int status() throw();
+    /** Destructor for exception */
+    virtual ~Exception() throw();
+  private:
+    std::string m_what; ///< Error message for the exception
+    int m_status; ///< Status value for the exception
+  };
+};
+
+#endif
diff --git a/bindings/cpp/NeXusFile.cpp b/bindings/cpp/NeXusFile.cpp
new file mode 100644
index 0000000..e076ef2
--- /dev/null
+++ b/bindings/cpp/NeXusFile.cpp
@@ -0,0 +1,1809 @@
+#include <cstring>
+// REMOVE
+#include <iostream>
+#include <sstream>
+#include <typeinfo>
+#include "napiconfig.h"
+#include "NeXusFile.hpp"
+#include "NeXusException.hpp"
+
+using namespace NeXus;
+using std::map;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+/**
+ * \file NeXusFile.cpp
+ * The implementation of the NeXus C++ API
+ */
+
+static const string NULL_STR = "NULL";
+
+namespace { // anonymous namespace to keep it in the file
+template <typename NumT>
+static string toString(const vector<NumT>& data) {
+  stringstream result;
+  result << "[";
+  size_t size = data.size();
+  for (size_t i = 0; i < size; i++) {
+    result << data[i];
+    if (i+1 < size) {
+      result << ",";
+    }
+  }
+  result << "]";
+  return result.str();
+}
+
+static vector<int64_t> toInt64(const vector<int> & small_v) {
+  // copy the dims over to call the int64_t version
+  vector<int64_t> big_v;
+  big_v.reserve(small_v.size());
+  for (vector<int>::const_iterator it = small_v.begin(); it != small_v.end(); ++it)
+  {
+    big_v.push_back(static_cast<int64_t>(*it));
+  }
+  return big_v;
+}
+
+} // end of anonymous namespace
+
+namespace NeXus {
+
+  // catch for undefined types
+  template <typename NumT>
+  NXnumtype getType(NumT number) {
+    stringstream msg;
+	msg << "NeXus::getType() does not know type of " << typeid(number).name();
+    throw Exception(msg.str());
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(char number) {
+    (void)number;  // Avoid compiler warning
+    return CHAR;
+  }
+
+  // template specialisations for types we know 
+  template<>
+  NXDLL_EXPORT NXnumtype getType(float number) {
+    (void)number;  // Avoid compiler warning
+    return FLOAT32;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(double number) {
+    (void)number;  // Avoid compiler warning
+    return FLOAT64;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(int8_t number) {
+    (void)number;  // Avoid compiler warning
+    return INT8;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(uint8_t number) {
+    (void)number;  // Avoid compiler warning
+    return UINT8;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(int16_t number) {
+    (void)number;  // Avoid compiler warning
+    return INT16;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(uint16_t number) {
+    (void)number;  // Avoid compiler warning
+    return UINT16;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(int32_t number) {
+    (void)number;  // Avoid compiler warning
+    return INT32;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(uint32_t number) {
+    (void)number;  // Avoid compiler warning
+    return UINT32;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(int64_t number) {
+    (void)number;  // Avoid compiler warning
+    return INT64;
+  }
+
+  template<>
+  NXDLL_EXPORT NXnumtype getType(uint64_t number) {
+    (void)number;  // Avoid compiler warning
+    return UINT64;
+  }
+
+
+}
+
+// check type sizes - uses a trick that you cannot allocate an 
+// array of negative length
+#ifdef _MSC_VER
+#define ARRAY_OFFSET	1	/* cannot dimension an array with zero elements */
+#else
+#define ARRAY_OFFSET	0	/* can dimension an array with zero elements */
+#endif /* _MSC_VER */
+
+/*
+static int check_float_too_big[4 - sizeof(float) + ARRAY_OFFSET]; // error if float > 4 bytes
+static int check_float_too_small[sizeof(float) - 4 + ARRAY_OFFSET]; // error if float < 4 bytes
+static int check_double_too_big[8 - sizeof(double) + ARRAY_OFFSET]; // error if double > 8 bytes
+static int check_double_too_small[sizeof(double) - 8 + ARRAY_OFFSET]; // error if double < 8 bytes
+static int check_char_too_big[1 - sizeof(char) + ARRAY_OFFSET]; // error if char > 1 byte
+*/
+
+namespace {
+
+static void inner_malloc(void* & data, const std::vector<int64_t>& dims, NXnumtype type) {
+  int rank = dims.size();
+  int64_t c_dims[NX_MAXRANK];
+  for (int i = 0; i < rank; i++) {
+    c_dims[i] = dims[i];
+  }
+  NXstatus status = NXmalloc64(&data, rank, c_dims, type);
+  if (status != NX_OK) {
+    throw Exception("NXmalloc failed", status);
+  }
+}
+
+
+static void inner_free(void* & data) {
+  NXstatus status = NXfree(&data);
+  if (status != NX_OK) {
+    throw Exception("NXfree failed", status);
+  }
+}
+
+} // end of anonymous namespace
+
+namespace NeXus {
+File::File(NXhandle handle, bool close_handle) : m_file_id(handle), m_close_handle(close_handle) {
+}
+
+File::File(const string& filename, const NXaccess access) : m_close_handle (true) {
+  this->initOpenFile(filename, access);
+}
+
+File::File(const char *filename, const NXaccess access) : m_close_handle (true) {
+  this->initOpenFile(string(filename), access);
+}
+
+void File::initOpenFile(const string& filename, const NXaccess access) {
+  if (filename.empty()) {
+    throw Exception("Filename specified is empty constructor");
+  }
+
+  NXstatus status = NXopen(filename.c_str(), access, &(this->m_file_id));
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXopen(" << filename << ", "  << access << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+File::~File() {
+  if (m_close_handle && m_file_id != NULL) {
+    NXstatus status = NXclose(&(this->m_file_id));
+    this->m_file_id = NULL;
+    if (status != NX_OK) {
+      throw Exception("NXclose failed", status);
+    }
+  }
+}
+
+void File::close() {
+  if (this->m_file_id != NULL) {
+    NXstatus status = NXclose(&(this->m_file_id));
+    this->m_file_id = NULL;
+    if (status != NX_OK) {
+      throw Exception("NXclose failed", status);
+    }
+  }
+}
+
+void File::flush() {
+  NXstatus status = NXflush(&(this->m_file_id));
+  if (status != NX_OK) {
+    throw Exception("NXflush failed", status);
+  }
+}
+
+void File::makeGroup(const string& name, const string& class_name, bool open_group) {
+  if (name.empty()) {
+    throw Exception("Supplied empty name to makeGroup");
+  }
+  if (class_name.empty()) {
+    throw Exception("Supplied empty class name to makeGroup");
+  }
+  NXstatus status = NXmakegroup(this->m_file_id, name.c_str(),
+                                class_name.c_str());
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXmakegroup(" << name << ", " << class_name << ") failed";
+    throw Exception(msg.str(), status);
+  }
+  if (open_group) {
+      this->openGroup(name, class_name);
+  }
+}
+
+void File::openGroup(const string& name, const string& class_name) {
+  if (name.empty()) {
+    throw Exception("Supplied empty name to openGroup");
+  }
+  if (class_name.empty()) {
+    throw Exception("Supplied empty class name to openGroup");
+  }
+  NXstatus status = NXopengroup(this->m_file_id, name.c_str(),
+                                class_name.c_str());
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXopengroup(" << name << ", " << class_name << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+void File::openPath(const string& path) {
+  if (path.empty()) {
+    throw Exception("Supplied empty path to openPath");
+  }
+  NXstatus status = NXopenpath(this->m_file_id, path.c_str());
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXopenpath(" << path << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+void File::openGroupPath(const string& path) {
+  if (path.empty()) {
+    throw Exception("Supplied empty path to openGroupPath");
+  }
+  NXstatus status = NXopengrouppath(this->m_file_id, path.c_str());
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXopengrouppath(" << path << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+std::string File::getPath(){
+  char cPath[2048];
+
+  memset(cPath,0,sizeof(cPath));
+  NXstatus status = NXgetpath(this->m_file_id,cPath, sizeof(cPath)-1);
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXgetpath() failed";
+    throw Exception(msg.str(), status);
+  }
+  return std::string(cPath);
+}
+
+void File::closeGroup() {
+  NXstatus status = NXclosegroup(this->m_file_id);
+  if (status != NX_OK) {
+    throw Exception("NXclosegroup failed", status);
+  }
+}
+
+void File::makeData(const string& name, NXnumtype type,
+                    const vector<int>& dims, bool open_data) {
+  this->makeData(name, type, toInt64(dims), open_data);
+}
+
+void File::makeData(const string& name, NXnumtype type,
+                    const vector<int64_t>& dims, bool open_data) {
+  // error check the parameters
+  if (name.empty()) {
+    throw Exception("Supplied empty label to makeData");
+  }
+  if (dims.empty()) {
+    throw Exception("Supplied empty dimensions to makeData");
+  }
+
+  // do the work
+  NXstatus status = NXmakedata64(this->m_file_id, name.c_str(), (int)type,
+                               dims.size(), const_cast<int64_t*>(&(dims[0])));
+  // report errors
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXmakedata(" << name << ", " << type << ", " << dims.size()
+        << ", " << toString(dims) << ") failed";
+    throw Exception(msg.str(), status);
+  }
+  if (open_data) {
+      this->openData(name);
+  }
+}
+
+template <typename NumT>
+void File::makeData(const string & name, const NXnumtype type,
+                    const NumT length, bool open_data) {
+  vector<int64_t> dims;
+  dims.push_back(static_cast<int64_t>(length));
+  this->makeData(name, type, dims, open_data);
+}
+
+template <typename NumT>
+void File::writeData(const string& name, const NumT& value) {
+  std::vector<NumT> v(1, value);
+  this->writeData(name, v);
+}
+
+void File::writeData(const string& name, const char* value) {
+  this->writeData(name, std::string(value));
+}
+
+void File::writeData(const string& name, const string& value)
+{
+  string my_value(value);
+  // Allow empty strings by defaulting to a space
+  if (my_value.empty())
+    my_value = " ";
+  vector<int> dims;
+  dims.push_back(static_cast<int>(my_value.size()));
+  this->makeData(name, CHAR, dims, true);
+
+  this->putData(&(my_value[0]));
+
+  this->closeData();
+}
+
+
+
+template <typename NumT>
+void File::writeData(const string& name, const vector<NumT>& value) {
+  vector<int64_t> dims(1, value.size());
+  this->writeData(name, value, dims);
+}
+
+template <typename NumT>
+void File::writeData(const string& name, const vector<NumT>& value,
+                     const vector<int>& dims) {
+  this->makeData(name, getType<NumT>(), dims, true);
+  this->putData(value);
+  this->closeData();
+}
+
+template <typename NumT>
+void File::writeData(const string& name, const vector<NumT>& value,
+                     const vector<int64_t>& dims) {
+  this->makeData(name, getType<NumT>(), dims, true);
+  this->putData(value);
+  this->closeData();
+}
+
+
+template <typename NumT>
+void File::writeExtendibleData(const string& name, vector<NumT>& value)
+{
+  // Use a default chunk size of 4096 bytes. TODO: Is this optimal?
+  writeExtendibleData(name, value, 4096);
+}
+
+template <typename NumT>
+void File::writeExtendibleData(const string& name, vector<NumT>& value, const int64_t chunk)
+{
+  vector<int64_t> dims(1, NX_UNLIMITED);
+  vector<int64_t> chunk_dims(1, chunk);
+  // Use chunking without using compression
+  this->makeCompData(name, getType<NumT>(), dims, NONE, chunk_dims, true );
+  this->putSlab(value, int64_t(0), int64_t(value.size()));
+  this->closeData();
+}
+
+template <typename NumT>
+void File::writeExtendibleData(const string& name, vector<NumT>& value,
+    vector<int64_t>& dims, std::vector<int64_t> & chunk)
+{
+  // Create the data with unlimited 0th dimensions
+  std::vector<int64_t> unlim_dims(dims);
+  unlim_dims[0] = NX_UNLIMITED;
+  // Use chunking without using compression
+  this->makeCompData(name, getType<NumT>(), unlim_dims, NONE, chunk, true );
+  // And put that slab of that of that given size in there
+  std::vector<int64_t> start( dims.size(), 0 );
+  this->putSlab(value, start, dims);
+  this->closeData();
+
+}
+
+
+template <typename NumT>
+void File::writeUpdatedData(const std::string& name, std::vector<NumT>& value)
+{
+  this->openData(name);
+  this->putSlab(value, int64_t(0), int64_t(value.size()));
+  this->closeData();
+}
+
+template <typename NumT>
+void File::writeUpdatedData(const std::string& name, std::vector<NumT>& value,
+                            std::vector<int64_t>& dims)
+{
+  this->openData(name);
+  std::vector<int64_t> start( dims.size(), 0 );
+  this->putSlab(value, start, dims);
+  this->closeData();
+}
+
+
+void File::makeCompData(const string& name, const NXnumtype type,
+                        const vector<int>& dims, const NXcompression comp,
+                        const vector<int>& bufsize, bool open_data) {
+  this->makeCompData(name, type, toInt64(dims), comp, toInt64(bufsize), open_data);
+}
+
+void File::makeCompData(const string& name, const NXnumtype type,
+                        const vector<int64_t>& dims, const NXcompression comp,
+                        const vector<int64_t>& bufsize, bool open_data) {
+  // error check the parameters
+  if (name.empty()) {
+    throw Exception("Supplied empty name to makeCompData");
+  }
+  if (dims.empty()) {
+    throw Exception("Supplied empty dimensions to makeCompData");
+  }
+  if (bufsize.empty()) {
+    throw Exception("Supplied empty bufsize to makeCompData");
+  }
+  if (dims.size() != bufsize.size()) {
+    stringstream msg;
+    msg << "Supplied dims rank=" << dims.size()
+        << " must match supplied bufsize rank=" << bufsize.size()
+        << "in makeCompData";
+    throw Exception(msg.str());
+  }
+
+  // do the work
+  int i_type = static_cast<int>(type);
+  int i_comp = static_cast<int>(comp);
+  NXstatus status = NXcompmakedata64(this->m_file_id, name.c_str(), i_type,
+                                   dims.size(),
+                                   const_cast<int64_t *>(&(dims[0])), i_comp,
+                                   const_cast<int64_t *>(&(bufsize[0])));
+
+  // report errors
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXcompmakedata64(" << name << ", " << type << ", " << dims.size()
+        << ", " << toString(dims) << ", " << comp << ", " << toString(bufsize)
+        << ") failed";
+    throw Exception(msg.str(), status);
+  }
+  if (open_data) {
+	this->openData(name);
+  }
+}
+
+template <typename NumT>
+void File::writeCompData(const string & name, const vector<NumT> & value,
+                       const vector<int> & dims, const NXcompression comp,
+                         const vector<int> & bufsize) {
+  this->writeCompData(name, value, toInt64(dims), comp, toInt64(bufsize));
+}
+
+template <typename NumT>
+void File::writeCompData(const string & name, const vector<NumT> & value,
+                       const vector<int64_t> & dims, const NXcompression comp,
+                         const vector<int64_t> & bufsize) {
+  this->makeCompData(name, getType<NumT>(), dims, comp, bufsize, true);
+  this->putData(value);
+  this->closeData();
+}
+
+void File::compress(NXcompression comp) {
+  stringstream msg;
+  msg << "compress(" << comp << ") is depricated - use makeCompData()";
+  throw Exception(msg.str());
+}
+
+void File::openData(const string & name) {
+  if (name.empty()) {
+    throw Exception("Supplied empty name to openData");
+  }
+  NXstatus status = NXopendata(this->m_file_id, name.c_str());
+  if (status != NX_OK) {
+    throw Exception("NXopendata(" + name + ") failed", status);
+  }
+}
+
+void File::closeData() {
+  NXstatus status = NXclosedata(this->m_file_id);
+  if (status != NX_OK) {
+    throw Exception("NXclosedata() failed", status);
+  }
+}
+
+void File::putData(const void* data) {
+  if (data == NULL) {
+    throw Exception("Data specified as null in putData");
+  }
+  NXstatus status = NXputdata(this->m_file_id, const_cast<void *>(data));
+  if (status != NX_OK) {
+    throw Exception("NXputdata(void *) failed", status);
+  }
+}
+
+template <typename NumT>
+void File::putData(const vector<NumT> & data) {
+  if (data.empty()) {
+    throw Exception("Supplied empty data to putData");
+  }
+  this->putData(&(data[0]));
+}
+
+void File::putAttr(const AttrInfo& info, const void* data) {
+  if (info.name == NULL_STR) {
+    throw Exception("Supplied bad attribute name \"" + NULL_STR + "\"");
+  }
+  if (info.name.empty()) {
+    throw Exception("Supplied empty name to putAttr");
+  }
+  NXstatus status = NXputattr(this->m_file_id, info.name.c_str(),
+                              const_cast<void *>(data), info.length,
+                              (int)(info.type));
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXputattr(" << info.name << ", data, " << info.length << ", "
+        << info.type << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+template <typename NumT>
+void File::putAttr(const std::string& name, const NumT value) {
+  AttrInfo info;
+  info.name = name;
+  info.length = 1;
+  info.type = getType<NumT>();
+  this->putAttr(info, &value);
+}
+
+void File::putAttr(const char* name, const char* value) {
+  if (name == NULL) {
+    throw Exception("Specified name as null to putAttr");
+  }
+  if (value == NULL) {
+    throw Exception("Specified value as null to putAttr");
+  }
+  string s_name(name);
+  string s_value(value);
+  this->putAttr(s_name, s_value);
+}
+
+void File::putAttr(const std::string& name, const std::string value) {
+  string my_value(value);
+  if (my_value.empty())
+    my_value = " "; // Make a default "space" to avoid errors.
+  AttrInfo info;
+  info.name = name;
+  info.length = static_cast<int>(my_value.size());
+  info.type = CHAR;
+  this->putAttr(info, &(my_value[0]));
+}
+
+void File::putSlab(void* data, vector<int>& start, vector<int>& size) {
+  vector<int64_t> start_big = toInt64(start);
+  vector<int64_t> size_big = toInt64(size);
+  this->putSlab(data, start_big, size_big);
+}
+
+void File::putSlab(void* data, vector<int64_t>& start, vector<int64_t>& size) {
+  if (data == NULL) {
+    throw Exception("Data specified as null in putSlab");
+  }
+  if (start.empty()) {
+    throw Exception("Supplied empty start to putSlab");
+  }
+  if (size.empty()) {
+    throw Exception("Supplied empty size to putSlab");
+  }
+  if (start.size() != size.size()) {
+    stringstream msg;
+    msg << "Supplied start rank=" << start.size()
+        << " must match supplied size rank=" << size.size()
+        << "in putSlab";
+    throw Exception(msg.str());
+  }
+  NXstatus status = NXputslab64(this->m_file_id, data, &(start[0]), &(size[0]));
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXputslab64(data, " << toString(start) << ", " << toString(size)
+        << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+template <typename NumT>
+void File::putSlab(vector<NumT>& data, vector<int>& start,
+                   vector<int>& size) {
+  vector<int64_t> start_big = toInt64(start);
+  vector<int64_t> size_big = toInt64(size);
+  this->putSlab(data, start_big, size_big);
+}
+
+template <typename NumT>
+void File::putSlab(vector<NumT>& data, vector<int64_t>& start,
+                   vector<int64_t>& size) {
+  if (data.empty()) {
+    throw Exception("Supplied empty data to putSlab");
+  }
+  this->putSlab(&(data[0]), start, size);
+}
+
+template <typename NumT>
+void File::putSlab(vector<NumT>& data, int start, int size) {
+  this->putSlab(data, static_cast<int64_t>(start), static_cast<int64_t>(size));
+}
+
+template <typename NumT>
+void File::putSlab(vector<NumT>& data, int64_t start, int64_t size) {
+  vector<int64_t> start_v;
+  start_v.push_back(start);
+  vector<int64_t> size_v;
+  size_v.push_back(size);
+  this->putSlab(data, start_v, size_v);
+}
+
+NXlink File::getDataID() {
+  NXlink link;
+  NXstatus status = NXgetdataID(this->m_file_id, &link);
+  if (status != NX_OK) {
+    throw Exception("NXgetdataID failed", status);
+  }
+  return link;
+}
+
+bool File::isDataSetOpen()
+{
+  NXlink id;
+  if(NXgetdataID(this->m_file_id,&id) == NX_ERROR)
+  {
+    return false;
+  }
+  else 
+  {
+    return true;
+  }
+}
+/*----------------------------------------------------------------------*/
+
+void File::makeLink(NXlink& link) {
+  NXstatus status = NXmakelink(this->m_file_id, &link);
+  if (status != NX_OK) {
+    throw Exception("NXmakelink failed", status);
+  }
+}
+
+void File::makeNamedLink(const string& name, NXlink& link) {
+  if (name.empty()) {
+    throw Exception("Supplied empty name to makeNamedLink");
+  }
+  NXstatus status = NXmakenamedlink(this->m_file_id, name.c_str(), &link);
+  if (status != NX_OK) {
+    throw Exception("NXmakenamedlink(" + name + ", link)", status);
+  }
+}
+
+void File::openSourceGroup() {
+  NXstatus status = NXopensourcegroup(this->m_file_id);
+  if (status != NX_OK) {
+    throw Exception("NXopensourcegroup failed");
+  }
+}
+
+void File::getData(void* data) {
+  if (data == NULL) {
+    throw Exception("Supplied null pointer to getData");
+  }
+  NXstatus status = NXgetdata(this->m_file_id, data);
+  if (status != NX_OK) {
+    throw Exception("NXgetdata failed", status);
+  }
+}
+
+template <typename NumT>
+std::vector<NumT> * File::getData() {
+  Info info = this->getInfo();
+  if (info.type != getType<NumT>()) {
+    throw Exception("NXgetdata failed - invalid vector type");
+  }
+
+  // determine the number of elements
+  int64_t length=1;
+  for (vector<int64_t>::const_iterator it = info.dims.begin();
+       it != info.dims.end(); it++) {
+    length *= *it;
+  }
+
+  // allocate memory to put the data into
+  void * temp;
+  inner_malloc(temp, info.dims, info.type);
+
+  // fetch the data
+  this->getData(temp);
+
+  // put it in the vector
+  vector<NumT> * result = new vector<NumT>(static_cast<NumT *>(temp),
+                                           static_cast<NumT *>(temp)
+                                           + static_cast<size_t>(length));
+
+  inner_free(temp);
+  return result;
+}
+
+template <typename NumT>
+void File::getData(vector<NumT>& data) {
+  Info info = this->getInfo();
+
+  if (info.type != getType<NumT>())
+  {
+    throw Exception("NXgetdata failed - invalid vector type");
+  }
+  // determine the number of elements
+  int64_t length=1;
+  for (vector<int64_t>::const_iterator it = info.dims.begin();
+       it != info.dims.end(); it++) {
+    length *= *it;
+  }
+
+  // allocate memory to put the data into
+  // need to use resize() rather than reserve() so vector length gets set
+  data.resize(length);
+
+  // fetch the data
+  this->getData(&(data[0]));
+}
+
+
+void File::getDataCoerce(vector<int> &data)
+{
+  Info info = this->getInfo();
+  if (info.type == INT8)
+  {
+    vector<int8_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == UINT8)
+  {
+    vector<uint8_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == INT16)
+  {
+    vector<int16_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == UINT16)
+  {
+    vector<uint16_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == INT32)
+  {
+    vector<int32_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == UINT32)
+  {
+    vector<uint32_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else
+  {
+    throw Exception("NexusFile::getDataCoerce(): Could not coerce to int.");
+  }
+}
+
+void File::getDataCoerce(vector<double> &data)
+{
+  Info info = this->getInfo();
+  if (info.type == INT8)
+  {
+    vector<int8_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == UINT8)
+  {
+    vector<uint8_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == INT16)
+  {
+    vector<int16_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == UINT16)
+  {
+    vector<uint16_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == INT32)
+  {
+    vector<int32_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == UINT32)
+  {
+    vector<uint32_t> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == FLOAT32)
+  {
+    vector<float> result;
+    this->getData(result);
+    data.assign(result.begin(), result.end());
+  }
+  else if (info.type == FLOAT64)
+  {
+    this->getData(data);
+  }
+  else
+  {
+    throw Exception("NexusFile::getDataCoerce(): Could not coerce to double.");
+  }
+}
+
+template <typename NumT>
+void File::readData(const std::string & dataName, std::vector<NumT>& data)
+{
+  this->openData(dataName);
+  this->getData(data);
+  this->closeData();
+}
+
+template <typename NumT>
+void File::readData(const std::string & dataName, NumT & data)
+{
+  std::vector<NumT> dataVector;
+  this->openData(dataName);
+  this->getData(dataVector);
+  if (dataVector.size() > 0)
+    data = dataVector[0];
+  this->closeData();
+}
+
+void File::readData(const std::string & dataName, std::string& data)
+{
+  this->openData(dataName);
+  data = this->getStrData();
+  this->closeData();
+}
+
+bool File::isDataInt()
+{
+  Info info = this->getInfo();
+  switch(info.type)
+  {
+  case INT8:
+  case UINT8:
+  case INT16:
+  case UINT16:
+  case INT32:
+  case UINT32:
+    return true;
+  default:
+    return false;
+  }
+}
+
+
+
+string File::getStrData() {
+  string res;
+  Info info = this->getInfo();
+  if (info.type != NX_CHAR) {
+    stringstream msg;
+    msg << "Cannot use getStrData() on non-character data. Found type="
+        << info.type;
+    throw Exception(msg.str());
+  }
+  if (info.dims.size() != 1) {
+    stringstream msg;
+    msg << "getStrData() only understand rank=1 data. Found rank="
+        << info.dims.size();
+    throw Exception(msg.str());
+  }
+  char* value = new char[info.dims[0]+1]; // probably do not need +1, but being safe
+  try{
+     this->getData(value);
+  }
+  catch (const Exception& e)
+  {
+    delete[] value;
+    throw e;
+  }
+  res = string(value, info.dims[0]);
+  delete[] value;
+  return res;
+}
+
+Info File::getInfo() {
+  //vector<int> & dims, NXnumtype & type) {
+  int64_t dims[NX_MAXRANK];
+  int type;
+  int rank;
+  NXstatus status = NXgetinfo64(this->m_file_id, &rank, dims, &type);
+  if (status != NX_OK) {
+    throw Exception("NXgetinfo failed", status);
+  }
+  Info info;
+  info.type = static_cast<NXnumtype>(type);
+  for (int i = 0; i < rank; i++) {
+    info.dims.push_back(dims[i]);
+  }
+  return info;
+}
+
+pair<string, string> File::getNextEntry() {
+  // set up temporary variables to get the information
+  char name[NX_MAXNAMELEN];
+  char class_name[NX_MAXNAMELEN];
+  int datatype;
+
+  NXstatus status = NXgetnextentry(this->m_file_id, name, class_name,
+                                   &datatype);
+  if (status == NX_OK) {
+    string str_name(name);
+    string str_class(class_name);
+    return pair<string,string>(str_name, str_class);
+  }
+  else if (status == NX_EOD) {
+    return pair<string,string>(NULL_STR, NULL_STR); // TODO return the correct thing
+  }
+  else {
+    throw Exception("NXgetnextentry failed", status);
+  }
+}
+
+map<string, string> File::getEntries()
+{
+  map<string, string> result;
+  this->getEntries(result);
+  return result;
+}
+
+void File::getEntries(std::map<std::string, std::string> & result)
+{
+  result.clear();
+  this->initGroupDir();
+  pair<string,string> temp;
+  while (true) {
+    temp = this->getNextEntry();
+    if (temp.first == NULL_STR && temp.second == NULL_STR) { // TODO this needs to be changed when getNextEntry is fixed
+      break;
+    }
+    else {
+	    result.insert(temp);
+    }
+  }
+}
+
+
+void File::getSlab(void* data, const vector<int>& start,
+                   const vector<int>& size) {
+  this->getSlab(data, toInt64(start), toInt64(size));
+}
+
+void File::getSlab(void* data, const vector<int64_t>& start,
+                   const vector<int64_t>& size) {
+  if (data == NULL) {
+    throw Exception("Supplied null pointer to getSlab");
+  }
+  if (start.size() <= 0) {
+    stringstream msg;
+    msg << "Supplied empty start offset, rank = " << start.size()
+        << " in getSlab";
+    throw Exception(msg.str());
+  }
+  if (start.size() != size.size()) {
+    stringstream msg;
+    msg << "In getSlab start rank=" << start.size() << " must match size rank="
+        << size.size();
+    throw Exception(msg.str());
+  }
+
+  NXstatus status = NXgetslab64(this->m_file_id, data, &(start[0]), &(size[0]));
+  if (status != NX_OK) {
+    throw Exception("NXgetslab failed", status);
+  }
+}
+
+AttrInfo File::getNextAttr() {
+  //string & name, int & length, NXnumtype type) {
+  char name[NX_MAXNAMELEN];
+  int type;
+  int length;
+  NXstatus status = NXgetnextattr(this->m_file_id, name, &length, &type);
+  if (status == NX_OK) {
+    AttrInfo info;
+    info.type = static_cast<NXnumtype>(type);
+    info.length = length;
+    info.name = string(name);
+    return info;
+  }
+  else if (status == NX_EOD) {
+    AttrInfo info;
+    info.name = NULL_STR;
+    info.length = 0;
+    return info;
+  }
+  else {
+    throw Exception("NXgetnextattr failed", status);
+  }
+}
+
+void File::getAttr(const AttrInfo& info, void* data, int length) {
+  char name[NX_MAXNAMELEN];
+  strcpy(name, info.name.c_str());
+  int type = info.type;
+  if (length < 0)
+  {
+      length = info.length;
+  }
+  NXstatus status = NXgetattr(this->m_file_id, name, data, &length,
+                              &type);
+  if (status != NX_OK) {
+    throw Exception("NXgetattr(" + info.name + ") failed", status);
+  }
+  if (type != info.type) {
+    stringstream msg;
+    msg << "NXgetattr(" << info.name << ") changed type [" << info.type
+        << "->" << type << "]";
+    throw Exception(msg.str());
+  }
+  // char attributes are always NULL terminated and so may change length
+  if (static_cast<unsigned>(length) != info.length && type != NX_CHAR) {
+    stringstream msg;
+    msg << "NXgetattr(" << info.name << ") change length [" << info.length
+        << "->" << length << "]";
+    throw Exception(msg.str());
+  }
+}
+
+
+template <typename NumT>
+NumT File::getAttr(const AttrInfo& info) {
+  NumT value;
+  this->getAttr(info, &value);
+  return value;
+}
+
+template <>
+NXDLL_EXPORT void File::getAttr(const std::string& name, std::string& value)
+{
+    AttrInfo info;
+    info.type = getType<char>();
+    info.length = 2000; ///< @todo need to find correct length of attribute
+    info.name = name;
+    value = this->getStrAttr(info);
+}
+
+template <typename NumT>
+void File::getAttr(const std::string& name, NumT& value)
+{
+    AttrInfo info;
+    info.type = getType<NumT>();
+    info.length = 1;
+    info.name = name;
+    value = this->getAttr<NumT>(info);
+}
+ 
+
+string File::getStrAttr(const AttrInfo & info) {
+  string res;
+  if (info.type != CHAR) {
+    stringstream msg;
+    msg << "getStrAttr only works with strings (type=" << CHAR
+        << ") found type=" << info.type;
+    throw Exception(msg.str());
+  }
+  char* value = new char[info.length + 1];
+  try
+  {
+    this->getAttr(info, value, info.length+1);
+  }
+  catch (Exception& e)
+  {
+    //Avoid memory leak
+    delete [] value;
+    throw e; //re-throw
+  }
+
+  //res = string(value, info.length);
+  //allow the constructor to find the ending point of the string. Janik Zikovsky, sep 22, 2010
+  res = string(value);
+  delete [] value;
+
+  return res;
+}
+
+vector<AttrInfo> File::getAttrInfos() {
+  vector<AttrInfo> infos;
+  this->initAttrDir();
+  AttrInfo temp;
+  while(true) {
+    temp = this->getNextAttr();
+    if (temp.name == NULL_STR) {
+      break;
+    }
+    infos.push_back(temp);
+  }
+  return infos;
+}
+
+bool File::hasAttr(const std::string & name)
+{
+  this->initAttrDir();
+  AttrInfo temp;
+  while(true) {
+    temp = this->getNextAttr();
+    if (temp.name == NULL_STR) {
+      break;
+    }
+    if (temp.name == name)
+      return true;
+  }
+  return false;
+}
+
+
+NXlink File::getGroupID() {
+  NXlink link;
+  NXstatus status = NXgetgroupID(this->m_file_id, &link);
+  if (status != NX_OK) {
+    throw Exception("NXgetgroupID failed", status);
+  }
+  return link;
+}
+
+bool File::sameID(NXlink& first, NXlink& second) {
+  NXstatus status = NXsameID(this->m_file_id, &first, &second);
+  return (status == NX_OK);
+}
+
+void File::printLink(NXlink & link) {
+  NXstatus status = NXIprintlink(this->m_file_id, &link);
+  if (status != NX_OK) {
+    throw Exception("NXprintlink failed");
+  }
+}
+
+void File::initGroupDir() {
+  int status = NXinitgroupdir(this->m_file_id);
+  if (status != NX_OK) {
+    throw Exception("NXinitgroupdir failed", status);
+  }
+}
+
+void File::initAttrDir() {
+  int status = NXinitattrdir(this->m_file_id);
+  if (status != NX_OK) {
+    throw Exception("NXinitattrdir failed", status);
+  }
+}
+
+void File::setNumberFormat(NXnumtype& type, const string& format) {
+  if (format.empty()) {
+    throw Exception("Supplied empty format to setNumberFormat");
+  }
+  char c_format[NX_MAXNAMELEN];
+  strcpy(c_format, format.c_str());
+  NXstatus status = NXsetnumberformat(this->m_file_id, type, c_format);
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXsetnumberformat(" << format << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+string File::inquireFile(const int buff_length) {
+  string filename;
+  char* c_filename = new char[buff_length];
+  NXstatus status = NXinquirefile(this->m_file_id, c_filename, buff_length);
+  if (status != NX_OK) {
+    delete[] c_filename;
+    stringstream msg;
+    msg << "NXinquirefile(" << buff_length << ") failed";
+    throw Exception(msg.str(), status);
+  }
+  filename = c_filename;
+  delete[] c_filename;
+  return filename;
+}
+
+string File::isExternalGroup(const string& name, const string& type,
+                             const unsigned buff_length) {
+  string url; 
+  if (name.empty()) {
+    throw Exception("Supplied empty name to isExternalGroup");
+  }
+  if (type.empty()) {
+    throw Exception("Supplied empty type to isExternalGroup");
+  }
+  char* c_url = new char[buff_length];
+  NXstatus status = NXisexternalgroup(this->m_file_id, name.c_str(),
+                                      type.c_str(), c_url, buff_length);
+  if (status != NX_OK) {
+    delete[] c_url;
+    stringstream msg;
+    msg << "NXisexternalgroup(" <<  type << ", " << buff_length << ")";
+    throw Exception(msg.str(), buff_length);
+  }
+  url = c_url;
+  delete[] c_url;
+  return url;
+}
+
+void File::linkExternal(const string& name, const string& type,
+                        const string& url) {
+  if (name.empty()) {
+    throw Exception("Supplied empty name to linkExternal");
+  }
+  if (type.empty()) {
+    throw Exception("Supplied empty type to linkExternal");
+  }
+  if (url.empty()) {
+    throw Exception("Supplied empty url to linkExternal");
+  }
+  NXstatus status = NXlinkexternal(this->m_file_id, name.c_str(), type.c_str(),
+                                   url.c_str());
+  if (status != NX_OK) {
+    stringstream msg;
+    msg << "NXlinkexternal(" << name << ", " << type << ", " << url
+        << ") failed";
+    throw Exception(msg.str(), status);
+  }
+}
+
+const string File::makeCurrentPath(const string currpath, const string subpath) {
+	std::ostringstream temp;
+	temp << currpath << "/" << subpath;
+	return temp.str();
+}
+
+void File::walkFileForTypeMap(const string path, const string class_name, TypeMap& tmap) {
+	if (!path.empty()) {
+		tmap.insert(std::make_pair(class_name, path));
+	}
+	map<string, string> dirents = this->getEntries();
+	map<string, string>::iterator pos;
+	for (pos = dirents.begin(); pos != dirents.end(); ++pos) {
+		if (pos->second == "SDS") {
+			tmap.insert(std::make_pair(pos->second, this->makeCurrentPath(path, pos->first)));
+		}
+		else if (pos->second == "CDF0.0") {
+			// Do nothing with this
+			;
+		}
+		else {
+			this->openGroup(pos->first, pos->second);
+			this->walkFileForTypeMap(this->makeCurrentPath(path, pos->first), pos->second, tmap);
+		}
+	}
+	this->closeGroup();
+}
+
+TypeMap *File::getTypeMap() {
+	TypeMap *tmap = new TypeMap();
+	// Ensure that we're at the top of the file.
+	this->openPath("/");
+	this->walkFileForTypeMap("", "", *tmap);
+	return tmap;
+}
+
+template<typename NumT>
+void File::malloc(NumT*& data, const Info& info)
+{
+    if (getType<NumT>() != info.type)
+    {
+        throw Exception("Type mismatch in malloc()");
+    }
+    inner_malloc((void*&)data, info.dims, info.type);
+}
+
+template<typename NumT>
+void File::free(NumT*& data)
+{
+    inner_free((void*&)data);
+}
+
+}
+
+/* ---------------------------------------------------------------- */
+/* Concrete instantiations of template definitions.                 */
+/* ---------------------------------------------------------------- */
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const float value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const double value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const int8_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const uint8_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const int16_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const uint16_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const int32_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const uint32_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const int64_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const uint64_t value);
+template
+NXDLL_EXPORT void File::putAttr(const string& name, const char value);
+
+template
+NXDLL_EXPORT float File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT double File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT int8_t File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT uint8_t  File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT int16_t File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT uint16_t  File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT int32_t File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT uint32_t  File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT int64_t File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT uint64_t  File::getAttr(const AttrInfo& info);
+template
+NXDLL_EXPORT char File::getAttr(const AttrInfo& info);
+
+template
+NXDLL_EXPORT void File::makeData(const string & name, const NXnumtype type,
+				 const int length, bool open_data);
+template
+NXDLL_EXPORT void File::makeData(const string & name, const NXnumtype type,
+				 const int64_t length, bool open_data);
+
+template
+NXDLL_EXPORT void File::writeData(const string& name, const float& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const double& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const int8_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const uint8_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const int16_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const uint16_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const int32_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const uint32_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const int64_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const uint64_t& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const char& value);
+
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<float>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<double>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int8_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint8_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int16_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint16_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int32_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint32_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int64_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint64_t>& value);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<char>& value);
+
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<float>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<double>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int8_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint8_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int16_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint16_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int32_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint32_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<int64_t>& value, const std::vector<int>& dims);
+template
+NXDLL_EXPORT void File::writeData(const string& name, const vector<uint64_t>& value, const std::vector<int>& dims);
+
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<float>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<double>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int8_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint8_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int16_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint16_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int32_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint32_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int64_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint64_t>& value);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<char>& value);
+
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<float>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<double>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int8_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint8_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int16_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint16_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int32_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint32_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int64_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint64_t>& value, const int64_t chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<char>& value, const int64_t chunk);
+
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<float>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<double>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int8_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint8_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int16_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint16_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int32_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint32_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<int64_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<uint64_t>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+template
+NXDLL_EXPORT void File::writeExtendibleData(const string& name, std::vector<char>& value, std::vector<int64_t> & dims, std::vector<int64_t> & chunk);
+
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<float>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<double>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int8_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint8_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int16_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint16_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int32_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint32_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int64_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint64_t>& value);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<char>& value);
+
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<float>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<double>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int8_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint8_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int16_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint16_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int32_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint32_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<int64_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<uint64_t>& value, std::vector<int64_t> & dims);
+template
+NXDLL_EXPORT void File::writeUpdatedData(const string& name, vector<char>& value, std::vector<int64_t> & dims);
+
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<float> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<float> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<double> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<double> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int8_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int8_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint8_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint8_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int16_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int16_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint16_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint16_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int32_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int32_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint32_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint32_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int64_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<int64_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint64_t> & value,
+                                    const vector<int> & dims, const NXcompression comp,
+                                    const vector<int> & bufsize);
+template
+NXDLL_EXPORT void File::writeCompData(const string & name, const vector<uint64_t> & value,
+                                    const vector<int64_t> & dims, const NXcompression comp,
+                                    const vector<int64_t> & bufsize);
+
+template
+NXDLL_EXPORT vector<float> * File::getData();
+template
+NXDLL_EXPORT vector<double> * File::getData();
+template
+NXDLL_EXPORT vector<int8_t> * File::getData();
+template
+NXDLL_EXPORT vector<uint8_t> * File::getData();
+template
+NXDLL_EXPORT vector<int16_t> * File::getData();
+template
+NXDLL_EXPORT vector<uint16_t> * File::getData();
+template
+NXDLL_EXPORT vector<int32_t> * File::getData();
+template
+NXDLL_EXPORT vector<uint32_t> * File::getData();
+template
+NXDLL_EXPORT vector<int64_t> * File::getData();
+template
+NXDLL_EXPORT vector<uint64_t> * File::getData();
+template
+NXDLL_EXPORT vector<char> * File::getData();
+
+template
+NXDLL_EXPORT void File::getData(vector<float>& data);
+template
+NXDLL_EXPORT void File::getData(vector<double>& data);
+template
+NXDLL_EXPORT void File::getData(vector<int8_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<uint8_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<int16_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<uint16_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<int32_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<uint32_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<int64_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<uint64_t>& data);
+template
+NXDLL_EXPORT void File::getData(vector<char>& data);
+
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<float>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<double>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<int8_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<uint8_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<int16_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<uint16_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<int32_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<uint32_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<int64_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<uint64_t>& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, vector<char>& data);
+
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, float& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, double& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, int8_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, uint8_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, int16_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, uint16_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, int32_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, uint32_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, int64_t& data);
+template
+NXDLL_EXPORT void File::readData(const std::string & dataName, uint64_t& data);
+
+template
+NXDLL_EXPORT void File::putSlab(std::vector<float>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<double>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int8_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint8_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int16_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint16_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int32_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint32_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int64_t>& data, int start, int size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint64_t>& data, int start, int size);
+
+template
+NXDLL_EXPORT void File::putSlab(std::vector<float>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<double>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int8_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint8_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int16_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint16_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int32_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint32_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<int64_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+template
+NXDLL_EXPORT void File::putSlab(std::vector<uint64_t>& data, std::vector<int64_t> & start, std::vector<int64_t> & size);
+
+template 
+NXDLL_EXPORT void File::getAttr(const std::string& name, double& value);
+template 
+NXDLL_EXPORT void File::getAttr(const std::string& name, int& value);
+
+template
+NXDLL_EXPORT void File::malloc(int*& data, const Info& info);
+template
+NXDLL_EXPORT void File::malloc(float*& data, const Info& info);
+template
+NXDLL_EXPORT void File::malloc(double*& data, const Info& info);
+
+template
+NXDLL_EXPORT void File::free(int*& data);
+template
+NXDLL_EXPORT void File::free(float*& data);
+template
+NXDLL_EXPORT void File::free(double*& data);
diff --git a/bindings/cpp/NeXusFile.hpp b/bindings/cpp/NeXusFile.hpp
new file mode 100644
index 0000000..ad6bf30
--- /dev/null
+++ b/bindings/cpp/NeXusFile.hpp
@@ -0,0 +1,853 @@
+#ifndef NEXUSFILE_HPP
+#define NEXUSFILE_HPP 1
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+#include "napi.h"
+
+#ifdef _WIN32
+
+#ifndef _MSC_VER 
+#  define NXDLL_EXPORT
+#else
+#  if IN_NEXUS_CPP_LIBRARY
+#    define NXDLL_EXPORT __declspec(dllexport)
+#  else
+#    define NXDLL_EXPORT __declspec(dllimport)
+#  endif
+#endif /* _MSC_VER */
+
+#else /* _WIN32 */
+#  define NXDLL_EXPORT 
+#endif /* _WIN32 */
+
+/**
+ * \file NeXusFile.hpp Definition of the NeXus C++ API.
+ * \defgroup cpp_types C++ Types
+ * \defgroup cpp_core C++ Core
+ * \ingroup cpp_main
+ */
+
+namespace NeXus {
+  /**
+   * The primitive types published by this API.
+   * \li FLOAT32 float.
+   * \li FLOAT64 double
+   * \li INT8 int8_t
+   * \li UINT8 uint8_t
+   * \li INT16 int16_t
+   * \li UINT16 uint16_t
+   * \li INT32 int32_t
+   * \li UINT32 uint32_t
+   * \li INT64 int8_t if available on the machine
+   * \li UINT64 uint8_t if available on the machine
+   * \ingroup cpp_types
+   */
+  enum NXnumtype {
+    FLOAT32 = NX_FLOAT32,
+    FLOAT64 = NX_FLOAT64,
+    INT8 = NX_INT8,
+    UINT8 = NX_UINT8,
+    // BOOLEAN = NX_BOOLEAN, // NX_BOOLEAN is currently broken
+    INT16 = NX_INT16,
+    UINT16 = NX_UINT16,
+    INT32 = NX_INT32,
+    UINT32 = NX_UINT32,
+    INT64 = NX_INT64,
+    UINT64 = NX_UINT64,
+    CHAR = NX_CHAR,
+    BINARY = NX_BINARY
+  };
+
+  /**
+   * The available compression types. These are all ignored in xml files.
+   * \li NONE no compression
+   * \li LZW Lossless Lempel Ziv Welch compression (recommended)
+   * \li RLE Run length encoding (only HDF-4)
+   * \li HUF Huffmann encoding (only HDF-4)
+   * \ingroup cpp_types
+   */
+  enum NXcompression {
+    CHUNK = NX_CHUNK,
+    NONE = NX_COMP_NONE,
+    LZW = NX_COMP_LZW,
+    RLE = NX_COMP_RLE,
+    HUF = NX_COMP_HUF
+  };
+
+  /**
+   * Type definition for a type-keyed multimap
+   */
+  typedef std::multimap<std::string, std::string> TypeMap;
+
+  /**
+   * This structure holds the type and dimensions of a primative field/array.
+   */
+  struct Info{
+    /** The primative type for the field. */
+    NXnumtype type;
+    /** The dimensions of the file. */
+    std::vector<int64_t> dims;
+  };
+
+  /** Information about an attribute. */
+  struct AttrInfo{
+    /** The primative type for the attribute. */
+    NXnumtype type;
+    /** The length of the attribute. */
+    unsigned length;
+    /** The name of the attribute. */
+    std::string name;
+  };
+
+  /**
+   * The Object that allows access to the information in the file.
+   * \ingroup cpp_core
+   */
+  class NXDLL_EXPORT File
+  {
+  private:
+    /** The handle for the C-API. */
+    NXhandle m_file_id;
+    /** should be close handle on exit */
+    bool m_close_handle;
+
+  public:
+    /**
+     * \return A pair of the next entry available in a listing.
+     */
+    std::pair<std::string, std::string> getNextEntry();
+    /**
+     * \return Information about the next attribute.
+     */
+    AttrInfo getNextAttr();
+
+  private:
+    /**
+     * This is a deprecated function.
+     * \param com The compression type.
+     */
+    void compress(NXcompression comp);
+
+    /**
+     * Initialize the pending group search to start again.
+     */
+    void initGroupDir();
+
+    /**
+     * Initialize the pending attribute search to start again.
+     */
+    void initAttrDir();
+
+    /**
+     * Function to walk the file tree and fill in the TypeMap.
+     *
+     * \param path the current path in the file
+     * \param class_name the current NX class name
+     * \param tmap the typemap being constructed
+     */
+    void walkFileForTypeMap(const std::string path, const std::string class_name, TypeMap &tmap);
+
+    /**
+     * Function to append new path to current one.
+     * \param currpath the current path to append to
+     * \param subpath the path to append to the current path
+     * \return the newly joined path
+     */
+    const std::string makeCurrentPath(const std::string currpath, const std::string subpath);
+
+    /**
+     * Function to consolidate the file opening code for the various constructors
+     * \param filename The name of the file to open.
+     * \param access How to access the file.
+     */
+    void initOpenFile(const std::string& filename, const NXaccess access = NXACC_READ);
+
+  public:
+    /**
+     * Create a new File.
+     *
+     * \param filename The name of the file to open.
+     * \param access How to access the file.
+     */
+    File(const std::string& filename, const NXaccess access = NXACC_READ);
+
+    /**
+     * Create a new File.
+     *
+     * \param filename The name of the file to open.
+     * \param access How to access the file.
+     */
+    File(const char *filename, const NXaccess access = NXACC_READ);
+
+    /**
+     * Use an existing handle returned from NXopen()
+     *
+     * \param handle Handle to connect to
+     * \param close_handle Should the handle be closed on destruction
+     */
+    File(NXhandle handle, bool close_handle = false);
+
+    /** Destructor. This does close the file. */
+    ~File();
+
+    /** Close the file before the constructor is called. */
+    void close();
+
+    /** Flush the file. */
+    void flush();
+
+    template<typename NumT>
+    void malloc(NumT*& data, const Info& info);
+
+    template<typename NumT>
+    void free(NumT*& data);
+
+    /**
+     * Create a new group.
+     *
+     * \param name The name of the group to create (i.e. "entry").
+     * \param class_name The type of group to create (i.e. "NXentry").
+     * \param open_group Whether or not to automatically open the group after 
+     * creating it.
+     */
+    void makeGroup(const std::string& name, const std::string& class_name,
+                   bool open_group = false);
+
+    /**
+     * Open an existing group.
+     *
+     * \param name The name of the group to create (i.e. "entry").
+     * \param class_name The type of group to create (i.e. "NXentry").
+     */
+    void openGroup(const std::string& name, const std::string& class_name);
+
+    /**
+     * Open the NeXus object with the path specified.
+     *
+     * \param path A unix like path string to a group or field. The path 
+     * string is a list of group names and SDS names separated with a slash,
+     * '/' (i.e. "/entry/sample/name").
+     */
+    void openPath(const std::string& path);
+
+    /**
+     * Open the group in which the NeXus object with the specified path exists.
+     *
+     * \param path A unix like path string to a group or field. The path 
+     * string is a list of group names and SDS names separated with a slash,
+     * '/' (i.e. "/entry/sample/name").
+     */
+    void openGroupPath(const std::string& path);
+    /**
+     * Get the path into the current file
+     * \return A unix like path string pointing to the current 
+     *         position in the file
+     */
+    std::string  getPath();
+
+    /**
+     * Close the currently open group.
+     */
+    void closeGroup();
+
+    /**
+     * \copydoc NeXus::File::makeData(const std::string&, NXnumtype,
+     *                              const std::vector<int64_t>&, bool);
+     */
+    void makeData(const std::string& name, NXnumtype type,
+                  const std::vector<int>& dims, bool open_data = false);
+
+    /**
+     * Create a data field with the specified information.
+     *
+     * \param name The name of the field to create (i.e. "distance").
+     * \param type The primative type of the field (i.e. "NeXus::FLOAT32").
+     * \param dims The dimensions of the field.
+     * \param open_data Whether or not to open the data after creating it.
+     */
+    void makeData(const std::string& name, NXnumtype type,
+                  const std::vector<int64_t>& dims, bool open_data = false);
+
+    /**
+     * Create a 1D data field with the specified information.
+     *
+     * \param name The name of the field to create (i.e. "distance").
+     * \param type The primative type of the field (i.e. "NeXus::FLOAT32").
+     * \param length The number of elements in the field.
+     * \param open_data Whether or not to open the data after creating it.
+     */
+    template <typename NumT>
+    void makeData(const std::string& name, const NXnumtype type,
+                  const NumT length, bool open_data = false);
+
+    /**
+     * Create a 1D data field, insert the data, and close the data.
+     *
+     * \param name The name of the field to create.
+     * \param value The string to put into the file.
+     */
+    void writeData(const std::string& name, const std::string& value);
+
+    /**
+     * Create a 1D data field, insert the data, and close the data.
+     *
+     * \param name The name of the field to create.
+     * \param value The string to put into the file.
+     */
+    void writeData(const std::string& name, const char* value);
+
+    /**
+     * Create a 1D data field, insert the data, and close the data.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name The name of the field to create.
+     * \param value The vector to put into the file.
+     */
+    template <typename NumT>
+    void writeData(const std::string& name, const std::vector<NumT>& value);
+
+    /**
+     * Create a 1D data field, insert the data, and close the data.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name The name of the field to create.
+     * \param value The value to put into the file.
+     */
+    template <typename NumT>
+    void writeData(const std::string& name, const NumT& value);
+
+    /**
+     * Create a n-dimension data field, insert the data, and close the data.
+     *
+     * \param name The name of the field to create.
+     * \param value The data to put into the file.
+     * \param dims The dimensions of the data.
+     * \tparam NumT numeric data type of \a value
+     */
+    template <typename NumT>
+    void writeData(const std::string& name, const std::vector<NumT>& value,
+                   const std::vector<int>& dims);
+
+	/**
+     * Create a n-dimension data field, insert the data, and close the data.
+     *
+     * \param name The name of the field to create.
+     * \param value The data to put into the file.
+     * \param dims The dimensions of the data.
+     * \tparam NumT numeric data type of \a value
+     */
+    template <typename NumT>
+    void writeData(const std::string& name, const std::vector<NumT>& value,
+                   const std::vector<int64_t>& dims);
+
+    /** Create a 1D data field with an unlimited dimension, insert the data, and close the data.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name :: The name of the field to create.
+     * \param value :: The vector to put into the file.
+     */
+    template <typename NumT>
+    void writeExtendibleData(const std::string& name, std::vector<NumT>& value);
+
+    /** Create a 1D data field with an unlimited dimension, insert the data, and close the data.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name :: The name of the field to create.
+     * \param value :: The vector to put into the file.
+     * \param chunkSize :: chunk size to use when writing
+     */
+    template <typename NumT>
+    void writeExtendibleData(const std::string& name, std::vector<NumT>& value, const int64_t chunk);
+
+    /** Create a 1D data field with an unlimited dimension, insert the data, and close the data.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name :: The name of the field to create.
+     * \param value :: The vector to put into the file.
+     * \param dims :: The dimensions of the data.
+     * \param chunk :: chunk size to use when writing
+     */
+    template <typename NumT>
+    void writeExtendibleData(const std::string& name, std::vector<NumT>& value,
+                             std::vector<int64_t>& dims, std::vector<int64_t> & chunk);
+
+
+    /** Updates the data written into an already-created
+     * data vector. If the data was created as extendible, it will be resized.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name :: The name of the field to create.
+     * \param value :: The vector to put into the file.
+     */
+    template <typename NumT>
+    void writeUpdatedData(const std::string& name, std::vector<NumT>& value);
+
+    /** Updates the data written into an already-created
+     * data vector. If the data was created as extendible, it will be resized.
+     *
+     * \tparam NumT numeric data type of \a value
+     * \param name :: The name of the field to create.
+     * \param value :: The vector to put into the file.
+     * \param dims :: The dimensions of the data.
+     */
+    template <typename NumT>
+    void writeUpdatedData(const std::string& name, std::vector<NumT>& value,
+                          std::vector<int64_t>& dims);
+
+    /**
+     * \copydoc makeCompData(const std::string&, const NXnumtype,
+     *                       const std::vector<int64_t>&, const NXcompression,
+     *                       const std::vector<int64_t>&, bool)
+     */
+    void makeCompData(const std::string& name, const NXnumtype type,
+                      const std::vector<int>& dims, const NXcompression comp,
+                      const std::vector<int>& bufsize, bool open_data = false);
+
+    /**
+     * Create a field with compression.
+     *
+     * \param name The name of the data to create.
+     * \param type The primitive type for the data.
+     * \param dims The dimensions of the data.
+     * \param comp The compression algorithm to use.
+     * \param bufsize The size of the compression buffer to use.
+     * \param open_data Whether or not to open the data after creating it.
+     */
+    void makeCompData(const std::string& name, const NXnumtype type,
+                      const std::vector<int64_t>& dims, const NXcompression comp,
+                      const std::vector<int64_t>& bufsize, bool open_data = false);
+
+    /**
+     * \copydoc writeCompData(const std::string & name,
+     *                        const std::vector<NumT> & value,
+     *                        const std::vector<int64_t> & dims, const NXcompression comp,
+     *                        const std::vector<int64_t> & bufsize)
+     */
+    template <typename NumT>
+    void writeCompData(const std::string & name,
+                       const std::vector<NumT> & value,
+                       const std::vector<int> & dims, const NXcompression comp,
+                       const std::vector<int> & bufsize);
+
+    /**
+     * Create a compressed data, insert the data, and close it.
+     *
+     * \param name The name of the data to create.
+     * \param value The vector to put into the file.
+     * \param dims The dimensions of the data.
+     * \param comp The compression algorithm to use.
+     * \param bufsize The size of the compression buffer to use.
+     * \tparam NumT numeric data type of \a value
+     */
+    template <typename NumT>
+    void writeCompData(const std::string & name,
+                       const std::vector<NumT> & value,
+                       const std::vector<int64_t> & dims, const NXcompression comp,
+                       const std::vector<int64_t> & bufsize);
+
+    /**
+     * \param name The name of the data to open.
+     */
+    void openData(const std::string& name);
+
+    /**
+     * Close the currently open data.
+     */
+    void closeData();
+
+    /**
+     * \param data The data to put in the file.
+     */
+    void putData(const void* data);
+
+    /**
+     * \param data The data to put in the file.
+     * \tparam NumT numeric data type of \a data
+     */
+    template <typename NumT>
+    void putData(const std::vector<NumT>& data);
+
+    /**
+     * Put the supplied data as an attribute into the currently open data.
+     *
+     * \param info Description of the attribute to add.
+     * \param data The attribute value.
+     */
+    void putAttr(const AttrInfo& info, const void* data);
+
+    /**
+     * Put the supplied data as an attribute into the currently open data.
+     *
+     * \param name Name of the attribute to add.
+     * \param value The attribute value.
+     * \tparam NumT numeric data type of \a value
+     */
+    template <typename NumT>
+    void putAttr(const std::string& name, const NumT value);
+
+    /**
+     * Put a string as an attribute in the file.
+     *
+     * \param name Name of the attribute to add.
+     * \param value The attribute value.
+     */
+    void putAttr(const char* name, const char* value);
+
+    /**
+     * Put a string as an attribute in the file.
+     *
+     * \param name Name of the attribute to add.
+     * \param value The attribute value.
+     */
+    void putAttr(const std::string& name, const std::string value);
+
+    /**
+     * \copydoc NeXus::File::putSlab(void* data, std::vector<int64_t>& start,
+     *                                std::vector<int64_t>& size)
+     */
+    void putSlab(void* data, std::vector<int>& start,
+                 std::vector<int>& size);
+
+    /**
+     * Insert an array as part of a data in the final file.
+     *
+     * \param data The array to put in the file.
+     * \param start The starting index to insert the data.
+     * \param size The size of the array to put in the file.
+     */
+    void putSlab(void* data, std::vector<int64_t>& start,
+                 std::vector<int64_t>& size);
+
+    /**
+     * \copydoc NeXus::File::putSlab(std::vector<NumT>& data, std::vector<int64_t>&,
+     *                               std::vector<int64_t>&)
+     */
+    template <typename NumT>
+    void putSlab(std::vector<NumT>& data, std::vector<int>& start,
+                 std::vector<int>& size);
+
+    /**
+     * Insert an array as part of a data in the final file.
+     *
+     * \param data The array to put in the file.
+     * \param start The starting index to insert the data.
+     * \param size The size of the array to put in the file.
+     * \tparam NumT numeric data type of \a data
+     */
+    template <typename NumT>
+    void putSlab(std::vector<NumT>& data, std::vector<int64_t>& start,
+                 std::vector<int64_t>& size);
+
+    /**
+     * \copydoc NeXus::File::putSlab(std::vector<NumT>&, int64_t, int64_t)
+     */
+    template <typename NumT>
+    void putSlab(std::vector<NumT>& data, int start, int size);
+
+    /**
+     * Insert a number as part of a data in the final file.
+     *
+     * \param data The array to put in the file.
+     * \param start The starting index to insert the data.
+     * \param size The size of the array to put in the file.
+     * \tparam NumT numeric data type of \a data
+     */
+    template <typename NumT>
+    void putSlab(std::vector<NumT>& data, int64_t start, int64_t size);
+
+    /**
+     * \return The id of the data used for linking.
+     */
+    NXlink getDataID();
+
+    /**
+     * Create a link in the current location to the supplied id.
+     *
+     * \param link The object (group or data) in the file to link to.
+     */
+    void makeLink(NXlink& link);
+
+    /**
+     * Create a link with a new name.
+     *
+     * \param name The name of this copy of the link.
+     * \param link The object (group or data) in the file to link to.
+     */
+    void makeNamedLink(const std::string& name, NXlink& link);
+
+    /**
+     * Open the original copy of this group or data as declared by the
+     * "target" attribute.
+     */
+    void openSourceGroup();
+
+    /**
+     * Put the currently open data in the supplied pointer.
+     *
+     * \param data The pointer to copy the data to.
+     */
+    void getData(void* data);
+
+    /**
+     * Allocate memory and return the data as a vector. Since this
+     * does call "new vector<NumT>" the caller is responsible for
+     * calling "delete".
+     * \tparam NumT numeric data type of result
+     *
+     * \return The data as a vector.
+     */
+    template <typename NumT>
+    std::vector<NumT> * getData();
+
+    /**
+     * Put data into the supplied vector. The vector does not need to
+     * be the correct size, just the correct type as it is resized to
+     * the appropriate value.
+     *
+     * \param data Where to put the data.
+     * \tparam NumT numeric data type of \a data
+     */
+    template <typename NumT>
+    void getData(std::vector<NumT>& data);
+
+    /** Get data and coerce into an int vector.
+     *
+     * @throw Exception if the data is actually a float or
+     *    another type that cannot be coerced to an int.
+     * @param data :: vector to be filled.
+     */
+    void getDataCoerce(std::vector<int> &data);
+
+    /** Get data and coerce into a vector of doubles.
+     *
+     * @throw Exception if the data cannot be coerced to a double.
+     * @param data :: vector to be filled.
+     */
+    void getDataCoerce(std::vector<double> &data);
+
+    /** Return true if the data opened is of one of the
+     * int data types, 32 bits or less.
+     */
+    bool isDataInt();
+
+    /** Put data into the supplied vector. The vector does not need to
+     * be the correct size, just the correct type as it is resized to
+     * the appropriate value.
+     *
+     * The named data object is opened, loaded, then closed.
+     *
+     * @param dataName :: name of the data to open.
+     * @param data :: Where to put the data.
+     * \tparam NumT numeric data type of \a data
+     */
+    template <typename NumT>
+    void readData(const std::string & dataName, std::vector<NumT>& data);
+
+    /** Put data into the supplied value.
+     *
+     * The named data object is opened, loaded, then closed.
+     *
+     * \param dataName :: name of the data to open.
+     * \param data :: Where to put the data.
+     * \tparam NumT numeric data type of \a data
+     */
+    template <typename NumT>
+    void readData(const std::string & dataName, NumT & data);
+
+    /** Put data into the supplied string. The vector does not need to
+     * be the correct size, just the correct type as it is resized to
+     * the appropriate value.
+     *
+     * The named data object is opened, loaded, then closed.
+     *
+     * @param dataName :: name of the data to open.
+     * @param data :: Where to put the data.
+     */
+    void readData(const std::string & dataName, std::string & data);
+
+    /**
+     * \return String data from the file.
+     */
+    std::string getStrData();
+
+    /**
+     * \return The Info structure that describes the currently open data.
+     */
+    Info getInfo();
+
+    /**
+     * Return the entries available in the current place in the file.
+     */
+    std::map<std::string, std::string> getEntries();
+
+    /** Return the entries available in the current place in the file,
+     * but avoids the map copy of getEntries().
+     *
+     * \param result The map that will be filled with the entries
+     */
+    void getEntries(std::map<std::string, std::string> & result);
+
+    /**
+     * \copydoc NeXus::File::getSlab(void*, const std::vector<int64_t>&,
+     *                               const std::vector<int64_t>&)
+     */
+    void getSlab(void* data, const std::vector<int>& start,
+                 const std::vector<int>& size);
+
+    /**
+     * Get a section of data from the file.
+     *
+     * \param data The pointer to insert that data into.
+     * \param start The offset into the file's data block to start the read 
+     * from.
+     * \param size The size of the block to read from the file.
+     */
+    void getSlab(void* data, const std::vector<int64_t>& start,
+                 const std::vector<int64_t>& size);
+
+    /**
+     * \return Information about all attributes on the data that is
+     * currently open.
+     */
+    std::vector<AttrInfo> getAttrInfos();
+
+    /**
+     *  \return true if the current point in the file has the named attribute
+     *  \param name the name of the attribute to look for.
+     */
+    bool hasAttr(const std::string & name);
+
+    /**
+     * Get the value of the attribute specified by the AttrInfo supplied.
+     *
+     * \param info Designation of which attribute to read.
+     * \param data The pointer to put the attribute value in.
+     * \param length The length of the attribute. If this is "-1" then the 
+     * information in the supplied AttrInfo object will be used.
+     */
+    void getAttr(const AttrInfo& info, void* data, int length = -1);
+
+    /**
+     * Get the value of an attribute that is a scalar number.
+     *
+     * \param info Designation of which attribute to read.
+     * \tparam NumT numeric data type of result
+     *
+     * \return The attribute value.
+     */
+    template <typename NumT>
+    NumT getAttr(const AttrInfo& info);
+
+
+    /**
+     * Get the value of an attribute that is a scalar number.
+     *
+     * \param[in] name Name of attribute to read
+     * \param[out] value The read attribute value.
+     * \tparam NumT numeric data type of \a value
+     */
+    template <typename NumT>
+        void getAttr(const std::string& name, NumT& value);
+
+
+    /**
+     * Get the value of a string attribute.
+     *
+     * \param info Which attribute to read.
+     *
+     * \return The value of the attribute.
+     */
+    std::string getStrAttr(const AttrInfo & info);
+
+    /**
+     * \return The id of the group used for linking.
+     */
+    NXlink getGroupID();
+
+    /**
+     * Determine whether or not two links refer to the same data or group.
+     *
+     * \param first The first link information to compare.
+     * \param second The second link information to compare.
+     *
+     * \return True if the two point at the same data or group.
+     */
+    bool sameID(NXlink& first, NXlink& second);
+
+    /**
+     * Diagnostic print of the link information.
+     *
+     * \param link The link to print to stdout.
+     */
+    void printLink(NXlink & link);
+
+    /**
+     * Set the number format used for a particular type when using the
+     * xml base. This is ignore in the other bases.
+     *
+     * \param type The primitive type to set the format for.
+     * \param format The format to use.
+     */
+    void setNumberFormat(NXnumtype& type, const std::string& format);
+
+    /**
+     * Find out the name of the file this object is holding onto.
+     *
+     * \param buff_length The size of the buffer to use for reading the name.
+     *
+     * \return The name of the file.
+     */
+    std::string inquireFile(const int buff_length = NX_MAXPATHLEN);
+
+    /**
+     * Determine Whether or not a supplied group is external.
+     *
+     * \param name The name of the group to check.
+     * \param type The type of the group to check.
+     * \param buff_length The size of the buffer to use for reading the url.
+     *
+     * \return The url to the external group.
+     */
+    std::string isExternalGroup(const std::string& name,
+                                const std::string& type,
+                                const unsigned buff_length = NX_MAXNAMELEN);
+
+    /**
+     * Create a link to a group in an external file.
+     *
+     * \param name The name for the group in this file.
+     * \param type The type for the group in this file.
+     * \param url The url to the group in the external file.
+     */
+    void linkExternal(const std::string& name, const std::string& type,
+                      const std::string& url);
+    /**
+     * This function checksi if we are in an open dataset
+     * \returns true if we are currently in an open dataset else false
+     */
+    bool isDataSetOpen();
+
+    /**
+     * Create a multimap with the data types as keys and the associated paths as values.
+     *
+     * \return The multimap of the opened file.
+     */
+    TypeMap *getTypeMap();
+  };
+
+  /**
+   * This function returns the NXnumtype given a concrete number.
+   * \tparam NumT numeric data type of \a number to check
+   */
+   template <typename NumT>
+     NXDLL_EXPORT NXnumtype getType(NumT number = NumT());
+
+
+};
+
+#include "NeXusStream.hpp"
+
+#endif
diff --git a/bindings/cpp/NeXusStream.cpp b/bindings/cpp/NeXusStream.cpp
new file mode 100644
index 0000000..ec9cc20
--- /dev/null
+++ b/bindings/cpp/NeXusStream.cpp
@@ -0,0 +1,281 @@
+//
+//  NeXus - Neutron & X-ray Common Data Format
+//  
+//  $Id: Makefile.am 598 2005-08-19 16:19:15Z faa59 $
+//  
+//  IOStream like interface to NeXus C++ Bindings
+//
+//  Copyright (C) 2008 Freddie Akeroyd, STFC ISIS facility
+//  
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+// 
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+// 
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free 
+//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+//  MA  02111-1307  USA
+//             
+//  For further information, see http://www.nexusformat.org/
+//
+
+/////////////////// Subversion Repository Details ////////////////////////
+// Repository Location     $HeadURL$
+// Revision of last commit $LastChangedRevision$ 
+// Date of last commit     $LastChangedDate$
+// Last changed by         $LastChangedBy$
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * \file NeXusStream.cpp
+ * Implementation of IOStream like interface to NeXus files
+ * \author Freddie Akeroyd, STFC ISIS Facility, GB
+ * \version $LastChangedRevision$
+ * \date    $LastChangedDate$
+ */
+
+#include <iostream>
+#include "napiconfig.h"
+#include "NeXusStream.hpp"
+#include "NeXusException.hpp"
+namespace NeXus {
+namespace Stream {
+
+HolderBase::HolderBase(const std::string& name) : m_name(name)
+{
+}
+
+void HolderBase::setName(const std::string& name)
+{
+    m_name = name;
+}
+    
+template<typename NumT>
+AttrHolder<NumT>::AttrHolder(const std::string& name, NumT& value) : HolderBase(name), m_c_value(NULL), m_value(&value)
+{
+}
+
+template<typename NumT>
+AttrHolder<NumT>::AttrHolder(const std::string& name, const NumT& value) : HolderBase(name), m_c_value(&value), m_value(NULL)
+{
+}
+
+template<typename NumT>
+AttrHolder<NumT>::AttrHolder(NumT& value) : HolderBase(""), m_c_value(NULL), m_value(&value)
+{
+}
+
+template<typename NumT>
+AttrHolder<NumT>::AttrHolder(const NumT& value) : HolderBase(""), m_c_value(&value), m_value(NULL)
+{
+}
+
+template<typename NumT>
+NXnumtype AttrHolder<NumT>::getType()
+{
+    return NeXus::getType<NumT>();
+}
+
+template<>
+NXnumtype AttrHolder<std::string>::getType()
+{
+    return NeXus::getType<char>();
+}
+
+template<>
+void AttrHolder<std::string>::readFromFile(File& nf) const
+{
+    if (m_value != NULL)
+    {
+        nf.getAttr(m_name, *m_value);
+    }
+    else
+    {
+	throw Exception("AttrHolder<NumT>::readFromFile - not able to read into a constant");
+    }
+}
+
+template<typename NumT>
+void AttrHolder<NumT>::readFromFile(File& nf) const
+{
+    if (m_value != NULL)
+    {
+        nf.getAttr(m_name, *m_value);
+    }
+    else
+    {
+	throw Exception("AttrHolder<NumT>::readFromFile - not able to read into a constant");
+    }
+}
+
+template<typename NumT>
+void AttrHolder<NumT>::writeToFile(File& nf) const
+{
+    if (m_value != NULL)
+    {
+        nf.putAttr(m_name, *m_value);
+    }
+    else if (m_c_value != NULL)
+    {
+        nf.putAttr(m_name, *m_c_value);
+    }
+    else
+    {
+	throw Exception("AttrHolder<NumT>::writeToFile - no value to write");
+    }
+}
+
+
+template<typename NumT>
+void DataHolder<NumT>::readFromFile(File& nf) const
+{
+    if (m_value != NULL)
+    {
+    	nf.openData(m_name);
+	nf.getData(*m_value);
+	nf.closeData();
+    }
+    else if (m_c_value != NULL)
+    {
+	throw Exception("DataHolder<NumT>::readFromFile - not able to read into a constant");
+    }
+    else
+    {
+    	nf.openData(m_name);
+    }
+}
+
+template<typename NumT>
+void DataHolder<NumT>::writeToFile(File& nf) const
+{
+    if (m_value != NULL)
+    {
+        nf.writeData(m_name, *m_value);
+    }
+    else if (m_c_value != NULL)
+    {
+        nf.writeData(m_name, *m_c_value);
+    }
+    else
+    {
+	throw Exception("DataHolder<NumT>::writeToFile - no value to write");
+    }
+}
+
+template<typename NumT>
+DataHolder<NumT>::DataHolder(const std::string& name, std::vector<NumT>& value) : HolderBase(name), m_c_value(NULL), m_value(&value)
+{
+}
+
+template<typename NumT>
+DataHolder<NumT>::DataHolder(const std::string& name) : HolderBase(name), m_c_value(NULL), m_value(NULL)
+{
+}
+
+template<typename NumT>
+DataHolder<NumT>::DataHolder(const std::string& name, const std::vector<NumT>& value) : HolderBase(name), m_c_value(&value), m_value(NULL)
+{
+}
+
+template<typename NumT>
+DataHolder<NumT>::DataHolder(std::vector<NumT>& value) : HolderBase(""), m_c_value(NULL), m_value(&value)
+{
+}
+
+template<typename NumT>
+DataHolder<NumT>::DataHolder(const std::vector<NumT>& value) : HolderBase(""), m_c_value(&value), m_value(NULL)
+{
+}
+
+template class NXDLL_EXPORT AttrHolder<double>;
+template class NXDLL_EXPORT AttrHolder<int>;
+template class NXDLL_EXPORT AttrHolder<std::string>;
+
+template class NXDLL_EXPORT DataHolder<double>;
+template class NXDLL_EXPORT DataHolder<int>;
+template class NXDLL_EXPORT DataHolder<char>;
+
+void Data::readFromFile(File& nf) const
+{
+    m_holder->readFromFile(nf);
+    if (m_attr.size() > 0)
+    {
+    	nf.openData(m_holder->getName());
+	ObjectWithAttr::readFromFile(nf);
+    	nf.closeData();
+    }
+}
+
+void Data::writeToFile(File& nf) const
+{
+    m_holder->writeToFile(nf);
+    if (m_attr.size() > 0)
+    {
+        nf.openData(m_holder->getName());
+	ObjectWithAttr::writeToFile(nf);
+        nf.closeData();
+    }
+}
+
+File& operator<<(File& nf, const ISerialisable& obj)
+{
+    obj.writeToFile(nf);
+    return nf;
+}
+
+File& operator>>(File& nf, const ISerialisable& obj)
+{
+    obj.readFromFile(nf);
+    return nf;
+}
+
+File& operator<<(File& nf, const StreamModifier sm)
+{
+    switch(sm)
+    {
+	case Close:
+	    if (nf.isDataSetOpen())
+	    {
+		nf.closeData();
+	    }
+	    else
+ 	    {	
+		nf.closeGroup();
+	    }
+	    break;
+
+	default:
+	    break;
+    }
+    return nf;
+}
+
+File& operator>>(File& nf, const StreamModifier sm)
+{
+    switch(sm)
+    {
+	case Close:
+	    if (nf.isDataSetOpen())
+	    {
+		nf.closeData();
+	    }
+	    else
+ 	    {	
+		nf.closeGroup();
+	    }
+	    break;
+
+	default:
+	    break;
+    }
+    return nf;
+}
+
+} // Stream
+} // NeXus
diff --git a/bindings/cpp/NeXusStream.hpp b/bindings/cpp/NeXusStream.hpp
new file mode 100644
index 0000000..cc5887d
--- /dev/null
+++ b/bindings/cpp/NeXusStream.hpp
@@ -0,0 +1,291 @@
+#ifndef NEXUS_STREAM_HPP
+#define NEXUS_STREAM_HPP
+//
+//  NeXus - Neutron & X-ray Common Data Format
+//  
+//  IOStream like interface to NeXus C++ Bindings
+//
+//  Copyright (C) 2008 Freddie Akeroyd, STFC ISIS facility
+//  
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+// 
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+// 
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free 
+//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+//  MA  02111-1307  USA
+//             
+//  For further information, see http://www.nexusformat.org/
+//
+//
+
+/////////////////// Subversion Repository Details ////////////////////////
+// Repository Location     $HeadURL$
+// Revision of last commit $LastChangedRevision$ 
+// Date of last commit     $LastChangedDate$
+// Last changed by         $LastChangedBy$
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * \file NeXusStream.hpp
+ * Header for IOStream like interface to NeXus files
+ * \author Freddie Akeroyd, STFC ISIS Facility, GB
+ * \version $LastChangedRevision$
+ * \date    $LastChangedDate$
+ * \defgroup cpp_stream IOstream like interface
+ * \ingroup cpp_main
+ */
+
+#include <list>
+#include <vector>
+#include "NeXusFile.hpp"
+
+namespace NeXus
+{
+namespace Stream
+{
+  /**
+   * interface implemented by all serialisable NeXus components
+   */
+    class NXDLL_EXPORT ISerialisable
+    {
+      public:
+	virtual void readFromFile(File& nf) const = 0;
+	virtual void writeToFile(File& nf) const = 0;
+    };
+
+    /// \ingroup cpp_stream
+    enum StreamModifier { Close=0 };
+
+  /**
+   * Base class for serialisable named and typed parameter
+   */
+    class NXDLL_EXPORT HolderBase : public ISerialisable
+    {
+      protected:
+	std::string m_name;
+
+      public:
+	HolderBase() : m_name("") {}
+	HolderBase(const std::string& name);
+	void setName(const std::string& name);
+	std::string getName() { return m_name; }
+	virtual NXnumtype getType() = 0;
+	virtual HolderBase* clone() = 0;
+	virtual ~HolderBase() {}
+    };
+
+  /**
+   * Serialisable NeXus attribute
+   */
+    template<typename NumT>
+    class NXDLL_EXPORT AttrHolder : public HolderBase
+    {
+      protected:
+	const NumT* m_c_value;
+	NumT* m_value;
+	AttrHolder() : HolderBase(), m_c_value(NULL), m_value(NULL) { }
+	AttrHolder(const std::string& name, const NumT* cv, NumT* v) : HolderBase(name), m_c_value(cv), m_value(v) { }
+
+      public:
+	AttrHolder(const std::string& name, NumT& value);
+	AttrHolder(const std::string& name, const NumT& value);
+	AttrHolder(NumT& value);
+	AttrHolder(const NumT& value);
+	NXnumtype getType();
+	virtual void readFromFile(File& nf) const;
+	virtual void writeToFile(File& nf) const;
+	AttrHolder* clone() { return new AttrHolder(m_name, m_c_value, m_value); }
+	virtual ~AttrHolder() { m_value = NULL; m_c_value = NULL; }
+    };
+
+  /**
+   * Serialisable attribute
+   * \ingroup cpp_stream
+   */
+    class NXDLL_EXPORT Attr : public ISerialisable
+    {
+      protected:
+	HolderBase* m_holder;
+
+      public:
+	Attr() : m_holder(NULL) { }
+        template <typename NumT>
+	  Attr(NumT& d) { m_holder = new AttrHolder<NumT>(d); }
+        template <typename NumT>
+	  Attr(const NumT& d) { m_holder = new AttrHolder<NumT>(d); }
+        template <typename NumT>
+	  Attr(const std::string& name, NumT& d) { m_holder = new AttrHolder<NumT>(name, d); }
+        template <typename NumT>
+	  Attr(const std::string& name, const NumT& d) { m_holder = new AttrHolder<NumT>(name, d); }
+	Attr(const std::string& name, Attr& d) { m_holder = d.m_holder->clone(); setName(name); }
+	Attr(const std::string& name, const Attr& d) { m_holder = d.m_holder->clone(); setName(name); }
+        Attr(const Attr& a) : m_holder(NULL) {  m_holder = a.m_holder->clone(); }
+	Attr& operator=(const Attr& a) { if (this != &a) { delete m_holder; m_holder = a.m_holder->clone(); } return *this; }
+	void setName(const std::string& name) { m_holder->setName(name); }
+	virtual void readFromFile(File& nf) const { m_holder->readFromFile(nf); }
+	virtual void writeToFile(File& nf) const { m_holder->writeToFile(nf); }
+	virtual ~Attr() { delete m_holder; m_holder = NULL; }
+    };
+
+  /**
+   * Serialisable NeXus class with associated attributes
+   */
+    class NXDLL_EXPORT ObjectWithAttr : public ISerialisable
+    {
+       protected:
+	std::list<Attr> m_attr;
+	
+	void processAttr(const std::string& attr1_name, const Attr& attr1_value, const std::string& attr2_name, const Attr& attr2_value)
+	{
+	    if (attr1_name.size() > 0)
+	    {
+	        m_attr.push_back(Attr(attr1_name, attr1_value));
+	    }
+	    if (attr2_name.size() > 0)
+	    {
+	    	m_attr.push_back(Attr(attr2_name, attr2_value));
+	    }
+	}
+	
+      public:
+
+	ObjectWithAttr(const std::string& attr1_name = "", const Attr& attr1_value = Attr(), const std::string& attr2_name = "", const Attr& attr2_value = Attr())
+	{
+	    processAttr(attr1_name, attr1_value, attr2_name, attr2_value);
+	}
+	
+	virtual void readFromFile(File& nf) const
+	{
+    	    for(std::list<Attr>::const_iterator it = m_attr.begin(); it != m_attr.end(); it++)
+    	    {
+        	it->readFromFile(nf);
+    	    }
+	}
+
+	virtual void writeToFile(File& nf) const
+        {
+    	    for(std::list<Attr>::const_iterator it = m_attr.begin(); it != m_attr.end(); it++)
+    	    {
+		it->writeToFile(nf);
+   	    }
+  	}
+
+	virtual ~ObjectWithAttr() { }
+    };
+    
+  /**
+   * Serialisable NeXus group object
+   * \ingroup cpp_stream
+   */
+    class NXDLL_EXPORT Group : public ObjectWithAttr
+    {
+      protected:
+        std::string m_name;
+        std::string m_class;
+
+      public:
+	Group(const std::string& name, const std::string& nxclass, const std::string& attr1_name = "", const Attr& attr1_value = Attr(),
+	  		const std::string& attr2_name="", const Attr& attr2_value = Attr()) : 
+		ObjectWithAttr(attr1_name, attr1_value, attr2_name, attr2_value), m_name(name), m_class(nxclass)
+	{
+	}
+
+	virtual void readFromFile(File& nf) const
+	{
+    	    nf.openGroup(m_name, m_class);
+	    ObjectWithAttr::readFromFile(nf);
+	}
+
+	virtual void writeToFile(File& nf) const
+        {
+    	    nf.makeGroup(m_name, m_class, true);
+	    ObjectWithAttr::writeToFile(nf);
+  	}
+
+	virtual ~Group() {}
+    };
+
+  /**
+   * Serialisable NeXus data
+   */
+    template<typename NumT>
+    class NXDLL_EXPORT DataHolder : public HolderBase
+    {
+      protected:
+	const std::vector<NumT>* m_c_value;
+	std::vector<NumT>* m_value;
+	DataHolder() : HolderBase(), m_c_value(NULL), m_value(NULL) { }
+	DataHolder(const std::string& name, const std::vector<NumT>* cv, std::vector<NumT>* v) : HolderBase(name), m_c_value(cv), m_value(v) { }
+
+      public:
+	DataHolder(const std::string& name);
+	DataHolder(const std::string& name, std::vector<NumT>& value);
+	DataHolder(const std::string& name, const std::vector<NumT>& value);
+	DataHolder(std::vector<NumT>& value);
+	DataHolder(const std::vector<NumT>& value);
+	NXnumtype getType() { return NeXus::getType<NumT>(); }
+	virtual void readFromFile(File& nf) const;
+	virtual void writeToFile(File& nf) const;
+	DataHolder* clone() { return new DataHolder(m_name, m_c_value, m_value); }
+	virtual ~DataHolder() {}
+    };
+
+  /**
+   * Serialisable data object that contains attributes
+   * \ingroup cpp_stream
+   */
+    class NXDLL_EXPORT Data : public ObjectWithAttr
+    {
+	HolderBase* m_holder;
+	
+      public:
+	Data() : ObjectWithAttr(), m_holder(NULL) {}
+	Data(const std::string& name) : ObjectWithAttr()
+	{
+	    m_holder = new DataHolder<int>(name); // TODO: move name out of holder and use  m_holder = NULL
+	}
+        template <typename NumT>
+	  Data(const std::string& name, std::vector<NumT>& data, const std::string& attr1_name="", const Attr& attr1_value=Attr(), 
+	  		const std::string& attr2_name="", const Attr& attr2_value = Attr()) :
+		   ObjectWithAttr(attr1_name, attr1_value, attr2_name, attr2_value)
+	  {
+	    m_holder = new DataHolder<NumT>(name, data);
+	  }
+        template <typename NumT>
+	  Data(const std::string& name, const std::vector<NumT>& data, const std::string& attr1_name="", const Attr& attr1_value=Attr(),
+	  		const std::string& attr2_name="", const Attr& attr2_value = Attr()) :
+		ObjectWithAttr(attr1_name, attr1_value, attr2_name, attr2_value)
+	  {
+	    m_holder = new DataHolder<NumT>(name, data);
+	  }
+	Data(const Data& d) : ObjectWithAttr(d), m_holder(NULL) { m_holder = d.m_holder->clone(); }
+	Data& operator=(const Data& d) { if (this != &d) { delete m_holder; m_holder = d.m_holder->clone(); } return *this; }
+	virtual void readFromFile(File& nf) const;
+	virtual void writeToFile(File& nf) const;
+	virtual ~Data() { delete m_holder; }
+    };
+
+    /// \ingroup cpp_stream
+   NXDLL_EXPORT File& operator<<(File& nf, const ISerialisable& obj);
+    
+    /// \ingroup cpp_stream
+   NXDLL_EXPORT File& operator>>(File& nf, const ISerialisable& obj);
+
+    /// \ingroup cpp_stream
+   NXDLL_EXPORT File& operator<<(File& nf, const StreamModifier sm);
+ 
+    /// \ingroup cpp_stream
+   NXDLL_EXPORT File& operator>>(File& nf, const StreamModifier sm);
+
+  } // Stream
+} // NeXus
+
+#endif /* NEXUS_STREAM_HPP */
diff --git a/bindings/cpp/SConscript b/bindings/cpp/SConscript
new file mode 100644
index 0000000..dda0c2d
--- /dev/null
+++ b/bindings/cpp/SConscript
@@ -0,0 +1,61 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 961 2007-09-04 12:31:49Z Freddie Akeroyd $
+#
+#  Top level scons file for coordinating NeXus build
+#  
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+######################## Subversion Reposity details ########################
+# Repository Location     $HeadURL$
+# Revision of last commit $LastChangedRevision$ 
+# Date of last commit     $LastChangedDate$
+# Author of last commit   $LastChangedBy$
+############################################################################
+
+import os
+import platform
+import sys
+import shutil
+import re
+import os
+import nexus_scons_utils
+
+source_files = Split("""NeXusFile.cpp
+                        NeXusException.cpp
+                        NeXusStream.cpp""")
+
+#Import environment
+Import('env')
+myenv = env.Clone()
+myenv.Append(CPPPATH=['#include'])
+myenv.Append(CPPDEFINES=[('IN_NEXUS_CPP_LIBRARY',1)])
+myenv_static=myenv.Clone()
+myenv_dynamic=myenv.Clone()
+
+
+shared_objects = nexus_scons_utils.getSharedObjects(source_files, myenv)
+
+#BUILD CODE
+shared = myenv_dynamic.SharedLibrary('lib/NeXusCPP', source_files, LIBS=env['MYSHLIBLIST'], LIBPATH=env['MYSHLIBDIRLIST'], PDB='lib/NeXusCPP.pdb')
+static = myenv_static.StaticLibrary('libstatic/NeXusCPP', source_files, LIBS=env['MYLIBLIST'], LIBPATH=env['MYLIBDIRLIST'], PDB='libstatic/NeXusCPP.pdb')
+retval = { 'shared': shared, 'static': static, 'sharedobjs' : shared_objects, 'libs': [ 'NeXusCPP' ] }
+Return('retval')
diff --git a/bindings/f77/CMakeLists.txt b/bindings/f77/CMakeLists.txt
new file mode 100644
index 0000000..74d768c
--- /dev/null
+++ b/bindings/f77/CMakeLists.txt
@@ -0,0 +1,57 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+#Make NeXus F77 Bindings Static Library
+
+set (HEADERS napif.inc)
+set (SOURCES napif.f)
+
+add_library (NeXus_F77_Static_Library STATIC ${HEADERS} ${SOURCES})
+
+set_target_properties(NeXus_F77_Static_Library PROPERTIES OUTPUT_NAME NeXus77)
+
+target_link_libraries(NeXus_F77_Static_Library NeXus_Static_Library ${HDF5_LIBRARIES} ${MXML_LINK}
+                      ${HDF4_LINK} ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+#Make NeXus F77 Bindings Shared Library
+
+add_library (NeXus_F77_Shared_Library SHARED ${HEADERS} ${SOURCES})
+
+#Note - library version needs to be got from somewhere?
+set_target_properties(NeXus_F77_Shared_Library PROPERTIES OUTPUT_NAME NeXusCPP
+                      VERSION 1.0 SOVERSION 4)
+
+target_link_libraries(NeXus_F77_Shared_Library NeXus_Shared_Library ${HDF5_LIBRARIES} ${MXML_LINK}
+                      ${HDF4_LINK} ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+install (TARGETS NeXus_F77_Static_Library NeXus_F77_Shared_Library
+         RUNTIME DESTINATION bin COMPONENT Runtime
+         LIBRARY DESTINATION lib COMPONENT Runtime
+         ARCHIVE DESTINATION lib/nexus COMPONENT Development)
diff --git a/bindings/f77/Makefile.am b/bindings/f77/Makefile.am
new file mode 100644
index 0000000..3c4c23a
--- /dev/null
+++ b/bindings/f77/Makefile.am
@@ -0,0 +1,39 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for NeXus FORTRAN 77 bindings
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+lib_LTLIBRARIES=libNeXus77.la
+
+libNeXus77_la_SOURCES=napif.f
+libNeXus77_la_LIBADD=$(top_builddir)/src/libNeXus.la # @FLIBS@
+libNeXus77_la_LDFLAGS=@SHARED_LDFLAGS@ -version-info $(NXLTVERSINFO)
+
+include_HEADERS = napif.inc
+#EXTRA_DIST = napif.inc
+
+include $(top_srcdir)/build_rules.am
diff --git a/bindings/f77/napif.f b/bindings/f77/napif.f
new file mode 100644
index 0000000..e2787c7
--- /dev/null
+++ b/bindings/f77/napif.f
@@ -0,0 +1,518 @@
+C------------------------------------------------------------------------------
+C NeXus - Neutron & X-ray Common Data Format
+C  
+C Application Program Interface (Fortran 77)
+C
+C Copyright (C) 1997-2002 Freddie Akeroyd, Mark Koennecke
+C
+C This library is free software; you can redistribute it and/or
+C modify it under the terms of the GNU Lesser General Public
+C License as published by the Free Software Foundation; either
+C version 2 of the License, or (at your option) any later version.
+C
+C This library is distributed in the hope that it will be useful,
+C but WITHOUT ANY WARRANTY; without even the implied warranty of
+C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+C Lesser General Public License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public
+C License along with this library; if not, write to the Free Software
+C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+C
+C  For further information, see <http://www.nexusformat.org>
+C
+C $Id$
+C------------------------------------------------------------------------------
+
+C------------------------------------------------------------------------------
+C Doxygen comments follow
+C for help, see: http://www.stack.nl/~dimitri/doxygen/docblocks.html#fortranblocks
+C
+!> \mainpage Fortan 77 NeXus API
+!!
+!! The Fortran routines have the same names and argument lists as the 
+!! corresponding C routines, which they call using wrappers. Some extra 
+!! routines for handling input/output of character data and attributes 
+!! have been added. Care must be taken to ensure enough space is allocated
+!! for the input/output operations being performed.
+!!
+!! It is necessary to reverse the order of indices in multidimensional 
+!! arrays, compared to an equivalent C program, so that data are stored in
+!! the same order in the NeXus file.
+!!
+!! Any program using the F77 API needs to include the following line near
+!! the top in order to define the required constants (NXHANDLESIZE,
+!! NXLINKSIZE, etc.): 
+!!
+!!       include 'NAPIF.INC'
+!!
+!! Use this table to convert from the C data types listed with each routine to the F77 data types: 
+!!
+!! ==========================  ================================================
+!! C                           FORTRAN 77
+!! ==========================  ================================================
+!! int a, int* a               INTEGER A
+!! char* a                     CHARACTER*(*) A
+!! NXhandle a, NXhandle* a     INTEGER A(NXHANDLESIZE)
+!! NXstatus                    INTEGER
+!! int[] a                     INTEGER A(*)
+!! void* a                     REAL A(*) or DOUBLE A(*) or INTEGER A(*)
+!! NXlink a, NXlink* a         INTEGER A(NXLINKSIZE)
+!! ==========================  ================================================
+!<
+C------------------------------------------------------------------------------
+
+
+
+!> Return length of a string, ignoring trailing blanks
+!<
+      INTEGER FUNCTION TRUELEN(STRING)
+      CHARACTER*(*) STRING
+      DO TRUELEN=LEN(STRING),1,-1
+          IF (STRING(TRUELEN:TRUELEN) .NE. ' ' .AND. 
+     &        STRING(TRUELEN:TRUELEN) .NE. CHAR(0) ) RETURN
+      ENDDO
+      TRUELEN = 0
+      END
+
+!> Convert FORTRAN string STRING into NULL terminated C string ISTRING
+!<
+      SUBROUTINE EXTRACT_STRING(ISTRING, LENMAX, STRING)
+      CHARACTER*(*) STRING
+      INTEGER I,ILEN,TRUELEN,LENMAX
+      INTEGER*1 ISTRING(LENMAX)
+      EXTERNAL TRUELEN
+      ILEN = TRUELEN(STRING)
+      IF (ILEN .GE. LENMAX) THEN
+          WRITE(6,9000) LENMAX, ILEN+1
+          RETURN
+      ENDIF
+      DO I=1,ILEN
+          ISTRING(I) = ICHAR(STRING(I:I))
+      ENDDO
+      ISTRING(ILEN+1) = 0
+      RETURN
+ 9000 FORMAT('NeXus(NAPIF/EXTRACT_STRING): String too long -',
+     +       'buffer needs increasing from ', i4,' to at least ',i4)
+      END
+
+!> Convert NULL terminated C string ISTRING to FORTRAN string STRING
+!<
+      SUBROUTINE REPLACE_STRING(STRING, ISTRING)
+      INTEGER*1 ISTRING(*)
+      CHARACTER*(*) STRING
+      INTEGER I
+      STRING = ' '
+      DO I=1,LEN(STRING)
+          IF (ISTRING(I) .EQ. 0) RETURN
+          STRING(I:I) = CHAR(ISTRING(I))
+      ENDDO
+      IF (ISTRING(LEN(STRING)+1) .NE. 0) WRITE(6,9010) LEN(STRING) 
+      RETURN
+ 9010 FORMAT('NeXus(NAPIF/REPLACE_STRING): String truncated - ',
+     +  'buffer needs to be > ', I4)
+      END
+
+!> Wrapper routines for NXAPI interface
+!<
+      INTEGER FUNCTION NXOPEN(FILENAME, ACCESS_METHOD, FILEID)
+      CHARACTER*(*) FILENAME
+      INTEGER*1 IFILENAME(256)
+      INTEGER ACCESS_METHOD
+      INTEGER FILEID(*),NXIFOPEN
+      EXTERNAL NXIFOPEN
+      CALL EXTRACT_STRING(IFILENAME, 256, FILENAME)
+      NXOPEN = NXIFOPEN(IFILENAME, ACCESS_METHOD, FILEID)
+      END
+
+      INTEGER FUNCTION NXCLOSE(FILEID)
+      INTEGER FILEID(*),NXIFCLOSE
+      EXTERNAL NXIFCLOSE
+      NXCLOSE = NXIFCLOSE(FILEID)
+      END
+
+      INTEGER FUNCTION NXFLUSH(FILEID)
+      INTEGER FILEID(*), NXIFFLUSH
+      EXTERNAL NXIFFLUSH
+      NXFLUSH = NXIFFLUSH(FILEID)
+      END
+
+      INTEGER FUNCTION NXMAKEGROUP(FILEID, VGROUP, NXCLASS)
+      INTEGER FILEID(*),NXIMAKEGROUP
+      CHARACTER*(*) VGROUP, NXCLASS
+      INTEGER*1 IVGROUP(256), INXCLASS(256)
+      EXTERNAL NXIMAKEGROUP
+      CALL EXTRACT_STRING(IVGROUP, 256, VGROUP)
+      CALL EXTRACT_STRING(INXCLASS, 256, NXCLASS)
+      NXMAKEGROUP = NXIMAKEGROUP(FILEID, IVGROUP, INXCLASS)
+      END
+
+      INTEGER FUNCTION NXOPENGROUP(FILEID, VGROUP, NXCLASS)
+      INTEGER FILEID(*),NXIOPENGROUP
+      CHARACTER*(*) VGROUP, NXCLASS
+      INTEGER*1 IVGROUP(256), INXCLASS(256)
+      EXTERNAL NXIOPENGROUP
+      CALL EXTRACT_STRING(IVGROUP, 256, VGROUP)
+      CALL EXTRACT_STRING(INXCLASS, 256, NXCLASS)
+      NXOPENGROUP = NXIOPENGROUP(FILEID, IVGROUP, INXCLASS)
+      END
+
+      INTEGER FUNCTION NXOPENPATH(FILEID, PATH)
+      INTEGER FILEID(*),NXIOPENPATH
+      CHARACTER*(*) PATH
+      INTEGER*1 IPATH(256)
+      EXTERNAL NXIOPENPATH
+      CALL EXTRACT_STRING(IPATH, 256, PATH)
+      NXOPENPATH = NXIOPENPATH(FILEID, IPATH)
+      END
+
+      INTEGER FUNCTION NXGETPATH(FILEID, PATH)
+      INTEGER FILEID(*),NXIGETPATH, NXIFGETPATH
+      CHARACTER*(*) PATH
+      INTEGER*1 IPATH(1024)
+      INTEGER PLEN
+      EXTERNAL NXIFGETPATH
+      PLEN = 1024
+      NXGETPATH = NXIFGETPATH(FILEID,IPATH,PLEN)
+      CALL REPLACE_STRING(PATH,IPATH)
+      END
+
+      INTEGER FUNCTION NXOPENGROUPPATH(FILEID, PATH)
+      INTEGER FILEID(*),NXIOPENGROUPPATH
+      CHARACTER*(*) PATH
+      INTEGER*1 IPATH(256)
+      EXTERNAL NXIOPENGROUPPATH
+      CALL EXTRACT_STRING(IPATH, 256, PATH)
+      NXOPENGROUPPATH = NXIOPENGROUPPATH(FILEID, IPATH)
+      END
+
+      INTEGER FUNCTION NXCLOSEGROUP(FILEID)
+      INTEGER FILEID(*),NXICLOSEGROUP
+      EXTERNAL NXICLOSEGROUP
+      NXCLOSEGROUP = NXICLOSEGROUP(FILEID)
+      END
+
+      INTEGER FUNCTION NXMAKEDATA(FILEID, LABEL, DATATYPE, RANK, DIM)  
+      INTEGER FILEID(*), DATATYPE, RANK, DIM(*), NXIFMAKEDATA
+      CHARACTER*(*) LABEL
+      INTEGER*1 ILABEL(256)
+      EXTERNAL NXIFMAKEDATA
+      CALL EXTRACT_STRING(ILABEL, 256, LABEL)
+      NXMAKEDATA = NXIFMAKEDATA(FILEID, ILABEL, DATATYPE, RANK, DIM) 
+      END
+
+      INTEGER FUNCTION NXCOMPMAKEDATA(FILEID, LABEL, DATATYPE, RANK, 
+     &                                DIM, COMPRESSION_TYPE, CHUNK)  
+      INTEGER FILEID(*), DATATYPE, RANK, DIM(*)
+      INTEGER COMPRESSION_TYPE, CHUNK(*)
+      INTEGER NXIFCOMPMAKEDATA
+      CHARACTER*(*) LABEL
+      INTEGER*1 ILABEL(256)
+      EXTERNAL NXIFMAKEDATA
+      CALL EXTRACT_STRING(ILABEL, 256, LABEL)
+      NXCOMPMAKEDATA = NXIFCOMPMAKEDATA(FILEID, ILABEL, DATATYPE, 
+     &                      RANK, DIM, COMPRESSION_TYPE, CHUNK) 
+      END
+
+      INTEGER FUNCTION NXOPENDATA(FILEID, LABEL)
+      INTEGER FILEID(*),NXIOPENDATA
+      CHARACTER*(*) LABEL
+      INTEGER*1 ILABEL(256)
+      EXTERNAL NXIOPENDATA
+      CALL EXTRACT_STRING(ILABEL, 256, LABEL)
+      NXOPENDATA = NXIOPENDATA(FILEID, ILABEL)
+      END
+
+      INTEGER FUNCTION NXSETNUMBERFORMAT(FILEID, ITYPE, FORMAT)
+      INTEGER FILEID(*),NXISETNUMBERFORMAT,ITYPE
+      CHARACTER*(*) FORMAT
+      INTEGER*1 ILABEL(256)
+      EXTERNAL NXISETNUMBERFORMAT
+      CALL EXTRACT_STRING(ILABEL, 256, FORMAT)
+      NXSETNUMBERFORMAT = NXISETNUMBERFORMAT(FILEID, ITYPE, ILABEL)
+      END
+
+      INTEGER FUNCTION NXCOMPRESS(FILEID, COMPR_TYPE)
+      INTEGER FILEID(*),NXIFCOMPRESS,COMPR_TYPE
+      EXTERNAL NXIFCOMPRESS
+      NXCOMPRESS = NXIFCOMPRESS(FILEID, COMPR_TYPE)
+      END
+
+      INTEGER FUNCTION NXCLOSEDATA(FILEID)
+      INTEGER FILEID(*),NXICLOSEDATA
+      EXTERNAL NXICLOSEDATA
+      NXCLOSEDATA = NXICLOSEDATA(FILEID)
+      END
+
+      INTEGER FUNCTION NXGETDATA(FILEID, DATA)
+      INTEGER FILEID(*), DATA(*), NXIGETDATA
+      EXTERNAL NXIGETDATA
+      NXGETDATA = NXIGETDATA(FILEID, DATA)
+      END
+
+      INTEGER FUNCTION NXGETCHARDATA(FILEID, DATA)
+      INTEGER FILEID(*), NXIGETDATA
+      CHARACTER*(*) DATA
+      INTEGER NX_ERROR,NX_IDATLEN
+      PARAMETER(NX_ERROR=0,NX_IDATLEN=1024)
+      INTEGER*1 IDATA(NX_IDATLEN)
+      EXTERNAL NXIGETDATA
+C *** We need to zero IDATA as GETDATA doesn't NULL terminate character data,
+C *** and so we would get "buffer not big enough" messages from REPLACE_STRING
+      DO I=1,NX_IDATLEN
+          IDATA(I) = 0
+      ENDDO
+      NXGETCHARDATA = NXIGETDATA(FILEID, IDATA)
+      IF (NXGETCHARDATA .NE. NX_ERROR) THEN
+          CALL REPLACE_STRING(DATA, IDATA)
+      ENDIF
+      END
+
+      INTEGER FUNCTION NXGETSLAB(FILEID, DATA, START, SIZE)
+      INTEGER FILEID(*), DATA(*), START(*), SIZE(*)
+      INTEGER NX_MAXRANK, NX_OK
+      PARAMETER(NX_MAXRANK=32,NX_OK=1)
+      INTEGER RANK, DIM(NX_MAXRANK), DATATYPE, I
+      INTEGER CSTART(NX_MAXRANK), CSIZE(NX_MAXRANK)
+      INTEGER NXIGETSLAB, NXGETINFO
+      EXTERNAL NXIGETSLAB
+      NXGETSLAB = NXGETINFO(FILEID, RANK, DIM, DATATYPE)
+      IF (NXGETSLAB .NE. NX_OK) RETURN
+      DO I = 1, RANK
+         CSTART(I) = START(RANK-I+1) - 1
+         CSIZE(I) = SIZE(RANK-I+1)
+      ENDDO
+      NXGETSLAB = NXIGETSLAB(FILEID, DATA, CSTART, CSIZE)
+      END
+      
+      INTEGER FUNCTION NXGETATTR(FILEID, NAME, DATA, DATALEN, TYPE)
+      INTEGER FILEID(*),DATA(*),DATALEN,TYPE
+      CHARACTER*(*) NAME
+      INTEGER*1 INAME(256)
+      INTEGER NXIGETATTR
+      EXTERNAL NXIGETATTR
+      CALL EXTRACT_STRING(INAME, 256, NAME)
+      NXGETATTR = NXIGETATTR(FILEID, INAME, DATA, DATALEN, TYPE)
+      END
+
+      INTEGER FUNCTION NXGETCHARATTR(FILEID, NAME, DATA, 
+     +                                 DATALEN, TYPE)
+      INTEGER MAX_DATALEN,NX_ERROR
+      INTEGER FILEID(*), DATALEN, TYPE
+      PARAMETER(MAX_DATALEN=1024,NX_ERROR=0)
+      CHARACTER*(*) NAME, DATA
+      INTEGER*1 IDATA(MAX_DATALEN)
+      INTEGER*1 INAME(256)
+      INTEGER NXIGETATTR
+      EXTERNAL NXIGETATTR
+      CALL EXTRACT_STRING(INAME, 256, NAME)
+      IF (DATALEN .GE. MAX_DATALEN) THEN
+          WRITE(6,9020) DATALEN, MAX_DATALEN
+          NXGETCHARATTR=NX_ERROR
+          RETURN
+      ENDIF
+      NXGETCHARATTR = NXIGETATTR(FILEID, INAME, IDATA, DATALEN, TYPE)
+      IF (NXGETCHARATTR .NE. NX_ERROR) THEN
+          CALL REPLACE_STRING(DATA, IDATA)
+      ENDIF
+      RETURN
+ 9020 FORMAT('NXgetattr: asked for attribute size ', I4, 
+     +       ' with buffer size only ', I4)
+      END
+
+      INTEGER FUNCTION NXPUTDATA(FILEID, DATA)
+      INTEGER FILEID(*), DATA(*), NXIPUTDATA
+      EXTERNAL NXIPUTDATA
+      NXPUTDATA = NXIPUTDATA(FILEID, DATA)
+      END
+
+      INTEGER FUNCTION NXPUTCHARDATA(FILEID, DATA)
+      INTEGER FILEID(*), NXIPUTDATA
+      CHARACTER*(*) DATA
+      INTEGER*1 IDATA(1024)
+      EXTERNAL NXIPUTDATA
+      CALL EXTRACT_STRING(IDATA, 1024, DATA)
+      NXPUTCHARDATA = NXIPUTDATA(FILEID, IDATA)
+      END
+
+      INTEGER FUNCTION NXPUTSLAB(FILEID, DATA, START, SIZE)
+      INTEGER FILEID(*), DATA(*), START(*), SIZE(*)
+      INTEGER NX_MAXRANK,NX_OK
+      PARAMETER(NX_MAXRANK=32,NX_OK=1)
+      INTEGER RANK, DIM(NX_MAXRANK), DATATYPE, I
+      INTEGER CSTART(NX_MAXRANK), CSIZE(NX_MAXRANK)
+      INTEGER NXIPUTSLAB, NXGETINFO
+      EXTERNAL NXIPUTSLAB
+      NXPUTSLAB = NXGETINFO(FILEID, RANK, DIM, DATATYPE)
+      IF (NXPUTSLAB .NE. NX_OK) RETURN
+      DO I = 1, RANK
+         CSTART(I) = START(RANK-I+1) - 1
+         CSIZE(I) = SIZE(RANK-I+1)
+      ENDDO
+      NXPUTSLAB = NXIPUTSLAB(FILEID, DATA, CSTART, CSIZE)
+      END
+
+      INTEGER FUNCTION NXPUTATTR(FILEID, NAME, DATA, DATALEN, TYPE)
+      INTEGER FILEID(*), DATA(*), DATALEN, TYPE
+      CHARACTER*(*) NAME
+      INTEGER*1 INAME(256)
+      INTEGER NXIFPUTATTR
+      EXTERNAL NXIFPUTATTR
+      CALL EXTRACT_STRING(INAME, 256, NAME)
+      NXPUTATTR = NXIFPUTATTR(FILEID, INAME, DATA, DATALEN, TYPE)
+      END
+
+      INTEGER FUNCTION NXPUTCHARATTR(FILEID, NAME, DATA, 
+     +                                 DATALEN, TYPE)
+      INTEGER FILEID(*), DATALEN, TYPE 
+      CHARACTER*(*) NAME, DATA
+      INTEGER*1 INAME(256)
+      INTEGER*1 IDATA(1024)
+      INTEGER NXIFPUTATTR
+      EXTERNAL NXIFPUTATTR
+      CALL EXTRACT_STRING(INAME, 256, NAME)
+      CALL EXTRACT_STRING(IDATA, 1024, DATA)
+      NXPUTCHARATTR = NXIFPUTATTR(FILEID, INAME, IDATA, DATALEN, TYPE)
+      END
+
+      INTEGER FUNCTION NXGETINFO(FILEID, RANK, DIM, DATATYPE)
+      INTEGER FILEID(*), RANK, DIM(*), DATATYPE
+      INTEGER I, J, NXIGETINFO, NX_CHAR
+      EXTERNAL NXIGETINFO
+      NXGETINFO = NXIGETINFO(FILEID, RANK, DIM, DATATYPE)
+C *** Reverse dimension array as C is ROW major, FORTRAN column major
+      DO I = 1, RANK/2
+          J = DIM(I)
+          DIM(I) = DIM(RANK-I+1)
+          DIM(RANK-I+1) = J
+      ENDDO
+      END
+
+      INTEGER FUNCTION NXGETNEXTENTRY(FILEID, NAME, CLASS, DATATYPE)
+      INTEGER FILEID(*), DATATYPE
+      CHARACTER*(*) NAME, CLASS
+      INTEGER*1 INAME(256), ICLASS(256)
+      INTEGER NXIGETNEXTENTRY
+      EXTERNAL NXIGETNEXTENTRY
+      NXGETNEXTENTRY = NXIGETNEXTENTRY(FILEID, INAME, ICLASS, DATATYPE)
+      CALL REPLACE_STRING(NAME, INAME)
+      CALL REPLACE_STRING(CLASS, ICLASS)
+      END
+
+      INTEGER FUNCTION NXGETNEXTATTR(FILEID, PNAME, ILENGTH, ITYPE)
+      INTEGER FILEID(*), ILENGTH, ITYPE, NXIGETNEXTATTR
+      CHARACTER*(*) PNAME
+      INTEGER*1 IPNAME(1024)
+      EXTERNAL NXIGETNEXTATTR
+      NXGETNEXTATTR = NXIGETNEXTATTR(FILEID, IPNAME, ILENGTH, ITYPE)
+      CALL REPLACE_STRING(PNAME, IPNAME)
+      END
+
+      INTEGER FUNCTION NXGETGROUPID(FILEID, LINK)
+      INTEGER FILEID(*), LINK(*), NXIGETGROUPID
+      EXTERNAL NXIGETGROUPID
+      NXGETGROUPID = NXIGETGROUPID(FILEID, LINK)
+      END
+
+      INTEGER FUNCTION NXGETDATAID(FILEID, LINK)
+      INTEGER FILEID(*), LINK(*), NXIGETDATAID
+      EXTERNAL NXIGETDATAID
+      NXGETDATAID = NXIGETDATAID(FILEID, LINK)
+      END
+
+      INTEGER FUNCTION NXMAKELINK(FILEID, LINK)
+      INTEGER FILEID(*), LINK(*), NXIMAKELINK
+      EXTERNAL NXIMAKELINK
+      NXMAKELINK = NXIMAKELINK(FILEID, LINK)
+      END
+
+      INTEGER FUNCTION NXMAKENAMEDLINK(FILEID, PNAME, LINK)
+      INTEGER FILEID(*), LINK(*), NXIMAKELINK
+      CHARACTER*(*) PNAME
+      INTEGER*1 INAME(256)
+      EXTERNAL NXIMAKENAMEDLINK
+      CALL EXTRACT_STRING(INAME,256,PNAME)
+      NXMAKENAMEDLINK = NXIMAKENAMEDLINK(FILEID, INAME, LINK)
+      END
+
+      INTEGER FUNCTION NXOPENSOURCEGROUP(FILEID)
+      INTEGER FILEID(*),NXIOPENSOURCEGROUP
+      EXTERNAL NXIOPENSOURCEGROUP
+      NXOPENSOURCEGROUP = NXIOPENSOURCEGROUP(FILEID)
+      END
+
+      LOGICAL FUNCTION NXSAMEID(FILEID, LINK1, LINK2)
+      INTEGER FILEID(*), LINK1(*), LINK2(*), NXISAMEID, STATUS
+      EXTERNAL NXISAMEID
+      STATUS = NXISAMEID(FILEID, LINK1, LINK2)
+      IF (STATUS .EQ. 1) THEN
+         NXSAMEID = .TRUE.
+      ELSE
+         NXSAMEID = .FALSE.
+      ENDIF
+      END
+
+      INTEGER FUNCTION NXGETGROUPINFO(FILEID, NUM, NAME, CLASS)
+      INTEGER FILEID(*), NUM, NXIGETGROUPINFO
+      CHARACTER*(*) NAME, CLASS
+      INTEGER*1 INAME(256), ICLASS(256)
+      EXTERNAL NXIGETGROUPINFO
+      NXGETGROUPINFO = NXIGETGROUPINFO(FILEID, NUM, INAME, ICLASS)
+      CALL REPLACE_STRING(NAME, INAME)
+      CALL REPLACE_STRING(CLASS, ICLASS)
+      END
+
+      INTEGER FUNCTION NXINITGROUPDIR(FILEID)
+      INTEGER FILEID(*), NXIINITGROUPDIR
+      EXTERNAL NXIINITGROUPDIR
+      NXINITGROUPDIR = NXIINITGROUPDIR(FILEID)
+      END
+
+      INTEGER FUNCTION NXGETATTRINFO(FILEID, NUM)
+      INTEGER FILEID(*), NUM, NXIGETATTRINFO
+      EXTERNAL NXIGETATTRINFO
+      NXGETATTRINFO = NXIGETATTRINFO(FILEID, NUM)
+      END
+
+      INTEGER FUNCTION NXINITATTRDIR(FILEID)
+      INTEGER FILEID(*), NXIINITATTRDIR
+      EXTERNAL NXIINITATTRDIR
+      NXINITATTRDIR = NXIINITATTRDIR(FILEID)
+      END
+
+      INTEGER FUNCTION NXISEXTERNALGROUP(FILEID, VGROUP, NXCLASS, NXURL)
+      INTEGER FILEID(*),NXIISEXTERNALGROUP, LENGTH
+      CHARACTER*(*) VGROUP, NXCLASS, NXURL
+      INTEGER*1 IVGROUP(256), INXCLASS(256), INXURL(256)
+      EXTERNAL NXIISEXTERNALGROUP
+      LENGTH = 256
+      CALL EXTRACT_STRING(IVGROUP, 256, VGROUP)
+      CALL EXTRACT_STRING(INXCLASS, 256, NXCLASS)
+      NXISEXTERNALGROUP = NXIISEXTERNALGROUP(FILEID, IVGROUP, INXCLASS, 
+     &  INXURL,LENGTH)
+      CALL REPLACE_STRING(NXURL, INXURL)
+      END
+
+
+      INTEGER FUNCTION NXINQUIREFILE(FILEID, NXFILE)
+      INTEGER FILEID(*),NXIINQUIREFILE, LENGTH
+      CHARACTER*(*) NXFILE
+      INTEGER*1 INXFILE (1024)
+      EXTERNAL NXIINQUIREFILE
+      LENGTH = 1023
+      NXINQUIREFILE = NXIINQUIREFILE(FILEID,INXFILE, 1023)
+      CALL REPLACE_STRING(NXFILE, INXFILE)
+      END
+
+      INTEGER FUNCTION NXLINKEXTERNAL(FILEID, VGROUP, NXCLASS, NXURL)
+      INTEGER FILEID(*),NXILINKEXTERNAL
+      CHARACTER*(*) VGROUP, NXCLASS, NXURL
+      INTEGER*1 IVGROUP(256), INXCLASS(256), INXURL(1024)
+      EXTERNAL NXILINKEXTERNAL
+      CALL EXTRACT_STRING(IVGROUP, 256, VGROUP)
+      CALL EXTRACT_STRING(INXCLASS, 256, NXCLASS)
+      CALL EXTRACT_STRING(INXURL, 1023, NXURL)
+      NXLINKEXTERNAL = NXILINKEXTERNAL(FILEID, IVGROUP,INXCLASS, 
+     & INXURL)
+      END
+
diff --git a/bindings/f77/napif.inc b/bindings/f77/napif.inc
new file mode 100644
index 0000000..2a26eb8
--- /dev/null
+++ b/bindings/f77/napif.inc
@@ -0,0 +1,94 @@
+C------------------------------------------------------------------------------
+C NeXus - Neutron & X-ray Common Data Format
+C  
+C Application Program Interface (Fortran 77) Header File
+C
+C Copyright (C) 1997-2004 Freddie Akeroyd, Mark Koennecke
+C
+C This library is free software; you can redistribute it and/or
+C modify it under the terms of the GNU Lesser General Public
+C License as published by the Free Software Foundation; either
+C version 2 of the License, or (at your option) any later version.
+C
+C This library is distributed in the hope that it will be useful,
+C but WITHOUT ANY WARRANTY; without even the implied warranty of
+C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+C Lesser General Public License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public
+C License along with this library; if not, write to the Free Software
+C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+C
+C  For further information, see <http://www.nexusformat.org>
+C
+C $Id$
+C------------------------------------------------------------------------------
+
+C *** Version of NeXus interface - should be consistent with napi.h!
+      CHARACTER*5 NEXUS_VERSION
+      PARAMETER(NEXUS_VERSION='3.9.0')
+C *** NXaccess enum - access modes for NXopen
+      INTEGER NXACC_READ,NXACC_RDWR,NXACC_CREATE, NXACC_CREATE5,
+     +  NXACC_CREATE4, NXACC_CREATEXML
+      PARAMETER(NXACC_READ=1,NXACC_RDWR=2,NXACC_CREATE=3,
+     +    NXACC_CREATE4=4,NXACC_CREATE5=5,NXACC_CREATEXML=6)
+C *** NXHANDLESIZE should be the size of an INTEGER*4 array that is (at least)
+C *** large enough to hold an NXhandle structure
+      INTEGER NXHANDLESIZE
+C      PARAMETER(NXHANDLESIZE=5120)
+      PARAMETER(NXHANDLESIZE=9058)
+C *** NXLINKSIZE is (at least) the size of an INTEGER*4 array that can hold
+C *** an NXlink structure: we'll assume 64bit alignment of structure members for safety
+      INTEGER NXLINKSIZE
+      PARAMETER(NXLINKSIZE=1040)
+C *** Possible NXstatus values - these are returned by all NX routines
+      INTEGER NX_OK,NX_ERROR,NX_EOD
+      PARAMETER(NX_OK=1,NX_ERROR=0,NX_EOD=-1)
+C *** Maximum values defined in HDF standard
+      INTEGER NX_MAXRANK,NX_MAXNAMELEN
+      PARAMETER(NX_MAXRANK=32,NX_MAXNAMELEN=64)
+C *** HDF datatypes used by Nexus - see hntdefs.h in HDF distribution
+      INTEGER DFNT_FLOAT32,DFNT_FLOAT64,DFNT_INT8,DFNT_UINT8,DFNT_INT16,
+     +        DFNT_UINT16,DFNT_INT32,DFNT_UINT32,DFNT_UCHAR8,DFNT_CHAR8,
+     +        DFNT_INT64, DFNT_UINT64
+      PARAMETER(DFNT_FLOAT32=5,DFNT_FLOAT64=6,DFNT_INT8=20,
+     +          DFNT_UINT8=21,DFNT_INT16=22,DFNT_UINT16=23,
+     +          DFNT_INT32=24,DFNT_UINT32=25,DFNT_UCHAR8=3,
+     +          DFNT_CHAR8=4, DFNT_INT64=26, DFNT_UINT64=27)
+C *** NeXus names for HDF parameters
+      INTEGER NX_FLOAT32,NX_FLOAT64,NX_INT8,NX_UINT8,NX_INT16,
+     +        NX_UINT16,NX_INT32,NX_UINT32,NX_CHAR,NX_BINARY,
+     +        NX_BOOLEAN, NX_INT64, NX_UINT64
+      PARAMETER(NX_FLOAT32=5,NX_FLOAT64=6,NX_INT8=20,
+     +          NX_UINT8=21,NX_INT16=22,NX_UINT16=23,
+     +          NX_INT32=24,NX_UINT32=25,NX_CHAR=4,NX_BOOLEAN=21,
+     +          NX_BINARY=21, NX_INT64=26,NX_UINT64=27)
+C**** NeXus compression schemes
+      INTEGER NX_COMP_NONE, NX_COMP_LZW, NX_COMP_HUF, NX_COMP_RLE
+      PARAMETER(NX_COMP_NONE=100,NX_COMP_LZW=200,NX_COMP_RLE=300,
+     +          NX_COMP_HUF=400)
+C**** NeXus Unlimited Dimension
+      INTEGER NX_UNLIMITED
+      PARAMETER (NX_UNLIMITED=-1)
+      INTEGER NXOPEN, NXCLOSE, NXMAKEGROUP, NXOPENGROUP, NXCLOSEGROUP,
+     +       NXMAKEDATA, NXOPENDATA, NXCLOSEDATA, NXGETDATA, 
+     +       NXGETCHARDATA, NXGETSLAB, NXGETATTR, NXGETCHARATTR, 
+     +       NXPUTDATA, NXPUTCHARDATA, NXPUTSLAB, 
+     +       NXPUTATTR, NXPUTCHARATTR, NXGETINFO, 
+     +       NXGETNEXTENTRY, NXGETNEXTATTR, NXGETGROUPID, NXMAKELINK,
+     +       NXGETGROUPINFO, NXINITGROUPDIR, NXGETATTRINFO, 
+     +       NXINITATTRDIR, NXFLUSH, NXCOMPMAKEDATA, NXOPENPATH,
+     +       NXSETNUMBERFORMAT, NXOPENGROUPPATH, NXOPENSOURCEGROUP,
+     +       NXMAKENAMEDLINK, NXGETPATH
+      LOGICAL NXSAMEID
+      EXTERNAL NXOPEN, NXCLOSE, NXMAKEGROUP, NXOPENGROUP, NXCLOSEGROUP,
+     +       NXMAKEDATA, NXOPENDATA, NXCLOSEDATA, NXGETDATA, 
+     +       NXGETCHARDATA, NXGETSLAB, NXGETATTR, NXGETCHARATTR, 
+     +       NXPUTDATA, NXPUTCHARDATA, NXPUTSLAB, 
+     +       NXPUTATTR, NXPUTCHARATTR, NXGETINFO, 
+     +       NXGETNEXTENTRY, NXGETNEXTATTR, NXGETGROUPID, NXMAKELINK,
+     +       NXGETGROUPINFO, NXINITGROUPDIR, NXGETATTRINFO, 
+     +       NXINITATTRDIR, NXFLUSH, NXCOMPMAKEDATA, NXSAMEID, 
+     +       NXOPENPATH,NXSETNUMBERFORMAT, NXOPENGROUPPATH,
+     +       NXOPENSOURCEGROUP, NXINQUIREFILE, NXISEXTERNALGROUP, 
+     +       NXLINKEXTERNAL, NXMAKENAMEDLINK, NXGETPATH
diff --git a/bindings/f77/napif_test.f b/bindings/f77/napif_test.f
new file mode 100644
index 0000000..2cfee22
--- /dev/null
+++ b/bindings/f77/napif_test.f
@@ -0,0 +1,327 @@
+C------------------------------------------------------------------------------
+C NeXus - Neutron & X-ray Common Data Format
+C  
+C Test program for NeXus FORTRAN 77 interface
+C
+C Copyright (C) 1997-2002, Freddie Akeroyd
+C
+C This library is free software; you can redistribute it and/or
+C modify it under the terms of the GNU Lesser General Public
+C License as published by the Free Software Foundation; either
+C version 2 of the License, or (at your option) any later version.
+C
+C This library is distributed in the hope that it will be useful,
+C but WITHOUT ANY WARRANTY; without even the implied warranty of
+C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+C Lesser General Public License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public
+C License along with this library; if not, write to the Free Software
+C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+C
+C  For further information, see <http://www.nexusformat.org>
+C
+C $Id$
+C------------------------------------------------------------------------------
+
+      INCLUDE 'napif.inc'
+      INTEGER NXRANK, NXDIMS(NX_MAXRANK), NXTYPE, NXLEN
+      INTEGER ENTRY_STATUS, ATTR_STATUS
+      INTEGER*4 I, J
+      REAL*4 R
+      BYTE I1_ARRAY(4)
+      INTEGER*2 I2_ARRAY(4)
+      INTEGER*4 I4_ARRAY(4) 
+      REAL*4 R4_ARRAY(4,5)
+      REAL*8 R8_ARRAY(4,5)
+      INTEGER*4 ARRAY_DIMS(2), UNLIMITED_DIMS(1)
+      INTEGER*4 CHUNK_SIZE(2)
+      INTEGER*4 SLAB_START(2), SLAB_SIZE(2)
+      CHARACTER*64 NAME, CLASS
+      CHARACTER*128 CHAR_BUFFER
+      BYTE CHAR_BUFFER_B(128)
+      CHARACTER*64 GROUP_NAME, CLASS_NAME
+      INTEGER FILEID(NXHANDLESIZE)
+      INTEGER GLINK(NXLINKSIZE), DLINK(NXLINKSIZE), BLINK(NXLINKSIZE)
+      INTEGER*4 COMP_ARRAY(20,100)
+      INTEGER*4 DIMS(2), CDIMS(2), UDIMS(1)
+      BYTE I1_BUFFER(4)
+      INTEGER*2 I2_BUFFER(4)
+      INTEGER*4 I4_BUFFER(4), U_BUFFER(7)
+      REAL*4 R4_BUFFER(4)
+      REAL*8 R8_BUFFER(16)
+      DATA I1_ARRAY /1, 2, 3, 4/
+      DATA I2_ARRAY /1000, 2000, 3000, 4000/
+      DATA I4_ARRAY /1000000, 2000000, 3000000, 4000000/
+      DATA R4_ARRAY /1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA R8_ARRAY/1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA ARRAY_DIMS /4, 5/
+      DATA CHUNK_SIZE /4, 5/
+      DATA U_BUFFER /0,1,2,3,4,5,6/
+      EQUIVALENCE (CHAR_BUFFER, CHAR_BUFFER_B)
+
+      IF (NXOPEN('NXtest.nxs', NXACC_CREATEXML, FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 10) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus data') .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i1_data', NX_INT8, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i1_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I1_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i2_data', NX_INT16, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i2_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I2_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i4_data', NX_INT32, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXCOMPMAKEDATA(FILEID, 'r4_data', NX_FLOAT32, 2, 
+     +        ARRAY_DIMS, NX_COMP_LZW, CHUNK_SIZE) .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, R4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'r8_data', NX_FLOAT64, 2, ARRAY_DIMS) 
+     +        .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r8_data') .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 5
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXPUTSLAB(FILEID, R8_ARRAY(1,5), SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 4
+            IF (NXPUTSLAB(FILEID, R8_ARRAY, SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTCHARATTR(FILEID, 'ch_attribute', 'NeXus',5,NX_CHAR) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'i4_attribute', 42, 1, NX_INT32) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'r4_attribute', 3.14159265, 1, 
+     +        NX_FLOAT32) .NE. NX_OK) STOP
+            IF (NXGETDATAID(FILEID, DLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+            IF (NXMAKELINK(FILEID, DLINK) .NE. NX_OK) STOP
+            DIMS(1) = 20
+            DIMS(2) = 100
+            DO I = 1,100
+               DO J = 1,20
+                  COMP_ARRAY(J,I) = I-1
+               END DO
+            END DO
+            CDIMS(1) = 20
+            CDIMS(2) = 20
+            IF (NXCOMPMAKEDATA(FILEID, 'comp_data', NX_INT32, 2, DIMS, 
+     +        NX_COMP_LZW, CDIMS) .NE. NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'comp_data') .NE. NX_OK) STOP
+               IF (NXPUTDATA(FILEID, COMP_ARRAY) .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+C            UDIMS(1) = NX_UNLIMITED
+            UDIMS(1) = 7*SLAB_SIZE(1)
+            IF (NXMAKEDATA(FILEID, 'flush_data', NX_INT32, 1, UDIMS) 
+     +        .NE. NX_OK) STOP
+               SLAB_SIZE(1) = 1
+               DO I = 1,7
+                  SLAB_START(1) = I
+                  IF (NXOPENDATA(FILEID, 'flush_data') .NE. NX_OK) STOP
+                     IF (NXPUTSLAB(FILEID, U_BUFFER(I), SLAB_START, 
+     +                 SLAB_SIZE) .NE. NX_OK) STOP
+                     IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+               END DO
+         IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+            IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 12) .NE. 
+     +        NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus sample') .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXMAKELINK (fileid, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+C *** read data
+      IF (NXOPEN('NXtest.nxs', NXACC_READ, FILEID) .NE. NX_OK) STOP
+      IF (NXGETATTRINFO(FILEID, J) .NE. NX_OK) STOP
+      IF (J .GT. 0) WRITE(*,'(1X,A,I2)') 
+     +  'Number of global attributes: ', J
+      DO I = 1,J
+         ATTR_STATUS = NXGETNEXTATTR(FILEID,NAME,NXDIMS,NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) THEN
+            STOP
+         ELSE IF (ATTR_STATUS .EQ. NX_OK) THEN
+            NXLEN = LEN(CHAR_BUFFER)
+            IF (NXGETCHARATTR(FILEID, NAME, CHAR_BUFFER, NXLEN, NXTYPE)
+     +        .NE. NX_OK) STOP
+            WRITE(*,'(4X,A)') NAME(1:LEN_TRIM(NAME))//' = '
+     +        //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+         END IF
+      END DO
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXGETGROUPINFO(FILEID, I, GROUP_NAME, CLASS_NAME) .NE. 
+     +     NX_OK) STOP
+         WRITE(*,'(1X,A,I2,A)') 'Group: '
+     +     //GROUP_NAME(1:LEN_TRIM(GROUP_NAME))//'('
+     +     //CLASS_NAME(1:LEN_TRIM(CLASS_NAME))
+     +     //') contains ',I,' items'
+  100 ENTRY_STATUS=NXGETNEXTENTRY(FILEID,NAME,CLASS,NXTYPE)
+      IF (ENTRY_STATUS .EQ. NX_ERROR) STOP
+      IF (CLASS(1:LEN_TRIM(CLASS)) .NE. 'SDS') THEN
+         IF (ENTRY_STATUS .NE. NX_EOD) THEN
+            WRITE(*,'(4X,A)') 'Subgroup: '//NAME(1:LEN_TRIM(NAME))//'('
+     +        //CLASS(1:LEN_TRIM(CLASS))//')'
+            ENTRY_STATUS = NX_OK
+         END IF
+      ELSE IF (ENTRY_STATUS .EQ. NX_OK) THEN
+         IF (NXOPENDATA(FILEID,NAME) .NE. NX_OK) STOP
+         IF (NXGETINFO(FILEID,NXRANK,NXDIMS,NXTYPE) .NE. NX_OK) STOP
+         WRITE(*,FMT='(4X,A,I2,A)') NAME(1:LEN_TRIM(NAME))//'(', 
+     +     NXTYPE,')'
+         IF (NXTYPE .EQ. NX_CHAR) THEN
+            IF (NXGETCHARDATA(FILEID,CHAR_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A)') 
+     +        'Values : '//CHAR_BUFFER(1:NXDIMS(1))
+         ELSE IF (NXTYPE .EQ. NX_INT8) THEN
+            IF (NXGETDATA(FILEID,I1_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I3)') 'Values : ', I1_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT16) THEN
+            IF (NXGETDATA(FILEID,I2_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I6)') 'Values : ', I2_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+            IF (NXGETDATA(FILEID,I4_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I12)') 'Values : ', I4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', R4_BUFFER
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT64) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', 
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', 
+     +        (R8_BUFFER(I), I=1,4)
+         END IF
+  200    ATTR_STATUS = NXGETNEXTATTR (FILEID, NAME, NXDIMS, NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) STOP
+         IF (ATTR_STATUS .EQ. NX_OK) THEN
+            IF (NXTYPE .EQ. NX_CHAR) THEN
+               LENGTH=LEN(CHAR_BUFFER)
+               IF (NXGETCHARATTR(FILEID,NAME,CHAR_BUFFER,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A)') NAME(1:LEN_TRIM(NAME))//' : '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+            ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,I,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,I5)') NAME(1:LEN_TRIM(NAME))//' : ',
+     +           I
+            ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,R,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,F10.6)') NAME(1:LEN_TRIM(NAME))
+     +           //' : ', R
+            END IF
+         END IF
+         IF (ATTR_STATUS .NE. NX_EOD) GOTO 200
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+      END IF
+      IF (ENTRY_STATUS .NE. NX_EOD) GOTO 100
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, BLINK) .NE. NX_OK) STOP
+         IF (NXSAMEID(FILEID, GLINK, BLINK)) THEN
+            WRITE(*,*) 'Link Check OK'
+         ELSE
+            WRITE(*,*) 'Link Check Failed'
+         ENDIF
+C-------- NXOPENPATH Test
+      IF(NXOPENPATH(FILEID,'/entry/data/comp_data') .NE. NX_OK)STOP
+      IF(NXOPENPATH(FILEID,'/entry/data/comp_data') .NE. NX_OK)STOP
+      IF(NXOPENPATH(FILEID,'../r8_data') .NE. NX_OK)STOP
+      WRITE(6,*)'NXOPENPATH Test Succeeded'
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+      STOP
+      END
+C----------------------------------------------------------------------
+C     LEN_TRIM trims remaining blanks and tabs from the end of "string"
+C      INTEGER FUNCTION LEN_TRIM (STRING)
+C      INTEGER I
+C      CHARACTER*(*) STRING
+C      I = LEN(STRING)
+C      DO WHILE (I .GE. 1 .AND. 
+C     +(STRING(I:I).EQ.' '.OR. STRING(I:I).EQ.CHAR(0).OR.
+C     + STRING(I:I).EQ.CHAR(9)))
+C         I = I - 1
+C      END DO
+C      LEN_TRIM = MIN(I,LEN(STRING))
+C      RETURN
+C      END
+
diff --git a/bindings/f90/CMakeLists.txt b/bindings/f90/CMakeLists.txt
new file mode 100644
index 0000000..f05a2ec
--- /dev/null
+++ b/bindings/f90/CMakeLists.txt
@@ -0,0 +1,56 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+#Make NeXus F90 Bindings Static Library
+
+set (SOURCES NXmodule.f90 NXUmodule.f90)
+
+add_library (NeXus_F90_Static_Library STATIC ${SOURCES})
+
+set_target_properties(NeXus_F90_Static_Library PROPERTIES OUTPUT_NAME NeXus90)
+
+target_link_libraries(NeXus_F90_Static_Library NeXus_Static_Library ${HDF5_LIBRARIES} ${MXML_LINK}
+                      ${HDF4_LINK} ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+#Make NeXus F90 Bindings Shared Library
+
+add_library (NeXus_F90_Shared_Library SHARED ${SOURCES})
+
+#Note - library version needs to be got from somewhere?
+set_target_properties(NeXus_F90_Shared_Library PROPERTIES OUTPUT_NAME NeXus90
+                      VERSION 1.0 SOVERSION 4)
+
+target_link_libraries(NeXus_F90_Shared_Library NeXus_Shared_Library ${HDF5_LIBRARIES} ${MXML_LINK}
+                      ${HDF4_LINK} ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES})
+
+install (TARGETS NeXus_F90_Static_Library NeXus_F90_Shared_Library
+         RUNTIME DESTINATION bin COMPONENT Runtime
+         LIBRARY DESTINATION lib COMPONENT Runtime
+         ARCHIVE DESTINATION lib/nexus COMPONENT Development)
diff --git a/bindings/f90/Makefile.am b/bindings/f90/Makefile.am
new file mode 100644
index 0000000..255b863
--- /dev/null
+++ b/bindings/f90/Makefile.am
@@ -0,0 +1,52 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for NeXus FORTRAN 90 bindings
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+lib_LTLIBRARIES = libNeXus90.la
+
+libNeXus90_la_SOURCES = NXmodule.f90 NXUmodule.f90
+libNeXus90_la_LIBADD = $(top_builddir)/src/libNeXus.la
+libNeXus90_la_LDFLAGS = @SHARED_LDFLAGS@ -version-info $(NXLTVERSINFO)
+libNeXus90_la_LINK = $(FCLINK)
+
+NXUmodule.o: NXUmodule.f90 NXmodule.o
+
+# This is needed as f90 is not supported as a valid tag in libtool
+# and the relink command (used during an install) which is written to
+# libNeXus90.la will not work. 
+#all: all-am libNeXus90.la_orig
+
+#libNeXus90.la_orig: libNeXus90.la
+#	mv libNeXus90.la $@
+#	sed -e 's/--mode=relink/--mode=relink @LTF90LINKTAG@/' < $@ > libNeXus90.la
+#	touch $@
+
+include $(top_srcdir)/build_rules.am
+
+CLEANFILES = libNeXus90.la_orig nxmodule.mod nxumodule.mod
+
diff --git a/bindings/f90/NXUmodule.f90 b/bindings/f90/NXUmodule.f90
new file mode 100755
index 0000000..4fcf301
--- /dev/null
+++ b/bindings/f90/NXUmodule.f90
@@ -0,0 +1,1374 @@
+!------------------------------------------------------------------------------
+! NeXus - Neutron & X-ray Common Data Format
+!  
+! Fortran 90 Utilities
+!
+! Copyright (C) 1999-2002, Ray Osborn
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Lesser General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+! Lesser General Public License for more details.
+!
+! You should have received a copy of the GNU Lesser General Public
+! License along with this library; if not, write to the Free Software
+! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+!
+!  For further information, see <http://www.nexusformat.org>
+!
+!$Id$
+!------------------------------------------------------------------------------
+
+MODULE NXUmodule
+
+   USE NXmodule
+   PUBLIC
+! *** NeXus utility functions ***
+   PUBLIC :: NXUwriteglobals, NXUwritegroup, NXUwritedata, NXUreaddata
+   PUBLIC :: NXUsetcompress
+   PUBLIC :: NXUfindgroup, NXUfindclass, NXUfinddata, NXUfindattr
+   PUBLIC :: NXUfindsignal, NXUfindaxis
+   PUBLIC :: NXUfindlink, NXUresumelink
+! *** NeXus utility internal functions
+   PRIVATE :: NXUpreparedata, NXUconfirmdata, NXUsearchgroup
+! *** NeXus utility global variables
+   INTEGER, PRIVATE :: NXcompress_type = NX_COMP_NONE
+   INTEGER, PRIVATE :: NXcompress_size = 1000
+   INTEGER, PRIVATE :: group_level
+   INTEGER, PRIVATE :: NXrank, NXdims(NX_MAXRANK), NXtype, NXsize
+! *** NeXus generic interfaces ***
+   INTERFACE NXUwritedata
+       MODULE PROCEDURE NXUwritei4, NXUwriter4, NXUwriter8, NXUwritechar, &
+                          NXUwritei4array, NXUwriter4array, &
+                          NXUwriter8array, NXUwrite2Di4array, &
+                          NXUwrite2Dr4array, NXUwrite2Dr8array, &
+                          NXUwrite3Di4array, NXUwrite3Dr4array, &
+                          NXUwrite3Dr8array
+   END INTERFACE
+   INTERFACE NXUreaddata
+       MODULE PROCEDURE NXUreadi4, NXUreadr4, NXUreadr8, NXUreadchar, &
+                          NXUreadi4array, NXUreadr4array, NXUreadr8array, &
+                          NXUread2Di4array, NXUread2Dr4array, &
+                          NXUread2Dr8array, NXUread3Di4array, &
+                          NXUread3Dr4array, NXUread3Dr8array
+   END INTERFACE
+
+CONTAINS
+!------------------------------------------------------------------------------
+!NXUwriteglobals writes the global attributes to a file
+   FUNCTION NXUwriteglobals (file_id, user, affiliation, address, phone, fax, &
+                        email) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id      
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: user, affiliation, address, &
+                        phone, fax, email
+      INTEGER :: status
+
+      IF (PRESENT(user)) THEN
+         status = NXputattr (file_id, "user", trim(user))
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(affiliation)) THEN
+         status = NXputattr (file_id, "affiliation", trim(affiliation))
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(address)) THEN
+         status = NXputattr (file_id, "address", trim(address))
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(phone)) THEN
+         status = NXputattr (file_id, "telephone_number", trim(phone))
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(fax)) THEN
+         status = NXputattr (file_id, "fax_number", trim(fax))
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(email)) THEN
+         status = NXputattr (file_id, "email", trim(email))
+         IF (status /= NX_OK) RETURN
+      END IF
+
+   END FUNCTION NXUwriteglobals
+!------------------------------------------------------------------------------
+!NXUwritegroup creates and leaves open a group
+   FUNCTION NXUwritegroup (file_id, group_name, group_class) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      CHARACTER(len=*), INTENT(in) :: group_name, group_class
+      INTEGER :: status
+
+      status = NXmakegroup (file_id, group_name, group_class)
+      IF (status == NX_OK) THEN
+         status = NXopengroup (file_id, group_name, group_class)
+      END IF
+
+   END FUNCTION NXUwritegroup
+!------------------------------------------------------------------------------
+!NXUwritedata creates and writes a data set
+!
+!The following routines define the generic function NXUwritedata
+!------------------------------------------------------------------------------
+!NXUwritei4 writes a scalar integer*4 data item
+   FUNCTION NXUwritei4 (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), INTENT(in)    :: data
+      CHARACTER(len=*),   INTENT(in), OPTIONAL :: units
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_INT32, 1, (/1/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      status = NXputdata (file_id, (/ data /))
+
+   END FUNCTION NXUwritei4
+!------------------------------------------------------------------------------
+!NXUwriter4 writes a scalar real*4 data item
+   FUNCTION NXUwriter4 (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  INTENT(in)    :: data
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT32, 1, (/1/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      status = NXputdata (file_id, (/ data /))
+
+   END FUNCTION NXUwriter4
+!------------------------------------------------------------------------------
+!NXUwriter8 writes a scalar real*8 data item
+   FUNCTION NXUwriter8 (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  INTENT(in)    :: data
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT64, 1, (/1/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      status = NXputdata (file_id, (/ data /))
+
+   END FUNCTION NXUwriter8
+!------------------------------------------------------------------------------
+!NXUwritechar writes a character data item
+   FUNCTION NXUwritechar (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      CHARACTER(len=*), INTENT(in)    :: data
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_CHAR, 1, &
+                        (/len_trim(data)/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units, len_trim(units), NX_CHAR)
+         IF (status /= NX_OK) RETURN
+      END IF
+      status = NXputdata (file_id, data)
+
+   END FUNCTION NXUwritechar
+!------------------------------------------------------------------------------
+!NXUwritei4array writes 1D integer*4 array data
+   FUNCTION NXUwritei4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), INTENT(in)    :: data(:)
+      CHARACTER(len=*),   INTENT(in), OPTIONAL :: units
+      INTEGER,            INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_INT32, 1, (/size(data)/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, data, data_start, data_size)
+      ELSE
+         status = NXputdata (file_id, data)
+      END IF
+
+   END FUNCTION NXUwritei4array
+!------------------------------------------------------------------------------
+!NXUwriter4array writes 1D real*4 array data
+   FUNCTION NXUwriter4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  INTENT(in)    :: data(:)
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER,          INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT32, 1, &
+                        (/size(data)/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, data, data_start, data_size)
+      ELSE
+         status = NXputdata (file_id, data)
+      END IF
+
+   END FUNCTION NXUwriter4array
+!------------------------------------------------------------------------------
+!NXUwriter8array writes real*8 array data
+   FUNCTION NXUwriter8array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  INTENT(in)    :: data(:)
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER,          INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT64, 1, &
+                        (/size(data)/))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, data, data_start, data_size)
+      ELSE
+         status = NXputdata (file_id, data)
+      END IF
+
+   END FUNCTION NXUwriter8array
+!------------------------------------------------------------------------------
+!NXUwrite2Di4array writes 2D integer*4 data
+   FUNCTION NXUwrite2Di4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), INTENT(in)    :: data(:,:)
+      CHARACTER(len=*),   INTENT(in), OPTIONAL :: units
+      INTEGER,            INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+      INTEGER, ALLOCATABLE :: buffer(:)
+
+      status = NXUpreparedata (file_id, data_name, NX_INT32, 2, shape(data))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      ALLOCATE (buffer(size(data)))
+      buffer = RESHAPE (data, (/ size(data) /))
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, buffer, data_start, data_size)
+      ELSE
+         status = NXputdata(file_id, buffer)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUwrite2Di4array
+!------------------------------------------------------------------------------
+!NXUwrite2Dr4array writes 2D real*4 data
+   FUNCTION NXUwrite2Dr4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  INTENT(in)    :: data(:,:)
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER,          INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+      REAL(kind=NXr4), ALLOCATABLE :: buffer(:)
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT32, 2, shape(data))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      ALLOCATE (buffer(size(data)))
+      buffer = RESHAPE (data, (/ size(data) /))
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, buffer, data_start, data_size)
+      ELSE
+         status = NXputdata(file_id, buffer)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUwrite2Dr4array
+!------------------------------------------------------------------------------
+!NXUwrite2Dr8array writes 2D real*8 data
+   FUNCTION NXUwrite2Dr8array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  INTENT(in)    :: data(:,:)
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER,          INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+      REAL(kind=NXr8), ALLOCATABLE :: buffer(:)
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT64, 2, shape(data))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      ALLOCATE (buffer(size(data)))
+      buffer = RESHAPE (data, (/ size(data) /))
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, buffer, data_start, data_size)
+      ELSE
+         status = NXputdata(file_id, buffer)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUwrite2Dr8array
+!------------------------------------------------------------------------------
+!NXUwrite3Di4array writes 3D integer*4 data
+   FUNCTION NXUwrite3Di4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), INTENT(in)    :: data(:,:,:)
+      CHARACTER(len=*),   INTENT(in), OPTIONAL :: units
+      INTEGER,            INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+      INTEGER, ALLOCATABLE :: buffer(:)
+
+      status = NXUpreparedata (file_id, data_name, NX_INT32, 3, shape(data))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      ALLOCATE (buffer(size(data)))
+      buffer = RESHAPE (data, (/ size(data) /))
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, buffer, data_start, data_size)
+      ELSE
+         status = NXputdata(file_id, buffer)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUwrite3Di4array
+!------------------------------------------------------------------------------
+!NXUwrite3Dr4array writes 3D real*4 data
+   FUNCTION NXUwrite3Dr4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  INTENT(in)    :: data(:,:,:)
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER,          INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+      REAL(kind=NXr4), ALLOCATABLE :: buffer(:)
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT32, 3, shape(data))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      ALLOCATE (buffer(size(data)))
+      buffer = RESHAPE (data, (/ size(data) /))
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, buffer, data_start, data_size)
+      ELSE
+         status = NXputdata(file_id, buffer)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUwrite3Dr4array
+!------------------------------------------------------------------------------
+!NXUwrite3Dr8array writes 3D real*8 data
+   FUNCTION NXUwrite3Dr8array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  INTENT(in)    :: data(:,:,:)
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: units
+      INTEGER,          INTENT(in), OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status
+      REAL(kind=NXr8), ALLOCATABLE :: buffer(:)
+
+      status = NXUpreparedata (file_id, data_name, NX_FLOAT64, 3, shape(data))
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(units) .AND. NXUfindattr(file_id, "units") == NX_EOD) THEN
+         status = NXputattr (file_id, "units", units)
+         IF (status /= NX_OK) RETURN
+      END IF
+      ALLOCATE (buffer(size(data)))
+      buffer = RESHAPE (data, (/ size(data) /))
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         status = NXputslab (file_id, buffer, data_start, data_size)
+      ELSE
+         status = NXputdata(file_id, buffer)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUwrite3Dr8array
+!------------------------------------------------------------------------------
+!NXUreaddata reads data
+!
+!The following routines define the generic function NXUreaddata
+!------------------------------------------------------------------------------
+!NXUreadi4 reads a scalar integer*4 data item
+   FUNCTION NXUreadi4 (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout)  :: file_id
+      CHARACTER(len=*),   INTENT(in)     :: data_name
+      INTEGER(kind=NXi4), INTENT(out)    :: data
+      CHARACTER(len=*),   INTENT(out), OPTIONAL :: units
+      INTEGER :: status, dimensions(NX_MAXRANK)
+      INTEGER(kind=NXi4) :: buffer(1)
+
+      status = NXUconfirmdata (file_id, data_name, NX_INT32, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (dimensions(1) /= 1) THEN
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgetdata(file_id, buffer)
+      IF (status == NX_OK) THEN
+         data = buffer(1)
+         IF (PRESENT(units)) THEN
+            status = NXgetattr (file_id, "units", units)
+         END IF
+      END IF
+
+   END FUNCTION NXUreadi4
+!------------------------------------------------------------------------------
+!NXgetr4 reads a scalar real*4 data item
+   FUNCTION NXUreadr4 (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  INTENT(out)   :: data
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER :: status, dimensions(NX_MAXRANK)
+      REAL(kind=NXr4) :: buffer(1)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT32, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (dimensions(1) /= 1) THEN
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgetdata(file_id, buffer)
+      IF (status == NX_OK) THEN
+         data = buffer(1)
+         IF (PRESENT(units)) THEN
+            status = NXgetattr (file_id, "units", units)
+         END IF
+      END IF
+
+   END FUNCTION NXUreadr4
+!------------------------------------------------------------------------------
+!NXgetr8 reads a scalar real*8 data item
+   FUNCTION NXUreadr8 (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  INTENT(out)   :: data
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER :: status, dimensions(NX_MAXRANK)
+      REAL(kind=NXr8) :: buffer(1)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT64, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (dimensions(1) /= 1) THEN
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgetdata(file_id, buffer)
+      IF (status == NX_OK) THEN
+         data = buffer(1)
+         IF (PRESENT(units)) THEN
+            status = NXgetattr (file_id, "units", units)
+         END IF
+      END IF
+
+   END FUNCTION NXUreadr8
+!------------------------------------------------------------------------------
+!NXgetchar reads a character string
+   FUNCTION NXUreadchar (file_id, data_name, data, units) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      CHARACTER(len=*), INTENT(out)   :: data
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER :: status, dimensions(NX_MAXRANK)
+
+      status = NXUconfirmdata (file_id, data_name, NX_CHAR, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (dimensions(1) > len(data)) THEN
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgetdata(file_id, data)
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+            status = NXgetattr (file_id, "units", units)
+      END IF
+
+   END FUNCTION NXUreadchar
+!------------------------------------------------------------------------------
+!NXUreadi4array reads an integer*4 array
+   FUNCTION NXUreadi4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), POINTER       :: data(:)
+      CHARACTER(len=*),   INTENT(out), OPTIONAL :: units
+      INTEGER,            INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK) 
+
+      status = NXUconfirmdata (file_id, data_name, NX_INT32, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (data(data_size(1)))
+         status = NXgetslab (file_id, data, data_start, data_size)
+      ELSE
+         ALLOCATE (data(dimensions(1)))
+         status = NXgetdata (file_id, data)
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+
+   END FUNCTION NXUreadi4array
+!------------------------------------------------------------------------------
+!NXUreadr4array reads a real*4 array
+   FUNCTION NXUreadr4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  POINTER       :: data(:)
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER,          INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT32, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (data(data_size(1)))
+         status = NXgetslab (file_id, data, data_start, data_size)
+      ELSE
+         ALLOCATE (data(dimensions(1)))
+         status = NXgetdata (file_id, data)
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+
+   END FUNCTION NXUreadr4array
+!------------------------------------------------------------------------------
+!NXUreadr8array reads a real*8 array
+   FUNCTION NXUreadr8array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  POINTER       :: data(:)
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER,          INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT64, 1, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (data(data_size(1)))
+         status = NXgetslab (file_id, data, data_start, data_size)
+      ELSE
+         ALLOCATE (data(dimensions(1)))
+         status = NXgetdata (file_id, data)
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+
+   END FUNCTION NXUreadr8array
+!------------------------------------------------------------------------------
+!NXUread2Di4array reads a 2D integer*4 array
+   FUNCTION NXUread2Di4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), POINTER       :: data(:,:)
+      CHARACTER(len=*),   INTENT(out), OPTIONAL :: units
+      INTEGER,            INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK), data_shape(2)
+      INTEGER, ALLOCATABLE :: buffer(:)
+
+      status = NXUconfirmdata (file_id, data_name, NX_INT32, 2, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (buffer(PRODUCT(data_size(1:2))))
+         status = NXgetslab (file_id, buffer, data_start, data_size)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(data_size(1),data_size(2)))
+            data_shape = data_size(1:2)
+            data = RESHAPE (buffer, data_shape)
+         END IF
+      ELSE
+         ALLOCATE (buffer(PRODUCT(dimensions(1:2))))
+         status = NXgetdata(file_id, buffer)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(dimensions(1),dimensions(2)))
+            data = RESHAPE (buffer, dimensions(1:2))
+         END IF
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUread2Di4array
+!------------------------------------------------------------------------------
+!NXUread2Dr4array reads a 2D real*4 array
+   FUNCTION NXUread2Dr4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  POINTER       :: data(:,:)
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER,          INTENT(in),  OPTIONAL ::data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK), data_shape(2)
+      REAL, ALLOCATABLE :: buffer(:)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT32, 2, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (buffer(PRODUCT(data_size(1:2))))
+         status = NXgetslab (file_id, buffer, data_start, data_size)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(data_size(1),data_size(2)))
+            data_shape = data_size(1:2)
+            data = RESHAPE (buffer, data_shape)
+         END IF
+      ELSE
+         ALLOCATE (buffer(PRODUCT(dimensions(1:2))))
+         status = NXgetdata(file_id, buffer)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(dimensions(1),dimensions(2)))
+            data = RESHAPE (buffer, dimensions(1:2))
+         END IF
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUread2Dr4array
+!------------------------------------------------------------------------------
+!NXUread2Dr8array reads a 2D real*8 precision array
+   FUNCTION NXUread2Dr8array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  POINTER       :: data(:,:)
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER,          INTENT(in),  OPTIONAL ::data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK), data_shape(2)
+      REAL, ALLOCATABLE :: buffer(:)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT64, 2, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (buffer(PRODUCT(data_size(1:2))))
+         status = NXgetslab (file_id, buffer, data_start, data_size)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(data_size(1),data_size(2)))
+            data_shape = data_size(1:2)
+            data = RESHAPE (buffer, data_shape)
+         END IF
+      ELSE
+         ALLOCATE (buffer(PRODUCT(dimensions(1:2))))
+         status = NXgetdata(file_id, buffer)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(dimensions(1),dimensions(2)))
+            data = RESHAPE (buffer, dimensions(1:2))
+         END IF
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUread2Dr8array
+!------------------------------------------------------------------------------
+!NXUread3Di4array reads a 3D integer*4 array
+   FUNCTION NXUread3Di4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(inout) :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: data_name
+      INTEGER(kind=NXi4), POINTER       :: data(:,:,:)
+      CHARACTER(len=*),   INTENT(out), OPTIONAL :: units
+      INTEGER,            INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK), data_shape(3)
+      INTEGER, ALLOCATABLE :: buffer(:)
+
+      status = NXUconfirmdata (file_id, data_name, NX_INT32, 3, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (buffer(PRODUCT(data_size(1:3))))
+         status = NXgetslab (file_id, buffer, data_start, data_size)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(data_size(1),data_size(2),data_size(3)))
+            data_shape = data_size(1:3)
+            data = RESHAPE (buffer, data_shape)
+         END IF
+      ELSE
+         ALLOCATE (buffer(PRODUCT(dimensions(1:3))))
+         status = NXgetdata(file_id, buffer)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(dimensions(1),dimensions(2),dimensions(3)))
+            data = RESHAPE (buffer, dimensions(1:3))
+         END IF
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUread3Di4array
+!------------------------------------------------------------------------------
+!NXUread3Dr4array reads a 3D real*4 array
+   FUNCTION NXUread3Dr4array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr4),  POINTER       :: data(:,:,:)
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER,          INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK), data_shape(3)
+      REAL, ALLOCATABLE :: buffer(:)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT32, 3, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (buffer(PRODUCT(data_size(1:3))))
+         status = NXgetslab (file_id, buffer, data_start, data_size)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(data_size(1),data_size(2),data_size(3)))
+            data_shape = data_size(1:3)
+            data = RESHAPE (buffer, data_shape)
+         END IF
+      ELSE
+         ALLOCATE (buffer(PRODUCT(dimensions(1:3))))
+         status = NXgetdata(file_id, buffer)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(dimensions(1),dimensions(2),dimensions(3)))
+            data = RESHAPE (buffer, dimensions(1:3))
+         END IF
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUread3Dr4array
+!------------------------------------------------------------------------------
+!NXUread3Dr8array reads a 3D real*8 array
+   FUNCTION NXUread3Dr8array (file_id, data_name, data, units, data_start, &
+                        data_size) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      REAL(kind=NXr8),  POINTER       :: data(:,:,:)
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: units
+      INTEGER,          INTENT(in),  OPTIONAL :: data_start(:), data_size(:)
+      INTEGER :: status, dimensions(NX_MAXRANK), data_shape(3)
+      REAL, ALLOCATABLE :: buffer(:)
+
+      status = NXUconfirmdata (file_id, data_name, NX_FLOAT64, 3, dimensions)
+      IF (status /= NX_OK) RETURN
+      IF (PRESENT(data_start) .AND. PRESENT(data_size)) THEN
+         ALLOCATE (buffer(PRODUCT(data_size(1:3))))
+         status = NXgetslab (file_id, buffer, data_start, data_size)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(data_size(1),data_size(2),data_size(3)))
+            data_shape = data_size(1:3)
+            data = RESHAPE (buffer, data_shape)
+         END IF
+      ELSE
+         ALLOCATE (buffer(PRODUCT(dimensions(1:3))))
+         status = NXgetdata(file_id, buffer)
+         IF (status == NX_OK) THEN
+            ALLOCATE (data(dimensions(1),dimensions(2),dimensions(3)))
+            data = RESHAPE (buffer, dimensions(1:3))
+         END IF
+      END IF
+      IF (status == NX_OK .and. PRESENT(units)) THEN
+         status = NXgetattr (file_id, "units", units)
+      END IF
+      DEALLOCATE (buffer)
+
+   END FUNCTION NXUread3Dr8array
+!------------------------------------------------------------------------------
+!------------------------------------------------------------------------------
+!NXUsetcompress sets the default compression type and minimum size
+   FUNCTION NXUsetcompress (file_id, compress_type, compress_size) &
+                        RESULT (status)
+
+      TYPE(NXhandle), INTENT(inout) :: file_id
+      INTEGER,        INTENT(in)    :: compress_type
+      INTEGER,        INTENT(in), OPTIONAL :: compress_size
+      INTEGER :: status
+
+      IF (compress_type == NX_COMP_LZW .OR. compress_type == NX_COMP_HUF .OR. &
+          compress_type == NX_COMP_RLE .OR. compress_type == NX_COMP_NONE) THEN
+         NXcompress_type = compress_type
+         IF (PRESENT(compress_size)) NXcompress_size = compress_size
+         status = NX_OK
+      ELSE
+         call NXerror ("Invalid compression option")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXUsetcompress
+!------------------------------------------------------------------------------
+!NXUfindgroup finds if a NeXus group of the specified name exists
+   FUNCTION NXUfindgroup (file_id, group_name, group_class) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: group_name
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: group_class
+      CHARACTER(len=NX_MAXNAMELEN), ALLOCATABLE :: name(:), class(:)
+      INTEGER :: status, n, i
+
+      status = NXgetgroupinfo (file_id, n)
+      IF (status /= NX_OK) RETURN
+      ALLOCATE (name(n), class(n), STAT=status)
+      IF (status /= 0) THEN
+         call NXerror ("Unable to allocate directory arrays")
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgroupdir (file_id, n, name, class)
+      IF (status == NX_OK) THEN
+         status = NX_EOD
+         DO i = 1,n
+            IF (trim(name(i)) == trim(group_name)) THEN
+               group_class = trim(class(i))
+               IF (class(i)(1:2) == "NX") THEN
+                  status = NX_OK
+               ELSE
+                  CALL NXerror (trim(name(i))//" is not a group")
+                  status = NX_ERROR
+               END IF
+               EXIT
+            END IF
+         END DO
+      END IF
+      DEALLOCATE (name, class)
+
+   END FUNCTION NXUfindgroup
+!------------------------------------------------------------------------------
+!NXUfindclass finds if a NeXus group of the specified class exists
+   FUNCTION NXUfindclass (file_id, group_class, group_name, find_index) &
+                        RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: group_class
+      CHARACTER(len=*), INTENT(out)   :: group_name
+      INTEGER,          INTENT(in), OPTIONAL :: find_index
+      CHARACTER(len=NX_MAXNAMELEN), ALLOCATABLE :: name(:), class(:)
+      INTEGER :: status, n, i, j
+
+      status = NXgetgroupinfo (file_id, n)
+      IF (status /= NX_OK) RETURN
+      ALLOCATE (name(n), class(n), STAT=status)
+      IF (status /= 0) THEN
+         CALL NXerror ("Unable to allocate directory arrays")
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgroupdir (file_id, n, name, class)
+      IF (status == NX_OK) THEN
+         j = 0
+         status = NX_EOD
+         DO i = 1,n
+            IF (trim(class(i)) == trim(group_class)) THEN
+               IF (PRESENT(find_index)) THEN
+                  j = j + 1
+                  IF (j < find_index) CYCLE
+               END IF
+               group_name = trim(name(i))
+               status = NX_OK
+               EXIT
+            END IF
+         END DO
+      END IF
+      DEALLOCATE (name, class)
+
+   END FUNCTION NXUfindclass
+!------------------------------------------------------------------------------
+!NXUfinddata finds if a NeXus data item is in the current group
+   FUNCTION NXUfinddata (file_id, data_name) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      CHARACTER(len=NX_MAXNAMELEN), ALLOCATABLE :: name(:), class(:)
+      INTEGER :: status, n, i
+
+      status = NXgetgroupinfo (file_id, n)
+      IF (status /= NX_OK) RETURN
+      ALLOCATE (name(n), class(n), STAT=status)
+      IF (status /= 0) THEN
+         call NXerror ("Unable to allocate directory arrays")
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgroupdir (file_id, n, name, class)
+      IF (status == NX_OK) THEN
+         status = NX_EOD
+         DO i = 1,n
+            IF (trim(name(i)) == trim(data_name)) THEN
+               IF (class(i)(1:3) == "SDS") THEN
+                  status = NX_OK
+               ELSE
+                  CALL NXerror (trim(name(i))//" is not a data item")
+                  status = NX_ERROR
+               END IF
+               EXIT
+            END IF
+         END DO
+      END IF
+      DEALLOCATE (name, class)
+
+   END FUNCTION NXUfinddata
+!------------------------------------------------------------------------------
+!NXUfindattr finds if a NeXus attribute exists
+   FUNCTION NXUfindattr (file_id, attr_name) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: attr_name
+      CHARACTER(len=NX_MAXNAMELEN), ALLOCATABLE :: name(:)
+      INTEGER :: status, n, i
+
+      status = NXgetattrinfo (file_id, n)
+      IF (status /= NX_OK) RETURN
+      ALLOCATE (name(n), STAT=status)
+      IF (status /= 0) THEN
+         call NXerror ("Unable to allocate directory arrays")
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXattrdir (file_id, n, name)
+      IF (status == NX_OK) THEN
+         status = NX_EOD
+         DO i = 1,n
+            IF (trim(name(i)) == trim(attr_name)) status = NX_OK
+         END DO
+      END IF
+      DEALLOCATE (name)
+
+   END FUNCTION NXUfindattr
+!------------------------------------------------------------------------------
+!NXUfindsignal finds the NeXus data item containing the required signal
+   FUNCTION NXUfindsignal (file_id, signal, data_name, data_rank, data_type, &
+                        data_dimensions) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      INTEGER,          INTENT(in)    :: signal
+      CHARACTER(len=*)                :: data_name
+      INTEGER,          INTENT(out)   :: data_rank, data_type, data_dimensions(:)
+      CHARACTER(len=len(data_name)) :: name
+      CHARACTER(len=NX_MAXNAMELEN) :: class, attr_name
+      INTEGER :: status, value
+
+      status = NXinitgroupdir (file_id)
+      IF (status /= NX_OK) RETURN
+      DO
+         status = NXgetnextentry (file_id, name, class, NXtype)
+         IF (status == NX_OK .AND. class == "SDS") THEN
+            status = NXopendata (file_id, name)
+            IF (status /= NX_OK) RETURN
+            status = NXUfindattr (file_id, "signal")
+            IF (status == NX_OK) THEN
+               status = NXgetattr (file_id, "signal", value)
+               IF (status /= NX_OK) RETURN
+               IF (value == signal) THEN
+                  status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+                  IF (status == NX_OK) THEN
+                     data_name = name
+                     data_rank = NXrank
+                     data_type = NXtype
+                     data_dimensions = NXdims
+                     RETURN
+                  END IF
+               END IF
+            ELSE IF (status == NX_EOD) THEN
+               CYCLE
+            ELSE IF (status == NX_ERROR) THEN         
+               RETURN
+            END IF
+         ELSE IF (status == NX_EOD) THEN
+            CALL NXerror ("No data with the attribute ""signal"" found")
+            status = NX_ERROR
+            EXIT
+         ELSE IF (status == NX_ERROR) THEN
+            RETURN
+         END IF
+      END DO
+
+   END FUNCTION NXUfindsignal
+!------------------------------------------------------------------------------
+!NXUfindaxis finds the NeXus data item containing the required axis
+   FUNCTION NXUfindaxis (file_id, axis, primary, data_name, data_type, &
+                        data_dimensions) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      INTEGER,          INTENT(in)    :: axis, primary
+      CHARACTER(len=*)                :: data_name
+      INTEGER,          INTENT(out)   :: data_type, data_dimensions(NX_MAXRANK)
+      CHARACTER(len=len(data_name)) :: name
+      CHARACTER(len=NX_MAXNAMELEN) :: class, attr_name
+      CHARACTER(len=255) :: axis_list
+      INTEGER :: status, signal=1, value, data_rank, C_axis, i, j, k
+
+      !First find data with "signal" attribute to check for "axes" attribute
+      status = NXUfindsignal (file_id, signal, data_name, data_rank, &
+                        data_type, data_dimensions)
+      IF (status /= NX_OK) RETURN
+      !The axis number cannot be greater than the data rank
+      IF (axis > data_rank) THEN
+         CALL NXerror ("Axis number greater than the data rank")
+         status = NX_ERROR
+         RETURN
+      END IF
+      !Check for "axes" attribute
+      status = NXopendata (file_id, data_name)
+      IF (status /= NX_OK) RETURN
+      status = NXUfindattr (file_id, "axes")
+      IF (status == NX_ERROR) THEN
+         RETURN
+      ELSE IF (status == NX_OK) THEN !"axes" attribute found
+         status = NXgetattr (file_id, "axes", axis_list)
+         !Strip off brackets around axis list
+         IF (index(axis_list,"[") > 0) THEN 
+            axis_list = axis_list(index(axis_list,"[")+1:len(axis_list))
+         END IF
+         IF (index(axis_list,"]") > 0) THEN
+            axis_list = axis_list(1:index(axis_list,"]")-1)
+         END IF
+         !"axes" lists the axes in C (row-major) order so the axis numbers are reversed
+         C_axis = data_rank - axis + 1 
+         !Find axis label by looking for the delimiting commas
+         j = 1
+         DO i = 1,C_axis
+            k = scan(axis_list(j:),",:") - 1
+            IF (k < 0) k = len(trim(axis_list)) - j + 1
+            IF (k < 0) THEN !We've run out of delimiters
+               CALL NXerror ("Data attribute ""axes"" is not correctly defined")
+               status = NX_ERROR
+               RETURN
+            END IF
+            name = adjustl(axis_list(j:j+k-1))
+            j = j + k + 1
+         END DO
+         !Open data to retrieve information about the dimension scale
+         status = NXopendata (file_id, name)
+         IF (status /= NX_OK) RETURN
+         status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+         IF (status == NX_OK) THEN
+            data_name = name
+            data_type = NXtype
+            data_dimensions = NXdims(1)
+            RETURN
+         ELSE
+            RETURN
+         END IF
+      END IF   
+      !Otherwise, check for "axis" attribute in each NXdata item
+      status = NXinitgroupdir (file_id)
+      IF (status /= NX_OK) RETURN
+      DO
+         status = NXgetnextentry (file_id, name, class, NXtype)
+         IF (status == NX_OK .AND. class == "SDS") THEN
+            status = NXopendata (file_id, name)
+            IF (status /= NX_OK) RETURN
+            status = NXUfindattr (file_id, "axis")
+            IF (status == NX_OK) THEN
+               status = NXgetattr (file_id, "axis", value)
+               IF (status /= NX_OK) RETURN
+               IF (value == axis) THEN
+                  status = NXUfindattr (file_id, "primary")
+                  IF (status == NX_OK) THEN
+                     status = NXgetattr (file_id, "primary", value)
+                  ELSE IF (status == NX_EOD) THEN
+                     value = 1
+                  ELSE
+                     RETURN
+                  END IF
+                  IF (value == primary) THEN
+                     status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+                     IF (status == NX_OK) THEN
+                        data_name = name
+                        data_type = NXtype
+                        data_dimensions = NXdims(1)
+                        RETURN
+                     ELSE
+                        RETURN
+                     END IF
+                  END IF
+                END IF
+             END IF
+         ELSE IF (status == NX_EOD) THEN
+            CALL NXerror ("Requested axis not found")
+            status = NX_ERROR
+            EXIT
+         ELSE IF (status == NX_ERROR) THEN
+            RETURN
+         END IF
+      END DO
+
+   END FUNCTION NXUfindaxis
+!------------------------------------------------------------------------------
+!NXUfindlink finds another link to a NeXus data item and opens the group
+   FUNCTION NXUfindlink (file_id, group_id, group_class) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      TYPE(NXlink),     INTENT(out)   :: group_id
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: group_class
+      TYPE(NXlink) :: data_id
+      INTEGER :: status
+
+      !Get current group and data IDs
+      status = NXgetgroupID (file_id, group_id)
+      IF (status /= NX_OK) RETURN
+      status = NXgetdataID (file_id, data_id)
+      IF (status /= NX_OK) RETURN
+      !Start the search in the group one level up
+      status = NXclosegroup (file_id)
+      IF (status /= NX_OK) RETURN
+      !Start recursive searches for this data ID within this group 
+      group_level = 0
+      status = NXUsearchgroup (file_id, group_id, data_id, group_class)
+
+   END FUNCTION NXUfindlink
+!------------------------------------------------------------------------------
+!NXUresumelink reopens the original group from which NXUfindlink was called
+   FUNCTION NXUresumelink (file_id, group_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(inout) :: file_id
+      TYPE(NXlink),   INTENT(in)    :: group_id
+      TYPE(NXlink) :: new_id
+      CHARACTER(len=NX_MAXNAMELEN), ALLOCATABLE :: name(:), class(:)
+      INTEGER :: status, n, i
+
+      !Return to group level from which the link search was started
+      DO i = 1, group_level
+         status = NXclosegroup (file_id)
+         IF (status /= NX_OK) RETURN
+      END DO
+      !Obtain list of groups at this level
+      status = NXgetgroupinfo (file_id, n)
+      IF (status /= NX_OK) RETURN
+      ALLOCATE (name(n), class(n), STAT=status)
+      IF (status /= 0) THEN
+         CALL NXerror ("Unable to allocate space for group info")
+         status = NX_ERROR
+         RETURN
+      END IF
+      status = NXgroupdir (file_id, n, name, class)
+      IF (status == NX_OK) THEN
+         DO i = 1,n
+            IF (class(i)(1:2) == "NX") THEN
+               status = NXopengroup (file_id, name(i), class(i))
+               IF (status /= NX_OK) EXIT
+               status = NXgetgroupID (file_id, new_id)
+               IF (status /= NX_OK) EXIT
+               IF (NXsameID (file_id, new_id, group_id)) EXIT !Original group found
+               status = NXclosegroup (file_id)
+               IF (status /= NX_OK) EXIT
+            END IF       
+            status = NX_EOD
+         END DO
+      END IF
+      !None of the groups was the correct one
+      DEALLOCATE (name, class)
+
+   END FUNCTION NXUresumelink
+!------------------------------------------------------------------------------
+!NXUsearchgroup searches a group for the required data
+   RECURSIVE FUNCTION NXUsearchgroup (file_id, group_id, data_id, &
+                        group_class) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      TYPE(NXlink),     INTENT(in)    :: group_id, data_id
+      CHARACTER(len=*), INTENT(in), OPTIONAL :: group_class
+      TYPE(NXlink) :: new_id
+      CHARACTER(len=NX_MAXNAMELEN), ALLOCATABLE :: name(:), class(:)
+      CHARACTER(len=NX_MAXNAMELEN) :: current_group, current_class
+      INTEGER :: status, n, i
+
+      !Obtain list of groups contained within this group
+      status = NXgetgroupinfo (file_id, n, current_group, current_class)
+      IF (status /= NX_OK) RETURN
+      ALLOCATE (name(n), class(n), STAT=status)
+      IF (status /= 0) THEN
+         CALL NXerror ("Unable to allocate space for group info")
+         status = NX_ERROR
+         RETURN
+      END IF      
+      status = NXgroupdir (file_id, n, name, class)
+      IF (status == NX_OK) THEN
+         DO i = 1,n
+            IF (class(i)(1:3) == "SDS") THEN
+               IF (PRESENT(group_class) .AND. &
+                        trim(group_class) /= trim(current_class)) THEN
+                  status = NX_EOD
+                  CYCLE
+               END IF
+               status = NXopendata (file_id, name(i))
+               IF (status /= NX_OK) EXIT       
+               status = NXgetdataID (file_id, new_id)
+               IF (status /= NX_OK) EXIT
+               IF (NXsameID (file_id, new_id, data_id)) THEN !Linked item found
+                  status = NX_OK
+                  EXIT
+               END IF
+            ELSE IF (class(i)(1:2) == "NX") THEN
+               status = NXopengroup (file_id, name(i), class(i))
+               IF (status /= NX_OK) EXIT
+               status = NXgetgroupID (file_id, new_id)
+               IF (status /= NX_OK) EXIT
+               !Skip this group if it's where we started
+               IF (NXsameID (file_id, new_id, group_id)) THEN
+                  status = NXclosegroup (file_id)
+                  IF (status /= NX_OK) EXIT
+                  CYCLE
+               END IF
+               group_level = group_level + 1
+               status = NXUsearchgroup(file_id, group_id, data_id, group_class)
+               IF (status == NX_OK) EXIT !The item must have been found
+               status = NXclosegroup (file_id)
+               group_level = group_level - 1
+               IF (status /= NX_OK) EXIT
+            END IF
+            status = NX_EOD
+         END DO
+      END IF
+      !Return an error status because nothing has been found in this group
+      DEALLOCATE (name, class)
+
+   END FUNCTION NXUsearchgroup
+!------------------------------------------------------------------------------
+!NXUpreparedata creates and opens a data set
+   FUNCTION NXUpreparedata (file_id, data_name, data_type, data_rank, &
+                        data_dimensions) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      INTEGER,          INTENT(in)    :: data_type, data_rank
+      INTEGER,          INTENT(in)    :: data_dimensions(:)
+      INTEGER :: status, i
+
+      status = NXUfinddata (file_id, data_name)
+      IF (status == NX_EOD) THEN       !Data item needs to be created
+         IF (NXcompress_type /= NX_COMP_NONE .AND. &
+             PRODUCT(data_dimensions(1:data_rank)) > NXcompress_size) THEN
+            status = NXmakedata (file_id, data_name, data_type, data_rank, &
+                        data_dimensions, NXcompress_type)
+         ELSE
+            status = NXmakedata (file_id, data_name, data_type, data_rank, &
+                        data_dimensions)
+         END IF
+         IF (status == NX_OK) status = NXopendata (file_id, data_name)
+      ELSE if (status == NX_OK) THEN   !Data item already exists
+         status = NXopendata (file_id, data_name)
+         IF (status /= NX_OK) RETURN
+         status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+         IF (NXtype /= data_type) THEN
+            CALL NXerror ("Type of existing data item does not match new data")
+            status = NX_ERROR
+         ELSE IF (NXrank /= data_rank) THEN
+            CALL NXerror ("Rank of existing data item does not match new data")
+            status = NX_ERROR
+         ELSE
+            DO i = 1,NXrank
+               IF (data_dimensions(i) > NXdims(i)) THEN
+                  call NXerror ("Size of new data too large for existing item")
+                  status = NX_ERROR
+                  EXIT
+               END IF
+            END DO
+         END IF
+      END IF
+      
+   END FUNCTION NXUpreparedata
+!------------------------------------------------------------------------------
+!NXUconfirmdata checks that a dataset has the expected type, rank & dimensions
+   FUNCTION NXUconfirmdata (file_id, data_name, data_type, data_rank, &
+                        data_dimensions) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout) :: file_id
+      CHARACTER(len=*), INTENT(in)    :: data_name
+      INTEGER,          INTENT(in)    :: data_type, data_rank
+      INTEGER,          INTENT(out)   :: data_dimensions(:)
+      INTEGER :: status
+
+      status = NXopendata (file_id, data_name)
+      IF (status /= NX_OK) RETURN
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      IF (NXrank == data_rank) THEN
+         !Check that the types match, or that they are both integer or real
+         IF (NXtype /= data_type .AND. (NXtype/10) /= (data_type/10)) THEN
+            CALL NXerror ("Type of data does not match supplied array")
+         ELSE
+            data_dimensions(1:NXrank) = NXdims(1:NXrank)
+            status = NX_OK
+            RETURN
+         END IF
+      ELSE
+         CALL NXerror ("Rank of data does not match supplied array")
+      END IF
+      status = NXclosedata(file_id)
+      status = NX_ERROR
+
+   END FUNCTION NXUconfirmdata
+         
+END MODULE NXUmodule
diff --git a/bindings/f90/NXmodule.f90 b/bindings/f90/NXmodule.f90
new file mode 100755
index 0000000..caa3d9e
--- /dev/null
+++ b/bindings/f90/NXmodule.f90
@@ -0,0 +1,1371 @@
+!------------------------------------------------------------------------------
+! NeXus - Neutron & X-ray Common Data Format
+!  
+! Application Program Interface (Fortran 90)
+!
+! Copyright (C) 1999-2002, Ray Osborn
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Lesser General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+! Lesser General Public License for more details.
+!
+! You should have received a copy of the GNU Lesser General Public
+! License along with this library; if not, write to the Free Software
+! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+!
+!  For further information, see <http://www.nexusformat.org>
+!
+!$Id$
+!------------------------------------------------------------------------------
+
+MODULE NXmodule
+
+   IMPLICIT NONE
+
+   PUBLIC
+! *** NeXus version parameter
+   CHARACTER(len=*), PARAMETER, PUBLIC :: NeXus_version = "2.0.1"
+! *** NeXus file access parameters
+   INTEGER, PARAMETER, PUBLIC :: NXACC_READ = 1
+   INTEGER, PARAMETER, PUBLIC :: NXACC_RDWR = 2
+   INTEGER, PARAMETER, PUBLIC :: NXACC_CREATE = 3
+   INTEGER, PARAMETER, PUBLIC :: NXACC_CREATE4 = 4
+   INTEGER, PARAMETER, PUBLIC :: NXACC_CREATE5 = 5
+! *** NeXus status parameters
+   INTEGER, PARAMETER, PUBLIC :: NX_OK = 1
+   INTEGER, PARAMETER, PUBLIC :: NX_ERROR = 0
+   INTEGER, PARAMETER, PUBLIC :: NX_EOD = -1
+! *** NeXus datatype parameters
+   INTEGER, PARAMETER, PUBLIC :: NX_CHAR    = 4
+   INTEGER, PARAMETER, PUBLIC :: NX_FLOAT32 = 5
+   INTEGER, PARAMETER, PUBLIC :: NX_FLOAT64 = 6
+   INTEGER, PARAMETER, PUBLIC :: NX_INT8    = 20
+   INTEGER, PARAMETER, PUBLIC :: NX_UINT8   = 21
+   INTEGER, PARAMETER, PUBLIC :: NX_INT16   = 22
+   INTEGER, PARAMETER, PUBLIC :: NX_UINT16  = 23
+   INTEGER, PARAMETER, PUBLIC :: NX_INT32   = 24
+   INTEGER, PARAMETER, PUBLIC :: NX_UINT32  = 25
+! *** NeXus compression parameters
+   INTEGER, PARAMETER, PUBLIC :: NX_COMP_NONE = 100
+   INTEGER, PARAMETER, PUBLIC :: NX_COMP_LZW  = 200
+   INTEGER, PARAMETER, PUBLIC :: NX_COMP_RLE  = 300
+   INTEGER, PARAMETER, PUBLIC :: NX_COMP_HUF  = 400
+! *** NeXus Unlimited parameters
+   INTEGER, PARAMETER, PUBLIC :: NX_UNLIMITED = -1
+! *** NeXus limits
+   INTEGER, PARAMETER, PUBLIC :: NX_MAXRANK = 32
+   INTEGER, PARAMETER, PUBLIC :: NX_MAXNAMELEN = 64
+   INTEGER, PARAMETER, PUBLIC :: NX_MAXSTACK = 20
+! *** Kind parameters for different byte lengths (not guaranteed to work)
+   INTEGER, PARAMETER, PUBLIC :: NXi1 = selected_int_kind(2)
+   INTEGER, PARAMETER, PUBLIC :: NXi2 = selected_int_kind(4)
+   INTEGER, PARAMETER, PUBLIC :: NXi4 = selected_int_kind(8)
+   INTEGER, PARAMETER, PUBLIC :: NXr4 = kind(1.0)
+   INTEGER, PARAMETER, PUBLIC :: NXr8 = kind(1.0D0)
+! *** NeXus type definitions
+   TYPE, PUBLIC :: NXlink
+      INTEGER(kind=NXi4) :: dummy(1040) ! at least as large as in napi.h
+   END TYPE
+   TYPE, PUBLIC :: NXhandle
+      INTEGER(kind=NXi4) :: dummy(5120) ! at least as large as in nxstack.c
+   END TYPE
+! *** Buffers for each type of parameter
+   INTEGER(KIND=NXi1), ALLOCATABLE, PRIVATE :: buffer_i1(:)
+   INTEGER(KIND=NXi2), ALLOCATABLE, PRIVATE :: buffer_i2(:)
+   INTEGER(KIND=NXi4), ALLOCATABLE, PRIVATE :: buffer_i4(:)
+   REAL(KIND=NXr4),    ALLOCATABLE, PRIVATE :: buffer_r4(:)
+   REAL(KIND=NXr8),    ALLOCATABLE, PRIVATE :: buffer_r8(:)
+   INTEGER, PRIVATE :: NXrank, NXdims(NX_MAXRANK), NXtype, NXsize
+! *** NeXus core functions ***
+   PUBLIC :: NXopen, NXclose, NXflush
+   PUBLIC :: NXmakegroup, NXopengroup, NXclosegroup
+   PUBLIC :: NXmakedata, NXopendata, NXcompress, NXclosedata
+   PUBLIC :: NXgetdata, NXgetslab, NXgetattr, NXputdata, NXputslab, NXputattr
+   PUBLIC :: NXgetinfo, NXgetnextentry, NXgetnextattr
+   PUBLIC :: NXgetgroupID, NXgetdataID, NXsameID, NXmakelink 
+   PUBLIC :: NXgetgroupinfo, NXinitgroupdir, NXgroupdir
+   PUBLIC :: NXgetattrinfo, NXinitattrdir, NXattrdir
+   PUBLIC :: NXreverse, NXCstring, NXFstring, NXdatatype, NXerror
+! *** NeXus generic interfaces ***
+   INTERFACE NXgetdata
+      MODULE PROCEDURE NXgeti1, NXgeti2, NXgeti4, NXgetr4, NXgetr8, NXgetchar
+   END INTERFACE
+   INTERFACE NXgetslab
+      MODULE PROCEDURE NXgeti1slab, NXgeti2slab, NXgeti4slab, &
+                        NXgetr4slab, NXgetr8slab
+   END INTERFACE
+   INTERFACE NXgetattr
+      MODULE PROCEDURE NXgeti1attr, NXgeti2attr, NXgeti4attr, NXgetr4attr, &
+                        NXgetr8attr, NXgetcharattr
+   END INTERFACE
+   INTERFACE NXputdata
+      MODULE PROCEDURE NXputi1, NXputi2, NXputi4, NXputr4, NXputr8, NXputchar
+   END INTERFACE
+   INTERFACE NXputslab
+      MODULE PROCEDURE NXputi1slab, NXputi2slab, NXputi4slab, &
+                        NXputr4slab, NXputr8slab
+   END INTERFACE
+   INTERFACE NXputattr
+      MODULE PROCEDURE NXputi1attr, NXputi2attr, NXputi4attr,  &
+                        NXputr4attr, NXputr8attr, NXputcharattr
+   END INTERFACE
+
+CONTAINS
+!------------------------------------------------------------------------------
+!NXopen opens a NeXus file and returns a file ID 
+   FUNCTION NXopen (file_name, access_method, file_id) RESULT (status)
+
+      CHARACTER(len=*), INTENT(in)  :: file_name
+      INTEGER,          INTENT(in)  :: access_method
+      TYPE(NXhandle),   INTENT(out) :: file_id
+      INTEGER :: status, nxifopen
+      EXTERNAL nxifopen
+
+      status = nxifopen (NXCstring(file_name), access_method, file_id)
+
+   END FUNCTION NXopen
+!------------------------------------------------------------------------------
+!NXclose closes a NeXus file defined by its file ID
+   FUNCTION NXclose (file_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(in) :: file_id
+      INTEGER :: status, nxifclose
+      EXTERNAL nxifclose
+
+      status = nxifclose (file_id)
+
+   END FUNCTION NXclose
+!------------------------------------------------------------------------------
+!NXflush flushes all pending data to disk
+   FUNCTION NXflush (file_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(inout) :: file_id
+      INTEGER :: status, nxifflush
+      EXTERNAL nxifflush
+
+      status = nxifflush (file_id)
+
+   END FUNCTION NXflush
+!------------------------------------------------------------------------------
+!NXmakegroup creates a NeXus group
+   FUNCTION NXmakegroup (file_id, group_name, group_class) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      CHARACTER(len=*), INTENT(in) :: group_name, group_class
+      INTEGER :: status, nximakegroup
+      EXTERNAL nximakegroup
+
+      status = nximakegroup(file_id, NXCstring(group_name), &
+                        NXCstring(group_class))
+
+   END FUNCTION NXmakegroup
+!------------------------------------------------------------------------------
+!NXopengroup opens an existing NeXus group for input/output
+   FUNCTION NXopengroup (file_id, group_name, group_class) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      CHARACTER(len=*), INTENT(in) :: group_name, group_class
+      INTEGER :: status, nxiopengroup
+      EXTERNAL nxiopengroup
+
+      status = nxiopengroup(file_id, NXCstring(group_name), &
+                        NXCstring(group_class))
+
+   END FUNCTION NXopengroup
+!------------------------------------------------------------------------------
+!NXclosegroup closes a NeXus group
+   FUNCTION NXclosegroup (file_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(in) :: file_id
+      INTEGER :: status, nxiclosegroup
+      EXTERNAL nxiclosegroup
+
+      status = nxiclosegroup(file_id)
+
+   END FUNCTION NXclosegroup
+!------------------------------------------------------------------------------
+!NXmakedata creates a NeXus data set (optionally with compression)
+   FUNCTION NXmakedata (file_id, data_name, data_type, data_rank, &
+                        data_dimensions, compress_type, chunk_size) &
+                        RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      CHARACTER(len=*), INTENT(in) :: data_name
+      INTEGER,          INTENT(in) :: data_type,data_rank,data_dimensions(:)
+      INTEGER, OPTIONAL,INTENT(in) :: compress_type, chunk_size(:)
+      INTEGER, ALLOCATABLE :: NXchunk_size(:)
+      INTEGER :: status, i, nxifmakedata, nxifcompmakedata
+      EXTERNAL nxifmakedata, nxifcompmakedata
+
+      IF (PRESENT(compress_type)) THEN
+         IF (PRESENT(chunk_size)) THEN
+            ALLOCATE (NXchunk_size(data_rank))
+            NXchunk_size = chunk_size
+         ELSE
+            ALLOCATE (NXchunk_size(data_rank))
+            NXchunk_size = (/(data_dimensions(i),i=1,data_rank)/)
+         END IF
+         status = nxifcompmakedata(file_id, NXCstring(data_name), data_type, &
+                        data_rank, data_dimensions, compress_type, NXchunk_size)
+         DEALLOCATE (NXchunk_size)
+      ELSE
+         status = nxifmakedata(file_id, NXCstring(data_name), data_type, &
+                        data_rank, data_dimensions)
+      END IF
+
+   END FUNCTION NXmakedata
+!------------------------------------------------------------------------------
+!NXopendata opens an existing NeXus data set for input/output
+   FUNCTION NXopendata (file_id, data_name) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      CHARACTER(len=*), INTENT(in) :: data_name
+      INTEGER :: status, nxiopendata
+      EXTERNAL nxiopendata
+
+      status = nxiopendata(file_id, NXCstring(data_name))
+
+   END FUNCTION NXopendata
+!------------------------------------------------------------------------------
+!NXcompress sets the compression algorithm for the open NeXus data set
+   FUNCTION NXcompress (file_id, compress_type) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      INTEGER,          INTENT(in) :: compress_type
+      INTEGER :: status, nxifcompress
+      EXTERNAL nxifcompress
+
+      status = nxifcompress(file_id, compress_type)
+
+   END FUNCTION NXcompress
+!------------------------------------------------------------------------------
+!NXclosedata closes a NeXus data set
+   FUNCTION NXclosedata (file_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(in) :: file_id
+      INTEGER :: status, nxiclosedata
+      EXTERNAL nxiclosedata
+
+      status = nxiclosedata(file_id)
+
+   END FUNCTION NXclosedata
+!------------------------------------------------------------------------------
+!NXgetdata reads data from the open data set
+!
+!The following routines define the generic function NXgetdata
+!------------------------------------------------------------------------------
+!NXgeti1 reads an integer*1 array from the open data set
+   FUNCTION NXgeti1 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)  :: file_id
+      INTEGER(KIND=NXi1), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetdata
+      EXTERNAL nxigetdata
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(NXdims(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_INT8 .OR. NXtype == NX_UINT8) THEN
+         ALLOCATE (buffer_i1(NXsize))
+         status = nxigetdata(file_id, buffer_i1)
+         data = buffer_i1
+         DEALLOCATE (buffer_i1)
+      ELSE IF (NXtype == NX_INT16 .OR. NXtype == NX_UINT16) THEN
+         ALLOCATE (buffer_i2(NXsize))
+         status = nxigetdata(file_id, buffer_i2)
+         IF (abs(maxval(buffer_i2)) <= HUGE(data)) THEN
+            data = buffer_i2
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_i2)
+      ELSE IF (NXtype == NX_INT32 .OR. NXtype == NX_UINT32) THEN
+         ALLOCATE (buffer_i4(NXsize))
+         status = nxigetdata(file_id, buffer_i4)
+         IF (abs(maxval(buffer_i4)) <= HUGE(data)) THEN
+            data = buffer_i4
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_i4)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgeti1
+!------------------------------------------------------------------------------
+!NXgeti2 reads an integer*2 array from the open data set
+   FUNCTION NXgeti2 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)  :: file_id
+      INTEGER(KIND=NXi2), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetdata
+      EXTERNAL nxigetdata
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(NXdims(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_INT8 .OR. NXtype == NX_UINT8) THEN
+         ALLOCATE (buffer_i1(NXsize))
+         status = nxigetdata(file_id, buffer_i1)
+         data = buffer_i1
+         DEALLOCATE (buffer_i1)
+      ELSE IF (NXtype == NX_INT16 .OR. NXtype == NX_UINT16) THEN
+         ALLOCATE (buffer_i2(NXsize))
+         status = nxigetdata(file_id, buffer_i2)
+         data = buffer_i2
+         DEALLOCATE (buffer_i2)
+      ELSE IF (NXtype == NX_INT32 .OR. NXtype == NX_UINT32) THEN
+         ALLOCATE (buffer_i4(NXsize))
+         status = nxigetdata(file_id, buffer_i4)
+         IF (abs(maxval(buffer_i4)) <= HUGE(data)) THEN
+            data = buffer_i4
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_i4)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgeti2
+!------------------------------------------------------------------------------
+!NXgeti4 reads an integer*4 array from the open data set
+   FUNCTION NXgeti4 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)  :: file_id
+      INTEGER(KIND=NXi4), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetdata
+      EXTERNAL nxigetdata
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(NXdims(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_INT8 .OR. NXtype == NX_UINT8) THEN
+         ALLOCATE (buffer_i1(NXsize))
+         status = nxigetdata(file_id, buffer_i1)
+         data = buffer_i1
+         DEALLOCATE (buffer_i1)
+      ELSE IF (NXtype == NX_INT16 .OR. NXtype == NX_UINT16) THEN
+         ALLOCATE (buffer_i2(NXsize))
+         status = nxigetdata(file_id, buffer_i2)
+         data = buffer_i2
+         DEALLOCATE (buffer_i2)
+      ELSE IF (NXtype == NX_INT32 .OR. NXtype == NX_UINT32) THEN
+         ALLOCATE (buffer_i4(NXsize))
+         status = nxigetdata(file_id, buffer_i4)
+         data = buffer_i4
+         DEALLOCATE (buffer_i4)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgeti4
+!------------------------------------------------------------------------------
+!NXgetr4 reads a real*4 array from the open data set
+   FUNCTION NXgetr4 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in)  :: file_id
+      REAL(KIND=NXr4), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetdata
+      EXTERNAL nxigetdata
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(NXdims(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_FLOAT32) THEN
+         ALLOCATE (buffer_r4(NXsize))
+         status = nxigetdata(file_id, buffer_r4)
+         data = buffer_r4
+         DEALLOCATE (buffer_r4)
+      ELSE IF (NXtype == NX_FLOAT64) THEN
+         ALLOCATE (buffer_r8(NXsize))
+         status = nxigetdata(file_id, buffer_r8)
+         data = buffer_r8
+         DEALLOCATE (buffer_r8)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgetr4
+!------------------------------------------------------------------------------
+!NXgetr8 reads a real*8 array from the open data set
+   FUNCTION NXgetr8 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in)  :: file_id
+      REAL(KIND=NXr8), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetdata
+      EXTERNAL nxigetdata
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(NXdims(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_FLOAT32) THEN
+         ALLOCATE (buffer_r4(NXsize))
+         status = nxigetdata(file_id, buffer_r4)
+         data = buffer_r4
+         DEALLOCATE (buffer_r4)
+      ELSE IF (NXtype == NX_FLOAT64) THEN
+         ALLOCATE (buffer_r8(NXsize))
+         status = nxigetdata(file_id, buffer_r8)
+         IF (abs(maxval(buffer_r8)) <= HUGE(data)) THEN
+            data = buffer_r8
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_r8)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgetr8
+!------------------------------------------------------------------------------
+!NXgetchar reads a character string from the open data set
+   FUNCTION NXgetchar (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in)  :: file_id
+      CHARACTER(len=*), INTENT(out) :: data
+      INTEGER :: status, nxigetdata
+      INTEGER(kind=NXi1) :: Cstring(255)
+      EXTERNAL nxigetdata
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(NXdims(1:NXrank))
+      IF (NXsize > len(data)) THEN
+         CALL NXerror ("The supplied string is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_CHAR) THEN
+         Cstring = 0 !HDF does not add null termination so ensure it's there
+         status = nxigetdata(file_id, Cstring)
+         IF (status == NX_OK) data = trim(NXFstring(Cstring))
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgetchar
+!------------------------------------------------------------------------------
+!NXgetslab reads a slab of the open data set
+!
+!The following routines define the generic function NXgetslab
+!------------------------------------------------------------------------------
+!NXgeti1slab reads a slab of integer*1 data from the open data set 
+   FUNCTION NXgeti1slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)  :: file_id
+      INTEGER,            INTENT(in)  :: data_start(:), data_size(:)
+      INTEGER(KIND=NXi1), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetslab
+      EXTERNAL nxigetslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(data_size(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_INT8 .OR. NXtype == NX_UINT8) THEN
+         ALLOCATE (buffer_i1(NXsize))
+         status = nxigetslab(file_id, buffer_i1, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_i1
+         DEALLOCATE (buffer_i1)
+      ELSE IF (NXtype == NX_INT16 .OR. NXtype == NX_UINT16) THEN
+         ALLOCATE (buffer_i2(NXsize))
+         status = nxigetslab(file_id, buffer_i2, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         IF (abs(maxval(buffer_i2)) <= HUGE(data)) THEN
+            data = buffer_i2
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_i2)
+      ELSE IF (NXtype == NX_INT32 .OR. NXtype == NX_UINT32) THEN
+         ALLOCATE (buffer_i4(NXsize))
+         status = nxigetslab(file_id, buffer_i4, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         IF (abs(maxval(buffer_i4)) <= HUGE(data)) THEN
+            data = buffer_i4
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_i4)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgeti1slab
+!------------------------------------------------------------------------------
+!NXgeti2slab reads a slab of integer*2 data from the open data set 
+   FUNCTION NXgeti2slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)  :: file_id
+      INTEGER,            INTENT(in)  :: data_start(:), data_size(:)
+      INTEGER(KIND=NXi2), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetslab
+      EXTERNAL nxigetslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(data_size(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_INT8 .OR. NXtype == NX_UINT8) THEN
+         ALLOCATE (buffer_i1(NXsize))
+         status = nxigetslab(file_id, buffer_i1, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_i1
+         DEALLOCATE (buffer_i1)
+      ELSE IF (NXtype == NX_INT16 .OR. NXtype == NX_UINT16) THEN
+         ALLOCATE (buffer_i2(NXsize))
+         status = nxigetslab(file_id, buffer_i2, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_i2
+         DEALLOCATE (buffer_i2)
+      ELSE IF (NXtype == NX_INT32 .OR. NXtype == NX_UINT32) THEN
+         ALLOCATE (buffer_i4(NXsize))
+         status = nxigetslab(file_id, buffer_i4, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         IF (abs(maxval(buffer_i4)) <= HUGE(data)) THEN
+            data = buffer_i4
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_i4)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgeti2slab
+!------------------------------------------------------------------------------
+!NXgeti4slab reads a slab of integer*4 data from the open data set 
+   FUNCTION NXgeti4slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)  :: file_id
+      INTEGER,            INTENT(in)  :: data_start(:), data_size(:)
+      INTEGER(KIND=NXi4), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetslab
+      EXTERNAL nxigetslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(data_size(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_INT8 .OR. NXtype == NX_UINT8) THEN
+         ALLOCATE (buffer_i1(NXsize))
+         status = nxigetslab(file_id, buffer_i1, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_i1
+         DEALLOCATE (buffer_i1)
+      ELSE IF (NXtype == NX_INT16 .OR. NXtype == NX_UINT16) THEN
+         ALLOCATE (buffer_i2(NXsize))
+         status = nxigetslab(file_id, buffer_i2, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_i2
+         DEALLOCATE (buffer_i2)
+      ELSE IF (NXtype == NX_INT32 .OR. NXtype == NX_UINT32) THEN
+         ALLOCATE (buffer_i4(NXsize))
+         status = nxigetslab(file_id, buffer_i4, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_i4
+         DEALLOCATE (buffer_i4)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgeti4slab
+!------------------------------------------------------------------------------
+!NXgetr4slab reads a slab of real*4 data from the open data set 
+   FUNCTION NXgetr4slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in)  :: file_id
+      INTEGER,         INTENT(in)  :: data_start(:), data_size(:)
+      REAL(KIND=NXr4), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetslab
+      EXTERNAL nxigetslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(data_size(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_FLOAT32) THEN
+         ALLOCATE (buffer_r4(NXsize))
+         status = nxigetslab(file_id, buffer_r4, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         data = buffer_r4
+         DEALLOCATE (buffer_r4)
+      ELSE IF (NXtype == NX_FLOAT64) THEN
+         ALLOCATE (buffer_r8(NXsize))
+         status = nxigetslab(file_id, buffer_r8, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+         IF (abs(maxval(buffer_r8)) <= HUGE(data)) THEN
+            data = buffer_r8
+         ELSE
+            CALL NXerror ("Input values too large for data type")
+            status = NX_ERROR
+         END IF
+         DEALLOCATE (buffer_r8)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgetr4slab
+!------------------------------------------------------------------------------
+!NXgetr8slab reads a slab of real*8 data from the open data set 
+   FUNCTION NXgetr8slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in)  :: file_id
+      INTEGER,         INTENT(in)  :: data_start(:), data_size(:)
+      REAL(KIND=NXr8), INTENT(out) :: data(:)
+      INTEGER :: status, nxigetslab
+      EXTERNAL nxigetslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      IF (status /= NX_OK) RETURN
+      NXsize = PRODUCT(data_size(1:NXrank))
+      IF (NXsize > size(data)) THEN
+         CALL NXerror ("The supplied array is not large enough for the data")
+         status = NX_ERROR
+      ELSE IF (NXtype == NX_FLOAT32) THEN
+         ALLOCATE (buffer_r4(NXsize))
+         status = nxigetslab(file_id, buffer_r4, &
+                   NXreverse(NXrank,data_start), NXreverse(NXrank,data_size))
+         data = buffer_r4
+         DEALLOCATE (buffer_r4)
+      ELSE IF (NXtype == NX_FLOAT64) THEN
+         ALLOCATE (buffer_r8(NXsize))
+         status = nxigetslab(file_id, buffer_r8, &
+                   NXreverse(NXrank,data_start), NXreverse(NXrank,data_size))
+         data = buffer_r8
+         DEALLOCATE (buffer_r8)
+      ELSE
+         call NXerror &
+              ("The datatype is incompatible with the supplied variable")
+         status = NX_ERROR
+      END IF
+
+   END FUNCTION NXgetr8slab
+!------------------------------------------------------------------------------
+!NXgetattr reads attributes from the open data set 
+!
+!The following routines define the generic function NXgetattr
+!------------------------------------------------------------------------------
+!NXgeti1attr reads an integer*1 attribute from the open data set 
+   FUNCTION NXgeti1attr (file_id, attr_name, value, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)    :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: attr_name
+      INTEGER(KIND=NXi1), INTENT(out)   :: value
+      INTEGER, OPTIONAL,  INTENT(inout) :: attr_length
+      INTEGER, OPTIONAL,  INTENT(in)    :: attr_type
+      INTEGER :: status, nxigetattr, value_length, value_type
+      EXTERNAL nxigetattr
+
+      value_length = 1; value_type = NX_INT8
+      status = nxigetattr(file_id, NXCstring(attr_name), value, value_length, &
+                        value_type)
+
+   END FUNCTION NXgeti1attr
+!------------------------------------------------------------------------------
+!NXgeti2attr reads an integer*2 attribute from the open data set 
+   FUNCTION NXgeti2attr (file_id, attr_name, value, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)    :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: attr_name
+      INTEGER(KIND=NXi2), INTENT(out)   :: value
+      INTEGER, OPTIONAL,  INTENT(inout) :: attr_length
+      INTEGER, OPTIONAL,  INTENT(in)    :: attr_type
+      INTEGER :: status, nxigetattr, value_length, value_type
+      EXTERNAL nxigetattr
+
+      value_length = 1; value_type = NX_INT16
+      status = nxigetattr(file_id, NXCstring(attr_name), value, value_length, &
+                        value_type)
+
+   END FUNCTION NXgeti2attr
+!------------------------------------------------------------------------------
+!NXgeti4attr reads an integer*4 attribute from the open data set 
+   FUNCTION NXgeti4attr (file_id, attr_name, value, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)    :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: attr_name
+      INTEGER(KIND=NXi4), INTENT(out)   :: value
+      INTEGER, OPTIONAL,  INTENT(inout) :: attr_length
+      INTEGER, OPTIONAL,  INTENT(in)    :: attr_type
+      INTEGER :: status, nxigetattr, value_length, value_type
+      EXTERNAL nxigetattr
+
+      value_length = 1; value_type = NX_INT32
+      status = nxigetattr(file_id, NXCstring(attr_name), value, value_length, &
+                        value_type)
+
+   END FUNCTION NXgeti4attr
+!------------------------------------------------------------------------------
+!NXgetr4attr reads a real*4 attribute from the open data set 
+   FUNCTION NXgetr4attr (file_id, attr_name, value, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)    :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: attr_name
+      REAL(KIND=NXr4),    INTENT(out)   :: value
+      INTEGER, OPTIONAL,  INTENT(inout) :: attr_length
+      INTEGER, OPTIONAL,  INTENT(in)    :: attr_type
+      INTEGER :: status, nxigetattr, value_length, value_type
+      EXTERNAL nxigetattr
+
+      value_length = 1; value_type = NX_FLOAT32
+      status = nxigetattr(file_id, NXCstring(attr_name), value, value_length, &
+                        value_type)
+
+   END FUNCTION NXgetr4attr
+!------------------------------------------------------------------------------
+!NXgetr8attr reads a real*8 attribute from the open data set 
+   FUNCTION NXgetr8attr (file_id, attr_name, value, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)    :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: attr_name
+      REAL(KIND=NXr8),    INTENT(out)   :: value
+      INTEGER, OPTIONAL,  INTENT(inout) :: attr_length
+      INTEGER, OPTIONAL,  INTENT(in)    :: attr_type
+      INTEGER :: status, nxigetattr, value_length, value_type
+      EXTERNAL nxigetattr
+
+      value_length = 1; value_type = NX_FLOAT64
+      status = nxigetattr(file_id, NXCstring(attr_name), value, value_length, &
+                        value_type)
+
+   END FUNCTION NXgetr8attr
+!------------------------------------------------------------------------------
+!NXgetcharattr reads a character attribute from the open data set 
+   FUNCTION NXgetcharattr (file_id, attr_name, value, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in)    :: file_id
+      CHARACTER(len=*),   INTENT(in)    :: attr_name
+      CHARACTER(len=*),   INTENT(out)   :: value
+      INTEGER, OPTIONAL,  INTENT(inout) :: attr_length
+      INTEGER, OPTIONAL,  INTENT(in)    :: attr_type
+      INTEGER :: status, nxigetattr, value_length, value_type
+      INTEGER(kind=NXi1) :: Cstring(255)
+      EXTERNAL nxigetattr
+
+      value_length = len(value); value_type = NX_CHAR
+      Cstring = 0
+      status = nxigetattr(file_id, NXCstring(attr_name), Cstring, &
+                        value_length, value_type)
+      value = trim(NXFstring(Cstring))
+
+   END FUNCTION NXgetcharattr
+!------------------------------------------------------------------------------
+!NXputdata writes data into the open data set
+!
+!The following routines define the generic function NXputdata
+!------------------------------------------------------------------------------
+!NXputi1 writes an integer*1 array to the open data set
+   FUNCTION NXputi1 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      INTEGER(KIND=NXi1), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputdata
+      EXTERNAL nxiputdata
+
+      status = nxiputdata(file_id, data)
+
+   END FUNCTION NXputi1
+!------------------------------------------------------------------------------
+!NXputi2 writes an integer*2 array to the open data set
+   FUNCTION NXputi2 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      INTEGER(KIND=NXi2), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputdata
+      EXTERNAL nxiputdata
+
+      status = nxiputdata(file_id, data)
+
+   END FUNCTION NXputi2
+!------------------------------------------------------------------------------
+!NXputi1 writes an integer*4 array to the open data set
+   FUNCTION NXputi4 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      INTEGER(KIND=NXi4), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputdata
+      EXTERNAL nxiputdata
+
+      status = nxiputdata(file_id, data)
+
+   END FUNCTION NXputi4
+!------------------------------------------------------------------------------
+!NXputreal writes a real*4 array to the open data set
+   FUNCTION NXputr4 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in) :: file_id
+      REAL(KIND=NXr4), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputdata
+      EXTERNAL nxiputdata
+
+      status = nxiputdata(file_id, data)
+
+   END FUNCTION NXputr4
+!------------------------------------------------------------------------------
+!NXputr8 writes a real*8 array to the open data set
+   FUNCTION NXputr8 (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in) :: file_id
+      REAL(KIND=NXr8), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputdata
+      EXTERNAL nxiputdata
+
+      status = nxiputdata(file_id, data)
+
+   END FUNCTION NXputr8
+!------------------------------------------------------------------------------
+!NXputchar writes a character string to the open data set
+   FUNCTION NXputchar (file_id, data) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in) :: file_id
+      CHARACTER(len=*), INTENT(in) :: data
+      INTEGER :: status, nxiputdata
+      EXTERNAL nxiputdata
+
+      status = nxiputdata(file_id, NXCstring(data))
+
+   END FUNCTION NXputchar
+!------------------------------------------------------------------------------
+!NXputslab writes a slab of data into the open data set
+!
+!The following routines define the generic function NXputslab
+!------------------------------------------------------------------------------
+!NXputi1slab writes a slab of integer*1 data into the open data set 
+   FUNCTION NXputi1slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      INTEGER,            INTENT(in) :: data_start(:), data_size(:)
+      INTEGER(KIND=NXi1), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputslab
+      EXTERNAL nxiputslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      status = nxiputslab(file_id, data, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+
+   END FUNCTION NXputi1slab
+!------------------------------------------------------------------------------
+!NXputi2slab writes a slab of integer*2 data into the open data set 
+   FUNCTION NXputi2slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      INTEGER,            INTENT(in) :: data_start(:), data_size(:)
+      INTEGER(KIND=NXi2), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputslab
+      EXTERNAL nxiputslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      status = nxiputslab(file_id, data, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+
+   END FUNCTION NXputi2slab
+!------------------------------------------------------------------------------
+!NXputi4slab writes a slab of integer*4 data into the open data set 
+   FUNCTION NXputi4slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      INTEGER,            INTENT(in) :: data_start(:), data_size(:)
+      INTEGER(KIND=NXi4), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputslab
+      EXTERNAL nxiputslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      status = nxiputslab(file_id, data, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+
+   END FUNCTION NXputi4slab
+!------------------------------------------------------------------------------
+!NXputr4slab writes a slab of real*4 data into the open data set 
+   FUNCTION NXputr4slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in) :: file_id
+      INTEGER,         INTENT(in) :: data_start(:), data_size(:)
+      REAL(KIND=NXr4), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputslab
+      EXTERNAL nxiputslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      status = nxiputslab(file_id, data, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+
+   END FUNCTION NXputr4slab
+!------------------------------------------------------------------------------
+!NXputr8slab writes a slab of real*8 data into the open data set 
+   FUNCTION NXputr8slab (file_id, data, data_start, data_size) RESULT (status)
+
+      TYPE(NXhandle),  INTENT(in) :: file_id
+      INTEGER,         INTENT(in) :: data_start(:), data_size(:)
+      REAL(KIND=NXr8), INTENT(in) :: data(:)
+      INTEGER :: status, nxiputslab
+      EXTERNAL nxiputslab
+
+      status = NXgetinfo (file_id, NXrank, NXdims, NXtype)
+      status = nxiputslab(file_id, data, &
+                   NXreverse(NXrank,data_start)-1, NXreverse(NXrank,data_size))
+
+   END FUNCTION NXputr8slab
+!------------------------------------------------------------------------------
+!NXputattr writes an attribute of the open data set
+!
+!The following routines define the generic function NXputdata
+!------------------------------------------------------------------------------
+!NXputi1attr writes an integer*1 attribute of the open data set 
+   FUNCTION NXputi1attr (file_id, name, value, value_length, value_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      CHARACTER(len=*),   INTENT(in) :: name
+      INTEGER(KIND=NXi1), INTENT(in) :: value
+      INTEGER, OPTIONAL,  INTENT(in) :: value_length
+      INTEGER, OPTIONAL,  INTENT(in) :: value_type
+      INTEGER :: status, nxifputattr
+      EXTERNAL nxifputattr
+
+      status = nxifputattr(file_id, NXCstring(name), value, 1, NX_INT8)
+
+   END FUNCTION NXputi1attr
+!------------------------------------------------------------------------------
+!NXputi2attr writes an integer*2 attribute of the open data set 
+   FUNCTION NXputi2attr (file_id, name, value, value_length, value_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      CHARACTER(len=*),   INTENT(in) :: name
+      INTEGER(KIND=NXi2), INTENT(in) :: value
+      INTEGER, OPTIONAL,  INTENT(in) :: value_length
+      INTEGER, OPTIONAL,  INTENT(in) :: value_type
+      INTEGER :: status, nxifputattr
+      EXTERNAL nxifputattr
+
+      status = nxifputattr(file_id, NXCstring(name), value, 1, NX_INT16)
+
+   END FUNCTION NXputi2attr
+!------------------------------------------------------------------------------
+!NXputi4attr writes an integer*4 attribute of the open data set 
+   FUNCTION NXputi4attr (file_id, name, value, value_length, value_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      CHARACTER(len=*),   INTENT(in) :: name
+      INTEGER(KIND=NXi4), INTENT(in) :: value
+      INTEGER, OPTIONAL,  INTENT(in) :: value_length
+      INTEGER, OPTIONAL,  INTENT(in) :: value_type
+      INTEGER :: status, nxifputattr
+      EXTERNAL nxifputattr
+
+      status = nxifputattr(file_id, NXCstring(name), value, 1, NX_INT32)
+
+   END FUNCTION NXputi4attr
+!------------------------------------------------------------------------------
+!NXputr4attr writes a real*4 attribute of the open data set 
+   FUNCTION NXputr4attr (file_id, name, value, value_length, value_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      CHARACTER(len=*),   INTENT(in) :: name
+      REAL(KIND=NXr4),    INTENT(in) :: value
+      INTEGER, OPTIONAL,  INTENT(in) :: value_length
+      INTEGER, OPTIONAL,  INTENT(in) :: value_type
+      INTEGER :: status, nxifputattr
+      EXTERNAL nxifputattr
+
+      status = nxifputattr(file_id, NXCstring(name), value, 1, NX_FLOAT32)
+
+   END FUNCTION NXputr4attr
+!------------------------------------------------------------------------------
+!NXputr8attr writes a real*8 attribute of the open data set 
+   FUNCTION NXputr8attr (file_id, name, value, value_length, value_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      CHARACTER(len=*),   INTENT(in) :: name
+      REAL(KIND=NXr8),    INTENT(in) :: value
+      INTEGER, OPTIONAL,  INTENT(in) :: value_length
+      INTEGER, OPTIONAL,  INTENT(in) :: value_type
+      INTEGER :: status, nxifputattr
+      EXTERNAL nxifputattr
+
+      status = nxifputattr(file_id, NXCstring(name), value, 1, NX_FLOAT64)
+
+   END FUNCTION NXputr8attr
+!------------------------------------------------------------------------------
+!NXputcharattr writes character attribute of the open data set 
+   FUNCTION NXputcharattr (file_id, name, value, value_length, value_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),     INTENT(in) :: file_id
+      CHARACTER(len=*),   INTENT(in) :: name
+      CHARACTER(len=*),   INTENT(in) :: value
+      INTEGER, OPTIONAL,  INTENT(in) :: value_length
+      INTEGER, OPTIONAL,  INTENT(in) :: value_type
+      INTEGER :: status, nxifputattr
+      EXTERNAL nxifputattr
+
+      status = nxifputattr(file_id, NXCstring(name), NXCstring(value), &
+                        len_trim(value), NX_CHAR)
+
+   END FUNCTION NXputcharattr
+!------------------------------------------------------------------------------
+!------------------------------------------------------------------------------
+!NXgetinfo gets the rank, dimensions and type of the open data set
+   FUNCTION NXgetinfo (file_id, data_rank, data_dimensions, data_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle), INTENT(in)  :: file_id
+      INTEGER,        INTENT(out) :: data_rank, data_dimensions(:), data_type
+      INTEGER :: status, nxigetinfo, i, j, dimensions(size(data_dimensions))
+      EXTERNAL nxigetinfo
+
+      status = nxigetinfo(file_id, data_rank, dimensions, data_type)
+      IF (status == NX_OK) THEN
+         data_dimensions = NXreverse (data_rank, dimensions)
+      END IF
+
+   END FUNCTION NXgetinfo
+!------------------------------------------------------------------------------
+!NXgetnextentry implements a directory search of the open group
+   FUNCTION NXgetnextentry (file_id, name, class, data_type) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in)  :: file_id
+      CHARACTER(len=*), INTENT(out) :: name, class
+      INTEGER,          INTENT(out) :: data_type
+      INTEGER :: status, nxigetnextentry, i, j
+      INTEGER(kind=NXi1) :: Cname(NX_MAXNAMELEN), Cclass(NX_MAXNAMELEN)
+      EXTERNAL nxigetnextentry
+
+      status = nxigetnextentry(file_id, Cname, Cclass, data_type)
+      name = trim(NXFstring(Cname))
+      class = trim(NXFstring(Cclass))
+
+   END FUNCTION NXgetnextentry
+!------------------------------------------------------------------------------
+!NXgetnextattr implements a search of all the attributes of the open data set
+   FUNCTION NXgetnextattr (file_id, attr_name, attr_length, attr_type) &
+                        RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in)  :: file_id
+      CHARACTER(len=*), INTENT(out) :: attr_name
+      INTEGER,          INTENT(out) :: attr_length, attr_type
+      INTEGER :: status, nxigetnextattr
+      INTEGER(kind=NXi1) :: Cstring(NX_MAXNAMELEN)
+      EXTERNAL nxigetnextattr
+
+      status = nxigetnextattr(file_id, Cstring, attr_length, attr_type)
+      attr_name = trim(NXFstring(Cstring))
+
+   END FUNCTION NXgetnextattr
+!------------------------------------------------------------------------------
+!NXgetgroupID returns the identifier of the open group as an NXlink structure
+   FUNCTION NXgetgroupID (file_id, group_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(in)  :: file_id
+      TYPE(NXlink),   INTENT(out) :: group_id
+      TYPE(NXlink) :: current_id
+      INTEGER :: status, nxigetgroupid
+      EXTERNAL nxigetgroupid
+
+      status = nxigetgroupid(file_id, current_id)
+      group_id = current_id
+
+   END FUNCTION NXgetgroupID
+!------------------------------------------------------------------------------
+!NXgetdataID returns the identifier of the open data set as an NXlink structure
+   FUNCTION NXgetdataID (file_id, data_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(in)  :: file_id
+      TYPE(NXlink),   INTENT(out) :: data_id
+      TYPE(NXlink) :: current_id
+      INTEGER :: status, nxigetdataid
+      EXTERNAL nxigetdataid
+
+      status = nxigetdataid(file_id, current_id)
+      data_id = current_id
+
+   END FUNCTION NXgetdataID
+!------------------------------------------------------------------------------
+!NXsameID checks that two group or data ID's are the same
+   FUNCTION NXsameID (file_id, first_id, second_id) RESULT (same)
+
+      TYPE(NXhandle), INTENT(in) :: file_id
+      TYPE(NXlink), INTENT(in)   :: first_id, second_id
+      LOGICAL :: same
+      INTEGER :: status, nxisameid
+      EXTERNAL nxisameid
+
+      status = nxisameid(file_id, first_id, second_id)
+      IF (status == NX_OK) THEN
+         same = .TRUE.
+      ELSE
+         same = .FALSE.
+      ENDIF
+
+   END FUNCTION NXsameID
+!------------------------------------------------------------------------------
+!NXmakelink links a data item (group or set) to another group 
+   FUNCTION NXmakelink (file_id, link) RESULT (status)
+
+      TYPE(NXhandle), INTENT(in) :: file_id
+      TYPE(NXlink),   INTENT(in) :: link
+      INTEGER :: status, nximakelink
+      EXTERNAL nximakelink
+
+      status = nximakelink(file_id, link)
+
+   END FUNCTION NXmakelink
+!------------------------------------------------------------------------------
+!NXgetgroupinfo returns the number of entries, name and class of the open group
+   FUNCTION NXgetgroupinfo (file_id, item_number, group_name, group_class) &
+                        RESULT (status)
+
+      TYPE(NXhandle),   INTENT(in)  :: file_id
+      INTEGER,          INTENT(out) :: item_number
+      CHARACTER(len=*), INTENT(out), OPTIONAL :: group_name, group_class
+      TYPE(NXlink) :: group_id, new_id
+      INTEGER :: status, nxigetgroupinfo
+      INTEGER(kind=NXi1) :: Cname(NX_MAXNAMELEN), Cclass(NX_MAXNAMELEN)
+      EXTERNAL nxigetgroupinfo
+
+      status = nxigetgroupinfo (file_id, item_number, Cname, Cclass)
+      IF (PRESENT(group_name)) group_name = trim(NXFstring(Cname))
+      IF (PRESENT(group_class)) group_class = trim(NXFstring(Cclass))
+
+   END FUNCTION NXgetgroupinfo
+!------------------------------------------------------------------------------
+!NXinitgroupdir initializes data searches using NXgetnextentry
+   FUNCTION NXinitgroupdir (file_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(inout) :: file_id
+      INTEGER :: status, nxiinitgroupdir
+      EXTERNAL nxiinitgroupdir
+
+      status = nxiinitgroupdir (file_id)
+
+  END FUNCTION NXinitgroupdir
+!------------------------------------------------------------------------------
+!NXgroupdir returns a list of items in the currently open group
+   FUNCTION NXgroupdir (file_id, item_number, item_name, item_class) &
+                        RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout)  :: file_id
+      INTEGER,          INTENT(out)    :: item_number
+      CHARACTER(len=*)                 :: item_name(:), item_class(:)
+      CHARACTER(len=len(item_name)) :: name
+      CHARACTER(len=len(item_class)) :: class
+      INTEGER :: status
+
+      status = NXinitgroupdir (file_id)
+      item_number = 0
+      DO
+         status = NXgetnextentry (file_id, name, class, NXtype)
+         IF (status == NX_OK .AND. &
+                        (class(1:2) == "NX" .OR. class(1:3) == "SDS")) THEN
+            item_number = item_number + 1
+            IF (item_number > size(item_name) .OR. &
+                        item_number > size(item_class)) THEN
+               CALL NXerror ("Number of items greater than array size")
+               status = NX_ERROR
+               RETURN
+            END IF
+            item_name(item_number) = trim(name)
+            item_class(item_number) = trim(class)
+         ELSE IF (status == NX_EOD) THEN
+            EXIT
+         ELSE IF (status == NX_ERROR) THEN
+            RETURN
+         END IF
+      END DO
+      status = NX_OK
+
+   END FUNCTION NXgroupdir
+!------------------------------------------------------------------------------
+!NXgetattrinfo returns the number of attributes of the open data set
+   FUNCTION NXgetattrinfo (file_id, attr_number) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout)  :: file_id
+      INTEGER,          INTENT(out)    :: attr_number
+      INTEGER :: status, nxigetattrinfo
+      EXTERNAL nxigetattrinfo
+
+      status = nxigetattrinfo (file_id, attr_number)
+
+   END FUNCTION NXgetattrinfo
+!------------------------------------------------------------------------------
+!NXinitattrdir initializes attribute searches using NXgetnextattr
+   FUNCTION NXinitattrdir (file_id) RESULT (status)
+
+      TYPE(NXhandle), INTENT(inout) :: file_id
+      INTEGER :: status, nxiinitattrdir
+      EXTERNAL nxiinitattrdir
+
+      status = nxiinitattrdir (file_id)
+
+  END FUNCTION NXinitattrdir
+!------------------------------------------------------------------------------
+!NXattrdir returns a list of NeXus attributes of current data item
+   FUNCTION NXattrdir (file_id, attr_number, attr_name) RESULT (status)
+
+      TYPE(NXhandle),   INTENT(inout)  :: file_id
+      INTEGER,          INTENT(out)    :: attr_number
+      CHARACTER(len=*)    :: attr_name(:)
+      CHARACTER(len=len(attr_name))    :: name
+      INTEGER :: status
+
+      status = NXinitattrdir (file_id)
+      attr_number = 0
+      DO
+         status = NXgetnextattr (file_id, name, NXsize, NXtype)
+         IF (status == NX_OK) THEN
+            attr_number = attr_number + 1
+            IF (attr_number > size(attr_name)) THEN
+               CALL NXerror ("Number of attributes greater than array size")
+               status = NX_ERROR
+               RETURN
+            ELSE
+               attr_name(attr_number) = trim(name)
+            END IF
+         ELSE IF (status == NX_EOD) THEN
+            EXIT
+         ELSE IF (status == NX_ERROR) THEN
+            RETURN
+         END IF
+      END DO
+      status = NX_OK
+
+   END FUNCTION NXattrdir
+!------------------------------------------------------------------------------
+!NXreverse reverses dimensions for transferring data from F90 to C
+   FUNCTION NXreverse (rank, dimensions) RESULT (reversed_dimensions)
+
+      INTEGER, INTENT(in) :: rank
+      INTEGER, INTENT(in) :: dimensions(:)
+      INTEGER :: reversed_dimensions(size(dimensions))
+      INTEGER :: i
+
+      DO i = 1,rank
+         reversed_dimensions(i) = dimensions(rank-i+1)
+      END DO
+
+  END FUNCTION NXreverse
+!------------------------------------------------------------------------------
+!NXCstring converts a Fortran string into a C string
+   FUNCTION NXCstring (string) RESULT (array)
+
+      CHARACTER(len=*), INTENT(in) :: string
+      INTEGER(kind=NXi1) :: array(255)
+      INTEGER :: i
+
+      DO i = 1,min(len_trim(string),(size(array)-1))
+         array(i) = ichar(string(i:i))
+      END DO
+      array(len_trim(string)+1) = 0
+
+  END FUNCTION NXCstring
+!------------------------------------------------------------------------------
+!NXFstring converts a C string into a Fortran string
+   FUNCTION NXFstring (array) RESULT (string)
+
+      INTEGER(kind=NXi1), INTENT(in) :: array(:)
+      CHARACTER(len=255) :: string
+      INTEGER :: i
+
+      string = " "
+      DO i = 1,size(array)
+         IF (array(i) == 0) EXIT
+         string(i:i) = char(array(i))
+      END DO
+
+  END FUNCTION NXFstring
+!------------------------------------------------------------------------------
+!NXdatatype converts a NeXus data type into a character string
+   FUNCTION NXdatatype (int_type) RESULT (char_type)
+
+      INTEGER, INTENT(in) :: int_type
+      CHARACTER(len=10) :: char_type
+
+      SELECT CASE (int_type)
+         CASE(NX_CHAR); char_type = "NX_CHAR"
+         CASE(NX_FLOAT32); char_type = "NX_FLOAT32"
+         CASE(NX_FLOAT64); char_type = "NX_FLOAT64"
+         CASE(NX_INT8); char_type = "NX_INT8"
+         CASE(NX_INT16); char_type = "NX_INT16"
+         CASE(NX_INT32); char_type = "NX_INT32"
+         CASE(NX_UINT32); char_type = "NX_UINT32"
+         CASE DEFAULT; char_type = "UNKNOWN"
+      END SELECT
+
+  END FUNCTION NXdatatype
+!------------------------------------------------------------------------------
+!NXerror prints out an error message to the default unit
+   SUBROUTINE NXerror (message)
+
+      CHARACTER(len=*), INTENT(in) :: message
+
+      PRINT *, "NXerror : "//message
+
+  END SUBROUTINE NXerror
+
+END MODULE NXmodule
diff --git a/bindings/idl/Makefile.am b/bindings/idl/Makefile.am
new file mode 100755
index 0000000..e275692
--- /dev/null
+++ b/bindings/idl/Makefile.am
@@ -0,0 +1,82 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for NeXus FORTRAN 90 bindings
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+#
+# Unix makefile for NeXusIDL-API DLM.
+#
+# This makefile is used to build NeXusIDL-API --- an example DLM.
+# It works by determining what platform you are on and then
+# recursively invoking make with the proper options to do the build.
+#
+idldlmdir = @IDLDLM@
+idldlm_LTLIBRARIES = libNeXusIDL-API.la
+idldlm_DATA = NeXusIDL-API.dlm
+
+libNeXusIDL_API_la_SOURCES = NeXusIDL-API.c handle.c handle.h
+libNeXusIDL_API_la_LIBADD = $(top_builddir)/src/libNeXus.la
+libNeXusIDL_API_la_LDFLAGS = @SHARED_LDFLAGS@ -L$(IDLROOT)/bin/$(IDL_HOST) -lidl $(LDFLAGS)
+
+AM_CPPFLAGS = -I$(IDLROOT)/external/include
+
+all : all-am NeXusIDL-API.so
+
+install-exec-hook :
+	( cd $(DESTDIR)$(idldlmdir); ln -s libNeXusIDL-API.so NeXusIDL-API.so )
+
+NeXusIDL-API.so : libNeXusIDL-API.la
+	ln -sf .libs/libNeXusIDL-API.so $@
+	if test ! -r NeXusIDL-API.dlm; then ln -s $(srcdir)/NeXusIDL-API.dlm .; fi
+
+CLEANFILES = NeXusIDL-API.so
+
+EXTRA_DIST = \
+ build_testmodule.pro \
+ build_win.bat \
+ data \
+ NeXusIDL-API.def \
+ NeXusIDL-API.dlm \
+ NeXusIDL-API.export \
+ nxext.h5 \
+ nxext.hdf \
+ nxext.xml \
+ NXtest.h5 \
+ NXtest.hdf \
+ NXtest.xml \
+ README.html \
+ read_test.pro \
+ recursiveread.pro \
+ recursivesearch.pro \
+ testfocus.pro \
+ write_test.pro \
+ testidlnapi
+
+dist-hook :
+	find $(distdir)/data -depth -type d -name '.svn' -exec rm -fr {} \;
+
+include $(top_srcdir)/build_rules.am
diff --git a/bindings/idl/NXtest.h5 b/bindings/idl/NXtest.h5
new file mode 100644
index 0000000..20e8e01
Binary files /dev/null and b/bindings/idl/NXtest.h5 differ
diff --git a/bindings/idl/NXtest.hdf b/bindings/idl/NXtest.hdf
new file mode 100644
index 0000000..f2d0cf8
Binary files /dev/null and b/bindings/idl/NXtest.hdf differ
diff --git a/bindings/idl/NXtest.xml b/bindings/idl/NXtest.xml
new file mode 100644
index 0000000..603b4c0
--- /dev/null
+++ b/bindings/idl/NXtest.xml
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="UTF-8"?>
+  <NXroot NeXus_version="4.1.0" XML_version="mxml" file_name="NXtest.xml"
+xmlns="http://definition.nexusformat.org/schema/3.0"
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="http://definition.nexusformat.org/schema/3.0 http://definition.nexusformat.org/schema/3.0/BASE.xsd"
+file_time="2009-02-20T10:05:53+01:00">
+    <NXentry name="entry" hugo="namenlos" cucumber="passion">
+      <ch_data NAPItype="NX_CHAR[10]">NeXus Data</ch_data>
+      <i1_data NAPItype="NX_UINT8[4,4]">
+            0     1     2     4     4     5     6     7     8     9    10    11 
+           12    13    14    15 
+      </i1_data>
+      <i4_data NAPItype="NX_INT32[4,4]">
+                   0            1            2            3            4 
+                   5            6            7            8            9 
+                  10           11           12           13           14 
+                  15 
+      </i4_data>
+      <r4_data NAPItype="NX_FLOAT32[4,4]">
+              0.0110       0.0210       0.2330       0.3440       0.3440 
+              0.5560       0.6670       0.7780       0.6670       1.0000 
+             10.1000      11.2220     -12.2000     -13.4440     -14.2220 
+            -15.4440 
+      </r4_data>
+      <r8_data NAPItype="NX_FLOAT64[4,4]" ch_attribute="NeXus"
+i4_attribute="NX_INT32:42" r4_attribute="NX_FLOAT32:3.141593"
+target="/entry/r8_data">
+                 0.00000          0.00000          0.01111          0.00000 
+                 0.00000          0.00000          0.02122          0.00000 
+                 0.00000          0.00000          0.23333          0.00000 
+                 0.00000          0.00000          0.34444          0.00000 
+      </r8_data>
+      <NXdata name="data">
+        <NAPIlink target="/entry/r8_data" />
+        <comp_data NAPItype="NX_INT32[20,100]">
+                     0            1            2            3            4 
+                     5            6            7            8            9 
+                    10           11           12           13           14 
+                    15           16           17           18           19 
+                    20           21           22           23           24 
+                    25           26           27           28           29 
+                    30           31           32           33           34 
+                    35           36           37           38           39 
+                    40           41           42           43           44 
+                    45           46           47           48           49 
+                    50           51           52           53           54 
+                    55           56           57           58           59 
+                    60           61           62           63           64 
+                    65           66           67           68           69 
+                    70           71           72           73           74 
+                    75           76           77           78           79 
+                    80           81           82           83           84 
+                    85           86           87           88           89 
+                    90           91           92           93           94 
+                    95           96           97           98           99 
+                   100          101          102          103          104 
+                   105          106          107          108          109 
+                   110          111          112          113          114 
+                   115          116          117          118          119 
+                   120          121          122          123          124 
+                   125          126          127          128          129 
+                   130          131          132          133          134 
+                   135          136          137          138          139 
+                   140          141          142          143          144 
+                   145          146          147          148          149 
+                   150          151          152          153          154 
+                   155          156          157          158          159 
+                   160          161          162          163          164 
+                   165          166          167          168          169 
+                   170          171          172          173          174 
+                   175          176          177          178          179 
+                   180          181          182          183          184 
+                   185          186          187          188          189 
+                   190          191          192          193          194 
+                   195          196          197          198          199 
+                   200          201          202          203          204 
+                   205          206          207          208          209 
+                   210          211          212          213          214 
+                   215          216          217          218          219 
+                   220          221          222          223          224 
+                   225          226          227          228          229 
+                   230          231          232          233          234 
+                   235          236          237          238          239 
+                   240          241          242          243          244 
+                   245          246          247          248          249 
+                   250          251          252          253          254 
+                   255          256          257          258          259 
+                   260          261          262          263          264 
+                   265          266          267          268          269 
+                   270          271          272          273          274 
+                   275          276          277          278          279 
+                   280          281          282          283          284 
+                   285          286          287          288          289 
+                   290          291          292          293          294 
+                   295          296          297          298          299 
+                   300          301          302          303          304 
+                   305          306          307          308          309 
+                   310          311          312          313          314 
+                   315          316          317          318          319 
+                   320          321          322          323          324 
+                   325          326          327          328          329 
+                   330          331          332          333          334 
+                   335          336          337          338          339 
+                   340          341          342          343          344 
+                   345          346          347          348          349 
+                   350          351          352          353          354 
+                   355          356          357          358          359 
+                   360          361          362          363          364 
+                   365          366          367          368          369 
+                   370          371          372          373          374 
+                   375          376          377          378          379 
+                   380          381          382          383          384 
+                   385          386          387          388          389 
+                   390          391          392          393          394 
+                   395          396          397          398          399 
+                   400          401          402          403          404 
+                   405          406          407          408          409 
+                   410          411          412          413          414 
+                   415          416          417          418          419 
+                   420          421          422          423          424 
+                   425          426          427          428          429 
+                   430          431          432          433          434 
+                   435          436          437          438          439 
+                   440          441          442          443          444 
+                   445          446          447          448          449 
+                   450          451          452          453          454 
+                   455          456          457          458          459 
+                   460          461          462          463          464 
+                   465          466          467          468          469 
+                   470          471          472          473          474 
+                   475          476          477          478          479 
+                   480          481          482          483          484 
+                   485          486          487          488          489 
+                   490          491          492          493          494 
+                   495          496          497          498          499 
+                   500          501          502          503          504 
+                   505          506          507          508          509 
+                   510          511          512          513          514 
+                   515          516          517          518          519 
+                   520          521          522          523          524 
+                   525          526          527          528          529 
+                   530          531          532          533          534 
+                   535          536          537          538          539 
+                   540          541          542          543          544 
+                   545          546          547          548          549 
+                   550          551          552          553          554 
+                   555          556          557          558          559 
+                   560          561          562          563          564 
+                   565          566          567          568          569 
+                   570          571          572          573          574 
+                   575          576          577          578          579 
+                   580          581          582          583          584 
+                   585          586          587          588          589 
+                   590          591          592          593          594 
+                   595          596          597          598          599 
+                   600          601          602          603          604 
+                   605          606          607          608          609 
+                   610          611          612          613          614 
+                   615          616          617          618          619 
+                   620          621          622          623          624 
+                   625          626          627          628          629 
+                   630          631          632          633          634 
+                   635          636          637          638          639 
+                   640          641          642          643          644 
+                   645          646          647          648          649 
+                   650          651          652          653          654 
+                   655          656          657          658          659 
+                   660          661          662          663          664 
+                   665          666          667          668          669 
+                   670          671          672          673          674 
+                   675          676          677          678          679 
+                   680          681          682          683          684 
+                   685          686          687          688          689 
+                   690          691          692          693          694 
+                   695          696          697          698          699 
+                   700          701          702          703          704 
+                   705          706          707          708          709 
+                   710          711          712          713          714 
+                   715          716          717          718          719 
+                   720          721          722          723          724 
+                   725          726          727          728          729 
+                   730          731          732          733          734 
+                   735          736          737          738          739 
+                   740          741          742          743          744 
+                   745          746          747          748          749 
+                   750          751          752          753          754 
+                   755          756          757          758          759 
+                   760          761          762          763          764 
+                   765          766          767          768          769 
+                   770          771          772          773          774 
+                   775          776          777          778          779 
+                   780          781          782          783          784 
+                   785          786          787          788          789 
+                   790          791          792          793          794 
+                   795          796          797          798          799 
+                   800          801          802          803          804 
+                   805          806          807          808          809 
+                   810          811          812          813          814 
+                   815          816          817          818          819 
+                   820          821          822          823          824 
+                   825          826          827          828          829 
+                   830          831          832          833          834 
+                   835          836          837          838          839 
+                   840          841          842          843          844 
+                   845          846          847          848          849 
+                   850          851          852          853          854 
+                   855          856          857          858          859 
+                   860          861          862          863          864 
+                   865          866          867          868          869 
+                   870          871          872          873          874 
+                   875          876          877          878          879 
+                   880          881          882          883          884 
+                   885          886          887          888          889 
+                   890          891          892          893          894 
+                   895          896          897          898          899 
+                   900          901          902          903          904 
+                   905          906          907          908          909 
+                   910          911          912          913          914 
+                   915          916          917          918          919 
+                   920          921          922          923          924 
+                   925          926          927          928          929 
+                   930          931          932          933          934 
+                   935          936          937          938          939 
+                   940          941          942          943          944 
+                   945          946          947          948          949 
+                   950          951          952          953          954 
+                   955          956          957          958          959 
+                   960          961          962          963          964 
+                   965          966          967          968          969 
+                   970          971          972          973          974 
+                   975          976          977          978          979 
+                   980          981          982          983          984 
+                   985          986          987          988          989 
+                   990          991          992          993          994 
+                   995          996          997          998          999 
+                  1000         1001         1002         1003         1004 
+                  1005         1006         1007         1008         1009 
+                  1010         1011         1012         1013         1014 
+                  1015         1016         1017         1018         1019 
+                  1020         1021         1022         1023         1024 
+                  1025         1026         1027         1028         1029 
+                  1030         1031         1032         1033         1034 
+                  1035         1036         1037         1038         1039 
+                  1040         1041         1042         1043         1044 
+                  1045         1046         1047         1048         1049 
+                  1050         1051         1052         1053         1054 
+                  1055         1056         1057         1058         1059 
+                  1060         1061         1062         1063         1064 
+                  1065         1066         1067         1068         1069 
+                  1070         1071         1072         1073         1074 
+                  1075         1076         1077         1078         1079 
+                  1080         1081         1082         1083         1084 
+                  1085         1086         1087         1088         1089 
+                  1090         1091         1092         1093         1094 
+                  1095         1096         1097         1098         1099 
+                  1100         1101         1102         1103         1104 
+                  1105         1106         1107         1108         1109 
+                  1110         1111         1112         1113         1114 
+                  1115         1116         1117         1118         1119 
+                  1120         1121         1122         1123         1124 
+                  1125         1126         1127         1128         1129 
+                  1130         1131         1132         1133         1134 
+                  1135         1136         1137         1138         1139 
+                  1140         1141         1142         1143         1144 
+                  1145         1146         1147         1148         1149 
+                  1150         1151         1152         1153         1154 
+                  1155         1156         1157         1158         1159 
+                  1160         1161         1162         1163         1164 
+                  1165         1166         1167         1168         1169 
+                  1170         1171         1172         1173         1174 
+                  1175         1176         1177         1178         1179 
+                  1180         1181         1182         1183         1184 
+                  1185         1186         1187         1188         1189 
+                  1190         1191         1192         1193         1194 
+                  1195         1196         1197         1198         1199 
+                  1200         1201         1202         1203         1204 
+                  1205         1206         1207         1208         1209 
+                  1210         1211         1212         1213         1214 
+                  1215         1216         1217         1218         1219 
+                  1220         1221         1222         1223         1224 
+                  1225         1226         1227         1228         1229 
+                  1230         1231         1232         1233         1234 
+                  1235         1236         1237         1238         1239 
+                  1240         1241         1242         1243         1244 
+                  1245         1246         1247         1248         1249 
+                  1250         1251         1252         1253         1254 
+                  1255         1256         1257         1258         1259 
+                  1260         1261         1262         1263         1264 
+                  1265         1266         1267         1268         1269 
+                  1270         1271         1272         1273         1274 
+                  1275         1276         1277         1278         1279 
+                  1280         1281         1282         1283         1284 
+                  1285         1286         1287         1288         1289 
+                  1290         1291         1292         1293         1294 
+                  1295         1296         1297         1298         1299 
+                  1300         1301         1302         1303         1304 
+                  1305         1306         1307         1308         1309 
+                  1310         1311         1312         1313         1314 
+                  1315         1316         1317         1318         1319 
+                  1320         1321         1322         1323         1324 
+                  1325         1326         1327         1328         1329 
+                  1330         1331         1332         1333         1334 
+                  1335         1336         1337         1338         1339 
+                  1340         1341         1342         1343         1344 
+                  1345         1346         1347         1348         1349 
+                  1350         1351         1352         1353         1354 
+                  1355         1356         1357         1358         1359 
+                  1360         1361         1362         1363         1364 
+                  1365         1366         1367         1368         1369 
+                  1370         1371         1372         1373         1374 
+                  1375         1376         1377         1378         1379 
+                  1380         1381         1382         1383         1384 
+                  1385         1386         1387         1388         1389 
+                  1390         1391         1392         1393         1394 
+                  1395         1396         1397         1398         1399 
+                  1400         1401         1402         1403         1404 
+                  1405         1406         1407         1408         1409 
+                  1410         1411         1412         1413         1414 
+                  1415         1416         1417         1418         1419 
+                  1420         1421         1422         1423         1424 
+                  1425         1426         1427         1428         1429 
+                  1430         1431         1432         1433         1434 
+                  1435         1436         1437         1438         1439 
+                  1440         1441         1442         1443         1444 
+                  1445         1446         1447         1448         1449 
+                  1450         1451         1452         1453         1454 
+                  1455         1456         1457         1458         1459 
+                  1460         1461         1462         1463         1464 
+                  1465         1466         1467         1468         1469 
+                  1470         1471         1472         1473         1474 
+                  1475         1476         1477         1478         1479 
+                  1480         1481         1482         1483         1484 
+                  1485         1486         1487         1488         1489 
+                  1490         1491         1492         1493         1494 
+                  1495         1496         1497         1498         1499 
+                  1500         1501         1502         1503         1504 
+                  1505         1506         1507         1508         1509 
+                  1510         1511         1512         1513         1514 
+                  1515         1516         1517         1518         1519 
+                  1520         1521         1522         1523         1524 
+                  1525         1526         1527         1528         1529 
+                  1530         1531         1532         1533         1534 
+                  1535         1536         1537         1538         1539 
+                  1540         1541         1542         1543         1544 
+                  1545         1546         1547         1548         1549 
+                  1550         1551         1552         1553         1554 
+                  1555         1556         1557         1558         1559 
+                  1560         1561         1562         1563         1564 
+                  1565         1566         1567         1568         1569 
+                  1570         1571         1572         1573         1574 
+                  1575         1576         1577         1578         1579 
+                  1580         1581         1582         1583         1584 
+                  1585         1586         1587         1588         1589 
+                  1590         1591         1592         1593         1594 
+                  1595         1596         1597         1598         1599 
+                  1600         1601         1602         1603         1604 
+                  1605         1606         1607         1608         1609 
+                  1610         1611         1612         1613         1614 
+                  1615         1616         1617         1618         1619 
+                  1620         1621         1622         1623         1624 
+                  1625         1626         1627         1628         1629 
+                  1630         1631         1632         1633         1634 
+                  1635         1636         1637         1638         1639 
+                  1640         1641         1642         1643         1644 
+                  1645         1646         1647         1648         1649 
+                  1650         1651         1652         1653         1654 
+                  1655         1656         1657         1658         1659 
+                  1660         1661         1662         1663         1664 
+                  1665         1666         1667         1668         1669 
+                  1670         1671         1672         1673         1674 
+                  1675         1676         1677         1678         1679 
+                  1680         1681         1682         1683         1684 
+                  1685         1686         1687         1688         1689 
+                  1690         1691         1692         1693         1694 
+                  1695         1696         1697         1698         1699 
+                  1700         1701         1702         1703         1704 
+                  1705         1706         1707         1708         1709 
+                  1710         1711         1712         1713         1714 
+                  1715         1716         1717         1718         1719 
+                  1720         1721         1722         1723         1724 
+                  1725         1726         1727         1728         1729 
+                  1730         1731         1732         1733         1734 
+                  1735         1736         1737         1738         1739 
+                  1740         1741         1742         1743         1744 
+                  1745         1746         1747         1748         1749 
+                  1750         1751         1752         1753         1754 
+                  1755         1756         1757         1758         1759 
+                  1760         1761         1762         1763         1764 
+                  1765         1766         1767         1768         1769 
+                  1770         1771         1772         1773         1774 
+                  1775         1776         1777         1778         1779 
+                  1780         1781         1782         1783         1784 
+                  1785         1786         1787         1788         1789 
+                  1790         1791         1792         1793         1794 
+                  1795         1796         1797         1798         1799 
+                  1800         1801         1802         1803         1804 
+                  1805         1806         1807         1808         1809 
+                  1810         1811         1812         1813         1814 
+                  1815         1816         1817         1818         1819 
+                  1820         1821         1822         1823         1824 
+                  1825         1826         1827         1828         1829 
+                  1830         1831         1832         1833         1834 
+                  1835         1836         1837         1838         1839 
+                  1840         1841         1842         1843         1844 
+                  1845         1846         1847         1848         1849 
+                  1850         1851         1852         1853         1854 
+                  1855         1856         1857         1858         1859 
+                  1860         1861         1862         1863         1864 
+                  1865         1866         1867         1868         1869 
+                  1870         1871         1872         1873         1874 
+                  1875         1876         1877         1878         1879 
+                  1880         1881         1882         1883         1884 
+                  1885         1886         1887         1888         1889 
+                  1890         1891         1892         1893         1894 
+                  1895         1896         1897         1898         1899 
+                  1900         1901         1902         1903         1904 
+                  1905         1906         1907         1908         1909 
+                  1910         1911         1912         1913         1914 
+                  1915         1916         1917         1918         1919 
+                  1920         1921         1922         1923         1924 
+                  1925         1926         1927         1928         1929 
+                  1930         1931         1932         1933         1934 
+                  1935         1936         1937         1938         1939 
+                  1940         1941         1942         1943         1944 
+                  1945         1946         1947         1948         1949 
+                  1950         1951         1952         1953         1954 
+                  1955         1956         1957         1958         1959 
+                  1960         1961         1962         1963         1964 
+                  1965         1966         1967         1968         1969 
+                  1970         1971         1972         1973         1974 
+                  1975         1976         1977         1978         1979 
+                  1980         1981         1982         1983         1984 
+                  1985         1986         1987         1988         1989 
+                  1990         1991         1992         1993         1994 
+                  1995         1996         1997         1998         1999 
+        </comp_data>
+        <flush_data NAPItype="NX_INT32[8]">
+                     0            1            2            3            4 
+                     5            6            7 
+        </flush_data>
+      </NXdata>
+      <NXsample name="sample" target="/entry/sample">
+        <ch_data NAPItype="NX_CHAR[12]">NeXus sample</ch_data>
+      </NXsample>
+    </NXentry>
+    <NXentry name="link">
+      <NAPIlink target="/entry/sample" />
+      <NAPIlink target="/entry/sample" name="renLinkGroup" />
+      <NAPIlink target="/entry/r8_data" name="renLinkData" />
+    </NXentry>
+  </NXroot>
diff --git a/bindings/idl/NeXusIDL-API.c b/bindings/idl/NeXusIDL-API.c
new file mode 100644
index 0000000..c7a97db
--- /dev/null
+++ b/bindings/idl/NeXusIDL-API.c
@@ -0,0 +1,2636 @@
+/*
+  NeXus - Neutron & X-ray Common Data Format
+  
+  IDL Application Program Interface Routines
+  
+  Copyright (C) 2007-* Jussi Kauppila, Mark Koennecke 
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "idl_export.h"
+#include "../../include/napi.h" 
+#include "handle.h"
+
+/* Windows path: */
+/* #include "C:\Program Files\NeXus Data Format\include\napi.h" */
+
+/* prototype for IDL_Load */
+int IDL_Load( void );
+
+/*
+ * Define message codes and their corresponding printf(3) format
+ * strings. Note that message codes start at zero and each one is
+ * one less that the previous one. Codes must be monotonic and
+ * contiguous.
+ */
+static IDL_MSG_DEF msg_arr[] =
+{
+#define M_TM_INPRO                       0
+  {  "M_TM_INPRO",   "%NThis is from a loadable module procedure." },
+#define M_TM_INFUN                       -1
+  {  "M_TM_INFUN",   "%NThis is from a loadable module function." },
+};
+
+/*
+ * The load function fills in this message block handle with the
+ * opaque handle to the message block used for this module. The other
+ * routines can then use it to throw errors from this block.
+ */
+static IDL_MSG_BLOCK msg_block;
+
+static char nexusError[1024];
+
+static void idlError(void *pData, char *message){
+	strncpy(nexusError,message,1023);
+}
+
+/* Implementation of the NeXus IDL API */
+
+/*======================================================================
+ * NxOpen
+ * status = NXopen (file_name, access_method, file_id)
+ *======================================================================*/
+static IDL_VPTR NXopen_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR result;
+  int status, iHandle;
+  NXaccess am;
+  char* accesstype;
+  char* path;
+  NXhandle hHandle;
+
+  /* if ENSURE fails it jumps a "long jump" back and complains but the
+     proper NX_ERROR status is not returned. Maybe write an own macro */
+  IDL_ENSURE_STRING(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  /* Convert argumets from IDL side to C-land */
+  path = IDL_VarGetString(argv[0]);
+  accesstype = IDL_VarGetString(argv[1]);
+
+  /* If number of arguments is not 3 return status NX_ERROR */
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+
+  /* If the accesstype isn't NXACC_CREATE5 NXACC_CREATE NXACC_READ,NXACC_RDWR return NX_ERROR */
+
+   if (strcmp(accesstype,"NXACC_CREATE5") == 0) {;
+       am = NXACC_CREATE5;
+    } else if (strcmp(accesstype,"NXACC_CREATE") == 0) {
+       am = NXACC_CREATE;
+    } else if (strcmp(accesstype,"NXACC_CREATE4") == 0) {
+       am = NXACC_CREATE4;
+    } else if (strcmp(accesstype,"NXACC_CREATEXML") == 0) {
+       am = NXACC_CREATEXML;
+    } else if (strcmp(accesstype,"NXACC_READ") == 0) {
+       am = NXACC_READ;
+    } else if (strcmp(accesstype,"NXACC_RDWR") == 0) {
+       am = NXACC_RDWR;
+    } else {
+       IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown Access Type");
+       return IDL_GettmpInt(NX_ERROR);
+    }
+
+  NXMSetError(NULL,idlError);
+  status = NXopen (path, am, &hHandle);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  iHandle = HHMakeHandle(hHandle);
+    if(iHandle == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Error creating the handle");
+		return IDL_GettmpInt(NX_ERROR);
+	}
+
+
+  result = IDL_GettmpInt(iHandle);
+
+  /* Output argument */
+  IDL_VarCopy(result, argv[2]);
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * Nxopenpath
+ * status = NXopenpath(file_id, path_string)
+ *======================================================================*/
+
+static IDL_VPTR NXopenpath_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char* path;
+
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+  path = IDL_VarGetString(argv[1]);
+
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+  NXMSetError(NULL,idlError);
+
+  status = NXopenpath (hHandle, path);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXopengrouppath
+ * status = NXopengrouppath(file_id, path_string)
+ *======================================================================*/
+
+static IDL_VPTR NXopengrouppath_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char* path;
+
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+  path = IDL_VarGetString(argv[1]);
+
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+  NXMSetError(NULL,idlError);
+
+  status = NXopengrouppath (hHandle, path);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+/*======================================================================
+ * NXgetpath
+ * string = NXgetpath(file_id)
+ *======================================================================*/
+static IDL_VPTR NXgetpath_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char path[1024];
+
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One argument expected");
+	return IDL_StrToSTRING("One argument expected");
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_StrToSTRING("ERROR: Unknown file ID");
+	}
+
+  hHandle = HHGetPointer(fileid);
+  NXMSetError(NULL,idlError);
+
+  status = NXgetpath(hHandle,path,1024);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_StrToSTRING(nexusError);
+  }
+   return IDL_StrToSTRING(path);
+}
+
+/*======================================================================
+ * Nxclose
+ * status = NXclose (file_id)
+ *=======================================================================*/
+static IDL_VPTR  NXclose_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+  /* If number of arguments is not 2 return 0 */
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One argument expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  /* Convert IDL variables from arguments to C-land */
+  fileid = (int) IDL_LongScalar(argv[0]);
+
+  if( HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = (int *)HHGetPointer(fileid);
+
+
+  NXMSetError(NULL,idlError);
+
+  status = NXclose (&hHandle);
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+	  HHRemoveHandle(fileid);
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * datatypecheck
+ *
+ *=======================================================================*/
+
+
+int datatypecheck(IDL_VPTR argv) {
+  int data_type;
+  char* datatype;
+
+  if(argv->type == IDL_TYP_STRING) {
+	IDL_ENSURE_STRING(argv);
+	datatype = IDL_VarGetString(argv);
+
+  if (strcmp(datatype,"NX_CHAR") == 0) {
+       data_type = NX_CHAR;
+    } else if (strcmp(datatype,"NX_INT8") == 0) {
+       data_type = NX_INT8;
+    } else if (strcmp(datatype,"NX_UINT8") == 0) {
+       data_type = NX_UINT8;
+    } else if (strcmp(datatype,"NX_INT16") == 0) {
+       data_type = NX_INT16;
+    } else if (strcmp(datatype,"NX_UINT16") == 0) {
+       data_type = NX_UINT16;
+    } else if (strcmp(datatype,"NX_INT32") == 0) {
+       data_type = NX_INT32;
+    } else if (strcmp(datatype,"NX_UINT32") == 0) {
+       data_type = NX_UINT32;
+    } else if (strcmp(datatype,"NX_FLOAT32") == 0) {
+       data_type = NX_FLOAT32;
+    } else if (strcmp(datatype,"NX_FLOAT64") == 0) {
+       data_type = NX_FLOAT64;
+    } else {
+	 	char statusBuffer[100];
+		sprintf(statusBuffer,"Unknown attribute datatype: %s", datatype );
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+		return(-1);
+    }
+
+  }
+else {
+  IDL_ENSURE_SCALAR(argv);
+  data_type =  IDL_LongScalar(argv);
+  if(data_type == 4); else if (data_type == 5); else if (data_type == 6); else if
+     (data_type == 20); else if (data_type == 21); else if (data_type == 22); else if
+     (data_type == 23); else if (data_type == 24); else if (data_type == 25); else
+	{
+	char statusBuffer[100];
+	sprintf(statusBuffer,"Unknown attribute datatype: %i", data_type );
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+	return(-1);
+	}
+  }
+
+ return(data_type);
+}
+
+
+/*======================================================================
+ * NXsetnumberformat
+ * status = NXsetnumberformat(file_id,data_type,format_string)
+ *=======================================================================*/
+
+static IDL_VPTR NXsetnumberformat_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int data_type;
+  char* format_string;
+  char* datatype;
+
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  IDL_ENSURE_STRING(argv[2]);
+  format_string = IDL_VarGetString(argv[2]);
+
+
+  data_type = datatypecheck(argv[1]);
+  if(data_type == -1) return IDL_GettmpInt(NX_ERROR);
+
+/*if(argv[1]->type == IDL_TYP_STRING) {
+  IDL_ENSURE_STRING(argv[1]);
+  datatype = IDL_VarGetString(argv[1]);
+
+  if (strcmp(datatype,"NX_CHAR") == 0) {
+       data_type = NX_CHAR;
+    } else if (strcmp(datatype,"NX_INT8") == 0) {
+       data_type = NX_INT8;
+    } else if (strcmp(datatype,"NX_UINT8") == 0) {
+       data_type = NX_UINT8;
+    } else if (strcmp(datatype,"NX_INT16") == 0) {
+       data_type = NX_INT16;
+    } else if (strcmp(datatype,"NX_UINT16") == 0) {
+       data_type = NX_UINT16;
+    } else if (strcmp(datatype,"NX_INT32") == 0) {
+       data_type = NX_INT32;
+    } else if (strcmp(datatype,"NX_UINT32") == 0) {
+       data_type = NX_UINT32;
+    } else if (strcmp(datatype,"NX_FLOAT32") == 0) {
+       data_type = NX_FLOAT32;
+    } else if (strcmp(datatype,"NX_FLOAT64") == 0) {
+       data_type = NX_FLOAT64;
+    } else {
+	 	char statusBuffer[100];
+		sprintf(statusBuffer,"Unknown attribute datatype: %s", datatype );
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+		return IDL_GettmpInt(NX_ERROR);
+    }
+
+  }
+else {
+  IDL_ENSURE_SCALAR(argv[1]);
+  data_type =  IDL_LongScalar(argv[1]);
+  if(data_type == 4); else if (data_type == 5); else if (data_type == 6); else if
+     (data_type == 20); else if (data_type == 21); else if (data_type == 22); else if
+     (data_type == 23); else if (data_type == 24); else if (data_type == 25); else
+	{
+	char statusBuffer[100];
+	sprintf(statusBuffer,"Unknown attribute datatype: %i", data_type );
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  }*/
+
+  fileid = (int ) IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = (int *)HHGetPointer(fileid);
+  NXMSetError(NULL,idlError);
+
+  status = NXsetnumberformat(hHandle, data_type,format_string);
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+/*======================================================================
+ * NXmakegroup
+ * status = NXmakegroup (file_id, group_name, group_class)
+ *=======================================================================*/
+
+static IDL_VPTR NXmakegroup_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char* group_name;
+  char* group_class;
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_STRING(argv[2]);
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+
+  group_name = IDL_VarGetString(argv[1]);
+  group_class = IDL_VarGetString(argv[2]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXmakegroup (hHandle, group_name, group_class);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * Nxopengroup
+ * status = NXopengroup (file_id, group_name, group_class)
+ *=======================================================================*/
+
+static IDL_VPTR NXopengroup_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char* group_name;
+  char* group_class;
+
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_STRING(argv[2]);
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+  group_name = IDL_VarGetString(argv[1]);
+  group_class = IDL_VarGetString(argv[2]);
+
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXopengroup (hHandle, group_name, group_class);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXclosegroup
+ * status = NXclosegroup (file_id)
+ *=======================================================================*/
+
+static IDL_VPTR NXclosegroup_this(int argc, IDL_VPTR *argv)
+{
+
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One argument expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int )IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+
+  NXMSetError(NULL,idlError);
+
+  status = NXclosegroup (hHandle);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXopendata
+ * status = NXopendata (file_id, data_name)
+ *=======================================================================*/
+
+static IDL_VPTR NXopendata_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char* data_name;
+
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  fileid = (int )IDL_LongScalar(argv[0]);
+  data_name = IDL_VarGetString(argv[1]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXopendata (hHandle, data_name);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * Nxclosedata
+ * status = NXclosedata (file_id)
+ *=======================================================================*/
+static IDL_VPTR  NXclosedata_this(int argc, IDL_VPTR *argv)
+{
+
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  NXlink data_id;
+
+  /* If number of arguments is not 2 return 0
+   Should be handled also with the calling conversion not shure if necessary..*/
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One argument expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int ) IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+ /* status = NXgetdataID (hHandle, &data_id);
+  if(status == NX_ERROR) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dataset must be opened before nxclosedata");
+		return IDL_GettmpInt(NX_ERROR);
+	  }*/
+
+  NXMSetError(NULL,idlError);
+
+  status = NXclosedata (hHandle);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXcompress
+ * statusstatus = NXcompress (file_id, compress_type)
+ *=======================================================================*/
+
+static IDL_VPTR NXcompress_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int compresstype;
+  char* compress_type;
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  fileid = (int )IDL_LongScalar(argv[0]);
+  compress_type = IDL_VarGetString(argv[1]);
+
+   if (strcmp(compress_type,"NX_COMP_LZW") == 0) {;
+       compresstype = NX_COMP_LZW;
+    } else if (strcmp(compress_type,"NX_COMP_HUF") == 0) {
+       compresstype = NX_COMP_HUF;
+    } else if (strcmp(compress_type,"NX_COMP_RLE") == 0) {
+       compresstype = NX_COMP_RLE;
+    } else {
+       IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown Compression Type");
+       return IDL_GettmpInt(NX_ERROR);
+    }
+  if(HHCheckIfHandleExists(fileid) == -1) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+  NXMSetError(NULL,idlError);
+
+  status = NXcompress (hHandle, (int) &compresstype);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXmakedata
+ * status = NXmakedata (file_id, data_name, data_type, rank, dimensions[])
+ *=======================================================================*/
+
+static IDL_VPTR NXmakedata_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int dimension[NX_MAXRANK], trueDimension[NX_MAXRANK], n, datatype;
+  int rank;
+  IDL_LONG *dim;
+  char* data_name;
+  char* data_type;
+  //IDL_LONG dims[IDL_MAX_ARRAY_DIM];
+
+
+  if (argc != 5) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Five arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  IDL_ENSURE_SCALAR(argv[3]);
+
+
+  data_name = IDL_VarGetString(argv[1]);
+
+  datatype = datatypecheck(argv[2]);
+  if(datatype == -1) return IDL_GettmpInt(NX_ERROR);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  rank = (int ) IDL_LongScalar(argv[3]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = (int *)HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  if(argv[4]->type == IDL_TYP_STRING) {
+	char* unlimited_test = IDL_VarGetString(argv[4]);
+	if(strcmp(unlimited_test,"NX_UNLIMITED") == 0) {
+		int unlimited_dims[1] = {NX_UNLIMITED};
+	  	status = NXmakedata(hHandle, data_name, datatype, (int)rank, (int *) unlimited_dims);
+		}
+	  else {
+    IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dimension array must be type long or String: 'NX_UNLIMITED'");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  }
+  else if(argv[4]->type == IDL_TYP_LONG) {
+  	  IDL_ENSURE_ARRAY(argv[4]);
+	  /* dimensions have to be swapped for Fortran C storage order */
+	  dim = (IDL_LONG *)argv[4]->value.arr->data;
+	  for(n = 0; n < rank; n++){
+	    trueDimension[n] = dim[rank - 1 -n];
+          }
+  	  status = NXmakedata(hHandle, data_name, datatype, rank, 
+			      trueDimension);
+  }
+  else {
+    IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dimension array must be type long or String: 'NX_UNLIMITED'");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXcompmakedata
+ * statusstatus = NXcompmakedata (file_id, data_name, data_type, rank, dimensions[], compress_type, bufsize[])
+ *=======================================================================*/
+
+static IDL_VPTR NXcompmakedata_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int rank, dimension[NX_MAXRANK], trueDimension[NX_MAXRANK], 
+    trueChunk[NX_MAXRANK], n,  datatype;
+  IDL_LONG *dim;
+  int comptype;
+  char* data_type;
+  char* data_name;
+  char* comp_type;
+
+  if (argc != 7) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Seven arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+
+  IDL_ENSURE_SCALAR(argv[3]);
+  IDL_ENSURE_ARRAY(argv[4]);
+  IDL_ENSURE_STRING(argv[5]);
+  IDL_ENSURE_ARRAY(argv[6]);
+
+  data_name = IDL_VarGetString(argv[1]);
+
+  datatype = datatypecheck(argv[2]);
+  if(datatype == -1) return IDL_GettmpInt(NX_ERROR);
+
+  /* Compressio type check */
+  if(argv[5]->type == IDL_TYP_STRING) {
+  IDL_ENSURE_STRING(argv[5]);
+  comp_type = IDL_VarGetString(argv[5]);
+
+  if (strcmp(comp_type,"NX_COMP_LZW") == 0) {
+       comptype = NX_COMP_LZW;
+    } else if (strcmp(comp_type,"NX_COMP_HUF") == 0) {
+       comptype = NX_COMP_HUF;
+    } else if (strcmp(comp_type,"NX_COMP_RLE") == 0) {
+       comptype = NX_COMP_RLE;
+    } else {
+	char statusBuffer[100];
+	sprintf(statusBuffer,"Unknown Compression Type: %s", comp_type );
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+	return IDL_GettmpInt(NX_ERROR);
+    }
+
+  }
+else {
+  IDL_ENSURE_SCALAR(argv[5]);
+  comptype = IDL_LongScalar(argv[5]);
+  if(datatype == NX_COMP_LZW); else if (datatype == NX_COMP_HUF); else if (datatype == NX_COMP_RLE);
+  else{
+	char statusBuffer[100];
+	sprintf(statusBuffer,"Unknown Compression Type: %i", comptype );
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  }
+
+  if(argv[4]->type != IDL_TYP_LONG) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Argument 5, dimensions, Array must be type long");
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  if(argv[6]->type != IDL_TYP_LONG) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Argument 7, Buffer Array: Array must be type long");
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  fileid = (int ) IDL_LongScalar(argv[0]);
+  rank = (int ) IDL_LongScalar(argv[3]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+ hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  /* dimensions have to be swapped for Fortran C storage order */
+  dim = (IDL_LONG *)argv[4]->value.arr->data;
+  for(n = 0; n < rank; n++){
+    trueDimension[n] = dim[rank - 1 -n];
+  }
+  dim = (IDL_LONG *)argv[6]->value.arr->data;
+  if(dim != NULL){
+    for(n = 0; n < rank; n++){
+      trueChunk[n] = dim[rank - 1 -n];
+    }
+  } else {
+    for(n = 0; n < rank; n++){
+      trueChunk[n] = trueDimension[n];
+    }
+  }
+
+  status = NXcompmakedata(hHandle, data_name, datatype, (int)rank, 
+			  trueDimension, comptype, 
+			  trueChunk);
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXputdata
+ * status = NXputdata (file_id, data[])
+ *=======================================================================*/
+
+static IDL_VPTR NXputdata_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int rank, datatype;
+  int dimension[IDL_MAX_ARRAY_DIM];
+  NXlink data_id;
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  hHandle = HHGetPointer(fileid);
+
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  status = NXgetdataID (hHandle, &data_id);
+/*  if(status == NX_ERROR) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dataset must be opened before nxputdata");
+		return IDL_GettmpInt(NX_ERROR);
+		} */
+
+ /* get info, datatype especially! */
+    status = NXgetinfo (hHandle, &rank, dimension, &datatype);
+    if(status == NX_ERROR) {
+ 	 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Can't get the dimension and datatype info from The Nexus file");
+		return IDL_GettmpInt(NX_ERROR);
+	}
+
+	/* Check if the IDL datatypes and Nexusdatatypes match */
+
+    if ((datatype == NX_CHAR) && (argv[1]->type == IDL_TYP_STRING)) {
+    } else if ((datatype == NX_INT8) && (argv[1]->type == IDL_TYP_BYTE)) {
+    	/*	 This datatype cannot be created on the idl side so it cannot be an argument.  */
+
+     	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NX_INT8: data type is not supported in IDL");
+		return IDL_GettmpInt(NX_ERROR);
+	} else if (datatype == NX_UINT8){
+    } else if ((datatype == NX_INT16) && (argv[1]->type == IDL_TYP_INT)) {
+    } else if ((datatype == NX_UINT16) && (argv[1]->type == IDL_TYP_UINT)) {
+    } else if ((datatype == NX_INT32) && (argv[1]->type == IDL_TYP_LONG)) {
+    } else if ((datatype == NX_UINT32) && (argv[1]->type == IDL_TYP_ULONG))  {
+    } else if ((datatype == NX_FLOAT32) && (argv[1]->type == IDL_TYP_FLOAT)) {
+    } else if ((datatype == NX_FLOAT64) && (argv[1]->type == IDL_TYP_DOUBLE)) {
+    } else {
+		char statusBuffer[100];
+		/* Maybe print more information to the user about which datatypes match OR do conversions */
+		sprintf(statusBuffer,"IDL and NeXus types don't match!");
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+		return IDL_GettmpInt(NX_ERROR);
+    }
+
+
+  NXMSetError(NULL,idlError);
+  if(datatype == NX_CHAR) {
+
+  	/* Should there be a test here for trying to put a multidimensinal char array in to NeXus
+  	 * becose they are not really supported */
+
+	  char* char_buffer = IDL_VarGetString(argv[1]);
+	  status = NXputdata (hHandle, char_buffer);
+  }
+  else {
+	  status = NXputdata (hHandle, argv[1]->value.arr->data);
+  }
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXputslab
+ * statusstatus = NXputslab (file_id, data, start[], size[])
+ *=======================================================================*/
+
+static IDL_VPTR NXputslab_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int rank, datatype, n;
+  int start[NX_MAXRANK], size[NX_MAXRANK];
+  IDL_LONG *stDim, *szDim;
+  int dimension[IDL_MAX_ARRAY_DIM];
+  NXlink data_id;
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Four arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_ARRAY(argv[2]);
+  IDL_ENSURE_ARRAY(argv[3]);
+
+  if(argv[2]->type != IDL_TYP_LONG) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Array must be type long");
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  if(argv[3]->type != IDL_TYP_LONG) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Array must be type long");
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  hHandle = HHGetPointer(fileid);
+
+  status = NXgetdataID (hHandle, &data_id);
+/* if(status == NX_ERROR) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dataset must be opened before nxputdata");
+		return IDL_GettmpInt(NX_ERROR);
+		} */
+
+ /* get info, datatype especially! */
+    status = NXgetinfo (hHandle, &rank, dimension, &datatype);
+    if(status == NX_ERROR) {
+ 	 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Can't get the dimension and datatype info from The Nexus file");
+		return IDL_GettmpInt(NX_ERROR);
+	}
+	/* Check if the IDL datatypes and Nexusdatatypes match */
+
+    if ((datatype == NX_CHAR) && (argv[1]->type == IDL_TYP_STRING)) {
+    } else if ((datatype == NX_INT8) && (argv[1]->type == IDL_TYP_BYTE)) {
+	/*
+       } else if (datatype == NX_UINT8){
+    	 This datatype cannot be created on the idl side so it cannot be an argument.
+     */
+    } else if ((datatype == NX_INT16) && (argv[1]->type == IDL_TYP_INT)) {
+    } else if ((datatype == NX_UINT16) && (argv[1]->type == IDL_TYP_UINT)) {
+    } else if ((datatype == NX_INT32) && (argv[1]->type == IDL_TYP_LONG)) {
+    } else if ((datatype == NX_UINT32) && (argv[1]->type == IDL_TYP_ULONG))  {
+    } else if ((datatype == NX_FLOAT32) && (argv[1]->type == IDL_TYP_FLOAT)) {
+    } else if ((datatype == NX_FLOAT64) && (argv[1]->type == IDL_TYP_DOUBLE)) {
+    } else {
+		char statusBuffer[100];
+		/* Maybe print more information to the user about which datatypes match OR do conversions */
+		sprintf(statusBuffer,"IDL and NeXus types don't match!: %i & %i ", 
+			datatype, argv[1]->type);
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+		return IDL_GettmpInt(NX_ERROR);
+    }
+
+  NXMSetError(NULL,idlError);
+
+  if(datatype == NX_CHAR) {
+
+  	/* Should there be a test here for trying to put a multidimensinal char array in to NeXus
+  	 * becose they are not really supported */
+
+	char* char_buffer = IDL_VarGetString(argv[1]);
+	status = NXputslab (hHandle, char_buffer, (void *)argv[2]->value.arr->data, (void *)argv[3]->value.arr->data);
+
+  }
+  else {
+    stDim = (IDL_LONG *) argv[2]->value.arr->data;
+    szDim = (IDL_LONG *) argv[3]->value.arr->data;
+    for(n = 0; n < rank; n++){
+      start[n] = stDim[rank -n -1];
+      size[n] = szDim[rank -n -1];
+    }
+		status = NXputslab (hHandle, argv[1]->value.arr->data, 
+				    start, size);
+
+  }
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+/*======================================================================
+ * NXputattr
+ * status = NXputattr (file_id, attr_name, value, length, type)
+ *=======================================================================*/
+
+static IDL_VPTR NXputattr_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int length, attr_type;
+  long value_long;
+  char* attr_name;
+  char* attrtype;
+
+  void *value;
+  if (argc != 5) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Five arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_SIMPLE(argv[2]);
+/*  IDL_ENSURE_SCALAR(argv[3]); */
+
+   attr_name = IDL_VarGetString(argv[1]);
+   length = IDL_LongScalar(argv[3]);
+
+   fileid = (int) IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+   hHandle = HHGetPointer(fileid);
+
+
+  attr_type = datatypecheck(argv[4]);
+  if(attr_type == -1) return IDL_GettmpInt(NX_ERROR);
+
+  NXMSetError(NULL,idlError);
+
+    if ((attr_type == NX_CHAR) && (argv[2]->type == IDL_TYP_STRING)) {
+		attr_type = NX_CHAR;
+		IDL_ENSURE_STRING(argv[2]);
+		value = IDL_VarGetString(argv[2]);
+		status = NXputattr (hHandle, attr_name, value, length, attr_type);
+
+    } else if ((attr_type == NX_INT8) && (argv[2]->type == IDL_TYP_INT)) {
+		short *value_short;
+		attr_type = NX_INT8;
+		IDL_ENSURE_SCALAR(argv[2]);
+		value_short = (short *) IDL_LongScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_short, length, attr_type);
+
+    } else if ((attr_type == NX_UINT8) && (argv[2]->type == IDL_TYP_BYTE)) {
+    	UCHAR *value_uchar;
+		attr_type = NX_UINT8;
+       	IDL_ENSURE_SCALAR(argv[2]);
+		value_uchar = (UCHAR *) IDL_LongScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_uchar, length, attr_type);
+
+    } else if ((attr_type == NX_INT16) && (argv[2]->type == IDL_TYP_INT)) {
+		IDL_INT *value_short;
+		attr_type = NX_INT16;
+		IDL_ENSURE_SCALAR(argv[2]);
+		value_short = (IDL_INT *) IDL_LongScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_short, length, attr_type);
+
+    } else if ((attr_type == NX_UINT16) && (argv[2]->type == IDL_TYP_UINT)) {
+    	IDL_UINT *value_uint;
+		attr_type = NX_UINT16;
+       	IDL_ENSURE_SCALAR(argv[2]);
+ 		value_uint = (IDL_UINT *) IDL_LongScalar(argv[2]);
+ 		status = NXputattr (hHandle, attr_name, &value_uint, length, attr_type);
+
+    } else if ((attr_type == NX_INT32) && (argv[2]->type == IDL_TYP_LONG)) {
+		IDL_LONG *value_int;
+		attr_type = NX_INT32;
+		IDL_ENSURE_SCALAR(argv[2]);
+		value_int = (IDL_LONG *)IDL_LongScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_int, length, attr_type);
+
+    } else if ((attr_type == NX_UINT32) && (argv[2]->type == IDL_TYP_ULONG)) {
+		IDL_ULONG *value_uint;
+		attr_type = NX_UINT32;
+		IDL_ENSURE_SCALAR(argv[2]);
+		value_uint = (IDL_ULONG *) IDL_LongScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_uint, length, attr_type);
+
+    } else if ((attr_type == NX_FLOAT32) && (argv[2]->type == IDL_TYP_FLOAT)) {
+		float value_float;
+		attr_type = NX_FLOAT32;
+     	IDL_ENSURE_SCALAR(argv[2]);
+		value_float =  IDL_DoubleScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_float, length, attr_type);
+
+    } else if ((attr_type == NX_FLOAT64) && (argv[2]->type == IDL_TYP_DOUBLE)) {
+		double value_double;
+		attr_type = NX_FLOAT64;
+		IDL_ENSURE_SCALAR(argv[2]);
+		value_double =  IDL_DoubleScalar(argv[2]);
+		status = NXputattr (hHandle, attr_name, &value_double, length, attr_type);
+
+    } else {
+
+    char statusBuffer[100];
+	sprintf(statusBuffer,"Attribute type type doesn't match with the NeXus type: %i", attr_type );
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, statusBuffer);
+	return IDL_GettmpInt(NX_ERROR);
+    }
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXgetattr
+ * status = NXgetattr (file_id, attr_name, value, length, type)
+ *=======================================================================*/
+
+static IDL_VPTR NXgetattr_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status = 1;
+  int length, attr_type;
+  IDL_LONG dims[IDL_MAX_ARRAY_DIM];
+  IDL_VPTR r_value = 0, r_lenght;
+  char* attr_name;
+  char* attrtype;
+  char* value_str;
+  void *value;
+
+  if (argc != 5) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Five arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_SIMPLE(argv[3]);
+  IDL_ENSURE_SCALAR(argv[3]);
+
+  if (argv[3]->type != IDL_TYP_LONG) {
+  	if(argv[3]->type != IDL_TYP_INT) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Long or Int type argument required in lenght");
+		return IDL_GettmpInt(NX_ERROR);
+  		}
+  }
+
+/*  IDL_ENSURE_STRING(argv[4]); */
+  IDL_ENSURE_SCALAR(argv[4]);
+
+   attr_name = IDL_VarGetString(argv[1]);
+
+  attr_type = datatypecheck(argv[4]);
+
+  if(attr_type == -1) return IDL_GettmpInt(NX_ERROR);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  length = (int ) IDL_LongScalar(argv[3]);
+
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+   if(attr_type == NX_CHAR) {
+
+		length++; /* Add space for string termination */
+		NXmalloc((void**)&value_str, 1, &length, attr_type);
+  		status = NXgetattr (hHandle, attr_name, value_str, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_StrToSTRING(value_str);
+		NXfree((void**)&value_str);
+	}
+   else if(attr_type == NX_INT8) {
+		IDL_INT value_int;
+		/* There is no equivalent of this datatype in the IDL side
+		   returning type Int */
+
+		status = NXgetattr (hHandle, attr_name, &value_int, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_GettmpUInt(value_int);
+	}
+   else if(attr_type == NX_UINT8) {
+   		UCHAR value_uchar;
+		status = NXgetattr (hHandle, attr_name, &value_uchar, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		/* Why a warning?
+		 * Gives a warning in gcc and doesn't compile in ms. visual c
+		 * r_value = IDL_GettmpUChar(value_uchar); Return type int.
+		 */
+
+		r_value = IDL_GettmpInt(value_uchar);
+	}
+   else if(attr_type == NX_INT16) {
+   		IDL_INT value_int;
+		status = NXgetattr (hHandle, attr_name, &value_int, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_GettmpInt(value_int);
+	}
+   else if(attr_type == NX_UINT16) {
+   		IDL_UINT value_uint;
+		status = NXgetattr (hHandle, attr_name, &value_uint, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_GettmpUInt(value_uint);
+	}
+   else if(attr_type == NX_INT32) {
+   		IDL_LONG value_long;
+		status = NXgetattr (hHandle, attr_name, &value_long, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_GettmpLong(value_long);
+	}
+   else if(attr_type == NX_UINT32) {
+   		IDL_ULONG value_ulong;
+		status = NXgetattr (hHandle, attr_name, &value_ulong, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_GettmpULong(value_ulong);
+	}
+   else if(attr_type == NX_FLOAT32) {
+   		float value_float;
+		status = NXgetattr (hHandle, attr_name, &value_float, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_Gettmp();
+		r_value->type = IDL_TYP_FLOAT;
+		r_value->value.f = value_float;
+
+	}
+   else if(attr_type == NX_FLOAT64) {
+   		double value_double;
+		status = NXgetattr (hHandle, attr_name,  &value_double, &length, &attr_type);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    }
+		r_value = IDL_Gettmp();
+		r_value->type = IDL_TYP_DOUBLE;
+		r_value->value.d = value_double;
+	}
+
+
+  r_lenght = IDL_GettmpInt((IDL_INT)length);
+  IDL_VarCopy(r_value, argv[2]);
+  IDL_VarCopy(r_lenght, argv[3]);
+
+  return IDL_GettmpInt(status);
+}
+
+void releaseMemory( UCHAR * memPtr)
+{
+//	free(memPtr);
+}
+
+/*======================================================================
+ * NXgetinfo
+ * status =  (file_id, rank, dimensions[], data_type)
+ *
+ *=======================================================================*/
+
+static IDL_VPTR NXgetinfo_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR r_rank, r_datatype, array;
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status, n;
+  int rank,  datatype;
+  int dimension[IDL_MAX_ARRAY_DIM];
+  NXlink data_id;
+  IDL_MEMINT dims[] = {IDL_MAX_ARRAY_DIM};
+  IDL_INT *data_area_pointer;
+
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Four arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+/*  status = NXgetdataID (hHandle, &data_id);
+  if(status == NX_ERROR) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dataset must be opened before nxinfo");
+		return IDL_GettmpInt(NX_ERROR);
+	  } */
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetinfo (hHandle, &rank, dimension, &datatype);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  r_datatype = IDL_GettmpInt((IDL_INT)datatype);
+  r_rank = IDL_GettmpInt((IDL_INT)rank);
+
+/*IDL_MakeTempArray returns the data area pointer as its value. Last argument 'array' is the IDL_VPTR of array */
+
+  data_area_pointer = (IDL_INT *)IDL_MakeTempArray((int)IDL_TYP_INT, 1, dims, IDL_ARR_INI_ZERO, &array);
+
+  /* Dimensions are reversed to switch from C's Column major order to IDL row major order */
+  for(n = 0; n < rank; n++) {
+	data_area_pointer[n] = dimension[(rank-1)-n];
+	}
+
+//data_area_pointer[0] = (IDL_INT)55;
+//*data_area_pointer = *number;
+//  malloc(data_area_pointer, array->value.arr->arr_len);
+
+//  memcpy(data_area_pointer, dimension, sizeof(int));
+
+  // Output arguments
+  IDL_VarCopy(r_rank, argv[1]);
+  IDL_VarCopy(array, argv[2]);
+  IDL_VarCopy(r_datatype, argv[3]);
+//  releaseMemory(number);
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXgetgroupinfo
+ * status = NXgetgroupinfo (file_id, item_number, group_name, group_class)
+ *=======================================================================*/
+
+static IDL_VPTR NXgetgroupinfo_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR IDL_group_name, IDL_group_class, IDL_item_number;
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int item_number;
+
+/* Of the top of my head: 100.. What is the actual maximum lenght*/
+  char group_name[100];
+  char group_class[100];
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Four arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetgroupinfo(hHandle, &item_number, group_name, group_class);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  IDL_item_number = IDL_GettmpInt((IDL_INT)item_number);
+
+  IDL_group_name = IDL_StrToSTRING(group_name);
+  IDL_group_class = IDL_StrToSTRING(group_class);
+
+  /* Output arguments */
+  IDL_VarCopy(IDL_item_number, argv[1]);
+  IDL_VarCopy(IDL_group_name, argv[2]);
+  IDL_VarCopy(IDL_group_class, argv[3]);
+
+  return IDL_GettmpInt(status);
+}
+/*======================================================================
+ * NXinitgroupdir
+ * status = NXinitgroupdir (file_id)
+ * Not tested at all yet..
+ *=======================================================================*/
+
+static IDL_VPTR NXinitgroupdir_this(int argc, IDL_VPTR *argv)
+{
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One argument expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXinitgroupdir(hHandle);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXgetnextentry
+ * status = NXgetnextentry (file_id, name, class, data_type)
+ *=======================================================================*/
+
+static IDL_VPTR NXgetnextentry_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR IDL_group_name, IDL_group_class, IDL_data_type;
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+/* Too long or long enough*/
+  char group_name[255];
+  char group_class[255];
+  int data_type = 0;
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Four arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetnextentry(hHandle, group_name, group_class, &data_type);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  IDL_data_type = IDL_GettmpInt((IDL_INT)data_type);
+
+  IDL_group_name = IDL_StrToSTRING(group_name);
+  IDL_group_class = IDL_StrToSTRING(group_class);
+
+  /* Output arguments*/
+  IDL_VarCopy(IDL_group_name, argv[1]);
+  IDL_VarCopy(IDL_group_class, argv[2]);
+  IDL_VarCopy(IDL_data_type, argv[3]);
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXgetattrinfo
+ * status = NXgetattrinfo (file_id, attr_number)
+ *=======================================================================*/
+
+static IDL_VPTR NXgetattrinfo_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR IDL_attr_number;
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int attr_number = 0;
+
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetattrinfo (hHandle, &attr_number);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  IDL_attr_number = IDL_GettmpInt((IDL_INT)attr_number);
+
+  /* Output arguments*/
+  IDL_VarCopy(IDL_attr_number, argv[1]);
+
+  return IDL_GettmpInt(status);
+}
+/*======================================================================
+ * NXinitattrdir
+ * status = NXinitattrdir (file_id)
+ *=======================================================================*/
+
+static IDL_VPTR NXinitattrdir_this(int argc, IDL_VPTR *argv)
+{
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+
+  NXMSetError(NULL,idlError);
+
+  status = NXinitattrdir (hHandle);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXgetnextattr
+ * status = NXgetnextattr (file_id, attr_name, length, attr_type)
+ *=======================================================================*/
+
+static IDL_VPTR NXgetnextattr_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR IDL_attr_name = NULL, IDL_length= NULL, IDL_attr_type = NULL;
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+/* Too long or long enough*/
+  char attr_name[150];
+  int length = 0;
+  int attr_type = 0;
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Four arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetnextattr (hHandle, attr_name, &length, &attr_type);
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+  if(status == NX_EOD) {
+  	  IDL_attr_name = IDL_StrToSTRING("");
+	  IDL_length = IDL_GettmpInt((IDL_INT)0);
+	  IDL_attr_type = IDL_GettmpInt((IDL_INT)0);
+
+  }
+
+  if(status == NX_OK) {
+  IDL_attr_name = IDL_StrToSTRING(attr_name);
+  IDL_length = IDL_GettmpInt((IDL_INT)length);
+  IDL_attr_type = IDL_GettmpInt((IDL_INT)attr_type);
+  }
+
+  /* Output arguments*/
+  IDL_VarCopy(IDL_attr_name, argv[1]);
+  IDL_VarCopy(IDL_length, argv[2]);
+  IDL_VarCopy(IDL_attr_type, argv[3]);
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXgetgroupID
+ * statusstatus = NXgetgroupID (file_id, group_id)
+ *======================================================================*/
+static IDL_VPTR NXgetgroupID_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR result;
+  int status, iHandle, iLink;
+  NXaccess am;
+  int fileid;
+  NXhandle hHandle;
+  NXlink *group_id = NULL;
+
+  /* If number of arguments is not 2 return status NX_ERROR */
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  group_id = (NXlink *)malloc(sizeof(NXlink));
+  if(group_id == NULL){
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unable to allocate memory for the group id link file");
+  	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetgroupID (hHandle, group_id);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  iLink = HHMakeLinkHandle(group_id, fileid);
+     if(iLink == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Error creating the link handle");
+		return IDL_GettmpInt(NX_ERROR);
+	}
+
+  result = IDL_GettmpInt(iLink);
+
+  // Output argument
+  IDL_VarCopy(result, argv[1]);
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXgetdataID
+ * status = NXgetdataID (file_id, data_id)
+ *======================================================================*/
+static IDL_VPTR NXgetdataID_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR result;
+  int status, iHandle, iLink;
+  NXaccess am;
+  int fileid;
+  NXhandle hHandle;
+  NXlink *data_id = NULL;
+
+  /* If number of arguments is not 2 return status NX_ERROR */
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  data_id = (NXlink *)malloc(sizeof(NXlink));
+  if(data_id == NULL){
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unable to allocate memory for the data id link file");
+  	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  NXMSetError(NULL,idlError);
+
+  status = NXgetdataID (hHandle, data_id);
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  iLink = HHMakeLinkHandle(data_id, fileid);
+
+    if(iLink == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Error creating the link handle");
+		return IDL_GettmpInt(NX_ERROR);
+	}
+
+  result = IDL_GettmpInt(iLink);
+
+  // Output argument
+  IDL_VarCopy(result, argv[1]);
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXgetdata
+ * status = NXgetdata (file_id, data)
+ *=======================================================================*/
+
+static IDL_VPTR NXgetdata_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR data_array;
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int rank,  datatype, n;
+/*int dimension[IDL_MAX_ARRAY_DIM]; */
+/*  int dimension[8]; */
+  IDL_ARRAY_DIM dimension;
+  int data_area_pointer[NX_MAXRANK];
+  void *data_buffer = NULL;
+  char *char_buffer;
+  NXlink data_id;
+
+
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int ) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+
+  hHandle = HHGetPointer(fileid);
+
+/*  status = NXgetdataID (hHandle, &data_id);
+  if(status == NX_ERROR) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dataset must be opened before nxputdata");
+		return IDL_GettmpInt(NX_ERROR);
+		} */
+
+  NXMSetError(NULL,idlError);
+
+  /* First get the rank, dimension and datatype */
+  status = NXgetinfo (hHandle, &rank, data_area_pointer, &datatype);
+  if(status == NX_ERROR) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  /* Dimensions are reversed to switch from C's Column major order to IDL row major order */
+  for(n = 0; n < rank; n++) {
+	dimension[n] = data_area_pointer[rank - 1 -n];
+	}
+
+/* Check data type and prepare a Array or a String for NeXuS API nxgetdata function*/
+   switch (datatype) {
+	case NX_CHAR:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXCHAR");*/
+
+	break;
+	case NX_FLOAT32:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXFLOAT32");*/
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_FLOAT, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_FLOAT64:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXFLOAT64");*/
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_DOUBLE, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_INT8:
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "This data type is not supported in IDL");
+//		return IDL_GettmpInt(NX_ERROR);
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_BYTE, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+		/* This data type is not supported in IDL, A dangerous conversion to IDL_TYP_INT? */
+	break;
+	case NX_UINT8:
+		/*	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXUINT8"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_BYTE, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_INT16:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXINT16"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_INT, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_UINT16:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXINT16"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_UINT, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_INT32:
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXINT32");
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_LONG, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_UINT32:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXUINT32");*/
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_ULONG, rank, dimension, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	default:
+		/*IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Data is of an unknown datatype");*/
+		return IDL_GettmpInt(NX_ERROR);
+	break;
+	}
+
+  NXMSetError(NULL,idlError);
+
+if(datatype == NX_CHAR) {
+ 	status =  NXmalloc ((void **) &char_buffer, rank, data_area_pointer, 
+			    datatype);
+        if(status == NX_ERROR){
+ 		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+    		}
+
+	status = NXgetdata (hHandle, char_buffer);
+        if(status == NX_ERROR){
+ 		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+		}
+	data_array = IDL_StrToSTRING(char_buffer);
+	IDL_VarCopy(data_array, argv[1]);
+	NXfree((void **) &char_buffer);
+   }
+else {
+
+	status = NXgetdata (hHandle, data_buffer);
+        if(status == NX_ERROR){
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+	}
+
+   IDL_VarCopy(data_array, argv[1]);
+
+   }
+
+/* For temporary variables VarCopy copies the dynamic part to destination, not the actual data.
+ * So not really slower and a lot safer than writing the data straight to argv[1].
+ *
+ *External Development Guide: IDL Internals: Variables
+ * Copying Variables:
+ *If the source is a temporary variable, IDL_VarCopy() does not make a duplicate of the dynamic
+ *part for the destination. Instead, the dynamic part of the source is given to the destination,
+ *and the source variable itself is returned to the pool of free temporary variables. This is the
+ *equivalent of freeing the temporary variable. Therefore, the variable must not be used any
+ *further and the caller should not explicitly free the variable. This optimization significantly
+ *improves resource utilization and performance because this special case occurs frequently.
+ */
+
+  return IDL_GettmpInt(status);
+}
+/*======================================================================
+ * NXgetslab
+ * status = NXgetslab (file_id, data, start[], size[])
+ *=======================================================================*/
+
+static IDL_VPTR NXgetslab_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR data_array;
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int rank,  datatype, n;
+  IDL_MEMINT start[NX_MAXRANK], size[NX_MAXRANK], dim[NX_MAXRANK];
+  int istart[NX_MAXRANK], isize[NX_MAXRANK];
+  IDL_LONG *stDim, *szDim;
+  IDL_ARRAY_DIM dimension;
+  void *data_buffer = NULL;
+
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Four arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_ARRAY(argv[2]);
+  IDL_ENSURE_ARRAY(argv[3]);
+
+  /*Check that the arrays are type long */
+
+  if(argv[2]->type != IDL_TYP_LONG) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Argument 3, slap start, Array must be type long");
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  if(argv[3]->type != IDL_TYP_LONG) {
+  	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Argument 4, slap size: Array must be type long");
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+/*  status = NXgetdataID (hHandle, &data_id);
+  if(status == NX_ERROR) {
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Dataset must be opened before nxputdata");
+		return IDL_GettmpInt(NX_ERROR);
+	      } */
+
+  /* First get the rank, dimension and datatype */
+  status = NXgetinfo (hHandle, &rank, dim, &datatype);
+  if(status == NX_ERROR) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  /* swap dimensions again */
+  stDim = (IDL_LONG *)argv[2]->value.arr->data;
+  szDim = (IDL_LONG *)argv[3]->value.arr->data;
+  for(n = 0; n < rank; n++){
+    start[n] = stDim[rank -n  -1];
+    istart[n] = stDim[rank -n  -1];
+    size[n] = szDim[rank -n  -1];
+    isize[n] = szDim[rank -n  -1];
+  }
+
+
+/* Check data type and prepare a Array or a String for NeXuS API nxgetdata function*/
+   switch (datatype) {
+	case NX_CHAR:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXCHAR"); */
+
+	break;
+	case NX_FLOAT32:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXFLOAT32"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_FLOAT, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_FLOAT64:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXFLOAT64"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_DOUBLE, rank, (void *) size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_INT8:
+		/* This data type is not supported in IDL, A dangerous conversion to IDL_TYP_INT? */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_BYTE, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_UINT8:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXUINT8"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_BYTE, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_INT16:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXINT16"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_INT, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_UINT16:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXUINT16"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_UINT, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	case NX_INT32:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXINT32"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_LONG, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+
+	break;
+	case NX_UINT32:
+		/* IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NXUINT32"); */
+		data_buffer = (void *)IDL_MakeTempArray(IDL_TYP_ULONG, rank, (void *)size, IDL_ARR_INI_ZERO, &data_array);
+	break;
+	default:
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Data in the NeXus file is of an unknown datatype");
+		return IDL_GettmpInt(NX_ERROR);
+	break;
+	}
+
+  NXMSetError(NULL,idlError);
+
+   if(datatype == NX_CHAR) {
+	/* Api doesnt support getslab for textdata!
+	 *
+	 * Currently The C Api returns the correct string slab put mixes something up badly
+	 * and program crashes at some point.
+	 * */
+
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "NeXus IDL API doesn't support textdata for getslab ");
+	return IDL_GettmpInt(NX_ERROR);
+
+/*	char* char_buffer;
+
+	status =  NXmalloc ((void **) &char_buffer, rank, argv[3]->value.arr->data, datatype);
+    if(status == NX_ERROR){
+ 		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+    	}
+
+	status = NXgetslab (hHandle, char_buffer, (int *) argv[2]->value.arr->data, (int *) argv[3]->value.arr->data);
+	 if(status == NX_ERROR){
+ 		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+    	}
+
+	IDL_char_data = IDL_StrToSTRING(char_buffer);
+	IDL_VarCopy(IDL_char_data, argv[1]);
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Debug 3 zz");
+
+    if(status == NX_ERROR){
+ 		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+    	}
+*/
+     }
+
+  else {
+	  status = NXgetslab (hHandle, data_buffer, istart, isize);
+	  if(status == NX_ERROR)
+		{
+		IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+		return IDL_GettmpInt(NX_ERROR);
+    	}
+   	  IDL_VarCopy(data_array, argv[1]);
+   }
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXflush
+ * status = NXflush (file_id)
+ *======================================================================*/
+static IDL_VPTR NXflush_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR result;
+  int status, iHandle;
+  NXaccess am;
+  int fileid;
+  NXhandle hHandle;
+
+  /* If number of arguments is not 1 return status NX_ERROR */
+  if (argc != 1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "One argument expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+
+  NXMSetError(NULL,idlError);
+
+  status = NXflush (&hHandle);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+/* We don't loose the links with HHChangeHandle */
+  HHChangeHandle(hHandle, fileid);
+
+  result = IDL_GettmpLong(fileid);
+
+  // Output argument
+  IDL_VarCopy(result, argv[0]);
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * Nxinquirefile
+ * status = NXinquirefile(handle,filename, filenameLength)
+ *=======================================================================*/
+
+static IDL_VPTR NXinquirefile_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR IDL_filename;
+  IDL_INT fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+
+/* Max file name lenght in mac os, unix, linux, windows */
+  char filename[254];
+  int filenameLength;
+
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_SCALAR(argv[2]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+  filenameLength =  IDL_LongScalar(argv[2]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXinquirefile(hHandle, filename, filenameLength);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  IDL_filename = IDL_StrToSTRING(filename);
+
+  /* Output arguments*/
+  IDL_VarCopy(IDL_filename, argv[1]);
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXmakelink
+ * status = NXmakelink (file_id, link)
+ *======================================================================*/
+static IDL_VPTR NXmakelink_this(int argc, IDL_VPTR *argv)
+{
+  int status, iHandle, iLink;
+  NXaccess am;
+  int fileid, linkid;
+  NXhandle hHandle;
+  NXlink *link;
+
+  /* If number of arguments is not 2 return status NX_ERROR */
+  if (argc != 2) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Two arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+
+  fileid = (int) IDL_LongScalar(argv[0]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  linkid = (int) IDL_LongScalar(argv[1]);
+
+  if(HHCheckIfHandleExists(linkid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown link id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  link = (NXlink *)HHGetPointer(linkid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXmakelink (hHandle, link);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+/* Commented, No output arguments in makelink
+
+  iLink = HHMakeHandle(link);
+
+  result = IDL_GettmpInt(iLink);
+
+  // Output argument
+  IDL_VarCopy(result, argv[1]); */
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXmakenamedlink
+ * status = NXmakenamedlink (file_id, nameoflink, link)
+ *======================================================================*/
+static IDL_VPTR NXmakenamedlink_this(int argc, IDL_VPTR *argv)
+{
+
+  int status, iHandle, iLink;
+  NXaccess am;
+  int fileid, linkid;
+  NXhandle hHandle;
+  NXlink *link;
+  char* nameoflink;
+
+  /* If number of arguments is not 3 return status NX_ERROR */
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_SCALAR(argv[2]);
+  fileid = (int) IDL_LongScalar(argv[0]);
+  nameoflink = IDL_VarGetString(argv[1]);
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+  linkid = (int) IDL_LongScalar(argv[2]);
+
+  if(HHCheckIfHandleExists(linkid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown link id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  link = (NXlink *)HHGetPointer(linkid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXmakenamedlink (hHandle, nameoflink, link);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXlinkexternal
+ * status = NXlinkexternal(handle, name, nxclass, nxurl)
+ *=======================================================================*/
+
+static IDL_VPTR NXlinkexternal_this(int argc, IDL_VPTR *argv)
+{
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  char* name;
+  char* nxclass;
+  char* nxurl;
+
+  if (argc != 4) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_STRING(argv[2]);
+  IDL_ENSURE_STRING(argv[3]);
+
+  fileid = (int)IDL_LongScalar(argv[0]);
+  name = IDL_VarGetString(argv[1]);
+  nxclass = IDL_VarGetString(argv[2]);
+  nxurl = IDL_VarGetString(argv[3]);
+
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXlinkexternal(hHandle, name, nxclass, nxurl);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+
+  return IDL_GettmpInt(status);
+}
+
+
+/*======================================================================
+ * NXisexternalgroup
+ * status = NXisexternalgroup(handle,name, nxclass, nxurl, nxurllen)
+ *=======================================================================*/
+
+static IDL_VPTR NXisexternalgroup_this(int argc, IDL_VPTR *argv)
+{
+  IDL_VPTR IDL_NXurl;
+  int fileid;
+  NXhandle hHandle;
+  int iHandle, status;
+  int nxurllen;
+  char* name;
+  char* nxclass;
+  char* nxurl;
+  if (argc != 5) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Five arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_STRING(argv[1]);
+  IDL_ENSURE_STRING(argv[2]);
+  IDL_ENSURE_SCALAR(argv[4]);
+
+  fileid = (int )IDL_LongScalar(argv[0]);
+  name = IDL_VarGetString(argv[1]);
+  nxclass = IDL_VarGetString(argv[2]);
+  nxurllen =  IDL_LongScalar(argv[4]);
+
+		nxurllen++; /* Add space for string termination */
+		status = NXmalloc((void**)&nxurl, 1, &nxurllen, NX_CHAR);
+  		if(status == NX_ERROR){
+ 			IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+			return IDL_GettmpInt(NX_ERROR);
+	    	}
+
+
+
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  hHandle = HHGetPointer(fileid);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXisexternalgroup(hHandle, name, nxclass, nxurl, nxurllen);
+
+  NXfree((void**)&nxurl);
+
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+ 	IDL_NXurl = IDL_StrToSTRING("");
+ 	IDL_VarCopy(IDL_NXurl, argv[3]);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  IDL_NXurl = IDL_StrToSTRING(nxurl);
+
+  /* Output arguments*/
+  IDL_VarCopy(IDL_NXurl, argv[3]);
+
+  return IDL_GettmpInt(status);
+}
+
+/*======================================================================
+ * NXsameID
+ * status = NXsameID (file_id, link1, link2)
+ *======================================================================*/
+static IDL_VPTR NXsameID_this(int argc, IDL_VPTR *argv)
+{
+
+
+  int status, iHandle, iLink;
+  NXaccess am;
+  int fileid, linkid_one, linkid_two;
+  NXhandle hHandle;
+  NXlink *link_one, *link_two;
+
+  if (argc != 3) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Three arguments expected");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  IDL_ENSURE_SCALAR(argv[0]);
+  IDL_ENSURE_SCALAR(argv[1]);
+  IDL_ENSURE_SCALAR(argv[2]);
+
+  fileid = (int ) IDL_LongScalar(argv[0]);
+  linkid_one = (int ) IDL_LongScalar(argv[1]);
+  linkid_two = (int ) IDL_LongScalar(argv[2]);
+
+  if(HHCheckIfHandleExists(fileid) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Unknown file id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+  hHandle = HHGetPointer(fileid);
+
+
+  if(HHCheckIfHandleExists(linkid_one) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Argument 2, Unknown link id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  link_one = (NXlink *)HHGetPointer(linkid_one);
+
+  if(HHCheckIfHandleExists(linkid_two) == -1) {
+	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Argument 3, Unknown link id");
+	return IDL_GettmpInt(NX_ERROR);
+	}
+
+  link_two = (NXlink *)HHGetPointer(linkid_two);
+
+  NXMSetError(NULL,idlError);
+
+  status = NXsameID (hHandle, link_one, link_two);
+  if(status == NX_ERROR){
+ 	IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, nexusError);
+	return IDL_GettmpInt(NX_ERROR);
+  }
+
+  return IDL_GettmpInt(1);
+
+}
+
+
+int IDL_Load(void)
+{
+  /*
+   * These tables contain information on the functions and procedures
+   * that make up the NeXusIDL-API DLM. The information contained in these
+   * tables must be identical to that contained in NeXusIDL-API.dlm.
+   */
+  static IDL_SYSFUN_DEF2 function_addr[] = {
+    { NXopen_this, "NXOPEN", 0, IDL_MAXPARAMS, 0, 0},
+    { NXclose_this, "NXCLOSE", 0, IDL_MAXPARAMS, 0, 0},
+    { NXsetnumberformat_this, "NXSETNUMBERFORMAT", 0, IDL_MAXPARAMS, 0, 0},
+    { NXopenpath_this, "NXOPENPATH", 0, IDL_MAXPARAMS, 0, 0},
+    { NXopengrouppath_this, "NXOPENGROUPPATH", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetpath_this, "NXGETPATH", 0, IDL_MAXPARAMS, 0, 0},
+    { NXmakegroup_this, "NXMAKEGROUP", 0, IDL_MAXPARAMS, 0, 0},
+    { NXopengroup_this, "NXOPENGROUP", 0, IDL_MAXPARAMS, 0, 0},
+	{ NXcompress_this, "NXCOMPRESS", 0, IDL_MAXPARAMS, 0, 0},
+    { NXclosegroup_this, "NXCLOSEGROUP", 0, IDL_MAXPARAMS, 0, 0},
+    { NXmakedata_this, "NXMAKEDATA", 0, IDL_MAXPARAMS, 0, 0},
+    { NXcompmakedata_this, "NXCOMPMAKEDATA", 0, IDL_MAXPARAMS, 0, 0},
+    { NXputdata_this, "NXPUTDATA", 0, IDL_MAXPARAMS, 0, 0},
+    { NXputslab_this, "NXPUTSLAB", 0, IDL_MAXPARAMS, 0, 0},
+    { NXputattr_this, "NXPUTATTR", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetattr_this, "NXGETATTR", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetinfo_this, "NXGETINFO", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetgroupinfo_this, "NXGETGROUPINFO", 0, IDL_MAXPARAMS, 0, 0},
+    { NXinitgroupdir_this, "NXINITGROUPDIR", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetnextentry_this, "NXGETNEXTENTRY", 0, IDL_MAXPARAMS, 0, 0},
+    { NXinitattrdir_this, "NXINITATTRDIR", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetattrinfo_this, "NXGETATTRINFO", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetnextattr_this, "NXGETNEXTATTR", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetgroupID_this, "NXGETGROUPID", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetdataID_this, "NXGETDATAID", 0, IDL_MAXPARAMS, 0, 0},
+    { NXopendata_this, "NXOPENDATA", 0, IDL_MAXPARAMS, 0, 0},
+    { NXclosedata_this, "NXCLOSEDATA", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetdata_this, "NXGETDATA", 0, IDL_MAXPARAMS, 0, 0},
+    { NXgetslab_this, "NXGETSLAB", 0, IDL_MAXPARAMS, 0, 0},
+    { NXflush_this, "NXFLUSH", 0, IDL_MAXPARAMS, 0, 0},
+    { NXinquirefile_this, "NXINQUIREFILE", 0, IDL_MAXPARAMS, 0, 0},
+    { NXmakelink_this, "NXMAKELINK", 0, IDL_MAXPARAMS, 0, 0},
+    { NXmakenamedlink_this, "NXMAKENAMEDLINK", 0, IDL_MAXPARAMS, 0, 0},
+    { NXlinkexternal_this, "NXLINKEXTERNAL", 0, IDL_MAXPARAMS, 0, 0},
+    { NXisexternalgroup_this, "NXISEXTERNALGROUP", 0, IDL_MAXPARAMS, 0, 0},
+    { NXsameID_this, "NXSAMEID", 0, IDL_MAXPARAMS, 0, 0}
+  };
+
+  /* 
+   * Create a message block to hold our messages. Save its handle where
+   * the other routines can access it.
+   */
+  if (!(msg_block = IDL_MessageDefineBlock("NeXusIDL-API",
+					   IDL_CARRAY_ELTS(msg_arr), msg_arr)))
+    return IDL_FALSE;
+
+  /*
+   * Register our routine. The routines must be specified exactly the same
+   * as in NeXusIDL-API.dlm.
+   */
+
+   IDL_SysRtnAdd(function_addr, TRUE, IDL_CARRAY_ELTS(function_addr));
+
+   return IDL_TRUE;
+}
diff --git a/bindings/idl/NeXusIDL-API.def b/bindings/idl/NeXusIDL-API.def
new file mode 100644
index 0000000..fbd2f9d
--- /dev/null
+++ b/bindings/idl/NeXusIDL-API.def
@@ -0,0 +1,4 @@
+LIBRARY			testmodule
+DESCRIPTION		'Demonstrates use of IDL Dynamic Loadable Modules'
+
+EXPORTS			IDL_Load		@1
diff --git a/bindings/idl/NeXusIDL-API.dlm b/bindings/idl/NeXusIDL-API.dlm
new file mode 100644
index 0000000..a0e21bd
--- /dev/null
+++ b/bindings/idl/NeXusIDL-API.dlm
@@ -0,0 +1,40 @@
+MODULE NeXusIDL-API
+DESCRIPTION DLM file for NeXusIDL-API
+VERSION 1.0
+SOURCE Research Systems, Inc.
+FUNCTION 	NXOPEN 0	IDL_MAXPARAMS
+FUNCTION 	NXCLOSE 0 	IDL_MAXPARAMS
+FUNCTION 	NXSETNUMBERFORMAT 0 	IDL_MAXPARAMS
+FUNCTION	NXOPENPATH 0	IDL_MAXPARAMS
+FUNCTION	NXOPENGROUPPATH 0	IDL_MAXPARAMS
+FUNCTION	NXGETPATH       0	IDL_MAXPARAMS
+FUNCTION	NXMAKEGROUP 0	IDL_MAXPARAMS
+FUNCTION	NXCLOSEGROUP 0	IDL_MAXPARAMS
+FUNCTION	NXMAKEDATA 0	IDL_MAXPARAMS
+FUNCTION	NXCOMPMAKEDATA 0	IDL_MAXPARAMS
+FUNCTION	NXPUTDATA 0	IDL_MAXPARAMS
+FUNCTION	NXPUTSLAB 0	IDL_MAXPARAMS
+FUNCTION	NXPUTATTR 0	IDL_MAXPARAMS
+FUNCTION	NXGETATTR 0	IDL_MAXPARAMS
+FUNCTION	NXOPENGROUP 0	IDL_MAXPARAMS
+FUNCTION        NXGETINFO 0   	IDL_MAXPARAMS
+FUNCTION        NXGETGROUPINFO 0	IDL_MAXPARAMS
+FUNCTION	NXINITGROUPDIR 0	IDL_MAXPARAMS
+FUNCTION	NXGETNEXTENTRY 0	IDL_MAXPARAMS
+FUNCTION	NXGETATTRINFO 0		IDL_MAXPARAMS
+FUNCTION 	NXGETNEXTATTR 0 IDL_MAXPARAMS
+FUNCTION 	NXGETGROUPID 0 IDL_MAXPARAMS
+FUNCTION 	NXGETDATAID 0 IDL_MAXPARAMS
+FUNCTION        NXOPENDATA 0	IDL_MAXPARAMS
+FUNCTION        NXCOMPRESS 0	IDL_MAXPARAMS
+FUNCTION        NXCLOSEDATA 0	IDL_MAXPARAMS
+FUNCTION 	NXGETDATA 0 	IDL_MAXPARAMS
+FUNCTION 	NXGETSLAB 0 	IDL_MAXPARAMS
+FUNCTION 	NXFLUSH 0 	IDL_MAXPARAMS
+FUNCTION 	NXINQUIREFILE 0	IDL_MAXPARAMS
+FUNCTION 	NXMAKELINK 0	IDL_MAXPARAMS
+FUNCTION 	NXMAKENAMEDLINK 0	IDL_MAXPARAMS
+FUNCTION 	NXLINKEXTERNAL 0	IDL_MAXPARAMS
+FUNCTION 	NXISEXTERNALGROUP 0	IDL_MAXPARAMS
+FUNCTION 	NXSAMEID 0	IDL_MAXPARAMS
+
diff --git a/bindings/idl/NeXusIDL-API.export b/bindings/idl/NeXusIDL-API.export
new file mode 100644
index 0000000..31114a6
--- /dev/null
+++ b/bindings/idl/NeXusIDL-API.export
@@ -0,0 +1 @@
+IDL_Load
diff --git a/bindings/idl/README.html b/bindings/idl/README.html
new file mode 100644
index 0000000..7660c54
--- /dev/null
+++ b/bindings/idl/README.html
@@ -0,0 +1,1951 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<head>
+<title>
+Nexus-API IDL - README
+</title>
+</head>
+
+<body>
+<!-- start content -->
+
+<h1>Nexus-API IDL - README </h1>
+<hr>
+<table id="toc" class="toc" summary="Contents"><tbody><tr><td><h2>Contents</h2> </a>
+
+<ul>
+
+<li ><a href="#Overview">1. Overview</a>
+<ul> </ul>
+
+<li ><a href="#Installation">2. Installation</a>
+<ul>
+
+<li ><a href="#Requirements">2.1 Requirements</a></li>
+<li><a href="#Building and Installing">2.2 Building and Installing </a></li>
+<li><a href="#Linux">2.3 Linux </a></li>
+<li><a href="#Windows">2.4 Windows </a></li>
+
+</ul>
+
+<li ><a href="#Using API from IDL">3. Using API from IDL</a>
+<ul>
+
+<li ><a href="#Installing a New DLM File To IDL">3.1 Installing a New DLM File To IDL </a></li>
+<li><a href="#Test Files">3.2 Test Files </a></li>
+<li><a href="#Using The API And An Example">3.3 Using The API And An Example</a></li>
+<li><a href="#NeXus IDL API Routines">3.4 NeXus IDL API Routines</a></li>
+
+
+</ul>
+</ul>
+
+
+<a name="#Overview"></a><h2> Overview</h2>
+
+<p>NeXus IDL Api binds the NeXus libraries to IDL (Interactive Data Language). It brings functionality of the NeXus API to IDL for reading, writing and modifying NeXus Files. IDL NeXus API imitates the functionality NeXus API with few exeptions discussed later.
+
+<p>Information on NeXus Dataformat: <A HREF="http://www.nexusformat.org/Introduction">http://www.nexusformat.org/Introduction</A>.
+</p>
+<p>
+Information on IDL: <A HREF="http://www.ittvis.com/">http://www.nexusformat.org/Introduction</A>.
+</p>
+
+
+<p><br> </p>
+
+<a name="Installation"></a><h2> Installation</h2>
+
+<a name="Requirements"></a><h3> Requirements</h3>
+<p>
+
+Precompiled versions of the DLM (Dynamic Link Module) for Windows (NeXusIDL-API.dll) and Linux (NeXusIDL-API.so) are 
+included in the package. If you want to build the DLM a C compiler is required. GCC for Linux and Microsoft Visual C++ 
+version 6 have been tested. IDL (ver 6) and the latest NeXus API are required.
+
+<p>  The NeXus packages and installation instructions are available at
+<A HREF="http://www.nexusformat.org/Download">http://www.nexusformat.org/Download</A>. </p>
+
+<p> Microsoft offers a free Microsoft C Compiler Toolkit to Compile DLMs for IDL on Windows
+<A HREF="http://msdn.microsoft.com/visualc/vctoolkit2003/"> http://msdn.microsoft.com/visualc/vctoolkit2003/</A>
+</p>
+<P>For Windows the NeXus Data Format
+Windows Installer Kit, which includes the necessary hdf5, hdf4 and
+xml libraries, is recommended.
+<A HREF="http://download.nexusformat.org/kits/windows/">http://download.nexusformat.org/kits/windows/ </A></P>
+
+</p>
+
+<p>
+If the NeXus API header file napi.h is not installed in path you have to edit the correct path to #include list in NeXusIDL-API.c
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);">
+	<COL WIDTH=373>
+	<THEAD>
+		<TR>
+			<TD WIDTH=373 VALIGN=TOP>
+
+For linux: <br>
+#include "Nexus path/include/napi.h" <br>
+
+For windows: <br>
+#include "C:\Program Files\NeXus Data Format\include\napi.h" <br>
+			</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+
+</p>
+<a name="Linux"></a><h3> Linux</h3>
+<p>Edit correct IDL, HDF libraries and NeXus Library paths to Makefile.
+
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);">
+	<COL WIDTH=373>
+	<THEAD>
+		<TR>
+			<TD WIDTH=373 VALIGN=TOP>
+				#Configure these directories:
+				<P >IDL_DIR = /usr/pack/idl-6.3-vm/idl/</P>
+				<P >
+				</P>
+				<P >HDFROOT=/afs/psi.ch/project/sinq/sl-linux</P>
+				<P >
+				</P>
+				LIBNEXUS = ../../src/trunk/src/.libs/libNeXus.a
+			</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+</p>
+<p>
+Compile with 'make'.
+</p>
+
+<a name="Windows"></a><h3> Windows</h3>
+<p>
+Edit buildwin.bat and change the correct IDL and NeXus directories.
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+			<TD WIDTH=376 VALIGN=TOP>
+				REM Configure these directories:
+				<P>SET IDL_DIR=c:\rsi\idl63</P>
+				SET NXS_DIR= "C:\Program Files\NeXus Data Format"
+			</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+<p>
+
+
+The compiler and linker have to be set to a path. In Visual C++ they can be set with running the batch file in "Microsoft Visual C Directory\VC98\bin\vcvars32.bat". Run buildwin.bat to run build the API.
+
+</p>
+</p>
+
+
+<p><br> </p>
+
+
+
+<a name="Using API from IDL"></a><h2> Using API from IDL</h2>
+
+<a name="Installing a New DLM File To IDL"></a><h3> Installing a New DLM File To IDL</h3>
+<p>Recommeneded way to install the DLM file (NeXusIDL-API.dlm) and the library (NeXusIDL-API.so or NeXusIDL-API.dll) is to copy them to one of the directories IDL searches at startup (and contained in the !IDL_PATH system variable). NOTE: The DLM file and the library must excist in the same directory.
+
+</p>
+<p>
+DLM's can be also loaded with the DLM_REGISTER command in IDL. Also IDL registeres all the DLM files that are located in the directory where it was started in. These options are only preferred for testing.
+
+</p>
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+			<TD WIDTH=376 VALIGN=TOP>
+				new_dlm_file = '/home/scratch/lns/kauppila/temp/IDLNeXus-API/IDLNeXus-API.dlm'
+				<p></p>
+				DLM_REGISTER, new_dlm_file
+			</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+<a name="Test Files"></a><h3> Test Files</h3>
+<p>
+
+<P>The IDLNeXus-API includes IDL files for testing write and read
+functions of the API. write_test.pro and read_test.pro provide
+identical functionality as in the orginal C api napi_test.h</P>
+<P>Testfiles write_test.pro and
+read_test.pro are included. After registering the DLM run in IDL:</P>
+
+<p><b>write_test.pro:</b> Writes a test NeXus file. Accessmethod can be assigned with parameters hdf5, hdf4 and xml. The error codes returned by the routines are printed to IDL console. 1 = NX_OK, 0 = NX_ERROR </p>
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+			<TD WIDTH=376 VALIGN=TOP>
+		write_test (Uses NeXus accessmode HDF5
+for default. Writes NXtest.h5)
+<P>write_test, hdf5 ;(Writes HDF5 file
+NXtest.h5)</P>
+<P>write_test, hdf4 ;(Writes HDF4 file
+NXtest.hdf)</P>
+write_test, xml ;(Writes XML file
+NXtest.xml)
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+<P><BR>
+</P>
+<P ><b>read_test: </b>reads the NXtest file produced by write_test and tests the reading functions. Results are printed to IDL console. </P>
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+		<TD WIDTH=376 VALIGN=TOP>
+		read_test ;(Uses NeXus accessmode HDF5
+for default. Reads NXtest.h5)
+<P>read_test, hdf5 ;(Reads HDF5 file
+NXtest.h5)</P>
+<P>read_test, hdf4 ;(Reads HDF4 file
+NXtest.hdf)</P>
+read_test, xml ;(Reads XML file
+NXtest.xml)
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+
+<P><b>recursiveread.pro: </b>Takes a NeXus
+supported file as a parameter and prints all the data and attributes
+of the file to IDL console.</P>
+
+</p>
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+		<TD WIDTH=376 VALIGN=TOP>
+		recursiveread ;(Prints default file
+Nxtest.h5)
+<P></P>recursiveread, nexusfile.nxs ;(Prints
+nexusfile.nxs)
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+
+<a name="Using The API And An Example"></a><h3> Using The API And An Example</h3> <p> The API's functions aim to reproduce 
+the funtionality of the C API closely. Some low level functionality has been hidden from the user. Memory allocation 
+functions NXmalloc and NXfree are done automatically in the API when needed. In the spirit of IDL, variables or arrays 
+retrieved with nxgetdata, nxgetslab or nxgetattr don't have to be datatyped beforehand. However when inputting data or 
+attributes with nxputdata, nxputslab or nxputattr the datatypes in IDL have to match with the datatype of the dataset which 
+is declared with nxmakedata or in the nxputattr parameters. The matching datatypes are:
+
+
+<TABLE BORDER=1 WIDTH=50% CELLPADDING=2 CELLSPACING=1 ALIGN=CENTER style="background-color: rgb(238, 238, 238);">
+	<COL WIDTH=373>
+	<THEAD>
+		<TR style="background-color: rgb(204, 204, 204);">
+		<TD WIDTH=373 VALIGN=TOP>
+		NeXus Datatype
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		Idl Datatype
+		</TD>
+
+		</TR>
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_CHAR
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		IDL_STRING
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_FLOAT32
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		float
+		</TD>
+		</TR>
+
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_FLOAT64
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		double
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_UINT8
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		IDL_CHAR
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_INT16
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		IDL_INT
+		</TD>
+		</TR>
+
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_UINT16
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		IDL_UINT
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_INT32
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		IDL_LONG
+		</TD>
+		</TR>
+
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_UINT32
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		IDL_ULONG
+		</TD>
+		</TR>
+
+	</THEAD>
+</TABLE>
+
+<p> <br> </p>
+Here is simple example program that demonstrates the basic functions and most important differences between the C Nexus Api and the IDL Nexus API. <br> 1. Creates a NeXus file with access method HDF5 <br>2. adds datagroups  <br>3. makes a data array of data type NX_INT32 <br>4. puts data to the array <br>5. reads the data and attributes <br>6. prints data and attribute value <br>7.closes the groups and the file.
+
+
+
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+		<TD WIDTH=376 VALIGN=TOP>
+	pro simpletest <br>
+	<b>; Accessmethod accepts strings or integer </b><br>
+	S = nxopen("test.h5","NXACC_CREATE5",fileid) <br>
+        S = nxmakegroup(fileid, "testgroup", "NXentry") <br>
+        S = nxopengroup(fileid, "testgroup", "NXentry") <br>
+        S = nxmakegroup(fileid, "anothergroup", "NXentry") <br>
+
+	<p>
+	<b>;Only type Long arrays are accepted for declaring dimensions with nxmakedata or nxputslab </b><br>
+	array =[4L,4L] ; Array Dimensions <br>
+        rank = 2 ; Array rank<br>
+	<b>;Datatype long data array </b><br>
+        data =[[0L,1L,2L,3L],[4L,5L,6L,7L],[8L,9L,10L,11L],[12L,13L,14L,15L] ] <br>
+
+	</p>
+	 <b>; Make a data set for the array with 4x4 elements, rank 2 and data type NX_INT32, which matches the IDL data type Long<br>
+	; Data type accepts strings or integer values.  </b><br>
+        S = nxmakedata(fileid, 'data1', 'NX_INT32', rank, array) <br>
+        S = nxopendata(fileid, "data1") <br>
+	S = nxputdata(fileid, data) <br>
+	<p></p>
+	<b>; IDL data type of the attribute has to match the NeXus data type assigned with parameter datatype<br>
+	; Here IDL UINT and NX_UINT16 </b> <br>
+	attributevalue = 42UINT <br>
+        S = nxputattr(fileid,'test-attribute', attributevalue, 1, 'NX_UINT16') <br>
+	S = nxclosedata(fileid) <br>
+	S = nxopendata(fileid, "data1") <br>
+
+	S = nxgetdata(fileid, getdata) <br>
+	print, 'data : ',getdata <br>
+
+	S = nxgetnextattr (fileid, attrname, lenght, attr_type) <br>
+	S = nxgetattr(fileid, attrname, value, lenght,attr_type) <br>
+	print, 'attribute value: ', value <br>
+	S = nxclosedata(fileid) <br>
+	S = nxclosegroup(fileid) <br>
+	S = nxclose(fileid) <br>
+	end
+
+
+
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+</p>
+
+<a name="NeXus IDL API Routines"></a><h3> NeXus IDL API Routines</h3>
+<p>Here's the list of functions in the NeXus IDL API. <br>
+
+(Limitatins 8 dimensions data
+max 8192 handles and 200 links per handle, NXINT8 not supported in data)
+
+</p>
+
+
+
+
+
+<ul>
+<li ><a href="#General_Initialization_and_Shutdown">1. General Initialization and Shutdown</a>
+<ul>
+<li ><a href="#NXopen">1.1 NXopen</a></li>
+<li><a href="#NXclose">1.2 NXclose </a></li>
+<li><a href="#NXmakegroup">1.3 NXmakegroup</a></li>
+<li><a href="#NXopengroup">1.4 NXopengroup</a></li>
+<li><a href="#NXopenpath">1.5 NXopenpath</a></li>
+<li><a href="#NXopengrouppath">1.6 NXopengrouppath</a></li>
+<li><a href="#NXclosegroup">1.7 NXclosegroup</a></li>
+<li><a href="#NXmakedata">1.8 NXmakedata</a></li>
+<li><a href="#NXcompmakedata">1.9 NXcompmakedata</a></li>
+<li><a href="#NXopendata">1.10 NXopendata</a></li>
+<li><a href="#NXcompress">1.11 NXcompress</a></li>
+<li><a href="#NXclosedata">1.12 NXclosedata</a></li>
+<li><a href="#NXsetnumberformat">1.13 NXsetnumberformat</a></li>
+</ul>
+</li>
+<li class="toclevel-1"><a href="#Reading_and_Writing">2. Reading and Writing</a>
+<ul>
+<li><a href="#NXgetdata">2.1 NXgetdata</a></li>
+<li><a href="#NXgetslab">2.2 NXgetslab</a></li>
+<li><a href="#NXgetattr">2.3 NXgetattr</a></li>
+<li><a href="#NXputdata">2.4 NXputdata</a></li>
+<li><a href="#NXputslab">2.5 NXputslab</a></li>
+<li><a href="#NXputattr">2.6 NXputattr</a></li>
+<li><a href="#NXflush">2.7 NXflush</a></li>
+</ul>
+</li>
+<li class="toclevel-1"><a href="#Meta-Data_Routines">3. Meta-Data Routines</a>
+<ul>
+<li><a href="#NXgetinfo">3.1 NXgetinfo</a></li>
+<li><a href="#NXgetgroupinfo">3.2 NXgetgroupinfo</a></li>
+<li><a href="#NXinitgroupdir">3.3 NXinitgroupdir</a></li>
+<li><a href="#NXgetnextentry">3.4 NXgetnextentry</a></li>
+<li><a href="#NXgetattrinfo">3.5 NXgetattrinfo</a></li>
+<li><a href="#NXinitattrdir">3.6 NXinitattrdir</a></li>
+<li><a href="#NXgetnextattr">3.7 NXgetnextattr</a></li>
+<li><a href="#NXgetgroupID">3.8 NXgetgroupID</a></li>
+<li><a href="#NXgetdataID">3.9 NXgetdataID</a></li>
+<li><a href="#NXmakelink">3.10 NXmakelink</a></li>
+<li><a href="#NXsameID">3.11 NXsameID</a></li>
+<li><a href="#NXopensourcegroup">3.12 NXopensourcegroup</a></li>
+</ul>
+</li>
+
+<li class="toclevel-1"><a href="#External_Linking">4. External Linking</a>
+<ul>
+<li><a href="#Nxinquirefile">4.1 Nxinquirefile</a></li>
+<li><a href="#NXlinkexternal">4.2 NXlinkexternal</a></li>
+<li><a href="#NXisexternalgroup">4.3 NXisexternalgroup</a></li>
+</ul>
+</li>
+</ul>
+</td></tr></tbody></table>
+
+
+
+
+
+
+<a name="General_Initialization_and_Shutdown"></a><h2> General Initialization and Shutdown</h2>
+<a name="NXopen"></a><h3> NXopen</h3>
+<p>Opens the NeXus file, and creates and initializes the NeXus file structure. The returned handle is integer assosiated with a pointer structure, do not modify it.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXopen (file_name, access_method, file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Input Arguments
+</th><td> file_name
+</td><td> string
+</td><td> Name of NeXus file to be opened
+</td></tr>
+<tr>
+<td> access_method
+</td><td> int or string
+</td><td>
+<dl><dt>File Access</dt><dd>NXACC_READ - read only 
+</dd><dd>NXACC_RDWR - read and write access
+</dd><dd>NXACC_CREATE - create (HDF4) file
+</dd><dd>NXACC_CREATE4 - create HDF4 file
+</dd><dd>NXACC_CREATE5 - create HDF5 file
+</dd><dd>NXACC_CREATEXML - create XML file
+</dd></dl>
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Output Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr></tbody></table>
+
+<a name="NXclose"></a><h3> NXclose</h3>
+<p>Closes NeXus file and deletes all associated data structures from memory.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXclose (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr></tbody></table>
+<a name="NXmakegroup"></a><h3> NXmakegroup</h3>
+<p>Creates a NeXus group at the current level in the group hierarchy,
+defining its name and class. This does not open the new group
+automatically.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXmakegroup (file_id, group_name, group_class)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> group_name
+</td><td> string
+</td><td> Name of NeXus group
+</td></tr>
+<tr>
+<td> group_class
+</td><td> string
+</td><td> Class of NeXus group
+</td></tr></tbody></table>
+
+<a name="NXopengroup"></a><h3> NXopengroup</h3>
+<p>Opens an existing NeXus group for input and output of data.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXopengroup (file_id, group_name, group_class)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> group_name
+</td><td> string
+</td><td> Name of NeXus group
+</td></tr>
+<tr>
+<td> group_class
+</td><td> string
+</td><td> Class of NeXus group
+</td></tr></tbody></table>
+<a name="NXopenpath"></a><h3> NXopenpath</h3>
+<p>Opens a NeXus group or dataset from a path string. The NeXus item must exist for NXopenpath to work correctly.
+The path string for NXopenpath has the same form as a unix path string: /group1/group/group2/dataset. Both absolute 
+and relative path are supported.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXopenpath(file_id, path_string)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<td style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</td><td> file_id
+</td><td> int
+</td><td>Identifier of NeXus file
+</td></tr>
+<tr>
+<td> path_string
+</td><td> string
+</td><td> path to dataset or group in NeXus file
+</td></tr></tbody></table>
+<a name="NXopengrouppath"></a><h3> NXopengrouppath</h3>
+<p>Opens a NeXus group from a path string. This function is subtly different from NXopenpath in that it only
+opens the path to the last group; it does not open datasets. The NeXus item must exist for NXopengrouppath to work correctly.
+The path string for NXopengrouppath has the same form as a unix path string: /group1/group/group2/dataset. Both absolute 
+and relative path are supported.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXopengrouppath(file_id, path_string)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<td style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</td><td> file_id
+</td><td> int
+</td><td>Identifier of NeXus file
+</td></tr>
+<tr>
+<td> path_string
+</td><td> string
+</td><td> path to dataset or group in NeXus file
+</td></tr></tbody></table>
+<p><br>
+</p>
+<a name="NXclosegroup"></a><h3> NXclosegroup</h3>
+<p>Closes the currently open group. If this group is a top-level group
+(i.e. with class NXentry), no groups are left open. Otherwise, the next
+group up in the hierarchy (i.e. the group containing the currently open
+group) is left open.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXclosegroup (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr></tbody></table>
+<a name="NXmakedata"></a><h3> NXmakedata</h3>
+<p>Creates a new NeXus data set with the specified name, type, rank and dimensions. <p><b>NeXus IDL API NOTE: The data type for the dimensions array must be type long. </b> </p>
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXmakedata (file_id, data_name, data_type, rank, dimensions[])</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="5"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> data_name
+</td><td> string
+</td><td> Name of NeXus data set
+</td></tr>
+<tr>
+<td> data_type
+</td><td> int or string
+</td><td>
+<dl><dt>Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr>
+<tr>
+<td> rank
+</td><td> int
+</td><td> Rank of data
+</td></tr>
+<tr>
+<td> dimensions
+</td><td> Array of IDL type Long
+</td><td> Dimensions of data. The array is of size 'rank'
+</td></tr></tbody></table>
+<a name="NXcompmakedata"></a><h3>NXcompmakedata</h3>
+<p>Creates a new NeXus data set with the specified name, type, rank and dimensions, compressed using the specified protocol.
+
+<p><b>NeXus IDL API NOTE: The data type for the dimensions array and bufsize array must be type long in IDL. </b> </p>
+
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXcompmakedata (file_id, data_name, data_type, rank, dimensions[], compress_type, bufsize[])</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="7"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> data_name
+</td><td> string
+</td><td> Name of NeXus data set
+</td></tr>
+<tr>
+<td> data_type
+</td><td> int or string
+</td><td>
+<dl><dt>Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr>
+<tr>
+<td> rank
+</td><td> int
+</td><td> Rank of data
+</td></tr>
+<tr>
+<td> dimensions
+</td><td> Array of IDL type Long
+</td><td> Dimensions of data. The array is of size 'rank'
+</td></tr>
+<tr>
+<td> compress_type
+</td><td> int or string
+</td><td>
+<dl><dt>Compression algorithm</dt><dd>NX_COMP_LZW - GZIP
+</dd><dd>NX_COMP_HUF - Skipping Huffman
+</dd><dd>NX_COMP_RLE - Run Length Encoding
+</dd></dl>
+</td></tr>
+<tr>
+<td> bufsize
+</td><td> Array of IDL type Long
+</td><td> The typical buffersize for writing.
+</td></tr></tbody></table>
+<p>The buffersize requires further explanation. HDF-5 compresses data in chunks. And the buffersize 
+is this chunksize. If data is written in one go with a NXputdata, this is the dimensions of the 
+data. If data is written in slabs, this is the preferred size of the slabs. Please note, that this has
+only a performance impact when writing, it is no show stopper. Please note that HDF-4 does not support 
+compression on data sets written in slabs: If you want compression with HDF-4, data must be written with
+one call to NXputdata. Compression is ignored for XML-NeXus files.
+</p>
+<a name="NXopendata"></a><h3> NXopendata</h3>
+<p>Opens an existing NeXus data set for further processing i.e. reading
+and writing data or attributes, defining compression algorithms, and
+obtaining data set information.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXopendata (file_id, data_name)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> data_name
+</td><td> string
+</td><td> Name of NeXus data set
+</td></tr></tbody></table>
+<a name="NXcompress"></a><h3> NXcompress</h3>
+<p>Defines a compression algorithm for subsequent calls to NXputdata.
+This routine is now deprecated; please use NXcompmakedata instead.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXcompress (file_id, compress_type)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> compress_type
+</td><td> int or string
+</td><td>
+<dl><dt>Compression algorithm</dt><dd>NX_COMP_LZW - GZIP
+</dd><dd>NX_COMP_HUF - Skipping Huffman
+</dd><dd>NX_COMP_RLE - Run Length Encoding
+</dd></dl>
+</td></tr></tbody></table>
+<a name="NXclosedata"></a><h3>NXclosedata</h3>
+<p>Ends access to the currently active data set
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXclosedata (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+</tbody></table>
+<p><br>
+</p>
+<a name="NXsetnumberformat"></a><h3> NXsetnumberformat</h3>
+<p>Sets the number format when writing to ASCII files. When serializing
+NeXus file to ASCII-XML files a format for printing numbers is
+required. The NeXus-API has reasonable defaults for this. However, with
+this
+function a desired format can be choosen for special cases. Please note
+that calls to this function will be silently ignored for the binary
+NeXus formats HDF-4 and HDF-5.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXsetnumberformat(file_id,data_type,format_string</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td>data_type
+</td><td> int or string
+</td><td> The NeXus data type for which to change the print format.
+<dl><dt>Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr>
+<tr>
+<td> format_string
+</td><td> string
+</td><td> A ANSI-C language style format string
+</td></tr>
+</tbody></table>
+<p><br>
+</p>
+<a name="Reading_and_Writing"></a><h2> Reading and Writing</h2>
+<a name="NXgetdata"></a><h3> NXgetdata</h3>
+<p>Reads data values from the currently open data set. Please note that
+memory overwrite occurs if the caller has not allocated enough memory
+to hold all the data available. Call NXgetinfo to determine the
+required dimension sizes. The data set must have been opened by
+NXopendata.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetdata (file_id, data)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Output Arguments
+</th><td> data
+</td><td> equivalent IDL data type of the NeXus data
+</td><td> Data values
+</td></tr></tbody></table>
+<a name="NXgetslab"></a><h3>NXgetslab</h3>
+<p>Reads a subset of the data in the current data set specifying the
+starting indices and size of each dimension. The caller is responsible
+for allocating enough memory for the data.
+
+<p><b>NeXus IDL API NOTE: The data type for the slab start and slab size arrays must be type long in IDL. </b> </p>
+
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetslab (file_id, data, start[], size[])</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> start[]
+</td><td> Array of IDL type Long
+</td><td> Indices of starting values in each dimension
+</td></tr>
+<tr>
+<td> size[]
+</td><td> Array of IDL type Long
+</td><td> Length of slab in each dimension
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Output Arguments
+</th><td> data
+</td><td> equivalent IDL data type of the NeXus data
+</td><td> Data values
+</td></tr></tbody></table>
+<a name="NXgetattr"></a><h3> NXgetattr</h3>
+<p>Reads attribute values associated with the currently open data set.
+The attribute is defined by its name. Attributes are meta-data; data
+that provides information on the associated data set such as units,
+long names etc. If no data set is open, it looks for a global attribute
+i.e. attributes of the NeXus file. The caller is responsible for
+allocating enough memory for the attribute values. Note, however, that
+only the first 'length' bytes of the attribute are read to prevent
+memory overwrite.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetattr (file_id, attr_name, value, length, type)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="4"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> attr_name
+</td><td> string
+</td><td> Name of attribute
+</td></tr>
+<tr>
+<td> length
+</td><td> int
+</td><td> Length of buffer for storing attribute data
+</td></tr>
+<tr>
+<td> type
+</td><td> int or string
+</td><td>
+<dl><dt>Attribute Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Output Arguments
+</th><td> value
+</td><td> equivalent IDL data type of the NeXus data
+</td><td> Value of attribute
+</td></tr>
+<tr>
+<td> length
+</td><td> int
+</td><td> Actual length of attribute data
+</td></tr></tbody></table>
+<a name="NXputdata"></a><h3> NXputdata</h3>
+<p>Writes data into the specified data set.
+Datatype of the dataset and the IDL data type of the input data must be of equivalent data type. Refer to the chart:
+<a href="#Using The API And An Example">3.3 Using The API And An Example</a>
+
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXputdata (file_id, data[])</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> data
+</td><td> equivalent IDL data type of the prepared NeXus data
+</td><td> Data values
+</td></tr></tbody></table>
+<a name="NXputslab"></a><h3> NXputslab</h3>
+<p>Writes a subset of a multidimensional data array, specified by the
+starting indices and size of each dimension, into the currently open
+dataset.
+<p>
+Datatype of the dataset and the IDL data type of the input data must be of equivalent data type. Refer to the chart:
+<a href="#Using The API And An Example">3.3 Using The API And An Example</a>
+</p>
+<p><b>NeXus IDL API NOTE: The data type for the slab start and slab size arrays must be type long in IDL. </b> </p>
+
+
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXputslab (file_id, data, start[], size[])</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="4"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> data
+</td><td> equivalent IDL data type of the NeXus data
+</td><td> Data values
+</td></tr>
+<tr>
+<td> start[]
+</td><td> Array of IDL type Long
+</td><td> Indices of starting values in each dimension
+</td></tr>
+<tr>
+<td> size[]
+</td><td> Array of IDL type Long
+</td><td> Length of slab in each dimension
+</td></tr></tbody></table>
+<a name="NXputattr"></a><h3>NXputattr</h3>
+<p>Writes an attribute of the currently open data set. If no data set
+is open, a global attribute is generated. The attribute has both a name
+and a value.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXputattr (file_id, attr_name, value, length, type)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="5"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> attr_name
+</td><td> string
+</td><td> Name of attribute
+</td></tr>
+<tr>
+<td> value
+</td><td> equivalent IDL data type of the prepared NeXus data
+</td><td> Value of attribute
+</td></tr>
+<tr>
+<td> length
+</td><td> int
+</td><td> Length of data
+</td></tr>
+<tr>
+<td> type
+</td><td> int or string
+</td><td>
+<dl><dt>Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr></tbody></table>
+<a name="NXflush"></a><h3>NXflush</h3>
+<p>Flushes all data to the NeXus file. Since this command closes and
+reopens the file, a new file handle is returned. The command leaves the
+program in the same state, i.e. with the same group and/or data set
+open.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXflush (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input & Output Argument
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr></tbody></table>
+<a name="Meta-Data_Routines"></a><h2> Meta-Data Routines</h2>
+<a name="NXgetinfo"></a><h3> NXgetinfo</h3>
+<p>Gets the rank, dimensions and data type of the currently open data set.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetinfo (file_id, rank, dimensions[], data_type)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Output Arguments
+</th><td> rank
+</td><td> int
+</td><td> Rank of data
+</td></tr>
+<tr>
+<td> dimensions
+</td><td> int[]
+</td><td> Dimensions of data
+</td></tr>
+<tr>
+<td> data_type
+</td><td> int
+</td><td>
+<dl><dt>Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr></tbody></table>
+<a name="NXgetgroupinfo"></a><h3>NXgetgroupinfo</h3>
+<p>Returns the number of items in the current group, and the name and class of the current group.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetgroupinfo (file_id, item_number, group_name, group_class)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Output Arguments
+</th><td> item_number
+</td><td> int
+</td><td> Number of NeXus data items in the current group
+</td></tr>
+<tr>
+<td> group_name
+</td><td> string
+</td><td> Name of currently open NeXus group
+</td></tr>
+<tr>
+<td> group_class
+</td><td> string
+</td><td> Class of currently open NeXus group
+</td></tr></tbody></table>
+<a name="NXinitgroupdir"></a><h3> NXinitgroupdir</h3>
+<p>Initializes directory searches of the currently open group. This is
+required to reset searches using NXgetnextentry that may have been
+interrupted before completion.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXinitgroupdir (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr></tbody></table>
+<a name="NXgetnextentry"></a><h3> NXgetnextentry</h3>
+<p>Implements a directory search facility on the current group level.
+The first call initializes the search and returns information on the
+first data item in the list. Subsequent calls yield information about
+the remaining items. If the item is a group, its name and class is
+returned. If it is a data set, its name and type is returned with a
+class of "SDS."
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetnextentry (file_id, name, class, data_type)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR, NX_EOD)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Output Arguments
+</th><td> name
+</td><td> string
+</td><td> Name of NeXus data item (group or set)
+</td></tr>
+<tr>
+<td> class
+</td><td> string
+</td><td> Class of NeXus group
+</td></tr>
+<tr>
+<td> data_type
+</td><td> int
+</td><td>
+<dl><dt>Data Type</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr></tbody></table>
+<a name="NXgetattrinfo"></a><h3>NXgetattrinfo</h3>
+<p>Returns the number of attributes in the current data set.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetattrinfo (file_id, attr_number)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Output Arguments
+</th><td> attr_number
+</td><td> int
+</td><td> Number of attributes in the current data set
+</td></tr></tbody></table>
+<a name="NXinitattrdir"></a><h3>NXinitattrdir</h3>
+<p>Initializes attribute searches of the currently open data set. This
+is required to reset searches using NXgetnextattr that may have been
+interrupted before completion.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXinitattrdir (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr></tbody></table>
+<a name="NXgetnextattr"></a><h3>NXgetnextattr</h3>
+<p>Implements a search facility of the attributes of the currently open
+data set. The first call initializes the search and returns information
+on the first attribute in the list. Subsequent calls yield information
+about the remaining attributes. This routine returns global attributes
+if no data set is open.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetnextattr (file_id, attr_name, length, attr_type)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR, NX_EOD)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Output Arguments
+</th><td> attr_name
+</td><td> string
+</td><td> Name of next attribute
+</td></tr>
+<tr>
+<td> length
+</td><td> int
+</td><td> Length of next attribute
+</td></tr>
+<tr>
+<td> attr_type
+</td><td> int
+</td><td>
+<dl><dt>Data type of next attribute</dt><dd>NX_CHAR - Character string
+</dd><dd>NX_FLOAT32 - 4-byte real
+</dd><dd>NX_FLOAT64 - 8-byte real
+</dd><dd>NX_INT8 - 1-byte integer
+</dd><dd>NX_UINT8 - unsigned 1-byte integer
+</dd><dd>NX_INT16 - 2-byte integer
+</dd><dd>NX_UINT16 - unsigned 2-byte integer
+</dd><dd>NX_INT32 - 4-byte integer
+</dd><dd>NX_UINT32 - unsigned 4-byte integer
+</dd></dl>
+</td></tr></tbody></table>
+<a name="NXgetgroupID"></a><h3>NXgetgroupID</h3>
+<p>Returns the identifier of the currently open group as an NXlink structure.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetgroupID (file_id, group_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Output Arguments
+</th><td> group_id
+</td><td> int
+</td><td> Identifier of NeXus group
+</td></tr></tbody></table>
+<a name="NXgetdataID"></a><h3> NXgetdataID</h3>
+<p>Gets the identifier of the currently open data set as an NXlink structure. Returns NX_ERROR if there is no open data set.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXgetdataID (file_id, data_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Output Arguments
+</th><td> data_id
+</td><td> int
+</td><td> Identifier of NeXus data set
+</td></tr></tbody></table>
+<a name="NXmakelink"></a><h3> NXmakelink</h3>
+<p>Links a data item (group or set) to a NeXus group. Returns NX_ERROR
+if the current group level is the root level, since no data item can be
+linked here.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXmakelink (file_id, link)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td> </tr>
+<tr>
+
+<td>link
+</td><td> int
+</td><td> Identifier of linked group
+</td></tr>
+</tbody></table>
+
+
+<a name="NXmakelink"></a><h3> NXmakenamedlink</h3>
+<p>Links a data item (group or set) to a named NeXus group. Returns NX_ERROR
+if the current group level is the root level, since no data item can be
+linked here.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXmakenamedlink (file_id, linkname, link)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td> </tr>
+<tr>
+
+<td> linkname
+</td><td> string
+</td><td> Name of the link to be created
+</td> </tr>
+<tr>
+
+<td>link
+</td><td> int
+</td><td> Identifier of linked group
+</td></tr>
+</tbody></table>
+
+
+<a name="NXsameID"></a><h3>
+
+ NXsameID</h3>
+<p>Tests if two data items are the same, i.e. one is linked to the other.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXsameID (file_id, link1, link2)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="3"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+<tr>
+<td> link1
+</td><td> int
+</td><td> Identifier of first item
+</td></tr>
+<tr>
+<td> link2
+</td><td> int
+</td><td> Indentifier of second item
+</td></tr>
+</tbody></table>
+<a name="NXopensourcegroup"></a><h3>NXopensourcegroup</h3>
+<p>Opens the group from which a linked dataset was linked. This is
+useful for accessing auxiliary information related to the dataset. This
+works only if the linked dataset is currently open.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXopensourcegroup (file_id)</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Input Arguments
+</th><td> file_id
+</td><td> int
+</td><td> Identifier of NeXus file
+</td></tr>
+</tbody></table>
+
+<a name="External_Linking"></a><h2> External Linking</h2>
+<a name="Nxinquirefile"></a><h3> Nxinquirefile</h3>
+<p>Queries which file is really active.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXinquirefile(handle,filename, filenameLength);</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="2"> Input Arguments
+</th><td> handle
+</td><td> int
+</td><td> handle to a currently open NeXus file.
+</td></tr>
+<tr>
+<td> filenameLenght
+</td><td> int
+</td><td> length of filename buffer
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);">Output Arguments
+</th><td> filename
+</td><td> string
+</td><td> buffer to receive filename
+</td></tr></tbody></table>
+<a name="NXlinkexternal"></a><h3> NXlinkexternal</h3>
+<p>Links an external file. This happens by creating a group which
+points to an external file. Navigating into such a group automatically
+opens the external file.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXlinkexternal(handle,name, nxclass, nxurl);</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="4"> Input Arguments
+</th><td> handle
+</td><td> int
+</td><td> handle to a currently open NeXus file.
+</td></tr>
+<tr>
+<td> name
+</td><td> string (NXname)
+</td><td> The name of the group to link the file to.
+</td></tr>
+<tr>
+<td> nxclass
+</td><td> string (NXname)
+</td><td> The NeXus class of the group to which the external file is to be linked.
+</td></tr>
+<tr>
+<td> nxurl
+</td><td> string (NXURL)
+</td><td> An URL of a format which the NeXus-API understands. The only
+URL format so far is: nxfile://path-to-file#path-to-group-in-file. This
+consistes of two parts: The file path and a path to a group in the file
+which is to be mapped into the source file.
+</td></tr></tbody></table>
+<a name="NXisexternalgroup"></a><h3>NXisexternalgroup</h3>
+<p>Tests in the group is an external group. If not, NX_ERROR is
+returned. If yes, NX_OK is returned and the URL of the external file is
+copied into nxurl.
+</p>
+<dl><dt>Usage</dt><dd><pre>status = NXisexternalgroup(handle,name, nxclass, nxurl,nxurllen);</pre>
+</dd></dl>
+<table style="border: 1px solid navy; margin: 5px; padding: 2px; border-collapse: collapse; background-color: rgb(238, 238, 238); vertical-align: top;" align="center" border="1" cellpadding="2" cellspacing="2" width="90%">
+
+<tbody><tr>
+<th style="background-color: rgb(204, 204, 204);" width="20%"> 
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Name
+</th><th style="background-color: rgb(204, 204, 204);" width="15%">Type
+</th><th style="background-color: rgb(204, 204, 204);" width="50%">Description
+</th></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);"> Return Value
+</th><td> status
+</td><td> int
+</td><td> Error status (NX_OK, NX_ERROR)
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="4"> Input Arguments
+</th><td> handle
+</td><td> int
+</td><td> handle to a currently open NeXus file.
+</td></tr>
+<tr>
+<td> name
+</td><td> string (NXname)
+</td><td> The name of the group to test.
+</td></tr>
+<tr>
+<td> nxclass
+</td><td> string (NXname)
+</td><td> The NeXus class of the group to test.
+</td></tr>
+<tr>
+<td> nxurllen
+</td><td> int
+</td><td> length of the nxurl buffer
+</td></tr>
+<tr>
+<th style="background-color: rgb(204, 204, 204);" rowspan="4"> Output Arguments
+</th><td> nxurl
+</td><td> string
+</td><td> buffer to copy the URL, too.
+</td></tr></tbody></table>
+
+<!-- Served by shadow.nd.rl.ac.uk in 1.611 secs. --></body></html>
diff --git a/bindings/idl/build_testmodule.pro b/bindings/idl/build_testmodule.pro
new file mode 100644
index 0000000..dce6c03
--- /dev/null
+++ b/bindings/idl/build_testmodule.pro
@@ -0,0 +1,67 @@
+	pro build_testmodule, VERBOSE=verbose
+
+  ; Locate the testmodule files from the IDL distribution
+  ;
+  subdirs = [ 'external', 'dlm' ]
+  testmodule_dir = FILEPATH('', SUBDIRECTORY=subdirs)
+  dlm_file = FILEPATH('testmodule.dlm_base', SUBDIRECTORY=subdirs)
+  new_dlm_file = $
+	FILEPATH('testmodule.dlm', ROOT_DIR=!make_dll.compile_directory)
+
+  ; Build the testmodule DLM in the !MAKE_DLL.COMPILE_DIRECTORY directory.
+  ;
+  ; Normally, you wouldn't use VERBOSE, or SHOW_ALL_OUTPUT once your
+  ; work is debugged, but as a learning exercise it can be useful to
+  ; see all the underlying work that gets done. If the user specified
+  ; VERBOSE, then use those keywords to show what MAKE_DLL is doing.
+  ;
+  ;MAKE_DLL, 'testmodule','IDL_Load', INPUT_DIR=testmodule_dir, $
+  ;	VERBOSE=verbose, SHOW_ALL_OUTPUT=verbose
+
+inputfiles = [ 'NeXusIDL-API','handle']
+inputdir = '/home/scratch/lns/kauppila/temp/IDLNeXus-API'
+
+cd,'.',current=dir
+
+MAKE_DLL, inputfiles, 'IDL_Load', compile_directory=dir, INPUT_DIRECTORY=dir, output_dir=dir, EXTRA_CFLAGS='../../src/trunk/src/.libs/libNeXus.a -L$(HDFROOT)/lib -lhdf5 -lmfhdf -ldf -lmxml -lsz -lz -lm -ljpeg -lm '
+
+  ; Copy the DLM file into the directory with the sharable library
+  FILE_COPY, dlm_file, new_dlm_file, /OVERWRITE
+
+
+  ; NOTE TO IDL USERS: This call to DLM_REGISTER is not the recommended
+  ; way to make DLMs known to your IDL session. The best, and usually
+  ; the only recommended, way to do this is to put the DLM files into
+  ; one of the directories searched by IDL at startup (and contained in
+  ; the !DLM_PATH system variable). Not only is is easier, but IDL will
+  ; know the routines from your DLM before it compiles a single line of
+  ; PRO code, avoiding one of the most common LINKIMAGE pitfalls.
+  ; DLMs are largely intended to provide a safer easier interface to
+  ; the capabilities of LINKIMAGE, so this is an important point.
+  ;
+  ; We do this here in order to simplify the demo. Otherwise, it would be
+  ; necessary to alter the !DLM_PATH, and restart IDL, none of which is
+  ; really central to our demo.
+  ;
+  ;DLM_REGISTER, new_dlm_file
+
+  ; Display the DLM so the user can see that it is there
+  ;
+  ;print,''
+  ;HELP,/DLM, 'testmodule'
+
+  ; Run the 2 routines. Note that I have to use EXECUTE so that IDL
+  ; will see these as system routines within this BUILD_TESTMODULE
+  ; routine. This is because BUILD_TESTMODULE was compiled by IDL
+  ; before it knew about the TESTMODULE DLM, and as such, plain calls
+  ; get turned into IDL user routine calls. Since EXECUTE compiles at
+  ; runtime, it will see them as system routines now that DLM_REGISTER
+  ; has been called.
+  ;
+  ; This is the LINKIMAGE pitfall mentioned above, and a very good
+  ; reason not to make a habit of using DLM_REGISTER.
+  ;
+  ;void = execute('testpro')
+  ;void = execute('print, testfun()')
+
+end
diff --git a/bindings/idl/build_win.bat b/bindings/idl/build_win.bat
new file mode 100644
index 0000000..fc620d7
--- /dev/null
+++ b/bindings/idl/build_win.bat
@@ -0,0 +1,63 @@
+ at ECHO OFF
+REM  Copyright (c) 1988-2006, Research Systems Inc.  All rights reserved.
+REM  This software includes information which is proprietary to and a
+REM  trade secret of Research Systems, Inc.  It is not to be disclosed
+REM  to anyone outside of this organization. Reproduction by any means
+REM  whatsoever is  prohibited without express written permission.
+REM
+REM  MS Windows batch file to build the NeXusIDL-API DLM.
+REM
+REM  You may pass the location of the IDL directory to this file on the
+REM  command line: e.g., build_win d:\myidl\idl
+REM
+REM  You may also edit the default location below.
+
+SETLOCAL
+
+IF "%1" == "" GOTO SET_IDLDIR
+SET IDL_DIR=%1
+GOTO CONTINUE
+
+:SET_IDLDIR
+
+REM Set these directories to point 
+
+SET IDL_DIR=c:\rsi\idl63
+SET NXS_DIR= "C:\Program Files\NeXus Data Format"
+
+:CONTINUE
+
+SET IDL_LIBDIR=%IDL_DIR%\bin\bin.x86
+SET NXS_LIBDIR=%NXS_DIR%\lib
+
+IF NOT EXIST %IDL_LIBDIR%\idl.lib GOTO NO_IDL_LIB
+IF NOT EXIST %IDL_DIR%\external\include/idl_export.h GOTO NO_EXPORT_H
+
+ECHO ON
+
+cl -I%IDL_DIR%\external\include -nologo -DWIN32_LEAN_AND_MEAN -DWIN32 -c NeXusIDL-API.c
+cl -I%IDL_DIR%\external\include -nologo -DWIN32_LEAN_AND_MEAN -DWIN32 -c handle.c
+
+link /DLL /OUT:NeXusIDL-API.dll /DEF:NeXusIDL-API.def /IMPLIB:NeXusIDL-API.lib NeXusIDL-API.obj handle.obj %IDL_LIBDIR%\idl.lib %NXS_LIBDIR%\libNeXus.dll.lib
+
+
+ at ECHO OFF
+
+GOTO END
+
+:NO_IDL_LIB
+ECHO.
+ECHO Unable to locate %IDL_LIBDIR%\idl.lib.
+ECHO.
+GOTO END
+
+:NO_EXPORT_H
+ECHO.
+ECHO Unable to locate %IDL_DIR%\external\include\idl_export.h.
+ECHO.
+
+:END
+
+ENDLOCAL
+
+
diff --git a/bindings/idl/data/dmc01.h5 b/bindings/idl/data/dmc01.h5
new file mode 100644
index 0000000..1127b1a
Binary files /dev/null and b/bindings/idl/data/dmc01.h5 differ
diff --git a/bindings/idl/data/dmc01.hdf b/bindings/idl/data/dmc01.hdf
new file mode 100644
index 0000000..46b41df
Binary files /dev/null and b/bindings/idl/data/dmc01.hdf differ
diff --git a/bindings/idl/data/dmc01.xml b/bindings/idl/data/dmc01.xml
new file mode 100644
index 0000000..221a014
--- /dev/null
+++ b/bindings/idl/data/dmc01.xml
@@ -0,0 +1,245 @@
+<?xml version="1.0"?>
+  <NXroot NeXus_version="3.0.0"
+HDF_version="NCSA HDF Version 4.2 Release 0, December 2, 2003"
+file_name="/home/dmc/data/2005/003/dmc2005n003077.hdf"
+file_time="2005-05-27 05:44:13" instrument="DMC" owner="keller"
+owner_telephone_number="UNKNOWN" owner_fax_number="UNKNOWN"
+owner_email="UNKNOWN" owner_address="UNKNOWN">
+    <NXentry name="entry1">
+      <title>Ga0.94Mn0.04Sb_8mm 2.567A T=4</title>
+      <start_time>2005-05-27 05:44:13</start_time>
+      <NXinstrument name="DMC">
+        <name>DMC at SINQ</name>
+        <NXsource name="SINQ">
+          <name>SINQ</name>
+          <type>Continuous flux spallation source</type>
+        </NXsource>
+        <NXcrystal name="Monochromator">
+          <type>Pyrolithic Graphite 002</type>
+          <theta type="NX_FLOAT32">22.430000</theta>
+          <two_theta type="NX_FLOAT32">44.869999</two_theta>
+          <lambda type="NX_FLOAT32" units="Angstroem">2.566600</lambda>
+          <curvature type="NX_FLOAT32">14.000000</curvature>
+          <x_translation type="NX_FLOAT32">0.940000</x_translation>
+          <y_translation type="NX_FLOAT32">0.210000</y_translation>
+          <chi type="NX_FLOAT32">0.356000</chi>
+          <phi type="NX_FLOAT32">-0.002000</phi>
+          <d_spacing type="NX_FLOAT32" units="Angstroem">3.353700</d_spacing>
+        </NXcrystal>
+        <NXpsd name="DMC-BF3-Detector">
+          <Preset type="NX_INT32">1094713344</Preset>
+          <CounterMode>monitor</CounterMode>
+          <time type="NX_FLOAT32">284.553009</time>
+          <beam_monitor type="NX_INT32" units="counts">2368697</beam_monitor>
+          <Monitor type="NX_INT32" units="counts">12000</Monitor>
+          <proton_monitor type="NX_INT32" units="counts">33077902</proton_monitor>
+          <two_theta_start type="NX_FLOAT32" units="degree">18.299999</two_theta_start>
+          <Step type="NX_FLOAT32" units="degree">0.200000</Step>
+          <no_of_steps type="NX_INT32">400</no_of_steps>
+          <two_theta type="NX_FLOAT32[400]" axis="1" units="degree">
+             18.299999 18.499998 18.699999 18.900000 19.099998 19.299999 19.499998 19.699999
+             19.900000 20.099998 20.299999 20.499998 20.699999 20.900000 21.099998 21.299999
+             21.499998 21.699999 21.900000 22.099998 22.299999 22.499998 22.699999 22.900000
+             23.099998 23.299999 23.499998 23.699999 23.900000 24.099998 24.299999 24.499998
+             24.699999 24.900000 25.099998 25.299999 25.499998 25.699999 25.900000 26.099998
+             26.299999 26.499998 26.699999 26.900000 27.099998 27.299999 27.499998 27.699999
+             27.900000 28.099998 28.299999 28.499998 28.699999 28.900000 29.099998 29.299999
+             29.499998 29.699999 29.900000 30.099998 30.299999 30.499998 30.699999 30.900000
+             31.099998 31.299999 31.499998 31.699999 31.900000 32.099998 32.299999 32.500000
+             32.700001 32.899998 33.099998 33.299999 33.500000 33.700001 33.899998 34.099998
+             34.299999 34.500000 34.700001 34.899998 35.099998 35.299999 35.500000 35.700001
+             35.899998 36.099998 36.299999 36.500000 36.700001 36.899998 37.099998 37.299999
+             37.500000 37.700001 37.899998 38.099998 38.299999 38.500000 38.700001 38.899998
+             39.099998 39.299999 39.500000 39.700001 39.899998 40.099998 40.299999 40.500000
+             40.700001 40.899998 41.099998 41.299999 41.500000 41.700001 41.899998 42.099998
+             42.299999 42.500000 42.700001 42.899998 43.099998 43.299999 43.500000 43.700001
+             43.899998 44.099998 44.299999 44.500000 44.700001 44.899998 45.099998 45.299999
+             45.500000 45.700001 45.899998 46.099998 46.299999 46.500000 46.700001 46.899998
+             47.099998 47.299999 47.500000 47.700001 47.899998 48.099998 48.299999 48.500000
+             48.700001 48.899998 49.099998 49.299999 49.500000 49.700001 49.899998 50.099998
+             50.299999 50.500000 50.700001 50.899998 51.099998 51.299999 51.500000 51.700001
+             51.899998 52.099998 52.299999 52.500000 52.700001 52.899998 53.099998 53.299999
+             53.500000 53.700001 53.899998 54.099998 54.299999 54.500000 54.700001 54.899998
+             55.099998 55.299999 55.500000 55.700001 55.899998 56.099998 56.299999 56.500000
+             56.700001 56.899998 57.099998 57.299999 57.500000 57.700001 57.899998 58.099998
+             58.299999 58.500000 58.700001 58.899998 59.099998 59.299999 59.500000 59.700001
+             59.899998 60.099998 60.299999 60.500000 60.700001 60.899998 61.099998 61.299999
+             61.500000 61.700001 61.899998 62.099998 62.299999 62.500000 62.700001 62.899998
+             63.099998 63.299999 63.500000 63.700001 63.899998 64.099998 64.299995 64.500000
+             64.699997 64.900002 65.099998 65.299995 65.500000 65.699997 65.900002 66.099998
+             66.299995 66.500000 66.699997 66.900002 67.099998 67.299995 67.500000 67.699997
+             67.900002 68.099998 68.299995 68.500000 68.699997 68.900002 69.099998 69.299995
+             69.500000 69.699997 69.900002 70.099998 70.299995 70.500000 70.699997 70.900002
+             71.099998 71.299995 71.500000 71.699997 71.900002 72.099998 72.299995 72.500000
+             72.699997 72.900002 73.099998 73.299995 73.500000 73.699997 73.900002 74.099998
+             74.299995 74.500000 74.699997 74.900002 75.099998 75.299995 75.500000 75.699997
+             75.900002 76.099998 76.299995 76.500000 76.699997 76.900002 77.099998 77.299995
+             77.500000 77.699997 77.900002 78.099998 78.299995 78.500000 78.699997 78.900002
+             79.099998 79.299995 79.500000 79.699997 79.900002 80.099998 80.299995 80.500000
+             80.699997 80.900002 81.099998 81.299995 81.500000 81.699997 81.900002 82.099998
+             82.299995 82.500000 82.699997 82.900002 83.099998 83.299995 83.500000 83.699997
+             83.900002 84.099998 84.299995 84.500000 84.699997 84.900002 85.099998 85.299995
+             85.500000 85.699997 85.900002 86.099998 86.299995 86.500000 86.699997 86.900002
+             87.099998 87.299995 87.500000 87.699997 87.900002 88.099998 88.299995 88.500000
+             88.699997 88.900002 89.099998 89.299995 89.500000 89.699997 89.900002 90.099998
+             90.299995 90.500000 90.699997 90.900002 91.099998 91.299995 91.500000 91.699997
+             91.900002 92.099998 92.299995 92.500000 92.699997 92.900002 93.099998 93.299995
+             93.500000 93.699997 93.900002 94.099998 94.299995 94.500000 94.699997 94.900002
+             95.099998 95.299995 95.500000 95.699997 95.900002 96.099998 96.299995 96.500000
+             96.699997 96.900002 97.099998 97.299995 97.500000 97.699997 97.900002 98.099998
+            </two_theta>
+          <counts type="NX_INT32[400]" signal="1">
+             94 103 86 84 88 106 92 87 95 104
+             96 114 99 89 102 89 120 93 101 97
+             94 84 102 116 98 92 77 90 111 89
+             90 125 86 90 97 111 85 81 108 96
+             101 95 95 119 91 103 95 97 75 105
+             68 95 101 102 107 102 105 96 116 107
+             98 115 113 90 92 78 70 89 107 106
+             84 100 107 102 112 104 107 98 102 105
+             102 94 107 94 91 99 101 94 119 108
+             110 105 107 106 93 102 109 104 102 109
+             102 94 91 88 94 99 116 101 110 104
+             98 110 108 99 99 108 135 146 251 315
+             484 2049 3541 2935 901 178 134 110 137 132
+             120 89 121 107 92 104 115 111 114 89
+             91 113 120 100 93 110 92 104 115 127
+             117 108 94 109 118 101 152 198 199 188
+             135 117 109 102 112 102 113 104 93 96
+             100 119 135 124 121 96 93 108 100 97
+             105 88 92 101 114 101 118 104 73 98
+             76 104 85 93 86 90 98 88 96 111
+             81 94 86 97 86 96 102 116 99 112
+             114 105 89 99 106 115 90 83 103 87
+             113 78 89 82 94 92 106 97 85 117
+             92 96 106 90 92 101 73 76 102 98
+             111 104 109 84 108 99 105 99 93 88
+             85 88 92 105 100 109 115 136 130 114
+             113 116 102 108 99 111 107 106 97 144
+             249 827 1588 2159 2201 2225 1557 606 269 152
+             156 126 97 100 112 100 132 122 85 108
+             96 130 115 110 93 92 96 76 100 93
+             94 104 80 86 96 69 107 91 84 106
+             105 99 91 106 93 102 82 103 87 95
+             106 92 93 106 96 101 112 103 134 103
+             93 103 96 129 100 86 100 95 96 98
+             128 105 109 138 126 146 191 450 807 1423
+             1648 1986 1839 1614 1162 634 296 190 139 122
+             125 130 104 109 98 121 142 128 105 138
+             119 92 104 98 147 132 116 112 124 112
+             104 113 107 100 87 105 86 117 92 110
+             86 98 82 107 105 119 105 107 101 105
+            </counts>
+        </NXpsd>
+      </NXinstrument>
+      <NXsample name="sample">
+        <sample_name>Ga0.94Mn0.04Sb_8mm</sample_name>
+        <sample_table_rotation type="NX_FLOAT32" units="degree">297.209991</sample_table_rotation>
+        <sample_temperature type="NX_FLOAT32" units="K">4.001700</sample_temperature>
+        <device_name>ccr4k</device_name>
+        <temperature_mean type="NX_FLOAT32" units="K">4.000000</temperature_mean>
+        <temperature_stddev type="NX_FLOAT32" units="K">0.000000</temperature_stddev>
+        <sample_mur type="NX_FLOAT32" units="degree">0.000000</sample_mur>
+      </NXsample>
+      <NXdata name="data1">
+        <counts type="NX_INT32[400]" signal="1">
+          94 103 86 84 88 106 92 87 95 104
+          96 114 99 89 102 89 120 93 101 97
+          94 84 102 116 98 92 77 90 111 89
+          90 125 86 90 97 111 85 81 108 96
+          101 95 95 119 91 103 95 97 75 105
+          68 95 101 102 107 102 105 96 116 107
+          98 115 113 90 92 78 70 89 107 106
+          84 100 107 102 112 104 107 98 102 105
+          102 94 107 94 91 99 101 94 119 108
+          110 105 107 106 93 102 109 104 102 109
+          102 94 91 88 94 99 116 101 110 104
+          98 110 108 99 99 108 135 146 251 315
+          484 2049 3541 2935 901 178 134 110 137 132
+          120 89 121 107 92 104 115 111 114 89
+          91 113 120 100 93 110 92 104 115 127
+          117 108 94 109 118 101 152 198 199 188
+          135 117 109 102 112 102 113 104 93 96
+          100 119 135 124 121 96 93 108 100 97
+          105 88 92 101 114 101 118 104 73 98
+          76 104 85 93 86 90 98 88 96 111
+          81 94 86 97 86 96 102 116 99 112
+          114 105 89 99 106 115 90 83 103 87
+          113 78 89 82 94 92 106 97 85 117
+          92 96 106 90 92 101 73 76 102 98
+          111 104 109 84 108 99 105 99 93 88
+          85 88 92 105 100 109 115 136 130 114
+          113 116 102 108 99 111 107 106 97 144
+          249 827 1588 2159 2201 2225 1557 606 269 152
+          156 126 97 100 112 100 132 122 85 108
+          96 130 115 110 93 92 96 76 100 93
+          94 104 80 86 96 69 107 91 84 106
+          105 99 91 106 93 102 82 103 87 95
+          106 92 93 106 96 101 112 103 134 103
+          93 103 96 129 100 86 100 95 96 98
+          128 105 109 138 126 146 191 450 807 1423
+          1648 1986 1839 1614 1162 634 296 190 139 122
+          125 130 104 109 98 121 142 128 105 138
+          119 92 104 98 147 132 116 112 124 112
+          104 113 107 100 87 105 86 117 92 110
+          86 98 82 107 105 119 105 107 101 105
+         </counts>
+        <two_theta type="NX_FLOAT32[400]" axis="1" units="degree">
+          18.299999 18.499998 18.699999 18.900000 19.099998 19.299999 19.499998 19.699999
+          19.900000 20.099998 20.299999 20.499998 20.699999 20.900000 21.099998 21.299999
+          21.499998 21.699999 21.900000 22.099998 22.299999 22.499998 22.699999 22.900000
+          23.099998 23.299999 23.499998 23.699999 23.900000 24.099998 24.299999 24.499998
+          24.699999 24.900000 25.099998 25.299999 25.499998 25.699999 25.900000 26.099998
+          26.299999 26.499998 26.699999 26.900000 27.099998 27.299999 27.499998 27.699999
+          27.900000 28.099998 28.299999 28.499998 28.699999 28.900000 29.099998 29.299999
+          29.499998 29.699999 29.900000 30.099998 30.299999 30.499998 30.699999 30.900000
+          31.099998 31.299999 31.499998 31.699999 31.900000 32.099998 32.299999 32.500000
+          32.700001 32.899998 33.099998 33.299999 33.500000 33.700001 33.899998 34.099998
+          34.299999 34.500000 34.700001 34.899998 35.099998 35.299999 35.500000 35.700001
+          35.899998 36.099998 36.299999 36.500000 36.700001 36.899998 37.099998 37.299999
+          37.500000 37.700001 37.899998 38.099998 38.299999 38.500000 38.700001 38.899998
+          39.099998 39.299999 39.500000 39.700001 39.899998 40.099998 40.299999 40.500000
+          40.700001 40.899998 41.099998 41.299999 41.500000 41.700001 41.899998 42.099998
+          42.299999 42.500000 42.700001 42.899998 43.099998 43.299999 43.500000 43.700001
+          43.899998 44.099998 44.299999 44.500000 44.700001 44.899998 45.099998 45.299999
+          45.500000 45.700001 45.899998 46.099998 46.299999 46.500000 46.700001 46.899998
+          47.099998 47.299999 47.500000 47.700001 47.899998 48.099998 48.299999 48.500000
+          48.700001 48.899998 49.099998 49.299999 49.500000 49.700001 49.899998 50.099998
+          50.299999 50.500000 50.700001 50.899998 51.099998 51.299999 51.500000 51.700001
+          51.899998 52.099998 52.299999 52.500000 52.700001 52.899998 53.099998 53.299999
+          53.500000 53.700001 53.899998 54.099998 54.299999 54.500000 54.700001 54.899998
+          55.099998 55.299999 55.500000 55.700001 55.899998 56.099998 56.299999 56.500000
+          56.700001 56.899998 57.099998 57.299999 57.500000 57.700001 57.899998 58.099998
+          58.299999 58.500000 58.700001 58.899998 59.099998 59.299999 59.500000 59.700001
+          59.899998 60.099998 60.299999 60.500000 60.700001 60.899998 61.099998 61.299999
+          61.500000 61.700001 61.899998 62.099998 62.299999 62.500000 62.700001 62.899998
+          63.099998 63.299999 63.500000 63.700001 63.899998 64.099998 64.299995 64.500000
+          64.699997 64.900002 65.099998 65.299995 65.500000 65.699997 65.900002 66.099998
+          66.299995 66.500000 66.699997 66.900002 67.099998 67.299995 67.500000 67.699997
+          67.900002 68.099998 68.299995 68.500000 68.699997 68.900002 69.099998 69.299995
+          69.500000 69.699997 69.900002 70.099998 70.299995 70.500000 70.699997 70.900002
+          71.099998 71.299995 71.500000 71.699997 71.900002 72.099998 72.299995 72.500000
+          72.699997 72.900002 73.099998 73.299995 73.500000 73.699997 73.900002 74.099998
+          74.299995 74.500000 74.699997 74.900002 75.099998 75.299995 75.500000 75.699997
+          75.900002 76.099998 76.299995 76.500000 76.699997 76.900002 77.099998 77.299995
+          77.500000 77.699997 77.900002 78.099998 78.299995 78.500000 78.699997 78.900002
+          79.099998 79.299995 79.500000 79.699997 79.900002 80.099998 80.299995 80.500000
+          80.699997 80.900002 81.099998 81.299995 81.500000 81.699997 81.900002 82.099998
+          82.299995 82.500000 82.699997 82.900002 83.099998 83.299995 83.500000 83.699997
+          83.900002 84.099998 84.299995 84.500000 84.699997 84.900002 85.099998 85.299995
+          85.500000 85.699997 85.900002 86.099998 86.299995 86.500000 86.699997 86.900002
+          87.099998 87.299995 87.500000 87.699997 87.900002 88.099998 88.299995 88.500000
+          88.699997 88.900002 89.099998 89.299995 89.500000 89.699997 89.900002 90.099998
+          90.299995 90.500000 90.699997 90.900002 91.099998 91.299995 91.500000 91.699997
+          91.900002 92.099998 92.299995 92.500000 92.699997 92.900002 93.099998 93.299995
+          93.500000 93.699997 93.900002 94.099998 94.299995 94.500000 94.699997 94.900002
+          95.099998 95.299995 95.500000 95.699997 95.900002 96.099998 96.299995 96.500000
+          96.699997 96.900002 97.099998 97.299995 97.500000 97.699997 97.900002 98.099998
+         </two_theta>
+        <two_theta_start type="NX_FLOAT32" units="degree">18.299999</two_theta_start>
+        <Step type="NX_FLOAT32" units="degree">0.200000</Step>
+        <no_of_steps type="NX_INT32">400</no_of_steps>
+        <lambda type="NX_FLOAT32" units="Angstroem">2.566600</lambda>
+      </NXdata>
+    </NXentry>
+  </NXroot>
diff --git a/bindings/idl/data/dmc02.h5 b/bindings/idl/data/dmc02.h5
new file mode 100644
index 0000000..0a39fef
Binary files /dev/null and b/bindings/idl/data/dmc02.h5 differ
diff --git a/bindings/idl/data/dmc02.hdf b/bindings/idl/data/dmc02.hdf
new file mode 100644
index 0000000..ca27524
Binary files /dev/null and b/bindings/idl/data/dmc02.hdf differ
diff --git a/bindings/idl/data/dmc02.xml b/bindings/idl/data/dmc02.xml
new file mode 100644
index 0000000..b89a67d
--- /dev/null
+++ b/bindings/idl/data/dmc02.xml
@@ -0,0 +1,245 @@
+<?xml version="1.0"?>
+  <NXroot NeXus_version="3.0.0"
+HDF_version="NCSA HDF Version 4.2 Release 0, December 2, 2003"
+file_name="/home/dmc/data/2005/003/dmc2005n003078.hdf"
+file_time="2005-05-27 05:48:56" instrument="DMC" owner="keller"
+owner_telephone_number="UNKNOWN" owner_fax_number="UNKNOWN"
+owner_email="UNKNOWN" owner_address="UNKNOWN">
+    <NXentry name="entry1">
+      <title>Ga0.94Mn0.04Sb_8mm 2.567A T=4</title>
+      <start_time>2005-05-27 05:48:56</start_time>
+      <NXinstrument name="DMC">
+        <name>DMC at SINQ</name>
+        <NXsource name="SINQ">
+          <name>SINQ</name>
+          <type>Continuous flux spallation source</type>
+        </NXsource>
+        <NXcrystal name="Monochromator">
+          <type>Pyrolithic Graphite 002</type>
+          <theta type="NX_FLOAT32">22.430000</theta>
+          <two_theta type="NX_FLOAT32">44.869999</two_theta>
+          <lambda type="NX_FLOAT32" units="Angstroem">2.566600</lambda>
+          <curvature type="NX_FLOAT32">14.000000</curvature>
+          <x_translation type="NX_FLOAT32">0.940000</x_translation>
+          <y_translation type="NX_FLOAT32">0.210000</y_translation>
+          <chi type="NX_FLOAT32">0.356000</chi>
+          <phi type="NX_FLOAT32">-0.002000</phi>
+          <d_spacing type="NX_FLOAT32" units="Angstroem">3.353700</d_spacing>
+        </NXcrystal>
+        <NXpsd name="DMC-BF3-Detector">
+          <Preset type="NX_INT32">1094713344</Preset>
+          <CounterMode>monitor</CounterMode>
+          <time type="NX_FLOAT32">267.199005</time>
+          <beam_monitor type="NX_INT32" units="counts">2328990</beam_monitor>
+          <Monitor type="NX_INT32" units="counts">12000</Monitor>
+          <proton_monitor type="NX_INT32" units="counts">32704151</proton_monitor>
+          <two_theta_start type="NX_FLOAT32" units="degree">18.400000</two_theta_start>
+          <Step type="NX_FLOAT32" units="degree">0.200000</Step>
+          <no_of_steps type="NX_INT32">400</no_of_steps>
+          <two_theta type="NX_FLOAT32[400]" axis="1" units="degree">
+             18.400000 18.600000 18.799999 19.000000 19.200001 19.400000 19.600000 19.799999
+             20.000000 20.200001 20.400000 20.600000 20.799999 21.000000 21.200001 21.400000
+             21.600000 21.799999 22.000000 22.200001 22.400000 22.600000 22.799999 23.000000
+             23.200001 23.400000 23.600000 23.799999 24.000000 24.200001 24.400000 24.600000
+             24.799999 25.000000 25.200001 25.400000 25.600000 25.799999 26.000000 26.200001
+             26.400000 26.600000 26.799999 27.000000 27.200001 27.400000 27.600000 27.799999
+             28.000000 28.200001 28.400000 28.600000 28.799999 29.000000 29.200001 29.400000
+             29.600000 29.799999 30.000000 30.200001 30.400000 30.600000 30.799999 31.000000
+             31.200001 31.400000 31.600000 31.799999 32.000000 32.200001 32.400002 32.599998
+             32.799999 33.000000 33.200001 33.400002 33.599998 33.799999 34.000000 34.200001
+             34.400002 34.599998 34.799999 35.000000 35.200001 35.400002 35.599998 35.799999
+             36.000000 36.200001 36.400002 36.599998 36.799999 37.000000 37.200001 37.400002
+             37.599998 37.799999 38.000000 38.200001 38.400002 38.599998 38.799999 39.000000
+             39.200001 39.400002 39.599998 39.799999 40.000000 40.200001 40.400002 40.599998
+             40.799999 41.000000 41.200001 41.400002 41.599998 41.799999 42.000000 42.200001
+             42.400002 42.599998 42.799999 43.000000 43.200001 43.400002 43.599998 43.799999
+             44.000000 44.200001 44.400002 44.599998 44.799999 45.000000 45.200001 45.400002
+             45.599998 45.799999 46.000000 46.200001 46.400002 46.599998 46.799999 47.000000
+             47.200001 47.400002 47.599998 47.799999 48.000000 48.200001 48.400002 48.599998
+             48.799999 49.000000 49.200001 49.400002 49.599998 49.799999 50.000000 50.200001
+             50.400002 50.599998 50.799999 51.000000 51.200001 51.400002 51.599998 51.799999
+             52.000000 52.200001 52.400002 52.599998 52.799999 53.000000 53.200001 53.400002
+             53.599998 53.799999 54.000000 54.200001 54.400002 54.599998 54.799999 55.000000
+             55.200001 55.400002 55.599998 55.799999 56.000000 56.200001 56.400002 56.599998
+             56.799999 57.000000 57.200001 57.400002 57.599998 57.799999 58.000000 58.200001
+             58.400002 58.599998 58.799999 59.000000 59.200001 59.400002 59.599998 59.799999
+             60.000000 60.200001 60.400002 60.599998 60.799999 61.000000 61.200001 61.400002
+             61.599998 61.799999 62.000000 62.200001 62.400002 62.599998 62.799999 63.000000
+             63.200001 63.400002 63.599998 63.799999 64.000000 64.199997 64.400002 64.599998
+             64.800003 65.000000 65.199997 65.400002 65.599998 65.800003 66.000000 66.199997
+             66.400002 66.599998 66.800003 67.000000 67.199997 67.400002 67.599998 67.800003
+             68.000000 68.199997 68.400002 68.599998 68.800003 69.000000 69.199997 69.400002
+             69.599998 69.800003 70.000000 70.199997 70.400002 70.599998 70.800003 71.000000
+             71.199997 71.400002 71.599998 71.800003 72.000000 72.199997 72.400002 72.599998
+             72.800003 73.000000 73.199997 73.400002 73.599998 73.800003 74.000000 74.199997
+             74.400002 74.599998 74.800003 75.000000 75.199997 75.400002 75.599998 75.800003
+             76.000000 76.199997 76.400002 76.599998 76.800003 77.000000 77.199997 77.400002
+             77.599998 77.800003 78.000000 78.199997 78.400002 78.599998 78.800003 79.000000
+             79.199997 79.400002 79.599998 79.800003 80.000000 80.199997 80.400002 80.599998
+             80.800003 81.000000 81.199997 81.400002 81.599998 81.800003 82.000000 82.199997
+             82.400002 82.599998 82.800003 83.000000 83.199997 83.400002 83.599998 83.800003
+             84.000000 84.199997 84.400002 84.599998 84.800003 85.000000 85.199997 85.400002
+             85.599998 85.800003 86.000000 86.199997 86.400002 86.599998 86.800003 87.000000
+             87.199997 87.400002 87.599998 87.800003 88.000000 88.199997 88.400002 88.599998
+             88.800003 89.000000 89.199997 89.400002 89.599998 89.800003 90.000000 90.199997
+             90.400002 90.599998 90.800003 91.000000 91.199997 91.400002 91.599998 91.800003
+             92.000000 92.199997 92.400002 92.599998 92.800003 93.000000 93.199997 93.400002
+             93.599998 93.800003 94.000000 94.199997 94.400002 94.599998 94.800003 95.000000
+             95.199997 95.400002 95.599998 95.800003 96.000000 96.199997 96.400002 96.599998
+             96.800003 97.000000 97.199997 97.400002 97.599998 97.800003 98.000000 98.199997
+            </two_theta>
+          <counts type="NX_INT32[400]" signal="1">
+             114 102 107 106 90 102 99 95 80 104
+             119 101 100 109 101 98 90 93 102 112
+             104 84 87 98 95 86 100 104 90 99
+             67 92 100 99 81 103 94 90 75 100
+             107 75 86 101 107 92 83 76 95 101
+             79 101 108 90 78 104 85 85 88 104
+             113 106 92 100 96 92 107 94 97 96
+             93 96 96 109 96 89 89 76 99 131
+             88 101 103 98 90 89 130 93 122 108
+             97 94 117 79 94 106 99 90 98 105
+             88 89 92 94 99 92 104 103 101 101
+             115 111 87 120 108 123 115 202 264 316
+             1036 3216 3380 1958 341 149 100 107 116 119
+             102 98 103 102 89 92 81 98 100 97
+             109 117 103 99 114 101 107 104 114 112
+             102 109 90 102 109 154 166 202 198 197
+             103 100 116 97 96 108 94 105 86 115
+             109 136 139 135 108 98 101 96 75 103
+             86 112 86 88 101 85 100 112 103 101
+             95 92 76 102 97 96 71 89 92 98
+             90 100 102 96 82 83 92 105 94 101
+             80 111 83 93 99 98 115 93 105 88
+             113 85 97 102 100 92 96 81 92 92
+             86 99 90 86 88 104 94 98 90 82
+             108 89 95 75 100 115 103 106 102 111
+             111 89 92 108 106 116 154 129 134 120
+             112 121 103 104 94 102 126 122 125 153
+             460 1292 1855 2198 2195 2030 1030 379 171 126
+             120 132 95 115 102 90 100 117 104 102
+             91 117 122 96 92 97 97 108 108 95
+             132 117 103 85 118 91 84 101 95 103
+             83 115 92 87 94 94 98 87 102 95
+             122 96 101 73 103 86 104 92 106 82
+             90 90 94 114 127 100 88 96 109 116
+             103 124 102 111 124 159 289 608 970 1573
+             1741 1989 1689 1365 884 460 241 165 142 124
+             132 123 105 127 113 116 126 122 111 122
+             108 113 114 112 105 122 120 107 126 108
+             125 104 123 102 126 112 85 114 115 102
+             103 116 101 130 106 99 99 112 105 116
+            </counts>
+        </NXpsd>
+      </NXinstrument>
+      <NXsample name="sample">
+        <sample_name>Ga0.94Mn0.04Sb_8mm</sample_name>
+        <sample_table_rotation type="NX_FLOAT32" units="degree">297.209991</sample_table_rotation>
+        <sample_temperature type="NX_FLOAT32" units="K">4.001050</sample_temperature>
+        <device_name>ccr4k</device_name>
+        <temperature_mean type="NX_FLOAT32" units="K">4.000000</temperature_mean>
+        <temperature_stddev type="NX_FLOAT32" units="K">0.000000</temperature_stddev>
+        <sample_mur type="NX_FLOAT32" units="degree">0.000000</sample_mur>
+      </NXsample>
+      <NXdata name="data1">
+        <counts type="NX_INT32[400]" signal="1">
+          114 102 107 106 90 102 99 95 80 104
+          119 101 100 109 101 98 90 93 102 112
+          104 84 87 98 95 86 100 104 90 99
+          67 92 100 99 81 103 94 90 75 100
+          107 75 86 101 107 92 83 76 95 101
+          79 101 108 90 78 104 85 85 88 104
+          113 106 92 100 96 92 107 94 97 96
+          93 96 96 109 96 89 89 76 99 131
+          88 101 103 98 90 89 130 93 122 108
+          97 94 117 79 94 106 99 90 98 105
+          88 89 92 94 99 92 104 103 101 101
+          115 111 87 120 108 123 115 202 264 316
+          1036 3216 3380 1958 341 149 100 107 116 119
+          102 98 103 102 89 92 81 98 100 97
+          109 117 103 99 114 101 107 104 114 112
+          102 109 90 102 109 154 166 202 198 197
+          103 100 116 97 96 108 94 105 86 115
+          109 136 139 135 108 98 101 96 75 103
+          86 112 86 88 101 85 100 112 103 101
+          95 92 76 102 97 96 71 89 92 98
+          90 100 102 96 82 83 92 105 94 101
+          80 111 83 93 99 98 115 93 105 88
+          113 85 97 102 100 92 96 81 92 92
+          86 99 90 86 88 104 94 98 90 82
+          108 89 95 75 100 115 103 106 102 111
+          111 89 92 108 106 116 154 129 134 120
+          112 121 103 104 94 102 126 122 125 153
+          460 1292 1855 2198 2195 2030 1030 379 171 126
+          120 132 95 115 102 90 100 117 104 102
+          91 117 122 96 92 97 97 108 108 95
+          132 117 103 85 118 91 84 101 95 103
+          83 115 92 87 94 94 98 87 102 95
+          122 96 101 73 103 86 104 92 106 82
+          90 90 94 114 127 100 88 96 109 116
+          103 124 102 111 124 159 289 608 970 1573
+          1741 1989 1689 1365 884 460 241 165 142 124
+          132 123 105 127 113 116 126 122 111 122
+          108 113 114 112 105 122 120 107 126 108
+          125 104 123 102 126 112 85 114 115 102
+          103 116 101 130 106 99 99 112 105 116
+         </counts>
+        <two_theta type="NX_FLOAT32[400]" axis="1" units="degree">
+          18.400000 18.600000 18.799999 19.000000 19.200001 19.400000 19.600000 19.799999
+          20.000000 20.200001 20.400000 20.600000 20.799999 21.000000 21.200001 21.400000
+          21.600000 21.799999 22.000000 22.200001 22.400000 22.600000 22.799999 23.000000
+          23.200001 23.400000 23.600000 23.799999 24.000000 24.200001 24.400000 24.600000
+          24.799999 25.000000 25.200001 25.400000 25.600000 25.799999 26.000000 26.200001
+          26.400000 26.600000 26.799999 27.000000 27.200001 27.400000 27.600000 27.799999
+          28.000000 28.200001 28.400000 28.600000 28.799999 29.000000 29.200001 29.400000
+          29.600000 29.799999 30.000000 30.200001 30.400000 30.600000 30.799999 31.000000
+          31.200001 31.400000 31.600000 31.799999 32.000000 32.200001 32.400002 32.599998
+          32.799999 33.000000 33.200001 33.400002 33.599998 33.799999 34.000000 34.200001
+          34.400002 34.599998 34.799999 35.000000 35.200001 35.400002 35.599998 35.799999
+          36.000000 36.200001 36.400002 36.599998 36.799999 37.000000 37.200001 37.400002
+          37.599998 37.799999 38.000000 38.200001 38.400002 38.599998 38.799999 39.000000
+          39.200001 39.400002 39.599998 39.799999 40.000000 40.200001 40.400002 40.599998
+          40.799999 41.000000 41.200001 41.400002 41.599998 41.799999 42.000000 42.200001
+          42.400002 42.599998 42.799999 43.000000 43.200001 43.400002 43.599998 43.799999
+          44.000000 44.200001 44.400002 44.599998 44.799999 45.000000 45.200001 45.400002
+          45.599998 45.799999 46.000000 46.200001 46.400002 46.599998 46.799999 47.000000
+          47.200001 47.400002 47.599998 47.799999 48.000000 48.200001 48.400002 48.599998
+          48.799999 49.000000 49.200001 49.400002 49.599998 49.799999 50.000000 50.200001
+          50.400002 50.599998 50.799999 51.000000 51.200001 51.400002 51.599998 51.799999
+          52.000000 52.200001 52.400002 52.599998 52.799999 53.000000 53.200001 53.400002
+          53.599998 53.799999 54.000000 54.200001 54.400002 54.599998 54.799999 55.000000
+          55.200001 55.400002 55.599998 55.799999 56.000000 56.200001 56.400002 56.599998
+          56.799999 57.000000 57.200001 57.400002 57.599998 57.799999 58.000000 58.200001
+          58.400002 58.599998 58.799999 59.000000 59.200001 59.400002 59.599998 59.799999
+          60.000000 60.200001 60.400002 60.599998 60.799999 61.000000 61.200001 61.400002
+          61.599998 61.799999 62.000000 62.200001 62.400002 62.599998 62.799999 63.000000
+          63.200001 63.400002 63.599998 63.799999 64.000000 64.199997 64.400002 64.599998
+          64.800003 65.000000 65.199997 65.400002 65.599998 65.800003 66.000000 66.199997
+          66.400002 66.599998 66.800003 67.000000 67.199997 67.400002 67.599998 67.800003
+          68.000000 68.199997 68.400002 68.599998 68.800003 69.000000 69.199997 69.400002
+          69.599998 69.800003 70.000000 70.199997 70.400002 70.599998 70.800003 71.000000
+          71.199997 71.400002 71.599998 71.800003 72.000000 72.199997 72.400002 72.599998
+          72.800003 73.000000 73.199997 73.400002 73.599998 73.800003 74.000000 74.199997
+          74.400002 74.599998 74.800003 75.000000 75.199997 75.400002 75.599998 75.800003
+          76.000000 76.199997 76.400002 76.599998 76.800003 77.000000 77.199997 77.400002
+          77.599998 77.800003 78.000000 78.199997 78.400002 78.599998 78.800003 79.000000
+          79.199997 79.400002 79.599998 79.800003 80.000000 80.199997 80.400002 80.599998
+          80.800003 81.000000 81.199997 81.400002 81.599998 81.800003 82.000000 82.199997
+          82.400002 82.599998 82.800003 83.000000 83.199997 83.400002 83.599998 83.800003
+          84.000000 84.199997 84.400002 84.599998 84.800003 85.000000 85.199997 85.400002
+          85.599998 85.800003 86.000000 86.199997 86.400002 86.599998 86.800003 87.000000
+          87.199997 87.400002 87.599998 87.800003 88.000000 88.199997 88.400002 88.599998
+          88.800003 89.000000 89.199997 89.400002 89.599998 89.800003 90.000000 90.199997
+          90.400002 90.599998 90.800003 91.000000 91.199997 91.400002 91.599998 91.800003
+          92.000000 92.199997 92.400002 92.599998 92.800003 93.000000 93.199997 93.400002
+          93.599998 93.800003 94.000000 94.199997 94.400002 94.599998 94.800003 95.000000
+          95.199997 95.400002 95.599998 95.800003 96.000000 96.199997 96.400002 96.599998
+          96.800003 97.000000 97.199997 97.400002 97.599998 97.800003 98.000000 98.199997
+         </two_theta>
+        <two_theta_start type="NX_FLOAT32" units="degree">18.400000</two_theta_start>
+        <Step type="NX_FLOAT32" units="degree">0.200000</Step>
+        <no_of_steps type="NX_INT32">400</no_of_steps>
+        <lambda type="NX_FLOAT32" units="Angstroem">2.566600</lambda>
+      </NXdata>
+    </NXentry>
+  </NXroot>
diff --git a/bindings/idl/data/focus2007n001335.hdf b/bindings/idl/data/focus2007n001335.hdf
new file mode 100644
index 0000000..22b666b
Binary files /dev/null and b/bindings/idl/data/focus2007n001335.hdf differ
diff --git a/bindings/idl/handle.c b/bindings/idl/handle.c
new file mode 100644
index 0000000..630cc1b
--- /dev/null
+++ b/bindings/idl/handle.c
@@ -0,0 +1,140 @@
+/*
+  This implements a handle management module. Sometimes it is useful to
+  protect the user of some software module from messing with complicated
+  datastructures. In such cases it is useful  to use an integer handle
+  which can be translated into a pointer when needed by the code implementing
+  the module. Such a scheme is implemented in this module.
+
+  Mark Koennecke, October 2000
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "handle.h"
+
+#define MAX_NUMBEROFLINKS 200
+
+static void **pointerArray = NULL;
+
+/* This is a 2 dimensional dynamic array assosiates the link handles with their
+ * file id handles so they can be removed with in nxclose.
+ */
+static int (*listOfNXlinks)[MAXHANDLE] = NULL;
+
+static int iscreated = 0;
+
+/*----------------------------------------------------------------------*/
+static void checkArray()
+{
+  if(pointerArray == NULL)
+  {
+      pointerArray = (void **)malloc(MAXHANDLE*sizeof(void *));
+      assert(pointerArray != NULL);
+      memset(pointerArray,0,MAXHANDLE*sizeof(void *));
+  }
+}
+/*--------------------------------------------------------------------*/
+int HHMakeHandle(void *pData)
+{
+  int i;
+
+  checkArray();
+  /*
+    find first free slot in the pointerArray, store the pointer and
+    return the index.
+  */
+  for(i = 0; i < MAXHANDLE; i++)
+  {
+     if(pointerArray[i] == NULL)
+     {
+	pointerArray[i] = pData;
+	iscreated = 1;
+	listOfNXlinks = calloc (MAX_NUMBEROFLINKS, sizeof (*listOfNXlinks));
+
+       return i;
+     }
+  }
+  return -1;
+}
+/*--------------------------------------------------------------------*/
+void HHChangeHandle(void *pData, int currentHandle)
+{
+  int i;
+
+	pointerArray[currentHandle] = pData;
+	iscreated = 1;
+
+}
+/*--------------------------------------------------------------------*/
+int HHMakeLinkHandle(void *pData, int currentHandle)
+{
+  int i;
+  int k;
+
+  checkArray();
+  /*
+    find first free slot in the pointerArray, store the pointer and
+    return the index.
+  */
+  for(i = 0; i < MAXHANDLE; i++)
+  {
+     if(pointerArray[i] == NULL)
+     {
+       pointerArray[i] = pData;
+
+
+	for(k = 0; k < MAX_NUMBEROFLINKS; k++)
+	{
+	if(listOfNXlinks[currentHandle][k] == NULL)
+		{
+		listOfNXlinks[currentHandle][k] = i;
+		return i;
+		}
+
+     	}
+    }
+  }
+
+   return -1;
+}
+
+
+/*---------------------------------------------------------------------*/
+void *HHGetPointer(int handle)
+{
+  checkArray();
+  return pointerArray[handle];
+}
+/*---------------------------------------------------------------------*/
+int HHRemoveHandle(int handle)
+{
+  int k;
+
+  assert(handle < MAXHANDLE && handle >= 0);
+  checkArray();
+  pointerArray[handle] = NULL;
+
+  for(k = 0; k < MAX_NUMBEROFLINKS; k++)
+	{
+	if(listOfNXlinks[handle][k] == NULL)
+		{
+		return(0);
+		}
+	free(pointerArray[(listOfNXlinks[handle][k])]);
+	pointerArray[(listOfNXlinks[handle][k])] = NULL;
+	}
+  return(-1);
+}
+
+/*---------------------------------------------------------------------*/
+int HHCheckIfHandleExists(int check)
+{
+  if(iscreated == 1) {
+	  if(pointerArray[check] == NULL)
+  	  	check = -1;
+  	  else check = 0;
+	  }
+  else check = -1;
+  return check;
+
+}
diff --git a/bindings/idl/handle.h b/bindings/idl/handle.h
new file mode 100644
index 0000000..cea93ce
--- /dev/null
+++ b/bindings/idl/handle.h
@@ -0,0 +1,23 @@
+/*
+  This implements a handle management module. Sometimes it is useful to
+  protect the user of some software module from messing with complicated
+  datastructures. In such cases it is useful  to use an integer handle
+  which can be translated into a pointer when needed by the code implementing
+  the module. Such a scheme is implemented in this module.
+
+  Mark Koennecke, October 2000
+*/
+#ifndef HANDLEHANDLE
+#define HANDLEHANDLE
+
+/* The maximum number of handles. */
+#define MAXHANDLE 8192
+
+  int HHMakeHandle(void *pData);
+  void  *HHGetPointer(int handle);
+  void HHChangeHandle(void *pData, int currentHandle);
+  int HHRemoveHandle(int handle);  
+  int HHMakeLinkHandle(void *pData, int currentHandle); 
+  int HHCheckIfHandleExists(int check);
+#endif
+ 
diff --git a/bindings/idl/nxext.h5 b/bindings/idl/nxext.h5
new file mode 100644
index 0000000..5d765bd
Binary files /dev/null and b/bindings/idl/nxext.h5 differ
diff --git a/bindings/idl/nxext.hdf b/bindings/idl/nxext.hdf
new file mode 100644
index 0000000..939eb12
Binary files /dev/null and b/bindings/idl/nxext.hdf differ
diff --git a/bindings/idl/nxext.xml b/bindings/idl/nxext.xml
new file mode 100644
index 0000000..f70f71b
Binary files /dev/null and b/bindings/idl/nxext.xml differ
diff --git a/bindings/idl/read_test.pro b/bindings/idl/read_test.pro
new file mode 100644
index 0000000..aba06c5
--- /dev/null
+++ b/bindings/idl/read_test.pro
@@ -0,0 +1,336 @@
+pro read_test, argument
+	;new_dlm_file = '/home/scratch/lns/kauppila/temp/IDLNeXus-API/NeXusIDL-API.dlm'
+	;new_dlm_file =  'C:\temp\dlm\dlm\testmodule.dlm'
+	;DLM_REGISTER, new_dlm_file
+
+        filename = 'nothing'
+
+        if (N_PARAMS() GE 1) then begin
+
+                if(strcmp(argument, 'hdf5') EQ 1) then begin
+                        filename = 'NXtest.h5'
+			print, 'Opening file: ', filename
+                        endif
+
+                if(strcmp(argument, 'hdf4') EQ 1) then begin
+                        filename = 'NXtest.hdf'
+			print, 'Opening file: ', filename
+                endif
+
+                if(strcmp(argument, 'xml') EQ 1) then begin
+                        filename = 'NXtest.xml'
+			print, 'Opening file: ', filename
+                endif
+        endif
+
+        if (strcmp(filename, 'nothing') EQ 1) then begin
+                filename = 'NXtest.h5'
+		print, 'Default, Opening file: ', filename
+
+       endif
+
+
+
+
+	nx_char = 4
+	nx_float32 = 5
+	nx_float64 = 6
+	nx_int8 = 20
+	nx_uint8 = 21
+	nx_int16 = 22
+	nx_Uint16 = 23
+	nx_int32 = 24
+	nx_Uint32 = 25
+
+	S = nxopen(filename,"NXACC_RDWR",fileid)
+	print, 'nxopen status: ',S
+
+	S = nxinquirefile(fileid, filename, 20)
+	print, 'nxinquirefile status: ', S
+        if (S EQ 1) then begin
+		print, 'nxinquirefile found: ',  filename
+	endif
+
+	S = nxgetattrinfo(fileid, numberofattr)
+        print, 'nxgetattrinfo status:',S
+
+	if (numberofattr GT 0) then print, 'Number of global attributes: ', numberofattr
+
+	repeat begin
+		attr_status = NXgetnextattr (fileid, attrname, lenght,attr_type)
+		print, ''
+		print, 'NXgetnextattr status: ', attr_status
+		print, ''
+		if (attr_status EQ 1) then begin
+			S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+			print, 'attribute name: ', attrname
+			;print, 'attrubute lenght: ', lenght
+			;print, 'attribute type: ', attr_type
+			print, format='("attribute value: ",A)', value
+		endif
+	endrep until (attr_status NE 1)
+
+	S = nxopengroup(fileid,"entry","NXentry")
+	print, 'nxopengroup status:',S
+
+	S = nxgetattrinfo(fileid, numberofattr)
+        print, 'nxgetattrinfo status:',S
+	print, 'Number of group attributes: ', numberofattr
+
+	repeat begin
+		attr_status = NXgetnextattr (fileid, attrname, lenght, attr_type)
+		print, 'NXgetnextattr status: ', attr_status
+		if (attr_status EQ 1) then begin
+			S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+			print, 'nxgetattr status', S
+			print, 'attribute name: ', attrname
+			print, 'attrubute lenght: ', lenght
+			print, 'attribute type: ', attr_type
+			print, 'attribute value: ', value
+			print, ''
+		endif
+	endrep until (attr_status NE 1)
+
+         S = nxgetgroupinfo(fileid, item_number, group_name, group_class)
+       print, 'nxgetgroupinfo status', S
+
+		print, 'current group name: ', group_name
+	        print, 'current group class: ', group_class
+	        print, 'number of items in group: ', item_number
+	        print, ''
+
+	repeat begin
+		entry_status = nxgetnextentry(fileid, name, class, data_type)
+		print, 'nxgetnextentry status: ', entry_status
+		if(entry_status NE -1) then begin
+			print, 'nxgetnextentry name: ', name
+			print, 'nxgetnextentry class: ', class
+			print, 'nxgetnextentry data_type', data_type;			
+			print, ''
+		end
+
+		if(strcmp(class, 'SDS')) then begin
+			print, 'opening data: ', name
+			S = nxopendata(fileid, name)
+			print, 'nxopendata status: ',S
+			print, ''
+
+			S = nxgetinfo(fileid, rank, di, datatype)
+			print, 'nxgetinfo Status:', S
+			print, 'Rank:', rank
+			for i = 0,rank-1 DO print, 'Dim [',i,']:', di[i]
+			print, 'Data Type:', datatype
+			print, ''
+
+			if(datatype EQ nx_char) then begin
+				S = nxgetdata(fileid, data)
+				print, 'nxget data status: ', S
+				print, 'data :'
+				print,  data;				
+				print, ''
+			endif else begin;				
+				slabstart = [0L,0L]
+				slabsize = [1L,4L]
+
+				S = nxgetslab(fileid, data, slabstart, slabsize)
+				print, 'nxgetslab status: ', S
+			        print, 'data :'
+				print, data
+				print, ''
+
+				slabstart[0] = 1
+				S = nxgetslab(fileid, data, slabstart, slabsize)
+				print, 'nxgetslab status: ', S
+			        print, 'data :'
+				print, data
+				print, ''
+
+				slabstart[0] = 2
+				S = nxgetslab(fileid, data, slabstart, slabsize)
+				print, 'nxgetslab status: ', S
+			        print, 'data :'
+				print, data
+				print, ''
+
+				slabstart[0] = 3
+				S = nxgetslab(fileid, data, slabstart, slabsize)
+				print, 'nxgetslab status: ', S
+			        print, 'data :'
+				print, data
+				print, ''
+			endelse
+
+			S = nxgetattrinfo(fileid, numberofattr)
+		        print, 'nxgetattrinfo status:',S
+			print, 'Number of group attributes: ', numberofattr
+			if (numberofattr GT 0) then print, 'Number of global attributes: ', numberofattr
+
+			repeat begin
+				attr_status = NXgetnextattr (fileid, attrname, lenght, attr_type)
+				print, 'nxgetnextattr status: ', attr_status
+				if (attr_status EQ 1) then begin
+					S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+					print, 'nxgetattr status', S
+					print, 'attribute name: ', attrname
+					print, 'attribute value: ', value
+					print, ''
+				endif
+			endrep until (attr_status NE 1)
+
+			S = nxclosedata(fileid)
+			print, "nxclosedata status: ", S
+		endif
+
+	endrep until (entry_status NE 1)
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+
+	print, ''
+	print, '#######################  Checking Links ###########################'
+	print, ''
+
+	S = nxopengroup(fileid,"entry","NXentry")
+	print, 'nxopengroup status:',S
+	print, ''
+
+	S = nxopengroup(fileid,"sample","NXsample")
+	print, 'nxopengroup status:',S
+	print, ''
+
+		S = nxgetgroupid(fileid, groupid1)
+		print, 'nxgetgroupid status: ', S
+		print, 'groupid handle: ', groupid1
+		print, ''
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+	print, ''
+
+	S = nxopengroup(fileid,"data","NXdata")
+	print, 'nxopengroup status:',S
+	print, ''
+
+		S = nxopendata(fileid, 'r8_data')
+		print, 'nxopendata status: ',S
+		print, ''
+
+			S = nxgetdataid(fileid, dataid1)
+			print, 'nxgetdataid status: ', S
+			;print, 'dataid handle: ', dataid
+
+		S = nxclosedata(fileid)
+		print, 'nxclosedata status: ', S
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+	print, ''
+
+	S = nxopendata(fileid, 'r8_data')
+	print, 'nxopendata status: ',S
+	print, ''
+
+		S = nxgetdataid(fileid, dataid2)
+		print, 'nxgetdataid status: ', S
+		;print, 'dataid handle: ', dataid
+
+	S = nxclosedata(fileid)
+	print, 'nxclosedata status: ', S
+
+	print, 'debug'
+	S = nxsameid(fileid, dataid1, dataid2)
+        print, 'nxsamid status: ', S
+	if(S EQ 1) then begin
+	print, 'Data id: Link check succesfull'
+	endif else begin
+		print, 'Data id: Link check FAILED (sample)'
+	endelse
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+	print, ''
+
+	S = nxopengroup(fileid,'link','NXentry')
+	print, 'nxopengroup status:',S
+	print, ''
+
+	S = nxopengroup(fileid,"sample","NXsample")
+	print, 'nxopengroup status:',S
+	print, ''
+
+		S = nxgetgroupid(fileid, groupid2)
+		print, 'nxgetgroupid status: ', S
+		;print, 'groupid handle: ', groupid2
+		print, ''
+
+	S = nxsameid(fileid, groupid1, groupid2)
+	if(S EQ 1) then begin
+	print, 'Group Id: Link check succesfull'
+	endif else begin
+		print, 'Group Id: Link check FAILED (sample)';	
+	endelse
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+	print, ''
+
+	S = nxopengroup(fileid,"renLinkGroup","NXsample")
+	print, 'nxopengroup status:',S
+	print, ''
+
+		S = nxgetgroupid(fileid, groupid_named)
+		print, 'nxgetgroupid status: ', S
+		;print, 'groupid handle: ', groupid2
+		print, ''
+
+		S = nxsameid(fileid, groupid1, groupid_named)
+		if(S EQ 1) then begin
+		print, 'Group Id Named: Link check succesfull'
+		endif else begin
+		print, 'Group Id Named: Link check FAILED (sample)';
+		endelse
+
+
+	print, ''
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+	print, ''
+
+	S = nxopendata(fileid, 'renLinkData')
+	print, 'nxopendata status: ',S
+	print, ''
+
+		S = nxgetdataid(fileid, dataid_named)
+		print, 'nxgetdataid status: ', S
+		;print, 'dataid handle: ', dataid
+
+
+		S = nxsameid(fileid, dataid1, dataid_named)
+		if(S EQ 1) then begin
+		print, 'Data Id Named: Link check succesfull'
+		endif else begin
+		print, 'Data Id Named: Link check FAILED (sample)'
+		endelse
+
+	S = nxclosedata(fileid)
+	print, 'nxclosedata status: ', S
+
+	;nxopenpath tests
+
+	S = nxopenpath(fileid, '/entry/data/comp_data')
+	if(S EQ 1) then begin
+	print, 'Openpath succesfull (/entry/data/comp_data)'
+	endif else begin
+		print, 'Openpath FAILED (/entry/data/comp_data)'
+	endelse
+
+	S = nxopenpath(fileid, '../r8_data')
+	if(S EQ 1) then begin
+	print, 'Openpath on a relative path  (../r8_data) succesfull'
+	endif else begin
+		print, 'Openpath on a relative path FAILED (../r8_data)'
+        endelse
+
+	S = nxclose(fileid)
+	print, 'nxclose status: ',S
+
+end
diff --git a/bindings/idl/recursiveread.pro b/bindings/idl/recursiveread.pro
new file mode 100644
index 0000000..b17d631
--- /dev/null
+++ b/bindings/idl/recursiveread.pro
@@ -0,0 +1,161 @@
+pro opendir, fileid
+	S = nxinitgroupdir (fileid)
+	print, 'nxinitgroupdir', S
+	print, ''
+
+
+
+	S = nxgetgroupinfo(fileid, item_number, group_name, group_class)
+	print, 'nxgetgroupinfo status', S
+	print, 'current group name: ', group_name
+	print, 'current group class: ', group_class
+	print, 'number of items in group', item_number
+	print, ''
+
+	for j = 1, item_number, 1 do begin
+		;wait, 1
+		S = nxgetnextentry(fileid, name, class, data_type)
+		print, 'nxgetnextentry status: ', S
+		print, 'nxgetnextentry name: ', name
+		print, 'nxgetnextentry class: ', class
+		print, 'nxgetnextentry data_type', data_type
+		print, ''
+		if (strcmp(class, 'SDS')) then begin
+
+			print, 'opening data: ', name
+			S = nxopendata(fileid, name)
+			print, 'nxopendata status:', S
+			print, ''
+			if(S EQ 1) then opendata, fileid
+			S = nxclosedata(fileid)
+			print, 'nxclosedata status', S
+			print, ''
+
+		endif else begin
+			S = nxisexternalgroup(fileid ,name, class, nxurl, 100)
+			print, 'nxisexternalgroup status: ', S
+			if (S EQ 1) then begin
+				print, 'Group is an externally link group'
+				print, 'nxisexternalgroup url:', nxurl
+				print, ''
+				S = nxinquirefile(fileid,filename, 100);
+				print, 'nxinquirefile status:', S
+				print, 'file currently open: ', filename
+			endif
+			S = nxopengroup(fileid, name, class)
+			print, 'nxopengroup status', S
+			print, ''
+
+			if(S EQ 1) then opendir, fileid
+
+			S = nxclosegroup(fileid)
+			print, 'nxclosegroup status', S
+			print, ''
+
+		endelse
+
+	endfor
+
+end
+
+pro opendata, fileid
+
+        S = nxgetinfo(fileid, rank, di, info_type)
+        print, 'nxgetinfo status:', S
+        print, 'rank:', rank
+        for i = 0,rank-1 DO print, 'Dim [',i,']:', di[i]
+        print, 'Data Type:', info_type
+	print, ''
+	S = nxgetdata(fileid, data)
+        print, 'nxgetdata status: ', S
+        print, 'data :'
+        print,  data
+	print, ''
+        S = nxgetattrinfo(fileid, numberofattr)
+        print, 'nxgetattrinfo status:',S
+        print, 'number of attributes: ', numberofattr
+
+	;S= nxinitattrdir (fileid)
+	print, 'nxinitattrdir', S
+	print, ''
+
+	for j = 1, numberofattr, 1 do begin
+		S = nxgetnextattr(fileid, attrname, lenght,attr_type)
+	        print, 'attribute name: ', attrname
+	        print, 'attrubute lenght: ', lenght
+	        print, 'attribute type: ', attr_type
+
+		S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+	        ;print, 'attribute name: ', attrname
+	        ;print, 'attrubute lenght: ', lenght
+	        ;print, 'attribute type: ', attr_type
+	        print, 'attribute value: ', value
+		print, ''
+
+	endfor
+
+end
+
+
+pro recursiveread, filepath
+        new_dlm_file = '/home/scratch/lns/kauppila/temp/IDLNeXus-API/NeXusIDL-API.dlm'
+        DLM_REGISTER, new_dlm_file
+
+
+;	S = nxopen("data/nx.hdf","NXACC_READ",fileid)
+;	S = nxopen("data/dmc01.h5","NXACC_READ",fileid)
+;	S = nxopen("data/dmc01.hdf","NXACC_READ",fileid)
+;	S = nxopen("data/dmc01.xml","NXACC_READ",fileid)
+;	S = nxopen("data/dmc02.h5","NXACC_READ",fileid)
+;	S = nxopen("data/dmc02.hdf","NXACC_READ",fileid)
+;	S = nxopen("data/dmc02.xml","NXACC_READ",fileid)
+;	S = nxopen("data/NXtest.nxs","NXACC_READ",fileid)
+;	S = nxopen("data/NXtest.hdf","NXACC_READ",fileid)
+;	S = nxopen("NXtest.nxs","NXACC_READ",fileid)
+;	S = nxopen("C:\temp\dlm\dlm\NXtest.nxs","NXACC_READ",fileid)
+;	S = nxopen("C:\temp\dlm\dlm\data\dmc01.h5","NXACC_READ",fileid)
+
+	if(N_PARAMS() EQ 1) then begin
+		S = nxopen(filepath,"NXACC_READ",fileid)
+
+	endif else begin	
+		print, 'Reading default file NXtest.h5' 
+		S = nxopen("NXtest.h5","NXACC_READ",fileid)
+	endelse
+
+ 	print, 'nxopen status: ',S
+	print, ''
+
+	opendir, fileid
+
+	; Read global attributes
+
+        S = nxgetattrinfo(fileid, numberofattr)
+        print, 'nxgetattrinfo status:',S
+        print, 'number of attributes: ', numberofattr
+
+        S= nxinitattrdir (fileid)
+        print, 'nxinitattrdir', S
+        print, ''
+
+        for j = 1, numberofattr, 1 do begin
+                S = nxgetnextattr(fileid, attrname, lenght,attr_type)
+                print, 'global attribute name: ', attrname
+                print, 'global attrubute lenght: ', lenght
+                print, 'global attribute type: ', attr_type
+
+                S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+                ;print, 'global attribute name: ', attrname
+                ;print, 'global attrubute lenght: ', lenght
+                ;print, 'global attribute type: ', attr_type
+                print, 'global attribute value: ', value
+                print, ''
+
+        endfor
+
+
+
+	S = nxclose(fileid)
+	print, 'nxclose status: ', S
+end
+
diff --git a/bindings/idl/recursivesearch.pro b/bindings/idl/recursivesearch.pro
new file mode 100644
index 0000000..7b2856a
--- /dev/null
+++ b/bindings/idl/recursivesearch.pro
@@ -0,0 +1,175 @@
+functiorecursivesearch, filepath
+        ;new_dlm_file = '/home/scratch/lns/kauppila/temp/IDLNeXus-API/NeXusIDL-API.dlm'
+        ;DLM_REGISTER, new_dlm_file
+
+;	S = nxopen("data/nx.hdf","NXACC_READ",fileid)
+;	S = nxopen("data/dmc01.h5","NXACC_READ",fileid)
+;	S = nxopen("data/dmc01.hdf","NXACC_READ",fileid)
+;	S = nxopen("data/dmc01.xml","NXACC_READ",fileid)
+;	S = nxopen("data/dmc02.h5","NXACC_READ",fileid)
+;	S = nxopen("data/dmc02.hdf","NXACC_READ",fileid)
+;	S = nxopen("data/dmc02.xml","NXACC_READ",fileid)
+;	S = nxopen("data/NXtest.nxs","NXACC_READ",fileid)
+;	S = nxopen("data/NXtest.hdf","NXACC_READ",fileid)
+;	S = nxopen("NXtest.nxs","NXACC_READ",fileid)
+;	S = nxopen("C:\temp\dlm\dlm\NXtest.nxs","NXACC_READ",fileid)
+;	S = nxopen("C:\temp\dlm\dlm\data\dmc01.h5","NXACC_READ",fileid)
+
+	if(N_PARAMS() EQ 1) then begin
+		S = nxopen(filepath,"NXACC_READ",fileid)
+
+	paths = strarr(20)
+
+	endif else begin	
+		print, 'Reading default file NXtest.h5' 
+		;S = nxopen("NXtest.h5","NXACC_READ",fileid)
+		S = nxopen("data/dmc02.h5","NXACC_READ",fileid)
+
+	endelse
+
+ 	print, 'nxopen status: ',S
+	print, ''
+
+	common cblock, testpaths
+	common cblock2, numberofsignals
+
+	numberofsignals = 0
+	testpaths = strarr(20)
+
+	opendir, fileid, paths
+
+	; Read global attributes
+
+        S = nxgetattrinfo(fileid, numberofattr)
+;        print, 'nxgetattrinfo status:',S
+        print, 'number of global attributes: ', numberofattr
+
+        S= nxinitattrdir (fileid)
+;        print, 'nxinitattrdir', S
+;       print, ''
+
+        for j = 1, numberofattr, 1 do begin
+                S = nxgetnextattr(fileid, attrname, lenght,attr_type)
+                print, 'global attribute name: ', attrname
+                print, 'global attrubute lenght: ', lenght
+                print, 'global attribute type: ', attr_type
+
+                S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+                ;print, 'global attribute name: ', attrname
+                ;print, 'global attrubute lenght: ', lenght
+                ;print, 'global attribute type: ', attr_type
+                print, 'global attribute value: ', value
+                print, ''
+
+        endfor
+
+	S = nxclose(fileid)
+;	print, 'nxclose status: ', S
+
+	print, 'signal 1 found in paths: '
+
+	print, testpaths[0]
+	print, testpaths[1]
+
+	RETURN, testpaths
+end
+
+pro opendir, fileid, paths
+
+	common cblock
+	common cblock2
+
+	S = nxgetgroupinfo(fileid, item_number, group_name, group_class)
+	;print, 'nxgetgroupinfo status', S
+	print, 'current group name: ', group_name
+	;print, 'current group class: ', group_class
+	print, 'number of items in group', item_number
+	print, ''
+
+	for j = 1, item_number, 1 do begin
+
+		S = nxgetnextentry(fileid, name, class, data_type)
+		print, 'nxgetnextentry status: ', S
+		if(S EQ 1) then begin
+			print, 'nxgetnextentry name: ', name
+			;print, 'nxgetnextentry class: ', class
+			;print, 'nxgetnextentry data_type', data_type
+				print, ''
+			if (strcmp(class, 'SDS')) then begin
+
+				print, 'opening data: ', name
+				S = nxopendata(fileid, name)
+				;print, 'nxopendata status:', S
+				;print, ''
+				if(S EQ 1) then begin 
+
+					result = opendata(fileid)
+
+					if(result EQ 1) then begin
+						print, 'SIGNAL 1 FOUND'
+						testpaths[numberofsignals] = '/' + group_name + '/'+ name
+						print, 'SIGNAL 1 FOUND in : ', testpaths[1]
+						numberofsignals = numberofsignals + 1
+					endif
+
+				endif
+				
+
+				S = nxclosedata(fileid)
+				;print, 'nxclosedata status', S
+				;print, ''
+
+			endif else begin
+
+				S = nxopengroup(fileid, name, class)
+				;print, 'nxopengroup status', S
+				;print, ''
+				if(S EQ 1) then begin
+					opendir, fileid, paths
+				endif
+	
+				S = nxclosegroup(fileid)
+				;print, 'nxclosegroup status', S
+				;print, ''
+	
+			endelse
+		endif
+	endfor
+
+end
+
+function opendata, fileid
+
+        S = nxgetdata(fileid, data)
+        ;print, 'nxgetdata status: ', S
+        ;print, 'data :'
+        ;print,  data
+	;print, ''
+        S = nxgetattrinfo(fileid, numberofattr)
+        ;print, 'nxgetattrinfo status:',S
+        print, 'number of attributes: ', numberofattr
+
+	;S= nxinitattrdir (fileid)
+	;print, 'nxinitattrdir', S
+	;print, ''
+
+	for j = 1, numberofattr, 1 do begin
+		S = nxgetnextattr(fileid, attrname, lenght,attr_type)
+		if(S EQ 1) then begin
+		        ;print, 'attribute name: ', attrname
+		        ;print, 'attrubute lenght: ', lenght
+		        ;print, 'attribute type: ', attr_type
+
+			S = nxgetattr(fileid, attrname, value, lenght,attr_type)
+		        ;print, 'attribute name: ', attrname
+		        ;print, 'attrubute lenght: ', lenght
+		        ;print, 'attribute type: ', attr_type
+		        print, 'attribute value: ', value
+			print, ''
+			if((strcmp(attrname, 'signal')) AND (strcmp(string(value), '1'))) then begin
+				RETURN, 1
+			endif
+		endif
+	endfor
+	RETURN, 0
+end
diff --git a/bindings/idl/testfocus.pro b/bindings/idl/testfocus.pro
new file mode 100644
index 0000000..f2d3172
--- /dev/null
+++ b/bindings/idl/testfocus.pro
@@ -0,0 +1,8 @@
+DLM_REGISTER, 'NeXusIDL-API.dlm'
+
+s = nxopen('data/focus2007n001335.hdf',"NXACC_READ",fileid)
+s = nxopenpath(fileid,'/entry1/merged/counts')
+s = nxgetdata(fileid,data)
+;s = nxclose(fileid)
+loadct, 0
+tvscl, data
diff --git a/bindings/idl/testidlnapi b/bindings/idl/testidlnapi
new file mode 100755
index 0000000..f4697c9
--- /dev/null
+++ b/bindings/idl/testidlnapi
@@ -0,0 +1,14 @@
+#!/bin/bash
+IDLTMP=/tmp/nxidl.$$
+test=$1
+echo $test
+idl << EOF > $IDLTMP 2>&1
+print, 'starting napi test'
+write_test, $test
+read_test, $test
+print, 'finished napi test'
+EOF
+# need to remove IDL startup infomation as this is different on each machine
+# also remove file_time as it will be different every time
+sed -n -e '/^NeXus IDL Api Write test/,/^finished napi test/ p' < $IDLTMP | sed -e '/file_time/,/attribute value/ d'
+rm -f $IDLTMP
diff --git a/bindings/idl/write_test.pro b/bindings/idl/write_test.pro
new file mode 100644
index 0000000..fe5600e
--- /dev/null
+++ b/bindings/idl/write_test.pro
@@ -0,0 +1,379 @@
+pro write_test, argument
+
+	new_dlm_file = 'NeXusIDL-API.dlm'
+	DLM_REGISTER, new_dlm_file
+
+	print, 'NeXus IDL Api Write test'
+	access_method = 'nothing'
+
+	if (N_PARAMS() GE 1) then begin
+
+		if(strcmp(argument, 'hdf5') EQ 1) then begin
+			print, 'Using HDF5'
+			access_method = 'NXACC_CREATE5'
+			filename = 'NXtest.h5'
+			extfile = 'nxext.h5'
+			link_external_path = 'nxfile://data/dmc01.h5#/entry1'
+			endif
+
+		if(strcmp(argument, 'hdf4') EQ 1) then begin
+			print, 'Using HDF4'
+			access_method = 'NXACC_CREATE'
+			filename = 'NXtest.hdf'
+			extfile = 'nxext.hdf'
+			link_external_path = 'nxfile://data/dmc01.hdf#/entry1'
+		endif
+
+		if(strcmp(argument, 'xml') EQ 1) then begin
+			access_method = 'NXACC_CREATEXML'
+			print, 'Using XML'
+			filename = 'NXtest.xml'
+			extfile = 'nxext.xml'
+			link_external_path = 'nxfile://data/dmc01.xml#/entry1'
+		endif
+	endif
+
+	if (strcmp(access_method, 'nothing') EQ 1) then begin
+		print, 'Using Default Access Method: HDF5'
+		access_method = 'NXACC_CREATE5'
+		filename = 'NXtest.h5'
+		extfile = 'nxext.h5'
+		link_external_path = 'nxfile://data/dmc01.h5#/entry1'
+	endif
+
+	; Windows (set correct path)
+	;link_external_path = 'nxfile://C:\temp\dlm\dlm\data\dmc01.hdf#/entry1'
+
+	; Linux
+
+
+	; nxdatatypes:
+	nx_int16 = 22
+	nx_int32 = 24
+	nx_float32 = 5
+	nx_float64 = 6
+	nx_uint16 = 22
+
+	;access_method = 'NXACC_CREATE5'
+	;access_method = 'NXACC_CREATE'
+
+	; Only type LONG arrays are accepted in dimensions and chunck size.
+	array_dims =[4L,4L]
+	chunk_size =[4L,4L]
+
+	rank = 2
+
+	nx_uint8_array = BytArr(4, 4)
+	v1 = [0B,1B,2B,4B]
+	v2 = [4B,5B,6B,7B]
+	v3 = [8B,9B,10B,11B]
+	v4 = [12B,13B,14B,15B]
+	nx_uint8_array =[[v1],[v2],[v3],[v4]]
+
+	nx_int16_array = IntArr(4, 4)
+	v1 = [0S,1S,2S,4S]
+	v2 = [4S,5S,6S,7S]
+	v3 = [-8S,-9S,-10S,-11S]
+	v4 = [-12S,-13S,-14S,-15S]
+	nx_int16_array =[[v1],[v2],[v3],[v4]]
+
+	nx_int16_array = UIntArr(4, 4)
+	v1 = [0U,1U,2U,4U]
+	v2 = [4U,5U,6U,7U]
+	v3 = [-8U,-9U,-10U,-11U]
+	v4 = [-12U,-13U,-14U,-15U]
+	nx_int16_array =[[v1],[v2],[v3],[v4]]
+
+	nx_int32_array = LonArr(4, 4)
+	v1 = [0L,1L,2L,3L]
+	v2 = [4L,5L,6L,7L]
+	v3 = [8L,9L,10L,11L]
+	v4 = [12L,13L,14L,15L]
+	nx_int32_array =[[v1],[v2],[v3],[v4]]
+
+	nx_uint32_array = ULonArr(4, 4)
+	v1 = [0UL,1UL,2UL,3UL]
+	v2 = [4UL,5UL,6UL,7UL]
+	v3 = [-8UL,-9UL,-10UL,-11UL]
+	v4 = [-12UL,-13UL,-14UL,-15UL]
+	nx_uint32_array =[[v1],[v2],[v3],[v4]]
+
+	nx_float32_array = FltArr(4, 4)
+	v1 = [0.0111112,0.02122222,0.233333333,0.34444444]
+	v2 = [0.3443333,0.55555554,0.666666667,0.77777333]
+	v3 = [0.6666689,0.99999977,10.10000023,11.2222209]
+	v4 = [-12.20002,-13.444442,-14.2222223,-15.444444]
+	nx_float32_array =[[v1],[v2],[v3],[v4]]
+
+	nx_float64_array = ULonArr(4, 4)
+	v1 = [0.0111112D,0.02122222D,0.233333333D,0.34444444D]
+	v2 = [0.3443333D,0.55555554D,0.666666667D,0.77777333D]
+	v3 = [0.6666689D,0.99999977D,10.10000023D,11.2222209D]
+	v4 = [-12.20002D,-13.444442D,-14.2222223D,-15.444444D]
+	nx_float64_array =[[v1],[v2],[v3],[v4]]
+
+        S = nxopen(filename, access_method, fileid)
+	print, 'nxopen status: ', S
+	S = nxsetnumberformat(fileid,"NX_FLOAT32",'%9.3f')
+	print, 'nxsetnumberformat status: ', S
+
+        S = nxmakegroup(fileid, "entry", "NXentry")
+	print, 'nxmakegroup status: ', S
+        S = nxopengroup(fileid, "entry", "NXentry")
+	print, 'nxopengroup status: ', S
+;        S = nxmakegroup(fileid, "anothergroup", "NXentry")
+;	print, 'nxmakegroup status: ', S
+	S = nxputattr(fileid, "hugo", "namenlos",strlen('namenlos'), 'NX_CHAR')
+	print, 'nxputattr status: ', S
+	S = nxputattr(fileid, "cucumber", "passion",strlen('passion'), 'NX_CHAR')
+	print, 'nxputattr status: ', S
+
+	; needs to be an array?
+	nxlen = [10L]
+
+	S = nxmakedata(fileid, 'ch_data','NX_CHAR', 1, nxlen)
+        print, 'nxmakedata status: ', S
+        S = nxopendata(fileid, "ch_data")
+        print, "opendata status: ", S
+	S = nxputdata(fileid, 'NeXus Data')
+	print, 'nxputdata status:', S
+	S = nxclosedata(fileid)
+	print, "nxclosedata status: ", S
+
+	S = nxmakedata(fileid, 'i1_data','NX_UINT8', 2, array_dims)
+        print, 'nxmakedata status: ', S
+	S = nxopendata(fileid, "i1_data")
+        print, "opendata status: ", S
+	S = nxputdata(fileid, nx_uint8_array)
+	print, 'nxputdata status:', S
+	S = nxclosedata(fileid)
+	print, "nxclosedata status: ", S
+
+	S = nxmakedata(fileid, 'i4_data','NX_INT32', 2, array_dims)
+        print, 'nxmakedata status: ', S
+	S = nxopendata(fileid, "i4_data")
+        print, "opendata status: ", S
+	S = nxputdata(fileid, nx_int32_array)
+	print, 'nxputdata status:', S
+	S = nxclosedata(fileid)
+	print, "nxclosedata status: ", S
+
+	S = nxcompmakedata(fileid, 'r4_data','NX_FLOAT32', 2, array_dims, 'NX_COMP_LZW', chunk_size)
+        print, 'nxmakedata status: ', S
+	S = nxopendata(fileid, "r4_data")
+        print, "opendata status: ", S
+	S = nxputdata(fileid, nx_float32_array)
+	print, 'nxputdata status:', S
+	S = nxclosedata(fileid)
+	print, "nxclosedata status: ", S
+
+
+
+	S = nxmakedata(fileid, 'r8_data','NX_FLOAT64', 2, array_dims)
+        print, 'nxmakedata status: ', S
+	S = nxopendata(fileid, "r8_data")
+        print, "opendata status: ", S
+
+		slab_start = [2L,0L]
+		slab_size = [1L,4L]
+		S = nxputslab(fileid, nx_float64_array, slab_start, slab_size)
+		print, 'nxputslab status:', S
+
+		S = nxputattr(fileid,'ch_attribute', 'NeXus', strlen ('NeXus'), 'NX_CHAR')
+		print, 'nxputattr status : ',S
+
+		i = 42L
+		S = nxputattr(fileid,'i4_attribute', i, 1, 'NX_INT32')
+		print, 'nxputattr status : ',S
+
+		r = 3.14159265
+		S = nxputattr(fileid,'r4_attribute', r, 1, 'NX_FLOAT32')
+		print, 'nxputattr status : ',S
+		S = nxgetdataid(fileid, dataid)
+		print, 'nxgetdataid status: ', S
+		;print, 'dataid handle: ', dataid
+
+
+	S = nxclosedata(fileid)
+	print, "nxclosedata status: ", S
+
+	S = nxmakegroup(fileid, 'data', 'NXdata')
+	print, 'nxmakegroup status: ', S
+
+        S = nxopengroup(fileid, 'data', 'NXdata')
+	print, 'nxopengroup status: ', S
+
+	S = nxmakelink(fileid, dataid)
+	print, 'nxmakelink status: ', S
+
+	dims = [100L,20L]
+	; indexed array of longs
+	comp_array = lindgen(100,20)
+        cdims = [20L,20L]
+	rank = 2
+
+	S = nxcompmakedata(fileid, 'comp_data', 'NX_INT32', rank, dims, 'NX_COMP_LZW', cdims)
+	print, 'nxmakecompdata status:', S
+
+	S = nxopendata(fileid, "comp_data")
+        print, 'opendata status: ', S
+
+		S = nxputdata(fileid, comp_array)
+		print, 'nxputdata status:', S
+
+	S = nxclosedata(fileid)
+	print, 'nxclosedata status: ', S
+
+	S = nxflush(fileid)
+	print, 'nxflush status: ', S
+
+	S = nxmakedata(fileid, 'flush_data','NX_INT32', 1, 'NX_UNLIMITED')
+        print, 'nxmakedata status: ', S
+
+	data = [0L]
+	slab_size = [1L]
+	for i = 1L, 7L, 1L do begin
+		slab_start[0] = i
+
+		; Maybe the putslab/putdata should accept single variables also,
+		; easy to implement..
+
+		data[0] = long(i)
+		S = nxopendata(fileid, "flush_data")
+	        print, 'opendata status: ', S
+
+		S = nxputslab(fileid, data, slab_start, slab_size)
+		print, 'nxputslab ', i,' status:', S
+		S = nxflush(fileid)
+		print, 'nxflush status: ', S
+	endfor
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+
+	S = nxmakegroup(fileid, 'sample', 'NXsample')
+	print, 'nxmakegroup status: ', S
+
+        S = nxopengroup(fileid, 'sample', 'NXsample')
+	print, 'nxopengroup status: ', S
+	nxlen = [12L]
+	S = nxmakedata(fileid, 'ch_data', 'NX_CHAR', 1, nxlen)
+        print, 'nxmakedata status: ', S
+
+	S = nxopendata(fileid, "ch_data")
+	print, 'opendata status: ', S
+
+		S = nxputdata(fileid, 'NeXus sample')
+		print, 'nxputdata status:', S
+
+	S = nxclosedata(fileid)
+	print, 'nxclosedata status: ', S
+
+	S = nxgetgroupid(fileid, groupid)
+	print, 'nxgetgroupid status: ', S
+	print, 'groupid handle: ', groupid
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+
+	S = nxmakegroup(fileid, 'link', 'NXentry')
+	print, 'nxmakegroup status: ', S
+
+	S = nxopengroup(fileid, 'link', 'NXentry')
+	print, 'nxopengroup status: ', S
+
+	S = nxmakelink(fileid, groupid)
+	print, 'nxmakelink status: ', S
+
+	print, 'groupid handle', groupid
+	S = nxmakenamedlink(fileid, 'renLinkGroup', groupid)
+	print, 'nxmakenamedlink status : ', S
+
+	print, 'dataid handle', dataid
+
+	S = nxmakenamedlink(fileid, 'renLinkData', dataid)
+	print, 'nxmakenamedlink status : ', S
+
+	S = nxclosegroup(fileid)
+	print, 'nxclosegroup status: ', S
+
+	S = nxclose(fileid)
+	print, 'nxclose status: ', S
+
+
+	access_method = 'NXACC_CREATE'
+
+	print, ''
+	print, ' ####################  Test external linking  ######################'
+	print, ''
+
+
+	; Create the test file
+	S = nxopen(extfile, access_method, fileid)
+	print, 'nxopen status: ', S
+
+	S = nxmakegroup(fileid, 'entry1', 'NXentry')
+	print, 'nxmakegroup status: ', S
+
+	S = nxlinkexternal(fileid, 'entry1','NXentry',link_external_path)
+ 	print, 'nxlinkexternal: ', S
+
+	S = nxmakegroup(fileid, 'entry2', 'NXentry')
+	print, 'nxmakegroup status: ', S
+
+	S = nxlinkexternal(fileid, 'entry2','NXentry',link_external_path)
+	print, 'nxlinkexternal: ', S
+
+	S = nxclose(fileid)
+	print, 'nxclose status: ', S
+
+	; Actual link testing begins
+
+	access_method = 'NXACC_RDWR'
+	S = nxopen(extfile, access_method, fileid)
+	print, 'nxopen status: ', S
+	S = nxopenpath(fileid, '/entry1/start_time')
+	print, 'nxopenpath status', S
+	print, ''
+
+	S = nxgetdata(fileid, data)
+		print, 'nxget data status: ', S
+		print, 'First file time :'
+		print,  data
+		print, ''
+
+	S = nxinquirefile(fileid, filename, 256)
+	print, 'nxinquirefile status: ', S
+	print, 'current file: ', filename
+
+	S = nxopenpath(fileid, '/entry2/sample/sample_name')
+	print, 'nxopenpath status', S
+	S = nxgetdata(fileid, data)
+		print, 'nxget data status: ', S
+		print, 'Second file sample :'
+		print,  data
+		print, ''
+
+	S = nxinquirefile(fileid, filename, 256)
+	print, 'nxinquirefile status: ', S
+	print, 'current file: ', filename
+
+	S = nxopenpath(fileid, '/entry2/start_time')
+	print, 'nxopenpath status', S
+	S = nxgetdata(fileid, data)
+		print, 'nxget data status: ', S
+		print, 'Second file time :'
+		print,  data
+		print, ''
+
+	S = nxopenpath(fileid, '/')
+	S = nxisexternalgroup(fileid, 'entry1', 'NXentry', filename, 255)
+	print, 'nxisexternalgroup status', S
+	print, 'entry1 external URL =', filename
+
+	S = nxclose(fileid)
+	print, 'nxclose status: ', S
+end
diff --git a/bindings/java/CMakeLists.txt b/bindings/java/CMakeLists.txt
new file mode 100644
index 0000000..ef7c5cd
--- /dev/null
+++ b/bindings/java/CMakeLists.txt
@@ -0,0 +1,160 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+if(DEFINED Java_JAVAC_EXECUTABLE)
+    if(DEFINED JNI_INCLUDE_DIRS)
+
+        INCLUDE_DIRECTORIES(. ../ native ${JNI_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/bindings/java/native)
+
+        SET(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+#        MESSAGE(STATUS ${CMAKE_SOURCE_DIR}/bindings/java/)
+
+        SET(JAVA_TEST ${CMAKE_SOURCE_DIR}/bindings/java/test/TestJapi.java)
+
+        SET(JAVA_SOURCES ${CMAKE_SOURCE_DIR}/bindings/java/ncsa/hdf/hdflib/HDFException.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/ncsa/hdf/hdflib/HDFJavaException.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/ncsa/hdf/hdflib/HDFNotImplementedException.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/ncsa/hdf/hdflib/HDFConstants.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/ncsa/hdf/hdflib/HDFArray.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/ncsa/hdf/hdflib/HDFNativeData.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/org/nexusformat/NexusException.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/org/nexusformat/NXlink.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/org/nexusformat/NeXusFileInterface.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/org/nexusformat/AttributeEntry.java 
+             ${CMAKE_SOURCE_DIR}/bindings/java/org/nexusformat/NexusFile.java 
+             ${JAVA_TEST})
+
+        SET(JAVA_CLASSES ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/HDFException.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/HDFJavaException.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/HDFNotImplementedException.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/HDFConstants.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/HDFArray.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/HDFNativeData.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/org/nexusformat/NexusException.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/org/nexusformat/NXlink.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/org/nexusformat/NeXusFileInterface.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/org/nexusformat/AttributeEntry.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/org/nexusformat/NexusFile.class 
+             ${CMAKE_BINARY_DIR}/bindings/java/TestJapi.class)
+
+        SET(EXTRA_CLASSES ${CMAKE_BINARY_DIR}/bindings/java/ncsa/hdf/hdflib/ArrayDescriptor.class)
+
+        SET(JNI_HEADER native/org_nexusformat_NexusFile.h)
+
+        SET(JAR_ARCHIVE ${CMAKE_BINARY_DIR}/bindings/java/jnexus.jar)
+
+        SET(JAVA_DOCS ${CMAKE_BINARY_DIR}/bindings/java/apidoc)
+
+        STRING(REPLACE ".java" ".class" javaclass "${JAVA_SOURCES}")
+
+        ADD_CUSTOM_COMMAND( 
+            OUTPUT    ${JAVA_CLASSES}
+            COMMAND   ${Java_JAVAC_EXECUTABLE}
+            ARGS      -d . ${JAVA_SOURCES}
+            COMMENT   "Compile Java"
+        )
+
+        ADD_CUSTOM_COMMAND( 
+            OUTPUT    ${EXTRA_CLASSES}
+            COMMAND   
+            DEPENDS   ${JAVA_CLASSES}
+            COMMENT   "Include Extra Built Classes"
+        )
+
+        ADD_CUSTOM_COMMAND( 
+            OUTPUT    ${JAR_ARCHIVE}
+            COMMAND   ${Java_JAR_EXECUTABLE}
+            ARGS      cvf ${JAR_ARCHIVE} ${JAVA_CLASSES} ${EXTRA_CLASSES}
+            DEPENDS   ${EXTRA_CLASSES}
+            COMMENT   "Build JAR File"
+        )
+
+        ADD_CUSTOM_COMMAND( 
+            OUTPUT    ${JNI_HEADER}
+            COMMAND   ${Java_JAVAH_EXECUTABLE}
+            ARGS      -jni -d native -classpath . org.nexusformat.NexusFile
+            DEPENDS   ${JAR_ARCHIVE}
+            COMMENT   "Build JNI Header"
+        )
+
+        ADD_CUSTOM_COMMAND( 
+            OUTPUT    ${JAVA_DOCS}
+            COMMAND   ${Java_JAVADOC_EXECUTABLE}
+            ARGS      -d ${JAVA_DOCS} -windowtitle jnexus -doctitle jnexus -classpath . 
+                      -sourcepath ${CMAKE_SOURCE_DIR}/bindings/java org.nexusformat ncsa.hdf.hdflib
+            DEPENDS   ${JNI_HEADER}
+            COMMENT   "Build Javadocs"
+        )
+
+        ADD_CUSTOM_TARGET(NexusJavaBuild ALL echo
+           DEPENDS   ${JAR_ARCHIVE}
+        )
+        
+        ADD_CUSTOM_TARGET(NexusJavadocBuild ALL echo
+           DEPENDS   ${JAVA_DOCS}
+        )
+
+        ADD_LIBRARY(jnexus SHARED native/hdfnativeImp.c 
+                     native/hdfexceptionImp.c 
+                     native/handle.c 
+                     native/NexusFile.c 
+                     native/hdfexceptionImp.h)
+
+		if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+			set_target_properties(jnexus PROPERTIES OUTPUT_NAME libjnexus-0
+                      VERSION 1.0 SOVERSION 4 )
+		else(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+			set_target_properties(jnexus PROPERTIES OUTPUT_NAME jnexus
+                      VERSION 1.0 SOVERSION 4)
+		endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+
+        TARGET_LINK_LIBRARIES(jnexus NeXus_Shared_Library 
+                      ${READLINE_LINK} ${M_LINK} ${DF_LINK}
+                      ${DL_LINK} ${PTHREAD_LINK} ${TERMCAP_LINK} ${HDF4_LINK}
+                      ${HISTORY_LINK} ${JPEG_LIBRARIES} ${ZIP_LIB} ${SZIP_LIB}
+                      )
+
+        INSTALL(TARGETS jnexus
+            RUNTIME DESTINATION bin COMPONENT Runtime
+			LIBRARY DESTINATION lib COMPONENT Runtime 
+			ARCHIVE DESTINATION lib COMPONENT Runtime
+        )
+
+        INSTALL(FILES ${JAR_ARCHIVE} DESTINATION share/java COMPONENT Runtime)
+
+        INSTALL(DIRECTORY ${JAVA_DOCS} DESTINATION ${NXDOCDIR}/java COMPONENT Documentation)
+		
+		install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/COPYING.NCSA ${CMAKE_CURRENT_SOURCE_DIR}/README.JNEXUS DESTINATION ${NXDOCDIR}/java COMPONENT Documentation)
+
+        INSTALL(FILES ${JAVA_TEST} DESTINATION ${NXEXAMPLEDIR}/ COMPONENT Examples)
+
+     endif(DEFINED JNI_INCLUDE_DIRS)
+endif(DEFINED Java_JAVAC_EXECUTABLE)
+
+
diff --git a/bindings/java/COPYING.NCSA b/bindings/java/COPYING.NCSA
new file mode 100644
index 0000000..e418b4a
--- /dev/null
+++ b/bindings/java/COPYING.NCSA
@@ -0,0 +1,60 @@
+------------------------------------------------------------------
+
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF) 
+Software Library and Utilities
+
+Copyright 1988-2000 The Board of Trustees of the University of Illinois
+
+All rights reserved.
+
+Contributors:   National Center for Supercomputing Applications 
+(NCSA) at the University of Illinois, Fortner Software, Unidata 
+Program Center (netCDF), The Independent JPEG Group (JPEG), 
+Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment 
+Corporation (DEC). Macintosh support contributed by Gregory L. Guerin.
+
+
+The package 'glguerin':
+Copyright 1998, 1999 by Gregory L. Guerin.
+Redistribute or reuse only as described below.
+These files are from the MacBinary Toolkit for Java:
+   <http://www.amug.org/~glguerin/sw/#macbinary>
+and are redistributed by NCSA with permission of the 
+author.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted for any purpose (including commercial 
+purposes) provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright 
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright 
+notice, this list of conditions, and the following disclaimer in the 
+documentation and/or materials provided with the distribution.
+
+3. In addition, redistributions of modified forms of the source or 
+binary code must carry prominent notices stating that the original 
+code was changed and the date of the change.
+
+4. All publications or advertising materials mentioning features or use 
+of this software must acknowledge that it was developed by the National 
+Center for Supercomputing Applications at the University of Illinois, 
+and credit the Contributors.
+
+5. Neither the name of the University nor the names of the Contributors 
+may be used to endorse or promote products derived from this software 
+without specific prior written permission from the University or the 
+Contributors.
+
+DISCLAIMER
+
+THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS" 
+WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED.  In no event 
+shall the University or the Contributors be liable for any damages 
+suffered by the users arising out of the use of this software, even if 
+advised of the possibility of such damage. 
+
+
+
+
diff --git a/bindings/java/Make.alpha b/bindings/java/Make.alpha
new file mode 100755
index 0000000..6c7efdd
--- /dev/null
+++ b/bindings/java/Make.alpha
@@ -0,0 +1,144 @@
+#--------------------------------------------------------------------------
+# Makefile for the NeXus Java API. Builds both the required Java class
+# files and the shared library with the native methods.
+# 
+# Mark Koennecke, October 2000
+#--------------------------------------------------------------------------
+.SUFFIXES:
+.SUFFIXES: .java .class .c .o 
+
+###########################################################################
+#         C O N F I G U R A T I O N       S E C T I O N                   #
+###########################################################################
+
+include ../../make_general
+
+#-------Where Java lives
+JAVAROOT=/usr/opt/java131
+JAVABIN=$(JAVAROOT)/bin
+
+# The classpath for compiling java
+JCP=.:
+
+# The path to the include files for the jni-headers
+JINCLUDE= -I$(JAVAROOT)/include -I$(JAVAROOT)/include/alpha
+
+# The C-compiler to use
+CC=cc
+
+# Compiler flags to use for compiling
+CFLAGS= -g -c $(NXFLAGS) -pthread $(JINCLUDE)  -I../../include -Inative
+
+#Compiler flags used for linking
+LFLAGS= -g -shared $(NXLDFLAGS)  
+
+#Target location for the shared library
+SHLIB=bin/du40/libjnexus.so
+
+###########################################################################
+#     END OF C O N F I G U R A T I O N       S E C T I O N                #
+#                  DO NOT TOUCH ANYTHING BELOW!                           #
+###########################################################################
+
+.java.class:
+	$(JAVABIN)/javac -target 1.1 -g -classpath $(JCP) $*.java
+
+.c.o:
+	$(CC) $(CFLAGS) -o $*.o $*.c
+
+JOBJ=ncsa/hdf/hdflib/HDFException.class \
+     ncsa/hdf/hdflib/HDFJavaException.class \
+     ncsa/hdf/hdflib/HDFNotImplementedException.class \
+     ncsa/hdf/hdflib/HDFConstants.class \
+     ncsa/hdf/hdflib/HDFArray.class \
+     ncsa/hdf/hdflib/HDFNativeData.class \
+     neutron/nexus/NexusException.class \
+     neutron/nexus/NXlink.class \
+     neutron/nexus/NeXusFileInterface.class \
+     neutron/nexus/AttributeEntry.class \
+     neutron/nexus/NexusFile.class 
+     
+
+COBJ=native/hdfnativeImp.o \
+     native/hdfexceptionImp.o \
+     native/handle.o \
+     native/NexusFile.o
+
+all: jnexus.jar libjnexus.so test
+	
+
+jnexus.jar: $(JOBJ)
+	- rm jnexus.jar
+	$(JAVABIN)/jar cvf jnexus.jar $(JOBJ) \
+	  ncsa/hdf/hdflib/ArrayDescriptor.class
+
+jnexus.zip: $(JOBJ)
+	- rm jnexus.jar
+	zip jnexus.zip $(JOBJ) \
+	  ncsa/hdf/hdflib/ArrayDescriptor.class
+
+
+#-------- uncomment this vor a general Tru64Unix System
+# Please note that many Tru64Unix version come with an old incompatible
+# libjpeg.so. If you get linker errors, first consider to link
+# directly against the version coming with HDF-4
+ 
+#libjnexus.so: $(COBJ)
+#	$(CC)  -o $(SHLIB) $(COBJ) ../../src/libNeXus.a \
+#	$(LFLAGS) 
+
+#---------- special version for PSI with broken HDF4 in inconvenient place
+libjnexus.so: $(COBJ)
+	$(CC) -shared  -o $(SHLIB) $(COBJ) ../../src/libNeXus.a \
+	$(HDF4ROOT)/lib/libmfhdf.a $(HDF4ROOT)/lib/libdf.a \
+	$(HDF4ROOT)/lib/libhdf5.a $(HDF4ROOT)/lib/libjpeg.a \
+	-L/afs/psi.ch/project/sinq/tru64/lib -lmxml\
+	-lz -lm  
+
+header: neutron/nexus/NexusFile.class
+	$(JAVABIN)/javah -jni -d native neutron.nexus.NexusFile
+
+test: test/TestJapi.class
+
+clean:
+	- rm neutron/nexus/*.class
+	- rm ncsa/hdf/hdflib/*.class
+	- rm native/*.o
+
+apidoc: $(JOBJ)
+	javadoc -d apidoc neutron.nexus ncsa.hdf.hdflib
+
+# Make distributions
+ALLDIS=apidoc test jnexus.jar *.html neutron/nexus/*.java \
+	ncsa/hdf/hdflib/*.java README.* COPY*.* NeXus.gif 
+
+disdu40: $(ALLDIS)
+	- rm jnexusdu40.tar.gz
+	tar cvf jnexusdu40.tar $(ALLDIS)
+	cp bin/du40/libjnexus.so .
+	tar uvf jnexusdu40.tar libjnexus.so
+	gzip jnexusdu40.tar
+	- rm *.so
+ 
+distux: $(ALLDIS)
+	- rm jnexustux.tar.gz
+	tar cvf jnexustux.tar $(ALLDIS)
+	cp bin/rh62/libjnexus.so .
+	tar uvf jnexustux.tar libjnexus.so
+	gzip jnexustux.tar
+	- rm *.so
+
+ZIP=/data/koenneck/bin/zip
+disw32: $(ALLDIS)
+	- rm jnexusw32.zip
+	$(ZIP) -r jnexusw32.zip $(ALLDIS)
+	cp bin/win32/*.dll .
+	$(ZIP) -g jnexusw32.zip *.dll
+	- rm *.dll
+
+WWW:
+	- rm www.tar
+	cp index.html japinotes.html
+	tar cvf www.tar apidoc test/TestJapi.java \
+	japinotes.html jnexustut.html *.zip *.tar.gz COPYING.NCSA
+
diff --git a/bindings/java/Make.linux b/bindings/java/Make.linux
new file mode 100755
index 0000000..e8248c2
--- /dev/null
+++ b/bindings/java/Make.linux
@@ -0,0 +1,99 @@
+#--------------------------------------------------------------------------
+# Makefile for the NeXus Java API. Builds both the required Java class
+# files and the shared library with the native methods.
+#
+# This version for Redhat Linux 
+# 
+# Mark Koennecke, October 2003
+#--------------------------------------------------------------------------
+.SUFFIXES:
+.SUFFIXES: .java .class .c .o 
+
+###########################################################################
+#         C O N F I G U R A T I O N       S E C T I O N                   #
+###########################################################################
+
+include ../../make_general
+
+#Where to find the napi C stuff
+NAPIROOT=$(SINQDIR)/linux
+
+# Where Java lives
+JAVAROOT=/scratch/j2sdk1.4.2
+JAVABIN=$(JAVAROOT)/bin
+
+# The classpath for compiling java
+JCP=.:
+
+# The path to the include files for the jni-headers
+JINCLUDE= -I$(JAVAROOT)/include -I$(JAVAROOT)/include/linux 
+
+# The C-compiler to use
+CC=gcc
+
+# Compiler flags to use for compiling
+CFLAGS= -g -c $(JINCLUDE) $(NXFLAGS) -I../../include \
+       -Inative
+
+#Compiler flags used for linking
+LFLAGS= -g -shared -L../../src -lNeXus $(NXLDFLAGS)
+
+#Target location for the shared library
+SHLIB=bin/rh62/libjnexus.so
+
+###########################################################################
+#     END OF C O N F I G U R A T I O N       S E C T I O N                #
+#                  DO NOT TOUCH ANYTHING BELOW!                           #
+###########################################################################
+
+.java.class:
+	$(JAVABIN)/javac -g -target 1.1 -classpath $(JCP) $*.java
+
+.c.o:
+	$(CC) $(CFLAGS) -o $*.o $*.c
+
+JOBJ=ncsa/hdf/hdflib/HDFException.class \
+     ncsa/hdf/hdflib/HDFJavaException.class \
+     ncsa/hdf/hdflib/HDFNotImplementedException.class \
+     ncsa/hdf/hdflib/HDFConstants.class \
+     ncsa/hdf/hdflib/HDFArray.class \
+     ncsa/hdf/hdflib/HDFNativeData.class \
+     neutron/nexus/NexusException.class \
+     neutron/nexus/NXlink.class \
+     neutron/nexus/NeXusFileInterface.class \
+     neutron/nexus/AttributeEntry.class \
+     neutron/nexus/NexusFile.class 
+     
+
+COBJ=native/hdfnativeImp.o \
+     native/hdfexceptionImp.o \
+     native/handle.o \
+     native/NexusFile.o
+
+du40: all
+rh62: all
+
+
+all: jnexus.jar libjnexus.so test
+
+jnexus.jar: $(JOBJ)
+	- rm jnexus.jar
+	$(JAVABIN)/jar cvf jnexus.jar $(JOBJ) \
+	  ncsa/hdf/hdflib/ArrayDescriptor.class
+
+libjnexus.so: $(COBJ)
+	$(CC)  -o $(SHLIB) $(COBJ)  \
+	 $(LFLAGS) -lz -lm 
+
+
+header: neutron/nexus/NexusFile.class
+	$(JAVABIN)/javah -jni -d native neutron.nexus.NexusFile
+
+test: test/TestJapi.class
+
+clean:
+	- rm neutron/nexus/*.class
+	- rm ncsa/hdf/hdflib/*.class
+	- rm native/*.o
+
+
diff --git a/bindings/java/Make.mingw b/bindings/java/Make.mingw
new file mode 100755
index 0000000..2038e2e
--- /dev/null
+++ b/bindings/java/Make.mingw
@@ -0,0 +1,121 @@
+#--------------------------------------------------------------------------
+# Makefile for the NeXus Java API. Builds both the required Java class
+# files and the shared library with the native methods.
+#
+# This version is for Windows 32, using the mingw toolchain
+# 
+# Getting the import libraries for HDF right was a pain:
+# The HDF4 library ones were created through:
+# > reimp hdf4lib.dll
+# where hdf4lib must be replaced with the name of the HDF4 library to
+# convert.
+#
+# The HDF5 libraries seem to have been compiled with a different version of 
+# MS Visual Schrott and need another treatment:
+# > pexport  hdf5dll.dll > hdf5dll.def
+# > dlltool -d hdf5dll.def -l libhdfdll.a
+# Of course, these things may change between versions of MSVC and mingw.....
+# Windows is a pain in the ass ............................................
+# 
+# Mark Koennecke, November 2003
+#--------------------------------------------------------------------------
+.SUFFIXES:
+.SUFFIXES: .java .class .c .o 
+
+###########################################################################
+#         C O N F I G U R A T I O N       S E C T I O N                   #
+###########################################################################
+# Where to find the HDF libraries: HDF4.1r3 is REQUIRED
+HDFROOT=/g/hdf
+HDF4ROOT=$(HDFROOT)/HDF41r5
+HDF5ROOT=$(HDFROOT)/5-161-win2k/c/release
+#HDF5ROOT=/c/temp/hdf5-161mingw
+
+#Where to find the napi C stuff
+NAPIROOT=$(SINQDIR)/linux
+
+# Where the Java binaries live
+JAVAROOT=/java
+JAVABIN=$(JAVAROOT)/bin
+
+# The classpath for compiling java
+JCP=.:
+
+# The path to the include files for the jni-headers
+JINCLUDE= -I$(JAVAROOT)/include -I$(JAVAROOT)/include/win32 
+
+# The C-compiler to use
+CC=gcc
+
+# Compiler flags to use for compiling
+CFLAGS= -g -c $(JINCLUDE) -DHDF4 -DHDF5 -D_HDF5USEDLL_ -I$(HDF4ROOT)/include \
+ 	-I$(HDF5ROOT)/include -I../../include -Inative \
+        -D_JNI_IMPLEMENTATION_ -Wl,--kill-at 
+
+#Compiler flags used for linking
+LFLAGS= -g -shared  \
+        -D_JNI_IMPLEMENTATION_ -Wl,--kill-at
+
+#Target location for the shared library
+SHLIB=bin/win32/jnexus.dll
+
+###########################################################################
+#     END OF C O N F I G U R A T I O N       S E C T I O N                #
+#                  DO NOT TOUCH ANYTHING BELOW!                           #
+###########################################################################
+
+.java.class:
+	$(JAVABIN)/javac -g -target 1.1  $*.java
+
+.c.o:
+	$(CC) $(CFLAGS) -o $*.o $*.c
+
+JOBJ=ncsa/hdf/hdflib/HDFException.class \
+     ncsa/hdf/hdflib/HDFJavaException.class \
+     ncsa/hdf/hdflib/HDFNotImplementedException.class \
+     ncsa/hdf/hdflib/HDFConstants.class \
+     ncsa/hdf/hdflib/HDFArray.class \
+     ncsa/hdf/hdflib/HDFNativeData.class \
+     neutron/nexus/NexusException.class \
+     neutron/nexus/NXlink.class \
+     neutron/nexus/NeXusFileInterface.class \
+     neutron/nexus/AttributeEntry.class \
+     neutron/nexus/NexusFile.class 
+     
+
+COBJ=native/hdfnativeImp.o \
+     native/hdfexceptionImp.o \
+     native/handle.o \
+     ../../src/napi.o \
+     native/NexusFile.o 
+
+du40: all
+rh62: all
+
+../../src/napi.o:../../src/napi.c ../../src/napi4.c ../../src/napi5.c
+	$(CC) $(CFLAGS) -I../../src -o ../../src/napi.o ../../src/napi.c
+
+all: jnexus.jar libjnexus.so test
+
+jnexus.jar: $(JOBJ)
+	- rm jnexus.jar
+	$(JAVABIN)/jar cvf jnexus.jar $(JOBJ) \
+	  ncsa/hdf/hdflib/ArrayDescriptor.class
+
+libjnexus.so: $(COBJ)
+	$(CC) $(LFLAGS) -o $(SHLIB) $(COBJ)  --enable-stdcall-fixup\
+          --enable-auto-import \
+	  -L$(HDF4ROOT)/dlllib  \
+	  -L$(HDF5ROOT)/dll  -lhdf5dll -lhm415m -lhd415m
+
+
+header: neutron/nexus/NexusFile.class
+	$(JAVABIN)/javah -jni -d native neutron.nexus.NexusFile
+
+test: test/TestJapi.class
+
+clean:
+	- rm neutron/nexus/*.class
+	- rm ncsa/hdf/hdflib/*.class
+	- rm native/*.o
+	- rm ../../src/napi.o
diff --git a/bindings/java/Make.tux b/bindings/java/Make.tux
new file mode 100644
index 0000000..e88338e
--- /dev/null
+++ b/bindings/java/Make.tux
@@ -0,0 +1,99 @@
+#--------------------------------------------------------------------------
+# Makefile for the NeXus Java API. Builds both the required Java class
+# files and the shared library with the native methods.
+#
+# This version for Redhat Linux 6.2, which has an incompatible Make utility
+# 
+# Mark Koennecke, October 2000
+#--------------------------------------------------------------------------
+.SUFFIXES:
+.SUFFIXES: .java .class .c .o 
+
+###########################################################################
+#         C O N F I G U R A T I O N       S E C T I O N                   #
+###########################################################################
+# Where to find the HDF libraries: HDF4.1r3 is REQUIRED
+HDFROOT=$(SINQDIR)/linux
+
+#Where to find the napi C stuff
+NAPIROOT=$(SINQDIR)/linux
+
+# Where the Java binaries live
+JAVABIN=/usr/lib/IBMJava2-131/bin
+
+# The classpath for compiling java
+JCP=.:
+
+# The path to the include files for the jni-headers
+JINCLUDE= -I/usr/lib/IBMJava2-131/include 
+
+# The C-compiler to use
+CC=gcc
+
+# Compiler flags to use for compiling
+CFLAGS= -g -c $(JINCLUDE) -DHDF4 -DHDF5 -I$(HDFROOT)/include -I$(NAPIROOT) \
+       -Inative
+
+#Compiler flags used for linking
+LFLAGS= -g -shared -L$(HDFROOT)/lib -L$(NAPIROOT)
+
+#Target location for the shared library
+SHLIB=bin/rh62/libjnexus.so
+
+###########################################################################
+#     END OF C O N F I G U R A T I O N       S E C T I O N                #
+#                  DO NOT TOUCH ANYTHING BELOW!                           #
+###########################################################################
+
+.java.class:
+	$(JAVABIN)/javac -g -classpath $(JCP) $*.java
+
+.c.o:
+	$(CC) $(CFLAGS) -o $*.o $*.c
+
+JOBJ=ncsa/hdf/hdflib/HDFException.class \
+     ncsa/hdf/hdflib/HDFJavaException.class \
+     ncsa/hdf/hdflib/HDFNotImplementedException.class \
+     ncsa/hdf/hdflib/HDFConstants.class \
+     ncsa/hdf/hdflib/HDFArray.class \
+     ncsa/hdf/hdflib/HDFNativeData.class \
+     neutron/nexus/NexusException.class \
+     neutron/nexus/NXlink.class \
+     neutron/nexus/NeXusFileInterface.class \
+     neutron/nexus/AttributeEntry.class \
+     neutron/nexus/NexusFile.class 
+     
+
+COBJ=native/hdfnativeImp.o \
+     native/hdfexceptionImp.o \
+     native/handle.o \
+     native/NexusFile.o
+
+du40: all
+rh62: all
+
+
+all: jnexus.jar libjnexus.so test
+
+jnexus.jar: $(JOBJ)
+	- rm jnexus.jar
+	$(JAVABIN)/jar cvf jnexus.jar $(JOBJ) \
+	  ncsa/hdf/hdflib/ArrayDescriptor.class
+
+libjnexus.so: $(COBJ)
+	$(CC) $(LFLAGS) -o $(SHLIB) $(COBJ) -lnexus \
+	  -lmfhdf -ldf \
+	  $(HDFROOT)/lib/libjpeg.a $(HDFROOT)/lib/libhdf5.a -lz -lm 
+
+
+header: neutron/nexus/NexusFile.class
+	$(JAVABIN)/javah -jni -d native neutron.nexus.NexusFile
+
+test: test/TestJapi.class
+
+clean:
+	- rm neutron/nexus/*.class
+	- rm ncsa/hdf/hdflib/*.class
+	- rm native/*.o
+
+
diff --git a/bindings/java/Make.win32 b/bindings/java/Make.win32
new file mode 100644
index 0000000..a802c19
--- /dev/null
+++ b/bindings/java/Make.win32
@@ -0,0 +1,99 @@
+#--------------------------------------------------------------------------
+# Makefile for the NeXus Java API. Builds both the required Java class
+# files and the shared library with the native methods.
+#
+# This version for Windows32 using the free Borland bcc55 compiler
+# 
+# Mark Koennecke, October 2000
+#--------------------------------------------------------------------------
+.SUFFIXES:
+.SUFFIXES: .java .class .c .o 
+
+###########################################################################
+#         C O N F I G U R A T I O N       S E C T I O N                   #
+###########################################################################
+# Where to find the HDF libraries: HDF4.1r3 is REQUIRED
+HDFROOT=c:\hdf4lib\HDF41r4
+HDF5ROOT=C:\hdf5lib\5-144-winVS\c\release
+
+#Where to find the napi C stuff
+NAPIROOT=..\
+
+# Where the Java binaries live
+JAVABIN=C:\jdk1.1.8\bin
+
+# The classpath for compiling java
+JCP=C:\jdk1.1.8\lib\classes.zip;.;
+
+# The path to the include files for the jni-headers
+JINCLUDE= -I"C:\jdk1.1.8\include" \
+      -I"C:\jdk1.1.8\include\win32"
+
+# The C-compiler to use
+CC=bcc32
+
+# Compiler flags to use for compiling
+CFLAGS= -v -WD -w-8057 -w-8065 -w-8012 -w-8004 -w-8070 -w-8075 -w-8017 \
+        -w! -c $(JINCLUDE) -DHDF4 -DHDF5  -DJNEXUS -w-8066 -w-8008\
+        -I"$(HDFROOT)\include" -I"$(HDF5ROOT)\include" -I$(NAPIROOT) -Inative 
+
+#Compiler flags used for linking
+LFLAGS= /v /Tpd  /Lbin\win32
+
+#Target location for the shared library
+SHLIB=bin\win32\jnexus.dll
+
+###########################################################################
+#     END OF C O N F I G U R A T I O N       S E C T I O N                #
+#                  DO NOT TOUCH ANYTHING BELOW!                           #
+###########################################################################
+
+.java.class:
+	$(JAVABIN)\javac -g -classpath $(JCP) $*.java
+
+.c.obj:
+	$(CC) $(CFLAGS) -o$*.obj $*.c
+
+JOBJ=ncsa\hdf\hdflib\HDFException.class \
+     ncsa\hdf\hdflib\HDFJavaException.class \
+     ncsa\hdf\hdflib\HDFNotImplementedException.class \
+     ncsa\hdf\hdflib\HDFConstants.class \
+     ncsa\hdf\hdflib\HDFArray.class \
+     ncsa\hdf\hdflib\HDFNativeData.class \
+     neutron\nexus\NexusException.class \
+     neutron\nexus\NXlink.class \
+     neutron\nexus\NeXusFileInterface.class \
+     neutron\nexus\AttributeEntry.class \
+     neutron\nexus\NexusFile.class 
+     
+
+COBJ=native\hdfnativeImp.obj \
+     native\hdfexceptionImp.obj \
+     native\handle.obj \
+     native\NexusFile.obj \
+     ..\napi.obj
+
+
+
+all: jnexus.jar jnexus.dll test
+
+jnexus.jar: $(JOBJ)
+	- del jnexus.jar
+	$(JAVABIN)\jar cvf jnexus.jar $(JOBJ) \
+	  ncsa/hdf/hdflib/ArrayDescriptor.class
+
+jnexus.dll: $(COBJ)
+	 ilink32 $(LFLAGS) c0d32.obj $(COBJ),bin\win32\jnexus.dll,,\
+	 hm414m.lib hd414m.lib  hdf5.lib cw32.lib import32.lib
+
+
+header: neutron/nexus/NexusFile.class
+	$(JAVABIN)/javah -jni -d native neutron.nexus.NexusFile
+
+test: test/TestJapi.class
+
+clean:
+	- rm neutron/nexus/*.class
+	- rm ncsa/hdf/hdflib/*.class
+	- rm native/*.o
+
diff --git a/bindings/java/Makefile.am b/bindings/java/Makefile.am
new file mode 100644
index 0000000..881b434
--- /dev/null
+++ b/bindings/java/Makefile.am
@@ -0,0 +1,155 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for NeXus Java bindings
+#
+#  Copyright (C) 2004 Peter Peterson
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+# Modified after change to org.nexusformat package name change: 
+# Mark Koennecke, December 2006
+#
+#====================================================================
+
+AM_JAVACFLAGS	= -classpath .
+
+JAVAROOT	= .
+
+nxexampledir=$(NXEXAMPLEDIR)
+nxjavadocdir=$(NXDOCDIR)/java
+# jar file definitions
+javadir		= $(datadir)/java
+java_DATA = jnexus.jar 
+nxexample_DATA = test/TestJapi.java 
+nxjavadoc_DATA = README.JNEXUS COPYING.NCSA
+jnexus_jar_ARCHIVE = jnexus.jar
+
+jnexus_jar_CLASS = ncsa/hdf/hdflib/HDFException.class \
+               ncsa/hdf/hdflib/HDFJavaException.class \
+               ncsa/hdf/hdflib/HDFConstants.class \
+               ncsa/hdf/hdflib/HDFNativeData.class \
+               ncsa/hdf/hdflib/HDFArray.class \
+               ncsa/hdf/hdflib/HDFNotImplementedException.class \
+               org/nexusformat/AttributeEntry.class \
+               org/nexusformat/NexusException.class \
+               org/nexusformat/NXlink.class \
+               org/nexusformat/NeXusFileInterface.class \
+               org/nexusformat/NexusFile.class
+
+# jni definitions
+lib_LTLIBRARIES		= libjnexus.la
+libjnexus_la_SOURCES 	= native/hdfnativeImp.c \
+                       native/hdfexceptionImp.c \
+                       native/handle.c \
+                       native/NexusFile.c \
+		       native/hdfexceptionImp.h
+libjnexus_la_LIBADD 	= $(top_builddir)/src/libNeXus.la
+libjnexus_la_LDFLAGS 	= @SHARED_LDFLAGS@ -version-info $(NXLTVERSINFO) $(JNEXUS_LDFLAGS) -L$(top_builddir)/src/.libs
+libjnexus_la_CFLAGS 	= -I$(top_srcdir)/include -Inative @JAVAINCLUDE@ \
+     			@HDF4_CPPFLAGS@ @HDF5_CPPFLAGS@ $(JNEXUS_CFLAGS)
+
+BUILT_SOURCES		= native/org_nexusformat_NexusFile.h
+nodist_noinst_HEADERS 	= native/org_nexusformat_NexusFile.h 
+noinst_HEADERS		= native/handle.h
+
+CLEANFILES	= $(jnexus_jar_CLASS) $(jnexus_jar_ARCHIVE) $(BUILT_SOURCES) \
+	libjnexus.def libjnexus.dll.lib libjnexus.dll.exp jnexus.dll \
+               ncsa/hdf/hdflib/ArrayDescriptor.class
+
+
+noinst_JAVA	= ncsa/hdf/hdflib/HDFArray.java \
+		ncsa/hdf/hdflib/HDFConstants.java \
+		ncsa/hdf/hdflib/HDFException.java \
+		ncsa/hdf/hdflib/HDFJavaException.java \
+		ncsa/hdf/hdflib/HDFNativeData.java \
+		ncsa/hdf/hdflib/HDFNotImplementedException.java \
+		org/nexusformat/AttributeEntry.java \
+		org/nexusformat/NXlink.java \
+		org/nexusformat/NeXusFileInterface.java \
+		org/nexusformat/NexusException.java \
+		org/nexusformat/NexusFile.java \
+		test/TestJapi.java
+
+EXTRA_DIST	= $(noinst_JAVA) README.JNEXUS COPYING.NCSA
+
+# specific targets
+# org/nexusformat/NexusFile.class:	org/nexusformat/NexusFile.java
+
+native/org_nexusformat_NexusFile.h: jnexus.jar # org/nexusformat/NexusFile.class
+	test -d native || mkdir native
+	$(JAVAH) -jni -d native -classpath . org.nexusformat.NexusFile
+
+jnexus.jar: $(jnexus_jar_CLASS) apidoc
+	$(JAR) cvf jnexus.jar $(jnexus_jar_CLASS) \
+               ncsa/hdf/hdflib/ArrayDescriptor.class
+
+
+SUFFIXES = .java .class
+
+.java.class:
+	$(JAVAC) -d $(JAVAROOT) $(AM_JAVACFLAGS) $(JAVACFLAGS) $<
+
+apidoc : $(noinst_JAVA)
+	test -d apidoc || mkdir apidoc
+	$(JAVADOC) -d apidoc -windowtitle jnexus -doctitle jnexus -classpath . \
+                      -sourcepath $(srcdir) org.nexusformat ncsa.hdf.hdflib
+
+dist-hook :
+	if test -d $(srcdir)/apidoc; then \
+	    cp -r $(srcdir)/apidoc $(distdir); \
+	fi
+
+install-data-local :
+	$(mkinstalldirs) $(DESTDIR)$(nxjavadocdir)
+	if test -d $(srcdir)/apidoc; then \
+	  cp -r $(srcdir)/apidoc $(DESTDIR)$(nxjavadocdir); \
+	  find $(DESTDIR)$(nxjavadocdir)/apidoc -type f -exec chmod 0644 {} \; ;\
+	  find $(DESTDIR)$(nxjavadocdir)/apidoc -type d -exec chmod 0755 {} \; ;\
+	fi
+
+clean-local :
+	rm -rf apidoc
+
+uninstall-local :
+	rm -fr $(DESTDIR)$(nxjavadocdir)/apidoc
+
+#
+# Windows import library for DLL
+
+if MINGW_MSYS
+JNEXUS_CFLAGS=-D_JNI_IMPLEMENTATION_
+JNEXUS_LDFLAGS=-Wl,--kill-at
+msimplibdir = ${libdir}
+msimplib_DATA = libjnexus.dll.lib libjnexus.dll.exp libjnexus.def
+libjnexus.def: libjnexus.la
+	pexports .libs/libjnexus-0.dll > libjnexus.def
+libjnexus.dll.exp: libjnexus.dll.lib
+libjnexus.dll.lib: libjnexus.def
+	LIB /MACHINE:I386 /DEF:libjnexus.def /OUT:libjnexus.dll.lib
+jnexusbindir = ${bindir}
+jnexusbin_DATA = jnexus.dll
+jnexus.dll : libjnexus.la
+	ln -sf .libs/libjnexus-0.dll jnexus.dll
+endif
+
+
+## include $(top_srcdir)/build_rules.am
diff --git a/bindings/java/NeXus.gif b/bindings/java/NeXus.gif
new file mode 100644
index 0000000..d204291
Binary files /dev/null and b/bindings/java/NeXus.gif differ
diff --git a/bindings/java/README.JNEXUS b/bindings/java/README.JNEXUS
new file mode 100644
index 0000000..52a668d
--- /dev/null
+++ b/bindings/java/README.JNEXUS
@@ -0,0 +1,79 @@
+
+	JNEXUS
+
+	This is the README file for the NeXus API for Java, Version 2.0.
+        This version supports both HDF-4 and HDF-5.
+
+        The NeXus API for Java (JAPI) is implemented by a class NexusFile
+        which calls the C-language NeXus-API through the Java Native
+   	Methods Interface (JNI). For more documentation see the API
+        documentation in the directory apidoc and the class TestJapi.java
+        in directory test which not only serves as a test driver for
+     	the JAPI but also as a code example for the usage of the NexusFile
+        methods. 
+
+
+
+        ACKNOWLEGDEMENT
+
+	This library uses a lot of code taken from the Java HDF Interface
+        libraries provided by the NCSA-HDF team. Essentially all the number
+	conversion code is taken from there. Also, the JHI served as a
+        valuable source for inspiration during the devlopment of this 
+	library. Please see the file COPYING.NCSA for more details. See
+	JHI version from which the code was extracted was JHI-2.5 as 
+	downloaded in October 2000. 
+
+	USAGE
+	
+	I hope you downloaded a binary distribution of the JAPI. Due to the
+        complexity of this code we strive to provide binary distributions
+        for most platforms. If yours is not supported (we cannot have 
+        samples of any computer system in the world) compilation instructions 
+        can be found below.
+ 
+	As the JAPI uses native methods your Java runtime needs to locate the
+   	shared library implementing the NAPI. Otherwise you will get an
+        Unsatisfied Link Error. There are three possibilities how the Java 
+        runtime can locate the shared library:
+	- You or your system administrator puts the shared library into the
+          systems default location for shared libraries. On Windows
+          platforms this is any directory on the PATH, on a Unix system it
+          is usually something like /usr/shlib. 
+	- You put it wherever you want on your unix system and set the 
+          environment variable LD_LIBRARY_PATH to point to that directory.
+	  More info on this in the manpages of your systems loader.
+	- You explicitly tell the Java Runtime where the shared library is
+	  through the -Dorg.nexusformat.JNEXUSLIB=full-path-to-library
+	  option.  
+
+        Furthermore you need to include the jnexus.jar file in your Java
+        classpath both for compiling and running Java programs using the 
+        JAPI.
+ 
+        As an example, see the runtestxx scripts supplied in the test
+        directory for running the test driver.
+
+
+
+	COMPILING
+
+	Is fairly easy on a Unix system. Use one of the supplied Makefiles
+	(Makefile dor DigitalUnix4.0D or, Make.tux  for Redhat Linux 6.2)
+	and adapt the settings of the variables in the configuration 
+	section to the state of your system. You need to know:
+	- Where you Java binaries, include files, libraries reside.
+	- Where the HDF4.1r3 libraries are installed. 
+	- Furthermore adapt some compiler options in order to reflect the
+	  way how your compiler builds shared libraries. 
+
+
+	AUTHOR and Target for Comments:
+
+	Mark Koennecke
+	Laboratory for Neutron Scattering
+	Paul Scherrer Institut
+	CH-5232 Villigen-PSI
+	Switzerland
+	Mark.Koennecke at psi.ch
+ 
\ No newline at end of file
diff --git a/bindings/java/bin/README b/bindings/java/bin/README
new file mode 100644
index 0000000..8e77dbb
--- /dev/null
+++ b/bindings/java/bin/README
@@ -0,0 +1,5 @@
+	
+	Binary Distributions
+
+	- du40 shared jnexus library for DigitalUnix4.0D
+	- rh62 shared jnexus library for Redhat 6.2 on Intel
diff --git a/bindings/java/bin/win32/hd413m.def b/bindings/java/bin/win32/hd413m.def
new file mode 100644
index 0000000..96aa9f7
--- /dev/null
+++ b/bindings/java/bin/win32/hd413m.def
@@ -0,0 +1,870 @@
+LIBRARY     HD413M.DLL
+
+EXPORTS
+    _AFANNLEN                     = AFANNLEN                            ; AFANNLEN
+    _AFANNLIST                    = AFANNLIST                           ; AFANNLIST
+    _AFATYPETAG                   = AFATYPETAG                          ; AFATYPETAG
+    _AFCREATE                     = AFCREATE                            ; AFCREATE
+    _AFEND                        = AFEND                               ; AFEND
+    _AFENDACCESS                  = AFENDACCESS                         ; AFENDACCESS
+    _AFFCREATE                    = AFFCREATE                           ; AFFCREATE
+    _AFFILEINFO                   = AFFILEINFO                          ; AFFILEINFO
+    _AFGETTAGREF                  = AFGETTAGREF                         ; AFGETTAGREF
+    _AFIDTAGREF                   = AFIDTAGREF                          ; AFIDTAGREF
+    _AFNUMANN                     = AFNUMANN                            ; AFNUMANN
+    _AFREADANN                    = AFREADANN                           ; AFREADANN
+    _AFSELECT                     = AFSELECT                            ; AFSELECT
+    _AFSTART                      = AFSTART                             ; AFSTART
+    _AFTAGATYPE                   = AFTAGATYPE                          ; AFTAGATYPE
+    _AFTAGREFID                   = AFTAGREFID                          ; AFTAGREFID
+    _AFWRITEANN                   = AFWRITEANN                          ; AFWRITEANN
+    _ANannlen                     = ANannlen                            ; ANannlen
+    _ANannlist                    = ANannlist                           ; ANannlist
+    _ANatype2tag                  = ANatype2tag                         ; ANatype2tag
+    _ANcreate                     = ANcreate                            ; ANcreate
+    _ANcreatef                    = ANcreatef                           ; ANcreatef
+    _ANdestroy                    = ANdestroy                           ; ANdestroy
+    _ANend                        = ANend                               ; ANend
+    _ANendaccess                  = ANendaccess                         ; ANendaccess
+    _ANfileinfo                   = ANfileinfo                          ; ANfileinfo
+    _ANget_tagref                 = ANget_tagref                        ; ANget_tagref
+    _ANid2tagref                  = ANid2tagref                         ; ANid2tagref
+    _ANnumann                     = ANnumann                            ; ANnumann
+    _ANreadann                    = ANreadann                           ; ANreadann
+    _ANselect                     = ANselect                            ; ANselect
+    _ANstart                      = ANstart                             ; ANstart
+    _ANtag2atype                  = ANtag2atype                         ; ANtag2atype
+    _ANtagref2id                  = ANtagref2id                         ; ANtagref2id
+    _ANwriteann                   = ANwriteann                          ; ANwriteann
+    _DF24addimage                 = DF24addimage                        ; DF24addimage
+    _DF24getdims                  = DF24getdims                         ; DF24getdims
+    _DF24getimage                 = DF24getimage                        ; DF24getimage
+    _DF24lastref                  = DF24lastref                         ; DF24lastref
+    _DF24nimages                  = DF24nimages                         ; DF24nimages
+    _DF24putimage                 = DF24putimage                        ; DF24putimage
+    _DF24readref                  = DF24readref                         ; DF24readref
+    _DF24reqil                    = DF24reqil                           ; DF24reqil
+    _DF24restart                  = DF24restart                         ; DF24restart
+    _DF24setcompress              = DF24setcompress                     ; DF24setcompress
+    _DF24setdims                  = DF24setdims                         ; DF24setdims
+    _DF24setil                    = DF24setil                           ; DF24setil
+    _DFANIaddentry                = DFANIaddentry                       ; DFANIaddentry
+    _DFANIaddfann                 = DFANIaddfann                        ; DFANIaddfann
+    _DFANIclear                   = DFANIclear                          ; DFANIclear
+    _DFANIgetann                  = DFANIgetann                         ; DFANIgetann
+    _DFANIgetannlen               = DFANIgetannlen                      ; DFANIgetannlen
+    _DFANIgetfann                 = DFANIgetfann                        ; DFANIgetfann
+    _DFANIgetfannlen              = DFANIgetfannlen                     ; DFANIgetfannlen
+    _DFANIlablist                 = DFANIlablist                        ; DFANIlablist
+    _DFANIlocate                  = DFANIlocate                         ; DFANIlocate
+    _DFANIputann                  = DFANIputann                         ; DFANIputann
+    _DFANPshutdown                = DFANPshutdown                       ; DFANPshutdown
+    _DFANaddfds                   = DFANaddfds                          ; DFANaddfds
+    _DFANaddfid                   = DFANaddfid                          ; DFANaddfid
+    _DFANclear                    = DFANclear                           ; DFANclear
+    _DFANgetdesc                  = DFANgetdesc                         ; DFANgetdesc
+    _DFANgetdesclen               = DFANgetdesclen                      ; DFANgetdesclen
+    _DFANgetfds                   = DFANgetfds                          ; DFANgetfds
+    _DFANgetfdslen                = DFANgetfdslen                       ; DFANgetfdslen
+    _DFANgetfid                   = DFANgetfid                          ; DFANgetfid
+    _DFANgetfidlen                = DFANgetfidlen                       ; DFANgetfidlen
+    _DFANgetlabel                 = DFANgetlabel                        ; DFANgetlabel
+    _DFANgetlablen                = DFANgetlablen                       ; DFANgetlablen
+    _DFANlablist                  = DFANlablist                         ; DFANlablist
+    _DFANlastref                  = DFANlastref                         ; DFANlastref
+    _DFANputdesc                  = DFANputdesc                         ; DFANputdesc
+    _DFANputlabel                 = DFANputlabel                        ; DFANputlabel
+    _DFCIimcomp                   = DFCIimcomp                          ; DFCIimcomp
+    _DFCIjpeg                     = DFCIjpeg                            ; DFCIjpeg
+    _DFCIrle                      = DFCIrle                             ; DFCIrle
+    _DFCIunimcomp                 = DFCIunimcomp                        ; DFCIunimcomp
+    _DFCIunjpeg                   = DFCIunjpeg                          ; DFCIunjpeg
+    _DFCIunrle                    = DFCIunrle                           ; DFCIunrle
+    _DFGRIaddimlut                = DFGRIaddimlut                       ; DFGRIaddimlut
+    _DFGRIgetdims                 = DFGRIgetdims                        ; DFGRIgetdims
+    _DFGRIgetimlut                = DFGRIgetimlut                       ; DFGRIgetimlut
+    _DFGRIlastref                 = DFGRIlastref                        ; DFGRIlastref
+    _DFGRIreqil                   = DFGRIreqil                          ; DFGRIreqil
+    _DFGRIrestart                 = DFGRIrestart                        ; DFGRIrestart
+    _DFGRIsetdims                 = DFGRIsetdims                        ; DFGRIsetdims
+    _DFGRIsetil                   = DFGRIsetil                          ; DFGRIsetil
+    _DFGRPshutdown                = DFGRPshutdown                       ; DFGRPshutdown
+    _DFGRaddimage                 = DFGRaddimage                        ; DFGRaddimage
+    _DFGRaddlut                   = DFGRaddlut                          ; DFGRaddlut
+    _DFGRgetimage                 = DFGRgetimage                        ; DFGRgetimage
+    _DFGRgetimdims                = DFGRgetimdims                       ; DFGRgetimdims
+    _DFGRgetlut                   = DFGRgetlut                          ; DFGRgetlut
+    _DFGRgetlutdims               = DFGRgetlutdims                      ; DFGRgetlutdims
+    _DFGRputimage                 = DFGRputimage                        ; DFGRputimage
+    _DFGRreadref                  = DFGRreadref                         ; DFGRreadref
+    _DFGRreqimil                  = DFGRreqimil                         ; DFGRreqimil
+    _DFGRreqlutil                 = DFGRreqlutil                        ; DFGRreqlutil
+    _DFGRsetcompress              = DFGRsetcompress                     ; DFGRsetcompress
+    _DFGRsetimdims                = DFGRsetimdims                       ; DFGRsetimdims
+    _DFGRsetlut                   = DFGRsetlut                          ; DFGRsetlut
+    _DFGRsetlutdims               = DFGRsetlutdims                      ; DFGRsetlutdims
+    _DFIVOPN                      = DFIVOPN                             ; DFIVOPN
+    _DFKNTsize                    = DFKNTsize                           ; DFKNTsize
+    _DFKconvert                   = DFKconvert                          ; DFKconvert
+    _DFKgetPNSC                   = DFKgetPNSC                          ; DFKgetPNSC
+    _DFKislitendNT                = DFKislitendNT                       ; DFKislitendNT
+    _DFKisnativeNT                = DFKisnativeNT                       ; DFKisnativeNT
+    _DFKnb1b                      = DFKnb1b                             ; DFKnb1b
+    _DFKnb2b                      = DFKnb2b                             ; DFKnb2b
+    _DFKnb4b                      = DFKnb4b                             ; DFKnb4b
+    _DFKnb8b                      = DFKnb8b                             ; DFKnb8b
+    _DFKsb2b                      = DFKsb2b                             ; DFKsb2b
+    _DFKsb4b                      = DFKsb4b                             ; DFKsb4b
+    _DFKsb8b                      = DFKsb8b                             ; DFKsb8b
+    _DFKsetNT                     = DFKsetNT                            ; DFKsetNT
+    _DFPaddpal                    = DFPaddpal                           ; DFPaddpal
+    _DFPgetpal                    = DFPgetpal                           ; DFPgetpal
+    _DFPlastref                   = DFPlastref                          ; DFPlastref
+    _DFPnpals                     = DFPnpals                            ; DFPnpals
+    _DFPputpal                    = DFPputpal                           ; DFPputpal
+    _DFPreadref                   = DFPreadref                          ; DFPreadref
+    _DFPrestart                   = DFPrestart                          ; DFPrestart
+    _DFPwriteref                  = DFPwriteref                         ; DFPwriteref
+    _DFR8Pshutdown                = DFR8Pshutdown                       ; DFR8Pshutdown
+    _DFR8addimage                 = DFR8addimage                        ; DFR8addimage
+    _DFR8getdims                  = DFR8getdims                         ; DFR8getdims
+    _DFR8getimage                 = DFR8getimage                        ; DFR8getimage
+    _DFR8getpalref                = DFR8getpalref                       ; DFR8getpalref
+    _DFR8lastref                  = DFR8lastref                         ; DFR8lastref
+    _DFR8nimages                  = DFR8nimages                         ; DFR8nimages
+    _DFR8putimage                 = DFR8putimage                        ; DFR8putimage
+    _DFR8readref                  = DFR8readref                         ; DFR8readref
+    _DFR8restart                  = DFR8restart                         ; DFR8restart
+    _DFR8setcompress              = DFR8setcompress                     ; DFR8setcompress
+    _DFR8setpalette               = DFR8setpalette                      ; DFR8setpalette
+    _DFR8writeref                 = DFR8writeref                        ; DFR8writeref
+    _DFSDPshutdown                = DFSDPshutdown                       ; DFSDPshutdown
+    _DFSDadddata                  = DFSDadddata                         ; DFSDadddata
+    _DFSDclear                    = DFSDclear                           ; DFSDclear
+    _DFSDendslab                  = DFSDendslab                         ; DFSDendslab
+    _DFSDendslice                 = DFSDendslice                        ; DFSDendslice
+    _DFSDgetNT                    = DFSDgetNT                           ; DFSDgetNT
+    _DFSDgetcal                   = DFSDgetcal                          ; DFSDgetcal
+    _DFSDgetdata                  = DFSDgetdata                         ; DFSDgetdata
+    _DFSDgetdatalen               = DFSDgetdatalen                      ; DFSDgetdatalen
+    _DFSDgetdatastrs              = DFSDgetdatastrs                     ; DFSDgetdatastrs
+    _DFSDgetdimlen                = DFSDgetdimlen                       ; DFSDgetdimlen
+    _DFSDgetdims                  = DFSDgetdims                         ; DFSDgetdims
+    _DFSDgetdimscale              = DFSDgetdimscale                     ; DFSDgetdimscale
+    _DFSDgetdimstrs               = DFSDgetdimstrs                      ; DFSDgetdimstrs
+    _DFSDgetfillvalue             = DFSDgetfillvalue                    ; DFSDgetfillvalue
+    _DFSDgetrange                 = DFSDgetrange                        ; DFSDgetrange
+    _DFSDgetslice                 = DFSDgetslice                        ; DFSDgetslice
+    _DFSDlastref                  = DFSDlastref                         ; DFSDlastref
+    _DFSDndatasets                = DFSDndatasets                       ; DFSDndatasets
+    _DFSDpre32sdg                 = DFSDpre32sdg                        ; DFSDpre32sdg
+    _DFSDputdata                  = DFSDputdata                         ; DFSDputdata
+    _DFSDputslice                 = DFSDputslice                        ; DFSDputslice
+    _DFSDreadref                  = DFSDreadref                         ; DFSDreadref
+    _DFSDreadslab                 = DFSDreadslab                        ; DFSDreadslab
+    _DFSDrestart                  = DFSDrestart                         ; DFSDrestart
+    _DFSDsetNT                    = DFSDsetNT                           ; DFSDsetNT
+    _DFSDsetcal                   = DFSDsetcal                          ; DFSDsetcal
+    _DFSDsetdatastrs              = DFSDsetdatastrs                     ; DFSDsetdatastrs
+    _DFSDsetdims                  = DFSDsetdims                         ; DFSDsetdims
+    _DFSDsetdimscale              = DFSDsetdimscale                     ; DFSDsetdimscale
+    _DFSDsetdimstrs               = DFSDsetdimstrs                      ; DFSDsetdimstrs
+    _DFSDsetfillvalue             = DFSDsetfillvalue                    ; DFSDsetfillvalue
+    _DFSDsetlengths               = DFSDsetlengths                      ; DFSDsetlengths
+    _DFSDsetrange                 = DFSDsetrange                        ; DFSDsetrange
+    _DFSDstartslab                = DFSDstartslab                       ; DFSDstartslab
+    _DFSDstartslice               = DFSDstartslice                      ; DFSDstartslice
+    _DFSDwriteref                 = DFSDwriteref                        ; DFSDwriteref
+    _DFSDwriteslab                = DFSDwriteslab                       ; DFSDwriteslab
+    _DFVCLOS                      = DFVCLOS                             ; DFVCLOS
+    _DFdifree                     = DFdifree                            ; DFdifree
+    _DFdiget                      = DFdiget                             ; DFdiget
+    _DFdinobj                     = DFdinobj                            ; DFdinobj
+    _DFdiput                      = DFdiput                             ; DFdiput
+    _DFdiread                     = DFdiread                            ; DFdiread
+    _DFdisetup                    = DFdisetup                           ; DFdisetup
+    _DFdiwrite                    = DFdiwrite                           ; DFdiwrite
+    _DFfindnextref                = DFfindnextref                       ; DFfindnextref
+    _DFgetcomp                    = DFgetcomp                           ; DFgetcomp
+    _DFputcomp                    = DFputcomp                           ; DFputcomp
+    _GRIil_convert                = GRIil_convert                       ; GRIil_convert
+    _GRPshutdown                  = GRPshutdown                         ; GRPshutdown
+    _GRattrinfo                   = GRattrinfo                          ; GRattrinfo
+    _GRcreate                     = GRcreate                            ; GRcreate
+    _GRend                        = GRend                               ; GRend
+    _GRendaccess                  = GRendaccess                         ; GRendaccess
+    _GRfileinfo                   = GRfileinfo                          ; GRfileinfo
+    _GRfindattr                   = GRfindattr                          ; GRfindattr
+    _GRgetattr                    = GRgetattr                           ; GRgetattr
+    _GRgetchunkinfo               = GRgetchunkinfo                      ; GRgetchunkinfo
+    _GRgetiminfo                  = GRgetiminfo                         ; GRgetiminfo
+    _GRgetlutid                   = GRgetlutid                          ; GRgetlutid
+    _GRgetlutinfo                 = GRgetlutinfo                        ; GRgetlutinfo
+    _GRidtoref                    = GRidtoref                           ; GRidtoref
+    _GRluttoref                   = GRluttoref                          ; GRluttoref
+    _GRnametoindex                = GRnametoindex                       ; GRnametoindex
+    _GRreadchunk                  = GRreadchunk                         ; GRreadchunk
+    _GRreadimage                  = GRreadimage                         ; GRreadimage
+    _GRreadlut                    = GRreadlut                           ; GRreadlut
+    _GRreftoindex                 = GRreftoindex                        ; GRreftoindex
+    _GRreqimageil                 = GRreqimageil                        ; GRreqimageil
+    _GRreqlutil                   = GRreqlutil                          ; GRreqlutil
+    _GRselect                     = GRselect                            ; GRselect
+    _GRsetaccesstype              = GRsetaccesstype                     ; GRsetaccesstype
+    _GRsetattr                    = GRsetattr                           ; GRsetattr
+    _GRsetchunk                   = GRsetchunk                          ; GRsetchunk
+    _GRsetchunkcache              = GRsetchunkcache                     ; GRsetchunkcache
+    _GRsetcompress                = GRsetcompress                       ; GRsetcompress
+    _GRsetexternalfile            = GRsetexternalfile                   ; GRsetexternalfile
+    _GRstart                      = GRstart                             ; GRstart
+    _GRwritechunk                 = GRwritechunk                        ; GRwritechunk
+    _GRwriteimage                 = GRwriteimage                        ; GRwriteimage
+    _GRwritelut                   = GRwritelut                          ; GRwritelut
+    _HBPcloseAID                  = HBPcloseAID                         ; HBPcloseAID
+    _HBPendaccess                 = HBPendaccess                        ; HBPendaccess
+    _HBPinfo                      = HBPinfo                             ; HBPinfo
+    _HBPinquire                   = HBPinquire                          ; HBPinquire
+    _HBPread                      = HBPread                             ; HBPread
+    _HBPseek                      = HBPseek                             ; HBPseek
+    _HBPstread                    = HBPstread                           ; HBPstread
+    _HBPstwrite                   = HBPstwrite                          ; HBPstwrite
+    _HBPwrite                     = HBPwrite                            ; HBPwrite
+    _HBconvert                    = HBconvert                           ; HBconvert
+    _HCPcloseAID                  = HCPcloseAID                         ; HCPcloseAID
+    _HCPdecode_header             = HCPdecode_header                    ; HCPdecode_header
+    _HCPencode_header             = HCPencode_header                    ; HCPencode_header
+    _HCPendaccess                 = HCPendaccess                        ; HCPendaccess
+    _HCPinfo                      = HCPinfo                             ; HCPinfo
+    _HCPinquire                   = HCPinquire                          ; HCPinquire
+    _HCPquery_encode_header       = HCPquery_encode_header              ; HCPquery_encode_header
+    _HCPread                      = HCPread                             ; HCPread
+    _HCPseek                      = HCPseek                             ; HCPseek
+    _HCPstread                    = HCPstread                           ; HCPstread
+    _HCPstwrite                   = HCPstwrite                          ; HCPstwrite
+    _HCPwrite                     = HCPwrite                            ; HCPwrite
+    _HCcreate                     = HCcreate                            ; HCcreate
+    _HDDONTATEXIT                 = HDDONTATEXIT                        ; HDDONTATEXIT
+    _HDc2fstr                     = HDc2fstr                            ; HDc2fstr
+    _HDcalloc                     = HDcalloc                            ; HDcalloc
+    _HDcheck_tagref               = HDcheck_tagref                      ; HDcheck_tagref
+    _HDdont_atexit                = HDdont_atexit                       ; HDdont_atexit
+    _HDerr                        = HDerr                               ; HDerr
+    _HDf2cstring                  = HDf2cstring                         ; HDf2cstring
+    _HDfidtoname                  = HDfidtoname                         ; HDfidtoname
+    _HDflush                      = HDflush                             ; HDflush
+    _HDfree                       = HDfree                              ; HDfree
+    _HDgetNTdesc                  = HDgetNTdesc                         ; HDgetNTdesc
+    _HDget_special_info           = HDget_special_info                  ; HDget_special_info
+    _HDgetc                       = HDgetc                              ; HDgetc
+    _HDgettagdesc                 = HDgettagdesc                        ; HDgettagdesc
+    _HDgettagnum                  = HDgettagnum                         ; HDgettagnum
+    _HDgettagsname                = HDgettagsname                       ; HDgettagsname
+    _HDinqblockinfo               = HDinqblockinfo                      ; HDinqblockinfo
+    _HDmalloc                     = HDmalloc                            ; HDmalloc
+    _HDmemfill                    = HDmemfill                           ; HDmemfill
+    _HDpackFstring                = HDpackFstring                       ; HDpackFstring
+    _HDputc                       = HDputc                              ; HDputc
+    _HDrealloc                    = HDrealloc                           ; HDrealloc
+    _HDreuse_tagref               = HDreuse_tagref                      ; HDreuse_tagref
+    _HDset_special_info           = HDset_special_info                  ; HDset_special_info
+    _HDstrdup                     = HDstrdup                            ; HDstrdup
+    _HDvalidfid                   = HDvalidfid                          ; HDvalidfid
+    _HEPRNT                       = HEPRNT                              ; HEPRNT
+    _HEPclear                     = HEPclear                            ; HEPclear
+    _HESTRING                     = HESTRING                            ; HESTRING
+    _HESTRINGC                    = HESTRINGC                           ; HESTRINGC
+    _HEprint                      = HEprint                             ; HEprint
+    _HEpush                       = HEpush                              ; HEpush
+    _HEreport                     = HEreport                            ; HEreport
+    _HEshutdown                   = HEshutdown                          ; HEshutdown
+    _HEstring                     = HEstring                            ; HEstring
+    _HEvalue                      = HEvalue                             ; HEvalue
+    _HGFILVER                     = HGFILVER                            ; HGFILVER
+    _HGFILVERC                    = HGFILVERC                           ; HGFILVERC
+    _HGLIBVER                     = HGLIBVER                            ; HGLIBVER
+    _HGLIBVERC                    = HGLIBVERC                           ; HGLIBVERC
+    _HIISHDF                      = HIISHDF                             ; HIISHDF
+    _HIOPEN                       = HIOPEN                              ; HIOPEN
+    _HISHDF                       = HISHDF                              ; HISHDF
+    _HIget_access_rec             = HIget_access_rec                    ; HIget_access_rec
+    _HIgetspinfo                  = HIgetspinfo                         ; HIgetspinfo
+    _HIrelease_accrec_node        = HIrelease_accrec_node               ; HIrelease_accrec_node
+    _HIstrncpy                    = HIstrncpy                           ; HIstrncpy
+    _HLPcloseAID                  = HLPcloseAID                         ; HLPcloseAID
+    _HLPendaccess                 = HLPendaccess                        ; HLPendaccess
+    _HLPinfo                      = HLPinfo                             ; HLPinfo
+    _HLPinquire                   = HLPinquire                          ; HLPinquire
+    _HLPread                      = HLPread                             ; HLPread
+    _HLPseek                      = HLPseek                             ; HLPseek
+    _HLPstread                    = HLPstread                           ; HLPstread
+    _HLPstwrite                   = HLPstwrite                          ; HLPstwrite
+    _HLPwrite                     = HLPwrite                            ; HLPwrite
+    _HLconvert                    = HLconvert                           ; HLconvert
+    _HLcreate                     = HLcreate                            ; HLcreate
+    _HMCPcloseAID                 = HMCPcloseAID                        ; HMCPcloseAID
+    _HMCcreate                    = HMCcreate                           ; HMCcreate
+    _HMCreadChunk                 = HMCreadChunk                        ; HMCreadChunk
+    _HMCsetMaxcache               = HMCsetMaxcache                      ; HMCsetMaxcache
+    _HMCwriteChunk                = HMCwriteChunk                       ; HMCwriteChunk
+    _HNUMBER                      = HNUMBER                             ; HNUMBER
+    _HP_read                      = HP_read                             ; HP_read
+    _HP_write                     = HP_write                            ; HP_write
+    _HPbitshutdown                = HPbitshutdown                       ; HPbitshutdown
+    _HPcompare_accrec_tagref      = HPcompare_accrec_tagref             ; HPcompare_accrec_tagref
+    _HPcompare_filerec_path       = HPcompare_filerec_path              ; HPcompare_filerec_path
+    _HPend                        = HPend                               ; HPend
+    _HPfreediskblock              = HPfreediskblock                     ; HPfreediskblock
+    _HPgetdiskblock               = HPgetdiskblock                      ; HPgetdiskblock
+    _HPisappendable               = HPisappendable                      ; HPisappendable
+    _HPregister_term_func         = HPregister_term_func                ; HPregister_term_func
+    _HPseek                       = HPseek                              ; HPseek
+    _HRPcloseAID                  = HRPcloseAID                         ; HRPcloseAID
+    _HRPconvert                   = HRPconvert                          ; HRPconvert
+    _HRPendaccess                 = HRPendaccess                        ; HRPendaccess
+    _HRPinfo                      = HRPinfo                             ; HRPinfo
+    _HRPinquire                   = HRPinquire                          ; HRPinquire
+    _HRPread                      = HRPread                             ; HRPread
+    _HRPseek                      = HRPseek                             ; HRPseek
+    _HRPstread                    = HRPstread                           ; HRPstread
+    _HRPstwrite                   = HRPstwrite                          ; HRPstwrite
+    _HRPwrite                     = HRPwrite                            ; HRPwrite
+    _HXISCDIR                     = HXISCDIR                            ; HXISCDIR
+    _HXISDIR                      = HXISDIR                             ; HXISDIR
+    _HXPcloseAID                  = HXPcloseAID                         ; HXPcloseAID
+    _HXPendaccess                 = HXPendaccess                        ; HXPendaccess
+    _HXPinfo                      = HXPinfo                             ; HXPinfo
+    _HXPinquire                   = HXPinquire                          ; HXPinquire
+    _HXPread                      = HXPread                             ; HXPread
+    _HXPreset                     = HXPreset                            ; HXPreset
+    _HXPseek                      = HXPseek                             ; HXPseek
+    _HXPsetaccesstype             = HXPsetaccesstype                    ; HXPsetaccesstype
+    _HXPshutdown                  = HXPshutdown                         ; HXPshutdown
+    _HXPstread                    = HXPstread                           ; HXPstread
+    _HXPstwrite                   = HXPstwrite                          ; HXPstwrite
+    _HXPwrite                     = HXPwrite                            ; HXPwrite
+    _HXSCDIR                      = HXSCDIR                             ; HXSCDIR
+    _HXSDIR                       = HXSDIR                              ; HXSDIR
+    _HXcreate                     = HXcreate                            ; HXcreate
+    _HXsetcreatedir               = HXsetcreatedir                      ; HXsetcreatedir
+    _HXsetdir                     = HXsetdir                            ; HXsetdir
+    _Happendable                  = Happendable                         ; Happendable
+    _Hbitappendable               = Hbitappendable                      ; Hbitappendable
+    _Hbitread                     = Hbitread                            ; Hbitread
+    _Hbitseek                     = Hbitseek                            ; Hbitseek
+    _Hbitwrite                    = Hbitwrite                           ; Hbitwrite
+    _Hcache                       = Hcache                              ; Hcache
+    _Hclose                       = Hclose                              ; Hclose
+    _Hdeldd                       = Hdeldd                              ; Hdeldd
+    _Hdupdd                       = Hdupdd                              ; Hdupdd
+    _Hendaccess                   = Hendaccess                          ; Hendaccess
+    _Hendbitaccess                = Hendbitaccess                       ; Hendbitaccess
+    _Hexist                       = Hexist                              ; Hexist
+    _Hfidinquire                  = Hfidinquire                         ; Hfidinquire
+    _Hfind                        = Hfind                               ; Hfind
+    _Hgetbit                      = Hgetbit                             ; Hgetbit
+    _Hgetelement                  = Hgetelement                         ; Hgetelement
+    _Hgetfileversion              = Hgetfileversion                     ; Hgetfileversion
+    _Hgetlibversion               = Hgetlibversion                      ; Hgetlibversion
+    _Hinquire                     = Hinquire                            ; Hinquire
+    _Hishdf                       = Hishdf                              ; Hishdf
+    _Hlength                      = Hlength                             ; Hlength
+    _Hnewref                      = Hnewref                             ; Hnewref
+    _Hnextread                    = Hnextread                           ; Hnextread
+    _Hnumber                      = Hnumber                             ; Hnumber
+    _Hoffset                      = Hoffset                             ; Hoffset
+    _Hopen                        = Hopen                               ; Hopen
+    _Hputelement                  = Hputelement                         ; Hputelement
+    _Hread                        = Hread                               ; Hread
+    _Hseek                        = Hseek                               ; Hseek
+    _Hsetaccesstype               = Hsetaccesstype                      ; Hsetaccesstype
+    _Hsetlength                   = Hsetlength                          ; Hsetlength
+    _Hshutdown                    = Hshutdown                           ; Hshutdown
+    _Hstartaccess                 = Hstartaccess                        ; Hstartaccess
+    _Hstartbitread                = Hstartbitread                       ; Hstartbitread
+    _Hstartbitwrite               = Hstartbitwrite                      ; Hstartbitwrite
+    _Hstartread                   = Hstartread                          ; Hstartread
+    _Hstartwrite                  = Hstartwrite                         ; Hstartwrite
+    _Hsync                        = Hsync                               ; Hsync
+    _Htagnewref                   = Htagnewref                          ; Htagnewref
+    _Htell                        = Htell                               ; Htell
+    _Htrunc                       = Htrunc                              ; Htrunc
+    _Hwrite                       = Hwrite                              ; Hwrite
+    _MGATINF                      = MGATINF                             ; MGATINF
+    _MGCGICHNK                    = MGCGICHNK                           ; MGCGICHNK
+    _MGCRCCHNK                    = MGCRCCHNK                           ; MGCRCCHNK
+    _MGCRCHNK                     = MGCRCHNK                            ; MGCRCHNK
+    _MGCREAT                      = MGCREAT                             ; MGCREAT
+    _MGCSCCHNK                    = MGCSCCHNK                           ; MGCSCCHNK
+    _MGCSCHNK                     = MGCSCHNK                            ; MGCSCHNK
+    _MGCSCOMPRESS                 = MGCSCOMPRESS                        ; MGCSCOMPRESS
+    _MGCWCCHNK                    = MGCWCCHNK                           ; MGCWCCHNK
+    _MGCWCHNK                     = MGCWCHNK                            ; MGCWCHNK
+    _MGEND                        = MGEND                               ; MGEND
+    _MGENDAC                      = MGENDAC                             ; MGENDAC
+    _MGFINFO                      = MGFINFO                             ; MGFINFO
+    _MGFNDAT                      = MGFNDAT                             ; MGFNDAT
+    _MGGATTR                      = MGGATTR                             ; MGGATTR
+    _MGGCATT                      = MGGCATT                             ; MGGCATT
+    _MGGICHNK                     = MGGICHNK                            ; MGGICHNK
+    _MGGIINF                      = MGGIINF                             ; MGGIINF
+    _MGGLINF                      = MGGLINF                             ; MGGLINF
+    _MGGLTID                      = MGGLTID                             ; MGGLTID
+    _MGGNATT                      = MGGNATT                             ; MGGNATT
+    _MGICREAT                     = MGICREAT                            ; MGICREAT
+    _MGID2RF                      = MGID2RF                             ; MGID2RF
+    _MGIFNDAT                     = MGIFNDAT                            ; MGIFNDAT
+    _MGIGNAT                      = MGIGNAT                             ; MGIGNAT
+    _MGIN2NDX                     = MGIN2NDX                            ; MGIN2NDX
+    _MGIRIMG                      = MGIRIMG                             ; MGIRIMG
+    _MGISATTR                     = MGISATTR                            ; MGISATTR
+    _MGISCATT                     = MGISCATT                            ; MGISCATT
+    _MGISXFIL                     = MGISXFIL                            ; MGISXFIL
+    _MGIWIMG                      = MGIWIMG                             ; MGIWIMG
+    _MGN2NDX                      = MGN2NDX                             ; MGN2NDX
+    _MGR2IDX                      = MGR2IDX                             ; MGR2IDX
+    _MGRCCHNK                     = MGRCCHNK                            ; MGRCCHNK
+    _MGRCHNK                      = MGRCHNK                             ; MGRCHNK
+    _MGRCIMG                      = MGRCIMG                             ; MGRCIMG
+    _MGRCLUT                      = MGRCLUT                             ; MGRCLUT
+    _MGRDIMG                      = MGRDIMG                             ; MGRDIMG
+    _MGRDLUT                      = MGRDLUT                             ; MGRDLUT
+    _MGRIMIL                      = MGRIMIL                             ; MGRIMIL
+    _MGRLTIL                      = MGRLTIL                             ; MGRLTIL
+    _MGSACTP                      = MGSACTP                             ; MGSACTP
+    _MGSCATT                      = MGSCATT                             ; MGSCATT
+    _MGSCCHNK                     = MGSCCHNK                            ; MGSCCHNK
+    _MGSCHNK                      = MGSCHNK                             ; MGSCHNK
+    _MGSCOMPRESS                  = MGSCOMPRESS                         ; MGSCOMPRESS
+    _MGSELCT                      = MGSELCT                             ; MGSELCT
+    _MGSNATT                      = MGSNATT                             ; MGSNATT
+    _MGSTART                      = MGSTART                             ; MGSTART
+    _MGSXFIL                      = MGSXFIL                             ; MGSXFIL
+    _MGWCCHNK                     = MGWCCHNK                            ; MGWCCHNK
+    _MGWCHNK                      = MGWCHNK                             ; MGWCHNK
+    _MGWCIMG                      = MGWCIMG                             ; MGWCIMG
+    _MGWCLUT                      = MGWCLUT                             ; MGWCLUT
+    _MGWRIMG                      = MGWRIMG                             ; MGWRIMG
+    _MGWRLUT                      = MGWRLUT                             ; MGWRLUT
+    _VADTRC                       = VADTRC                              ; VADTRC
+    _VATCHC                       = VATCHC                              ; VATCHC
+    _VDELETE                      = VDELETE                             ; VDELETE
+    _VDELETEC                     = VDELETEC                            ; VDELETEC
+    _VDTCHC                       = VDTCHC                              ; VDTCHC
+    _VDTRC                        = VDTRC                               ; VDTRC
+    _VENTSC                       = VENTSC                              ; VENTSC
+    _VFADTR                       = VFADTR                              ; VFADTR
+    _VFAINFO                      = VFAINFO                             ; VFAINFO
+    _VFATCH                       = VFATCH                              ; VFATCH
+    _VFCFDAT                      = VFCFDAT                             ; VFCFDAT
+    _VFCSATT                      = VFCSATT                             ; VFCSATT
+    _VFCSCAT                      = VFCSCAT                             ; VFCSCAT
+    _VFDTCH                       = VFDTCH                              ; VFDTCH
+    _VFDTR                        = VFDTR                               ; VFDTR
+    _VFEND                        = VFEND                               ; VFEND
+    _VFENTS                       = VFENTS                              ; VFENTS
+    _VFFDATT                      = VFFDATT                             ; VFFDATT
+    _VFFESIZ                      = VFFESIZ                             ; VFFESIZ
+    _VFFISIZ                      = VFFISIZ                             ; VFFISIZ
+    _VFFLOC                       = VFFLOC                              ; VFFLOC
+    _VFFNAME                      = VFFNAME                             ; VFFNAME
+    _VFFORDR                      = VFFORDR                             ; VFFORDR
+    _VFFTYPE                      = VFFTYPE                             ; VFFTYPE
+    _VFGCATT                      = VFGCATT                             ; VFGCATT
+    _VFGCLS                       = VFGCLS                              ; VFGCLS
+    _VFGID                        = VFGID                               ; VFGID
+    _VFGNAM                       = VFGNAM                              ; VFGNAM
+    _VFGNATT                      = VFGNATT                             ; VFGNATT
+    _VFGNXT                       = VFGNXT                              ; VFGNXT
+    _VFGTTR                       = VFGTTR                              ; VFGTTR
+    _VFGTTRS                      = VFGTTRS                             ; VFGTTRS
+    _VFGVER                       = VFGVER                              ; VFGVER
+    _VFIND                        = VFIND                               ; VFIND
+    _VFINDC                       = VFINDC                              ; VFINDC
+    _VFINQ                        = VFINQ                               ; VFINQ
+    _VFINQTR                      = VFINQTR                             ; VFINQTR
+    _VFINSRT                      = VFINSRT                             ; VFINSRT
+    _VFISVG                       = VFISVG                              ; VFISVG
+    _VFISVS                       = VFISVS                              ; VFISVS
+    _VFLOCC                       = VFLOCC                              ; VFLOCC
+    _VFLONE                       = VFLONE                              ; VFLONE
+    _VFNATTS                      = VFNATTS                             ; VFNATTS
+    _VFNDCLS                      = VFNDCLS                             ; VFNDCLS
+    _VFNDCLSC                     = VFNDCLSC                            ; VFNDCLSC
+    _VFNFLDS                      = VFNFLDS                             ; VFNFLDS
+    _VFNTR                        = VFNTR                               ; VFNTR
+    _VFSCATT                      = VFSCATT                             ; VFSCATT
+    _VFSCLS                       = VFSCLS                              ; VFSCLS
+    _VFSNAM                       = VFSNAM                              ; VFSNAM
+    _VFSNATT                      = VFSNATT                             ; VFSNATT
+    _VFSTART                      = VFSTART                             ; VFSTART
+    _VFfieldesize                 = VFfieldesize                        ; VFfieldesize
+    _VFfieldisize                 = VFfieldisize                        ; VFfieldisize
+    _VFfieldname                  = VFfieldname                         ; VFfieldname
+    _VFfieldorder                 = VFfieldorder                        ; VFfieldorder
+    _VFfieldtype                  = VFfieldtype                         ; VFfieldtype
+    _VFnfields                    = VFnfields                           ; VFnfields
+    _VGCLSC                       = VGCLSC                              ; VGCLSC
+    _VGIDC                        = VGIDC                               ; VGIDC
+    _VGNAMC                       = VGNAMC                              ; VGNAMC
+    _VGNXTC                       = VGNXTC                              ; VGNXTC
+    _VGTTRC                       = VGTTRC                              ; VGTTRC
+    _VGTTRSC                      = VGTTRSC                             ; VGTTRSC
+    _VHFMKGP                      = VHFMKGP                             ; VHFMKGP
+    _VHFSCD                       = VHFSCD                              ; VHFSCD
+    _VHFSCDM                      = VHFSCDM                             ; VHFSCDM
+    _VHFSD                        = VHFSD                               ; VHFSD
+    _VHFSDM                       = VHFSDM                              ; VHFSDM
+    _VHMKGPC                      = VHMKGPC                             ; VHMKGPC
+    _VHSCDC                       = VHSCDC                              ; VHSCDC
+    _VHSCDMC                      = VHSCDMC                             ; VHSCDMC
+    _VHSDC                        = VHSDC                               ; VHSDC
+    _VHSDMC                       = VHSDMC                              ; VHSDMC
+    _VHmakegroup                  = VHmakegroup                         ; VHmakegroup
+    _VHstoredata                  = VHstoredata                         ; VHstoredata
+    _VHstoredatam                 = VHstoredatam                        ; VHstoredatam
+    _VINQC                        = VINQC                               ; VINQC
+    _VINQTRC                      = VINQTRC                             ; VINQTRC
+    _VINSRTC                      = VINSRTC                             ; VINSRTC
+    _VISVGC                       = VISVGC                              ; VISVGC
+    _VISVSC                       = VISVSC                              ; VISVSC
+    _VLONEC                       = VLONEC                              ; VLONEC
+    _VNREFS                       = VNREFS                              ; VNREFS
+    _VNTRC                        = VNTRC                               ; VNTRC
+    _VPshutdown                   = VPshutdown                          ; VPshutdown
+    _VQREF                        = VQREF                               ; VQREF
+    _VQTAG                        = VQTAG                               ; VQTAG
+    _VQueryref                    = VQueryref                           ; VQueryref
+    _VQuerytag                    = VQuerytag                           ; VQuerytag
+    _VSAPP                        = VSAPP                               ; VSAPP
+    _VSATCHC                      = VSATCHC                             ; VSATCHC
+    _VSCLSC                       = VSCLSC                              ; VSCLSC
+    _VSDLTC                       = VSDLTC                              ; VSDLTC
+    _VSDTCHC                      = VSDTCHC                             ; VSDTCHC
+    _VSELTSC                      = VSELTSC                             ; VSELTSC
+    _VSFAINF                      = VSFAINF                             ; VSFAINF
+    _VSFATCH                      = VSFATCH                             ; VSFATCH
+    _VSFCCPK                      = VSFCCPK                             ; VSFCCPK
+    _VSFCFDA                      = VSFCFDA                             ; VSFCFDA
+    _VSFCFDX                      = VSFCFDX                             ; VSFCFDX
+    _VSFCPAK                      = VSFCPAK                             ; VSFCPAK
+    _VSFCSAT                      = VSFCSAT                             ; VSFCSAT
+    _VSFCSCA                      = VSFCSCA                             ; VSFCSCA
+    _VSFDEFC                      = VSFDEFC                             ; VSFDEFC
+    _VSFDLTE                      = VSFDLTE                             ; VSFDLTE
+    _VSFDTCH                      = VSFDTCH                             ; VSFDTCH
+    _VSFELTS                      = VSFELTS                             ; VSFELTS
+    _VSFEX                        = VSFEX                               ; VSFEX
+    _VSFEXC                       = VSFEXC                              ; VSFEXC
+    _VSFFCLS                      = VSFFCLS                             ; VSFFCLS
+    _VSFFDAT                      = VSFFDAT                             ; VSFFDAT
+    _VSFFDEF                      = VSFFDEF                             ; VSFFDEF
+    _VSFFIDX                      = VSFFIDX                             ; VSFFIDX
+    _VSFFNAS                      = VSFFNAS                             ; VSFFNAS
+    _VSFFND                       = VSFFND                              ; VSFFND
+    _VSFGCAT                      = VSFGCAT                             ; VSFGCAT
+    _VSFGCLS                      = VSFGCLS                             ; VSFGCLS
+    _VSFGFLD                      = VSFGFLD                             ; VSFGFLD
+    _VSFGID                       = VSFGID                              ; VSFGID
+    _VSFGINT                      = VSFGINT                             ; VSFGINT
+    _VSFGNAM                      = VSFGNAM                             ; VSFGNAM
+    _VSFGNAT                      = VSFGNAT                             ; VSFGNAT
+    _VSFINQ                       = VSFINQ                              ; VSFINQ
+    _VSFISAT                      = VSFISAT                             ; VSFISAT
+    _VSFLONE                      = VSFLONE                             ; VSFLONE
+    _VSFNATS                      = VSFNATS                             ; VSFNATS
+    _VSFNCPK                      = VSFNCPK                             ; VSFNCPK
+    _VSFNDC                       = VSFNDC                              ; VSFNDC
+    _VSFNPAK                      = VSFNPAK                             ; VSFNPAK
+    _VSFRD                        = VSFRD                               ; VSFRD
+    _VSFRDC                       = VSFRDC                              ; VSFRDC
+    _VSFREAD                      = VSFREAD                             ; VSFREAD
+    _VSFSCAT                      = VSFSCAT                             ; VSFSCAT
+    _VSFSCLS                      = VSFSCLS                             ; VSFSCLS
+    _VSFSEEK                      = VSFSEEK                             ; VSFSEEK
+    _VSFSEXTF                     = VSFSEXTF                            ; VSFSEXTF
+    _VSFSFLD                      = VSFSFLD                             ; VSFSFLD
+    _VSFSINT                      = VSFSINT                             ; VSFSINT
+    _VSFSIZ                       = VSFSIZ                              ; VSFSIZ
+    _VSFSNAM                      = VSFSNAM                             ; VSFSNAM
+    _VSFSNAT                      = VSFSNAT                             ; VSFSNAT
+    _VSFWRIT                      = VSFWRIT                             ; VSFWRIT
+    _VSFWRT                       = VSFWRT                              ; VSFWRT
+    _VSFWRTC                      = VSFWRTC                             ; VSFWRTC
+    _VSGCLSC                      = VSGCLSC                             ; VSGCLSC
+    _VSGFLDC                      = VSGFLDC                             ; VSGFLDC
+    _VSGIDC                       = VSGIDC                              ; VSGIDC
+    _VSGINTC                      = VSGINTC                             ; VSGINTC
+    _VSGNAMC                      = VSGNAMC                             ; VSGNAMC
+    _VSGVER                       = VSGVER                              ; VSGVER
+    _VSINQC                       = VSINQC                              ; VSINQC
+    _VSLONEC                      = VSLONEC                             ; VSLONEC
+    _VSNAMC                       = VSNAMC                              ; VSNAMC
+    _VSPhshutdown                 = VSPhshutdown                        ; VSPhshutdown
+    _VSPshutdown                  = VSPshutdown                         ; VSPshutdown
+    _VSQFFLDS                     = VSQFFLDS                            ; VSQFFLDS
+    _VSQFINTR                     = VSQFINTR                            ; VSQFINTR
+    _VSQFLDSC                     = VSQFLDSC                            ; VSQFLDSC
+    _VSQFNAME                     = VSQFNAME                            ; VSQFNAME
+    _VSQFNELT                     = VSQFNELT                            ; VSQFNELT
+    _VSQFVSIZ                     = VSQFVSIZ                            ; VSQFVSIZ
+    _VSQNAMEC                     = VSQNAMEC                            ; VSQNAMEC
+    _VSQREF                       = VSQREF                              ; VSQREF
+    _VSQTAG                       = VSQTAG                              ; VSQTAG
+    _VSQueryref                   = VSQueryref                          ; VSQueryref
+    _VSQuerytag                   = VSQuerytag                          ; VSQuerytag
+    _VSREADC                      = VSREADC                             ; VSREADC
+    _VSSCLSC                      = VSSCLSC                             ; VSSCLSC
+    _VSSEEKC                      = VSSEEKC                             ; VSSEEKC
+    _VSSEXTFC                     = VSSEXTFC                            ; VSSEXTFC
+    _VSSFLDC                      = VSSFLDC                             ; VSSFLDC
+    _VSSINTC                      = VSSINTC                             ; VSSINTC
+    _VSSIZC                       = VSSIZC                              ; VSSIZC
+    _VSSNAMC                      = VSSNAMC                             ; VSSNAMC
+    _VSWRITC                      = VSWRITC                             ; VSWRITC
+    _VSappendable                 = VSappendable                        ; VSappendable
+    _VSattach                     = VSattach                            ; VSattach
+    _VSattrinfo                   = VSattrinfo                          ; VSattrinfo
+    _VSdelete                     = VSdelete                            ; VSdelete
+    _VSdetach                     = VSdetach                            ; VSdetach
+    _VSdump                       = VSdump                              ; VSdump
+    _VSelts                       = VSelts                              ; VSelts
+    _VSfdefine                    = VSfdefine                           ; VSfdefine
+    _VSfexist                     = VSfexist                            ; VSfexist
+    _VSfind                       = VSfind                              ; VSfind
+    _VSfindattr                   = VSfindattr                          ; VSfindattr
+    _VSfindclass                  = VSfindclass                         ; VSfindclass
+    _VSfindex                     = VSfindex                            ; VSfindex
+    _VSfnattrs                    = VSfnattrs                           ; VSfnattrs
+    _VSfpack                      = VSfpack                             ; VSfpack
+    _VSgetattr                    = VSgetattr                           ; VSgetattr
+    _VSgetclass                   = VSgetclass                          ; VSgetclass
+    _VSgetfields                  = VSgetfields                         ; VSgetfields
+    _VSgetid                      = VSgetid                             ; VSgetid
+    _VSgetinterlace               = VSgetinterlace                      ; VSgetinterlace
+    _VSgetname                    = VSgetname                           ; VSgetname
+    _VSgetversion                 = VSgetversion                        ; VSgetversion
+    _VSinquire                    = VSinquire                           ; VSinquire
+    _VSisattr                     = VSisattr                            ; VSisattr
+    _VSlone                       = VSlone                              ; VSlone
+    _VSnattrs                     = VSnattrs                            ; VSnattrs
+    _VSread                       = VSread                              ; VSread
+    _VSseek                       = VSseek                              ; VSseek
+    _VSsetattr                    = VSsetattr                           ; VSsetattr
+    _VSsetclass                   = VSsetclass                          ; VSsetclass
+    _VSsetexternalfile            = VSsetexternalfile                   ; VSsetexternalfile
+    _VSsetfields                  = VSsetfields                         ; VSsetfields
+    _VSsetinterlace               = VSsetinterlace                      ; VSsetinterlace
+    _VSsetname                    = VSsetname                           ; VSsetname
+    _VSsizeof                     = VSsizeof                            ; VSsizeof
+    _VSwrite                      = VSwrite                             ; VSwrite
+    _Vaddtagref                   = Vaddtagref                          ; Vaddtagref
+    _Vattach                      = Vattach                             ; Vattach
+    _Vattrinfo                    = Vattrinfo                           ; Vattrinfo
+    _Vclose                       = Vclose                              ; Vclose
+    _Vdelete                      = Vdelete                             ; Vdelete
+    _Vdeletetagref                = Vdeletetagref                       ; Vdeletetagref
+    _Vdetach                      = Vdetach                             ; Vdetach
+    _Ventries                     = Ventries                            ; Ventries
+    _Vfind                        = Vfind                               ; Vfind
+    _Vfindattr                    = Vfindattr                           ; Vfindattr
+    _Vfindclass                   = Vfindclass                          ; Vfindclass
+    _Vfinish                      = Vfinish                             ; Vfinish
+    _Vflocate                     = Vflocate                            ; Vflocate
+    _Vgetattr                     = Vgetattr                            ; Vgetattr
+    _Vgetclass                    = Vgetclass                           ; Vgetclass
+    _Vgetid                       = Vgetid                              ; Vgetid
+    _Vgetname                     = Vgetname                            ; Vgetname
+    _Vgetnext                     = Vgetnext                            ; Vgetnext
+    _Vgettagref                   = Vgettagref                          ; Vgettagref
+    _Vgettagrefs                  = Vgettagrefs                         ; Vgettagrefs
+    _Vgetversion                  = Vgetversion                         ; Vgetversion
+    _Vinitialize                  = Vinitialize                         ; Vinitialize
+    _Vinqtagref                   = Vinqtagref                          ; Vinqtagref
+    _Vinquire                     = Vinquire                            ; Vinquire
+    _Vinsert                      = Vinsert                             ; Vinsert
+    _Visvg                        = Visvg                               ; Visvg
+    _Visvs                        = Visvs                               ; Visvs
+    _Vlone                        = Vlone                               ; Vlone
+    _Vnattrs                      = Vnattrs                             ; Vnattrs
+    _Vnrefs                       = Vnrefs                              ; Vnrefs
+    _Vntagrefs                    = Vntagrefs                           ; Vntagrefs
+    _Vopen                        = Vopen                               ; Vopen
+    _Vsetattr                     = Vsetattr                            ; Vsetattr
+    _Vsetclass                    = Vsetclass                           ; Vsetclass
+    _Vsetname                     = Vsetname                            ; Vsetname
+    _Vsetzap                      = Vsetzap                             ; Vsetzap
+    AFANNLEN                      = _AFANNLEN at 4                         
+    AFANNLIST                     = _AFANNLIST at 20                       
+    AFATYPETAG                    = _AFATYPETAG at 4                       
+    AFCREATE                      = _AFCREATE at 16                        
+    AFEND                         = _AFEND at 4                            
+    AFENDACCESS                   = _AFENDACCESS at 4                      
+    AFFCREATE                     = _AFFCREATE at 8                        
+    AFFILEINFO                    = _AFFILEINFO at 20                      
+    AFGETTAGREF                   = _AFGETTAGREF at 20                     
+    AFIDTAGREF                    = _AFIDTAGREF at 12                      
+    AFNUMANN                      = _AFNUMANN at 16                        
+    AFREADANN                     = _AFREADANN at 16                       
+    AFSELECT                      = _AFSELECT at 12                        
+    AFSTART                       = _AFSTART at 4                          
+    AFTAGATYPE                    = _AFTAGATYPE at 4                       
+    AFTAGREFID                    = _AFTAGREFID at 12                      
+    AFWRITEANN                    = _AFWRITEANN at 16                      
+    HCLOSE                        = _HCLOSE at 4                           
+    HESTRING                      = _HESTRING at 12                        
+    HGFILVER                      = _HGFILVER at 24                        
+    HGLIBVER                      = _HGLIBVER at 20                        
+    HISHDF                        = _HISHDF at 8                           
+    HNUMBER                       = _HNUMBER at 8                          
+    HOPEN                         = _HOPEN at 16                           
+    HXSCDIR                       = _HXSCDIR at 8                          
+    HXSDIR                        = _HXSDIR at 8                           
+    MGATINF                       = _MGATINF at 24                         
+    MGCREAT                       = _MGCREAT at 28                         
+    MGEND                         = _MGEND at 4                            
+    MGENDAC                       = _MGENDAC at 4                          
+    MGFINFO                       = _MGFINFO at 12                         
+    MGFNDAT                       = _MGFNDAT at 12                         
+    MGGATTR                       = _MGGATTR at 12                         
+    MGGCATT                       = _MGGCATT at 16                         
+    MGGICHNK                      = _MGGICHNK at 12                        
+    MGGIINF                       = _MGGIINF at 32                         
+    MGGLINF                       = _MGGLINF at 20                         
+    MGGLTID                       = _MGGLTID at 8                          
+    MGGNATT                       = _MGGNATT at 12                         
+    MGID2RF                       = _MGID2RF at 4                          
+    MGN2NDX                       = _MGN2NDX at 12                         
+    MGR2IDX                       = _MGR2IDX at 8                          
+    MGRCCHNK                      = _MGRCCHNK at 16                        
+    MGRCHNK                       = _MGRCHNK at 12                         
+    MGRCIMG                       = _MGRCIMG at 24                         
+    MGRCLUT                       = _MGRCLUT at 12                         
+    MGRDIMG                       = _MGRDIMG at 20                         
+    MGRDLUT                       = _MGRDLUT at 8                          
+    MGRIMIL                       = _MGRIMIL at 8                          
+    MGRLTIL                       = _MGRLTIL at 8                          
+    MGSACTP                       = _MGSACTP at 8                          
+    MGSCATT                       = _MGSCATT at 28                         
+    MGSCCHNK                      = _MGSCCHNK at 12                        
+    MGSCHNK                       = _MGSCHNK at 16                         
+    MGSCOMPRESS                   = _MGSCOMPRESS at 12                     
+    MGSELCT                       = _MGSELCT at 8                          
+    MGSNATT                       = _MGSNATT at 24                         
+    MGSTART                       = _MGSTART at 4                          
+    MGSXFIL                       = _MGSXFIL at 16                         
+    MGWCCHNK                      = _MGWCCHNK at 16                        
+    MGWCHNK                       = _MGWCHNK at 12                         
+    MGWCIMG                       = _MGWCIMG at 24                         
+    MGWCLUT                       = _MGWCLUT at 28                         
+    MGWRIMG                       = _MGWRIMG at 20                         
+    MGWRLUT                       = _MGWRLUT at 24                         
+    VDELETE                       = _VDELETE at 8                          
+    VFADTR                        = _VFADTR at 12                          
+    VFAINFO                       = _VFAINFO at 28                         
+    VFATCH                        = _VFATCH at 16                          
+    VFDTCH                        = _VFDTCH at 4                           
+    VFDTR                         = _VFDTR at 12                           
+    VFEND                         = _VFEND at 4                            
+    VFENTS                        = _VFENTS at 8                           
+    VFFDATT                       = _VFFDATT at 12                         
+    VFFESIZ                       = _VFFESIZ at 8                          
+    VFFISIZ                       = _VFFISIZ at 8                          
+    VFFLOC                        = _VFFLOC at 12                          
+    VFFNAME                       = _VFFNAME at 16                         
+    VFFORDR                       = _VFFORDR at 8                          
+    VFFTYPE                       = _VFFTYPE at 8                          
+    VFGCATT                       = _VFGCATT at 16                         
+    VFGCLS                        = _VFGCLS at 12                          
+    VFGID                         = _VFGID at 8                            
+    VFGNAM                        = _VFGNAM at 12                          
+    VFGNATT                       = _VFGNATT at 12                         
+    VFGNXT                        = _VFGNXT at 8                           
+    VFGTTR                        = _VFGTTR at 16                          
+    VFGTTRS                       = _VFGTTRS at 16                         
+    VFGVER                        = _VFGVER at 4                           
+    VFIND                         = _VFIND at 12                           
+    VFINQ                         = _VFINQ at 16                           
+    VFINQTR                       = _VFINQTR at 12                         
+    VFINSRT                       = _VFINSRT at 8                          
+    VFISVG                        = _VFISVG at 8                           
+    VFISVS                        = _VFISVS at 8                           
+    VFLONE                        = _VFLONE at 12                          
+    VFNATTS                       = _VFNATTS at 4                          
+    VFNDCLS                       = _VFNDCLS at 12                         
+    VFNFLDS                       = _VFNFLDS at 4                          
+    VFNTR                         = _VFNTR at 4                            
+    VFSCATT                       = _VFSCATT at 28                         
+    VFSCLS                        = _VFSCLS at 12                          
+    VFSNAM                        = _VFSNAM at 12                          
+    VFSNATT                       = _VFSNATT at 24                         
+    VFSTART                       = _VFSTART at 4                          
+    VHFMKGP                       = _VHFMKGP at 32                         
+    VHFSCD                        = _VHFSCD at 44                          
+    VHFSCDM                       = _VHFSCDM at 48                         
+    VHFSD                         = _VHFSD at 40                           
+    VHFSDM                        = _VHFSDM at 44                          
+    VNREFS                        = _VNREFS at 8                           
+    VQREF                         = _VQREF at 4                            
+    VQTAG                         = _VQTAG at 4                            
+    VSFAINF                       = _VSFAINF at 32                         
+    VSFATCH                       = _VSFATCH at 16                         
+    VSFCPAK                       = _VSFCPAK at 44                         
+    VSFDLTE                       = _VSFDLTE at 8                          
+    VSFDTCH                       = _VSFDTCH at 4                          
+    VSFELTS                       = _VSFELTS at 4                          
+    VSFEX                         = _VSFEX at 12                           
+    VSFFCLS                       = _VSFFCLS at 12                         
+    VSFFDAT                       = _VSFFDAT at 16                         
+    VSFFDEF                       = _VSFFDEF at 20                         
+    VSFFIDX                       = _VSFFIDX at 16                         
+    VSFFNAS                       = _VSFFNAS at 8                          
+    VSFFND                        = _VSFFND at 12                          
+    VSFGCAT                       = _VSFGCAT at 20                         
+    VSFGCLS                       = _VSFGCLS at 12                         
+    VSFGFLD                       = _VSFGFLD at 12                         
+    VSFGID                        = _VSFGID at 8                           
+    VSFGINT                       = _VSFGINT at 4                          
+    VSFGNAM                       = _VSFGNAM at 12                         
+    VSFGNAT                       = _VSFGNAT at 16                         
+    VSFINQ                        = _VSFINQ at 32                          
+    VSFISAT                       = _VSFISAT at 4                          
+    VSFLONE                       = _VSFLONE at 12                         
+    VSFNATS                       = _VSFNATS at 4                          
+    VSFNPAK                       = _VSFNPAK at 40                         
+    VSFRD                         = _VSFRD at 16                           
+    VSFRDC                        = _VSFRDC at 20                          
+    VSFREAD                       = _VSFREAD at 20                         
+    VSFSCAT                       = _VSFSCAT at 32                         
+    VSFSCLS                       = _VSFSCLS at 12                         
+    VSFSEEK                       = _VSFSEEK at 8                          
+    VSFSEXTF                      = _VSFSEXTF at 16                        
+    VSFSFLD                       = _VSFSFLD at 12                         
+    VSFSINT                       = _VSFSINT at 8                          
+    VSFSIZ                        = _VSFSIZ at 12                          
+    VSFSNAM                       = _VSFSNAM at 12                         
+    VSFSNAT                       = _VSFSNAT at 28                         
+    VSFWRIT                       = _VSFWRIT at 20                         
+    VSFWRT                        = _VSFWRT at 16                          
+    VSFWRTC                       = _VSFWRTC at 20                         
+    VSGVER                        = _VSGVER at 4                           
+    VSQFFLDS                      = _VSQFFLDS at 12                        
+    VSQFINTR                      = _VSQFINTR at 8                         
+    VSQFNAME                      = _VSQFNAME at 12                        
+    VSQFNELT                      = _VSQFNELT at 8                         
+    VSQFVSIZ                      = _VSQFVSIZ at 8                         
+    VSQREF                        = _VSQREF at 4                           
+    VSQTAG                        = _VSQTAG at 4                           
+    _rigcompare                   = rigcompare                          ; rigcompare
+    _scanattrs                    = scanattrs                           ; scanattrs
+    _tagcompare                   = tagcompare                          ; tagcompare
+    _tagdestroynode               = tagdestroynode                      ; tagdestroynode
+    _vcheckcompat                 = vcheckcompat                        ; vcheckcompat
+    _vcompare                     = vcompare                            ; vcompare
+    _vdestroynode                 = vdestroynode                        ; vdestroynode
+    _vexistvg                     = vexistvg                            ; vexistvg
+    _vexistvs                     = vexistvs                            ; vexistvs
+    _vfdestroynode                = vfdestroynode                       ; vfdestroynode
+    _vicheckcompat                = vicheckcompat                       ; vicheckcompat
+    _vimakecompat                 = vimakecompat                        ; vimakecompat
+    _vmakecompat                  = vmakecompat                         ; vmakecompat
+    _vsdestroynode                = vsdestroynode                       ; vsdestroynode
diff --git a/bindings/java/bin/win32/hd413m.dll b/bindings/java/bin/win32/hd413m.dll
new file mode 100644
index 0000000..07fc807
Binary files /dev/null and b/bindings/java/bin/win32/hd413m.dll differ
diff --git a/bindings/java/bin/win32/hd413m.lib b/bindings/java/bin/win32/hd413m.lib
new file mode 100644
index 0000000..bf9a410
Binary files /dev/null and b/bindings/java/bin/win32/hd413m.lib differ
diff --git a/bindings/java/bin/win32/hd415m.dll b/bindings/java/bin/win32/hd415m.dll
new file mode 100755
index 0000000..bc116f0
Binary files /dev/null and b/bindings/java/bin/win32/hd415m.dll differ
diff --git a/bindings/java/bin/win32/hdf5dll.dll b/bindings/java/bin/win32/hdf5dll.dll
new file mode 100755
index 0000000..ec0e172
Binary files /dev/null and b/bindings/java/bin/win32/hdf5dll.dll differ
diff --git a/bindings/java/bin/win32/hm413m.def b/bindings/java/bin/win32/hm413m.def
new file mode 100644
index 0000000..6fbdacd
--- /dev/null
+++ b/bindings/java/bin/win32/hm413m.def
@@ -0,0 +1,201 @@
+LIBRARY     HM413M.DLL
+
+EXPORTS
+    _SDattrinfo                   = SDattrinfo                          ; SDattrinfo
+    _SDcheckempty                 = SDcheckempty                        ; SDcheckempty
+    _SDcreate                     = SDcreate                            ; SDcreate
+    _SDdiminfo                    = SDdiminfo                           ; SDdiminfo
+    _SDend                        = SDend                               ; SDend
+    _SDendaccess                  = SDendaccess                         ; SDendaccess
+    _SDfileinfo                   = SDfileinfo                          ; SDfileinfo
+    _SDfindattr                   = SDfindattr                          ; SDfindattr
+    _SDgetcal                     = SDgetcal                            ; SDgetcal
+    _SDgetchunkinfo               = SDgetchunkinfo                      ; SDgetchunkinfo
+    _SDgetdatastrs                = SDgetdatastrs                       ; SDgetdatastrs
+    _SDgetdimid                   = SDgetdimid                          ; SDgetdimid
+    _SDgetdimscale                = SDgetdimscale                       ; SDgetdimscale
+    _SDgetdimstrs                 = SDgetdimstrs                        ; SDgetdimstrs
+    _SDgetfillvalue               = SDgetfillvalue                      ; SDgetfillvalue
+    _SDgetinfo                    = SDgetinfo                           ; SDgetinfo
+    _SDgetrange                   = SDgetrange                          ; SDgetrange
+    _SDidtoref                    = SDidtoref                           ; SDidtoref
+    _SDiscoordvar                 = SDiscoordvar                        ; SDiscoordvar
+    _SDisdimval_bwcomp            = SDisdimval_bwcomp                   ; SDisdimval_bwcomp
+    _SDisrecord                   = SDisrecord                          ; SDisrecord
+    _SDnametoindex                = SDnametoindex                       ; SDnametoindex
+    _SDreadattr                   = SDreadattr                          ; SDreadattr
+    _SDreadchunk                  = SDreadchunk                         ; SDreadchunk
+    _SDreaddata                   = SDreaddata                          ; SDreaddata
+    _SDreftoindex                 = SDreftoindex                        ; SDreftoindex
+    _SDselect                     = SDselect                            ; SDselect
+    _SDsetaccesstype              = SDsetaccesstype                     ; SDsetaccesstype
+    _SDsetattr                    = SDsetattr                           ; SDsetattr
+    _SDsetblocksize               = SDsetblocksize                      ; SDsetblocksize
+    _SDsetcal                     = SDsetcal                            ; SDsetcal
+    _SDsetchunk                   = SDsetchunk                          ; SDsetchunk
+    _SDsetchunkcache              = SDsetchunkcache                     ; SDsetchunkcache
+    _SDsetcompress                = SDsetcompress                       ; SDsetcompress
+    _SDsetdatastrs                = SDsetdatastrs                       ; SDsetdatastrs
+    _SDsetdimname                 = SDsetdimname                        ; SDsetdimname
+    _SDsetdimscale                = SDsetdimscale                       ; SDsetdimscale
+    _SDsetdimstrs                 = SDsetdimstrs                        ; SDsetdimstrs
+    _SDsetdimval_comp             = SDsetdimval_comp                    ; SDsetdimval_comp
+    _SDsetexternalfile            = SDsetexternalfile                   ; SDsetexternalfile
+    _SDsetfillmode                = SDsetfillmode                       ; SDsetfillmode
+    _SDsetfillvalue               = SDsetfillvalue                      ; SDsetfillvalue
+    _SDsetnbitdataset             = SDsetnbitdataset                    ; SDsetnbitdataset
+    _SDsetrange                   = SDsetrange                          ; SDsetrange
+    _SDstart                      = SDstart                             ; SDstart
+    _SDwritechunk                 = SDwritechunk                        ; SDwritechunk
+    _SDwritedata                  = SDwritedata                         ; SDwritedata
+    _SFCHEMPTY                    = SFCHEMPTY                           ; SFCHEMPTY
+    _SFCREATE                     = SFCREATE                            ; SFCREATE
+    _SFDIMID                      = SFDIMID                             ; SFDIMID
+    _SFEND                        = SFEND                               ; SFEND
+    _SFENDACC                     = SFENDACC                            ; SFENDACC
+    _SFFATTR                      = SFFATTR                             ; SFFATTR
+    _SFFINFO                      = SFFINFO                             ; SFFINFO
+    _SFGAINFO                     = SFGAINFO                            ; SFGAINFO
+    _SFGCAL                       = SFGCAL                              ; SFGCAL
+    _SFGCFILL                     = SFGCFILL                            ; SFGCFILL
+    _SFGDINFO                     = SFGDINFO                            ; SFGDINFO
+    _SFGDMSTR                     = SFGDMSTR                            ; SFGDMSTR
+    _SFGDSCALE                    = SFGDSCALE                           ; SFGDSCALE
+    _SFGDTSTR                     = SFGDTSTR                            ; SFGDTSTR
+    _SFGFILL                      = SFGFILL                             ; SFGFILL
+    _SFGICHNK                     = SFGICHNK                            ; SFGICHNK
+    _SFGINFO                      = SFGINFO                             ; SFGINFO
+    _SFGRANGE                     = SFGRANGE                            ; SFGRANGE
+    _SFID2REF                     = SFID2REF                            ; SFID2REF
+    _SFISCVAR                     = SFISCVAR                            ; SFISCVAR
+    _SFISDMVC                     = SFISDMVC                            ; SFISDMVC
+    _SFISRCRD                     = SFISRCRD                            ; SFISRCRD
+    _SFN2INDEX                    = SFN2INDEX                           ; SFN2INDEX
+    _SFRATTR                      = SFRATTR                             ; SFRATTR
+    _SFRCATT                      = SFRCATT                             ; SFRCATT
+    _SFRCCHNK                     = SFRCCHNK                            ; SFRCCHNK
+    _SFRCDATA                     = SFRCDATA                            ; SFRCDATA
+    _SFRCHNK                      = SFRCHNK                             ; SFRCHNK
+    _SFRDATA                      = SFRDATA                             ; SFRDATA
+    _SFREF2INDEX                  = SFREF2INDEX                         ; SFREF2INDEX
+    _SFRNATT                      = SFRNATT                             ; SFRNATT
+    _SFSACCT                      = SFSACCT                             ; SFSACCT
+    _SFSATTR                      = SFSATTR                             ; SFSATTR
+    _SFSBLSZ                      = SFSBLSZ                             ; SFSBLSZ
+    _SFSCAL                       = SFSCAL                              ; SFSCAL
+    _SFSCATT                      = SFSCATT                             ; SFSCATT
+    _SFSCCHNK                     = SFSCCHNK                            ; SFSCCHNK
+    _SFSCFILL                     = SFSCFILL                            ; SFSCFILL
+    _SFSCHNK                      = SFSCHNK                             ; SFSCHNK
+    _SFSCOMPRESS                  = SFSCOMPRESS                         ; SFSCOMPRESS
+    _SFSDMNAME                    = SFSDMNAME                           ; SFSDMNAME
+    _SFSDMSTR                     = SFSDMSTR                            ; SFSDMSTR
+    _SFSDMVC                      = SFSDMVC                             ; SFSDMVC
+    _SFSDSCALE                    = SFSDSCALE                           ; SFSDSCALE
+    _SFSDTSTR                     = SFSDTSTR                            ; SFSDTSTR
+    _SFSELECT                     = SFSELECT                            ; SFSELECT
+    _SFSEXTF                      = SFSEXTF                             ; SFSEXTF
+    _SFSFILL                      = SFSFILL                             ; SFSFILL
+    _SFSFLMD                      = SFSFLMD                             ; SFSFLMD
+    _SFSNATT                      = SFSNATT                             ; SFSNATT
+    _SFSNBIT                      = SFSNBIT                             ; SFSNBIT
+    _SFSRANGE                     = SFSRANGE                            ; SFSRANGE
+    _SFSTART                      = SFSTART                             ; SFSTART
+    _SFWCCHNK                     = SFWCCHNK                            ; SFWCCHNK
+    _SFWCDATA                     = SFWCDATA                            ; SFWCDATA
+    _SFWCHNK                      = SFWCHNK                             ; SFWCHNK
+    _SFWDATA                      = SFWDATA                             ; SFWDATA
+    SFCHEMPTY                     = _SFCHEMPTY at 8                        
+    SFCREATE                      = _SFCREATE at 24                        
+    SFDIMID                       = _SFDIMID at 8                          
+    SFEND                         = _SFEND at 4                            
+    SFENDACC                      = _SFENDACC at 4                         
+    SFFATTR                       = _SFFATTR at 12                         
+    SFFINFO                       = _SFFINFO at 12                         
+    SFGAINFO                      = _SFGAINFO at 24                        
+    SFGCAL                        = _SFGCAL at 24                          
+    SFGCFILL                      = _SFGCFILL at 12                        
+    SFGDINFO                      = _SFGDINFO at 24                        
+    SFGDMSTR                      = _SFGDMSTR at 32                        
+    SFGDSCALE                     = _SFGDSCALE at 8                        
+    SFGDTSTR                      = _SFGDTSTR at 40                        
+    SFGFILL                       = _SFGFILL at 8                          
+    SFGICHNK                      = _SFGICHNK at 12                        
+    SFGINFO                       = _SFGINFO at 28                         
+    SFGRANGE                      = _SFGRANGE at 12                        
+    SFID2REF                      = _SFID2REF at 4                         
+    SFISCVAR                      = _SFISCVAR at 4                         
+    SFISDMVC                      = _SFISDMVC at 4                         
+    SFISRCRD                      = _SFISRCRD at 4                         
+    SFN2INDEX                     = _SFN2INDEX at 12                       
+    SFRATTR                       = _SFRATTR at 16                         
+    SFRCATT                       = _SFRCATT at 16                         
+    SFRCCHNK                      = _SFRCCHNK at 16                        
+    SFRCDATA                      = _SFRCDATA at 24                        
+    SFRCHNK                       = _SFRCHNK at 12                         
+    SFRDATA                       = _SFRDATA at 20                         
+    SFREF2INDEX                   = _SFREF2INDEX at 8                      
+    SFRNATT                       = _SFRNATT at 12                         
+    SFSACCT                       = _SFSACCT at 8                          
+    SFSATTR                       = _SFSATTR at 28                         
+    SFSBLSZ                       = _SFSBLSZ at 8                          
+    SFSCAL                        = _SFSCAL at 24                          
+    SFSCATT                       = _SFSCATT at 28                         
+    SFSCCHNK                      = _SFSCCHNK at 12                        
+    SFSCFILL                      = _SFSCFILL at 12                        
+    SFSCHNK                       = _SFSCHNK at 16                         
+    SFSCOMPRESS                   = _SFSCOMPRESS at 12                     
+    SFSDMNAME                     = _SFSDMNAME at 12                       
+    SFSDMSTR                      = _SFSDMSTR at 28                        
+    SFSDMVC                       = _SFSDMVC at 8                          
+    SFSDSCALE                     = _SFSDSCALE at 16                       
+    SFSDTSTR                      = _SFSDTSTR at 36                        
+    SFSELECT                      = _SFSELECT at 8                         
+    SFSEXTF                       = _SFSEXTF at 16                         
+    SFSFILL                       = _SFSFILL at 8                          
+    SFSFLMD                       = _SFSFLMD at 8                          
+    SFSNATT                       = _SFSNATT at 24                         
+    SFSNBIT                       = _SFSNBIT at 20                         
+    SFSRANGE                      = _SFSRANGE at 12                        
+    SFSTART                       = _SFSTART at 12                         
+    SFWCCHNK                      = _SFWCCHNK at 16                        
+    SFWCDATA                      = _SFWCDATA at 24                        
+    SFWCHNK                       = _SFWCHNK at 12                         
+    SFWDATA                       = _SFWDATA at 20                         
+    _ncabort                      = ncabort                             ; ncabort
+    _ncattcopy                    = ncattcopy                           ; ncattcopy
+    _ncattdel                     = ncattdel                            ; ncattdel
+    _ncattget                     = ncattget                            ; ncattget
+    _ncattinq                     = ncattinq                            ; ncattinq
+    _ncattname                    = ncattname                           ; ncattname
+    _ncattput                     = ncattput                            ; ncattput
+    _ncattrename                  = ncattrename                         ; ncattrename
+    _ncclose                      = ncclose                             ; ncclose
+    _nccreate                     = nccreate                            ; nccreate
+    _ncdimdef                     = ncdimdef                            ; ncdimdef
+    _ncdimid                      = ncdimid                             ; ncdimid
+    _ncdiminq                     = ncdiminq                            ; ncdiminq
+    _ncdimrename                  = ncdimrename                         ; ncdimrename
+    _ncendef                      = ncendef                             ; ncendef
+    _ncinquire                    = ncinquire                           ; ncinquire
+    _ncopen                       = ncopen                              ; ncopen
+    _ncopts                       = ncopts                              ; ncopts
+    _ncrecget                     = ncrecget                            ; ncrecget
+    _ncrecinq                     = ncrecinq                            ; ncrecinq
+    _ncrecput                     = ncrecput                            ; ncrecput
+    _ncredef                      = ncredef                             ; ncredef
+    _ncsetfill                    = ncsetfill                           ; ncsetfill
+    _ncsync                       = ncsync                              ; ncsync
+    _nctypelen                    = nctypelen                           ; nctypelen
+    _ncvardef                     = ncvardef                            ; ncvardef
+    _ncvarget                     = ncvarget                            ; ncvarget
+    _ncvarget1                    = ncvarget1                           ; ncvarget1
+    _ncvargetg                    = ncvargetg                           ; ncvargetg
+    _ncvargets                    = ncvargets                           ; ncvargets
+    _ncvarid                      = ncvarid                             ; ncvarid
+    _ncvarinq                     = ncvarinq                            ; ncvarinq
+    _ncvarput                     = ncvarput                            ; ncvarput
+    _ncvarput1                    = ncvarput1                           ; ncvarput1
+    _ncvarputg                    = ncvarputg                           ; ncvarputg
+    _ncvarputs                    = ncvarputs                           ; ncvarputs
+    _ncvarrename                  = ncvarrename                         ; ncvarrename
diff --git a/bindings/java/bin/win32/hm413m.dll b/bindings/java/bin/win32/hm413m.dll
new file mode 100644
index 0000000..174d739
Binary files /dev/null and b/bindings/java/bin/win32/hm413m.dll differ
diff --git a/bindings/java/bin/win32/hm413m.lib b/bindings/java/bin/win32/hm413m.lib
new file mode 100644
index 0000000..9344f8a
Binary files /dev/null and b/bindings/java/bin/win32/hm413m.lib differ
diff --git a/bindings/java/bin/win32/hm415m.dll b/bindings/java/bin/win32/hm415m.dll
new file mode 100755
index 0000000..0445bf7
Binary files /dev/null and b/bindings/java/bin/win32/hm415m.dll differ
diff --git a/bindings/java/bin/win32/szlibdll.dll b/bindings/java/bin/win32/szlibdll.dll
new file mode 100755
index 0000000..ebb39ff
Binary files /dev/null and b/bindings/java/bin/win32/szlibdll.dll differ
diff --git a/bindings/java/bin/win32/zlib.dll b/bindings/java/bin/win32/zlib.dll
new file mode 100755
index 0000000..b27eaf4
Binary files /dev/null and b/bindings/java/bin/win32/zlib.dll differ
diff --git a/bindings/java/compilejava.bat b/bindings/java/compilejava.bat
new file mode 100644
index 0000000..01bab9f
--- /dev/null
+++ b/bindings/java/compilejava.bat
@@ -0,0 +1,6 @@
+ at echo off
+REM Compile java files under Win32
+REM
+javac -g ncsa/hdf/hdflib/*.java
+javac -g neutron/nexus/*.java
+jar -cvf jnexus.jar ncsa/hdf/hdflib/*.class neutron/nexus/*.class
diff --git a/bindings/java/ignore-index.html b/bindings/java/ignore-index.html
new file mode 100644
index 0000000..b2987ce
--- /dev/null
+++ b/bindings/java/ignore-index.html
@@ -0,0 +1,395 @@
+<HTML> 
+<HEAD>
+<TITLE>The NeXus API for Java</TITLE>
+</HEAD>
+<BODY bgcolor=#FFFFFF>
+<p align="center">
+<IMG src="NeXus.gif" WIDTH=597 HEIGHT=90>
+</p>
+<b>
+   Note: this document is out-of-date and no longer updated.
+   It may be deleted in the future without notice.
+   Refer to the NeXus User Manual and Reference Documentation
+   for the most recent documentation.
+   See <a href="http://trac.nexusformat.org/code/ticket/279">TRAC ticket 279</a>
+   for discussion of this change.
+</b>
+
+<H1>The NeXus API for Java</H1>
+<P>
+<h2>Contents</h2>
+<ul>
+<li>Introduction
+<li><a href="#ack">Acknowledgement</a>
+<li><a href="#install">Installation</a>
+<li><a href="#run">Running Programs</a> with the  NeXus API for Java.
+<li><a href="jnexustut.html">NeXus for Java Programming Tutorial</a>
+<li><a href="#prog">Programming</a> with the NeXus API for Java (for
+ experienced NeXus API Programmers).  
+<li><a href="#lim">Known Limitations</a>.
+<li><a href="#comp">Compiling</a> the NeXus API for Java
+<li><a href="#sup">Support</a>
+</ul>
+</P>
+
+<h2>Introduction</h2>
+<p>
+<a href="http://lns00.psi.ch/Nexus">NeXus</a> is a proposal for a
+common file format for neutron and X-ray scattering. NeXus uses <a 
+ href="http://hdf.ncsa.uiuc.edu/">HDF</a> as its physical file format.
+Since October 2000 a Java NeXus API has been available which supports
+HDF version 4. Since then, the HDF team at NCSA has released a new
+incompatible version of HDF, HDF version 5. This now is version 2 of
+the Java NeXus API which supports both HDF versions.
+As recoding the HDF library in Java was no option the Java
+ API for NeXus (jnexus) was implemented through the Java Native
+ Methods Interface (JNI). This has the consequence that the Java API
+ for NeXus cannot be used in applets as the security restrictions for
+ applets prohibit downloading of shared libraries   and local file
+ access. Applets can use a NeXus Data Server in order to access NeXus
+ files in readonly mode.  
+</p>
+
+<h2><a name="ack">Acknowledgement</a></h2>
+<p>
+This implementation uses classes and native methods from NCSA's Java
+HDF Interface project. Basically all conversions from native types to
+Java types is done through code from the NCSA HDF group. Without this
+code the implementation of this API would have taken much longer. See <a 
+ href="COPYING.NCSA">NCSA's copyright</a> for more information.     
+</p>
+<h2><a name="install">Installation</a></h2>
+<h3>Requirements</h3>
+<p>
+For the binary distribution only a JDK1.1 compatible Java runtime is
+required. Suitable runtime environments for Solaris, Linux and
+Windows32 can be downloaded from <a
+href="http://www.javasoft.com">Sun's Java</a> homepage. This website
+also holds pointers to Java runtime systems for other
+platforms. 
+
+</p>
+<p>
+In order to compile the Java API for NeXus the following components
+are required:
+<ul>
+<li>A Java Development Kit 1.1 or better. For downloads see above.
+<li>A C compiler for your platform.
+<li>The HDF libraries version 4.1r3 or better and the HDF-5 libraries,
+newest version available. Both can be downloaded from <a
+href="http://hdf.ncsa.uiuc.edu/">NCSA's HDF</a> homepage.
+<li>A complete copy of the latest 
+ <a href="http://sutekh.nd.rl.ac.uk/NAPI"> NAPI sources</a> (including jnexus
+sources).
+</ul>
+</p>
+<h3>Installation under Windows32 (Windows NT, Windows 95, 98, ME)</h3>
+<p>
+<ol>
+<li>Copy the HDF DLL's (*413m.dll) and the file jnexus.dll to a
+directory in your path. For instance C:\Windows\system32. 
+<li>Copy the jnexus.jar to the place where you usually keep library
+jar files. 
+</ol>
+</p>
+<h3>Installation under Unix</h3>
+<p>
+Two files are needed: the jnexus.so shared library and the jnexus.jar
+file holding the required Java class. Copy them wherever you like and
+see below for instructions how to run programs using jnexus.
+</p>
+
+<h2><a name="#run">Running Programs with the NeXus API for Java</a></h2>
+<p>
+In order to successfully run a program with jnexus the Java runtime
+systems needs to locate two items:
+<ul>
+<li>The shared library implementing the native methods.
+<li>The nexus.jar file in order to find the Java classes.
+</ul> 
+</p>
+<h3>Locating the shared library</h3>
+<p>
+Of course the method for locating a shared library differ between
+systems. Under Windows32 systems the best method is to copy the
+jnexus.dll and the HDF-libarary DLL's into a directory in your
+path. The HDF DLL's have to go there anyway.
+</p>
+<p>
+On a unix system the problem can be solved in three different ways:
+<ul>
+<li>Make your system administrator copy the jnexus.so file into the
+systems default shared library directory (usually /usr/sbin).
+<li>Put the jnexus.so file wherever you see fit and set the
+LD_LIBRARY_PATH environment variable to point to the directory of your 
+choice.
+<li>Specify the full pathname of the jnexus shared library on the
+java command line with the
+-Dorg.nexusformat.JNEXUSLIB=full-path-2-shared-library option. 
+</ul>
+</p>
+<h3>Locating jnexus.jar</h3>
+<p>
+This is easier: just add the the full pathname to jnexus.jar to the
+classpath when starting java. 
+</p>
+<h3>Examples</h3>
+<p>
+A unix example shell script:
+<pre>
+#!/sbin/sh
+java -classpath /usr/lib/classes.zip:../jnexus.jar:. \
+ -Dorg.nexusformat.JNEXUSLIB=../bin/du40/libjnexus.so TestJapi
+ </pre>
+A Windows 32 example batch file:
+<pre>
+set JL=-Dorg.nexusformat.JNEXUSLIB=..\jnexus\bin\win32\jnexus.dll
+java -classpath C:\jdk1.1.5\lib\classes.zip;..\jnexus.jar;. %JL% TestJapi
+</pre>
+</p>
+
+<h2><a name="prog">Programming</a> with the NeXus API for Java.</h2>
+<p>
+The NeXus C-API is good enough but for Java a few adaptions of the API
+have been made in order to match the API better to the idioms used by
+Java programmers. In order to understand the Java -API it is useful to
+study the NeXus C-API because many methods work in the same way as
+their C equivalents. A full API documentation is available in Java
+documentation format. For full reference look especially at:
+<ul>
+<li>The interface <a
+href="apidoc/org.nexusformat.NeXusFileInterface.html">NeXusFileInterface
+</a> first. It gives an uncluttered view of the API.
+<li>The implementation <a
+href="apidoc/org.nexusformat.NexusFile.html">NexusFile</a> which gives more
+details about constructors and constants. However this documentation
+is interspersed with information about native methods which should not
+be called by an application programmer as they are not part of the
+standard and might change in future. 
+</ul> 
+Some more general explanation will be given below.
+</p>
+<h3>General Things</h3>
+<p>
+See the following code example for opening a file, opening a vGroup
+and closing the file again in order to get a feeling for the API.
+<pre>
+     try{
+           NexusFile nf = new NexusFile(filename,
+                    NexusFile.NXACC_READ);
+           nf.opengroup("entry1","NXentry");
+           nf.finalize();
+     }catch(NexusException ne) {
+         // oh shit! something was wrong!
+     }
+</pre>
+Some notes on this little example:
+<ul>
+<li>Each NeXus file is represented by a NexusFile object which is
+created through the constructor.
+<li>The NexusFile object takes care of all file handles for you. So
+there is no need to pass in a handle anymore to each method as in
+the C language API. 
+<li>All error handling is done through the Java exception handling
+mechanism. This saves all the code checking return values in the C
+language API. Most API functions return void. 
+<li>Closing files is tricky. The Java garbage collector is supposed to
+call the finalize method for each object it decides to delete. In
+order to enable this mechanism, the NXclose function was replaced by
+the finalize method. In practice it seems not to be guranteed that the 
+garbage collector calls the finalize method. It is safer to call
+finalize yourself in order to properly close a file. Multiple calls to
+the finalize method for the same object are safe and do no harm.  
+</ul>
+</p>
+<h3>Data Writing and Reading</h3>
+<p>
+Again a code sample which shows how this looks like:
+<pre>
+       int idata[][] = new idata[10][20];
+       int iDim[] = new int[2];
+
+        // put some data into iData.......
+
+        // write iData
+        iDim[0] = 10;
+        iDim[1] = 20;
+        nf.makedata("idata",NexusFile.NX_INT32,2,iDim);
+        nf.opendata("idata");
+	nf.putdata(idata);
+
+        // read idata
+        nf.getdata(idata);
+</pre>
+The dataset is created as usual with makedata and opened with
+putdata. The trick is in putdata. Java is meant to be type safe. One
+would think then that a putdata method would be required for each Java
+data type. In order to avoid this the data to write is passed into
+putdata as type Object. Then the API proceeds to analyze this object
+through the Java introspection API and convert the data to a byte
+stream for writing through the native method call. This is an elegant
+solution with one drawback: An array is needed at all times. Even if
+only a single data value is written (or read) an array of length one
+and an appropriate type is the required argument.    
+</p>
+<p>
+Another issue are strings. Strings are first class objects in
+Java. HDF (and NeXus) sees them as dumb arrays of bytes. Thus strings
+have to be converted to and from bytes when reading string data. See a
+writing example:
+<pre>
+        String ame = "Alle meine Entchen";
+	nf.makedata("string_data",NexusFile.NX_CHAR,1,
+                           ame.length()+2);
+        nf.opendata("string_data");
+        nf.putdata(ame.getBytes());
+</pre> 
+And reading:
+<pre>
+        byte bData[] = new byte[132];
+        nf.opendata("string_data");
+        nf.getdata(bData);
+        String string_data = new String(bData);
+</pre>
+The aforementioned holds for all strings written as SDS content or as
+an attribute. SDS or vGroup names do not need this treatment. 
+</p>
+<h3>Inquiry Routines</h3>
+<p>
+Let us compare the C-API and Java-API signatures of the getinfo
+routine or method:
+<pre>
+      /* C -API */
+      NXstatus NXgetinfo(NXhandle handle, int *rank, int iDim[], 
+                         int *datatype);
+      // Java 
+      void getinfo(int iDim[], int args[]);
+</pre>
+The problem is that Java passes arguments only by value, which means
+they cannot be modified by the method. Only array arguments can be
+modified. Thus args in the getinfo method holds the rank and datatype
+information passed in separate items in the C-API version. For
+resolving which one is which consult a debugger or the API-reference.  
+</p>
+<p>
+The attribute and vGroup search routines have been simplified using
+Hashtables. The Hastable returned by <b>groupdir()</b> holds the name
+of the item as a key and the classname or the string SDS as ths stored
+object for the key. Thus the code for a vGroup search looks like this:
+<pre>
+         nf.opengroup(group,nxclass);
+         h = nf.groupdir();
+         e = h.keys();
+         System.out.println("Found in vGroup entry:");
+         while(e.hasMoreElements())
+	 {
+            vname = (String)e.nextElement();
+            vclass = (String)h.get(vname);
+            System.out.println("     Item: " + vname + " class: " + vclass);
+         }
+</pre>
+For an attribute search both at global or SDS level the returned
+Hashtable will hold the name as the key and a little class holding the
+type and size information as value. Thus an attribute search looks
+like this in the Java-API:
+<pre>
+         Hashtable h = nf.attrdir();
+         Enumeration e = h.keys();
+         while(e.hasMoreElements())
+	 {
+           attname = (String)e.nextElement();
+           atten = (AttributeEntry)h.get(attname);
+           System.out.println("Found global attribute: " + attname +
+             " type: "+ atten.type + " ,length: " + atten.length); 
+         }
+</pre>   
+</p>
+<p>
+For more information about the usage of the API routines see the
+reference or the NeXus C-API reference pages. Another good source of
+information is the source code of the  <a href="test/TestJapi.java">test
+program </a> which exercises each API routine. 
+</p>
+
+<h2><a name="lim">Limitations</a></h2>
+<p>
+These are a couple of known problems which you might run into:
+<dl>
+<DT>Memory
+<DD>As the Java API for NeXus has to convert between native and Java
+number types a copy of the data must be made in the process. This
+means that if you want to read or write 20MB of data your memory requirement
+will be 40MB! This can be reduced by using getslab/putslab for data
+transfers. 
+<DT>Java.lang.OutOfMemoryException
+<DD>By default the Java runtime has a ceiling of 16MB of memory
+use. This ceiling can be increased through the -mxXXm option to the
+Java runtime. An example: java -mx32m ..... starts the Java runtime
+with a memory ceiling of 32MB.
+<dT>Trouble with compressed dataset on True64Unix with jdk118
+<DD>True64Unix's JDK-1.1.8 from HP, Compaq, DEC or however the company
+is called these days is built with a version of zlib incompatible with
+the version used by the HDF libraries. This causes failures to write or read
+compressed datasets when classes are loaded from jar-files. They
+promised to fix this a long time ago but SIGHHHHHHH!  The newer
+JDK-1.3.1 does not exhibit this problem. 
+<DT>Maximum 8192 files open.
+<DD>The NeXus API for Java has a fixed buffer for file handles which
+allows only 8192 NeXus files to be open at the same time.  If you ever
+hit this limit, increase the MAXHANDLE define in native/handle.h and
+recompile everything. 
+</dl>
+</p>
+<h2><a name="comp">Compiling</a> the Java API for NeXus</h2> 
+<p>
+You will need <li>a complete copy of the latest 
+ <a href="http://sutekh.nd.rl.ac.uk/NAPI"> NAPI sources</a> (including jnexus
+sources). See other <a href="#install">requirements</a> under
+ installation above. 
+</p>
+<p>
+For Windows32 the free <a href="http://www.borland.com/jbuilder">Borland bcc55
+</a> command line compiler is used. Just run make -fmake.win32 and
+everything will be built. If not, adapt the directory settings in the
+make.win32 file to match your systems configuration. A hint: The import
+libraries for bcc where created from the HDF DLL's with the impdef, implib
+utilities using the -a option. There was a problem with dplicate symbols for
+Hopen, Hclose. This was solved by removing the HOPEN, HCLOSE entries in the
+definition file. This is case sensitivity problem.
+</p>
+<p>
+For DigitalUnix4.0D and Redhat Linux 6.2 Makefiles are provided
+(Makefile and Make.tux repectively). For these systems everything can
+be build with make du40 of make -f make.tux respectively.  
+If the Makefiles do not work edit the
+directory paths in the configuration section to match your
+installation. If you wish to compile on another unix system, create a
+copy of one of the above mentioned Makefiles and edit the
+configuration section in your copy to match your installation of java
+and the HDF libraries. If you succeed in building the NeXus API for
+Java on a new system, please put back modified sources into the CVS
+repository and make your Makefile and the compiled shared library
+available to the NAPI team in order to provide a new binary
+distribution.    
+</p>
+<h2><a name="sup">Support</a></h2>
+<p>
+I'am sure this software contains swarms of bugs. If you manage to find
+one you may send requests either to the <a
+href="mailto:napi at isis.rl.ac.uk">NAPI developer mailing list </a> or
+to <a href="mailto:Mark.Koennecke at psi.ch">Mark Könnecke</a> who
+ wrote the Java API for NeXus.    
+</p>
+<hr>
+<p>
+Author:<br>
+Mark Könnecke<br>
+Laboratory for Neutron Scattering<br>
+Paul Scherrer Institut<br>
+CH-5232-Villigen-PSI<br>
+Switzerland<br>
+and the NeXus Design team.<br>
+Last Update: November, 22, 2002
+<p>
+</BODY>
+</HTML>
diff --git a/bindings/java/japinotes.html b/bindings/java/japinotes.html
new file mode 100644
index 0000000..e1ab096
--- /dev/null
+++ b/bindings/java/japinotes.html
@@ -0,0 +1,388 @@
+<HTML>
+<HEAD>
+<TITLE>The NeXus API for Java</TITLE>
+</HEAD>
+<BODY bgcolor=#FFFFFF>
+<p align="center">
+<IMG src="NeXus.gif" WIDTH=597 HEIGHT=90>
+</p>
+<H1>The NeXus API for Java</H1>
+<P>
+<h2>Contents</h2>
+<ul>
+<li>Introduction
+<li><a href="#ack">Acknowledgement</a>
+<li><a href="#install">Installation</a>
+<li><a href="#run">Running Programs</a> with the  NeXus API for Java.
+<li><a href="jnexustut.html">NeXus for Java Programming Tutorial</a>
+<li><a href="#prog">Programming</a> with the NeXus API for Java (for
+ experienced NeXus API Programmers).  
+<li><a href="#lim">Known Limitations</a>.
+<li><a href="#comp">Compiling</a> the NeXus API for Java
+<li><a href="#sup">Support</a>
+</ul>
+</P>
+
+<h2>Introduction</h2>
+<p>
+<a href="http://lns00.psi.ch/Nexus">NeXus</a> is a proposal for a
+common file format for neutron and X-ray scattering. NeXus uses <a 
+ href="http://hdf.ncsa.uiuc.edu/">HDF</a> as its physical file format.
+Since October 2000 a Java NeXus API has been available which supports
+HDF version 4. Since then, the HDF team at NCSA has released a new
+incompatible version of HDF, HDF version 5. This now is version 2 of
+the Java NeXus API which supports both HDF versions.
+As recoding the HDF library in Java was no option the Java
+ API for NeXus (jnexus) was implemented through the Java Native
+ Methods Interface (JNI). This has the consequence that the Java API
+ for NeXus cannot be used in applets as the security restrictions for
+ applets prohibit downloading of shared libraries   and local file
+ access. Applets can use a NeXus Data Server in order to access NeXus
+ files in readonly mode.  
+</p>
+
+<h2><a name="ack">Acknowledgement</a></h2>
+<p>
+This implementation uses classes and native methods from NCSA's Java
+HDF Interface project. Basically all conversions from native types to
+Java types is done through code from the NCSA HDF group. Without this
+code the implementation of this API would have taken much longer. See <a 
+ href="COPYING.NCSA">NCSA's copyright</a> for more information.     
+</p>
+<h2><a name="install">Installation</a></h2>
+<h3>Requirements</h3>
+<p>
+For the binary distribution only a JDK1.1 compatible Java runtime is
+required. Suitable runtime environments for Solaris, Linux and
+Windows32 can be downloaded from <a
+href="http://www.javasoft.com">Sun's Java</a> homepage. This website
+also holds pointers to Java runtime systems for other
+platforms. Jnexus has not been tested with Java 2 but should work with
+it.  
+</p>
+<p>
+In order to compile the Java API for NeXus the following components
+are required:
+<ul>
+<li>A Java Development Kit 1.1 or better. For downloads see above.
+<li>A C compiler for your platform.
+<li>The HDF libraries version 4.1r3 or better and the HDF-5 libraries,
+newest version . Can be downloaded from <a
+href="http://hdf.ncsa.uiuc.edu/">NCSA's HDF</a> homepage.
+<li>A complete copy of the latest 
+ <a href="http://sutekh.nd.rl.ac.uk/NAPI"> NAPI sources</a> (including jnexus
+sources).
+</ul>
+</p>
+<h3>Installation under Windows32 (Windows NT, Windows 95, 98, ME)</h3>
+<p>
+<ol>
+<li>Copy the HDF DLL's (*413m.dll) and the file jnexus.dll to a
+directory in your path. For instance C:\Windows\system32. 
+<li>Copy the jnexus.jar to the place where you usually keep library
+jar files. 
+</ol>
+</p>
+<h3>Installation under Unix</h3>
+<p>
+Two files are needed: the jnexus.so shared library and the jnexus.jar
+file holding the required Java class. Copy them wherever you like and
+see below for instructions how to run programs using jnexus.
+</p>
+
+<h2><a name="#run">Running Programs with the NeXus API for Java</a></h2>
+<p>
+In order to successfully run a program with jnexus the Java runtime
+systems needs to locate two items:
+<ul>
+<li>The shared library implementing the native methods.
+<li>The nexus.jar file in order to find the Java classes.
+</ul> 
+</p>
+<h3>Locating the shared library</h3>
+<p>
+Of course the method for locating a shared library differ between
+systems. Under Windows32 systems the best method is to copy the
+jnexus.dll and the HDF-libarary DLL's into a directory in your
+path. The HDF DLL's have to go there anyway.
+</p>
+<p>
+On a unix system the problem can be solved in three different ways:
+<ul>
+<li>Make your system administrator copy the jnexus.so file into the
+systems default shared library directory (usually /usr/sbin).
+<li>Put the jnexus.so file wherever you see fit and set the
+LD_LIBRARY_PATH environment variable to point to the directory of your 
+choice.
+<li>Specify the full pathname of the jnexus shared library on the
+java command line with the
+-Dorg.nexusformat.JNEXUSLIB=full-path-2-shared-library option. 
+</ul>
+</p>
+<h3>Locating jnexus.jar</h3>
+<p>
+This is easier: just add the the full pathname to jnexus.jar to the
+classpath when starting java. 
+</p>
+<h3>Examples</h3>
+<p>
+A unix example shell script:
+<pre>
+#!/sbin/sh
+java -classpath /usr/lib/classes.zip:../jnexus.jar:. \
+ -Dorg.nexusformat.JNEXUSLIB=../bin/du40/libjnexus.so TestJapi
+ </pre>
+A Windows 32 example batch file:
+<pre>
+set JL=-Dorg.nexusformat.JNEXUSLIB=..\jnexus\bin\win32\jnexus.dll
+java -classpath C:\jdk1.1.5\lib\classes.zip;..\jnexus.jar;. %JL% TestJapi
+</pre>
+</p>
+
+<h2><a name="prog">Programming</a> with the NeXus API for Java.</h2>
+<p>
+The NeXus C-API is good enough but for Java a few adaptions of the API
+have been made in order to match the API better to the idioms used by
+Java programmers. In order to understand the Java -API it is useful to
+study the NeXus C-API because many methods work in the same way as
+their C equivalents. A full API documentation is available in Java
+documentation format. For full reference look especially at:
+<ul>
+<li>The interface <a
+href="apidoc/org.nexusformat.NeXusFileInterface.html">NeXusFileInterface
+</a> first. It gives an uncluttered view of the API.
+<li>The implementation <a
+href="apidoc/org.nexusformat.NexusFile.html">NexusFile</a> which gives more
+details about constructors and constants. However this documentation
+is interspersed with information about native methods which should not
+be called by an application programmer as they are not part of the
+standard and might change in future. 
+</ul> 
+Some more general explanation will be given below.
+</p>
+<h3>General Things</h3>
+<p>
+See the following code example for opening a file, opening a vGroup
+and closing the file again in order to get a feeling for the API.
+<pre>
+     try{
+           NexusFile nf = new NexusFile(filename,
+                    NexusFile.NXACC_READ);
+           nf.opengroup("entry1","NXentry");
+           nf.finalize();
+     }catch(NexusException ne) {
+         // oh shit! something was wrong!
+     }
+</pre>
+Some notes on this little example:
+<ul>
+<li>Each NeXus file is represented by a NexusFile object which is
+created through the constructor.
+<li>The NexusFile object takes care of all file handles for you. So
+there is no need to pass in a handle anymore to each method as in
+the C language API. 
+<li>All error handling is done through the Java exception handling
+mechanism. This saves all the code checking return values in the C
+language API. Most API functions return void. 
+<li>Closing files is tricky. The Java garbage collector is supposed to
+call the finalize method for each object it decides to delete. In
+order to enable this mechanism, the NXclose function was replaced by
+the finalize method. In practice it seems not to be guranteed that the 
+garbage collector calls the finalize method. It is safer to call
+finalize yourself in order to properly close a file. Multiple calls to
+the finalize method for the same object are safe and do no harm.  
+</ul>
+</p>
+<h3>Data Writing and Reading</h3>
+<p>
+Again a code sample which shows how this looks like:
+<pre>
+       int idata[][] = new idata[10][20];
+       int iDim[] = new int[2];
+
+        // put some data into iData.......
+
+        // write iData
+        iDim[0] = 10;
+        iDim[1] = 20;
+        nf.makedata("idata",NexusFile.NX_INT32,2,iDim);
+        nf.opendata("idata");
+	nf.putdata(idata);
+
+        // read idata
+        nf.getdata(idata);
+</pre>
+The dataset is created as usual with makedata and opened with
+putdata. The trick is in putdata. Java is meant to be type safe. One
+would think then that a putdata method would be required for each Java
+data type. In order to avoid this the data to write is passed into
+putdata as type Object. Then the API proceeds to analyze this object
+through the Java introspection API and convert the data to a byte
+stream for writing through the native method call. This is an elegant
+solution with one drawback: An array is needed at all times. Even if
+only a single data value is written (or read) an array of length one
+and an appropriate type is the required argument.    
+</p>
+<p>
+Another issue are strings. Strings are first class objects in
+Java. HDF (and NeXus) sees them as dumb arrays of bytes. Thus strings
+have to be converted to and from bytes when reading string data. See a
+writing example:
+<pre>
+        String ame = "Alle meine Entchen";
+	nf.makedata("string_data",NexusFile.NX_CHAR,1,
+                           ame.length()+2);
+        nf.opendata("string_data");
+        nf.putdata(ame.getBytes());
+</pre> 
+And reading:
+<pre>
+        byte bData[] = new byte[132];
+        nf.opendata("string_data");
+        nf.getdata(bData);
+        String string_data = new String(bData);
+</pre>
+The aforementioned holds for all strings written as SDS content or as
+an attribute. SDS or vGroup names do not need this treatment. 
+</p>
+<h3>Inquiry Routines</h3>
+<p>
+Let us compare the C-API and Java-API signatures of the getinfo
+routine or method:
+<pre>
+      /* C -API */
+      NXstatus NXgetinfo(NXhandle handle, int *rank, int iDim[], 
+                         int *datatype);
+      // Java 
+      void getinfo(int iDim[], int args[]);
+</pre>
+The problem is that Java passes arguments only by value, which means
+they cannot be modified by the method. Only array arguments can be
+modified. Thus args in the getinfo method holds the rank and datatype
+information passed in separate items in the C-API version. For
+resolving which one is which consult a debugger or the API-reference.  
+</p>
+<p>
+The attribute and vGroup search routines have been simplified using
+Hashtables. The Hastable returned by <b>groupdir()</b> holds the name
+of the item as a key and the classname or the string SDS as ths stored
+object for the key. Thus the code for a vGroup search looks like this:
+<pre>
+         nf.opengroup(group,nxclass);
+         h = nf.groupdir();
+         e = h.keys();
+         System.out.println("Found in vGroup entry:");
+         while(e.hasMoreElements())
+	 {
+            vname = (String)e.nextElement();
+            vclass = (String)h.get(vname);
+            System.out.println("     Item: " + vname + " class: " + vclass);
+         }
+</pre>
+For an attribute search both at global or SDS level the returned
+Hashtable will hold the name as the key and a little class holding the
+type and size information as value. Thus an attribute search looks
+like this in the Java-API:
+<pre>
+         Hashtable h = nf.attrdir();
+         Enumeration e = h.keys();
+         while(e.hasMoreElements())
+	 {
+           attname = (String)e.nextElement();
+           atten = (AttributeEntry)h.get(attname);
+           System.out.println("Found global attribute: " + attname +
+             " type: "+ atten.type + " ,length: " + atten.length); 
+         }
+</pre>   
+</p>
+<p>
+For more information about the usage of the API routines see the
+reference or the NeXus C-API reference pages. Another good source of
+information is the source code of the  <a href="test/TestJapi.java">test
+program </a> which exercises each API routine. 
+</p>
+
+<h2><a name="lim">Limitations</a></h2>
+<p>
+These are a couple of known problems which you might run into:
+<dl>
+<DT>Memory
+<DD>As the Java API for NeXus has to convert between native and Java
+number types a copy of the data must be made in the process. This
+means that if you want to read or write 20MB of data your memory requirement
+will be 40MB! This can be reduced by using getslab/putslab for data
+transfers. 
+<DT>Java.lang.OutOfMemoryException
+<DD>By default the Java runtime has a ceiling of 16MB of memory
+use. This ceiling can be increased through the -mxXXm option to the
+Java runtime. An example: java -mx32m ..... starts the Java runtime
+with a memory ceiling of 32MB.
+<dT>Trouble with compressed dataset on True64Unix with jdk118
+<DD>True64Unix's JDK-1.1.8 from HP, Compaq, DEC or however the company
+is called these days is built with a version of zlib incompatible with
+the version used by the HDF libraries. This causes failures to write or read
+compressed datasets when classes are loaded from jar-files. They
+promised to fix this a long time ago but SIGHHHHHHH!  The newer
+JDK-1.3.1 does not exhibit this problem. 
+<DT>Maximum 8192 files open.
+<DD>The NeXus API for Java has a fixed buffer for file handles which
+allows only 8192 NeXus files to be open at the same time.  If you ever
+hit this limit, increase the MAXHANDLE define in native/handle.h and
+recompile everything. 
+</dl>
+</p>
+<h2><a name="comp">Compiling</a> the Java API for NeXus</h2> 
+<p>
+You will need <li>a complete copy of the latest 
+ <a href="http://sutekh.nd.rl.ac.uk/NAPI"> NAPI sources</a> (including jnexus
+sources). See other <a href="#install">requirements</a> under
+ installation above. 
+</p>
+<p>
+For Windows32 a Microsoft Visual C++ 6.0 project file is supplied in
+the jnexus/jnexus directory. Use this project file. You will need to
+adapt the directory settings under Tools/Options/Directories for both
+include and library directories  in order to reflect the placement of
+the HDF libraries and the jnexus source code in your directory
+hierarchy. Hitting F7 after that should build the shared
+library. Hint: Only a release build is possible with the HDF library
+binaries. If a debug build is needed you have to recompile the HDF
+libraries yourself. For a recompilation of the Java classes use the
+compilejava batch file in the jnexus main directory.
+</p>
+<p>
+For DigitalUnix4.0D and Redhat Linux 6.2 Makefiles are provided
+(Makefile and Make.tux repectively). For these systems everything can
+be build with make du40 of make -f make.tux respectively.  
+If the Makefiles do not work edit the
+directory paths in the configuration section to match your
+installation. If you wish to compile on another unix system, create a
+copy of one of the above mentioned Makefiles and edit the
+configuration section in your copy to match your installation of java
+and the HDF libraries. If you succeed in building the NeXus API for
+Java on a new system, please put back modified sources into the CVS
+repository and make your Makefile and the compiled shared library
+available to the NAPI team in order to provide a new binary
+distribution.    
+</p>
+<h2><a name="sup">Support</a></h2>
+<p>
+I'am sure this software contains swarms of bugs. If you manage to find
+one you may send requests either to the <a
+href="mailto:napi at isis.rl.ac.uk">NAPI developer mailing list </a> or
+to <a href="mailto:Mark.Koennecke at psi.ch">Mark Könnecke</a> who
+ wrote the Java API for NeXus.    
+</p>
+<hr>
+<p>
+Author:<br>
+Mark Könnecke<br>
+Laboratory for Neutron Scattering<br>
+Paul Scherrer Institut<br>
+CH-5232-Villigen-PSI<br>
+Switzerland<br>
+and the NeXus Design team.<br>
+Last Update: November, 22, 2002
+<p>
+</BODY>
+</HTML>
diff --git a/bindings/java/jnexustut.html b/bindings/java/jnexustut.html
new file mode 100644
index 0000000..ec2a65f
--- /dev/null
+++ b/bindings/java/jnexustut.html
@@ -0,0 +1,329 @@
+<HTML>
+<HEAD>
+<TITLE>The NeXus for Java API Tutorial</TITLE>
+</HEAD>
+<BODY bgcolor=#FFFFFF>
+<p align="center">
+<IMG src="NeXus.gif" WIDTH=597 HEIGHT=90>
+</p>
+<H1>The NeXus for Java API Tutorial</H1>
+<P>
+This document explains in more detail how to program with the NeXus
+API for Java. The intended audience are Java programmers who do not
+know the C language NeXus API. This document will only explain how to
+deal with NeXus files. For a general description of NeXus see the <a
+href="http://lns00.psi.ch/nexus">NeXus WWW-pages</a>.  For
+reference,see the <a href="apidoc/Package-org.nexusformat.html">jnexus API
+documentation</a>. Another good source of information is the <a
+href="test/TestJapi.java">test driver source code</a> for the NeXus
+API for Java. It is a more involved example of API usage. And it is
+documented! 
+</P>
+<p>
+Before doing anything with the NeXus for Java API the necessary
+classes need to be imported. This is done with the statement:
+<center>import org.nexusformat.*;</center>
+at the head of your Java file.
+A NeXus programmer has to deal with the following five concepts:
+<dl>
+<dt><a href="#fil">NeXus Files</a>
+<dd>You should have guessed as much.
+<dt><a href="#group">Groups</a>
+<dd>Groups are NeXus means of structuring data in a file. Groups can
+hold other groups or datsets. The filesystem analogon to groups would be
+directories. 
+<dt><a href="#sds">SDS</a>
+<dd>SDS are scientific datasets. This is a n-dimensional array of
+numbers stored in the file. 
+<dt><a href="#att">Attributes</a>
+<DD>Attributes is auxiliary information stored in the file. Two types
+of attributes are possible: global file wide attributes and attributes
+linked to a SDS.
+<dt><a href="#link">Links</a>
+<dd>For organisational reasons it might be useful  to refer a SDS in more
+then one group. But it should be avoided to duplicate data. In order
+to avoid this it is possible to link SDS wherever you want. This
+concept is quite similar to a symbolic link in a unix file system. 
+</dl>
+All these concepts will be explained in more detail below. A note
+about error handling: A NexusException is thrown whenever an error
+occurs. This implies that all code samples stated below should be
+included in a try-catch block looking like this:
+<pre>
+    try{
+      // some NeXus for Java calls.
+    }catch(NexusException ne) {
+       // analyze and treat the error
+    }
+</pre>
+For brevity and clarity this will be left out in the following text.
+</p>
+<h2><a name=fil>NeXus Files</a></h2>
+<p>
+A Nexus File is opened by:
+<center>NexusFile nf = new NexusFile(name,
+NexusFile.NXACC_CREATE);</center>
+The first parameter to the constructor is of course the name. The
+second parameter is the access code valid for the file: Three access
+codes are supported:<dl>
+<dt>NXACC_CREATE, NXACC_CREATE4
+<dd>For creating a new NeXus file as HDF-4 file.
+<dt>NXACC_CREATE%
+<dd>For creating a new NeXus file as HDF-5 file.
+<dt>NXACC_RDWR
+<dd>For opening an existing NeXus file for modification or for
+appending.
+<dt>NXACC_READ
+<dd>Open a file for reading only.
+</dl>
+Please note that for all further examples, the name nf is assumed for
+the NexusFile object.
+</p>
+<p>
+Closing files is accomplished through the finalize method. This should
+be called automatically by the Java garbage collector but it is safer
+to explicitly call this method when done with a file.
+<center>nf.finalize()</center>
+does the trick.
+</p>
+<p>
+Sometimes it is necessary to flush all buffered data to disk before
+doing for instance something else in a program in order to prevent
+data loss. This can be done with the flush method:
+<center>nf.flush();</center> 
+flush has the side effect of closing all open SDS.
+</p>
+<h2><a name="group">Groups</a></h2>
+<p>
+A group (or vGroup) is the NeXus equivalent of a directory. Alike to a
+directory hierarchy, a hierarchy of groups can be built in a NeXus file. In
+contrast to directory names however, NeXus group names consist of two
+strings: the groupname and the groupclass. Both strings are needed in
+order to address a NeXus group. There are API functions for all
+necessary operations on groups. The first one is group creation:
+<center>nf.makegroup(name, nxclass);</center>
+This corresponds to a mkdir in a unix filesystem.
+</p>
+<p>
+In order to use a group we need a means of traversing the group
+hierarchy. For this the methods:
+<center>nf.opengroup(name,nxclass);</center> and
+<center>nf.closegroup();</center> are provided. 
+opengroup corresponds to a cd name,class and steps into the group name
+with class nxclass. closegroup corresponds to cd .. and steps one
+group lower in the group hierarchy. 
+</p>
+<p>
+NeXus is self describing. Clearly a method is needed to find out about
+the contents of the current group. For this the method:
+<center>Hashtable ha = nf.groupdir();</center>
+is used. The hashtable returned contains pairs of name, class as
+entries. For datasets the class name is set to SDS. See the following
+code snippet as an example how to print the contents of a NeXus group:
+<pre>
+         Hashtable h = nf.groupdir();
+         e = h.keys();
+         System.out.println("Found in Group");
+         while(e.hasMoreElements())
+	 {
+            vname = (String)e.nextElement();
+            vclass = (String)h.get(vname);
+            System.out.println("     Item: " + vname + " class: " + vclass);
+         }
+</pre>
+</p>
+<h2><a name="sds">SDS</a></h2>
+SDS are scientific dataset. They are used to store n-dimensional
+arrays of data in a variety of number types in a NeXus file. The
+following number types are allowed in NeXus files:
+<pre>
+	NexusFile.NX_INT8:
+	NexusFile.NX_UINT8:
+        NexusFile.NX_CHAR:
+	NexusFile.NX_INT16:
+	NexusFile.NX_UINT16:
+	NexusFile.NX_INT32:
+	NexusFile.NX_UINT32:
+	NexusFile.NX_FLOAT32:
+	NexusFile.NX_FLOAT64:
+</pre>
+I think the names are self describing. 
+These types are defined as constants in NexusFile.java.
+<p>
+When creating a new file a means is needed for creating a new SDS in
+the NeXus file. A SDS is fully characterized by its name,  its number
+type (out of the list above), the number of dimensions it has (its
+rank) and its size in each dimension. With this information a SDS can
+be created:
+<center>nf.makedata(name,type,rank,iDim);</center>with iDim being an
+integer array holding the size of the dataset in each dimension. A
+speciality of NeXus (and HDF) is that the first dimension can be
+unlimited. Simpy set the dimension 0. Then data can be appended in
+consecutive steps along this dimension. Please note, that makedata
+does not automatically open the SDS. Before writing data to it, a call
+to opendata is required.  
+<p>
+Analog to a file in a filesystem a SDS must be opened before anything
+can be done with it and closed when processing is finished. The
+appropriate calls are:
+<center>nf.opendata(name);</center> and <center>nf.closedata();</center>
+ Please
+note that all methods below this section require an openend SDS for
+proper operation. 
+<p>
+Once a SDS is open data can be read or written to it. Two means of
+data transfer are provided: putdata, getdata write and read all the
+data in one go, whereas putslab, getslab allows to write and read
+subsets of data. There is a trick here though. Java is meant to be
+type safe.  One
+would think then that a data transfer method would be required for each Java
+data type. In order to avoid this the data to transfer is passed into
+the data transfer methods  as type Object. Then the API proceeds to 
+analyze this object
+through the Java introspection API and converts the data to a byte
+stream for writing through the native method call. This is an elegant
+solution with one drawback: An array is needed at all times. Even if
+only a single data value is written (or read) an array of length one
+and an appropriate type is the required argument.    
+<p>
+Writing and reading then looks like:
+<pre>
+      // example data
+      int iData[][] = new iData[3][10];
+      // write it
+      nf.putdata(iData);
+      // read it
+      nf.getdata(iData);
+</pre>
+<p>
+Another issue are strings. Strings are first class objects in
+Java. HDF (and NeXus) sees them as dumb arrays of bytes. Thus strings
+have to be converted to and from bytes when reading string data. See a
+writing example:
+<pre>
+        String ame = "Alle meine Entchen";
+	nf.makedata("string_data",NexusFile.NX_CHAR,1,
+                           ame.length()+2);
+        nf.opendata("string_data");
+        nf.putdata(ame.getBytes());
+</pre> 
+And reading:
+<pre>
+        byte bData[] = new byte[132];
+        nf.opendata("string_data");
+        nf.getdata(bData);
+        String string_data = new String(bData);
+</pre>
+The aforementioned holds for all strings written as SDS content or as
+an attribute. SDS or vGroup names do not need this treatment. 
+<p>
+When writing a subset of data two more arguments are needed: The first
+is an integer array of size rank which holds the address in the
+dataset where to start the transfer of the subset. The second is another
+integer array of size rank which determines the size of the data
+subset to transfer in each dimension. The methods then look like:
+<pre>
+      // example data
+      int iData[][] = new iData[3][10];
+      int iStart[2] = {0,0};
+      int iSize[2] = {3,10};
+      // write it
+      nf.putslab(iStart, iSize,iData);
+      // read it
+      nf.getdata(iStart, iSize,iData);
+</pre>
+This example is a bit contrieved in that it uses the subset API for
+transfering the whole dataset. 
+<p>
+NeXus and HDF support the compression and decompression of data on the
+fly during transfer operations. The only thing which needs to be done
+is to tell NeXus to compress the data before writing data. An example
+looks like this:
+<pre>
+      float fData[][] = new float[100][1000];
+      int iDim[] = new int[2];
+      iDim[0] = 100;
+      iDim[1] = 1000;
+
+       nf.compmakedata("fData",2,NexusFile.NX_FLOAT32,iDim,
+               NexusFile.COMP_CODE_LZW,iDim);
+       nf.opendata("fData");
+       nf.putdata(fData);
+</pre> 
+The additional parameters to NXcompmakedata are the compression type
+and a buffer  size for use used during compression. This is an integer
+array of the same rank as the data.  If the data set is written
+in one go this should be the dimensions of the dataset,
+when writing in slabs, the slab size. This is a performance feauture.
+
+Please note the sequence of calls. The parameter to compress is the
+compression algorithm to use. Permitted values are:
+<dl>
+<dt>NexusFile.NX_COMP_NONE
+<DD> No compression
+<dt>NexusFile.NX_COMP_RLE
+<DD> Run length encoding
+<dt>NexusFile.NX_COMP_LZW
+<DD> gzip type compression
+<dt>NexusFile.NX_COMP_HUF
+<DD> Huffman compression.
+</dl> 
+Please note that transfers to compressed datasets have to be done
+through the putdata, getdata routines, subset operations are not
+supported with compression. When using HDF-5 as underlying file format, only LZW compression is available.  
+<p>
+When dealing with an unknown NeXus file we might need to find out
+about the characteristics of a SDS. This can be done with:
+<center>nf.getinfo(iDim,args);</center>
+After this call iDim will hold the size of the SDS in each dimension,
+args[0] will be the rank of the SDS and args[1] the number type. Make
+sure that iDim is large enough to hold all dimensions. Hint: 32 is the
+maximum number of dimensions supported by HDF. 
+<p>
+<h2><a name="att">Attributes</a></h2>
+Attributes are auxiliary information stored in a NeXus file. There are
+two variants: global attributes at file level and attributes at SDS
+level. The attribute part of the API acts on global attributes if no
+SDS is open and on SDS attributes if an SDS has been opened with
+opendata(). Attributes can be written:
+<center>nf.putattr(name,data,type);</center>
+name is a name, data is a one dimensional array of some data and type
+is the of the data. The same data types as for SDS writing are
+supported.
+<p>
+Attributes can be read:
+<center>nf.getattr(name, data, args);</center>
+args[0] will hold the length of the attribute array, args[1] its type.
+This must be supplied as input. Proper values for these parameters can
+be inquired trough the attribute directory method:
+<center>Hashtable ha = nf.attrdir();</center>
+This time the hashtable ha will hold pairs of attribute names and
+AttributeEntry objects. These objects are small classes which hold the
+length and type of the attribute. See an attribute printing example
+for more information:
+<pre>
+         AttributeEntry atten;
+         String attname;
+
+         Hashtable h = nf.attrdir();
+         Enumeration e = h.keys();
+         while(e.hasMoreElements())
+	 {
+           attname = (String)e.nextElement();
+           atten = (AttributeEntry)h.get(attname);
+           System.out.println("Found global attribute: " + attname +
+             " type: "+ atten.type + " ,length: " + atten.length); 
+         }
+</pre>   
+<h2><a name="link">Linking</a></h2>
+Linking a SDS into more then one group requires some
+precautions. First some internal information needed for linking must
+be retrieved while the SDS ist still open. The call:
+<center>NXlink nl = nf.getdataID();</center> does just that. Then,
+after moving to the appropriate place for the link in the
+group hierarchy the  call:
+<center>nf.makelink(nl);</center>
+will actually install the link. 
+<p>
+</BODY>
+</HTML>
diff --git a/bindings/java/native/NexusFile.c b/bindings/java/native/NexusFile.c
new file mode 100644
index 0000000..7351924
--- /dev/null
+++ b/bindings/java/native/NexusFile.c
@@ -0,0 +1,1588 @@
+/*
+   This is the implementation file for the native methods used by the NeXus
+   Java API.
+
+   Mark Koennecke, 2000 -- 2011
+
+   IMPLEMENTATION NOTES
+
+   The NAPI uses a handle type for hiding the NeXus file datastructure.
+   This handle is essentially a pointer. Now, dealing with pointers in
+   Java is hideous. Usually a a pointer is just an integer but depending
+   on the system this can be 4 byte, 8 byte or other. In order to get rid of 
+   this problem we manage the pointers ourselves. The handle module maps
+   integer handles to the NeXus handle for us. All the java code sees is
+   the integer. But any routine in here has to retrieve the NXhandle for
+   the integer first before it can do useful work.
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "org_nexusformat_NexusFile.h"
+#include <napi.h>
+#include "handle.h"
+
+#ifdef WIN32
+/* commented  away for MINGW 
+#include <mapiwin.h> 
+*/
+#endif
+
+/* #define DEBUG */
+
+static JavaVM *jvm;  // Global variable
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
+    JNIEnv *env;
+    jclass nexusException;  
+
+    jint ret = (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_1);
+
+    assert(ret == JNI_OK);
+
+    jvm = vm;
+
+    nexusException = (*env)->FindClass(env,"org/nexusformat/NexusException");
+    if (nexusException == NULL) {
+	fprintf(stderr, "cannot find NexusException - this will not work. Terminating.");
+	assert(nexusException);
+    }
+
+    return JNI_VERSION_1_1;
+}
+
+/*---------------------------------------------------------------------------
+                              ERROR TREATMENT
+
+  The NAPI posts any errors to a customisable function. 
+  We construct and throw a NexusException with the message received.
+  --------------------------------------------------------------------------*/
+static void JapiError(void *pData, char *text) {
+    JNIEnv *env = pData;
+    jclass nexusException;  
+
+#ifdef DEBUG
+    fprintf(stderr,"JapiError called with: %s\n", text); 
+#endif
+
+    /* ignore env passed in seems safer */
+    (*jvm)->AttachCurrentThread (jvm, (void **) &env, NULL);
+
+    if (env == NULL) {
+	// if there is no thread environment we do not need to throw an exception
+	return;
+    }
+
+    // Find and store the NexusException class for use in JapiError
+    nexusException = (*env)->FindClass(env,"org/nexusformat/NexusException");
+    (*env)->ThrowNew(env, nexusException, text);
+} 
+
+/*------------------------------------------------------------------------
+            init or NXopen
+-------------------------------------------------------------------------*/
+JNIEXPORT jint JNICALL Java_org_nexusformat_NexusFile_init
+  (JNIEnv *env, jobject obj, jstring filename, jint access)
+{
+    NXhandle handle;
+    char *fileName;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* extract the filename as a C char* */
+    fileName = (char *) (*env)->GetStringUTFChars(env, filename, 0);    
+    
+    /* call NXopen */
+#ifdef DEBUG
+    fprintf(stderr,"Calling NXopen on %s, with %d\n", fileName, access);
+#endif
+    iRet = NXopen(fileName,access,&handle);
+
+#ifdef DEBUG
+    fprintf(stderr,"Handle allocated for %s\n", fileName);
+#endif
+
+    /* release the filename string */
+    (*env)->ReleaseStringUTFChars(env,filename, fileName);
+
+    /* error return */
+    if(iRet != NX_OK)
+    {
+      return -1;
+    }
+
+    /* convert the NXhandle to a integer handle */
+    return HHMakeHandle(handle);
+}
+/*-----------------------------------------------------------------------
+                     nxflush
+------------------------------------------------------------------------*/ 
+JNIEXPORT jint JNICALL Java_org_nexusformat_NexusFile_nxflush
+  (JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* kill handle */
+    HHRemoveHandle(handle);
+
+    /* call NXflush */
+    iRet = NXflush(&nxhandle);
+
+    /* error return */
+    if(iRet != NX_OK)
+    {
+      return -1;
+    }
+
+    /* convert the NXhandle to a integer handle */
+    return HHMakeHandle(nxhandle);
+}
+/*-----------------------------------------------------------------------
+                     close or NXclose
+------------------------------------------------------------------------*/ 
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_close
+  (JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+#ifdef DEBUG
+    fprintf(stderr,"closing handle %d, nxhandle %d\n", handle, nxhandle);
+#endif
+
+    iRet = NXclose(&nxhandle);
+
+    /* kill handle */
+    HHRemoveHandle(handle);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXclose failed");
+    }
+}
+/*------------------------------------------------------------------------
+                     nxmakegroup
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakegroup
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jstring nxclass)
+{
+    char *Name, *Nxclass;
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+    Nxclass = (char *) (*env)->GetStringUTFChars(env,nxclass,0);    
+
+    iRet = NXmakegroup(nxhandle, Name, Nxclass);
+
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseStringUTFChars(env,nxclass, Nxclass);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXmakegroup failed");
+    }
+}
+/*------------------------------------------------------------------------
+                     nxopengroup
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxopengroup
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jstring nxclass)
+{
+    char *Name, *Nxclass;
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+    Nxclass = (char *) (*env)->GetStringUTFChars(env,nxclass,0);    
+
+    iRet = NXopengroup(nxhandle, Name, Nxclass);
+
+#ifdef DEBUG
+    if(iRet != NX_OK)
+    {
+      fprintf(stderr,"Cleanup code called after raising Exception\n");
+    }
+#endif
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseStringUTFChars(env,nxclass, Nxclass);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXopengroup failed");
+    }
+}
+/*------------------------------------------------------------------------
+                     nxopenpath
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxopenpath
+  (JNIEnv *env, jobject obj, jint handle, jstring path)
+{
+    char *nxpath;
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    nxpath = (char *) (*env)->GetStringUTFChars(env,path,0);    
+
+    iRet = NXopenpath(nxhandle, nxpath);
+
+#ifdef DEBUG
+    if(iRet != NX_OK)
+    {
+      fprintf(stderr,"Cleanup code called after raising Exception\n");
+    }
+#endif
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,path, nxpath);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXopenpath failed");
+    }
+}
+/*------------------------------------------------------------------------
+                     nxopengrouppath
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxopengrouppath
+  (JNIEnv *env, jobject obj, jint handle, jstring path)
+{
+    char *nxpath;
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    nxpath = (char *) (*env)->GetStringUTFChars(env,path,0);    
+
+    iRet = NXopengrouppath(nxhandle, nxpath);
+
+#ifdef DEBUG
+    if(iRet != NX_OK)
+    {
+      fprintf(stderr,"Cleanup code called after raising Exception\n");
+    }
+#endif
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,path, nxpath);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXopengrouppath failed");
+    }
+}
+/*-----------------------------------------------------------------------*/
+JNIEXPORT jstring JNICALL Java_org_nexusformat_NexusFile_nxgetpath
+  (JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+    char path[1024];
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    if (NXgetpath(nxhandle, path,1024) != NX_OK) {
+      JapiError(env, "NXgetpath failed");
+    }
+
+    return (*env)->NewStringUTF(env,path);
+}
+
+/*------------------------------------------------------------------------
+                     nxclosegroup
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxclosegroup
+  (JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    if (NXclosegroup(nxhandle) != NX_OK) {
+      JapiError(env, "NXclosegroup failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxmakedata
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakedata
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jint type, 
+  jint rank, jintArray dim)
+{
+   char *Name;
+   NXhandle nxhandle;
+   jint *iDim;
+   int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    /* access dim array */
+    iDim = (*env)->GetIntArrayElements(env,dim,0);
+
+    iRet = NXmakedata(nxhandle,Name,type,rank,iDim);
+
+    /* clean up */ 
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseIntArrayElements(env,dim,iDim,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXmakedata failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxmakedata64
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakedata64
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jint type, 
+  jint rank, jlongArray dim)
+{
+   char *Name;
+   NXhandle nxhandle;
+   jlong *iDim;
+   int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    /* access dim array */
+    iDim = (*env)->GetLongArrayElements(env,dim,0);
+
+    iRet = NXmakedata64(nxhandle,Name,type,rank,iDim);
+
+    /* clean up */ 
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseLongArrayElements(env,dim,iDim,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXmakedata failed");
+    }
+}
+/*-----------------------------------------------------------------------
+                               nxcompmakedata
+-------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakecompdata
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jint type, 
+   jint rank, jintArray dim, jint compression_type, jintArray chunk)
+{
+   char *Name;
+   NXhandle nxhandle;
+   jint *iDim, *iChunk;
+   int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    /* access dim array */
+    iDim = (*env)->GetIntArrayElements(env,dim,0);
+
+    /* access the chunksize array */
+    iChunk = (*env)->GetIntArrayElements(env,chunk,0);
+
+    iRet = NXcompmakedata(nxhandle,Name,type,rank,iDim,
+                          compression_type,iChunk);
+
+    /* clean up */ 
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseIntArrayElements(env,dim,iDim,0);  
+    (*env)->ReleaseIntArrayElements(env,chunk,iChunk,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXcompmakedata failed");
+    }
+}
+
+/*-----------------------------------------------------------------------
+                               nxcompmakedata64
+-------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakecompdata64
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jint type, 
+   jint rank, jlongArray dim, jint compression_type, jlongArray chunk)
+{
+   char *Name;
+   NXhandle nxhandle;
+   jlong *iDim, *iChunk;
+   int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    /* access dim array */
+    iDim = (*env)->GetLongArrayElements(env,dim,0);
+
+    /* access the chunksize array */
+    iChunk = (*env)->GetLongArrayElements(env,chunk,0);
+
+    iRet = NXcompmakedata64(nxhandle,Name,type,rank,iDim,
+                          compression_type,iChunk);
+
+    /* clean up */ 
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseLongArrayElements(env,dim,iDim,0);  
+    (*env)->ReleaseLongArrayElements(env,chunk,iChunk,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXcompmakedata failed");
+    }
+}
+
+/*------------------------------------------------------------------------
+                               nxopendata
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxopendata
+  (JNIEnv *env, jobject obj, jint handle , jstring name)
+{
+   char *Name;
+   NXhandle nxhandle;
+   int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    iRet = NXopendata(nxhandle,Name);
+
+    /* clean up */ 
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXopendata failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxclosedata
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxclosedata
+  (JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    if (NXclosedata(nxhandle) != NX_OK) {
+      JapiError(env, "NXclosedata failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxcompress
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxcompress
+  (JNIEnv *env, jobject obj, jint handle , jint comp_type)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+#ifdef DEBUG
+    fprintf(stderr,"Compressing at %d with type %d\n", nxhandle, comp_type);
+#endif
+
+    if (NXcompress(nxhandle,comp_type) != NX_OK) {
+      JapiError(env, "NXcompress failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxputdata
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxputdata
+  (JNIEnv *env, jobject obj, jint handle, jbyteArray data)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert jbteArray to C byte array */
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+
+    iRet = NXputdata(nxhandle, bdata);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    if(iRet != NX_OK)
+    {
+#ifdef DEBUG
+      HEprint(stderr,0);
+#else
+      JapiError(env, "NXputdata failed");
+#endif
+    }
+}
+/*------------------------------------------------------------------------
+                               nxputslab
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxputslab
+  (JNIEnv *env, jobject obj, jint handle, jbyteArray data, 
+   jintArray start, jintArray end)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    jint *iStart, *iEnd;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert arrays to C types  */
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+    iStart = (*env)->GetIntArrayElements(env,start,0);
+    iEnd = (*env)->GetIntArrayElements(env,end,0);
+
+
+    iRet = NXputslab(nxhandle, bdata, iStart, iEnd);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    (*env)->ReleaseIntArrayElements(env,start,iStart,0);  
+    (*env)->ReleaseIntArrayElements(env,end,iEnd,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXputslab failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxputslab64
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxputslab64
+  (JNIEnv *env, jobject obj, jint handle, jbyteArray data, 
+   jlongArray start, jlongArray end)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    jlong *iStart, *iEnd;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert arrays to C types  */
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+    iStart = (*env)->GetLongArrayElements(env,start,0);
+    iEnd = (*env)->GetLongArrayElements(env,end,0);
+
+
+    iRet = NXputslab64(nxhandle, bdata, iStart, iEnd);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    (*env)->ReleaseLongArrayElements(env,start,iStart,0);  
+    (*env)->ReleaseLongArrayElements(env,end,iEnd,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXputslab failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxputattr
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxputattr
+  (JNIEnv *env, jobject obj, jint handle , jstring name, 
+           jbyteArray data, jint type)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    char *Name;
+    int iRet, iDataLen, div = 1;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+   
+    /* convert java types to C types*/
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+    iDataLen = (*env)->GetArrayLength(env,data);
+    switch(type)
+    {
+        case NX_INT8:
+        case NX_UINT8:
+        case NX_CHAR:
+             div = 1;
+             break;
+        case NX_UINT16:
+        case NX_INT16:
+             div = 2;
+             break;
+        case NX_INT32:
+        case NX_UINT32:
+        case NX_FLOAT32:
+             div = 4;
+             break;
+        case NX_FLOAT64:
+        case NX_INT64:
+        case NX_UINT64:
+             div = 8;
+             break;
+        default:
+	  JapiError(env, "Bad data type in NXputattr");
+	  return;
+    }
+    iDataLen /=  div;
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+   
+    iRet = NXputattr(nxhandle,Name, bdata, iDataLen, type);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXputattr failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetdata
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetdata
+  (JNIEnv *env, jobject obj, jint handle, jbyteArray data)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert jbteArray to C byte array */
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+
+    iRet = NXgetdata(nxhandle, bdata);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    if(iRet != NX_OK)
+    {
+#ifdef DEBUG
+      HEprint(stderr,0);
+#else
+      JapiError(env, "NXgetdata failed");
+#endif
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetslab
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetslab
+  (JNIEnv *env, jobject obj, jint handle, jintArray start, 
+   jintArray end, jbyteArray data)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    jint *iStart, *iEnd;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert arrays to C types  */
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+    iStart = (*env)->GetIntArrayElements(env,start,0);
+    iEnd = (*env)->GetIntArrayElements(env,end,0);
+
+    iRet = NXgetslab(nxhandle, bdata, iStart, iEnd);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    (*env)->ReleaseIntArrayElements(env,start,iStart,0);  
+    (*env)->ReleaseIntArrayElements(env,end,iEnd,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXgetslab failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetslab64
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetslab64
+  (JNIEnv *env, jobject obj, jint handle, jlongArray start, 
+   jlongArray end, jbyteArray data)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    jlong *iStart, *iEnd;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert arrays to C types  */
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+    iStart = (*env)->GetLongArrayElements(env,start,0);
+    iEnd = (*env)->GetLongArrayElements(env,end,0);
+
+    iRet = NXgetslab64(nxhandle, bdata, iStart, iEnd);
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    (*env)->ReleaseLongArrayElements(env,start,iStart,0);  
+    (*env)->ReleaseLongArrayElements(env,end,iEnd,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXgetslab failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetattr
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetattr
+  (JNIEnv *env, jobject obj, jint handle, jstring name, 
+    jbyteArray data, jintArray args)
+{
+    NXhandle nxhandle;
+    jbyte *bdata;
+    char *Name;
+    int iRet;
+    jint *iargs;
+    int iLen, iType;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* convert java types to C types*/
+    bdata = (*env)->GetByteArrayElements(env,data,0);
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+    iargs = (*env)->GetIntArrayElements(env,args,0);
+#ifdef DEBUG
+    fprintf(stderr,"nxgetattr converted types \n");
+#endif
+
+    iLen = iargs[0];
+    iType = iargs[1];
+#ifdef DEBUG
+    fprintf(stderr,"nxgetattr: iLen %d, iType: %d\n",iLen, iType);
+#endif
+
+    iRet = NXgetattr(nxhandle, Name, bdata, &iLen, &iType);
+    iargs[0] = iLen;
+    iargs[1] = iType;
+#ifdef DEBUG
+    fprintf(stderr,"nxgetattr cleaning up \n");
+#endif
+
+    /* cleanup */
+    (*env)->ReleaseByteArrayElements(env,data,bdata,0);   
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseIntArrayElements(env,args,iargs,0);  
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXgetattr failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetgroupid
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetgroupid
+  (JNIEnv *env, jobject obj, jint handle, jobject linki)
+{
+    NXhandle nxhandle;
+    NXlink myLink;
+    int iRet;
+    jclass cls;
+    jfieldID fid;
+    jstring jstr;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    iRet = NXgetgroupID(nxhandle, &myLink);
+    if(iRet == NX_OK)
+    {
+	/* put the link info from our link structure into the object */
+        cls = (*env)->GetObjectClass(env, linki);
+        if(cls == NULL)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate class in nxgetgroupid");
+            return;
+        }
+        fid = (*env)->GetFieldID(env,cls,"tag","I");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate fieldID in nxgetgroupid");
+            return;
+        }
+        (*env)->SetIntField(env,linki,fid,myLink.iTag);
+
+        fid = (*env)->GetFieldID(env,cls,"ref","I");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate fieldID in nxgetgroupid");
+            return;
+        }
+        (*env)->SetIntField(env,linki,fid,myLink.iRef);
+
+#ifdef HDF5
+        /* 
+         set HDF-5 String variables
+	*/
+        fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate targetPath in nxgetgroupid");
+            return;
+        }
+	jstr = (*env)->NewStringUTF(env,myLink.targetPath);
+        (*env)->SetObjectField(env, linki, fid, jstr);
+
+        fid = (*env)->GetFieldID(env,cls,"linkType","I");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate linkType in nxgetgroupid");
+            return;
+        }
+        (*env)->SetIntField(env,linki,fid,myLink.linkType);
+
+#endif        
+        fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate targetPath in nxgetgroupid");
+            return;
+        }
+	jstr = (*env)->NewStringUTF(env,myLink.targetPath);
+        (*env)->SetObjectField(env, linki, fid, jstr);
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetgroupid
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetdataid
+  (JNIEnv *env, jobject obj, jint handle, jobject linki)
+{
+    NXhandle nxhandle;
+    NXlink myLink;
+    int iRet;
+    jclass cls;
+    jfieldID fid;
+    jstring jstr;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    iRet = NXgetdataID(nxhandle, &myLink);
+    if(iRet == NX_OK)
+    {
+	/* put the link info from our link structure into the object */
+        cls = (*env)->GetObjectClass(env, linki);
+        if(cls == NULL)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate class in nxgetdataid");
+            return;
+        }
+        fid = (*env)->GetFieldID(env,cls,"tag","I");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate fieldID in nxgetdataid");
+            return;
+        }
+        (*env)->SetIntField(env,linki,fid,myLink.iTag);
+        fid = (*env)->GetFieldID(env,cls,"ref","I");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate fieldID in nxgetdataid");
+            return;
+        }
+        (*env)->SetIntField(env,linki,fid,myLink.iRef);
+
+#ifdef HDF5
+        /* 
+         set HDF-5 String variables
+	*/
+        fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate targetPath in nxgetgroupid");
+            return;
+        }
+	jstr = (*env)->NewStringUTF(env,myLink.targetPath);
+        (*env)->SetObjectField(env, linki, fid, jstr);
+
+        fid = (*env)->GetFieldID(env,cls,"linkType","I");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate linkType in nxgetgroupid");
+            return;
+        }
+        (*env)->SetIntField(env,linki,fid,myLink.linkType);
+
+#endif
+        fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+        if(fid == 0)
+	{
+	    JapiError(env,
+	       "ERROR: failed to locate targetPath in nxgetdataid");
+            return;
+        }
+	jstr = (*env)->NewStringUTF(env,myLink.targetPath);
+        (*env)->SetObjectField(env, linki, fid, jstr);
+
+    }
+}
+/*------------------------------------------------------------------------
+                               nxmakelink
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakelink
+  (JNIEnv *env, jobject obj, jint handle, jobject target)
+{
+    NXhandle nxhandle;
+    NXlink myLink;
+    jclass cls;
+    jfieldID fid;
+    jstring jstr;
+    const char *cData;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    // convert target object data to myLink structure */
+    cls = (*env)->GetObjectClass(env, target);
+    if(cls == NULL)
+    {
+	 JapiError(env,
+	       "ERROR: failed to locate class in nxmakelink");
+         return;
+     }
+     fid = (*env)->GetFieldID(env,cls,"tag","I");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate fieldID in nxmakelink");
+          return;
+     }
+     myLink.iTag = (*env)->GetIntField(env,target,fid);
+     fid = (*env)->GetFieldID(env,cls,"ref","I");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate fieldID in nxmakelink");
+          return;
+     }
+     myLink.iRef = (*env)->GetIntField(env,target,fid);
+
+#ifdef HDF5    
+     /*
+       get the HDF-5 Strings
+     */
+     fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate targetPath in nxmakelink");
+          return;
+     }
+     jstr = (*env)->GetObjectField(env, target, fid);
+     cData = (*env)->GetStringUTFChars(env, jstr, 0);          
+     strcpy(myLink.targetPath,cData);
+     (*env)->ReleaseStringUTFChars(env, jstr, cData);
+
+     fid = (*env)->GetFieldID(env,cls,"linkType","I");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate linkType in nxmakelink");
+          return;
+     }
+     myLink.linkType = (*env)->GetIntField(env,target,fid);
+
+#endif
+     fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate targetPath in nxmakelink");
+          return;
+     }
+     jstr = (*env)->GetObjectField(env, target, fid);
+     cData = (*env)->GetStringUTFChars(env, jstr, 0);          
+     strcpy(myLink.targetPath,cData);
+     (*env)->ReleaseStringUTFChars(env, jstr, cData);
+
+     // do actually link
+     if (NXmakelink(nxhandle, &myLink) != NX_OK) {
+       JapiError(env, "NXmakelink failed");
+     }
+}
+/*------------------------------------------------------------------------
+                               nxmakenamedlink
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxmakenamedlink
+  (JNIEnv *env, jobject obj, jint handle, jstring name, jobject target)
+{
+    NXhandle nxhandle;
+    NXlink myLink;
+    jclass cls;
+    jfieldID fid;
+    jstring jstr;
+    const char *cData;
+    char *Name; 
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* get link name */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    // convert target object data to myLink structure */
+    cls = (*env)->GetObjectClass(env, target);
+    if(cls == NULL)
+    {
+	 JapiError(env,
+	       "ERROR: failed to locate class in nxmakelink");
+         return;
+     }
+     fid = (*env)->GetFieldID(env,cls,"tag","I");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate fieldID in nxmakelink");
+          return;
+     }
+     myLink.iTag = (*env)->GetIntField(env,target,fid);
+     fid = (*env)->GetFieldID(env,cls,"ref","I");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate fieldID in nxmakelink");
+          return;
+     }
+     myLink.iRef = (*env)->GetIntField(env,target,fid);
+
+#ifdef HDF5    
+     /*
+       get the HDF-5 Strings
+     */
+     fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate targetPath in nxmakelink");
+          return;
+     }
+     jstr = (*env)->GetObjectField(env, target, fid);
+     cData = (*env)->GetStringUTFChars(env, jstr, 0);          
+     strcpy(myLink.targetPath,cData);
+     (*env)->ReleaseStringUTFChars(env, jstr, cData);
+
+     fid = (*env)->GetFieldID(env,cls,"linkType","I");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate linkType in nxmakelink");
+          return;
+     }
+     myLink.linkType = (*env)->GetIntField(env,target,fid);
+
+#endif
+     fid = (*env)->GetFieldID(env,cls,"targetPath","Ljava/lang/String;");
+     if(fid == 0)
+     {
+	  JapiError(env,
+	       "ERROR: failed to locate targetPath in nxmakelink");
+          return;
+     }
+     jstr = (*env)->GetObjectField(env, target, fid);
+     cData = (*env)->GetStringUTFChars(env, jstr, 0);          
+     strcpy(myLink.targetPath,cData);
+     (*env)->ReleaseStringUTFChars(env, jstr, cData);
+
+     // do actually link
+     if (NXmakenamedlink(nxhandle, Name,  &myLink) != NX_OK) {
+       JapiError(env, "NXmakenamedlink failed");
+     }
+}
+
+/*------------------------------------------------------------------------
+                     nxopensourcepath
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxopensourcegroup
+  (JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    if (NXopensourcegroup(nxhandle) != NX_OK) {
+       JapiError(env, "NXopensourcegroup failed");
+     }
+}
+
+/*----------------------------------------------------------------------
+                           nxsetnumberformat
+-----------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxsetnumberformat
+    (JNIEnv *env, jobject obj, jint handle, jint type, jstring format)
+{
+    NXhandle nxhandle;
+    char *cformat;
+    int iRet;
+
+   /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /*
+      extract format string
+    */
+    cformat = (char *) (*env)->GetStringUTFChars(env,format,0);
+
+    /*
+      call
+    */
+    iRet = NXsetnumberformat(nxhandle,type,cformat);
+    /*
+      release format string
+    */ 
+    (*env)->ReleaseStringUTFChars(env,format, cformat);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXsetnumberformat failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetinfo
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetinfo
+    (JNIEnv *env, jobject obj, jint handle, jintArray dim, jintArray args)
+{
+    int rank, type, iRet, iDim[NX_MAXRANK], i;
+    NXhandle nxhandle;
+    jint *jdata;
+
+   /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* call */
+    iRet = NXgetinfo(nxhandle, &rank, iDim, &type);
+
+    /* copy data to Java types */
+    if(iRet == NX_OK)
+    {
+	jdata = (*env)->GetIntArrayElements(env,dim,0);
+        for(i = 0; i < rank; i++)
+	{
+           jdata[i] = iDim[i];
+        }
+        (*env)->ReleaseIntArrayElements(env,dim,jdata,0);
+	jdata = (*env)->GetIntArrayElements(env,args,0);
+        jdata[0] = rank;
+        jdata[1] = type;
+        (*env)->ReleaseIntArrayElements(env,args,jdata,0);
+    }
+}
+/*------------------------------------------------------------------------
+                               nxgetinfo64
+--------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxgetinfo64
+    (JNIEnv *env, jobject obj, jint handle, jlongArray dim, jintArray args)
+{
+    int rank, type, iRet, i;
+    jlong iDim[NX_MAXRANK];
+    NXhandle nxhandle;
+    jlong *jdata;
+    jint *jargsdata;
+
+   /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    /* call */
+    iRet = NXgetinfo64(nxhandle, &rank, iDim, &type);
+
+    /* copy data to Java types */
+    if(iRet == NX_OK)
+    {
+	jdata = (*env)->GetLongArrayElements(env,dim,0);
+        for(i = 0; i < rank; i++)
+	{
+           jdata[i] = iDim[i];
+        }
+        (*env)->ReleaseLongArrayElements(env,dim,jdata,0);
+
+	jargsdata = (*env)->GetIntArrayElements(env,args,0);
+        jargsdata[0] = rank;
+        jargsdata[1] = type;
+        (*env)->ReleaseIntArrayElements(env,args,jargsdata,0);
+    }
+}
+/*------------------------------------------------------------------------
+                               nextentry
+--------------------------------------------------------------------------*/
+JNIEXPORT jint JNICALL Java_org_nexusformat_NexusFile_nextentry
+  (JNIEnv *env, jobject obj, jint handle, jobjectArray jnames)
+{
+    NXhandle nxhandle;
+    NXname pName, pClass;
+    int iRet, iType;
+    jstring rstring;
+
+   /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    iRet = NXgetnextentry(nxhandle,pName, pClass,&iType);
+    if(iRet != NX_ERROR)
+    {
+	/* convert C strings to Java Strings */
+        rstring = (*env)->NewStringUTF(env,pName);
+        (*env)->SetObjectArrayElement(env,jnames,0,(jobject)rstring);
+        rstring = (*env)->NewStringUTF(env,pClass);
+        (*env)->SetObjectArrayElement(env,jnames,1,(jobject)rstring);
+    }
+    return iRet;
+}
+/*------------------------------------------------------------------------
+                               nextattr
+--------------------------------------------------------------------------*/
+JNIEXPORT jint JNICALL Java_org_nexusformat_NexusFile_nextattr
+  (JNIEnv *env, jobject obj, jint handle, jobjectArray jnames, jintArray args)
+{
+    NXhandle nxhandle;
+    NXname pName;
+    int iRet, iType, iLen;
+    jstring rstring;
+    jint *jarray;
+   /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    iRet = NXgetnextattr(nxhandle, pName, &iLen, &iType);
+    if(iRet != NX_ERROR)
+    {
+        /* copy C types to Java */
+        rstring = (*env)->NewStringUTF(env,pName);
+        (*env)->SetObjectArrayElement(env,jnames,0,(jobject)rstring);
+	jarray = (*env)->GetIntArrayElements(env,args,0);
+        jarray[0] = iLen;
+        jarray[1] = iType;
+        (*env)->ReleaseIntArrayElements(env,args,jarray,0);
+    }
+    return iRet;
+}
+/*-----------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxinquirefile(JNIEnv *env, 
+				      jobject obj , jint handle, jobjectArray jnames){
+    NXhandle nxhandle;
+    int status;
+    char filename[1024];
+    jstring rstring;
+
+   /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+    status = NXinquirefile(nxhandle,filename,1023);
+    if(status == NX_OK){
+      rstring = (*env)->NewStringUTF(env,filename);
+      (*env)->SetObjectArrayElement(env,jnames,0,(jobject)rstring);
+    }
+}
+/*------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxlinkexternal
+(JNIEnv *env, jobject obj, jint handle, jstring name, 
+ jstring nxclass, jstring nxurl){
+    int iRet;
+    NXhandle nxhandle;
+    char *Name, *Nxclass, *Nxurl;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+  
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+    Nxclass = (char *) (*env)->GetStringUTFChars(env,nxclass,0);    
+    Nxurl = (char *) (*env)->GetStringUTFChars(env,nxurl,0);    
+    iRet = NXlinkexternal(nxhandle,Name,Nxclass,Nxurl);
+    
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseStringUTFChars(env,nxclass, Nxclass);
+    (*env)->ReleaseStringUTFChars(env,nxurl, Nxurl);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXlinkexternal failed");
+    }
+}
+/*------------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_nxlinkexternaldataset
+(JNIEnv *env, jobject obj, jint handle, jstring name, jstring nxurl){
+    int iRet;
+    NXhandle nxhandle;
+    char *Name, *Nxurl;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+  
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+    Nxurl = (char *) (*env)->GetStringUTFChars(env,nxurl,0);    
+    iRet = NXlinkexternaldataset(nxhandle,Name,Nxurl);
+    
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseStringUTFChars(env,nxurl, Nxurl);
+
+    if (iRet != NX_OK) {
+      JapiError(env, "NXlinkexternaldataset failed");
+    }
+}
+/*------------------------------------------------------------------------*/
+JNIEXPORT jint JNICALL Java_org_nexusformat_NexusFile_nxisexternalgroup
+(JNIEnv *env, jobject obj, jint handle, jstring name, jstring nxclass, 
+ jobjectArray jnames){
+    int status, length = 1024;
+    NXhandle nxhandle;
+    char *Name, *Nxclass, nxurl[1024];
+    jstring rstring;
+    
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+  
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+    Nxclass = (char *) (*env)->GetStringUTFChars(env,nxclass,0);    
+
+    status = NXisexternalgroup(nxhandle,Name,Nxclass,nxurl,length);
+
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    (*env)->ReleaseStringUTFChars(env,nxclass, Nxclass);
+    
+    if(status == NX_OK){
+      rstring = (*env)->NewStringUTF(env,nxurl);
+      (*env)->SetObjectArrayElement(env,jnames,0,(jobject)rstring);
+    }
+    return status;
+}
+/*------------------------------------------------------------------------*/
+JNIEXPORT jint JNICALL Java_org_nexusformat_NexusFile_nxisexternaldataset
+(JNIEnv *env, jobject obj, jint handle, jstring name, jobjectArray jnames){
+    int status, length = 1024;
+    NXhandle nxhandle;
+    char *Name, nxurl[1024];
+    jstring rstring;
+    
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+  
+    /* extract the name and class to char * */
+    Name = (char *) (*env)->GetStringUTFChars(env,name,0);    
+
+    status = NXisexternaldataset(nxhandle,Name,nxurl,length);
+
+    /* release strings */
+    (*env)->ReleaseStringUTFChars(env,name, Name);
+    
+    if(status == NX_OK){
+      rstring = (*env)->NewStringUTF(env,nxurl);
+      (*env)->SetObjectArrayElement(env,jnames,0,(jobject)rstring);
+    }
+    return status;
+}
+/*---------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_initattrdir
+(JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    if (NXinitattrdir(nxhandle) != NX_OK) {
+      JapiError(env, "NXinitattrdir failed");
+    }
+}
+/*---------------------------------------------------------------------*/
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_initgroupdir
+(JNIEnv *env, jobject obj, jint handle)
+{
+    NXhandle nxhandle;
+    int iRet;
+
+    /* set error handler */
+    NXMSetTError(env,JapiError);
+
+    /* exchange the Java handler to a NXhandle */
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+
+    if (NXinitgroupdir(nxhandle) != NX_OK) {
+      JapiError(env, "NXinitgroupdir failed");
+    }
+}
+/*------------------------------------------------------------------------
+                               debugstop
+--------------------------------------------------------------------------*/
+
+JNIEXPORT void JNICALL Java_org_nexusformat_NexusFile_debugstop
+  (JNIEnv *env, jobject obj)
+{
+   int iStop = 1;
+
+   while(iStop)
+   {
+/*       sleep(2); */
+   }
+}
diff --git a/bindings/java/native/handle.c b/bindings/java/native/handle.c
new file mode 100644
index 0000000..55ee1a2
--- /dev/null
+++ b/bindings/java/native/handle.c
@@ -0,0 +1,61 @@
+/*
+  This implements a handle management module. Sometimes it is useful to
+  protect the user of some software module from messing with complicated
+  datastructures. In such cases it is useful  to use an integer handle
+  which can be translated into a pointer when needed by the code implementing
+  the module. Such a scheme is implemented in this module.
+
+  Mark Koennecke, October 2000
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "handle.h"
+
+static void **pointerArray = NULL;
+
+/*----------------------------------------------------------------------*/
+static void checkArray()
+{
+  if(pointerArray == NULL)
+  {
+      pointerArray = (void **)malloc(MAXHANDLE*sizeof(void *));
+      assert(pointerArray != NULL);
+      memset(pointerArray,0,MAXHANDLE*sizeof(void *));
+  }
+}
+/*--------------------------------------------------------------------*/
+int HHMakeHandle(void *pData)
+{
+  int i;
+
+  checkArray();
+  /* 
+    find first free slot in the pointerArray, store the pointer and 
+    return the index.
+  */
+  for(i = 0; i < MAXHANDLE; i++)
+  {
+     if(pointerArray[i] == NULL)
+     {
+       pointerArray[i] = pData;
+       return i;
+     }
+  }
+  return -1;
+}
+/*---------------------------------------------------------------------*/
+void  *HHGetPointer(int handle)
+{
+  assert(handle < MAXHANDLE && handle >= 0);
+  checkArray();
+  return pointerArray[handle];
+}
+/*---------------------------------------------------------------------*/
+void HHRemoveHandle(int handle)
+{
+  assert(handle < MAXHANDLE && handle >= 0);
+  checkArray();
+  pointerArray[handle] = NULL;
+}
+
diff --git a/bindings/java/native/handle.h b/bindings/java/native/handle.h
new file mode 100644
index 0000000..a013d0e
--- /dev/null
+++ b/bindings/java/native/handle.h
@@ -0,0 +1,21 @@
+/*
+  This implements a handle management module. Sometimes it is useful to
+  protect the user of some software module from messing with complicated
+  datastructures. In such cases it is useful  to use an integer handle
+  which can be translated into a pointer when needed by the code implementing
+  the module. Such a scheme is implemented in this module.
+
+  Mark Koennecke, October 2000
+*/
+#ifndef HANDLEHANDLE
+#define HANDLEHANDLE
+
+/* The maximum number of handles. */
+#define MAXHANDLE 8192
+
+  int HHMakeHandle(void *pData);
+  void  *HHGetPointer(int handle);
+  void HHRemoveHandle(int handle);  
+
+#endif
+ 
diff --git a/bindings/java/native/hdfexceptionImp.c b/bindings/java/native/hdfexceptionImp.c
new file mode 100644
index 0000000..f773027
--- /dev/null
+++ b/bindings/java/native/hdfexceptionImp.c
@@ -0,0 +1,166 @@
+
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This is a utility program used by the HDF Java-C wrapper layer to
+ *  generate exceptions.  This may be called from any part of the
+ *  Java-C interface.
+ *
+ */
+
+#include <stdio.h>
+#include "jni.h"
+#include "hdfexceptionImp.h"
+
+jboolean buildException( JNIEnv *env, jint HDFerr)
+{
+jmethodID jm;
+jclass jc;
+int args[2];
+jobject ex;
+int rval;
+
+
+	jc = (*env)->FindClass(env, "ncsa/hdf/hdflib/HDFLibraryException");
+	if (jc == NULL) {
+		return JNI_FALSE;
+	}
+	jm = (*env)->GetMethodID(env, jc, "<init>", "(I)V");
+	if (jm == NULL) {
+		return JNI_FALSE;
+	}
+	args[0] = HDFerr;
+	args[1] = 0;
+
+	ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+	rval = (*env)->Throw(env, ex );
+
+	return JNI_TRUE;
+}
+
+jboolean NotImplemented( JNIEnv *env, char *functName)
+{
+jmethodID jm;
+jclass jc;
+char * args[2];
+jobject ex;
+jstring str;
+int rval;
+
+
+	jc = (*env)->FindClass(env, "ncsa/hdf/hdflib/HDFNotImplementedException");
+	if (jc == NULL) {
+		return JNI_FALSE;
+	}
+	jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+	if (jm == NULL) {
+		return JNI_FALSE;
+	}
+
+	str = (*env)->NewStringUTF(env,functName);
+	args[0] = (char *)str;
+	args[1] = 0;
+	ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+	rval = (*env)->Throw(env, ex );
+
+	return JNI_TRUE;
+}
+
+jboolean outOfMemory( JNIEnv *env, char *functName)
+{
+jmethodID jm;
+jclass jc;
+char * args[2];
+jobject ex;
+jstring str;
+int rval;
+
+	jc = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+	if (jc == NULL) {
+		return JNI_FALSE;
+	}
+	jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+	if (jm == NULL) {
+		return JNI_FALSE;
+	}
+
+	str = (*env)->NewStringUTF(env,functName);
+	args[0] = (char *)str;
+	args[1] = 0;
+	ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+	rval = (*env)->Throw(env, ex );
+
+	return JNI_TRUE;
+}
+
+
+/*
+ *  A fatal error in a JNI call
+ */
+jboolean JNIFatalError( JNIEnv *env, char *functName)
+{
+jmethodID jm;
+jclass jc;
+char * args[2];
+jobject ex;
+jstring str;
+int rval;
+
+	jc = (*env)->FindClass(env, "java/lang/InternalError");
+	if (jc == NULL) {
+		return JNI_FALSE;
+	}
+	jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+	if (jm == NULL) {
+		return JNI_FALSE;
+	}
+
+	str = (*env)->NewStringUTF(env,functName);
+	args[0] = (char *)str;
+	args[1] = 0;
+	ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+	rval = (*env)->Throw(env, ex );
+
+	return JNI_TRUE;
+}
+
+jboolean raiseException( JNIEnv *env, char *message)
+{
+jmethodID jm;
+jclass jc;
+char * args[2];
+jobject ex;
+jstring str;
+int rval;
+
+	jc = (*env)->FindClass(env, "ncsa/hdf/hdflib/HDFLibraryException");
+	if (jc == NULL) {
+		return JNI_FALSE;
+	}
+	jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+	if (jm == NULL) {
+		return JNI_FALSE;
+	}
+
+	str = (*env)->NewStringUTF(env,message);
+	args[0] = (char *)str;
+	args[1] = 0;
+	ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+	rval = (*env)->Throw(env, ex );
+
+	return JNI_TRUE;
+}
diff --git a/bindings/java/native/hdfexceptionImp.h b/bindings/java/native/hdfexceptionImp.h
new file mode 100644
index 0000000..816f23b
--- /dev/null
+++ b/bindings/java/native/hdfexceptionImp.h
@@ -0,0 +1,10 @@
+#ifndef HDFEXCEPTIONIMP
+#define HDFEXCEPTIONIMP
+
+extern jboolean outOfMemory( JNIEnv *env, char *functName);
+
+extern jboolean JNIFatalError( JNIEnv *env, char *functName);
+
+extern jboolean raiseException( JNIEnv *env, char *message);
+
+#endif /* HDFEXCEPTIONIMP */
diff --git a/bindings/java/native/hdfnativeImp.c b/bindings/java/native/hdfnativeImp.c
new file mode 100644
index 0000000..0819598
--- /dev/null
+++ b/bindings/java/native/hdfnativeImp.c
@@ -0,0 +1,1258 @@
+
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#include <stdio.h>
+
+/* #include "hdf.h"    /* this only seems to be needed to define "intn" */
+typedef int intn;
+
+#include "jni.h"
+#include "hdfexceptionImp.h"
+
+/* returns int [] */
+JNIEXPORT jintArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToInt___3B 
+( JNIEnv *env,
+jclass class, 
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	intn rval;
+	jbyte *barr;
+	jintArray rarray;
+	int blen;
+	jint *iarray;
+	jboolean bb;
+	char *bp;
+	jint *iap;
+	int ii;
+	int len;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToInt: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToInt: pin failed");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+
+	len = blen/sizeof(jint);
+	rarray = (*env)->NewIntArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToInt" );
+		return NULL;
+	}
+
+	iarray = (*env)->GetIntArrayElements(env,rarray,&bb);
+	if (iarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToInt: pin iarray failed");
+		return NULL;
+	}
+
+	bp = (char *)barr;
+	iap = iarray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jint *)bp;
+		iap++;
+		bp += sizeof(jint);
+	}
+
+	(*env)->ReleaseIntArrayElements(env,rarray,iarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns float [] */
+JNIEXPORT jfloatArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToFloat___3B 
+( JNIEnv *env,
+jclass class, 
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	jbyte *barr;
+	jfloatArray rarray;
+	int blen;
+	jfloat *farray;
+	jboolean bb;
+	char *bp;
+	jfloat *iap;
+	int ii;
+	int len;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToFloat: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToFloat: pin failed");
+		return NULL;
+	}
+	blen = (*env)->GetArrayLength(env,bdata);
+
+	len = blen/sizeof(jfloat);
+	rarray = (*env)->NewFloatArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToFloat" );
+		return NULL;
+	}
+	farray = (*env)->GetFloatArrayElements(env,rarray,&bb);
+	if (farray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToFloat: pin farray failed");
+		return NULL;
+	}
+
+	bp = (char *)barr;
+	iap = farray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jfloat *)bp;
+		iap++;
+		bp += sizeof(jfloat);
+	}
+
+	(*env)->ReleaseFloatArrayElements(env,rarray,farray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns short [] */
+JNIEXPORT jshortArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToShort___3B 
+( JNIEnv *env,
+jclass class, 
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	jbyte *barr;
+	jshortArray rarray;
+	int blen;
+	jshort *sarray;
+	jboolean bb;
+	char *bp;
+	jshort *iap;
+	int ii;
+	int len;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToShort: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToShort: pin failed");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+
+	len = blen/sizeof(jshort);
+	rarray = (*env)->NewShortArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToShort" );
+		return NULL;
+	}
+
+	sarray = (*env)->GetShortArrayElements(env,rarray,&bb);
+	if (sarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToShort: pin sarray failed");
+		return NULL;
+	}
+
+	bp = (char *)barr;
+	iap = sarray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jshort *)bp;
+		iap++;
+		bp += sizeof(jshort);
+	}
+
+	(*env)->ReleaseShortArrayElements(env,rarray,sarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+
+/* returns long [] */
+JNIEXPORT jlongArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToLong___3B 
+( JNIEnv *env,
+jclass class, 
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	jbyte *barr;
+	jlongArray rarray;
+	int blen;
+	jlong *larray;
+	jboolean bb;
+	char *bp;
+	jlong *iap;
+	int ii;
+	int len;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToLong: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToLong: pin failed");
+		return NULL;
+	}
+	blen = (*env)->GetArrayLength(env,bdata);
+
+	len = blen/sizeof(jlong);
+	rarray = (*env)->NewLongArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToLong" );
+		return NULL;
+	}
+
+	larray = (*env)->GetLongArrayElements(env,rarray,&bb);
+	if (larray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToLong: pin larray failed");
+		return NULL;
+	}
+
+	bp = (char *)barr;
+	iap = larray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jlong *)bp;
+		iap++;
+		bp += sizeof(jlong);
+	}
+	(*env)->ReleaseLongArrayElements(env,rarray,larray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+
+/* returns double [] */
+JNIEXPORT jdoubleArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToDouble___3B 
+( JNIEnv *env,
+jclass class, 
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	jbyte *barr;
+	jdoubleArray rarray;
+	int blen;
+	jdouble *darray;
+	jboolean bb;
+	char *bp;
+	jdouble *iap;
+	int ii;
+	int len;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToDouble: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToDouble: pin failed");
+		return NULL;
+	}
+	blen = (*env)->GetArrayLength(env,bdata);
+
+	len = blen/sizeof(jdouble);
+	rarray = (*env)->NewDoubleArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToDouble" );
+		return NULL;
+	}
+
+	darray = (*env)->GetDoubleArrayElements(env,rarray,&bb);
+	if (darray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToDouble: pin darray failed");
+		return NULL;
+	}
+
+	bp = (char *)barr;
+	iap = darray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jdouble *)bp;
+		iap++;
+		bp += sizeof(jdouble);
+	}
+
+	(*env)->ReleaseDoubleArrayElements(env,rarray,darray,0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+}
+
+
+/* returns int [] */
+JNIEXPORT jintArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToInt__II_3B 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	char *bp;
+	jbyte *barr;
+	jintArray rarray;
+	int blen;
+	jint *iarray;
+	jint *iap;
+	int ii;
+	jboolean bb;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToInt: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToInt: pin failed");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+	if ((start < 0) || ((start + (len*sizeof(jint))) > blen)) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToInt: getLen failed");
+		return NULL;
+	}
+
+	bp = (char *)barr + start;
+
+	rarray = (*env)->NewIntArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToInt" );
+		return NULL;
+	}
+
+	iarray = (*env)->GetIntArrayElements(env,rarray,&bb);
+	if (iarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToInt: pin iarray failed");
+		return NULL;
+	}
+
+	iap = iarray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jint *)bp;
+		iap++;
+		bp += sizeof(jint);
+	}
+
+	(*env)->ReleaseIntArrayElements(env,rarray,iarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns short [] */
+JNIEXPORT jshortArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToShort__II_3B 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	char *bp;
+	jbyte *barr;
+	jshortArray rarray;
+	int blen;
+	jshort *iarray;
+	jshort *iap;
+	int ii;
+	jboolean bb;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToShort: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToShort: getByte failed?");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+	if ((start < 0) || ((start + (len*(sizeof(jshort)))) > blen)) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		raiseException( env, "byteToShort: start or len is out of bounds");
+		return NULL;
+	}
+
+	bp = (char *)barr + start;
+
+	rarray = (*env)->NewShortArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToShort" );
+		return NULL;
+	}
+
+	iarray = (*env)->GetShortArrayElements(env,rarray,&bb);
+	if (iarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToShort: getShort failed?");
+		return NULL;
+	}
+
+	iap = iarray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jshort *)bp;
+		iap++;
+		bp += sizeof(jshort);
+	}
+
+	(*env)->ReleaseShortArrayElements(env,rarray,iarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns float [] */
+JNIEXPORT jfloatArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToFloat__II_3B 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	char *bp;
+	jbyte *barr;
+	jfloatArray rarray;
+	int blen;
+	jfloat *iarray;
+	jfloat *iap;
+	int ii;
+	jboolean bb;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToFloat: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToFloat: getByte failed?");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+	if ((start < 0) || ((start + (len*(sizeof(jfloat)))) > blen)) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		raiseException( env, "byteToFloat: start or len is out of bounds");
+		return NULL;
+	}
+
+	bp = (char *)barr + start;
+
+	rarray = (*env)->NewFloatArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToFloat" );
+		return NULL;
+	}
+
+	iarray = (*env)->GetFloatArrayElements(env,rarray,&bb);
+	if (iarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToFloat: getFloat failed?");
+		return NULL;
+	}
+
+	iap = iarray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jfloat *)bp;
+		iap++;
+		bp += sizeof(jfloat);
+	}
+
+	(*env)->ReleaseFloatArrayElements(env,rarray,iarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns long [] */
+JNIEXPORT jlongArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToLong__II_3B 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	char *bp;
+	jbyte *barr;
+	jlongArray rarray;
+	int blen;
+	jlong *iarray;
+	jlong *iap;
+	int ii;
+	jboolean bb;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToLong: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToLong: getByte failed?");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+	if ((start < 0) || ((start + (len*(sizeof(jlong)))) > blen)) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		raiseException( env, "byteToLong: start or len is out of bounds");
+		return NULL;
+	}
+
+	bp = (char *)barr + start;
+
+	rarray = (*env)->NewLongArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToLong" );
+		return NULL;
+	}
+
+	iarray = (*env)->GetLongArrayElements(env,rarray,&bb);
+	if (iarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		JNIFatalError( env, "byteToLong: getLong failed?");
+		return NULL;
+	}
+
+	iap = iarray;
+	for (ii = 0; ii < len; ii++) {
+
+		*iap = *(jlong *)bp;
+		iap++;
+		bp += sizeof(jlong);
+	}
+
+	(*env)->ReleaseLongArrayElements(env,rarray,iarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns double [] */
+JNIEXPORT jdoubleArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToDouble__II_3B 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jbyteArray bdata)  /* IN: array of bytes */
+{
+	char *bp;
+	jbyte *barr;
+	jdoubleArray rarray;
+	int blen;
+	jdouble *iarray;
+	jdouble *iap;
+	int ii;
+	jboolean bb;
+
+	if (bdata == NULL) {
+		raiseException( env, "byteToDouble: bdata is NULL?");
+		return NULL;
+	}
+	barr = (*env)->GetByteArrayElements(env,bdata,&bb);
+	if (barr == NULL) {
+		JNIFatalError( env, "byteToDouble: getByte failed?");
+		return NULL;
+	}
+
+	blen = (*env)->GetArrayLength(env,bdata);
+	if ((start < 0) || ((start + (len*(sizeof(jdouble)))) > blen)) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		raiseException( env, "byteToDouble: start or len is out of bounds");
+		return NULL;
+	}
+
+	bp = (char *)barr + start;
+
+	rarray = (*env)->NewDoubleArray(env,len);
+	if (rarray == NULL) {
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		outOfMemory( env, "byteToDouble" );
+		return NULL;
+	}
+
+	iarray = (*env)->GetDoubleArrayElements(env,rarray,&bb);
+	if (iarray == NULL) {
+		JNIFatalError( env, "byteToDouble: getDouble failed?");
+		(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+		return NULL;
+	}
+
+	iap = iarray;
+	for (ii = 0; ii < len; ii++) {
+		*iap = *(jdouble *)bp;
+		iap++;
+		bp += sizeof(jdouble);
+	}
+
+	(*env)->ReleaseDoubleArrayElements(env,rarray,iarray, 0);
+	(*env)->ReleaseByteArrayElements(env,bdata,barr,JNI_ABORT);
+
+	return rarray;
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_intToByte__II_3I 
+(JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jintArray idata)  /* IN: array of int */
+{
+	jint *ip;
+	jint *iarr;
+	int ilen;
+	jbyteArray rarray;
+	int blen;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ii;
+	int ij;
+	union things {
+		int ival;
+		char bytes[4];
+	} u;
+
+	if (idata == NULL) {
+		raiseException( env, "intToByte: idata is NULL?");
+		return NULL;
+	}
+	iarr = (*env)->GetIntArrayElements(env,idata,&bb);
+	if (iarr == NULL) {
+		JNIFatalError( env, "intToByte: getInt failed?");
+		return NULL;
+	}
+
+	ilen = (*env)->GetArrayLength(env,idata);
+	if ((start < 0) || (((start + len)) > ilen)) {
+		(*env)->ReleaseIntArrayElements(env,idata,iarr,JNI_ABORT);
+		raiseException( env, "intToByte: start or len is out of bounds");
+		return NULL;
+	}
+
+	ip = iarr + start;
+
+	blen = ilen * sizeof(jint);
+	rarray = (*env)->NewByteArray(env,blen);
+	if (rarray == NULL) {
+		(*env)->ReleaseIntArrayElements(env,idata,iarr,JNI_ABORT);
+		outOfMemory( env, "intToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		(*env)->ReleaseIntArrayElements(env,idata,iarr,JNI_ABORT);
+		JNIFatalError( env, "intToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	for (ii = 0; ii < len; ii++) {
+		u.ival = *ip++;
+		for (ij = 0; ij < sizeof(jint); ij++) {
+			*bap = u.bytes[ij];
+			bap++;
+		}
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,barray, 0);
+	(*env)->ReleaseIntArrayElements(env,idata,iarr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_shortToByte__II_3S 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jshortArray idata)  /* IN: array of short */
+{
+	jshort *ip;
+	jshort *iarr;
+	int ilen;
+	jbyteArray rarray;
+	int blen;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ii;
+	int ij;
+	union things {
+		short ival;
+		char bytes[4];
+	} u;
+
+	if (idata == NULL) {
+		raiseException( env, "shortToByte: idata is NULL?");
+		return NULL;
+	}
+	iarr = (*env)->GetShortArrayElements(env,idata,&bb);
+	if (iarr == NULL) {
+		JNIFatalError( env, "shortToByte: getShort failed?");
+		return NULL;
+	}
+
+	ilen = (*env)->GetArrayLength(env,idata);
+	if ((start < 0) || (((start + len)) > ilen)) {
+		(*env)->ReleaseShortArrayElements(env,idata,iarr,JNI_ABORT);
+		raiseException( env, "shortToByte: start or len is out of bounds");
+		return NULL;
+	}
+
+	ip = iarr + start;
+
+	blen = ilen * sizeof(jshort);
+	rarray = (*env)->NewByteArray(env,blen);
+	if (rarray == NULL) {
+		(*env)->ReleaseShortArrayElements(env,idata,iarr,JNI_ABORT);
+		outOfMemory( env, "shortToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		(*env)->ReleaseShortArrayElements(env,idata,iarr,JNI_ABORT);
+		JNIFatalError( env, "shortToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	for (ii = 0; ii < len; ii++) {
+		u.ival = *ip++;
+		for (ij = 0; ij < sizeof(jshort); ij++) {
+			*bap = u.bytes[ij];
+			bap++;
+		}
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,barray, 0);
+	(*env)->ReleaseShortArrayElements(env,idata,iarr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_floatToByte__II_3F 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jfloatArray idata)  /* IN: array of float */
+{
+	jfloat *ip;
+	jfloat *iarr;
+	int ilen;
+	jbyteArray rarray;
+	int blen;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ii;
+	int ij;
+	union things {
+		float ival;
+		char bytes[4];
+	} u;
+
+	if (idata == NULL) {
+		raiseException( env, "floatToByte: idata is NULL?");
+		return NULL;
+	}
+	iarr = (*env)->GetFloatArrayElements(env,idata,&bb);
+	if (iarr == NULL) {
+		JNIFatalError( env, "floatToByte: getFloat failed?");
+		return NULL;
+	}
+
+	ilen = (*env)->GetArrayLength(env,idata);
+	if ((start < 0) || (((start + len)) > ilen)) {
+		(*env)->ReleaseFloatArrayElements(env,idata,iarr,JNI_ABORT);
+		raiseException( env, "floatToByte: start or len is out of bounds");
+		return NULL;
+	}
+
+	ip = iarr + start;
+
+	blen = ilen * sizeof(jfloat);
+	rarray = (*env)->NewByteArray(env,blen);
+	if (rarray == NULL) {
+		(*env)->ReleaseFloatArrayElements(env,idata,iarr,JNI_ABORT);
+		outOfMemory( env, "floatToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		(*env)->ReleaseFloatArrayElements(env,idata,iarr,JNI_ABORT);
+		JNIFatalError( env, "floatToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	for (ii = 0; ii < len; ii++) {
+		u.ival = *ip++;
+		for (ij = 0; ij < sizeof(jfloat); ij++) {
+			*bap = u.bytes[ij];
+			bap++;
+		}
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,barray, 0);
+	(*env)->ReleaseFloatArrayElements(env,idata,iarr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_doubleToByte__II_3D 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jdoubleArray idata)  /* IN: array of double */
+{
+	jdouble *ip;
+	jdouble *iarr;
+	int ilen;
+	jbyteArray rarray;
+	int blen;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ii;
+	int ij;
+	union things {
+		double ival;
+		char bytes[8];
+	} u;
+
+	if (idata == NULL) {
+		raiseException( env, "doubleToByte: idata is NULL?");
+		return NULL;
+	}
+	iarr = (*env)->GetDoubleArrayElements(env,idata,&bb);
+	if (iarr == NULL) {
+		JNIFatalError( env, "doubleToByte: getDouble failed?");
+		return NULL;
+	}
+
+	ilen = (*env)->GetArrayLength(env,idata);
+	if ((start < 0) || (((start + len)) > ilen)) {
+		(*env)->ReleaseDoubleArrayElements(env,idata,iarr,JNI_ABORT);
+		raiseException( env, "doubleToByte: start or len is out of bounds");
+		return NULL;
+	}
+
+	ip = iarr + start;
+
+	blen = ilen * sizeof(jdouble);
+	rarray = (*env)->NewByteArray(env,blen);
+	if (rarray == NULL) {
+		(*env)->ReleaseDoubleArrayElements(env,idata,iarr,JNI_ABORT);
+		outOfMemory( env, "doubleToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		(*env)->ReleaseDoubleArrayElements(env,idata,iarr,JNI_ABORT);
+		JNIFatalError( env, "doubleToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	for (ii = 0; ii < len; ii++) {
+		u.ival = *ip++;
+		for (ij = 0; ij < sizeof(jdouble); ij++) {
+			*bap = u.bytes[ij];
+			bap++;
+		}
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,barray, 0);
+	(*env)->ReleaseDoubleArrayElements(env,idata,iarr,JNI_ABORT);
+
+	return rarray;
+
+}
+
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_longToByte__II_3J 
+( JNIEnv *env,
+jclass class, 
+jint start,
+jint len,
+jlongArray idata)  /* IN: array of long */
+{
+	jlong *ip;
+	jlong *iarr;
+	int ilen;
+	jbyteArray rarray;
+	int blen;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ii;
+	int ij;
+	union things {
+		jlong ival;
+		char bytes[8];
+	} u;
+
+	if (idata == NULL) {
+		raiseException( env, "longToByte: idata is NULL?");
+		return NULL;
+	}
+	iarr = (*env)->GetLongArrayElements(env,idata,&bb);
+	if (iarr == NULL) {
+		JNIFatalError( env, "longToByte: getLong failed?");
+		return NULL;
+	}
+
+	ilen = (*env)->GetArrayLength(env,idata);
+	if ((start < 0) || (((start + len)) > ilen)) {
+		(*env)->ReleaseLongArrayElements(env,idata,iarr,JNI_ABORT);
+		raiseException( env, "longToByte: start or len is out of bounds?\n");
+		return NULL;
+	}
+
+	ip = iarr + start;
+
+	blen = ilen * sizeof(jlong);
+	rarray = (*env)->NewByteArray(env,blen);
+	if (rarray == NULL) {
+		(*env)->ReleaseLongArrayElements(env,idata,iarr,JNI_ABORT);
+		outOfMemory( env, "longToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		(*env)->ReleaseLongArrayElements(env,idata,iarr,JNI_ABORT);
+		JNIFatalError( env, "longToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	for (ii = 0; ii < len; ii++) {
+		u.ival = *ip++;
+		for (ij = 0; ij < sizeof(jlong); ij++) {
+			*bap = u.bytes[ij];
+			bap++;
+		}
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,barray, 0);
+	(*env)->ReleaseLongArrayElements(env,idata,iarr,JNI_ABORT);
+
+	return rarray;
+
+}
+ /******/
+
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_intToByte__I 
+( JNIEnv *env,
+jclass class, 
+jint idata)  /* IN: int */
+{
+	jbyteArray rarray;
+	jbyte *barray;
+	jbyte *bap;
+	int ij;
+	jboolean bb;
+	union things {
+		int ival;
+		char bytes[sizeof(int)];
+	} u;
+
+	rarray = (*env)->NewByteArray(env,sizeof(jint));
+	if (rarray == NULL) {
+		outOfMemory( env, "intToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		JNIFatalError( env, "intToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	u.ival = idata;
+	for (ij = 0; ij < sizeof(jint); ij++) {
+		*bap = u.bytes[ij];
+		bap++;
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,barray, 0);
+	return rarray;
+
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_floatToByte__F 
+( JNIEnv *env,
+jclass class, 
+jfloat idata)  /* IN: int */
+{
+	jbyteArray rarray;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ij;
+	union things {
+		float ival;
+		char bytes[sizeof(float)];
+	} u;
+
+	rarray = (*env)->NewByteArray(env,sizeof(jfloat));
+	if (rarray == NULL) {
+		outOfMemory( env, "floatToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		JNIFatalError( env, "floatToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	u.ival = idata;
+	for (ij = 0; ij < sizeof(jfloat); ij++) {
+		*bap = u.bytes[ij];
+		bap++;
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,(jbyte *)barray, 0);
+	return rarray;
+
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_shortToByte__S 
+( JNIEnv *env,
+jclass class, 
+jshort idata)  /* IN: short */
+{
+	jbyteArray rarray;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ij;
+	union things {
+		short ival;
+		char bytes[sizeof(short)];
+	} u;
+
+	rarray = (*env)->NewByteArray(env,sizeof(jshort));
+	if (rarray == NULL) {
+		outOfMemory( env, "shortToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		JNIFatalError( env, "shortToByte: getShort failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	u.ival = idata;
+	for (ij = 0; ij < sizeof(jshort); ij++) {
+		*bap = u.bytes[ij];
+		bap++;
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,(jbyte *)barray, 0);
+
+	return rarray;
+
+}
+
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_doubleToByte__D 
+( JNIEnv *env,
+jclass class, 
+jdouble idata)  /* IN: double */
+{
+	jbyteArray rarray;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ij;
+	union things {
+		double ival;
+		char bytes[sizeof(double)];
+	} u;
+
+	rarray = (*env)->NewByteArray(env,sizeof(jdouble));
+	if (rarray == NULL) {
+		outOfMemory( env, "doubleToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		JNIFatalError( env, "doubleToByte: getDouble failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	u.ival = idata;
+	for (ij = 0; ij < sizeof(jdouble); ij++) {
+		*bap = u.bytes[ij];
+		bap++;
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,(jbyte *)barray, 0);
+
+	return rarray;
+}
+
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_longToByte__J 
+( JNIEnv *env,
+jclass class, 
+jlong idata)  /* IN: array of long */
+{
+	jbyteArray rarray;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ij;
+	union things {
+		jlong ival;
+		char bytes[sizeof(jlong)];
+	} u;
+
+	rarray = (*env)->NewByteArray(env,sizeof(jlong));
+	if (rarray == NULL) {
+		outOfMemory( env, "longToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		JNIFatalError( env, "longToByte: getLong failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	u.ival = idata;
+	for (ij = 0; ij < sizeof(jlong); ij++) {
+		*bap = u.bytes[ij];
+		bap++;
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,(jbyte *)barray, 0);
+
+	return rarray;
+
+}
+
+/* returns byte [] */
+JNIEXPORT jbyteArray JNICALL Java_ncsa_hdf_hdflib_HDFNativeData_byteToByte__B 
+( JNIEnv *env,
+jclass class, 
+jbyte idata)  /* IN: array of long */
+{
+	jbyteArray rarray;
+	jbyte *barray;
+	jbyte *bap;
+	jboolean bb;
+	int ij;
+	union things {
+		jbyte ival;
+		char bytes[sizeof(jbyte)];
+	} u;
+
+	rarray = (*env)->NewByteArray(env,sizeof(jbyte));
+	if (rarray == NULL) {
+		outOfMemory( env, "byteToByte" );
+		return NULL;
+	}
+
+	barray = (*env)->GetByteArrayElements(env,rarray,&bb);
+	if (barray == NULL) {
+		JNIFatalError( env, "byteToByte: getByte failed?");
+		return NULL;
+	}
+
+	bap = barray;
+	u.ival = idata;
+	for (ij = 0; ij < sizeof(jbyte); ij++) {
+		*bap = u.bytes[ij];
+		bap++;
+	}
+
+	(*env)->ReleaseByteArrayElements(env,rarray,(jbyte *)barray, 0);
+
+	return rarray;
+}
diff --git a/bindings/java/ncsa/hdf/hdflib/HDFArray.java b/bindings/java/ncsa/hdf/hdflib/HDFArray.java
new file mode 100644
index 0000000..25f92fd
--- /dev/null
+++ b/bindings/java/ncsa/hdf/hdflib/HDFArray.java
@@ -0,0 +1,850 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  This is a class for handling multidimensional arrays for
+ *  HDF.
+ *  <p>
+ *  The purpose is to allow the storage and retrieval of
+ *  arbitrary array types containing scientific data.
+ *  <p>
+ *  The methods support the conversion of an array to and
+ *  from Java to a one-dimensional array of bytes suitable
+ *  for I/O by the C library.
+ *  <p>
+ *  This class heavily uses the <a href="./ncsa.hdf.hdflib.HDFNativeData.html">HDFNativeData</a>
+ *  class to convert between Java and C representations.
+ */
+
+public class HDFArray {
+
+private Object _theArray = null;
+private ArrayDescriptor _desc = null;
+private byte [] _barray = null;
+
+public HDFArray(Object anArray) throws HDFException {
+
+	if (anArray == null) {
+		HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: array is null?: ");
+ex.printStackTrace();
+	}
+	Class tc = anArray.getClass();
+        if (tc.isArray() == false) {
+                /* exception: not an array */
+		HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: not an array?: ");
+ex.printStackTrace();
+		throw(ex);
+        }
+	_theArray = anArray;
+	_desc = new ArrayDescriptor( _theArray );
+
+	/* extra error checking -- probably not needed */
+	if (_desc == null ) {
+		HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: internal error: array description failed?: ");
+		throw(ex);
+	}
+}
+
+/**
+ *  allocate a one-dimensional array of bytes sufficient to store
+ *  the array.
+ *  @exception HDFException .
+ */
+
+public byte[] emptyBytes()
+throws HDFException
+{
+	byte[] b = null;
+	if (_desc.dims == 1 && _desc.NT == 'B') {
+		b = (byte [])_theArray;
+	} else {
+		b = new byte[_desc.totalSize];
+	}
+	if (b == null) {
+                System.out.println("Error:  HDFArray can't allocate bytes for array");
+ HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: emptyBytes: allocation failed");
+                        throw(ex);
+	}
+	return (b);
+	//return (new byte[_desc.totalSize]);
+}
+
+/**
+ *  Given a Java array of numbers, convert it to a one-dimensional
+ *  array of bytes in correct native order.
+ *
+ *  @exception ncsa.hdf.hdflib.HDFException 
+ *             thrown for errors: 
+ *		object is not array:  HDFJavaException
+ */
+public byte[] byteify() throws HDFException{
+
+	if (_barray != null) return _barray;
+	if (_theArray == null) {
+                /* exception: not an array */
+		 HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: byteify not an array?: ");
+		throw(ex);
+        }
+
+	if (_desc.dims == 1) {
+		/* special case */
+		if (_desc.NT == 'B') {
+			/* really special case! */
+			_barray = (byte [])_theArray;
+			return _barray;
+		} else {
+			try {
+			_barray = new byte[_desc.totalSize];
+
+			byte [] therow;
+			if (_desc.NT == 'I') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.intToByte(0,_desc.dimlen[1],(int [])_theArray);
+			} else if (_desc.NT == 'S') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.shortToByte(0,_desc.dimlen[1],(short [])_theArray);
+			} else if (_desc.NT == 'F') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.floatToByte(0,_desc.dimlen[1],(float [])_theArray);
+			} else if (_desc.NT == 'J') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.longToByte(0,_desc.dimlen[1],(long [])_theArray);
+			} else if (_desc.NT == 'D') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.doubleToByte(0,_desc.dimlen[1],(double [])_theArray);
+			} else if (_desc.NT == 'L') {
+				if (_desc.className.equals("java.lang.Byte")) {
+					therow = ByteObjToByte((Byte[])_theArray);
+				} else if (_desc.className.equals("java.lang.Integer")) {
+					therow = IntegerToByte((Integer[])_theArray);
+				} else if (_desc.className.equals("java.lang.Short")) {
+					therow = ShortToByte((Short[])_theArray);
+				} else if (_desc.className.equals("java.lang.Float")) {
+					therow = FloatObjToByte((Float[])_theArray);
+				} else if (_desc.className.equals("java.lang.Double")) {
+					therow = DoubleObjToByte((Double[])_theArray);
+				} else if (_desc.className.equals("java.lang.Long")) {
+					therow = LongObjToByte((Long[])_theArray);
+				} else {
+					 HDFJavaException ex =
+						new HDFJavaException("HDFArray: unknown type of Object?");
+					 throw(ex);
+				}
+			} else {
+				HDFJavaException ex =
+					new HDFJavaException("HDFArray: unknown type of Object?");
+				throw(ex);
+			}
+			System.arraycopy(therow,0,_barray,0,(_desc.dimlen[1] * _desc.NTsize));
+			return _barray;
+			} catch (OutOfMemoryError err) {
+				 HDFException ex =
+				(HDFException)new HDFJavaException("HDFArray: byteify array too big?");
+				ex.printStackTrace();
+				throw(ex);
+			}
+		}
+	}
+
+	try {
+		_barray = new byte[_desc.totalSize];
+        } catch (OutOfMemoryError err) {
+	 HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: byteify array too big?");
+		ex.printStackTrace();
+                        throw(ex);
+	}
+
+
+	Object oo = _theArray;
+	int n = 0;  /* the current byte */
+	int index = 0;
+	int i;
+	while ( n < _desc.totalSize ) {
+		oo = _desc.objs[0];
+		index = n / _desc.bytetoindex[0];
+                index %= _desc.dimlen[0];
+		for (i = 0 ; i < (_desc.dims); i++) {
+			index = n / _desc.bytetoindex[i];
+			index %= _desc.dimlen[i];
+
+			if (index == _desc.currentindex[i]) {
+				/* then use cached copy */
+				oo = _desc.objs[i];
+			} else {
+				/* check range of index */		
+				if (index > (_desc.dimlen[i] - 1)) {
+					System.out.println("out of bounds?");
+					return null;
+				}
+				oo = java.lang.reflect.Array.get((Object) oo,index);
+				_desc.currentindex[i] = index;
+				_desc.objs[i] = oo;
+			}
+		}
+
+		/* byte-ify */
+		byte arow[];
+		try {
+		if (_desc.NT == 'J') {
+			arow = ncsa.hdf.hdflib.HDFNativeData.longToByte(0,_desc.dimlen[_desc.dims],(long [])_desc.objs[_desc.dims - 1]);
+			arow = ncsa.hdf.hdflib.HDFNativeData.longToByte(0,_desc.dimlen[_desc.dims],(long [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'I') {
+			arow = ncsa.hdf.hdflib.HDFNativeData.intToByte(0,_desc.dimlen[_desc.dims],(int [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'S') {
+			arow = ncsa.hdf.hdflib.HDFNativeData.shortToByte(0,_desc.dimlen[_desc.dims],(short [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'B') {
+			arow = (byte [])_desc.objs[_desc.dims - 1];
+		} else if (_desc.NT == 'F') {
+			/* 32 bit float */
+			arow = ncsa.hdf.hdflib.HDFNativeData.floatToByte(0,_desc.dimlen[_desc.dims],(float [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'D') {
+			/* 64 bit float */
+			arow = ncsa.hdf.hdflib.HDFNativeData.doubleToByte(0,_desc.dimlen[_desc.dims],(double [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'L') {
+			if (_desc.className.equals("java.lang.Byte")) {
+				arow = ByteObjToByte((Byte[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Integer")) {
+				arow = IntegerToByte((Integer[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Short")) {
+				arow = ShortToByte((Short[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Float")) {
+				arow = FloatObjToByte((Float[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Double")) {
+				arow = DoubleObjToByte((Double[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Long")) {
+				arow = LongObjToByte((Long[])_desc.objs[_desc.dims - 1]);
+			} else {
+				HDFJavaException ex =
+				new HDFJavaException("HDFArray: byteify Object type not implemented?");
+				throw(ex);
+			}
+		} else {
+			HDFJavaException ex =
+			new HDFJavaException("HDFArray: byteify Object type not implemented?");
+			throw(ex);
+		}
+		System.arraycopy(arow,0,_barray,n,(_desc.dimlen[_desc.dims] * _desc.NTsize));
+		n += _desc.bytetoindex[_desc.dims - 1];
+		} catch (OutOfMemoryError err) {
+		 HDFException ex =
+			(HDFException)new HDFJavaException("HDFArray: byteify array too big?");
+			ex.printStackTrace();
+			throw(ex);
+		}
+	}
+/* assert:  the whole array is completed--currentindex should == len - 1 */
+
+	/* error checks */
+
+	if (n < _desc.totalSize) {
+		throw new java.lang.InternalError(
+		new String("HDFArray:::byteify: Panic didn't complete all input data: n=  "+n+" size = "+_desc.totalSize));
+	}
+	for (i = 0;i < _desc.dims; i++) {
+		if (_desc.currentindex[i] != _desc.dimlen[i] - 1) {
+			throw new java.lang.InternalError(
+			new String("Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i] - 1)+" ?)"));
+		}
+	}
+	return _barray;
+}
+
+/**
+ *  Given a one-dimensional array of numbers, convert it to a java
+ *  array of the shape and size passed to the constructor.
+ *
+ *  @exception ncsa.hdf.hdflib.HDFException 
+ *             thrown for errors: 
+ *		object not an array:  HDFJavaException 
+ */
+public Object arrayify(byte[] bytes) throws HDFException {
+
+	if (_theArray == null) {
+                /* exception: not an array */
+		 HDFException ex = 
+		(HDFException)new HDFJavaException("arrayify: not an array?: "); 
+		throw(ex); 
+	} 
+
+	if (java.lang.reflect.Array.getLength((Object) bytes) != _desc.totalSize) { 
+		/* exception: array not right size */ 
+		 HDFException ex = 
+		(HDFException)new HDFJavaException("arrayify: array is wrong size?: "); 
+	} 
+	_barray = bytes; /* hope that the bytes are correct.... */ 
+	if (_desc.dims == 1) {
+		/* special case */
+		/* 2 data copies here! */
+		try {
+		if (_desc.NT == 'I') {
+			int [] x = (int [])ncsa.hdf.hdflib.HDFNativeData.byteToInt(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'S') {
+			short [] x = ncsa.hdf.hdflib.HDFNativeData.byteToShort(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'F') {
+			float x[] = ncsa.hdf.hdflib.HDFNativeData.byteToFloat(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'J') {
+			long x[] = ncsa.hdf.hdflib.HDFNativeData.byteToLong(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'D') {
+			double x[] = ncsa.hdf.hdflib.HDFNativeData.byteToDouble(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'B') {
+			System.arraycopy(_barray,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'L') {
+			if (_desc.className.equals("java.lang.Byte")) {
+				Byte I[] = ByteToByteObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Integer")) {
+				Integer I[] = ByteToInteger(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Short")) {
+				Short I[] = ByteToShort(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Float")) {
+				Float I[] = ByteToFloatObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Double")) {
+				Double I[] = ByteToDoubleObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Long")) {
+				Long I[] = ByteToLongObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else {
+			HDFJavaException ex =
+			new HDFJavaException("arrayify:  Object type not implemented yet...");
+			throw(ex); 
+			}
+		} else {
+			HDFJavaException ex =
+			new HDFJavaException("arrayify:  Object type not implemented yet...");
+			throw(ex); 
+		}
+		} catch (OutOfMemoryError err) {
+		 HDFException ex =
+			(HDFException)new HDFJavaException("HDFArray: arrayify array too big?");
+			ex.printStackTrace();
+			throw(ex);
+		}
+	}
+	/* Assert dims >= 2 */
+
+	Object oo = _theArray;
+	int n = 0;  /* the current byte */
+	int index = 0;
+	int i;
+	while ( n < _desc.totalSize ) {
+		oo = _desc.objs[0];
+		index = n / _desc.bytetoindex[0];
+		index %= _desc.dimlen[0];
+		for (i = 0 ; i < (_desc.dims); i++) {
+			index = n / _desc.bytetoindex[i];
+			index %= _desc.dimlen[i];
+
+			if (index == _desc.currentindex[i]) {
+				/* then use cached copy */
+				oo = _desc.objs[i];
+			} else {
+				/* check range of index */		
+				if (index > (_desc.dimlen[i] - 1)) {
+					System.out.println("out of bounds?");
+					return null;
+				}
+				oo = java.lang.reflect.Array.get((Object) oo,index);
+				_desc.currentindex[i] = index;
+				_desc.objs[i] = oo;
+			}
+		}
+
+		/* array-ify */
+		try {
+		if (_desc.NT == 'J') {
+			long [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToLong(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'I') {
+			int [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToInt(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'S') {
+			short [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToShort(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'B') {
+			System.arraycopy( _barray, n, _desc.objs[_desc.dims - 1], 0, _desc.dimlen[_desc.dims]);
+			n += _desc.bytetoindex[_desc.dims - 1];
+		} else if (_desc.NT == 'F') {
+			float arow[] = ncsa.hdf.hdflib.HDFNativeData.byteToFloat(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'D') {
+			double [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToDouble(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'L') {
+			if (_desc.className.equals("java.lang.Byte")) {
+				Byte I[] = ByteToByteObj(n,_desc.dimlen[_desc.dims],_barray);
+		java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+			(_desc.currentindex[_desc.dims - 1]), 
+			(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Integer")) {
+				Integer I[] = ByteToInteger(n,_desc.dimlen[_desc.dims],_barray);
+		java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+			(_desc.currentindex[_desc.dims - 1]), 
+			(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Short")) {
+				Short I[] = ByteToShort(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Float")) {
+				Float I[] = ByteToFloatObj(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Double")) {
+				Double I[] = ByteToDoubleObj(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Long")) {
+				Long I[] = ByteToLongObj(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else {
+			HDFJavaException ex =
+			new HDFJavaException("HDFArray: unsupported Object type: "+_desc.NT);
+			throw(ex);
+			}
+		} else {
+			HDFJavaException ex =
+			new HDFJavaException("HDFArray: unsupported Object type: "+_desc.NT);
+			throw(ex);
+		}
+		} catch (OutOfMemoryError err) {
+		 HDFException ex =
+			(HDFException)new HDFJavaException("HDFArray: arrayify array too big?");
+			ex.printStackTrace();
+			throw(ex);
+		}
+
+	}
+
+/* assert:  the whole array is completed--currentindex should == len - 1 */
+
+	/* error checks */
+
+	if (n < _desc.totalSize) {
+		throw new java.lang.InternalError(
+	       new String("HDFArray::arrayify Panic didn't complete all input data: n=  "+n+" size = "+_desc.totalSize));
+	}
+	for (i = 0;i <= _desc.dims-2; i++) {
+		if (_desc.currentindex[i] != _desc.dimlen[i] - 1) {
+		throw new java.lang.InternalError(
+			new String("HDFArray::arrayify Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i] - 1)+"?"));
+		}
+	}
+	if (_desc.NT != 'B') {
+	if (_desc.currentindex[_desc.dims - 1] != _desc.dimlen[_desc.dims - 1]) {
+		throw new java.lang.InternalError(
+		new String("HDFArray::arrayify Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i])+"?"));
+	}
+	} else {
+	if (_desc.currentindex[_desc.dims - 1] != (_desc.dimlen[_desc.dims - 1] - 1)) {
+		throw new java.lang.InternalError(
+		new String("HDFArray::arrayify Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i] - 1)+"?"));
+	}
+	}
+
+	return _theArray;
+}
+
+private byte[] IntegerToByte( Integer in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	int[] out = new int[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].intValue();
+	}
+	return  HDFNativeData.intToByte(0,nelems,out);
+}
+
+private Integer[] ByteToInteger( byte[] bin ) {
+	int in[] = (int [])HDFNativeData.byteToInt(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Integer[] out = new Integer[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Integer(in[i]);
+	}
+	return  out;
+}
+private Integer[] ByteToInteger( int start, int len, byte[] bin ) {
+	int in[] = (int [])HDFNativeData.byteToInt(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Integer[] out = new Integer[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Integer(in[i]);
+	}
+	return  out;
+}
+
+
+private byte[] ShortToByte( Short in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	short[] out = new short[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].shortValue();
+	}
+	return  HDFNativeData.shortToByte(0,nelems,out);
+}
+
+private Short[] ByteToShort( byte[] bin ) {
+	short in[] = (short [])HDFNativeData.byteToShort(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Short[] out = new Short[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Short(in[i]);
+	}
+	return  out;
+}
+
+private Short[] ByteToShort( int start, int len, byte[] bin ) {
+	short in[] = (short [])HDFNativeData.byteToShort(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Short[] out = new Short[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Short(in[i]);
+	}
+	return  out;
+}
+
+private byte[] ByteObjToByte( Byte in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	byte[] out = new byte[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].byteValue();
+	}
+	return out;
+}
+
+private Byte[] ByteToByteObj( byte[] bin ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)bin);
+	Byte[] out = new Byte[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Byte(bin[i]);
+	}
+	return  out;
+}
+
+private Byte[] ByteToByteObj( int start, int len, byte[] bin ) {
+	Byte[] out = new Byte[len];
+
+	for (int i = 0; i < len; i++) {
+		out[i] = new Byte(bin[i]);
+	}
+	return  out;
+}
+
+private byte[] FloatObjToByte( Float in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	float[] out = new float[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].floatValue();
+	}
+	return  HDFNativeData.floatToByte(0,nelems,out);
+}
+
+private Float[] ByteToFloatObj( byte[] bin ) {
+	float in[] = (float [])HDFNativeData.byteToFloat(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Float[] out = new Float[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Float(in[i]);
+	}
+	return  out;
+}
+
+private Float[] ByteToFloatObj( int start, int len, byte[] bin ) {
+	float in[] = (float [])HDFNativeData.byteToFloat(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Float[] out = new Float[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Float(in[i]);
+	}
+	return  out;
+}
+
+private byte[] DoubleObjToByte( Double in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	double[] out = new double[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].doubleValue();
+	}
+	return  HDFNativeData.doubleToByte(0,nelems,out);
+}
+
+private Double[] ByteToDoubleObj( byte[] bin ) {
+	double in[] = (double [])HDFNativeData.byteToDouble(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Double[] out = new Double[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Double(in[i]);
+	}
+	return  out;
+}
+
+private Double[] ByteToDoubleObj( int start, int len, byte[] bin ) {
+	double in[] = (double [])HDFNativeData.byteToDouble(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Double[] out = new Double[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Double(in[i]);
+	}
+	return  out;
+}
+
+private byte[] LongObjToByte( Long in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	long[] out = new long[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].longValue();
+	}
+	return  HDFNativeData.longToByte(0,nelems,out);
+}
+
+private Long[] ByteToLongObj( byte[] bin ) {
+	long in[] = (long [])HDFNativeData.byteToLong(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Long[] out = new Long[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Long(in[i]);
+	}
+	return  out;
+}
+
+private Long[] ByteToLongObj( int start, int len, byte[] bin ) {
+	long in[] = (long [])HDFNativeData.byteToLong(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Long[] out = new Long[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Long(in[i]);
+	}
+	return  out;
+}
+
+}
+
+
+/**
+  * This class is used by HDFArray to discover the shape and type of an
+  * arbitrary array.
+  */
+
+class ArrayDescriptor {
+
+	static String theType = "";
+	static Class theClass = null;
+        static int [] dimlen = null;
+        static int [] dimstart = null;
+        static int [] currentindex = null;
+        static int [] bytetoindex = null;
+	static int totalSize = 0;
+        static Object [] objs = null;
+	static char NT = ' ';  /*  must be B,S,I,L,F,D, else error */
+        static int NTsize = 0;
+	static int dims = 0;
+	static String className;
+
+	public ArrayDescriptor ( Object anArray ) throws HDFException {
+
+		Class tc = anArray.getClass();
+		if (tc.isArray() == false) {
+			/* exception: not an array */
+			 HDFException ex =
+		(HDFException)new HDFJavaException("ArrayDescriptor: not an array?: ");
+			throw(ex);
+		}
+
+		theClass = tc;
+
+		/* parse the type descriptor to discover the
+			shape of the array */
+		String ss = tc.toString();
+		theType = ss;
+		int n = 6;
+		dims = 0;
+		char c = ' ';
+		while (n < ss.length()) {
+			c = ss.charAt(n);
+			n++;
+			if (c == '[') {
+				dims++;
+			}
+		}
+
+		String css = ss.substring(ss.lastIndexOf('[')+1);
+		Class compC = tc.getComponentType();
+		String cs = compC.toString();
+		NT = c;
+		if (NT == 'B') {
+			NTsize = 1;
+		} else if (NT == 'S') {
+			NTsize = 2;
+		} else if ((NT == 'I') || (NT == 'F')) {
+			NTsize = 4;
+		} else if ((NT == 'J') || (NT == 'D')){
+			NTsize = 8;
+		} else if (css.startsWith("Ljava.lang.Byte")) {
+			NT='L';
+			className = "java.lang.Byte";
+			NTsize = 1;
+		} else if (css.startsWith("Ljava.lang.Short")) {
+			NT='L';
+			className = "java.lang.Short";
+			NTsize = 2;
+		} else if (css.startsWith("Ljava.lang.Integer")) {
+			NT='L';
+			className = "java.lang.Integer";
+			NTsize = 4;
+		} else if (css.startsWith("Ljava.lang.Float")) {
+			NT='L';
+			className = "java.lang.Float";
+			NTsize = 4;
+		} else if (css.startsWith("Ljava.lang.Double")) {
+			NT='L';
+			className = "java.lang.Double";
+			NTsize = 8;
+		} else if (css.startsWith("Ljava.lang.Long")) {
+			NT='L';
+			className = "java.lang.Long";
+			NTsize = 8;
+		} else if (css.startsWith("Ljava.lang.String")) {
+throw new HDFJavaException(new String("ArrayDesciptor: Error:  String array not supported yet"));
+		} else {
+			/* exception:  not a numeric type */
+throw new HDFJavaException(new String("Error:  array is not numeric? (type is "+css+")"));
+		}
+
+		/* fill in the table */
+		dimlen = new int [dims+1];
+		dimstart = new int [dims+1];
+		currentindex = new int [dims+1];
+		bytetoindex = new int [dims+1];
+		objs = new Object [dims+1];
+
+		Object o = anArray;
+		objs[0] = o;
+		dimlen[0]= 1;
+		dimstart[0] = 0;
+		currentindex[0] = 0;
+		int i;
+		for ( i = 1; i <= dims; i++) {
+			dimlen[i]= java.lang.reflect.Array.getLength((Object) o);
+			o = java.lang.reflect.Array.get((Object) o,0);
+			objs [i] = o;
+			dimstart[i] = 0;
+			currentindex[i] = 0;
+		}
+
+		int j;
+		int dd;
+		bytetoindex[dims] = NTsize;
+		for ( i = dims; i >= 0; i--) {
+			dd = NTsize;
+			for (j = i; j < dims; j++) {
+				dd *= dimlen[j + 1];
+			}
+			bytetoindex[i] = dd;
+		}
+
+		totalSize = bytetoindex[0];
+	}
+
+	public void dumpInfo()
+	{
+		System.out.println("Type: "+theType);
+		System.out.println("Class: "+theClass);
+		System.out.println("NT: "+NT+" NTsize: "+NTsize);
+		System.out.println("Array has "+dims+" dimensions ("+totalSize+" bytes)");
+		int i;
+		for (i = 0; i <= dims; i++) {
+			Class tc = objs[i].getClass();
+			String ss = tc.toString();
+			System.out.println(i+":  start "+dimstart[i]+": len "+dimlen[i]+" current "+currentindex[i]+" bytetoindex "+bytetoindex[i]+" object "+objs[i]+" otype "+ss);
+		}
+	}
+}
diff --git a/bindings/java/ncsa/hdf/hdflib/HDFConstants.java b/bindings/java/ncsa/hdf/hdflib/HDFConstants.java
new file mode 100644
index 0000000..5209fb6
--- /dev/null
+++ b/bindings/java/ncsa/hdf/hdflib/HDFConstants.java
@@ -0,0 +1,312 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  This interface defines the values of constants defined
+ *  by the HDF 4.1 API.
+ * <p>
+ *  For details of the HDF libraries, see the HDF Documentation at:
+ *     <a href="http://hdf.ncsa.uiuc.edu">http://hdf.ncsa.uiuc.edu</a>
+ */
+public class HDFConstants
+{
+    /** FAIL */
+    public static final int FAIL = -1;
+
+    // file access code definitions
+    public static final int     DFACC_READ = 1;
+    public static final int     DFACC_WRITE= 2;
+    public static final int     DFACC_RDWR = 3;
+    public static final int     DFACC_CREATE=4;
+    public static final int     DFACC_RDONLY=DFACC_READ;
+    public static final int     DFACC_DEFAULT=000;
+    public static final int     DFACC_SERIAL=001;
+    public static final int     DFACC_PARALLEL=011;
+
+    // annotation type in HDF
+    public static final int     AN_DATA_LABEL  = 0;
+    public static final int     AN_DATA_DESC   = AN_DATA_LABEL + 1;
+    public static final int     AN_FILE_LABEL  = AN_DATA_LABEL + 2;
+    public static final int     AN_FILE_DESC   = AN_DATA_LABEL + 3;
+
+    // HDF Tag Definations
+
+    // HDF WILDCARD
+    public static final int     DFTAG_WILDCARD = 0;
+    public static final int     DFREF_WILDCARD = 0;
+
+    // File identifier
+    public static final int     DFTAG_FID = 100;
+
+    // File Description
+    public static final int     DFTAG_FD  = 101;
+
+    // Data Identifier Label
+    public static final int     DFTAG_DIL = 104;
+
+    // Data Identifier Annotation
+    public static final int     DFTAG_DIA = 105;
+
+    // 8-bits Raster image
+    public static final int     DFTAG_RI8  = 202;
+    public static final int     DFTAG_CI8  = 203;
+    public static final int     DFTAG_II8  = 204;
+
+    // 24-bits Raster image
+    public static final int     DFTAG_RI  = 302;
+    public static final int     DFTAG_CI  = 303;
+    public static final int     DFTAG_RIG = 306;
+
+    // SDS
+    public static final int     DFTAG_SD  = 702;
+    public static final int     DFTAG_SDG  = 700;
+    public static final int     DFTAG_NDG  = 720;
+    
+    // Vgroup or Vdata
+    public static final int     DFTAG_VH  = 1962;
+    public static final int     DFTAG_VS  = 1963;
+    public static final int     DFTAG_VG  = 1965;
+
+    /** pixel interlacing scheme */
+    public static final int MFGR_INTERLACE_PIXEL = 0;
+
+    /** line interlacing scheme */
+    public static final int MFGR_INTERLACE_LINE = MFGR_INTERLACE_PIXEL +1;
+
+    /** component interlacing scheme */ 
+    public static final int MFGR_INTERLACE_COMPONENT = MFGR_INTERLACE_PIXEL +2;
+
+    /** interlacing supported by the vset.*/
+    public static final int FULL_INTERLACE = 0;
+    public static final int NO_INTERLACE   = 1;
+
+    /** unsigned char */
+    public static final int DFNT_UCHAR8 = 3;
+    public static final int DFNT_UCHAR  = 3;
+
+    /** char */
+    public static final int DFNT_CHAR8  = 4;
+    public static final int DFNT_CHAR   = 4;
+
+    /** No supported by HDF */
+    public static final int DFNT_CHAR16 = 42;
+    public static final int DFNT_UCHAR16= 43;
+
+
+    /** float */
+    public static final int  DFNT_FLOAT32   =  5;
+    public static final int  DFNT_FLOAT     =  5 ;
+
+    //** double */
+    public static final int  DFNT_FLOAT64   =  6;
+    public static final int  DFNT_FLOAT128  =  7 ; 
+    public static final int  DFNT_DOUBLE    =  6  ;
+
+    /** 8-bit integer */
+    public static final int  DFNT_INT8      =  20;
+
+    /** unsigned 8-bit interger */
+    public static final int  DFNT_UINT8    =  21;
+
+    /** short */
+    public static final int  DFNT_INT16    =  22;
+
+    /** unsigned interger */
+    public static final int  DFNT_UINT16   =  23;
+
+    /** interger */
+    public static final int  DFNT_INT32    =  24;
+
+    /** unsigned interger */
+    public static final int  DFNT_UINT32   =  25;
+
+    /** No supported */
+    public static final int  DFNT_INT64    =  26;
+    public static final int  DFNT_UINT64   =  27;
+    public static final int  DFNT_INT128   =  28;
+    public static final int  DFNT_UINT128  =  30;
+    public static final int  DFNT_LITEND =  0x00004000;
+
+    public static final int DF_FORWARD  = 1;
+    public static final int  DFS_MAXLEN = 255;
+
+    public static final int COMP_NONE     =  0;
+    public static final int COMP_JPEG     =  2;
+    public static final int COMP_RLE      =  11;
+    public static final int COMP_IMCOMP   =  12;
+    public static final int COMP_CODE_NONE     =  0;
+    public static final int COMP_CODE_RLE     =  1;
+    public static final int COMP_CODE_NBIT     =  2;
+    public static final int COMP_CODE_SKPHUFF  =  3; 
+    public static final int COMP_CODE_DEFLATE  =  4;
+    public static final int COMP_CODE_INVALID  =  5;
+    public static final int COMP_MODEL_STDIO  =  0;
+
+    // Interlace schemes
+    public static final int DFIL_PIXEL  = 0;  /* Pixel Interlacing */
+    public static final int DFIL_LINE   = 1;  /* Scan Line Interlacing */
+    public static final int DFIL_PLANE  = 2;  /* Scan Plane Interlacing */
+
+    public static final int SD_FILL  = 0;  
+    public static final int SD_NOFILL  = 0x100;
+    public static final int SD_DIMVAL_BW_COMP  = 1;  
+    public static final int SD_DIMVAL_BW_INCOMP  = 0;
+
+    public static final int HDF_NONE  = 0x0;
+    public static final int HDF_CHUNK  = 0x1;
+    public static final int HDF_COMP  = 0x3;
+    public static final int HDF_NBIT  = 0x5;
+    public static final int MAX_VAR_DIMS =32;
+
+    //the names of the Vgroups created by the GR interface
+    public static final String GR_NAME = "RIG0.0";
+    public static final String RI_NAME = "RI0.0";
+    public static final String RIGATTRNAME = "RIATTR0.0N";
+    public static final String RIGATTRCLASS = "RIATTR0.0C";
+
+    // names of classes of the Vdatas/Vgroups created by the SD interface 
+    public static final String  HDF_ATTRIBUTE = "Attr0.0";
+    public static final String  HDF_VARIABLE = "Var0.0";
+    public static final String  HDF_DIMENSION = "Dim0.0";
+    public static final String  HDF_UDIMENSION = "UDim0.0";
+    public static final String  DIM_VALS = "DimVal0.0";
+    public static final String  DIM_VALS01 = "DimVal0.1";
+    public static final String  HDF_CHK_TBL = "_HDF_CHK_TBL_";
+    public static final String  HDF_CDF = "CDF0.0";
+
+    // names of data object types
+    public static final String ANNOTATION = "HDF_ANNOTATION";
+    public static final String RI8 = "HDF_RI8";
+    public static final String RI24 = "HDF_RI24";
+    public static final String GR = "HDF_GR";
+    public static final String SDS = "HDF_SDS";
+    public static final String VDATA = "HDF_VDATA";
+    public static final String VGROUP = "HDF_GROUP";
+
+    // data types represented by Strings
+    public static final String UCHAR8   = "UCHAR8";
+    public static final String CHAR8    = "CHAR8";
+    public static final String UCHAR16  = "UCHAR16";
+    public static final String CHAR16   = "CHAR16";
+    public static final String FLOAT32  = "FLOAT32";
+    public static final String FLOAT64  = "FLOAT64";
+    public static final String FLOAT128 = "FLOAT128";
+    public static final String INT8     = "INT8";
+    public static final String UINT8    = "UINT8";
+    public static final String INT16    = "INT16";
+    public static final String UINT16   = "UINT16";
+    public static final String INT32    = "INT32";
+    public static final String UINT32   = "UINT32";
+    public static final String INT64    = "INT64";
+    public static final String UINT64   = "UINT64";
+    public static final String INT128   = "INT128";
+    public static final String UINT128  = "UINT128";
+
+
+    /**
+     *  convert number type to string type
+     *  params type  the number representing the data type
+     *  return the string representing the data type
+     */
+    public static String getType(int type)
+    {
+        if   (type == HDFConstants.DFNT_UCHAR8) return HDFConstants.UCHAR8;
+        else if (type == HDFConstants.DFNT_CHAR8) return HDFConstants.CHAR8;
+        else if (type == HDFConstants.DFNT_UCHAR16) return HDFConstants.UCHAR16;
+        else if (type == HDFConstants.DFNT_CHAR16) return HDFConstants.CHAR16;
+        else if (type == HDFConstants.DFNT_FLOAT32) return HDFConstants.FLOAT32;
+        else if (type == HDFConstants.DFNT_FLOAT64) return HDFConstants.FLOAT64;
+        else if (type == HDFConstants.DFNT_FLOAT128) return HDFConstants.FLOAT128;
+        else if (type == HDFConstants.DFNT_INT8) return HDFConstants.INT8;
+        else if (type == HDFConstants. DFNT_UINT8) return HDFConstants.UINT8;
+        else if (type == HDFConstants.DFNT_INT16) return HDFConstants.INT16;
+        else if (type == HDFConstants.DFNT_UINT16) return HDFConstants.UINT16;
+        else if (type == HDFConstants.DFNT_INT32) return HDFConstants.INT32;
+        else if (type == HDFConstants.DFNT_UINT32) return HDFConstants.UINT32;
+        else if (type == HDFConstants.DFNT_INT64) return HDFConstants.INT64;
+        else if (type == HDFConstants.DFNT_UINT64) return HDFConstants.UINT64;
+        else if (type == HDFConstants.DFNT_INT128) return HDFConstants.INT128;
+        else if (type == HDFConstants.DFNT_UINT128) return HDFConstants.UINT128;
+        else return "Undefined Data Type";
+    }
+
+    /**
+     *  convert string type to number type
+     *  params type  the string representing the data type
+     *  return the integer representing the data type
+     */
+    public static int getType(String type)
+    {
+        if   (type.equalsIgnoreCase(HDFConstants.UCHAR8)) return HDFConstants.DFNT_UCHAR8;
+        else if (type.equalsIgnoreCase(HDFConstants.CHAR8)) return HDFConstants.DFNT_CHAR8;
+        else if (type.equalsIgnoreCase(HDFConstants.UCHAR16)) return HDFConstants.DFNT_UCHAR16;
+        else if (type.equalsIgnoreCase(HDFConstants.CHAR16)) return HDFConstants.DFNT_CHAR16;
+        else if (type.equalsIgnoreCase(HDFConstants.FLOAT32)) return HDFConstants.DFNT_FLOAT32;
+        else if (type.equalsIgnoreCase(HDFConstants.FLOAT64)) return HDFConstants.DFNT_FLOAT64;
+        else if (type.equalsIgnoreCase(HDFConstants.FLOAT128)) return HDFConstants.DFNT_FLOAT128;
+        else if (type.equalsIgnoreCase(HDFConstants.INT8)) return HDFConstants.DFNT_INT8;
+        else if (type.equalsIgnoreCase(HDFConstants. UINT8)) return HDFConstants.DFNT_UINT8;
+        else if (type.equalsIgnoreCase(HDFConstants.INT16)) return HDFConstants.DFNT_INT16;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT16)) return HDFConstants.DFNT_UINT16;
+        else if (type.equalsIgnoreCase(HDFConstants.INT32)) return HDFConstants.DFNT_INT32;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT32)) return HDFConstants.DFNT_UINT32;
+        else if (type.equalsIgnoreCase(HDFConstants.INT64)) return HDFConstants.DFNT_INT64;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT64)) return HDFConstants.DFNT_UINT64;
+        else if (type.equalsIgnoreCase(HDFConstants.INT128)) return HDFConstants.DFNT_INT128;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT128)) return HDFConstants.DFNT_UINT128;
+        else return -1;
+    }
+
+    /**
+     *  gets the size of the data type in bytes,
+     *  e.g size of DFNT_FLOAT32 = 4
+     *
+     *  the size of the data type
+     */
+    public static int getTypeSize(int type)
+    {
+        int size = 0;
+
+        switch(type)
+        {
+            case HDFConstants.DFNT_UCHAR16:
+            case HDFConstants.DFNT_CHAR16:
+            case HDFConstants.DFNT_INT16:
+            case HDFConstants.DFNT_UINT16:
+                size = 2;
+                break;
+            case HDFConstants.DFNT_FLOAT32:
+            case HDFConstants.DFNT_INT32:
+            case HDFConstants.DFNT_UINT32:
+                size = 4;
+                break;
+            case HDFConstants.DFNT_FLOAT64:
+            case HDFConstants.DFNT_INT64:
+            case HDFConstants.DFNT_UINT64:
+                size = 8;
+                break;
+            case HDFConstants.DFNT_FLOAT128:
+            case HDFConstants.DFNT_INT128:
+            case HDFConstants.DFNT_UINT128:
+                size = 16;
+                break;
+            default:
+                size = 1;
+                break;
+        }
+
+        return size;
+    }
+
+}
diff --git a/bindings/java/ncsa/hdf/hdflib/HDFException.java b/bindings/java/ncsa/hdf/hdflib/HDFException.java
new file mode 100644
index 0000000..45904cd
--- /dev/null
+++ b/bindings/java/ncsa/hdf/hdflib/HDFException.java
@@ -0,0 +1,61 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  The class HDFException returns errors from the HDF
+ *  library.
+ *  <p>
+ *  Two sub-classes of HDFException are defined:
+ *  <p>
+ *  <ol>
+ *  <li>
+ *   HDFLibraryException -- errors raised the HDF library code
+ *  <li>
+ *   HDFJavaException -- errors raised the HDF Java wrapper code
+ *  </ol>
+ *  <p>
+ *  These exceptions will be sub-classed to represent specific
+ *  error conditions, as needed.
+ *  <p>
+ *  The only specific exception currently defined is 
+ *  HDFNotImplementedException, indicating a function that is part
+ *  of the HDF API, but which cannot or will not be implemented
+ *  for Java.
+ */
+public class HDFException extends Exception {
+
+	
+	static public final String OutOfMemoryMessage="ERROR: HDF Library: Out of memory";
+	static public final String HDFExceptionMessage="ERROR: HDF Library Error"; 
+	static public final String HDFMessage="ERROR: Unknown HDF Error"; 
+
+	int HDFerror;
+	String msg;
+
+	public HDFException() {
+		HDFerror = 0;
+	}
+
+	public HDFException(String s) {
+		msg = s;
+	}
+
+	public HDFException(int err) {
+		HDFerror = err;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
diff --git a/bindings/java/ncsa/hdf/hdflib/HDFJavaException.java b/bindings/java/ncsa/hdf/hdflib/HDFJavaException.java
new file mode 100644
index 0000000..1afafec
--- /dev/null
+++ b/bindings/java/ncsa/hdf/hdflib/HDFJavaException.java
@@ -0,0 +1,37 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  The class HDFJavaException returns errors from the Java
+ *  wrapper of theHDF library.
+ *  <p>
+ *  These errors include Java configuration errors, security
+ *  violations, and resource exhaustion.
+ */
+public class HDFJavaException extends HDFException {
+
+	String msg;
+
+	public HDFJavaException() {
+		HDFerror = 0;
+	}
+
+	public HDFJavaException(String s) {
+		msg = "HDFLibraryException: "+s;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
diff --git a/bindings/java/ncsa/hdf/hdflib/HDFNativeData.java b/bindings/java/ncsa/hdf/hdflib/HDFNativeData.java
new file mode 100644
index 0000000..1f0b11b
--- /dev/null
+++ b/bindings/java/ncsa/hdf/hdflib/HDFNativeData.java
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+public class HDFNativeData
+{
+    public HDFNativeData() {}
+    public static native int[] byteToInt( byte[] data );
+    public static native float[] byteToFloat( byte[] data );
+    public static native short[] byteToShort( byte[] data );
+    public static native long[] byteToLong( byte[] data );
+    public static native double[] byteToDouble( byte[] data );
+
+    public static native int[] byteToInt( int start, int len, byte[] data );
+    public static int byteToInt( byte[] data, int start)
+    {
+        int []ival = new int[1];
+        ival = byteToInt(start,1,data);
+        return(ival[0]);
+    }
+
+    public static native short[] byteToShort( int start, int len, byte[] data );
+    public static short byteToShort( byte[] data, int start)
+    {
+        short []sval = new short[1];
+        sval = byteToShort(start,1,data);
+        return(sval[0]);
+    }
+
+    public static native float[] byteToFloat( int start, int len, byte[] data );
+    public static float byteToFloat( byte[] data, int start)
+    {
+        float []fval = new float[1];
+        fval = byteToFloat(start,1,data);
+        return(fval[0]);
+    }
+
+    public static native long[] byteToLong( int start, int len, byte[] data );
+    public static long byteToLong( byte[] data, int start)
+    {
+        long []lval = new long[1];
+        lval = byteToLong(start,1,data);
+        return(lval[0]);
+    }
+
+    public static native double[] byteToDouble( int start, int len, byte[] data );
+    public static double byteToDouble( byte[] data, int start)
+    {
+        double []dval = new double[1];
+        dval = byteToDouble(start,1,data);
+        return(dval[0]);
+    }
+
+    public static native byte[] intToByte( int start, int len, int[] data);
+    public static native byte[] shortToByte( int start, int len, short[] data);
+    public static native byte[] floatToByte( int start, int len, float[] data);
+    public static native byte[] longToByte( int start, int len, long[] data);
+    public static native byte[] doubleToByte( int start, int len, double[] data);
+
+    public static native byte[] byteToByte( byte data);
+    static byte[] byteToByte( Byte data){return byteToByte(data.byteValue());}
+    public static native byte[] intToByte( int data);
+    static byte[] intToByte( Integer data){return intToByte(data.intValue());}
+    public static native byte[] shortToByte(short data);
+    static byte[] shortToByte( Short data){return shortToByte(data.shortValue());}
+    public static native byte[] floatToByte( float data);
+    static byte[] floatToByte( Float data){return floatToByte(data.floatValue());};
+    public static native byte[] longToByte( long data);
+    static byte[] longToByte(Long data){ return longToByte(data.longValue());}
+    public static native byte[] doubleToByte( double data);
+    static byte[] doubleToByte( Double data){return doubleToByte(data.doubleValue());}
+
+    public Object byteToNumber( byte[] barray, Object obj)
+        throws HDFException
+    {
+        Class theClass = obj.getClass();
+        String type = theClass.getName();
+        Object retobj = null;
+
+        if (type.equals("java.lang.Integer")) {
+            int[] i = ncsa.hdf.hdflib.HDFNativeData.byteToInt(0,1,barray);
+            retobj = new Integer(i[0]);
+        } else  if (type.equals("java.lang.Byte")) {
+            retobj = new Byte(barray[0]);
+        } else  if (type.equals("java.lang.Short")) {
+            short[] f = ncsa.hdf.hdflib.HDFNativeData.byteToShort(0,1,barray);
+            retobj = new Short(f[0]) ;
+        } else  if (type.equals("java.lang.Float")) {
+            float[] f = ncsa.hdf.hdflib.HDFNativeData.byteToFloat(0,1,barray);
+            retobj = new Float(f[0]) ;
+        } else  if (type.equals("java.lang.Long")) {
+            long[] f = ncsa.hdf.hdflib.HDFNativeData.byteToLong(0,1,barray);
+            retobj = new Long(f[0]) ;
+        } else  if (type.equals("java.lang.Double")) {
+            double[] f = ncsa.hdf.hdflib.HDFNativeData.byteToDouble(0,1,barray);
+            retobj = new Double(f[0] );
+        } else {
+            /* exception: unsupprted type */
+            HDFException ex =
+            (HDFException)new HDFJavaException("byteToNumber: setfield bad type: "+obj+" "+type);
+            throw(ex);
+        }
+        return(retobj);
+    }
+
+    /**
+     *  Allocate a 1D array large enough to hold a multidimensional
+     *  array of 'datasize' elements of 'dataType' numbers.
+     *  This is called from ncsa.hdf.hdfobject.HDFGR and
+     *  ncsa.hdf.hdfobject.HDFSDS, and hdf.ncsa.io.ASCII2HDF
+     *
+     *  @param dataType  the type of the iamge data
+     *  @param datasize  the size of the image data array
+     *  @returns         an array of 'datasize' numbers of 'dataType
+     *
+     *  @see ncsa.hdf.hdfobject.HDFGR 
+     *  @see ncsa.hdf.hdfobject.HDFSDS
+     */
+public static Object defineDataObject(int dataType, int datasize)
+    {
+        Object data = null;
+
+        if ((dataType & HDFConstants.DFNT_LITEND) != 0) {
+          dataType -= HDFConstants.DFNT_LITEND;
+        }
+
+        switch(dataType)
+        {
+            case HDFConstants.DFNT_INT16:
+            case HDFConstants.DFNT_UINT16:
+                data = new short[datasize];
+                break;
+            case HDFConstants.DFNT_INT32:
+            case HDFConstants.DFNT_UINT32:
+                data = new int[datasize];
+                break;
+            case HDFConstants.DFNT_INT64:
+            case HDFConstants.DFNT_UINT64:
+                data = new long[datasize];
+                break;
+            case HDFConstants.DFNT_FLOAT32:
+                data = new float[datasize];
+                break;
+            case HDFConstants.DFNT_FLOAT64:
+                data = new double[datasize];
+                break;
+            default:
+            case HDFConstants.DFNT_CHAR:
+            case HDFConstants.DFNT_UCHAR8:
+            case HDFConstants.DFNT_UINT8:
+            case HDFConstants.DFNT_INT8:
+                data = new byte[datasize];
+                break;
+            
+        }
+        return data;
+    }
+}
diff --git a/bindings/java/ncsa/hdf/hdflib/HDFNotImplementedException.java b/bindings/java/ncsa/hdf/hdflib/HDFNotImplementedException.java
new file mode 100644
index 0000000..73cf322
--- /dev/null
+++ b/bindings/java/ncsa/hdf/hdflib/HDFNotImplementedException.java
@@ -0,0 +1,41 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  HDFNotImplementedException indicates a function that is part
+ *  of the HDF API, but which cannot or will not be implemented
+ *  for Java.
+ *  <p>
+ *  For instance, C routines which take Unix FILE objects
+ *  as parameters are not appropriate for the Java interface
+ *  and will not be implemented.  These routines will raise
+ *  an HDFNotImplementedException.
+ */
+
+public class HDFNotImplementedException  extends HDFJavaException {
+
+	String msg;
+
+	public HDFNotImplementedException() {
+		HDFerror = 0;
+	}
+
+	public HDFNotImplementedException(String s) {
+		msg = "HDFJavaException: HDF function not implmented (yet): "+s;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
diff --git a/bindings/java/org/nexusformat/AttributeEntry.java b/bindings/java/org/nexusformat/AttributeEntry.java
new file mode 100644
index 0000000..e4bb0d6
--- /dev/null
+++ b/bindings/java/org/nexusformat/AttributeEntry.java
@@ -0,0 +1,19 @@
+/**
+  * This is a little helper class which holds additional information about
+  * a dataset or global attribute.
+  *
+  * @author Mark Koennecke, October 2000
+  *
+  * @see NeXusFileInterface.
+  *
+  * copyright: see acompanying COPYRIGHT file.
+  */
+package org.nexusformat;
+
+public class AttributeEntry {
+    /**
+      * length is the length of the attribute.
+      * type is the number type of the attribute.
+      */
+  public int length, type;
+}
diff --git a/bindings/java/org/nexusformat/NXlink.java b/bindings/java/org/nexusformat/NXlink.java
new file mode 100644
index 0000000..3dd12d7
--- /dev/null
+++ b/bindings/java/org/nexusformat/NXlink.java
@@ -0,0 +1,24 @@
+/**
+  * NXlink is a replacement for the structure holding the data necessary
+  * for doing a link in the NeXus-API. Consequently it is primitive.
+  *
+  * Mark Koennecke, October 2000
+  * 
+  * updated for Napi-2.0 with HDF-5
+  * Mark Koennecke, August 2001
+  *
+  * updated for NAPI-3.0 with XML
+  * Mark Koennecke, October 2004
+  *
+  * copyright: see accompanying COPYRIGHT file 
+  */
+package org.nexusformat;
+
+public class NXlink {
+    public int tag, ref, linkType;
+    public String targetPath;
+   
+    public NXlink(){
+       targetPath = new String("");
+    }
+}
diff --git a/bindings/java/org/nexusformat/NeXusFileInterface.java b/bindings/java/org/nexusformat/NeXusFileInterface.java
new file mode 100644
index 0000000..1f28b53
--- /dev/null
+++ b/bindings/java/org/nexusformat/NeXusFileInterface.java
@@ -0,0 +1,440 @@
+/**
+  *
+  * The NeXus-API for Java. NeXus is an attempt to define a common data 
+  * format for org and x-ray diffraction. NeXus is built on top of the
+  * Hierarchical Data Format from NCSA. There exist already API's to
+  * NeXus files for F77, F90, C and C++. This is the interface definition
+  * for a Java API to NeXus files.
+  *
+  * Some changes to the API have been necessary however, due to the 
+  * different calling standards between C and Java. 
+  *
+  *
+  * @author Mark Koennecke, 2000 -- 2011
+  *
+  * copyright: see accompanying COPYRIGHT file
+  */
+package org.nexusformat;
+
+import java.util.Hashtable;
+
+public interface NeXusFileInterface {
+
+    // general functions
+    /**
+      * flush writes all previously unsaved data to disk. All directory
+      * searches are invalidated. Any open SDS is closed.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public void flush() throws NexusException;
+
+    /**
+      * finalize closes the file. It is supposed to be called by the
+      * garbage collector when the object is collected. As this happens
+      * at discretion of the garbage collector it is safer to call finalize
+      * yourself, when a NeXus file needs to be closed. Multiple calls to
+      * finalize do no harm.
+      * @exception Throwable because it is required by the definition of
+      * finalize. 
+      */
+    public void finalize() throws Throwable;
+
+    /**
+     * close the NeXus file. To make javalint and diamond happy
+     * @throws NexusException
+     */
+    public void close() throws NexusException;
+
+    // group functions
+    /** 
+      * makegroup creates a new group below the current group within
+      * the NeXus file hierarchy.
+      * @param name The name of the group to create.
+      * @param nxclass The classname of the group.
+      * @exception NexusException if an error occurs during this operation.
+      */ 
+    public void makegroup(String name, String nxclass) throws 
+                            NexusException;
+    /**
+      * opengroup opens the group name with class nxclass. 
+      * The group must exist, otherwise an exception is thrown. opengroup is
+      * similar to a cd name in a filesystem.
+      * @param name the name of the group to open.
+      * @param nxclass the classname of the group to open. 
+      * @exception NexusException when something goes wrong.
+      */   
+    public void opengroup(String name, String nxclass) throws 
+                             NexusException;
+    /**
+      * openpath opens groups and datsets accroding to the path string
+      * given. The path syntax follows unix conventions. Both absolute
+      * and relative paths are possible. All objects of the path must
+      * exist.
+      * @param path The path string
+      * @exception NexusException when something goes wrong.
+      */   
+    public void openpath(String path) throws NexusException;
+
+    /**
+      * opengrouppath opens groups and datsets accroding to the path string
+      * given. The path syntax follows unix conventions. Both absolute
+      * and relative paths are possible. All objects of the path must
+      * exist. This function stops int the last group.
+      * @param path The path string
+      * @exception NexusException when something goes wrong.
+      */   
+    public void opengrouppath(String path) throws NexusException;
+
+    /**
+     * return the current path into the NeXus file in the 
+     * form of a Unix path string.
+     * @return A unix path string
+     */
+    public String getpath() throws NexusException;
+
+    /**
+      * closegroup closes access to the current group and steps down one
+      * step in group hierarchy.
+      * @exception NexusException when an HDF error occurs during this
+      * operation.
+      */ 
+    public void closegroup() throws NexusException;
+
+    // data set handling
+    /**
+      * makedata creates a new dataset with the specified characteristics 
+      * in the current group.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. Dimension passed as -1 denote an
+      * unlimited dimension.
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void makedata(String name, int type, int rank, int dim[]) 
+	throws NexusException;
+
+    /**
+      * makedata creates a new dataset with the specified characteristics 
+      * in the current group.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. Dimension passed as -1 denote an
+      * unlimited dimension.
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void makedata(String name, int type, int rank, long dim[]) 
+	throws NexusException;
+
+    /**
+      * compmakedata creates a new dataset with the specified characteristics 
+      * in the current group. This data set will be compressed.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. Dimension passed as -1 denote an
+      * unlimited dimension.
+      * @param compression_type determines the compression type. 
+      * @param iChunk With HDF-5, slabs can be written to compressed data 
+      * sets. The size of these slabs is specified through the chunk array.
+      * This must have the rank values for the size of the chunk to
+      * be written in each dimension. 
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void compmakedata(String name, int type, int rank, int dim[],
+             int compression_type, int iChunk[]) throws NexusException; 
+
+    /**
+      * compmakedata creates a new dataset with the specified characteristics 
+      * in the current group. This data set will be compressed.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. Dimension passed as -1 denote an
+      * unlimited dimension.
+      * @param compression_type determines the compression type. 
+      * @param iChunk With HDF-5, slabs can be written to compressed data 
+      * sets. The size of these slabs is specified through the chunk array.
+      * This must have the rank values for the size of the chunk to
+      * be written in each dimension. 
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void compmakedata(String name, int type, int rank, long dim[],
+             int compression_type, long iChunk[]) throws NexusException; 
+
+    /**
+      * opendata opens an existing dataset for access. For instance for 
+      * reading or writing.
+      * @param name The name of the dataset to open.
+      * @exception NexusException when the dataset does not exist or 
+      * something else is wrong.
+      */
+    public void opendata(String name)throws NexusException;
+
+    /**
+      * closedata closes an opened dataset. Then no further access is 
+      * possible without a call to opendata.
+      * @exception NexusException when an HDF error occurrs.
+      */
+    public void closedata() throws NexusException;
+
+    /**
+      * causes the currently open dataset to be compressed on file.
+      * This must be called after makedata and before writing to the
+      * dataset.
+      * @param compression_type determines the type of compression 
+      * to use.
+      * @exception NexusException when no dataset is open or an HDF error 
+      * occurs.
+      */ 
+    public void compress(int compression_type) throws NexusException;
+
+    // data set reading
+    /**
+      * getdata reads the data from an previously openend dataset into
+      * array.
+      * @param array An n-dimensional array of the appropriate number
+      * type for the dataset. Make sure to have the right type and size
+      * here.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getdata(Object array) throws NexusException;
+
+    /**
+      * getslab reads a subset of a large dataset into array.
+      * @param start An array of dimension rank which contains the start 
+      * position in the dataset from where to start reading.
+      * @param size An array of dimension rank which contains the size
+      * in each dimension of the data subset to read.
+      * @param array An array for holding the returned data values.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getslab(int start[], int size[], Object array) throws
+                          NexusException;
+
+    /**
+      * getslab reads a subset of a large dataset into array.
+      * @param start An array of dimension rank which contains the start 
+      * position in the dataset from where to start reading.
+      * @param size An array of dimension rank which contains the size
+      * in each dimension of the data subset to read.
+      * @param array An array for holding the returned data values.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getslab(long start[], long size[], Object array) throws
+                          NexusException;
+
+    /**
+      * getattr retrieves the data associated with the attribute 
+      * name. 
+      * @param name The name of the attribute.
+      * @param data an array with sufficient space for holding the attribute 
+      * data.
+      * @param args An integer array holding the number of data elements
+      * in data as args[0], and the type as args[1]. Both values will be
+      * updated while reading.
+      * @exception NexusException when either an HDF error occurs or 
+      * the attribute could not be found.
+      */
+    public void getattr(String name, Object data, int args[]) throws
+                          NexusException;
+
+    // data set writing
+    /**
+      * putdata writes the data from array into a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @exception NexusException when an HDF error occurs.
+      */
+    public void putdata(Object array) throws NexusException;
+
+    /**
+      * putslab writes a subset of a larger dataset to a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @param start An integer array of dimension rank which holds the
+      * startcoordinates of the data subset in the larger dataset.
+      * @param size An integer array of dimension rank whidh holds the
+      * size in each dimension of the data subset to write.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public void putslab(Object array, int start[], int size[]) throws
+                          NexusException;
+
+    /**
+      * putslab writes a subset of a larger dataset to a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @param start An integer array of dimension rank which holds the
+      * startcoordinates of the data subset in the larger dataset.
+      * @param size An integer array of dimension rank whidh holds the
+      * size in each dimension of the data subset to write.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public void putslab(Object array, long start[], long size[]) throws
+                          NexusException;
+
+    /**
+      * putattr adds a named attribute to a previously opened dataset or
+      * a global attribute if no dataset is open.
+      * @param name The name of the attribute.
+      * @param array The data of the attribute.
+      * @param iType The number type of the attribute.
+      * @exception NexusException if an HDF error occurs.
+      */  
+    public void putattr(String name, Object array, int iType) throws
+                          NexusException;
+
+    // inquiry
+    /**
+      * getinfo retrieves information about a previously opened dataset.
+      * @param iDim An array which will be filled with the size of
+      * the dataset in each dimension.
+      * @param args An integer array which will hold more information about
+      * the dataset after return. The fields: args[0] is the rank, args[1] is
+      * the number type.
+      * @exception NexusException when  an HDF error occurs.
+      */ 
+    public void getinfo(int iDim[], int args[]) throws NexusException;
+
+    /**
+      * getinfo retrieves information about a previously opened dataset.
+      * @param iDim An array which will be filled with the size of
+      * the dataset in each dimension.
+      * @param args An integer array which will hold more information about
+      * the dataset after return. The fields: args[0] is the rank, args[1] is
+      * the number type.
+      * @exception NexusException when  an HDF error occurs.
+      */ 
+    public void getinfo(long iDim[], int args[]) throws NexusException;
+
+    /**
+     * setnumberformat sets the number format for printing number when
+     * using the XML-NeXus format. For HDF4 and HDF5 this is ignored.
+     * If a dataset is open, the format for the dataset is set, if none 
+     * is open the default setting for the number type is changed.
+     * The format must be a ANSII-C language format string.
+     * @param type The NeXus type to set the format for. 
+     * @param format The new format to use.
+     */
+    public void setnumberformat(int type, String format) throws NexusException;
+
+    /**
+      * groupdir will retrieve the content of the currently open vGroup.
+      * groupdir is similar to an ls in unix. 
+      * @return A Hashtable  which will hold the names of the items in 
+      * the group as keys and the NeXus classname for vGroups or the 
+      * string 'SDS' for datasets as values. 
+      * @exception NexusException if an HDF error occurs
+      */
+    public Hashtable groupdir() throws NexusException;
+
+    /**
+      * attrdir returns the attributes of the currently open dataset or
+      * the file global attributes if no dataset is open.
+      * @return A Hashtable which will hold the names of the attributes
+      * as keys. For each key there is an AttributeEntry class as value.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public Hashtable attrdir() throws NexusException;
+    
+    // linking 
+    /**
+      * getgroupID gets the data necessary for linking the current vGroup
+      * somewhere else.
+      * @return A NXlink object holding the link data.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public NXlink getgroupID() throws NexusException;
+
+    /**
+      * getdataID gets the data necessary for linking the current dataset
+      * somewhere else.
+      * @return A NXlink object holding the link data.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public NXlink getdataID()throws NexusException;
+
+    /**
+      * makelink links the object described by target into the current
+      * vGroup.
+      * @param target The Object to link into the current group.
+      * @exception NexusException if an error occurs.
+      */
+    public void makelink(NXlink target)throws NexusException;     
+    /**
+      * makenamedlink links the object described by target into the current
+      * vGroup. The object will have a new name in the group into which it is 
+      * linked
+      * @param target The Object to link into the current group.
+      * @param name The name of this object in the current group
+      * @exception NexusException if an error occurs.
+      */
+    public void makenamedlink(String name, NXlink target) throws NexusException;     
+
+    /**
+      * opensourcepath opens the group from which the current item was linked
+      * Returns an error if the current item is not linked.
+      * @exception NexusException if an error occurs.
+      */
+    public void opensourcepath() throws NexusException;     
+
+    /**
+     * inquirefile inquires which file we are currently in. This is
+     * a support function for external linking
+     * @return The current file
+     * @throws NexusException when things are wrong
+     */
+    public String inquirefile() throws NexusException;
+
+    /** 
+     * linkexternal links group name, nxclass to the URL nxurl
+     * @param name The name of the vgroup to link to
+     * @param nxclass The class name of the linked vgroup
+     * @param nxurl The URL to the linked external file
+     * @throws NexusException if things are wrong
+     */
+    public void linkexternal(String name, String nxclass, String nxurl) throws NexusException;
+
+    /** 
+     * linkexternaldataset links dataset name to the URL nxurl
+     * @param name The name of the dataset to link to
+     * @param nxurl The URL to the linked external file
+     * @throws NexusException if things are wrong
+     */
+    public void linkexternaldataset(String name, String nxurl) throws NexusException;
+
+    /**
+     * nxisexternalgroup test the group name, nxclass if it is linked externally
+     * @param name of the group to test
+     * @param  nxclass class of the group to test
+     * @return null when the group is not linked, else a string giving the URL of the
+     * linked resource
+     * @throws NexusException if things are wrong
+     */
+    public String isexternalgroup(String name, String nxclass) throws NexusException;
+
+    /**
+     * nxisexternaldataset if the named dataset is is linked externally
+     * @param name of the dataset to test
+     * @return null when the it is not linked, else a string giving the URL of the
+     * linked resource
+     * @throws NexusException if things are wrong
+     */
+    public String isexternaldataset(String name) throws NexusException;
+}
diff --git a/bindings/java/org/nexusformat/NexusException.java b/bindings/java/org/nexusformat/NexusException.java
new file mode 100644
index 0000000..ce6fec8
--- /dev/null
+++ b/bindings/java/org/nexusformat/NexusException.java
@@ -0,0 +1,39 @@
+/**
+  * NexusException is thrown whenever an error occurs in the NeXus Java API
+  *
+  * Mark Koennecke, October 2000
+  *
+  * copyright: see accompanying COPYRIGHT file.  
+  */ 
+package org.nexusformat;
+
+public class NexusException extends Exception {
+
+	
+	static public final String OutOfMemoryMessage= 
+                        "ERROR: NeXus-API: Out of memory";
+	static public final String NexusExceptionMessage= 
+                        "ERROR: NeXus-API Error"; 
+	static public final String NeXusMessage=
+                        "ERROR: Unknown NeXus-API Error"; 
+
+	int HDFerror;
+	String msg;
+
+	public NexusException() {
+		HDFerror = 0;
+	}
+
+	public NexusException(String s) {
+		msg = s;
+	}
+
+	public NexusException(int err) {
+		HDFerror = err;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
+
diff --git a/bindings/java/org/nexusformat/NexusFile.java b/bindings/java/org/nexusformat/NexusFile.java
new file mode 100644
index 0000000..20359b1
--- /dev/null
+++ b/bindings/java/org/nexusformat/NexusFile.java
@@ -0,0 +1,686 @@
+/**
+  * @mainpage This is an implementation of
+  * a Java NeXus API using native methods.
+  *
+  * Some changes to the API have been necessary, due to the 
+  * different calling standards between C and Java. 
+  *
+  * @author Mark Koennecke, 2000 -- 2011
+  *
+  * copyright: see accompanying COPYRIGHT file
+  *
+  * @see TestJapi.java
+  * Test program for Java API.
+  * Illustrates using the #org.nexusformat package
+  */
+package org.nexusformat;
+
+import java.util.Hashtable;
+import java.io.File;
+import ncsa.hdf.hdflib.HDFArray;
+import ncsa.hdf.hdflib.HDFException;
+import ncsa.hdf.hdflib.HDFConstants;
+
+public class NexusFile implements NeXusFileInterface {
+
+    // constants 
+    /**
+      * possible access codes, @see #NexusFile.
+      */
+    public final static int NXACC_READ = 1;
+    public final static int NXACC_RDWR = 2;
+    public final static int NXACC_CREATE = 3;
+    public final static int NXACC_CREATE4 = 4;
+    public final static int NXACC_CREATE5 = 5;
+    public final static int NXACC_CREATEXML = 6;
+    public final static int NXACC_NOSTRIP = 128;
+    
+    /**
+      * constant denoting an unlimited dimension.
+      */
+    public final static int NX_UNLIMITED = -1;
+
+    /**
+      * constants for number types. @see #makedata, @see #putattr 
+      * and others.
+      */
+    public final static int NX_FLOAT32 = 5; 
+    public final static int NX_FLOAT64 = 6; 
+    public final static int NX_INT8 = 20; 
+    public final static int NX_BINARY = 20;
+    public final static int NX_UINT8 = 21; 
+    public final static int NX_BOOLEAN = 21; 
+    public final static int NX_INT16 = 22; 
+    public final static int NX_UINT16 = 23; 
+    public final static int NX_INT32 = 24; 
+    public final static int NX_UINT32 = 25; 
+    public final static int NX_INT64 = 26; 
+    public final static int NX_UINT64 = 27; 
+    public final static int NX_CHAR   = 4;
+
+    /**
+      * constants for compression schemes 
+      */
+    public final static int NX_COMP_NONE = 100;
+    /* this one does zlib (deflate), no idea who chose the name */
+    public final static int NX_COMP_LZW =  200;
+    public final static int NX_COMP_RLE =  300; /* hdf4 only */
+    public final static int NX_COMP_HUF =  400; /* hdf4 only */
+
+    public final static int NX_COMP_LZW_LVL0 = (100*NX_COMP_LZW + 0);
+    public final static int NX_COMP_LZW_LVL1 = (100*NX_COMP_LZW + 1);
+    public final static int NX_COMP_LZW_LVL2 = (100*NX_COMP_LZW + 2);
+    public final static int NX_COMP_LZW_LVL3 = (100*NX_COMP_LZW + 3);
+    public final static int NX_COMP_LZW_LVL4 = (100*NX_COMP_LZW + 4);
+    public final static int NX_COMP_LZW_LVL5 = (100*NX_COMP_LZW + 5);
+    public final static int NX_COMP_LZW_LVL6 = (100*NX_COMP_LZW + 6);
+    public final static int NX_COMP_LZW_LVL7 = (100*NX_COMP_LZW + 7);
+    public final static int NX_COMP_LZW_LVL8 = (100*NX_COMP_LZW + 8);
+    public final static int NX_COMP_LZW_LVL9 = (100*NX_COMP_LZW + 9);
+
+    /**
+      * Maximum name length, must be VGNAMELENMAX in hlimits.h
+      */
+    protected final static int MAXNAMELEN = 64;
+
+    /*
+       This code takes care of loading the static library required for
+       this class to work properly. The algorithm first looks for a 
+       property org.nexusformat.JNEXUSLIB and loads that file if available,
+       else it tries to locate the library in the system shared library 
+       path.
+    */
+     static
+     {
+        String filename = null;   
+        filename = System.getProperty("org.nexusformat.JNEXUSLIB",null);
+        if ((filename != null) && (filename.length() > 0))
+        {
+            File hdfdll = new File(filename);
+            if (hdfdll.exists() && hdfdll.canRead() && hdfdll.isFile()) 
+	    {
+                System.load(filename);
+             } else {
+                 throw (new UnsatisfiedLinkError("Invalid JNEXUS library"));
+             }
+         }
+         else {
+            System.loadLibrary("jnexus");
+         }
+      }
+
+    /**
+      * This is the handle to the NeXus file handle.
+      */
+    protected int handle;
+
+    // Construction
+    // native methods for this section
+    protected native int  init(String filename, int access);
+    protected native void close(int handle);
+    protected native int  nxflush(int handle);
+    
+    /**
+      * constructs a new NexusFile Object.
+      * @param filename The name of the NeXus file to access.
+      * @param access The access mode for the file. Can only be one
+      * of the predefined NeXus access code NXACC.... These are:
+      * <dl>
+      * <dt>NXACC_CREATE
+      * <DD>or creating a new file.
+      * <DT>NXACC_RDWR
+      * <DD>For opening an existing file for modification or appending 
+      * data.
+      * <DT>NXACC_READ
+      * <DD>For opening a file for reading.
+      * <DT>NXACC_NOSTRIP
+      * <DD>To keep leading and trailing whitespace on strings
+      * </dl>
+      * @exception NexusException when the file could not be found or
+      * an HDF error occurred.
+      */
+    public NexusFile(String filename, int access) throws NexusException {
+         checkForNull(filename);
+
+         handle = init(filename,access);
+         if(handle < 0){
+	    throw new NexusException("Failed to open " + filename);
+	 }
+    }
+
+    /**
+      * flushes all pending data to disk. Closes any open SDS's.
+      */
+    public void flush() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	 handle = nxflush(handle);
+    }
+
+    /**
+     * close the NeXus file. To make javalint and diamond happy
+     * @throws NexusException
+     */
+    public void close() throws NexusException {
+        if(handle  >= 0) {
+           close(handle);
+           handle = -1;
+        }
+    }
+    
+    /**
+      * removes all NeXus file data structures and closes the file. This 
+      * function should automatically be called by the Java garbage 
+      * collector whenever the NexusFile object falls into disuse. However
+      * the time when this is done is left to the garbage collector. My
+      * personal experience is that finalize might never be called. I
+      * suggest, to call finalize yourself when you are done with the 
+      * NeXus file. finalize makes sure that multiple invocations will not
+      * do any harm.
+      */   
+    public void finalize() throws Throwable {
+    	close();
+    }
+
+
+    // group functions
+    //native methods for this section
+    protected native void nxmakegroup(int handle, String name, String nxclass);
+    protected native void nxopengroup(int handle, String name, String nxclass);
+    protected native void nxopenpath(int handle, String path);
+    protected native void nxopengrouppath(int handle, String path);
+    protected native void nxclosegroup(int handle);
+    protected native String nxgetpath(int handle);
+
+    public void makegroup(String name, String nxclass) throws NexusException {
+    	checkForNull(name, nxclass);
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxmakegroup(handle, name, nxclass);
+    }
+
+    public void opengroup(String name, String nxclass) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkForNull(name, nxclass);
+	nxopengroup(handle, name, nxclass);
+    }
+
+    public void openpath(String path) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkForNull(path);
+	nxopenpath(handle,path);
+    }
+
+    public void opengrouppath(String path) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(path);
+	nxopengrouppath(handle,path);
+    }
+
+    public String getpath() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	return nxgetpath(handle);
+    }
+
+    public void closegroup() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxclosegroup(handle);
+    }
+
+    // data set handling
+    // native methods for this section
+    protected native void nxmakedata(int handle, String name, int type, int rank, int dim[]);
+    protected native void nxmakedata64(int handle, String name, int type, int rank, long dim[]);
+    protected native void nxmakecompdata(int handle, String name, int type, int rank, int dim[], int iCompress, int iChunk[]);
+    protected native void nxmakecompdata64(int handle, String name, int type, int rank, long dim[], int iCompress, long iChunk[]);
+    protected native void nxopendata(int handle, String name);
+    protected native void nxclosedata(int handle);
+    protected native void nxcompress(int handle, int compression_type);
+
+    public void compmakedata(String name, int type, int rank, int dim[],
+                   int compression_type, int iChunk[]) throws NexusException {
+        if (handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(type);    
+        checkForNull(name, rank, iChunk);
+        checkForNegInArray(true, dim, iChunk);
+        checkCompression(compression_type);
+	nxmakecompdata(handle, name, type, rank, dim, compression_type, iChunk);
+    }
+
+    public void compmakedata(String name, int type, int rank, long dim[],
+                   int compression_type, long iChunk[]) throws NexusException {
+        if (handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(type);    
+        checkForNull(name, rank, iChunk);
+        checkForNegInArray(true, dim, iChunk);
+        checkCompression(compression_type);
+	nxmakecompdata64(handle, name, type, rank, dim, compression_type, iChunk);
+    }
+
+    public void makedata(String name, int type, int rank, int dim[]) throws
+	                   NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(type);
+        checkForNull(name, dim);
+        checkForNegInArray(true, dim);
+        nxmakedata(handle, name, type, rank, dim);
+    }
+
+    public void makedata(String name, int type, int rank, long dim[]) throws
+	                   NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(type);
+        checkForNull(name, dim);
+        checkForNegInArray(true, dim);
+        nxmakedata64(handle, name, type, rank, dim);
+    }
+
+    public void opendata(String name) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(name);
+	nxopendata(handle,name);
+    }
+
+    public void closedata() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxclosedata(handle);
+    }
+
+    public void compress(int compression_type) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkCompression(compression_type);
+	nxcompress(handle,compression_type);
+    }
+
+    // data set reading
+    // native methods in this section
+    protected native void nxgetdata(int handle, byte bdata[]);
+    protected native void nxgetslab(int handle, int Start[], int size[], byte bdata[]);
+    protected native void nxgetslab64(int handle, long Start[], long size[], byte bdata[]);
+    protected native void nxgetattr(int handle, String name, byte bdata[], int args[]);
+
+    public void getdata(Object array) throws NexusException {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(array);
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetdata(handle,bdata);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+
+    public void getslab(int start[], int size[], Object array) throws NexusException {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(start, size, array);
+    	checkForNegInArray(false, start, size);
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetslab(handle,start,size,bdata);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+
+    public void getslab(long start[], long size[], Object array) throws NexusException {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(start, size, array);
+    	checkForNegInArray(false, start, size);
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetslab64(handle,start,size,bdata);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+
+    public void getattr(String name, Object array, int args[]) throws NexusException {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(args[1]);
+    	checkForNull(name, array);
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetattr(handle, name, bdata,args);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+
+    // data set writing
+    // native methods for this section
+    protected native void nxputdata(int handle, byte array[]); 
+    protected native void nxputslab(int handle, byte array[], int start[], int size[]); 
+    protected native void nxputslab64(int handle, byte array[], long start[], long size[]); 
+    protected native void nxputattr(int handle, String name, byte array[], int type); 
+
+    public void putdata(Object array) throws NexusException {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+   	   checkForNull(array);
+
+       try {
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       } catch (HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputdata(handle,data);
+       data = null;
+    }
+
+    public void putslab(Object array, int start[], int size[]) throws NexusException {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       checkForNull(array, start, size);
+       checkForNegInArray(false, start, size);
+       try {
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       } catch(HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputslab(handle,data,start,size);
+       data = null;
+    }
+
+    public void putslab(Object array, long start[], long size[]) throws NexusException {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       checkForNull(array, start, size);
+       checkForNegInArray(false, start, size);
+       try {
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       } catch(HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputslab64(handle,data,start,size);
+       data = null;
+    }
+
+    public void putattr(String name, Object array, int iType) throws NexusException {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       checkType(iType);
+       checkForNull(name, array);
+       try{
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       }catch(HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputattr(handle,name,data,iType);
+       data = null;
+    }
+
+    // inquiry
+    //native methods for this section
+    protected native void nxgetinfo(int handle, int iDim[], int args[]);
+    protected native void nxgetinfo64(int handle, long iDim[], int args[]);
+    protected native void nxsetnumberformat(int handle, int type, 
+					    String format);
+    protected native int nextentry(int handle, String names[]);
+    protected native int nextattr(int handle, String names[], int args[]);
+    protected native void initattrdir(int handle);
+    protected native void initgroupdir(int handle);
+
+    public void setnumberformat(int type, String format) throws NexusException {
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       checkType(type);
+       checkForNull(format);
+       nxsetnumberformat(handle,type,format);
+    }
+
+    public void getinfo(int iDim[], int args[]) throws NexusException {
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       nxgetinfo(handle,iDim,args);
+    }
+
+    public void getinfo(long iDim[], int args[]) throws NexusException {
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       nxgetinfo64(handle,iDim,args);
+    }
+
+    public Hashtable groupdir() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        Hashtable h = new Hashtable();
+        String names[] = new String[2];
+
+        initgroupdir(handle);
+        while(nextentry(handle,names) != -1) {
+           h.put(names[0],names[1]);
+        }
+        return h;
+    }
+
+    public Hashtable attrdir()throws NexusException {
+        int args[] = new int[2];
+        AttributeEntry at;
+        String names[] = new String[1];
+
+        Hashtable h = new Hashtable();
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	initattrdir(handle);
+        while(nextattr(handle,names,args) != -1)
+	{
+          at = new AttributeEntry();
+          at.length = args[0];
+          at.type   = args[1];
+          h.put(names[0], at);
+        } 
+        return h;
+    }
+    
+    // linking 
+    // native methods for this section
+    protected native void nxgetgroupid(int handle, NXlink link);
+    protected native void nxgetdataid(int handle, NXlink link);
+    protected native void nxmakelink(int handle, NXlink target); 
+    protected native void nxmakenamedlink(int handle, String name, NXlink target); 
+    protected native void nxopensourcepath(int handle); 
+
+    public NXlink getgroupID() throws NexusException {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      NXlink l = new NXlink();
+      nxgetgroupid(handle,l);
+      return l;
+    }
+
+    public NXlink getdataID()throws NexusException {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      NXlink l = new NXlink();
+      nxgetdataid(handle,l);
+      return l;
+    }
+
+    public void makelink(NXlink target) throws NexusException {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      checkForNull(target);
+      nxmakelink(handle, target);
+    }
+
+    public void makenamedlink(String name, NXlink target) throws NexusException {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      checkForNull(name, target);
+      nxmakenamedlink(handle, name, target);
+    }     
+
+    public void opensourcepath() throws NexusException {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      nxopensourcepath(handle);
+    }
+	
+    /**
+     * checks if any of the arguments is null, 
+     * throws appropriate runtime exception if so
+     */
+    private void checkForNull(Object... args) {
+    	for (Object o : args)
+    		if (o==null) throw new NullPointerException();
+    }
+    
+    /**
+     * checks if any of the ints in the arrays are negative, 
+     * throws appropriate runtime exception if so
+     */
+    private void checkForNegInArray(boolean allowUnlimited, int[]... args) {
+    	for (int[] array : args)
+    		for (int value: array) {
+    			if (value<0)
+    				if (value == this.NX_UNLIMITED && allowUnlimited) {
+    					// all ok this time
+    				} else
+    					throw new IllegalArgumentException("negative dimension received");
+    		}
+    }
+
+    /**
+     * checks if any of the longs in the arrays are negative, 
+     * throws appropriate runtime exception if so
+     */
+    private void checkForNegInArray(boolean allowUnlimited, long[]... args) {
+    	for (long[] array : args)
+    		for (long value: array) {
+    			if (value<0)
+    				if (value == this.NX_UNLIMITED && allowUnlimited) {
+    					// all ok this time
+    				} else
+    					throw new IllegalArgumentException("negative dimension received");
+    		}
+    }
+
+    /**
+      * checkType verifies if a parameter is a valid NeXus type code. 
+      * If not an exception is thrown.
+      * @param type The type value to check.
+      * @exception NexusException if the the type is no known type value
+      */
+    private void checkType(int type) throws NexusException {
+	switch(type) {
+	case NexusFile.NX_FLOAT32:
+	case NexusFile.NX_FLOAT64:
+	case NexusFile.NX_INT8:
+	case NexusFile.NX_UINT8:
+	case NexusFile.NX_INT16:
+	case NexusFile.NX_UINT16:
+	case NexusFile.NX_INT32:
+	case NexusFile.NX_UINT32:
+	case NexusFile.NX_INT64:
+	case NexusFile.NX_UINT64:
+	case NexusFile.NX_CHAR:
+	    break;
+        default:
+	    throw new NexusException("Illegal number type requested");
+        }
+    } 
+
+    /**
+      * checkCompression verifies a parameter is a valid NeXus compression code. 
+      * If not an exception is thrown.
+      * @param type The value to check.
+      * @exception NexusException if the the type is no known compression value
+      */
+    private void checkCompression(int compression_type) throws NexusException {
+        switch(compression_type) {
+	case NexusFile.NX_COMP_NONE:
+    	case NexusFile.NX_COMP_LZW:
+    	case NexusFile.NX_COMP_RLE:
+    	case NexusFile.NX_COMP_HUF:
+	case NexusFile.NX_COMP_LZW_LVL0:
+    	case NexusFile.NX_COMP_LZW_LVL1:
+    	case NexusFile.NX_COMP_LZW_LVL2:
+    	case NexusFile.NX_COMP_LZW_LVL3:
+    	case NexusFile.NX_COMP_LZW_LVL4:
+    	case NexusFile.NX_COMP_LZW_LVL5:
+    	case NexusFile.NX_COMP_LZW_LVL6:
+    	case NexusFile.NX_COMP_LZW_LVL7:
+    	case NexusFile.NX_COMP_LZW_LVL8:
+    	case NexusFile.NX_COMP_LZW_LVL9:
+	    break;
+	default:
+	    throw new NexusException("Invalid compression code requested");
+	}
+    } 
+
+    // external file interface
+    // native methods for this section
+    protected native void nxinquirefile(int handle, String names[]);
+    protected native void nxlinkexternal(int handle, String name, String nxclass, String nxurl);
+    protected native void nxlinkexternaldataset(int handle, String name, String nxurl);
+    protected native int nxisexternalgroup(int handle, String name, String nxclass, String nxurl[]); 
+    protected native int nxisexternaldataset(int handle, String name, String nxurl[]); 
+
+    public String inquirefile() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	String names[] = new String[1];
+	nxinquirefile(handle,names);
+	return names[0];
+    }
+
+    public void linkexternal(String name, String nxclass, String nxurl) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(name, nxclass, nxurl);
+	nxlinkexternal(handle,name,nxclass,nxurl);
+    }
+
+    public void linkexternaldataset(String name, String nxurl) throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(name, nxurl);
+	nxlinkexternaldataset(handle,name,nxurl);
+    }
+
+    public String isexternalgroup(String name, String nxclass) throws NexusException {
+        if (handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(name, nxclass);
+	String nxurl[] = new String[1];
+
+	int status = nxisexternalgroup(handle,name,nxclass,nxurl);
+	if (status == 1) {
+	    return nxurl[0];
+	} else {
+	    return null;
+	}
+    }
+
+    public String isexternaldataset(String name) throws NexusException {
+        if (handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+    	checkForNull(name);
+	String nxurl[] = new String[1];
+
+	int status = nxisexternaldataset(handle,name,nxurl);
+	if (status == 1) {
+	    return nxurl[0];
+	} else {
+	    return null;
+	}
+    }
+
+    /**
+      * debugstop is a debugging helper function which goes into an 
+      * endless loop in the dynamic link library. Then a unix debugger
+      * may attach to the running java process using the pid, interrupt,
+      * set the loop variable to leave the loop, set a new breakpoint and
+      * continue debugging. This works with ladebug on DU40D. This is an
+      * developer support routine and should NEVER be called in normal
+      * code. 
+      */
+    public native void debugstop();
+}
diff --git a/bindings/java/test/TestJapi.java b/bindings/java/test/TestJapi.java
new file mode 100644
index 0000000..b2b4d89
--- /dev/null
+++ b/bindings/java/test/TestJapi.java
@@ -0,0 +1,275 @@
+/**
+ * TestJapi does some testing of the NeXus for Java API. It can also serve as an example for the usage of the NeXus API
+ * for Java. Mark Koennecke, October 2000 updated for NAPI-2 with HDF-5 support Mark Koennecke, August 2001
+ */
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import org.nexusformat.*;
+
+public class TestJapi {
+	
+	void fileTest(int fileType, String fileName) throws Exception {
+		NexusFile nf = null;
+		NXlink gid, did;
+		String group = "entry1";
+		String nxclass = "NXentry";
+		
+		// create a NexusFile
+		nf = new NexusFile(fileName, fileType);
+
+		try {
+		// error handling check
+		try {
+			nf.opengroup(group, nxclass);
+			throw new RuntimeException("Exception handling broken");
+		} catch (NexusException nex) {
+			System.out.println("Exception handling mechanism works");
+		}
+		
+		int iData1[][] = new int[3][10];
+		int iData2[][] = new int[3][10];
+		float fData1[][] = new float[3][10];
+		int islab[] = new int[10];
+		int iDim[] = new int[2], i, j;
+		int iStart[] = new int[2];
+		int signal[] = new int[1];
+		int iEnd[] = new int[2];
+		String attname, vname, vclass;
+		AttributeEntry atten;
+		
+		// create some data
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 10; j++) {
+				iData1[i][j] = i * 10 + j;
+				fData1[i][j] = (float) (i * 10.1 + j * .2);
+			}
+		}
+		for (i = 0; i < 10; i++) {
+			islab[i] = 10000 + i;
+		}
+		
+		// create and open a group
+		nf.makegroup(group, nxclass);
+		nf.opengroup(group, nxclass);
+
+		// get a link ID for this group
+		gid = nf.getgroupID();
+
+		// create and open a dataset
+		iDim[0] = 3;
+		iDim[1] = 10;
+		nf.makedata("iData1", NexusFile.NX_INT32, 2, iDim);
+		nf.opendata("iData1");
+
+		// get a link ID to this data set
+		did = nf.getdataID();
+
+		// write data to it
+		nf.putdata(iData1);
+
+		// add attributes, the first one is also an example how to write
+		// strings (by converting to byte arrays)
+		String units = "MegaFarts";
+		nf.putattr("Units", units.getBytes(), NexusFile.NX_CHAR);
+		iStart[0] = 1;
+		signal[0] = 1;
+		nf.putattr("signal", signal, NexusFile.NX_INT32);
+
+		// closedata
+		nf.closedata();
+
+		// try unlimimited dim
+		int unDim[] = new int[1];
+		unDim[0] = -1;
+		nf.makedata("Stuart", NexusFile.NX_FLOAT64, 1, unDim);
+
+		// write a compressed data set
+		nf.compmakedata("iData1_compressed", NexusFile.NX_INT32, 2, iDim, NexusFile.NX_COMP_LZW, iDim);
+		nf.opendata("iData1_compressed");
+		nf.putdata(iData1);
+		nf.closedata();
+
+		// write a float data set
+		nf.makedata("fData1", NexusFile.NX_FLOAT32, 2, iDim);
+		nf.opendata("fData1");
+		nf.putdata(fData1);
+		nf.closedata();
+
+		// write a dataset in slabs */
+		nf.makedata("slabbed", NexusFile.NX_INT32, 2, iDim);
+		nf.opendata("slabbed");
+		iStart[1] = 0;
+		iEnd[1] = 10;
+		iEnd[0] = 1;
+		for (i = 0; i < 3; i++) {
+			iStart[0] = i;
+			nf.putslab(islab, iStart, iEnd);
+		}
+		nf.closedata();
+
+		// closegroup
+		nf.closegroup();
+
+		// test linking code
+		nf.makegroup("entry2", "NXentry");
+		nf.opengroup("entry2", "NXentry");
+		nf.makegroup("data", "NXdata");
+		nf.opengroup("data", "NXdata");
+		nf.makelink(did);
+		// nf.debugstop();
+		nf.closegroup();
+
+		// close a file explicitly (recommended!)
+		nf.close();
+		System.out.println(" *** Writing Tests passed with flying banners");
+
+		// **************** reading tests *******************************
+		iData2[2][5] = 66666;
+		fData1[2][5] = (float) 66666.66;
+
+		nf = new NexusFile(fileName, NexusFile.NXACC_READ);
+
+		// test attribute enquiry routine at global attributes
+		Hashtable h = nf.attrdir();
+		Enumeration e = h.keys();
+		byte bData[];
+		while (e.hasMoreElements()) {
+			attname = (String) e.nextElement();
+			atten = (AttributeEntry) h.get(attname);
+			System.out.println("Found global attribute: " + attname + " type: " + atten.type + " ,length: "
+					+ atten.length);
+			bData = new byte[atten.length];
+			iDim[0] = atten.length;
+			iDim[1] = atten.type;
+			nf.getattr(attname, bData, iDim);
+			System.out.println(attname + "=" + new String(bData));
+		}
+
+		// test reading vGroup directory
+		// nf.debugstop();
+		nf.opengroup(group, nxclass);
+		h = nf.groupdir();
+		e = h.keys();
+		System.out.println("Found in vGroup entry:");
+		while (e.hasMoreElements()) {
+			vname = (String) e.nextElement();
+			vclass = (String) h.get(vname);
+			System.out.println("     Item: " + vname + " class: " + vclass);
+		}
+
+		// test reading SDS info and attributes
+		nf.opendata("iData1");
+		nf.getinfo(iDim, iStart);
+		System.out.println("Found iData1 with: rank = " + iStart[0] + " type = " + iStart[1] + " dims = " + iDim[0]
+				+ ", " + iDim[1]);
+		h = nf.attrdir();
+		e = h.keys();
+		while (e.hasMoreElements()) {
+			attname = (String) e.nextElement();
+			atten = (AttributeEntry) h.get(attname);
+			System.out.println("Found SDS attribute: " + attname + " type: " + atten.type + " ,length: "
+					+ atten.length);
+		}
+
+		// success for inquiry routines
+		nf.closedata();
+		nf.closegroup();
+		System.out.println(" **** Inquiry routines passed test");
+
+		// test the data reading routines
+		nf.opengroup(group, nxclass);
+		nf.opendata("iData1");
+		nf.getdata(iData2);
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 10; j++) {
+				if (iData1[i][j] != iData2[i][j])
+					System.out.println(" Data Reading Error at : " + i + ", " + j);
+			}
+		}
+		// test attribute reading. This is also an example for reading
+		// Strings from a NeXus file.
+		byte bString[] = new byte[60];
+		iDim[0] = 60;
+		iDim[1] = NexusFile.NX_CHAR;
+		nf.getattr("Units", bString, iDim);
+		System.out.println("Read attribute Units to: " + new String(bString));
+		// check reading a slab
+		iStart[0] = 0;
+		iStart[1] = 0;
+		iEnd[0] = 1;
+		iEnd[1] = 10;
+		nf.getslab(iStart, iEnd, islab);
+		for (i = 0; i < 10; i++) {
+			if (islab[i] != iData1[0][i])
+				System.out.println(" Slab Reading Error at : " + i + " expected: " + iData1[0][i] + ", got: "
+						+ islab[i]);
+		}
+		nf.closedata();
+
+		// check compressed data
+		nf.opendata("iData1_compressed");
+		nf.getdata(iData2);
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 10; j++) {
+				if (iData1[i][j] != iData2[i][j])
+					System.out.println(" Data Reading Error at : " + i + ", " + j);
+			}
+		}
+		nf.closedata();
+
+		// now, for completeness: check float data as well
+		nf.opendata("fData1");
+		nf.getdata(fData1);
+		nf.closedata();
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 10; j++) {
+				if (Math.abs(fData1[i][j] - (float) (i * 10.1 + j * .2)) > .05) {
+					System.out.println(" Float Reading Error at : " + i + ", " + j);
+				}
+			}
+		}
+
+		// reading success
+		System.out.println(" *** Data Reading routines appear to work");
+
+		// test openpath
+		nf.openpath("/entry2/data/iData1");
+		nf.openpath("/entry2/data/iData1");
+		nf.openpath("../");
+		System.out.println("*** openpath seems to work");
+
+		} finally {
+		nf.close();
+		}
+	}
+	
+	static public void main(String args[]) {
+		
+		TestJapi tj = new TestJapi();
+		
+		System.out.println("Testing XML");
+		try {
+			tj.fileTest(NexusFile.NXACC_CREATEXML, "japitest.xml");
+			System.out.println("Success.");
+		} catch (Exception e) {
+			System.err.println("Failed with exception: "+e.getMessage());
+			e.printStackTrace();
+		}
+		System.out.println("Testing HDF4");
+		try {
+		tj.fileTest(NexusFile.NXACC_CREATE4, "japitest.h4");	
+		System.out.println("Success.");
+		} catch (Exception e) {
+			System.err.println("Failed with exception: "+e.getMessage());
+			e.printStackTrace();
+		}		System.out.println("Testing HDF5");
+		try {
+		tj.fileTest(NexusFile.NXACC_CREATE5, "japitest.h5");
+		System.out.println("Success.");
+		} catch (Exception e) {
+			System.err.println("Failed with exception: "+e.getMessage());
+			e.printStackTrace();
+		}
+	}
+}
\ No newline at end of file
diff --git a/bindings/matlab/Makefile.am b/bindings/matlab/Makefile.am
new file mode 100755
index 0000000..d89708b
--- /dev/null
+++ b/bindings/matlab/Makefile.am
@@ -0,0 +1,81 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for NeXus Matlab bindings
+#
+#  Copyright (C) 2010 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+MATLABLIBDIR=$(MATLAB_ROOT)/bin/$(MATLAB_ARCH)
+MATLAB_LIBS=-lmx -lmex
+AM_CPPFLAGS=-I$(MATLAB_ROOT)/extern/include -DMATLAB_MEX_FILE # -DARGCHECK
+
+
+idldlmdir = @IDLDLM@
+idldlm_LTLIBRARIES = libNeXusIDL-API.la
+idldlm_DATA = NeXusIDL-API.dlm
+
+libNeXusIDL_API_la_SOURCES = NeXusIDL-API.c handle.c handle.h
+libNeXusIDL_API_la_LIBADD = $(top_builddir)/src/libNeXus.la
+libNeXusIDL_API_la_LDFLAGS = @SHARED_LDFLAGS@ -L$(IDLROOT)/bin/$(IDL_HOST) -lidl $(LDFLAGS)
+
+AM_CPPFLAGS = -I$(IDLROOT)/external/include
+
+all : all-am NeXusIDL-API.so
+
+install-exec-hook :
+	( cd $(DESTDIR)$(idldlmdir); ln -s libNeXusIDL-API.so NeXusIDL-API.so )
+
+NeXusIDL-API.so : libNeXusIDL-API.la
+	ln -sf .libs/libNeXusIDL-API.so $@
+	if test ! -r NeXusIDL-API.dlm; then ln -s $(srcdir)/NeXusIDL-API.dlm .; fi
+
+CLEANFILES = NeXusIDL-API.so
+
+EXTRA_DIST = \
+ build_testmodule.pro \
+ build_win.bat \
+ data \
+ NeXusIDL-API.def \
+ NeXusIDL-API.dlm \
+ NeXusIDL-API.export \
+ nxext.h5 \
+ nxext.hdf \
+ nxext.xml \
+ NXtest.h5 \
+ NXtest.hdf \
+ NXtest.xml \
+ README.html \
+ read_test.pro \
+ recursiveread.pro \
+ recursivesearch.pro \
+ testfocus.pro \
+ write_test.pro \
+ testidlnapi
+
+dist-hook :
+	find $(distdir)/data -depth -type d -name '.svn' -exec rm -fr {} \;
+
+include $(top_srcdir)/build_rules.am
diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt
new file mode 100644
index 0000000..a42203b
--- /dev/null
+++ b/bindings/python/CMakeLists.txt
@@ -0,0 +1,83 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+if(DEFINED PYTHONINTERP_FOUND)
+
+    SET (PYDOC_OUTPUT napi.html)
+    SET (NXSPYTHON_DOC nxs.napi.html)
+    FILE(GLOB NXSPYTHON_SOURCE "${CMAKE_SOURCE_DIR}/bindings/python/nxs/*.py")
+	list(APPEND NXSPYTHON_SOURCE setup.py)
+
+    GET_TARGET_PROPERTY(LIB_NAME NeXus_Shared_Library LOCATION)
+    SET (ENV{NEXUSLIB} ${LIB_NAME})
+
+    FILE(READ "${CMAKE_SOURCE_DIR}/bindings/python/nxs/napi.py" TEMP_SOURCE_IN)
+
+    STRING(REGEX REPLACE "nxprefix = .*" "nxprefix = ${CMAKE_INSTALL_PREFIX}" TEMP_SOURCE_OUT ${TEMP_SOURCE_IN})
+
+    FILE(WRITE nxs/napi.py.out ${TEMP_SOURCE_OUT}) 
+
+    #We need to run py_compile somehow now on napi.py.out
+    #according to the Makefile.am. py_compile is not portable
+    #and DESTDIR is not available as a variable in CMAKE
+    #(more googleing needed).
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    ${PYDOC_OUTPUT}
+        COMMAND   ${CMAKE_COMMAND} 
+        ARGS      -D NEXUSLIB="${LIB_NAME}" -D NXSPYTHON_SOURCE="${NXSPYTHON_SOURCE}" -D PYTHON_DOC="${PYTHON_DOC}" -P "${CMAKE_SOURCE_DIR}/bindings/python/pythondoc.cmake"
+        COMMENT   "Build NXS Python Docs"
+    )
+
+ #   ADD_CUSTOM_COMMAND( 
+ #       OUTPUT    ${PYDOC_OUTPUT}
+ #       COMMAND   ${CMAKE_COMMAND} -E env "NEXUSLIB=${LIB_NAME}" ${PYTHON_DOC}
+ #       ARGS      -w ${NXSPYTHON_SOURCE}
+ #       COMMENT   "Build NXS Python Docs"
+ #   )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    ${NXSPYTHON_DOC}
+        COMMAND   ${CMAKE_COMMAND}
+        ARGS      -E copy ${PYDOC_OUTPUT} ${NXSPYTHON_DOC}
+        DEPENDS   ${PYDOC_OUTPUT}
+        COMMENT   "Rename NXS Python Docs"
+    )
+
+	if (PYTHON_DOC)
+		ADD_CUSTOM_TARGET(NXSPythonDoc ALL echo
+			DEPENDS   ${NXSPYTHON_DOC}
+		)
+        install (FILES ${CMAKE_BINARY_DIR}/bindings/python/${NXSPYTHON_DOC} DESTINATION ${NXDOCDIR}/python COMPONENT Documentation)
+	endif()
+
+    install (FILES ${NXSPYTHON_SOURCE} DESTINATION lib/python/nxs COMPONENT Development)
+    
+endif(DEFINED PYTHONINTERP_FOUND)
+
+
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
new file mode 100755
index 0000000..5baf656
--- /dev/null
+++ b/bindings/python/Makefile.am
@@ -0,0 +1,58 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 715 2005-12-16 18:11:19Z faa59 $
+#  
+#  Makefile for NeXus python bindings
+#
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+pydocdir 	= $(NXDOCDIR)/python
+pydoc_DATA	= README.html nxs.napi.html
+#nxspythondir	= $(pkgpythondir)/nxs
+nxspythondir	= $(pythondir)/nxs
+#pkgpython_PYTHON = nxstest.py
+nxspython_PYTHON = nxs/__init__.py nxs/napi.py nxs/tree.py nxs/unit.py
+EXTRA_DIST	= README.html nxs.napi.html nxstest.py run_nxstest setup.py
+
+nxs.napi.html : $(srcdir)/nxs/napi.py
+	env NEXUSLIB=../../src/.libs/libNeXus.$(SHARED_EXT) pydoc -w $(srcdir)/nxs/napi.py
+	if test -r napi.html; then \
+	    mv napi.html $@; \
+	else \
+	    touch $@; \
+	fi
+
+install-data-hook :
+	sed -e "s|nxlibdir = .*|nxlibdir = \'${libdir}\'|" < ${srcdir}/nxs/napi.py > $(DESTDIR)${nxspythondir}/napi.py
+	if test -z "$(DESTDIR)"; then \
+	    $(py_compile) --basedir "$(nxspythondir)" napi.py; \
+	else \
+	    $(py_compile) --destdir "$(DESTDIR)" --basedir "$(nxspythondir)" napi.py; \
+	fi
+
+# python setup.py install --root=$(DESTDIR)
+CLEANFILES=nxs.napi.html nxs/napi.pyc
+
+include $(top_srcdir)/build_rules.am
diff --git a/bindings/python/README.html b/bindings/python/README.html
new file mode 100644
index 0000000..423be0c
--- /dev/null
+++ b/bindings/python/README.html
@@ -0,0 +1,307 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<head>
+<title>
+Nexus Python API - README
+</title>
+</head>
+
+<body>
+<!-- start content -->
+
+<h1>Nexus Python API - README </h1>
+<hr>
+<table id="toc" class="toc" summary="Contents"><tbody><tr><td><h2>Contents</h2> </a>
+
+<ul>
+
+<li ><a href="#Overview">1. Overview</a>
+
+<li ><a href="#Installation">2. Installation</a>
+<ul>
+
+<li ><a href="#Requirements">2.1 Requirements</a></li>
+<li><a href="#Building and Installing">2.2 Building and Installing </a></li>
+<li><a href="#Linux">2.3 Linux </a></li>
+<li><a href="#Windows">2.4 Windows </a></li>
+
+</ul>
+
+<li ><a href="#Using API from Python">3. Using API from Python</a>
+<ul>
+
+<li><a href="#Test Files">3.1 Test Files </a></li>
+<li><a href="#Using The API And An Example">3.2 Using The API And An Example</a></li>
+<li><a href="#NeXus API Routines">3.3 NeXus API Routines</a></li>
+
+
+</ul>
+</ul>
+
+
+<a name="#Overview"></a><h2> Overview</h2>
+
+<p>NeXus Python Api binds the NeXus libraries to Python. It brings functionality of the NeXus API to Python for reading, writing and modifying NeXus Files. Python NeXus API imitates the functionality NeXus API though with a more object oriented flavour.
+
+<p>Information on NeXus Dataformat: <A HREF="http://www.nexusformat.org/Introduction">http://www.nexusformat.org/Introduction</A>.
+</p>
+<p>
+Information on IDL: <A HREF="http://www.ittvis.com/">http://www.nexusformat.org/Introduction</A>.
+</p>
+
+<p><br> </p>
+
+<a name="Installation"></a><h2> Installation</h2>
+
+<a name="Requirements"></a><h3> Requirements</h3>
+<p>
+This package provides a ctypes binding from Python+numpy to the precompiled NeXus library.
+
+It has been tested on Python 2.5 in Windows, OS X and Linux.  
+
+The bindings should be easily modified for any version of Python which supports 
+ctypes and numpy.
+</p>
+
+<p>
+
+<p>  The NeXus packages and installation instructions are available at
+<A HREF="http://www.nexusformat.org/Download">http://www.nexusformat.org/Download</A>. </p>
+</p>
+
+<P>For Windows the NeXus Data Format
+Windows Installer Kit, which includes the necessary hdf5, hdf4 and
+xml libraries, is recommended.
+<A HREF="http://download.nexusformat.org/kits/windows/">http://download.nexusformat.org/kits/windows/ </A></P>
+
+</p>
+
+<a href="Building and Installing"></a><h3>Building and Installing</h3>
+
+This package uses the standard distutils installer for python.
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+		<TD WIDTH=376 VALIGN=TOP>
+<pre>
+$ python setup.py install
+</pre>
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+You will also need to make sure that libNeXus can be found.  For windows, libNeXus.dll and
+the associated hdf/xml dlls should be together in nxs.py directory.  The package will also look in the
+standard nexus windows installer location, C:/Program Files/NeXus Data Format/.  For Linux, libNeXus.so
+should be in nxs.py directory, /usr/lib, /usr/local/lib, or one of the directories listed on LD_LIBRARY_PATH.
+For Apple OS X, libNeXus.dylib should be in the nxs.py directory, /usr/lib, /usr/local/lib, or one of the
+directories listed on DYLD_LIBRARY_PATH.  If the file is not in a standard place with the standard name,
+set NEXUSLIB to the full path to the NeXus library.
+
+<a name="Using API from Python"></a><h2> Using API from Python</h2>
+
+<a name="Test Files"></a><h3> Test Files</h3>
+
+<P>The Python NeXus-API includes nxstest.py, which provides similar
+tests to the original C api file napi_test.c.</P>
+
+</P>After installing, you can run the test using:
+<pre>
+    python [options] [formats]
+</pre>
+where options are -q for quiet and -x for external, and formats are
+hdf4, hdf5 and xml.  The default is to test hdf5 format read/write.
+</P>
+
+<a name="Using The API And An Example"></a><h3> Using The API And An Example</h3> 
+
+<p> The API's functions aim to reproduce 
+the funtionality of the C API closely. Some low level functionality has been hidden from the user. Memory allocation 
+functions NXmalloc and NXfree are done automatically in the API when needed.  The file handle
+is an object with methods rather than a parameter to functions.  Instead of checking status codes, errors raise
+exceptions.</p>
+
+<p>The input and returned values match the format of the data in the files.  On return, python creates
+values of the correct type.  However on input, numeric types must be created correctly using 
+numpy.array(...,dtype='type'). The matching datatypes are:
+
+
+<TABLE BORDER=1 WIDTH=50% CELLPADDING=2 CELLSPACING=1 ALIGN=CENTER style="background-color: rgb(238, 238, 238);">
+	<COL WIDTH=373>
+	<THEAD>
+		<TR style="background-color: rgb(204, 204, 204);">
+		<TD WIDTH=373 VALIGN=TOP>
+		NeXus Datatype
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		Python Datatype
+		</TD>
+
+		</TR>
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_CHAR
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'char'
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_FLOAT32
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'float32'
+		</TD>
+		</TR>
+
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_FLOAT64
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'float64'
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_UINT8
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'uint8'
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_INT16
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'int16'
+		</TD>
+		</TR>
+
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_UINT16
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'uint16'
+		</TD>
+		</TR>
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_INT32
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'int32'
+		</TD>
+		</TR>
+
+
+		<TR>
+		<TD WIDTH=373 VALIGN=TOP>
+		NX_UINT32
+		</TD>
+		<TD WIDTH=373 VALIGN=TOP>
+		'uint32'
+		</TD>
+		</TR>
+
+	</THEAD>
+</TABLE>
+
+<p> <br> </p>
+Here is simple example program that demonstrates the basic functions and most important differences between the C Nexus Api and the Python Nexus API.
+<ol>
+<li>Creates a NeXus file with access method HDF5</li>
+<li>adds datagroups</li>
+<li>makes a data array of data type NX_INT32</li>
+<li>puts data to the array</li>
+<li>reads the data and attributes</li>
+<li>prints data and attribute value</li>
+<li>closes the groups and the file.</li>
+</ol>
+
+
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+		<TD WIDTH=376 VALIGN=TOP>
+<pre>
+import nxs,numpy
+
+# Access method accepts strings or integer (e.g., nxs.ACC_CREATE5)
+f = nxs.open("test.h5", 'w5')
+f.makegroup("testgroup", "NXentry")
+f.opengroup("testgroup", "NXentry")
+f.makegroup("anothergroup", "NXentry")
+
+# Some data to store in the file, this of type int16
+data = numpy.array([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15] ],'int16')
+
+# Make a data set for the array. Note that this could also
+# be done as f.makedata('data1','int16',[4,4])
+f.makedata('data1', dtype=data.dtype, shape=data.shape)
+f.opendata("data1")
+f.putdata(data)
+
+# Attribute type can be inferred from the data or specified.  If inferred, it
+# must match the type of the data.  Attributes are scalars or strings, with
+# string length inferred from value.
+f.putattr('integer-attribute', 42, 'int16')
+f.putattr('double-attribute', 3.14159)
+f.closedata() 
+# NeXus returns arrays from getattr/getdata/getslab
+f.opendata("data1")
+print 'data :',f.getdata()
+
+# getnext functions return tuples
+attrname,length,type = f.getnextattr ()
+value = f.getattr(attrname, length, type)
+print 'first attribute: ', value
+
+# ... or you can use iterators for attrs and entries
+print 'all attributes'
+for attr,value in f.attrs(): 
+    print "  %s: %s"%(attr,value)
+
+f.closedata()
+f.closegroup()
+f.close()
+</pre>
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+
+</p>
+
+<a name="NeXus API Routines"></a><h3> NeXus API Routines</h3>
+<p>Documentation for the individual methods, and how they differ
+from the basic NAPI methods is available from the Python command
+line.  Rather than duplicate it here, use the following in Python:
+
+<TABLE WIDTH=85% BORDER=1 CELLPADDING=4 CELLSPACING=3 ALIGN=CENTER style="background-color: rgb(238, 238, 238);" >
+	<COL WIDTH=376>
+	<THEAD>
+		<TR>
+		<TD WIDTH=376 VALIGN=TOP>
+<pre>
+import nxs
+help(nxs)
+</pre>
+		</TD>
+		</TR>
+	</THEAD>
+</TABLE>
+</p>
+</body></html>
diff --git a/bindings/python/nxs/__init__.py b/bindings/python/nxs/__init__.py
new file mode 100644
index 0000000..73c3c9c
--- /dev/null
+++ b/bindings/python/nxs/__init__.py
@@ -0,0 +1,21 @@
+# This program is public domain
+"""@package nxs
+Python NeXus interface.
+
+NeXus_ is a common data format for neutron, Xray and muon science.
+The files contain multidimensional data elements grouped into a
+hierarchical structure.  The data sets are self-describing, with
+a description of the instrument configuration including the units
+used as well as the data measured.
+
+The NeXus file interface requires compiled libraries to read the
+underlying HDF_ files.  Binary packages are available for some
+platforms from the NeXus site.  Details of where the nxs package
+searches for the libraries are recorded in `nxs.napi`.
+"""
+
+## @mainpage NeXus Python Documentation
+## See nxs.napi on the Packages tab
+
+from nxs.napi import *
+from nxs.tree import *
diff --git a/bindings/python/nxs/napi.py b/bindings/python/nxs/napi.py
new file mode 100755
index 0000000..6216832
--- /dev/null
+++ b/bindings/python/nxs/napi.py
@@ -0,0 +1,1470 @@
+# This program is public domain 
+# Author: Paul Kienzle
+
+"""@package nxs.napi
+Wrapper for the NeXus shared library.
+
+Use this interface when converting code from other languages which
+do not support the natural view of the hierarchy.
+
+Library Location
+================
+
+This wrapper needs the location of the libNeXus precompiled binary. It
+looks in the following places in order::
+
+ at verbatim
+   os.environ['NEXUSLIB']                  - All
+   directory containing nxs.py             - All
+   os.environ['NEXUSDIR']\\bin              - Windows
+   os.environ['LD_LIBRARY_PATH']           - Unix
+   os.environ['DYLD_LIBRARY_PATH']         - Darwin
+   LIBDIR                                  - Unix and Darwin
+ at endverbatim
+
+- On Windows it looks for one of libNeXus.dll or libNeXus-0.dll.
+- On OS X it looks for libNeXus.0.dylib
+- On Unix it looks for libNeXus.so.0
+- NEXUSDIR defaults to 'C:\\Program Files\\NeXus Data Format'.
+- LIBDIR defaults to /usr/local/lib, but is replaced by the value of --libdir during configure.
+
+The import will raise an OSError exception if the library wasn't found
+or couldn't be loaded.  Note that on Windows in particular this may be
+because the supporting HDF5 dlls were not available in the usual places.
+
+If you are extracting the nexus library from a bundle at runtime, set
+os.environ['NEXUSLIB'] to the path where it is extracted before the
+first import of nxs.
+
+Example
+=======
+ at code
+  import nxs
+  file = nxs.open('filename.nxs','rw')
+  file.opengroup('entry1')
+  file.opendata('definition')
+  print file.getdata()
+  file.close()
+ at endcode
+
+  See @see nxstest.py for a more complete example.
+
+Interface
+=========
+
+When converting code to python from other languages you do not
+necessarily want to redo the file handling code.  The nxs
+provides an interface which more closely follows the
+NeXus application programming interface (NAPI_).
+
+This wrapper differs from NAPI in several respects::
+
+  - Data values are loaded/stored directly from numpy arrays.
+  - Return codes are turned into exceptions.
+  - The file handle is stored in a file object
+  - Constants are handled somewhat differently (see below)
+  - Type checking on data/parameter storage
+  - Adds iterators file.entries() and file.attrs()
+  - Adds link() function to return the name of the linked to group, if any
+  - NXmalloc/NXfree are not needed.
+
+File open modes can be constants or strings::
+
+ at verbatim
+ nxs.ACC_READ      'r'
+ nxs.ACC_RDWR      'rw'
+ nxs.ACC_CREATE    'w'
+ nxs.ACC_CREATE4   'w4'
+ nxs.ACC_CREATE5   'w5'
+ nxs.ACC_CREATEXML 'wx'
+ at endverbatim
+
+Dimension constants::
+
+  - nxs.UNLIMITED  - for the extensible data dimension
+  - nxs.MAXRANK    - for the number of possible dimensions
+
+Data types are strings corresponding to the numpy data types::
+
+  'float32' 'float64'
+  'int8' 'int16' 'int32' 'int64'
+  'uint8' 'uint16' 'uint32' 'uint64'
+
+  Use 'char' for string data.
+
+You can use the numpy A.dtype attribute for the type of array A.
+
+Dimensions are lists of integers or numpy arrays.  You can use the
+numpy A.shape attribute for the dimensions of array A.
+
+Compression codes are::
+
+ 'none' 'lzw' 'rle' 'huffman'
+
+  As of this writing NeXus only supports 'none' and 'lzw'.
+
+Miscellaneous constants::
+
+  - nxs.MAXNAMELEN  - names must be shorter than this
+  - nxs.MAXPATHLEN  - total path length must be shorter than this
+  - nxs.H4SKIP - class names that may appear in HDF4 files but can be ignored
+
+Caveats
+=======
+
+ at todo NOSTRIP constant is probably not handled properly,
+ at todo Embedded nulls in strings is not supported
+
+ at warning  We have a memory leak.  Calling open/close costs about 90k a pair.
+This is an eigenbug:
+ - if I test ctypes on a simple library it does not leak
+ - if I use the leak_test1 code in the nexus distribution it doesn't leak
+ - if I remove the open/close call in the wrapper it doesn't leak.
+
+"""
+
+## @example nxstest.py
+#  Test program for NeXus python interface
+
+__all__ = ['UNLIMITED', 'MAXRANK', 'MAXNAMELEN','MAXPATHLEN','H4SKIP',
+           'NeXus','NeXusError','open']
+
+import sys, os, numpy, ctypes
+
+# Defined ctypes
+from ctypes import c_void_p, c_int, c_int64, c_long, c_char, c_char_p
+from ctypes import byref as _ref
+c_void_pp = ctypes.POINTER(c_void_p)
+c_int_p = ctypes.POINTER(c_int)
+c_int64_p = ctypes.POINTER(c_int64)
+class _NXlink(ctypes.Structure):
+    _fields_ = [("iTag", c_long),
+                ("iRef", c_long),
+                ("targetPath", c_char*1024),
+                ("linktype", c_int)]
+    _pack_ = False
+c_NXlink_p = ctypes.POINTER(_NXlink)
+
+
+# Open modes:
+ACC_READ,ACC_RDWR,ACC_CREATE=1,2,3
+ACC_CREATE4,ACC_CREATE5,ACC_CREATEXML=4,5,6
+_nxopen_mode=dict(r=1,rw=2,w=3,w4=4,w5=5,wx=6)
+NOSTRIP=128
+
+# Status codes
+OK,ERROR,EOD=1,0,-1
+
+# Other constants
+UNLIMITED=-1
+MAXRANK=32
+MAXNAMELEN=64
+MAXPATHLEN=1024 # inferred from code
+
+# bogus groups; these groups are ignored in HDFView from NCSA.
+H4SKIP = ['CDF0.0','_HDF_CHK_TBL_','Attr0.0',
+          'RIG0.0','RI0.0', 'RIATTR0.0N','RIATTR0.0C']
+
+# HDF data types from numpy types
+_nxtype_code=dict(
+    char=4,
+    float32=5,float64=6,
+    int8=20,uint8=21,
+    int16=22,uint16=23,
+    int32=24,uint32=25,
+    int64=26,uint64=27,
+    )
+# Python types from HDF data types
+# Other than 'char' for the string type, the python types correspond to
+# the numpy data types, and can be used directly to create numpy arrays.
+# Note: put this in a lambda to hide v,k from the local namespace
+_pytype_code=(lambda : dict([(v,k) for (k,v) in _nxtype_code.iteritems()]))()
+
+# Compression to use when creating data blocks
+_compression_code=dict(
+    none=100,
+    lzw=200,
+    rle=300,
+    huffman=400)
+
+def _is_string_like(obj):
+    """
+    Return True if object acts like a string.
+    """
+    # From matplotlib cbook.py John D. Hunter
+    # Python 2.2 style licence.  See license.py in matplotlib for details.
+    if hasattr(obj, 'shape'): return False
+    try: obj + ''
+    except (TypeError, ValueError): return False
+    return True
+
+def _is_list_like(obj):
+    """
+    Return True if object acts like a list
+    """
+    try: obj + []
+    except TypeError: return False
+    return True
+
+def _libnexus():
+    """
+    Load the NeXus library.
+    """
+    # this will get changed as part of the install process
+    # it should correspond to --libdir specified to ./configure
+    nxlibdir = '/usr/local/lib'
+    # NEXUSLIB takes precedence
+    if 'NEXUSLIB' in os.environ:
+        file = os.environ['NEXUSLIB']
+        if not os.path.isfile(file):
+            raise OSError, \
+                "File %s from environment variable NEXUSLIB does exist"%(file)
+        files = [file]
+    else:
+        files = []
+
+    # Default names and locations to look for the library are system dependent
+    filedir = os.path.dirname(__file__)
+    if sys.platform in ('win32','cygwin'):
+        # NEXUSDIR is set by the Windows installer for NeXus
+        if 'NEXUSDIR' in os.environ:
+            winnxdir = os.environ['NEXUSDIR']
+        else:
+            winnxdir =  'C:/Program Files/NeXus Data Format'
+
+        files += [filedir+"/libNeXus-0.dll",
+                  winnxdir + '/bin/libNeXus-0.dll',
+                  filedir+"/libNeXus.dll"]
+    else:
+        if sys.platform in ('darwin'):
+            lib = 'libNeXus.0.dylib'
+            ldenv = 'DYLD_LIBRARY_PATH'
+        else:
+            lib = 'libNeXus.so.0'
+            ldenv = 'LD_LIBRARY_PATH'
+        # Search the load library path as well as the standard locations
+        ldpath = [p for p in os.environ.get(ldenv,'').split(':') if p != '']
+        stdpath = [ nxlibdir ]
+        files += [os.path.join(p,lib) for p in [filedir]+ldpath+stdpath]
+
+    # Given a list of files, try loading the first one that is available.
+    for file in files:
+        if not os.path.isfile(file): continue
+        try:
+            return ctypes.cdll[file]
+        except:
+            raise OSError, \
+                "NeXus library %s could not be loaded: %s"%(file,sys.exc_info())
+    raise OSError, "Set NEXUSLIB or move NeXus to one of: %s"%(", ".join(files))
+
+def _init():
+    lib = _libnexus()
+    lib.NXMDisableErrorReporting()
+    return lib
+
+# Define the interface to the dll
+nxlib = _init()
+
+
+def open(filename, mode='r'):
+    """
+    Returns a NeXus file object.
+    """
+    return NeXus(filename, mode)
+
+class NeXusError(Exception):
+    """NeXus Error"""
+    pass
+
+class NeXus(object):
+
+    # ==== File ====
+    nxlib.nxiopen_.restype = c_int
+    nxlib.nxiopen_.argtypes = [c_char_p, c_int, c_void_pp]
+    def __init__(self, filename, mode='r'):
+        """
+        Open the NeXus file returning a handle.
+
+        mode can be one of the following:
+            nxs.ACC_READ      'r'     open a file read-only
+            nxs.ACC_RDWR      'rw'    open a file read/write
+            nxs.ACC_CREATE    'w'     open a file write
+            nxs.ACC_CREATE4   'w4'    open a Nexus file with HDF4
+            nxs.ACC_CREATE5   'w5'    open a Nexus file with HDF5
+            nxs.ACC_CREATEXML 'wx'    open a Nexus file with XML
+
+        Raises ValueError if the open mode is invalid.
+
+        Raises NeXusError if the file could not be opened, with the
+        filename as part of the error message.
+
+        Corresponds to NXopen(filename,mode,&handle)
+        """
+        self.isopen = False
+
+        # Convert open mode from string to integer and check it is valid
+        if mode in _nxopen_mode: mode = _nxopen_mode[mode]
+        if mode not in _nxopen_mode.values():
+            raise ValueError, "Invalid open mode %s",str(mode)
+
+        self.filename, self.mode = filename, mode
+        self.handle = c_void_p(None)
+        self._path = []
+        self._indata = False
+        status = nxlib.nxiopen_(filename,mode,_ref(self.handle))
+        if status == ERROR:
+            if mode in [ACC_READ, ACC_RDWR]:
+                op = 'open'
+            else:
+                op = 'create'
+            raise NeXusError, "Could not %s %s"%(op,filename)
+        self.isopen = True
+
+    def _getpath(self):
+        mypath = [level[0] for level in self._path]
+        return '/'+'/'.join(mypath)
+    path = property(_getpath,doc="Unix-style path to node")
+
+    def _getlongpath(self):
+        mypath = [':'.join(level) for level in self._path]
+        return '/' + '/'.join(mypath)
+    longpath = property(_getlongpath, doc="Unix-style path including " \
+                        + "nxclass to the node")
+
+    def __del__(self):
+        """
+        Be sure to close the file before deleting the last reference.
+        """
+        if self.isopen: self.close()
+
+
+    def __str__(self):
+        """
+        Return a string representation of the NeXus file handle.
+        """
+        return "NeXus('%s')"%self.filename
+
+
+    def open(self):
+        """
+        Opens the NeXus file handle if it is not already open.
+
+        Raises NeXusError if the file could not be opened.
+
+        Corresponds to NXopen(filename,mode,&handle)
+        """
+        if self.isopen: return
+        if self.mode==ACC_READ:
+            mode = ACC_READ
+        else:
+            mode = ACC_RDWR
+        status = nxlib.nxiopen_(self.filename,mode,_ref(self.handle))
+        if status == ERROR:
+            raise NeXusError, "Could not open %s"%(self.filename)
+        self._path = []
+        self._indata = False
+
+    nxlib.nxiclose_.restype = c_int
+    nxlib.nxiclose_.argtypes = [c_void_pp]
+    def close(self):
+        """
+        Close the NeXus file associated with handle.
+
+        Raises NeXusError if file could not be closed.
+
+        Corresponds to NXclose(&handle)
+        """
+        if self.isopen:
+            self.isopen = False
+            status = nxlib.nxiclose_(_ref(self.handle))
+            if status == ERROR:
+                raise NeXusError, "Could not close NeXus file %s"%(self.filename)
+        self._path = []
+        self._indata = False
+
+    nxlib.nxiflush_.restype = c_int
+    nxlib.nxiflush_.argtypes = [c_void_pp]
+    def flush(self):
+        """
+        Flush all data to the NeXus file.
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXflush(&handle)
+        """
+        status = nxlib.nxiflush_(_ref(self.handle))
+        if status == ERROR:
+            raise NeXusError, "Could not flush NeXus file %s"%(self.filename)
+
+    nxlib.nxisetnumberformat_.restype = c_int
+    nxlib.nxisetnumberformat_.argtypes = [c_void_p, c_int, c_char_p]
+    def setnumberformat(self,type,format):
+        """
+        Set the output format for the numbers of the given type (only
+        applies to XML).
+
+        Raises ValueError if the number format is incorrect.
+
+        Corresponds to NXsetnumberformat(&handle,type,format)
+        """
+        type = _nxtype_code[type]
+        status = nxlib.nxisetnumberformat_(self.handle,type,format)
+        if status == ERROR:
+            raise ValueError,\
+                "Could not set %s to %s in %s"%(type,format,self.filename)
+
+    # ==== Group ====
+    nxlib.nximakegroup_.restype = c_int
+    nxlib.nximakegroup_.argtypes = [c_void_p, c_char_p, c_char_p]
+    def makegroup(self, name, nxclass):
+        """
+        Create the group nxclass:name.
+
+        Raises NeXusError if the group could not be created.
+
+        Corresponds to NXmakegroup(handle, name, nxclass)
+        """
+        #print "makegroup",self._loc(),name,nxclass
+        status = nxlib.nximakegroup_(self.handle, name, nxclass)
+        if status == ERROR:
+            raise NeXusError,\
+                "Could not create %s:%s in %s"%(nxclass,name,self._loc())
+
+    nxlib.nxiopenpath_.restype = c_int
+    nxlib.nxiopenpath_.argtypes = [c_void_p, c_char_p]
+    def openpath(self, path):
+        """
+        Open a particular group '/path/to/group'.  Paths can be
+        absolute or relative to the currently open group.  If openpath
+        fails, then currently open path may not be different from the
+        starting path. For better performation the types can be
+        specified as well using '/path:type1/to:type2/group:type3'
+        which will prevent searching the file for the types associated
+        with the supplied names.
+
+        Raises ValueError.
+
+        Corresponds to NXopenpath(handle, path)
+        """
+        self._openpath(path, opendata=True)
+
+    def _openpath(self, path, opendata=True):
+        """helper function: open relative path and maybe data"""
+        # Determine target node as sequence of group names
+        if path == '/':
+            target = []
+        else:
+            if path.endswith("/"):
+                path = path[:-1]
+            if path.startswith('/'):
+                target = path[1:].split('/')
+            else:
+                target = self._path + path.split('/')
+
+        # Remove relative path indicators from target
+        L = []
+        for t in target:
+            if t == '.': 
+                # Skip current node
+                pass
+            elif t == '..':
+                if L == []:
+                    raise ValueError("too many '..' in path")
+                L.pop()
+            else:
+                L.append(t)
+        target = L
+
+        # split out nxclass from each level if available
+        L = []
+        for t in target:
+            try:
+                item = t.split(":")
+                if len(item) == 1:
+                    L.append((item[0], None))
+                else:
+                    L.append(tuple(item))
+            except AttributeError:
+                L.append(t)
+        target = L
+
+        #print "current path",self._path
+        #print "%s"%path,target
+
+        # Find which groups need to be closed and opened
+        up = []
+        down = []
+        for (i, (name, nxclass)) in enumerate(target):
+            if i == len(self._path):
+                #print "target longer than current"
+                up = []
+                down = target[i:]
+                break
+            elif self._path[i] != name:
+                #print "target and current differ at",name
+                up = self._path[i:]
+                down = target[i:]
+                break
+        else:
+            #print "target shorter than current"
+            up = self._path[len(target):]
+            down = []
+
+        # add more information to the down path
+        for i in xrange(len(down)):
+            try:
+                (name, nxclass) = down[i]
+            except ValueError:
+                down[i] = (down[i], None)
+        #print "close,open",up,down
+
+        # Close groups on the way up
+        if self._indata and up != []:
+            self.closedata()
+            up.pop()
+        for target in up:
+            self.closegroup()
+        
+        # Open groups on the way down
+        for target in down:
+            (name, nxclass) = target
+            if nxclass is None:
+                nxclass = self.__getnxclass(name)
+            if nxclass != "SDS":
+                self.opengroup(name, nxclass)
+            elif opendata:
+                self.opendata(name)
+            else:
+                raise ValueError("node %s not in %s"%(name,self.path))
+
+    nxlib.nxiopengrouppath_.restype = c_int
+    nxlib.nxiopengrouppath_.argtypes = [c_void_p, c_char_p]
+    def opengrouppath(self, path):
+        """
+        Open a particular group '/path/to/group', or the dataset containing
+        the group if the path refers to a dataset.  Paths can be relative to
+        the currently open group.
+
+        Raises ValueError.
+
+        Corresponds to NXopengrouppath(handle, path)
+        """
+        self._openpath(path,opendata=False)
+
+    nxlib.nxiopengroup_.restype = c_int
+    nxlib.nxiopengroup_.argtypes = [c_void_p, c_char_p, c_char_p]
+    def opengroup(self, name, nxclass=None):
+        """
+        Open the group nxclass:name. If the nxclass is not specified
+        this will search for it.
+
+        Raises NeXusError if the group could not be opened.
+
+        Corresponds to NXopengroup(handle, name, nxclass)
+        """
+        #print "opengroup",self._loc(),name,nxclass
+        if nxclass is None:
+            nxclass = self.__getnxclass(name)
+        status = nxlib.nxiopengroup_(self.handle, name, nxclass)
+        if status == ERROR:
+            raise ValueError,\
+                "Could not open %s:%s in %s"%(nxclass,name,self._loc())
+        self._path.append((name,nxclass))
+
+    nxlib.nxiclosegroup_.restype = c_int
+    nxlib.nxiclosegroup_.argtypes = [c_void_p]
+    def closegroup(self):
+        """
+        Close the currently open group.
+
+        Raises NeXusError if the group could not be closed.
+
+        Corresponds to NXclosegroup(handle)
+        """
+        #print "closegroup"
+        if self._indata:
+            raise NeXusError, "Close data before group at %s"%(self._loc())
+        status = nxlib.nxiclosegroup_(self.handle)
+        if status == ERROR:
+            raise NeXusError, "Could not close group at %s"%(self._loc())
+        self._path.pop()
+
+    nxlib.nxigetgroupinfo_.restype = c_int
+    nxlib.nxigetgroupinfo_.argtypes = [c_void_p, c_int_p, c_char_p, c_char_p]
+    def getgroupinfo(self):
+        """
+        Query the currently open group returning the tuple
+        numentries, name, nxclass.
+
+        Raises ValueError if the group could not be opened.
+
+        Corresponds to NXgetgroupinfo(handle)
+
+        Note: corrects error in HDF5 where getgroupinfo returns the entire
+        path rather than the group name.  Use the path attribute to get
+        a sensible value of path.
+        """
+        # Space for the returned strings
+        path = ctypes.create_string_buffer(MAXPATHLEN)
+        nxclass = ctypes.create_string_buffer(MAXNAMELEN)
+        n = c_int(0)
+        status = nxlib.nxigetgroupinfo_(self.handle,_ref(n),path,nxclass)
+        if status == ERROR:
+            raise ValueError, "Could not get group info: %s"%(self._loc())
+        #print "getgroupinfo",self._loc(),nxclass.value,name.value,n.value
+        name = path.value.split('/')[-1]  # Protect against HDF5 returning path
+        return n.value,name,nxclass.value
+
+    nxlib.nxiinitgroupdir_.restype = c_int
+    nxlib.nxiinitgroupdir_.argtypes = [c_void_p]
+    def initgroupdir(self):
+        """
+        Reset getnextentry to return the first entry in the group.
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXinitgroupdir(handle)
+        """
+        status = nxlib.nxiinitgroupdir_(self.handle)
+        if status == ERROR:
+            raise NeXusError, \
+                "Could not reset group scan: %s"%(self._loc())
+
+    nxlib.nxigetnextentry_.restype = c_int
+    nxlib.nxigetnextentry_.argtypes = [c_void_p, c_char_p, c_char_p, c_int_p]
+    def getnextentry(self):
+        """
+        Return the next entry in the group as name,nxclass tuple. If
+        end of data is reached this returns the tuple (None, None)
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXgetnextentry(handle,name,nxclass,&storage).
+
+        This function doesn't return the storage class for data entries
+        since getinfo returns shape and storage, both of which are required
+        to read the data.
+
+        Note that HDF4 files can have entries in the file with classes
+        that don't need to be processed.  If the file follows the standard
+        NeXus DTDs then skip any entry for which nxclass.startswith('NX') 
+        is False.  For non-conforming files, skip those entries with 
+        nxclass in nxs.H4SKIP.
+        """
+        name = ctypes.create_string_buffer(MAXNAMELEN)
+        nxclass = ctypes.create_string_buffer(MAXNAMELEN)
+        storage = c_int(0)
+        status = nxlib.nxigetnextentry_(self.handle,name,nxclass,_ref(storage))
+        if status == EOD:
+            return (None, None)
+        if status == ERROR:
+            raise NeXusError, \
+                "Could not get next entry: %s"%(self._loc())
+        ## Note: ignoring storage --- it is useless without dimensions
+        #if nxclass == 'SDS':
+        #    dtype = _pytype_code(storage.value)
+        #print "nextentry",nxclass.value, name.value, storage.value
+        return name.value,nxclass.value
+
+    def getentries(self):
+        """
+        Return a dictionary of the groups[name]=type below the
+        existing open one.
+
+        Raises NeXusError if this fails.
+        """
+        self.initgroupdir()
+        result = {}
+        (name, nxclass) = self.getnextentry()
+        if (name, nxclass) != (None, None):
+            result[name] = nxclass
+        while (name, nxclass) != (None, None):
+            result[name] = nxclass
+            (name, nxclass) = self.getnextentry()
+        return result
+
+    def __getnxclass(self, target):
+        """
+        Return the nxclass of the supplied name.
+        """
+        self.initgroupdir()
+        while True:
+            (nxname, nxclass) = self.getnextentry()
+            if nxname == target:
+                return nxclass
+            if nxname is None:
+                break
+        raise NeXusError("Failed to find entry with name \"%s\" at %s" % (target, self.path))
+
+    def entries(self):
+        """
+        Iterator of entries.
+
+        for name,nxclass in nxs.entries():
+            process(name,nxclass)
+
+        This automatically opens the corresponding group/data for you,
+        and closes it when you are done.  Do not rely on any paths
+        remaining open between entries as we restore the current
+        path each time.
+
+        This does not correspond to an existing NeXus API function,
+        but instead combines the work of initgroupdir/getnextentry
+        and open/close on data and group.  Entries in nxs.H4SKIP are
+        ignored.
+        """
+        # To preserve the semantics we must read in the whole list
+        # first, then process the entries one by one.  Keep track
+        # of the path so we can restore it between entries.
+        path = self.path
+
+        # Read list of entries
+        self.initgroupdir()
+        n,_,_ = self.getgroupinfo()
+        L = []
+        for dummy in range(n):
+            name,nxclass = self.getnextentry()
+            if nxclass not in H4SKIP:
+                L.append((name,nxclass))
+        for name,nxclass in L:
+            self.openpath(path)  # Reset the file cursor
+            if nxclass == "SDS":
+                self.opendata(name)
+            else:
+                self.opengroup(name,nxclass)
+            yield name,nxclass
+
+    # ==== Data ====
+    nxlib.nxigetrawinfo64_.restype = c_int
+    nxlib.nxigetrawinfo64_.argtypes = [c_void_p, c_int_p, c_void_p, c_int_p]
+    def getrawinfo(self):
+        """
+        Returns the tuple dimensions,type for the currently open dataset.
+        Dimensions is an integer array whose length corresponds to the rank
+        of the dataset and whose elements are the size of the individual
+        dimensions.  Storage type is returned as a string, with 'char' for
+        a stored string, '[u]int[8|16|32]' for various integer values or
+        'float[32|64]' for floating point values.  No support for
+        complex values.
+
+        Unlike getinfo(), the size of the string storage area is
+        returned rather than the length of the stored string.
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXgetrawinfo(handle, &rank, dims, &storage),
+        but with storage converted from HDF values to numpy compatible
+        strings, and rank implicit in the length of the returned dimensions.
+        """
+        rank = c_int(0)
+        shape = numpy.zeros(MAXRANK, 'int64')
+        storage = c_int(0)
+        status = nxlib.nxigetrawinfo64_(self.handle, _ref(rank), 
+                                        shape.ctypes.data, _ref(storage))
+        if status == ERROR:
+            raise NeXusError, "Could not get data info: %s"%(self._loc())
+        shape = shape[:rank.value]+0
+        dtype = _pytype_code[storage.value]
+        #print "getrawinfo",self._loc(),"->",shape,dtype
+        return shape,dtype
+
+    nxlib.nxigetinfo64_.restype = c_int
+    nxlib.nxigetinfo64_.argtypes = [c_void_p, c_int_p, c_void_p, c_int_p]
+    def getinfo(self):
+        """
+        Returns the tuple dimensions,type for the currently open dataset.
+        Dimensions is an integer array whose length corresponds to the rank
+        of the dataset and whose elements are the size of the individual
+        dimensions.  Storage type is returned as a string, with 'char' for
+        a stored string, '[u]int[8|16|32]' for various integer values or
+        'float[32|64]' for floating point values.  No support for
+        complex values.
+
+        Unlike getrawinfo(), the length of the stored string is
+        returned rather than the size of the string storage area.
+
+        Raises NeXusError if this fails.
+
+        Note that this is the recommended way to establish if you have
+        a dataset open.
+
+        Corresponds to NXgetinfo(handle, &rank, dims, &storage),
+        but with storage converted from HDF values to numpy compatible
+        strings, and rank implicit in the length of the returned dimensions.
+        """
+        rank = c_int(0)
+        shape = numpy.zeros(MAXRANK, 'int64')
+        storage = c_int(0)
+        status = nxlib.nxigetinfo64_(self.handle, _ref(rank), 
+                                     shape.ctypes.data,
+                                     _ref(storage))
+        if status == ERROR:
+            raise NeXusError, "Could not get data info: %s"%(self._loc())
+        shape = shape[:rank.value]+0
+        dtype = _pytype_code[storage.value]
+        #print "getinfo",self._loc(),"->",shape,dtype
+        return shape,dtype
+
+    nxlib.nxiopendata_.restype = c_int
+    nxlib.nxiopendata_.argtypes = [c_void_p, c_char_p]
+    def opendata(self, name):
+        """
+        Open the named data set within the current group.
+
+        Raises ValueError if could not open the dataset.
+
+        Corresponds to NXopendata(handle, name)
+        """
+        #print "opendata",self._loc(),name
+        if self._indata:
+            status = ERROR
+        else:
+            status = nxlib.nxiopendata_(self.handle, name)
+        if status == ERROR:
+            raise ValueError, "Could not open data %s: %s"%(name, self._loc())
+        self._path.append((name,"SDS"))
+        self._indata = True
+
+    nxlib.nxiclosedata_.restype = c_int
+    nxlib.nxiclosedata_.argtypes = [c_void_p]
+    def closedata(self):
+        """
+        Close the currently open data set.
+
+        Raises NeXusError if this fails (e.g., because no
+        dataset is open).
+
+        Corresponds to NXclosedata(handle)
+        """
+        #print "closedata"
+        status = nxlib.nxiclosedata_(self.handle)
+        if status == ERROR:
+            raise NeXusError,\
+                "Could not close data at %s"%(self._loc())
+        self._path.pop()
+        self._indata = False
+
+    nxlib.nximakedata64_.restype = c_int
+    nxlib.nximakedata64_.argtypes  = [c_void_p, c_char_p, c_int, c_int, c_int64_p]
+    def makedata(self, name, dtype=None, shape=None):
+        """
+        Create a data element of the given type and shape.  See getinfo
+        for details on types.  This does not open the data for writing.
+
+        Set the first dimension to nxs.UNLIMITED, for extensible data sets,
+        and use putslab to write individual slabs.
+
+        Raises ValueError if it fails.
+
+        Corresponds to NXmakedata(handle,name,type,rank,dims)
+        """
+        # TODO: With keywords for compression and chunks, this can act as
+        # TODO: compmakedata.
+        # TODO: With keywords for value and attr, this can be used for
+        # TODO: makedata, opendata, putdata, putattr, putattr, ..., closedata
+        #print "makedata",self._loc(),name,shape,dtype
+        storage = _nxtype_code[str(dtype)]
+        shape = numpy.asarray(shape,'int64')
+        status = nxlib.nximakedata64_(self.handle,name,storage,len(shape),
+                                      shape.ctypes.data_as(c_int64_p))
+        if status == ERROR:
+            raise ValueError, "Could not create data %s: %s"%(name,self._loc())
+
+    nxlib.nxicompmakedata64_.restype = c_int
+    nxlib.nxicompmakedata64_.argtypes  = [c_void_p, c_char_p, c_int, c_int, c_int64_p,
+                                          c_int, c_int64_p]
+    def compmakedata(self, name, dtype=None, shape=None, mode='lzw',
+                     chunks=None):
+        """
+        Create a data element of the given dimensions and type.  See
+        getinfo for details on types.  Compression mode is one of
+        'none', 'lzw', 'rle' or 'huffman'.  chunks gives the alignment
+        of the compressed chunks in the data file.  There should be one
+        chunk size for each dimension in the data.
+
+        Defaults to mode='lzw' with chunk size set to the length of the
+        fastest varying dimension.
+
+        Raises ValueError if it fails.
+
+        Corresponds to NXmakedata(handle,name,type,rank,dims).
+        """
+        storage = _nxtype_code[str(dtype)]
+        # Make sure shape/chunk_shape are integers; hope that 32/64 bit issues
+        # with the c int type sort themselves out.
+        dims = numpy.asarray(shape,'int64')
+        if chunks == None:
+            chunks = numpy.ones(dims.shape,'int64')
+            chunks[-1] = shape[-1]
+        else:
+            chunks = numpy.array(chunks,'int64')
+        status = nxlib.nxicompmakedata64_(self.handle,name,storage,len(dims),
+                                          dims.ctypes.data_as(c_int64_p),
+                                          _compression_code[mode],
+                                          chunks.ctypes.data_as(c_int64_p))
+        if status == ERROR:
+            raise ValueError, \
+                "Could not create compressed data %s: %s"%(name,self._loc())
+
+    nxlib.nxigetdata_.restype = c_int
+    nxlib.nxigetdata_.argtypes = [c_void_p, c_void_p]
+    def getdata(self):
+        """
+        Return the data.  If data is a string (1-D char array), a python
+        string is returned.  If data is a scalar (1-D numeric array of
+        length 1), a python scalar is returned.  If data is a string 
+        array, a numpy array of type 'S#' where # is the maximum string
+        length is returned.  If data is a numeric array, a numpy array
+        is returned.
+
+        Raises ValueError if this fails.
+
+        Corresponds to NXgetdata(handle, data)
+        """
+        # TODO: consider accepting preallocated data so we don't thrash memory
+        shape,dtype = self.getinfo()
+        dummy_data,pdata,dummy_size,datafn = self._poutput(dtype,shape)
+        status = nxlib.nxigetdata_(self.handle,pdata)
+        if status == ERROR:
+            raise ValueError, "Could not read data: %s"%(self._loc())
+        #print "getdata",self._loc(),shape,dtype
+        return datafn()
+
+    nxlib.nxigetslab64_.restype = c_int
+    nxlib.nxigetslab64_.argtypes = [c_void_p, c_void_p, c_int64_p, c_int64_p]
+    def getslab(self, slab_offset, slab_shape):
+        """
+        Get a slab from the data array.
+
+        Offsets are 0-origin.  Shape can be inferred from the data.
+        Offset and shape must each have one entry per dimension.
+
+        Raises ValueError if this fails.
+
+        Corresponds to NXgetslab(handle,data,offset,shape)
+        """
+        # TODO: consider accepting preallocated data so we don't thrash memory
+        dummy_shape,dtype = self.getrawinfo()
+        dummy_data,pdata,dummy_size,datafn = self._poutput(dtype,slab_shape)
+        slab_offset = numpy.asarray(slab_offset,'int64')
+        slab_shape = numpy.asarray(slab_shape,'int64')
+        status = nxlib.nxigetslab64_(self.handle,pdata,
+                                     slab_offset.ctypes.data_as(c_int64_p),
+                                     slab_shape.ctypes.data_as(c_int64_p))
+        #print "slab",offset,size,data
+        if status == ERROR:
+            raise ValueError, "Could not read slab: %s"%(self._loc())
+        return datafn()
+
+    nxlib.nxiputdata_.restype = c_int
+    nxlib.nxiputdata_.argtypes = [c_void_p, c_void_p]
+    def putdata(self, data):
+        """
+        Write data into the currently open data block.
+
+        Raises ValueError if this fails.
+
+        Corresponds to NXputdata(handle, data)
+        """
+        shape,dtype = self.getrawinfo()
+        #print "putdata",self._loc(),shape,dtype
+        data,pdata = self._pinput(data,dtype,shape)
+        status = nxlib.nxiputdata_(self.handle,pdata)
+        if status == ERROR:
+            raise ValueError, "Could not write data: %s"%(self._loc())
+
+    nxlib.nxiputslab64_.restype = c_int
+    nxlib.nxiputslab64_.argtypes = [c_void_p, c_void_p, c_int64_p, c_int64_p]
+    def putslab(self, data, slab_offset, slab_shape):
+        """
+        Put a slab into the data array.
+
+        Offsets are 0-origin.  Shape can be inferred from the data.
+        Offset and shape must each have one entry per dimension.
+
+        Raises ValueError if this fails.
+
+        Corresponds to NXputslab(handle,data,offset,shape)
+        """
+        dummy_shape,dtype = self.getrawinfo()
+        data,pdata = self._pinput(data,dtype,slab_shape)
+        slab_offset = numpy.asarray(slab_offset,'int64')
+        slab_shape = numpy.asarray(slab_shape,'int64')
+        #print "slab",offset,size,data
+        status = nxlib.nxiputslab64_(self.handle,pdata,
+                                     slab_offset.ctypes.data_as(c_int64_p),
+                                     slab_shape.ctypes.data_as(c_int64_p))
+        if status == ERROR:
+            raise ValueError, "Could not write slab: %s"%(self._loc())
+
+
+
+    # ==== Attributes ====
+    nxlib.nxiinitattrdir_.restype = c_int
+    nxlib.nxiinitattrdir_.argtypes = [c_void_p]
+    def initattrdir(self):
+        """
+        Reset the getnextattr list to the first attribute.
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXinitattrdir(handle)
+        """
+        status = nxlib.nxiinitattrdir_(self.handle)
+        if status == ERROR:
+            raise NeXusError, \
+                "Could not reset attribute list: %s"%(self._loc())
+
+    nxlib.nxigetattrinfo_.restype = c_int
+    nxlib.nxigetattrinfo_.argtypes = [c_void_p, c_int_p]
+    def getattrinfo(self):
+        """
+        Returns the number of attributes for the currently open
+        group/data object.  Do not call getnextattr() more than
+        this number of times.
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXgetattrinfo(handl, &n)
+        """
+        n = c_int(0)
+        status = nxlib.nxigetattrinfo_(self.handle,_ref(n))
+        if status == ERROR:
+            raise NeXusError, "Could not get attr info: %s"%(self._loc())
+        #print "num attrs",n.value
+        return n.value
+
+    nxlib.nxigetnextattr_.restype = c_int
+    nxlib.nxigetnextattr_.argtypes = [c_void_p, c_char_p, c_int_p, c_int_p]
+    def getnextattr(self):
+        """
+        Returns the name, length, and data type for the next attribute.
+        Call getattrinfo to determine the number of attributes before
+        calling getnextattr. Data type is returned as a string.  See
+        getinfo for details.  Length is the number of elements in the
+        attribute.
+
+        Raises NeXusError if NeXus returns ERROR or EOD.
+
+        Corresponds to NXgetnextattr(handle,name,&length,&storage)
+        but with storage converted from HDF values to numpy compatible
+        strings.
+
+        Note: NeXus API documentation seems to say that length is the number
+        of bytes required to store the entire attribute.
+        """
+        name = ctypes.create_string_buffer(MAXNAMELEN)
+        length = c_int(0)
+        storage = c_int(0)
+        status = nxlib.nxigetnextattr_(self.handle,name,_ref(length),_ref(storage))
+        if status == EOD:
+            return (None, None, None)
+        if status == ERROR or status == EOD:
+            raise NeXusError, "Could not get next attr: %s"%(self._loc())
+        dtype = _pytype_code[storage.value]
+        #print "getnextattr",name.value,length.value,dtype
+        return name.value, length.value, dtype
+
+    # TODO: Resolve discrepency between NeXus API documentation and
+    # TODO: apparent behaviour for getattr/putattr length.
+    nxlib.nxigetattr_.restype = c_int
+    nxlib.nxigetattr_.argtypes = [c_void_p, c_char_p, c_void_p, c_int_p, c_int_p]
+    def getattr(self, name, length, dtype):
+        """
+        Returns the value of the named attribute.  Requires length and
+        data type from getnextattr to allocate the appropriate amount of
+        space for the attribute.
+
+        Corresponds to NXgetattr(handle,name,data,&length,&storage)
+        """
+        if dtype is 'char': length += 1  # HDF4 needs zero-terminator
+        dummy_data,pdata,size,datafn = self._poutput(str(dtype),[length])
+        storage = c_int(_nxtype_code[str(dtype)])
+        #print "getattr",self._loc(),name,length,size,dtype
+        size = c_int(size)
+        status = nxlib.nxigetattr_(self.handle,name,pdata,_ref(size),_ref(storage))
+        if status == ERROR:
+            raise ValueError, "Could not read attr %s: %s" % (name,self._loc())
+        #print "getattr",self._loc(),name,datafn()
+        return datafn()
+
+    nxlib.nxiputattr_.restype = c_int
+    nxlib.nxiputattr_.argtypes = [c_void_p, c_char_p, c_void_p, c_int, c_int]
+    def putattr(self, name, value, dtype = None):
+        """
+        Saves the named attribute.  The attribute value is a string
+        or a scalar.
+
+        Raises TypeError if the value type is incorrect.
+        Raises NeXusError if the attribute could not be saved.
+
+        Corresponds to NXputattr(handle,name,data,length,storage)
+
+        Note length is the number of elements to write rather
+        than the number of bytes to write.
+        """
+        # Establish attribute type
+        if dtype == None:
+            # Type is inferred from value
+            if hasattr(value,'dtype'):
+                dtype = str(value.dtype)
+            elif _is_string_like(value):
+                dtype = 'char'
+            else:
+                value = numpy.array(value)
+                dtype = str(value.dtype)
+        else:
+            # Set value to type
+            dtype = str(dtype)
+            if dtype == 'char' and not _is_string_like(value):
+                raise TypeError, "Expected string for 'char' attribute value"
+            if dtype != 'char':
+                value = numpy.array(value,dtype=dtype)
+
+        # Determine shape
+        if dtype == 'char':
+            length = len(value)
+            data = value
+        elif numpy.prod(value.shape) != 1:
+            # NAPI silently ignores attribute arrays
+            raise TypeError, "Attribute value must be scalar or string"
+        else:
+            length = 1
+            data = value.ctypes.data
+
+        # Perform the call
+        storage = c_int(_nxtype_code[dtype])
+        status = nxlib.nxiputattr_(self.handle,name,data,length,storage)
+        if status == ERROR:
+            raise NeXusError, "Could not write attr %s: %s"%(name,self._loc())
+
+    def getattrs(self):
+        """
+        Returns a dicitonary of the attributes on the current node.
+
+        This is a second form of attrs(self).
+        """
+        result = {}
+        for (name, value) in self.attrs():
+            result[name] = value
+        return result
+
+    def attrs(self):
+        """
+        Iterate over attributes.
+
+        for name,value in file.attrs():
+            process(name,value)
+
+        This automatically reads the attributes of the group/data.  Do not
+        change the active group/data while processing the list.
+
+        This does not correspond to an existing NeXus API function, but
+        combines the work of attrinfo/initattrdir/getnextattr/getattr.
+        """
+        self.initattrdir()
+        n = self.getattrinfo()
+        for dummy in range(n):
+            name,length,dtype = self.getnextattr()
+            value = self.getattr(name,length,dtype)
+            yield name,value
+
+    # ==== Linking ====
+    nxlib.nxigetgroupid_.restype = c_int
+    nxlib.nxigetgroupid_.argtypes = [c_void_p, c_NXlink_p]
+    def getgroupID(self):
+        """
+        Return the id of the current group so we can link to it later.
+
+        Raises NeXusError
+
+        Corresponds to NXgetgroupID(handle, &ID)
+        """
+        ID = _NXlink()
+        status = nxlib.nxigetgroupid_(self.handle,_ref(ID))
+        if status == ERROR:
+            raise NeXusError, "Could not link to group: %s"%(self._loc())
+        return ID
+
+    nxlib.nxigetdataid_.restype = c_int
+    nxlib.nxigetdataid_.argtypes = [c_void_p, c_NXlink_p]
+    def getdataID(self):
+        """
+        Return the id of the current data so we can link to it later.
+
+        Raises NeXusError
+
+        Corresponds to NXgetdataID(handle, &ID)
+        """
+        ID = _NXlink()
+        status = nxlib.nxigetdataid_(self.handle,_ref(ID))
+        if status == ERROR:
+            raise NeXusError, "Could not link to data: %s"%(self._loc())
+        return ID
+
+    nxlib.nximakelink_.restype = c_int
+    nxlib.nximakelink_.argtypes = [c_void_p, c_NXlink_p]
+    def makelink(self, ID):
+        """
+        Link the previously captured group/data ID into the currently
+        open group.
+
+        Raises NeXusError
+
+        Corresponds to NXmakelink(handle, &ID)
+        """
+        status = nxlib.nximakelink_(self.handle,_ref(ID))
+        if status == ERROR:
+            raise NeXusError, "Could not make link: %s"%(self._loc())
+
+    nxlib.nximakenamedlink_.restype = c_int
+    nxlib.nximakenamedlink_.argtypes = [c_void_p, c_char_p, c_NXlink_p]
+    def makenamedlink(self,name,ID):
+        """
+        Link the previously captured group/data ID into the currently
+        open group, but under a different name.
+
+        Raises NeXusError
+
+        Corresponds to NXmakenamedlink(handle,name,&ID)
+        """
+        status = nxlib.nximakenamedlink_(self.handle,name,_ref(ID))
+        if status == ERROR:
+            raise NeXusError, "Could not make link %s: %s"%(name,self._loc())
+
+    nxlib.nxisameid_.restype = c_int
+    nxlib.nxisameid_.argtypes = [c_void_p, c_NXlink_p, c_NXlink_p]
+    def sameID(self, ID1, ID2):
+        """
+        Return True of ID1 and ID2 point to the same group/data.
+
+        This should not raise any errors.
+
+        Corresponds to NXsameID(handle,&ID1,&ID2)
+        """
+        status = nxlib.nxisameid_(self.handle, _ref(ID1), _ref(ID2))
+        return status == OK
+
+    nxlib.nxiopensourcegroup_.restype = c_int
+    nxlib.nxiopensourcegroup_.argtyps = [c_void_p]
+    def opensourcegroup(self):
+        """
+        If the current node is a linked to another group or data, then
+        open the group or data that it is linked to.
+
+        Note: it is unclear how can we tell if we are linked, other than
+        perhaps the existence of a 'target' attribute in the current item.
+
+        Raises NeXusError.
+
+        Corresponds to NXopensourcegroup(handle)
+        """
+        status = nxlib.nxiopensourcegroup_(self.handle)
+        if status == ERROR:
+            raise NeXusError, "Could not open source group: %s"%(self._loc())
+
+    def link(self):
+        """
+        Returns the item which the current item links to, or None if the
+        current item is not linked.  This is equivalent to scanning the
+        attributes for target and returning it if target is not equal
+        to self.
+
+        This does not correspond to an existing NeXus API function, but
+        combines the work of attrinfo/initattrdir/getnextattr/getattr.
+        """
+        n = self.getattrinfo()
+        self.initattrdir()
+        for dummy in range(n):
+            name,length,dtype = self.getnextattr()
+            if name == "target":
+                target = self.getattr(name,length,dtype)
+                #print "target %s, path %s"%(target,self.path)
+                if target != self.path:
+                    return target
+                else:
+                    return None
+        return None
+
+    # ==== External linking ====
+    nxlib.nxiinquirefile_.restype = c_int
+    nxlib.nxiinquirefile_.argtypes = [c_void_p, c_char_p, c_int]
+    def inquirefile(self, maxnamelen=MAXPATHLEN):
+        """
+        Return the filename for the current file.  This may be different
+        from the file that was opened (file.filename) if the current
+        group is an external link to another file.
+
+        Raises NeXusError if this fails.
+
+        Corresponds to NXinquirefile(&handle,file,len)
+        """
+        filename = ctypes.create_string_buffer(maxnamelen)
+        status = nxlib.nxiinquirefile_(self.handle,filename,maxnamelen)
+        if status == ERROR:
+            raise NeXusError,\
+                "Could not determine filename: %s"%(self._loc())
+        return filename.value
+
+    nxlib.nxilinkexternal_.restype = c_int
+    nxlib.nxilinkexternal_.argtyps = [c_void_p, c_char_p,
+                                       c_char_p, c_char_p]
+    def linkexternal(self, name, nxclass, url):
+        """
+        Return the filename for the external link if there is one,
+        otherwise return None.
+
+        Raises NeXusError if link fails.
+
+        Corresponds to NXisexternalgroup(&handle,name,nxclass,file,len)
+        """
+        status = nxlib.nxilinkexternal_(self.handle,name,nxclass,url)
+        if status == ERROR:
+            raise NeXusError,\
+                "Could not link %s to %s: %s"%(name,url,self._loc())
+
+
+
+    nxlib.nxiisexternalgroup_.restype = c_int
+    nxlib.nxiisexternalgroup_.argtyps = [c_void_p, c_char_p,
+                                       c_char_p, c_char_p, c_int]
+    def isexternalgroup(self, name, nxclass, maxnamelen=MAXPATHLEN):
+        """
+        Return the filename for the external link if there is one,
+        otherwise return None.
+
+        Corresponds to NXisexternalgroup(&handle,name,nxclass,file,len)
+        """
+        url = ctypes.create_string_buffer(maxnamelen)
+        status = nxlib.nxiisexternalgroup_(self.handle,name,nxclass,
+                                              url,maxnamelen)
+        if status == ERROR:
+            return None
+        else:
+            return url.value
+
+    # ==== Utility functions ====
+    def _loc(self):
+        """
+        Return file location as string filename(path)
+
+        This is an extension to the NeXus API.
+        """
+        return "%s(%s)"%(self.filename,self.path)
+
+    def _poutput(self, dtype, shape):
+        """
+        Build space to collect a nexus data element.
+        Returns data,pdata,size,datafn where
+        - data is a python type to hold the returned data
+        - pdata is the pointer to the start of the data
+        - size is the number of bytes in the data block
+        - datafn is a lamba expression to extract the return value from data
+        Note that datafn can return a string, a scalar or an array depending
+        on the data type and shape of the data group.
+        """
+        if isinstance(shape, int):
+            shape = [shape]
+        if len(shape) == 1 and dtype == 'char':
+            # string - use ctypes allocator
+            size = int(shape[0])
+            data = ctypes.create_string_buffer(size)
+            pdata = data
+            datafn = lambda: data.value
+        else:
+            # scalar, array or string list - use numpy array
+            if dtype=='char': 
+                data = numpy.zeros(shape[:-1], dtype='S%i'%shape[-1])
+            else:
+                data = numpy.zeros(shape, dtype)
+            if len(shape) == 1 and shape[0] == 1:
+                datafn = lambda: data[0]
+            else:
+                datafn = lambda: data
+            pdata = data.ctypes.data
+            size = data.nbytes
+        return data,pdata,size,datafn
+
+    def _pinput(self, data, dtype, shape):
+        """
+        Convert an input array to a C pointer to a dense array.
+
+        Returns data, pdata where 
+        - data is a possibly new copy of the array
+        - pdata is a pointer to the beginning of the array.  
+        Note that you must hold a reference to data for as long 
+        as you need pdata to keep the memory from being released to the heap.
+        """
+        if isinstance(shape, int):
+            shape = [shape]
+        if dtype == "char":
+            data = numpy.asarray(data, dtype='S%d'%(shape[-1]))
+        else:
+            # Convert scalars to vectors of length one
+            if numpy.prod(shape) == 1 and not hasattr(data,'shape'):
+                data = numpy.array([data], dtype=dtype)
+            # Check that dimensions match
+            # Ick! need to exclude dimensions of length 1 in order to catch
+            # array slices such as a[:,1], which only report one dimension
+            input_shape = numpy.array([i for i in data.shape if i != 1])
+            target_shape = numpy.array([i for i in shape if i != 1])
+            if len(input_shape) != len(target_shape) \
+                    or (input_shape != target_shape).any():
+                raise ValueError,\
+                    "Shape mismatch %s!=%s: %s"%(data.shape,shape,self._loc())
+            # Check data type
+            if str(data.dtype) != dtype:
+                raise ValueError,\
+                    "Type mismatch %s!=%s: %s"%(dtype,data.dtype,self._loc())
+
+        data = numpy.ascontiguousarray(data)
+        pdata = data.ctypes.data
+            
+        return data,pdata
+
+    def show(self, path=None, indent=0):
+        """
+        Print the structure of a NeXus file from the current node.
+
+        TODO: Break this into a tree walker and a visitor.
+        """
+        oldpath = self.path
+        self.openpath(path)
+
+        print "=== File",self.inquirefile(),path
+        self._show(indent=indent)
+        self.openpath(oldpath)
+
+    def _show(self, indent=0):
+        """
+        Print the structure of a NeXus file from the current node.
+
+        TODO: Break this into a tree walker and a visitor.
+        """
+        prefix = ' '*indent
+        link = self.link()
+        if link:
+            print "%(prefix)s-> %(link)s" % locals()
+            return
+        for attr,value in self.attrs():
+            print "%(prefix)s@%(attr)s: %(value)s" % locals()
+        for name,nxclass in self.entries():
+            if nxclass == "SDS":
+                shape,dtype = self.getinfo()
+                dims = "x".join([str(x) for x in shape])
+                print "%(prefix)s%(name)s %(dtype)s %(dims)s" % locals()
+                link = self.link()
+                if link:
+                    print "  %(prefix)s-> %(link)s" % locals()
+                else:
+                    for attr,value in self.attrs():
+                        print "  %(prefix)s@%(attr)s: %(value)s" % locals()
+                    if numpy.prod(shape) < 8:
+                        value = self.getdata()
+                        print "  %s%s"%(prefix,str(value))
+            else:
+                print "%(prefix)s%(name)s %(nxclass)s" % locals()
+                self._show(indent=indent+2)
+
+
+__id__ = "$ID$"
diff --git a/bindings/python/nxs/tree.py b/bindings/python/nxs/tree.py
new file mode 100644
index 0000000..eec71c9
--- /dev/null
+++ b/bindings/python/nxs/tree.py
@@ -0,0 +1,3249 @@
+#!/usr/bin/env python
+# This program is public domain 
+# Author: Paul Kienzle, Ray Osborn
+
+"""
+NeXus data as Python trees
+==========================
+The `nexus.tree` modules are designed to accomplish two goals:
+
+    1. To provide convenient access to existing data contained in NeXus files.
+    2. To enable new NeXus data to be created and manipulated interactively.
+
+These goals are achieved by mapping hierarchical NeXus data structures directly
+into python objects, which either represent NeXus groups or NeXus fields.
+Entries in a group are referenced much like fields in a class are referenced in
+python. The entire data hierarchy can be referenced at any time, whether the
+NeXus data has been loaded in from an existing NeXus file or created dynamically
+within the python session. This provides a much more natural scripting interface
+to NeXus data than the directory model of the `nexus.napi` interface.
+
+Example 1: Loading a NeXus file
+-------------------------------
+The following commands loads NeXus data from a file, displays (some of) the
+contents as a tree, and then accesses individual data items.
+
+    >>> from nexpy.api import nexus as nx
+    >>> a=nx.load('sns/data/ARCS_7326.nxs')
+    >>> print a.tree
+    root:NXroot
+      @HDF5_Version = 1.8.2
+      @NeXus_version = 4.2.1
+      @file_name = ARCS_7326.nxs
+      @file_time = 2010-05-05T01:59:25-05:00
+      entry:NXentry
+        data:NXdata
+          data = float32(631x461x4x825)
+            @axes = rotation_angle:tilt_angle:sample_angle:time_of_flight
+            @signal = 1
+          rotation_angle = float32(632)
+            @units = degree
+          sample_angle = [ 210.  215.  220.  225.  230.]
+            @units = degree
+          tilt_angle = float32(462)
+            @units = degree
+          time_of_flight = float32(826)
+            @units = microsecond
+        run_number = 7326
+        sample:NXsample
+          pulse_time = 2854.94747365
+            @units = microsecond
+    .
+    .
+    .
+    >>> a.entry.run_number
+    NXfield(7326)
+
+So the tree returned from load() has an entry for each group, field and
+attribute.  You can traverse the hierarchy using the names of the groups.  For
+example, tree.entry.instrument.detector.distance is an example of a field
+containing the distance to each pixel in the detector. Entries can also be
+referenced by NXclass name, such as tree.NXentry[0].instrument. Since there may
+be multiple entries of the same NeXus class, the NXclass attribute returns a
+(possibly empty) list.
+
+The load() and save() functions are implemented using the class
+`nexus.tree.NeXusTree`, a subclass of `nexus.napi.NeXus` which allows all the
+usual API functions.
+
+Example 2: Creating a NeXus file dynamically
+--------------------------------------------
+The second example shows how to create NeXus data dynamically and saves it to a
+file. The data are first created as Numpy arrays
+
+    >>> import numpy as np
+    >>> x=y=np.linspace(0,2*np.pi,101)
+    >>> X,Y=np.meshgrid(y,x)
+    >>> z=np.sin(X)*np.sin(Y)
+
+Then a NeXus data groups are created and the data inserted to produce a
+NeXus-compliant structure that can be saved to a file.
+
+    >>> root=nx.NXroot(NXentry())
+    >>> print root.tree
+    root:NXroot
+      entry:NXentry
+    >>> root.entry.data=nx.NXdata(z,[x,y])
+
+Additional metadata can be inserted before saving the data to a file.
+
+    >>> root.entry.sample=nx.NXsample()
+    >>> root.entry.sample.temperature = 40.0
+    >>> root.entry.sample.temperature.units = 'K'
+    >>> root.save('example.nxs')
+
+NXfield objects have much of the functionality of Numpy arrays. They may be used
+in simple arithmetic expressions with other NXfields, Numpy arrays or scalar
+values and will be cast as ndarray objects if used as arguments in Numpy
+modules.
+
+    >>> x=nx.NXfield(np.linspace(0,10.0,11))
+    >>> x
+    NXfield([  0.   1.   2. ...,   8.   9.  10.])
+    >>> x + 10
+    NXfield([ 10.  11.  12. ...,  18.  19.  20.])
+    >>> sin(x)
+    array([ 0.        ,  0.84147098,  0.90929743, ...,  0.98935825,
+        0.41211849, -0.54402111])
+
+If the arithmetic operation is assigned to a NeXus group attribute, it will be
+automatically cast as a valid NXfield object with the type and shape determined
+by the Numpy array type and shape.
+
+    >>> entry.data.result = sin(x)
+    >>> entry.data.result
+    NXfield([ 0.          0.84147098  0.90929743 ...,  0.98935825  0.41211849
+     -0.54402111])
+    >>> entry.data.result.dtype, entry.data.result.shape
+    (dtype('float64'), (11,))
+
+NeXus Objects
+-------------
+Properties of the entry in the tree are referenced by attributes that depend
+on the object type, different nx attributes may be available.
+
+Objects (class NXobject) have attributes shared by both groups and fields::
+    * nxname   object name
+    * nxclass  object class for groups, 'NXfield' for fields
+    * nxgroup  group containing the entry, or None for the root
+    * attrs    dictionary of NeXus attributes for the object
+
+Groups (class NXgroup) have attributes for accessing children::
+    * entries  dictionary of entries within the group
+    * component('nxclass')  return group entries of a particular class
+    * dir()    print the list of entries in the group
+    * tree     return the list of entries and subentries in the group
+    * plot()   plot signal and axes for the group, if available
+
+Fields (class NXfield) have attributes for accessing data:
+    * shape    dimensions of data in the field
+    * dtype    data type
+    * nxdata   data in the field
+
+Linked fields or groups (class NXlink) have attributes for accessing the link::
+    * nxlink   reference to the linked field or group
+
+NeXus attributes (class NXattr) have a type and a value only::
+    * dtype    attribute type
+    * nxdata   attribute data
+
+There is a subclass of NXgroup for each group class defined by the NeXus standard,
+so it is possible to create an NXgroup of NeXus class NXsample directly using:
+
+    >>> sample = NXsample()
+
+The default group name will be the class name following the 'NX', so the above
+group will have an nxname of 'sample'. However, this is overridden by the
+attribute name when it is assigned as a group attribute, e.g.,
+
+    >>> entry.sample1 = NXsample()
+    >>> entry.sample1.nxname
+    sample1
+
+You can traverse the tree by component class instead of component name. Since
+there may be multiple components of the same class in one group you will need to
+specify which one to use.  For example,
+
+    tree.NXentry[0].NXinstrument[0].NXdetector[0].distance
+
+references the first detector of the first instrument of the first entry.
+Unfortunately, there is no guarantee regarding the order of the entries, and it
+may vary from call to call, so this is mainly useful in iterative searches.
+
+
+Unit Conversion
+---------------
+Data can be stored in the NeXus file in a variety of units, depending on which
+facility is storing the file.  This makes life difficult for reduction and
+analysis programs which must know the units they are working with.  Our solution
+to this problem is to allow the reader to retrieve data from the file in
+particular units.  For example, if detector distance is stored in the file using
+millimeters you can retrieve them in meters using::
+
+    entry.instrument.detector.distance.convert('m')
+
+See `nexus.unit` for more details on the unit formats supported.
+
+Reading and Writing Slabs
+-------------------------
+The slab interface to field data works by opening the file handle and keeping it
+open as long as the slab interface is needed.  This is done in python 2.5 using
+the with statement.  Once the context is entered, get() and put() methods on the
+object allow you to read and write data a slab at a time.  For example::
+
+    # Read a Ni x Nj x Nk array one vector at a time
+    with root.NXentry[0].data.data as slab:
+        Ni,Nj,Nk = slab.shape
+        size = [1,1,Nk]
+        for i in range(Ni):
+            for j in range(Nj):
+                value = slab.get([i,j,0],size)
+
+The equivalent can be done in Python 2.4 and lower using the context
+functions __enter__ and __exit__::
+
+    slab = data.slab.__enter__()
+    ... do the slab functions ...
+    data.slab.__exit__()
+
+Plotting NeXus data
+-------------------
+There is a plot() method for groups that automatically looks for 'signal' and
+'axes' attributes within the group in order to determine what to plot. These are
+defined by the 'nxsignal' and 'nxaxes' properties of the group. This means that
+the method will determine whether the plot should be one- or two- dimensional.
+For higher than two dimensions, only the top slice is plotted by default.
+
+The plot method accepts as arguments the standard matplotlib.pyplot.plot format 
+strings to customize one-dimensional plots, axis and scale limits, and will
+transmit keyword arguments to the matplotlib plotting methods.
+
+    >>> a=nx.load('chopper.nxs')
+    >>> a.entry.monitor1.plot()
+    >>> a.entry.monitor2.plot('r+', xmax=2600)
+    
+It is possible to plot over the existing figure with the oplot() method and to
+plot with logarithmic intensity scales with the logplot() method. The x- and
+y-axes can also be rendered logarithmically using the logx and logy keywards.
+
+Although the plot() method uses matplotlib by default to plot the data, you can replace
+this with your own plotter by setting nexus.NXgroup._plotter to your own plotter
+class.  The plotter class has one method::
+
+    plot(signal, axes, entry, title, format, **opts)
+
+where signal is the field containing the data, axes are the fields listing the
+signal sample points, entry is file/path within the file to the data group and
+title is the title of the group or the parent NXentry, if available.
+"""
+from __future__ import with_statement
+from copy import copy, deepcopy
+
+import numpy as np
+import napi
+from napi import NeXusError
+
+#Memory in MB
+NX_MEMORY = 500
+
+__all__ = ['NeXusTree', 'NXobject', 'NXfield', 'NXgroup', 'NXattr',
+           'NX_MEMORY', 'setmemory', 'load', 'save', 'tree', 'centers',
+           'NXlink', 'NXlinkfield', 'NXlinkgroup', 'SDS', 'NXlinkdata']
+
+#List of defined base classes (later added to __all__)
+_nxclasses = ['NXroot', 'NXentry', 'NXsubentry', 'NXdata', 'NXmonitor',
+              'NXlog', 'NXsample', 'NXinstrument', 'NXaperture', 'NXattenuator',
+              'NXbeam', 'NXbeam_stop', 'NXbending_magnet', 'NXcharacterization',
+              'NXcollection', 'NXcollimator', 'NXcrystal', 'NXdetector',
+              'NXdisk_chopper', 'NXenvironment', 'NXevent_data',
+              'NXfermi_chopper', 'NXfilter', 'NXflipper', 'NXgeometry',
+              'NXguide', 'NXinsertion_device', 'NXmirror', 'NXmoderator',
+              'NXmonochromator', 'NXnote', 'NXorientation', 'NXparameter',
+              'NXpolarizer', 'NXpositioner', 'NXprocess', 'NXsensor', 'NXshape',
+              'NXsource', 'NXtranslation', 'NXuser', 'NXvelocity_selector', 'NXtree']
+
+np.set_printoptions(threshold=5)
+
+class NeXusTree(napi.NeXus):
+
+    """
+    Structure-based interface to the NeXus file API.
+
+    Usage::
+
+      file = NeXusTree(filename, ['r','rw','w'])
+        - open the NeXus file
+      root = file.readfile()
+        - read the structure of the NeXus file.  This returns a NeXus tree.
+      file.writefile(root)
+        - write a NeXus tree to the file.
+      data = file.readpath(path)
+        - read data from a particular path
+
+    Example::
+
+      nx = NeXusTree('REF_L_1346.nxs','r')
+      tree = nx.readfile()
+      for entry in tree.NXentry:
+          process(entry)
+      copy = NeXusTree('modified.nxs','w')
+      copy.writefile(tree)
+
+    Note that the large datasets are not loaded immediately.  Instead, the
+    when the data set is requested, the file is reopened, the data read, and
+    the file closed again.  open/close are available for when we want to
+    read/write slabs without the overhead of moving the file cursor each time.
+    The NXdata objects in the returned tree hold the object values.
+    """
+
+    def readfile(self):
+        """
+        Read the NeXus file structure from the file and return a tree of NXobjects.
+
+        Large datasets are not read until they are needed.
+        """
+        self.open()
+        self.openpath("/")
+        root = self._readgroup()
+        self.close()
+        root._group = None
+        # Resolve links (not necessary now that link is set as a property)
+        #self._readlinks(root, root)
+        root._file = self
+        return root
+
+    def writefile(self, tree):
+        """
+        Write the NeXus file structure to a file.
+
+        The file is assumed to start empty. Updating individual objects can be
+        done using the napi interface, with nx.handle as the nexus file handle.
+        """
+        self.open()
+        links = []
+        for entry in tree.entries.values():
+            links += self._writegroup(entry, path="")
+        self._writelinks(links)
+        self.close()
+
+    def readpath(self, path):
+        """
+        Return the data on a particular file path.
+
+        Returns a numpy array containing the data, a python scalar, or a
+        string depending on the shape and storage class.
+        """
+        self.open()
+        self.openpath(path)
+        try:
+            return self.getdata()
+        except ValueError:
+            return None
+
+    def _readdata(self, name):
+        """
+        Read a data object and return it as an NXfield or NXlink.
+        """
+        # Finally some data, but don't read it if it is big
+        # Instead record the location, type and size
+        self.opendata(name)
+        attrs={}
+        attrs = self.getattrs()
+        if 'target' in attrs and attrs['target'] != self.path:
+            # This is a linked dataset; don't try to load it.
+            data = NXlinkfield(target=attrs['target'], name=name)
+        else:
+            dims,type = self.getinfo()
+            #Read in the data if it's not too large
+            if np.prod(dims) < 1000:# i.e., less than 1k dims
+                try:
+                    value = self.getdata()
+                except ValueError:
+                    value = None
+            else:
+                value = None
+            data = NXfield(value=value,name=name,dtype=type,shape=dims,attrs=attrs)
+        self.closedata()
+        data._infile = data._saved = data._changed = True
+        return data
+
+    # These are groups that HDFView explicitly skips
+    _skipgroups = ['CDF0.0','_HDF_CHK_TBL_','Attr0.0','RIG0.0','RI0.0',
+                   'RIATTR0.0N','RIATTR0.0C']
+
+    def _readchildren(self,n):
+        children = {}
+        for _item in range(n):
+            name,nxclass = self.getnextentry()
+            if nxclass in self._skipgroups:
+                pass # Skip known bogus classes
+            elif nxclass == 'SDS': # NXgetnextentry returns 'SDS' as the class for NXfields
+                children[name] = self._readdata(name)
+            else:
+                self.opengroup(name,nxclass)
+                children[name] = self._readgroup()
+                self.closegroup()
+        return children
+
+    def _readgroup(self):
+        """
+        Read the currently open group and return it as an NXgroup.
+        """
+        n,name,nxclass = self.getgroupinfo()
+        attrs = {}
+        attrs = self.getattrs()
+        if 'target' in attrs and attrs['target'] != self.path:
+            # This is a linked group; don't try to load it.
+            group = NXlinkgroup(target=attrs['target'], name=name)
+        else:
+            children = self._readchildren(n)
+            # If we are subclassed with a handler for the particular
+            # NXentry class name use that constructor for the group
+            # rather than the generic NXgroup class.
+            group = NXgroup(nxclass=nxclass,name=name,attrs=attrs,entries=children)
+            # Build chain back structure
+            for obj in children.values():
+                obj._group = group
+        group._infile = group._saved = group._changed = True
+        return group
+
+    def _readlinks(self, root, group):
+        """
+        Convert linked objects into direct references.
+        """
+        for entry in group.entries.values():
+            if isinstance(entry, NXlink):
+                link = root
+                try:
+                    for level in entry._target[1:].split('/'):
+                        link = getattr(link,level)
+                    entry.nxlink = link
+                except AttributeError:
+                    pass
+            elif isinstance(entry, NXgroup):
+                self._readlinks(root, entry)
+
+    def _writeattrs(self, attrs):
+        """
+        Return the attributes for the currently open group/data.
+
+        If no group or data object is open, the file attributes are returned.
+        """
+        for name,pair in attrs.iteritems():
+            self.putattr(name,pair.nxdata,pair.dtype)
+
+    def _writedata(self, data, path):
+        """
+        Write the given data to a file.
+
+        NXlinks cannot be written until the linked group is created, so
+        this routine returns the set of links that need to be written.
+        Call writelinks on the list.
+        """
+
+        path = path + "/" + data.nxname
+
+        # If the data is linked then
+        if hasattr(data,'_target'):
+            return [(path, data._target)]
+
+        shape = data.shape
+        if shape == (): shape = (1,)
+
+        #If the array size is too large, their product needs a long integer
+        if np.prod(shape) > 10000:
+            # Compress the fastest moving dimension of large datasets
+            slab_dims = np.ones(len(shape),'i')
+            if shape[-1] < 100000:
+                slab_dims[-1] = shape[-1]
+            else:
+                slab_dims[-1] = 100000
+            self.compmakedata(data.nxname, data.dtype, shape, 'lzw', slab_dims)
+        else:
+            # Don't use compression for small datasets
+            try:
+                self.makedata(data.nxname, data.dtype, shape)
+            except StandardError,errortype:
+                print "Error in tree, makedata: ",errortype
+
+        self.opendata(data.nxname)
+        self._writeattrs(data.attrs)
+        value = data.nxdata
+        if value is not None:
+            self.putdata(data.nxdata)
+        self.closedata()
+        return []
+
+    def _writegroup(self, group, path):
+        """
+        Write the given group structure, including the data.
+
+        NXlinks cannot be written until the linked group is created, so
+        this routine returns the set of links that need to be written.
+        Call writelinks on the list.
+        """
+        path = path + "/" + group.nxname
+
+        links = []
+        self.makegroup(group.nxname, group.nxclass)
+        self.opengroup(group.nxname, group.nxclass)
+        self._writeattrs(group.attrs)
+        if hasattr(group, '_target'):
+            links += [(path, group._target)]
+        for child in group.entries.values():
+            if child.nxclass == 'NXfield':
+                links += self._writedata(child,path)
+            elif hasattr(child,'_target'):
+                links += [(path+"/"+child.nxname,child._target)]
+            else:
+                links += self._writegroup(child,path)
+        self.closegroup()
+        return links
+
+    def _writelinks(self, links):
+        """
+        Create links within the NeXus file.
+
+        THese are defined by the set of pairs returned by _writegroup.
+        """
+        gid = {}
+
+        # identify targets
+        for path,target in links:
+            gid[target] = None
+
+        # find gids for targets
+        for target in gid.iterkeys():
+            self.openpath(target)
+            # Can't tell from the name if we are linking to a group or
+            # to a dataset, so cheat and rely on getdataID to signal
+            # an error if we are not within a group.
+            try:
+                gid[target] = self.getdataID()
+            except NeXusError:
+                gid[target] = self.getgroupID()
+
+        # link sources to targets
+        for path,target in links:
+            if path != target:
+                # ignore self-links
+                parent = "/".join(path.split("/")[:-1])
+                self.openpath(parent)
+                self.makelink(gid[target])
+
+
+def _readaxes(axes):
+    """
+    Return a list of axis names stored in the 'axes' attribute.
+
+    The delimiter separating each axis can be white space, a comma, or a colon.
+    """
+    import re
+    sep=re.compile('[\[]*(\s*,*:*)+[\]]*')
+    return filter(lambda x: len(x)>0, sep.split(axes))
+
+
+class AttrDict(dict):
+
+    """
+    A dictionary class to assign all attributes to the NXattr class.
+    """
+
+    def __setitem__(self, key, value):
+        if isinstance(value, NXattr):
+            dict.__setitem__(self, key, value)
+        else:
+            dict.__setitem__(self, key, NXattr(value))
+
+
+class NXattr(object):
+
+    """
+    Class for NeXus attributes of a NXfield or NXgroup object.
+
+    This class is only used for NeXus attributes that are stored in a
+    NeXus file and helps to distinguish them from Python attributes.
+    There are two Python attributes for each NeXus attribute.
+
+    Python Attributes
+    -----------------
+    nxdata : string, Numpy scalar, or Numpy ndarray
+        The value of the NeXus attribute.
+    dtype : string
+        The data type of the NeXus attribute. This is set to 'char' for
+        a string attribute or the string of the corresponding Numpy data type
+        for a numeric attribute.
+
+    NeXus Attributes
+    ----------------
+    NeXus attributes are stored in the 'attrs' dictionary of the parent object,
+    NXfield or NXgroup, but can often be referenced or assigned using the
+    attribute name as if it were an object attribute.
+
+    For example, after assigning the NXfield, the following three attribute
+    assignments are all equivalent::
+
+        >>> entry.sample.temperature = NXfield(40.0)
+        >>> entry.sample.temperature.attrs['units'] = 'K'
+        >>> entry.sample.temperature.units = NXattr('K')
+        >>> entry.sample.temperature.units = 'K'
+
+    The third version above is only allowed for NXfield attributes and is
+    not allowed if the attribute has the same name as one of the following
+    internally defined attributes, i.e.,
+
+    ['entries', 'attrs', 'dtype','shape']
+
+    or if the attribute name begins with 'nx' or '_'. It is only possible to
+    reference attributes with one of the proscribed names using the 'attrs'
+    dictionary.
+
+    """
+
+    def __init__(self,value=None,dtype=''):
+        if isinstance(value, NXattr):
+            self._data,self._dtype = value.nxdata,value.dtype
+        elif dtype:
+            if dtype in np.typeDict:
+                self._data,self._dtype = np.__dict__[dtype](value),dtype
+            elif dtype == 'char':
+                self._data,self._dtype = str(value),dtype
+            else:
+                raise NeXusError("Invalid data type")
+        else:
+            if isinstance(value, str):
+                self._data,self._dtype = str(value), 'char'
+            elif value is not None:
+                if isinstance(value, NXobject):
+                    raise NeXusError("A data attribute cannot be a NXfield or NXgroup")
+                else:
+                    self._data = np.array(value)
+                self._dtype = self._data.dtype.name
+                if self._data.size == 1:
+                    self._data = np.__dict__[self._dtype](self._data)
+            else:
+                self._data,self._dtype = None, 'char'
+
+    def __str__(self):
+        return str(self.nxdata)
+
+    def __repr__(self):
+        if str(self.dtype) == 'char':
+            return "NXattr('%s')"%self.nxdata
+        else:
+            return "NXattr(%s)"%self.nxdata
+
+    def __eq__(self, other):
+        """
+        Return true if the value of the attribute is the same as the other.
+        """
+        if isinstance(other, NXattr):
+            return self.nxdata == other.nxdata
+        else:
+            return self.nxdata == other
+
+    def _getdata(self):
+        """
+        Return the attribute value.
+        """
+        return self._data
+
+    def _getdtype(self):
+        return self._dtype
+
+    nxdata = property(_getdata,doc="The attribute values")
+    dtype = property(_getdtype, "Data type of NeXus attribute")
+
+_npattrs = filter(lambda x: not x.startswith('_'), np.ndarray.__dict__.keys())
+
+class NXobject(object):
+
+    """
+    Abstract base class for elements in NeXus files.
+
+    The object has a subclass of NXfield, NXgroup, or one of the NXgroup
+    subclasses. Child nodes should be accessible directly as object attributes.
+    Constructors for NXobject objects are defined by either the NXfield or
+    NXgroup classes.
+
+    Python Attributes
+    -----------------
+    nxclass : string
+        The class of the NXobject. NXobjects can have class NXfield, NXgroup, or
+        be one of the NXgroup subclasses.
+    nxname : string
+        The name of the NXobject. Since it is possible to reference the same
+        Python object multiple times, this is not necessarily the same as the
+        object name. However, if the object is part of a NeXus tree, this will
+        be the attribute name within the tree.
+    nxgroup : NXgroup
+        The parent group containing this object within a NeXus tree. If the
+        object is not part of any NeXus tree, it will be set to None.
+    nxpath : string
+        The path to this object with respect to the root of the NeXus tree. For
+        NeXus data read from a file, this will be a group of class NXroot, but
+        if the NeXus tree was defined interactively, it can be any valid
+        NXgroup.
+    nxroot : NXgroup
+        The root object of the NeXus tree containing this object. For
+        NeXus data read from a file, this will be a group of class NXroot, but
+        if the NeXus tree was defined interactively, it can be any valid
+        NXgroup.
+    nxfile : NeXusTree
+        The file handle of the root object of the NeXus tree containing this
+        object.
+    filename : string
+        The file name of NeXus object's tree file handle.
+    attrs : dict
+        A dictionary of the NeXus object's attributes.
+
+    Methods
+    -------
+    dir(self, attrs=False, recursive=False):
+        Print the group directory.
+
+        The directory is a list of NeXus objects within this group, either NeXus
+        groups or NXfield data. If 'attrs' is True, NXfield attributes are
+        displayed. If 'recursive' is True, the contents of child groups are also
+        displayed.
+
+    tree:
+        Return the object's tree as a string.
+
+        It invokes the 'dir' method with both 'attrs' and 'recursive'
+        set to True. Note that this is defined as a property attribute and
+        does not require parentheses.
+
+    save(self, filename, format='w5')
+        Save the NeXus group into a file
+
+        The object is wrapped in an NXroot group (with name 'root') and an
+        NXentry group (with name 'entry'), if necessary, in order to produce
+        a valid NeXus file.
+
+    """
+
+    _class = "unknown"
+    _name = "unknown"
+    _group = None
+    _file = None
+    _infile = False
+    _saved = False
+    _changed = True
+
+    def __str__(self):
+        return "%s:%s"%(self.nxclass,self.nxname)
+
+    def __repr__(self):
+        return "NXobject('%s','%s')"%(self.nxclass,self.nxname)
+
+    def _setattrs(self, attrs):
+        for k,v in attrs.items():
+            self._attrs[k] = v
+
+    def _str_name(self,indent=0):
+        if self.nxclass == 'NXfield':
+            return " "*indent+self.nxname
+        else:
+            return " "*indent+self.nxname+':'+self.nxclass
+
+    def _str_value(self,indent=0):
+        return ""
+
+    def _str_attrs(self,indent=0):
+        names = self.attrs.keys()
+        names.sort()
+        result = []
+        for k in names:
+            result.append(" "*indent+"@%s = %s"%(k,self.attrs[k].nxdata))
+        return "\n".join(result)
+
+    def _str_tree(self,indent=0,attrs=False,recursive=False):
+        """
+        Print current object and possibly children.
+        """
+        result = [self._str_name(indent=indent)]
+        if attrs and self.attrs:
+            result.append(self._str_attrs(indent=indent+2))
+        # Print children
+        entries = self.entries
+        if entries:
+            names = entries.keys()
+            names.sort()
+            if recursive:
+                for k in names:
+                    result.append(entries[k]._str_tree(indent=indent+2,
+                                                       attrs=attrs, recursive=True))
+            else:
+                for k in names:
+                    result.append(entries[k]._str_name(indent=indent+2))
+        result
+        return "\n".join(result)
+
+    def walk(self):
+        if False: yield
+
+    def dir(self,attrs=False,recursive=False):
+        """
+        Print the object directory.
+
+        The directory is a list of NeXus objects within this object, either
+        NeXus groups or NXfields. If 'attrs' is True, NXfield attributes are
+        displayed. If 'recursive' is True, the contents of child groups are
+        also displayed.
+        """
+        print self._str_tree(attrs=attrs,recursive=recursive)
+
+    @property
+    def tree(self):
+        """
+        Return the directory tree as a string.
+
+        The tree contains all child objects of this object and their children.
+        It invokes the 'dir' method with both 'attrs' and 'recursive' set
+        to True.
+        """
+        return self._str_tree(attrs=True,recursive=True)
+
+    def __enter__(self):
+        """
+        Open the datapath for reading or writing.
+
+        Note: the results are undefined if you try accessing
+        more than one slab at a time.  Don't nest your
+        "with data" statements!
+        """
+        self._close_on_exit = not self.nxfile.isopen
+        self.nxfile.open() # Force file open even if closed
+        self.nxfile.openpath(self.nxpath)
+        self._incontext = True
+        return self.nxfile
+
+    def __exit__(self, type, value, traceback):
+        """
+        Close the file associated with the data.
+        """
+        self._incontext = False
+        if self._close_on_exit:
+            self.nxfile.close()
+
+    def save(self, filename=None, format='w5'):
+        """
+        Save the NeXus object to a data file.
+
+        An error is raised if the object is an NXroot group from an external file
+        that has been opened as readonly and no file name is specified.
+
+        The object is wrapped in an NXroot group (with name 'root') and an
+        NXentry group (with name 'entry'), if necessary, in order to produce
+        a valid NeXus file.
+        
+        Example
+        -------
+        >>> data = NXdata(sin(x), x)
+        >>> data.save('file.nxs')
+        >>> print data.nxroot.tree
+        root:NXroot
+          @HDF5_Version = 1.8.2
+          @NeXus_version = 4.2.1
+          @file_name = file.nxs
+          @file_time = 2012-01-20T13:14:49-06:00
+          entry:NXentry
+            data:NXdata
+              axis1 = float64(101)
+              signal = float64(101)
+                @axes = axis1
+                @signal = 1              
+        >>> root.entry.data.axis1.units = 'meV'
+        >>> root.save()
+        """
+        if filename:
+            if self.nxclass == "NXroot":
+                root = self
+            elif self.nxclass == "NXentry":
+                root = NXroot(self)
+            else:
+                root = NXroot(NXentry(self))
+            if root.nxfile: root.nxfile.close()
+            file = NeXusTree(filename, format)
+            file.writefile(root)
+            file.close()
+            root._file = NeXusTree(filename, 'rw')
+            root._setattrs(root._file.getattrs())
+            for node in root.walk():
+                node._infile = node._saved = True
+            
+        elif self.nxfile:
+            for entry in self.nxroot.values():
+                entry.write()
+
+        else:
+            raise NeXusError("No output file specified")
+
+    @property
+    def infile(self):
+        """
+        Returns True if the object has been created in a NeXus file.
+        """
+        return self._infile
+    
+    @property
+    def saved(self):
+        """
+        Returns True if the object has been saved to a file.
+        """
+        return self._saved
+
+    @property
+    def changed(self):
+        """
+        Returns True if the object has been changed.
+        
+        This property is for use by external scripts that need to track
+        which NeXus objects have been changed.
+        """
+        return self._changed
+    
+    def set_unchanged(self, recursive=False):
+        """
+        Set an object's change status to unchanged.
+        """
+        if recursive:
+            for node in self.walk():
+                node._changed = False
+        else:
+            self._changed = False
+    
+    def _getclass(self):
+        return self._class
+
+    def _getname(self):
+        return self._name
+
+    def _setname(self, value):
+        self._name = str(value)
+
+    def _getgroup(self):
+        return self._group
+
+    def _getpath(self):
+        if self.nxgroup is None:
+            return ""
+        elif isinstance(self.nxgroup, NXroot):
+            return "/" + self.nxname
+        else:
+            return self.nxgroup._getpath()+"/"+self.nxname
+
+    def _getroot(self):
+        if self.nxgroup is None:
+            return self
+        elif isinstance(self.nxgroup, NXroot):
+            return self.nxgroup
+        else:
+            return self.nxgroup._getroot()
+
+    def _getfile(self):
+        return self.nxroot._file
+
+    def _getfilename(self):
+        return self.nxroot._file.filename
+
+    def _getattrs(self):
+        return self._attrs
+
+    nxclass = property(_getclass, doc="Class of NeXus object")
+    nxname = property(_getname, _setname, doc="Name of NeXus object")
+    nxgroup = property(_getgroup, doc="Parent group of NeXus object")
+    nxpath = property(_getpath, doc="Path to NeXus object")
+    nxroot = property(_getroot, doc="Root group of NeXus object's tree")
+    nxfile = property(_getfile, doc="File handle of NeXus object's tree")
+    attrs = property(_getattrs, doc="NeXus attributes for an object")
+
+
+class NXfield(NXobject):
+
+    """
+    A NeXus data field.
+
+    This is a subclass of NXobject that contains scalar, array, or string data
+    and associated NeXus attributes.
+
+    NXfield(value=None, name='unknown', dtype='', shape=[], attrs={}, file=None,
+            path=None, group=None, **attr)
+
+    Input Parameters
+    ----------------
+    value : scalar value, Numpy array, or string
+        The numerical or string value of the NXfield, which is directly
+        accessible as the NXfield attribute 'nxdata'.
+    name : string
+        The name of the NXfield, which is directly accessible as the NXfield
+        attribute 'name'. If the NXfield is initialized as the attribute of a
+        parent object, the name is automatically set to the name of this
+        attribute.
+    dtype : string
+        The data type of the NXfield value, which is directly accessible as the
+        NXfield attribute 'dtype'. Valid input types correspond to standard
+        Numpy data types, using names defined by the NeXus API,
+        i.e., 'float32' 'float64'
+              'int8' 'int16' 'int32' 'int64'
+              'uint8' 'uint16' 'uint32' 'uint64'
+              'char'
+        If the data type is not specified, then it is determined automatically
+        by the data type of the 'value' parameter.
+    shape : list of ints
+        The dimensions of the NXfield data, which is accessible as the NXfield
+        attribute 'shape'. This corresponds to the shape of the Numpy array.
+        Scalars (numeric or string) are stored as Numpy zero-rank arrays,
+        for which shape=[].
+    attrs : dict
+        A dictionary containing NXfield attributes. The dictionary values should
+        all have class NXattr.
+    file : filename
+        The file from which the NXfield has been read.
+    path : string
+        The path to this object with respect to the root of the NeXus tree,
+        using the convention for unix file paths.
+    group : NXgroup or subclass of NXgroup
+        The parent NeXus object. If the NXfield is initialized as the attribute
+        of a parent group, this attribute is automatically set to the parent group.
+
+    Python Attributes
+    -----------------
+    nxclass : 'NXfield'
+        The class of the NXobject.
+    nxname : string
+        The name of the NXfield. Since it is possible to reference the same
+        Python object multiple times, this is not necessarily the same as the
+        object name. However, if the field is part of a NeXus tree, this will
+        be the attribute name within the tree.
+    nxgroup : NXgroup
+        The parent group containing this field within a NeXus tree. If the
+        field is not part of any NeXus tree, it will be set to None.
+    dtype : string or Numpy dtype
+        The data type of the NXfield value. If the NXfield has been initialized
+        but the data values have not been read in or defined, this is a string.
+        Otherwise, it is set to the equivalent Numpy dtype.
+    shape : list or tuple of ints
+        The dimensions of the NXfield data. If the NXfield has been initialized
+        but the data values have not been read in or defined, this is a list of
+        ints. Otherwise, it is set to the equivalent Numpy shape, which is a
+        tuple. Scalars (numeric or string) are stored as Numpy zero-rank arrays,
+        for which shape=().
+    attrs : dict
+        A dictionary of all the NeXus attributes associated with the field.
+        These are objects with class NXattr.
+    nxdata : scalar, Numpy array or string
+        The data value of the NXfield. This is normally initialized using the
+        'value' parameter (see above). If the NeXus data is contained
+        in a file and the size of the NXfield array is too large to be stored
+        in memory, the value is not read in until this attribute is directly
+        accessed. Even then, if there is insufficient memory, a value of None
+        will be returned. In this case, the NXfield array should be read as a
+        series of smaller slabs using 'get'.
+    nxdata_as('units') : scalar value or Numpy array
+        If the NXfield 'units' attribute has been set, the data values, stored
+        in 'nxdata', are returned after conversion to the specified units.
+    nxpath : string
+        The path to this object with respect to the root of the NeXus tree. For
+        NeXus data read from a file, this will be a group of class NXroot, but
+        if the NeXus tree was defined interactively, it can be any valid
+        NXgroup.
+    nxroot : NXgroup
+        The root object of the NeXus tree containing this object. For
+        NeXus data read from a file, this will be a group of class NXroot, but
+        if the NeXus tree was defined interactively, it can be any valid
+        NXgroup.
+
+    NeXus Attributes
+    ----------------
+    NeXus attributes are stored in the 'attrs' dictionary of the NXfield, but
+    can usually be assigned or referenced as if they are Python attributes, as
+    long as the attribute name is not the same as one of those listed above.
+    This is to simplify typing in an interactive session and should not cause
+    any problems because there is no name clash with attributes so far defined
+    within the NeXus standard. When writing modules, it is recommended that the
+    attributes always be referenced using the 'attrs' dictionary if there is
+    any doubt.
+
+    a) Assigning a NeXus attribute
+
+    In the example below, after assigning the NXfield, the following three
+    NeXus attribute assignments are all equivalent:
+
+        >>> entry.sample.temperature = NXfield(40.0)
+        >>> entry.sample.temperature.attrs['units'] = 'K'
+        >>> entry.sample.temperature.units = NXattr('K')
+        >>> entry.sample.temperature.units = 'K'
+
+    b) Referencing a NeXus attribute
+
+    If the name of the NeXus attribute is not the same as any of the Python
+    attributes listed above, or one of the methods listed below, or any of the
+    attributes defined for Numpy arrays, they can be referenced as if they were
+    a Python attribute of the NXfield. However, it is only possible to reference
+    attributes with one of the proscribed names using the 'attrs' dictionary.
+
+        >>> entry.sample.temperature.tree = 10.0
+        >>> entry.sample.temperature.tree
+        temperature = 40.0
+          @tree = 10.0
+          @units = K
+        >>> entry.sample.temperature.attrs['tree']
+        NXattr(10.0)
+
+    Numerical Operations on NXfields
+    --------------------------------
+    NXfields usually consist of arrays of numeric data with associated
+    meta-data, the NeXus attributes. The exception is when they contain
+    character strings. This makes them similar to Numpy arrays, and this module
+    allows the use of NXfields in numerical operations in the same way as Numpy
+    ndarrays. NXfields are technically not a sub-class of the ndarray class, but
+    most Numpy operations work on NXfields, returning either another NXfield or,
+    in some cases, an ndarray that can easily be converted to an NXfield.
+
+        >>> x = NXfield((1.0,2.0,3.0,4.0))
+        >>> print x+1
+        [ 2.  3.  4.  5.]
+        >>> print 2*x
+        [ 2.  4.  6.  8.]
+        >>> print x/2
+        [ 0.5  1.   1.5  2. ]
+        >>> print x**2
+        [  1.   4.   9.  16.]
+        >>> print x.reshape((2,2))
+        [[ 1.  2.]
+         [ 3.  4.]]
+        >>> y = NXfield((0.5,1.5,2.5,3.5))
+        >>> x+y
+        NXfield(name=x,value=[ 1.5  3.5  5.5  7.5])
+        >>> x*y
+        NXfield(name=x,value=[  0.5   3.    7.5  14. ])
+        >>> (x+y).shape
+        (4,)
+        >>> (x+y).dtype
+        dtype('float64')
+
+    All these operations return valid NXfield objects containing the same
+    attributes as the first NXobject in the expression. The 'reshape' and
+    'transpose' methods also return NXfield objects.
+
+    It is possible to use the standard slice syntax.
+
+        >>> x=NXfield(np.linspace(0,10,11))
+        >>> x
+        NXfield([  0.   1.   2. ...,   8.   9.  10.])
+        >>> x[2:5]
+        NXfield([ 2.  3.  4.])
+
+    In addition, it is possible to use floating point numbers as the slice
+    indices. If one of the indices is not integer, both indices are used to
+    extract elements in the array with values between the two index values.
+
+        >>> x=NXfield(np.linspace(0,100.,11))
+        >>> x
+        NXfield([   0.   10.   20. ...,   80.   90.  100.])
+        >>> x[20.:50.]
+        NXfield([ 20.  30.  40.  50.])
+
+    The standard Numpy ndarray attributes and methods will also work with
+    NXfields, but will return scalars or Numpy arrays.
+
+        >>> x.size
+        4
+        >>> x.sum()
+        10.0
+        >>> x.max()
+        4.0
+        >>> x.mean()
+        2.5
+        >>> x.var()
+        1.25
+        >>> x.reshape((2,2)).sum(1)
+        array([ 3.,  7.])
+
+    Finally, NXfields are cast as ndarrays for operations that require them.
+    The returned value will be the same as for the equivalent ndarray
+    operation, e.g.,
+
+    >>> np.sin(x)
+    array([ 0.84147098,  0.90929743,  0.14112001, -0.7568025 ])
+    >>> np.sqrt(x)
+    array([ 1.        ,  1.41421356,  1.73205081,  2.        ])
+
+    Methods
+    -------
+    dir(self, attrs=False):
+        Print the NXfield specification.
+
+        This outputs the name, dimensions and data type of the NXfield.
+        If 'attrs' is True, NXfield attributes are displayed.
+
+    tree:
+        Return the NXfield's tree.
+
+        It invokes the 'dir' method with both 'attrs' and 'recursive'
+        set to True. Note that this is defined as a property attribute and
+        does not require parentheses.
+
+
+    save(self, filename, format='w5')
+        Save the NXfield into a file wrapped in a NXroot group and NXentry group
+        with default names. This is equivalent to
+
+        >>> NXroot(NXentry(NXfield(...))).save(filename)
+
+    Examples
+    --------
+    >>> x = NXfield(np.linspace(0,2*np.pi,101), units='degree')
+    >>> phi = x.nxdata_as(units='radian')
+    >>> y = NXfield(np.sin(phi))
+
+    # Read a Ni x Nj x Nk array one vector at a time
+    >>> with root.NXentry[0].data.data as slab:
+            Ni,Nj,Nk = slab.shape
+            size = [1,1,Nk]
+            for i in range(Ni):
+                for j in range(Nj):
+                    value = slab.get([i,j,0],size)
+
+    """
+
+    def __init__(self, value=None, name='field', dtype=None, shape=(), group=None,
+                 attrs={}, **attr):
+        if isinstance(value, list) or isinstance(value, tuple):
+            value = np.array(value)
+        self._value = value
+        self._class = 'NXfield'
+        self._name = name.replace(' ','_')
+        self._group = group
+        self._dtype = dtype
+        if dtype == 'char':
+            self._dtype = 'char'
+        elif dtype in np.typeDict:
+            self._dtype = np.dtype(dtype)
+        elif dtype:
+            raise NeXusError("Invalid data type: %s" % dtype)
+        self._shape = tuple(shape)
+        # Append extra keywords to the attribute list
+        self._attrs = AttrDict()
+        for key in attr.keys():
+            attrs[key] = attr[key]
+        # Convert NeXus attributes to python attributes
+        self._setattrs(attrs)
+        if 'units' in attrs:
+            units = attrs['units']
+        else:
+            units = None
+        self._incontext = False
+        del attrs
+        if value is not None and dtype == 'char': value = str(value)
+        self._setdata(value)
+        self._saved = False
+        self._changed = True
+
+    def __repr__(self):
+        if self._value is not None:
+            if str(self.dtype) == 'char':
+                return "NXfield('%s')" % str(self)
+            else:
+                return "NXfield(%s)" % self._str_value()
+        else:
+            return "NXfield(dtype=%s,shape=%s)" % (self.dtype,self.shape)
+
+    def __getattr__(self, name):
+        """
+        Enable standard numpy ndarray attributes if not otherwise defined.
+        """
+        if name in _npattrs:
+            return self.nxdata.__getattribute__(name)
+        elif name in self.attrs:
+            return self.attrs[name].nxdata
+        raise KeyError(name+" not in "+self.nxname)
+
+    def __setattr__(self, name, value):
+        """
+        Add an attribute to the NXfield 'attrs' dictionary unless the attribute
+        name starts with 'nx' or '_', or unless it is one of the standard Python
+        attributes for the NXfield class.
+        """
+        if name.startswith('_') or name.startswith('nx'):
+            object.__setattr__(self, name, value)
+        elif isinstance(value, NXattr):
+            self._attrs[name] = value
+            self._saved = False
+            self._changed = True
+        else:
+            self._attrs[name] = NXattr(value)
+            self._saved = False
+            self._changed = True
+
+    def __getitem__(self, index):
+        """
+        Returns a slice from the NXfield.
+
+        In most cases, the slice values are applied to the NXfield nxdata array
+        and returned within an NXfield object with the same metadata. However,
+        if the array is one-dimensional and the index start and stop values
+        are real, the nxdata array is returned with values between those limits.
+        This is to allow axis arrays to be limited by their actual value. This
+        real-space slicing should only be used on monotonically increasing (or
+        decreasing) one-dimensional arrays.
+        """
+        if isinstance(index, slice) and \
+           (isinstance(index.start, float) or isinstance(index.stop, float)):
+            index = slice(self.index(index.start), self.index(index.stop,max=True)+1)
+        if self._value is not None:
+            result = self.nxdata.__getitem__(index)
+        else:
+            offset = np.zeros(len(self.shape),dtype=int)
+            size = np.array(self.shape)
+            if isinstance(index, int):
+                offset[0] = index
+                size[0] = 1
+            else:
+                if isinstance(index, slice): index = [index]
+                i = 0
+                for ind in index:
+                    if isinstance(ind, int):
+                        offset[i] = ind
+                        size[i] = 1
+                    else:
+                        if ind.start: offset[i] = ind.start
+                        if ind.stop: size[i] = ind.stop - offset[i]
+                    i = i + 1
+            try:
+                result = self.get(offset, size)
+            except ValueError:
+                result = self.nxdata.__getitem__(index)
+        return NXfield(result, name=self.nxname, attrs=self.attrs)
+
+    def __setitem__(self, index, value):
+        """
+        Assign a slice to the NXfield.
+        """
+        if self._value is not None:
+            self.nxdata[index] = value
+            self._saved = False
+            self._changed = True
+        else:
+            raise NeXusError("NXfield dataspace not yet allocated")
+
+    def __deepcopy__(self, memo):
+        dpcpy = self.__class__()
+        memo[id(self)] = dpcpy
+        dpcpy._value = copy(self._value)
+        dpcpy._name = copy(self.nxname)
+        dpcpy._dtype = copy(self.dtype)
+        dpcpy._shape = copy(self.shape)
+        for k, v in self.attrs.items():
+            dpcpy.attrs[k] = copy(v)
+        return dpcpy
+
+    def __len__(self):
+        """
+        Return the length of the NXfield data.
+        """
+        return np.prod(self.shape)
+
+    def index(self, value, max=False):
+        """
+        Return the index of the NXfield nxdata array that is greater than or equal to the value.
+
+        If max, then return the index that is less than or equal to the value.
+        This should only be used on one-dimensional monotonically increasing arrays.
+        """
+        if max:
+            return len(self.nxdata)-len(self.nxdata[self.nxdata>=value])
+        else:
+            return len(self.nxdata[self.nxdata<value])
+
+    def __array__(self):
+        """
+        Cast the NXfield as an array when it is expected by numpy
+        """
+        return self.nxdata
+
+    def __eq__(self, other):
+        """
+        Return true if the values of the NXfield are the same.
+        """
+        if isinstance(other, NXfield):
+            if isinstance(self.nxdata, np.ndarray) and isinstance(other.nxdata, np.ndarray):
+                return all(self.nxdata == other.nxdata)
+            else:
+                return self.nxdata == other.nxdata
+        else:
+            return False
+
+    def __ne__(self, other):
+        """
+        Return true if the values of the NXfield are not the same.
+        """
+        if isinstance(other, NXfield):
+            if isinstance(self.nxdata, np.ndarray) and isinstance(other.nxdata, np.ndarray):
+                return any(self.nxdata != other.nxdata)
+            else:
+                return self.nxdata != other.nxdata
+        else:
+            return True
+
+    def __add__(self, other):
+        """
+        Return the sum of the NXfield and another NXfield or number.
+        """
+        if isinstance(other, NXfield):
+            return NXfield(value=self.nxdata+other.nxdata, name=self.nxname,
+                           attrs=self.attrs)
+        else:
+            return NXfield(value=self.nxdata+other, name=self.nxname,
+                           attrs=self.attrs)
+
+    def __radd__(self, other):
+        """
+        Return the sum of the NXfield and another NXfield or number.
+
+        This variant makes __add__ commutative.
+        """
+        return self.__add__(other)
+
+    def __sub__(self, other):
+        """
+        Return the NXfield with the subtraction of another NXfield or number.
+        """
+        if isinstance(other, NXfield):
+            return NXfield(value=self.nxdata-other.nxdata, name=self.nxname,
+                           attrs=self.attrs)
+        else:
+            return NXfield(value=self.nxdata-other, name=self.nxname,
+                           attrs=self.attrs)
+
+    def __mul__(self, other):
+        """
+        Return the product of the NXfield and another NXfield or number.
+        """
+        if isinstance(other, NXfield):
+            return NXfield(value=self.nxdata*other.nxdata, name=self.nxname,
+                           attrs=self.attrs)
+        else:
+            return NXfield(value=self.nxdata*other, name=self.nxname,
+                          attrs=self.attrs)
+
+    def __rmul__(self, other):
+        """
+        Return the product of the NXfield and another NXfield or number.
+
+        This variant makes __mul__ commutative.
+        """
+        return self.__mul__(other)
+
+    def __div__(self, other):
+        """
+        Return the NXfield divided by another NXfield or number.
+        """
+        if isinstance(other, NXfield):
+            return NXfield(value=self.nxdata/other.nxdata, name=self.nxname,
+                           attrs=self.attrs)
+        else:
+            return NXfield(value=self.nxdata/other, name=self.nxname,
+                           attrs=self.attrs)
+
+    def __rdiv__(self, other):
+        """
+        Return the inverse of the NXfield divided by another NXfield or number.
+        """
+        if isinstance(other, NXfield):
+            return NXfield(value=other.nxdata/self.nxdata, name=self.nxname,
+                           attrs=self.attrs)
+        else:
+            return NXfield(value=other/self.nxdata, name=self.nxname,
+                           attrs=self.attrs)
+
+    def __pow__(self, power):
+        """
+        Return the NXfield raised to the specified power.
+        """
+        return NXfield(value=pow(self.nxdata,power), name=self.nxname,
+                       attrs=self.attrs)
+
+    def reshape(self, shape):
+        """
+        Returns an NXfield with the specified shape.
+        """
+        return NXfield(value=self.nxdata.reshape(shape), name=self.nxname,
+                       attrs=self.attrs)
+
+    def transpose(self):
+        """
+        Returns an NXfield containing the transpose of the data array.
+        """
+        return NXfield(value=self.nxdata.transpose(), name=self.nxname,
+                       attrs=self.attrs)
+
+    @property
+    def T(self):
+        return self.transpose()
+
+    def centers(self):
+        """
+        Returns an NXfield with the centers of a single axis
+        assuming it contains bin boundaries.
+        """
+        return NXfield((self.nxdata[:-1]+self.nxdata[1:])/2,
+                        name=self.nxname,attrs=self.attrs)
+
+    def read(self):
+        """
+        Read the NXfield, including attributes, from the NeXus file.
+
+        The data values are read provided they do not exceed NX_MEMORY. In that
+        case, the data have to be read in as slabs using the get method.
+        """
+        if self.nxfile:
+            with self as path:
+                self._setattrs(path.getattrs())
+                shape, dtype = path.getinfo()
+                if dtype == 'char':
+                    self._value = path.getdata()
+                elif np.prod(shape) * np.dtype(dtype).itemsize <= NX_MEMORY*1024*1024:
+                    self._value = path.getdata()
+                else:
+                    raise MemoryError('Data size larger than NX_MEMORY=%s MB' % NX_MEMORY)
+                self._shape = tuple(shape)
+                self._dtype = dtype
+                if dtype == 'char':
+                    self._dtype = 'char'
+                elif dtype in np.typeDict:
+                    self._dtype = np.dtype(dtype)
+                self._infile = self._saved = self._changed = True
+        else:
+            raise IOError("Data is not attached to a file")
+
+    def write(self):
+        """
+        Write the NXfield, including attributes, to the NeXus file.
+        """
+        if self.nxfile:
+            if self.nxfile.mode == napi.ACC_READ:
+                raise NeXusError("NeXus file is readonly")
+            if not self.infile:
+                shape = self.shape
+                if shape == (): shape = (1,)
+                with self.nxgroup as path:
+                    if np.prod(shape) > 10000:
+                    # Compress the fastest moving dimension of large datasets
+                        slab_dims = np.ones(len(shape),'i')
+                        if shape[-1] < 100000:
+                            slab_dims[-1] = shape[-1]
+                        else:
+                            slab_dims[-1] = 100000
+                        path.compmakedata(self.nxname, self.dtype, shape, 'lzw', 
+                                          slab_dims)
+                    else:
+                    # Don't use compression for small datasets
+                        path.makedata(self.nxname, self.dtype, shape)
+                self._infile = True
+            if not self.saved:            
+                with self as path:
+                    path._writeattrs(self.attrs)
+                    value = self.nxdata
+                    if value is not None:
+                        path.putdata(value)
+                self._saved = True
+        else:
+            raise IOError("Data is not attached to a file")
+
+    def get(self, offset, size):
+        """
+        Return a slab from the data array.
+
+        Offsets are 0-origin. Shape can be inferred from the data.
+        Offset and shape must each have one entry per dimension.
+
+        Corresponds to NXgetslab(handle,data,offset,shape)
+        """
+        if self.nxfile:
+            with self as path:
+                value = path.getslab(offset,size)
+                return value
+        else:
+            raise IOError("Data is not attached to a file")
+
+    def put(self, data, offset, refresh=True):
+        """
+        Put a slab into the data array.
+
+        Offsets are 0-origin.  Shape can be inferred from the data.
+        Offset and shape must each have one entry per dimension.
+
+        Corresponds to NXputslab(handle,data,offset,shape)
+        """
+        if self.nxfile:
+            if self.nxfile.mode == napi.ACC_READ:
+                raise NeXusError("NeXus file is readonly")
+            with self as path:
+                if isinstance(data, NXfield):
+                    path.putslab(data.nxdata.astype(self.dtype), offset, data.shape)
+                else:
+                    data = np.array(data)
+                    path.putslab(data.astype(self.dtype), offset, data.shape)
+            if refresh: self.read()
+        else:
+            raise IOError("Data is not attached to a file")
+
+    def add(self, data, offset, refresh=True):
+        """
+        Add a slab into the data array.
+
+        Calls get to read in existing data before adding the value
+        and calling put. It assumes that the two sets of data have
+        compatible data types.
+        """
+        if isinstance(data, NXfield):
+            value = self.get(offset, data.shape)
+            self.put(data.nxdata.astype(self.dtype)+value, offset)
+        else:
+            value = self.get(offset, data.shape)
+            self.put(data.astype(self.dtype)+value, offset)
+        if refresh: self.refresh()
+
+    def refresh(self):
+        """
+        Rereads the data from the file.
+
+        If put has been called, then nxdata is no longer synchronized with the
+        file making a refresh necessary. This will only be performed if nxdata
+        already stores the data.
+        """
+        if self._value is not None:
+            if self.nxfile:
+                self._value = self.nxfile.readpath(self.nxpath)
+                self._infile = self._saved = True
+            else:
+                raise IOError("Data is not attached to a file")
+
+    def convert(self, units=""):
+        """
+        Return the data in particular units.
+        """
+        try:
+            import units
+        except ImportError:
+            raise NeXusError("No conversion utility available")
+        if self._value is not None:
+            return self._converter(self._value,units)
+        else:
+            return None
+
+    def __str__(self):
+        """
+        If value is loaded, return the value as a string.  If value is
+        not loaded, return the empty string.  Only the first view values
+        for large arrays will be printed.
+        """
+        if self._value is not None:
+            return str(self._value)
+        return ""
+
+    def _str_value(self,indent=0):
+        v = str(self)
+        if '\n' in v:
+            v = '\n'.join([(" "*indent)+s for s in v.split('\n')])
+        return v
+
+    def _str_tree(self,indent=0,attrs=False,recursive=False):
+        dims = 'x'.join([str(n) for n in self.shape])
+        s = str(self)
+        if '\n' in s or s == "":
+            s = "%s(%s)"%(self.dtype, dims)
+        v=[" "*indent + "%s = %s"%(self.nxname, s)]
+        if attrs and self.attrs: v.append(self._str_attrs(indent=indent+2))
+        return "\n".join(v)
+
+    def walk(self):
+        yield self
+
+    def _getaxes(self):
+        """
+        Return a list of NXfields containing axes.
+
+        Only works if the NXfield has the 'axes' attribute
+        """
+        try:
+            return [getattr(self.nxgroup,name) for name in _readaxes(self.axes)]
+        except KeyError:
+            return None
+
+    def _getdata(self):
+        """
+        Return the data if it is not larger than NX_MEMORY.
+        """
+        if self._value is None:
+            if self.nxfile:
+                if str(self.dtype) == 'char':
+                    self._value = self.nxfile.readpath(self.nxpath)
+                elif np.prod(self.shape) * np.dtype(self.dtype).itemsize <= NX_MEMORY*1024*1024:
+                    self._value = self.nxfile.readpath(self.nxpath)
+                else:
+                    raise MemoryError('Data size larger than NX_MEMORY=%s MB' % NX_MEMORY)
+                self._saved = True
+            else:
+                return None
+
+        return self._value
+
+    def _setdata(self, value):
+        if value is not None:
+            if str(self._dtype) == 'char' or isinstance(value,str):
+                self._value = str(value)
+                self._shape = (len(self._value),)
+                self._dtype = 'char'
+            else:
+                if self.dtype in np.typeDict:
+                    self._value = np.array(value,self.dtype)
+                else:
+                    self._value = np.array(value)
+                self._shape = self._value.shape
+                self._dtype = self._value.dtype
+            self._saved = False
+            self._changed = True
+       
+    def _getdtype(self):
+        return self._dtype
+
+    def _getshape(self):
+        return self._shape
+
+    def _getsize(self):
+        return len(self)
+
+    nxdata = property(_getdata,_setdata,doc="The data values")
+    nxaxes = property(_getaxes,doc="The plotting axes")
+    dtype = property(_getdtype,doc="Data type of NeXus field")
+    shape = property(_getshape,doc="Shape of NeXus field")
+    size = property(_getsize,doc="Size of NeXus field")
+
+SDS = NXfield # For backward compatibility
+
+def _fixaxes(signal, axes):
+    """
+    Remove length-one dimensions from plottable data
+    """
+    shape = list(signal.shape)
+    while 1 in shape: shape.remove(1)
+    newaxes = []
+    for axis in axes:
+        if axis.size > 1: newaxes.append(axis)
+    return signal.nxdata.view().reshape(shape), newaxes
+
+class PylabPlotter(object):
+
+    """
+    Matplotlib plotter class for NeXus data.
+    """
+
+    def plot(self, signal, axes, title, errors, fmt, 
+             xmin, xmax, ymin, ymax, zmin, zmax, **opts):
+        """
+        Plot the data entry.
+
+        Raises NeXusError if the data cannot be plotted.
+        """
+        try:
+            import matplotlib.pyplot as plt
+        except ImportError:
+            raise NeXusError("Default plotting package (matplotlib) not available.")
+
+        over = False
+        if "over" in opts.keys():
+            if opts["over"]: over = True
+            del opts["over"]
+
+        log = logx = logy = False
+        if "log" in opts.keys():
+            if opts["log"]: log = True
+            del opts["log"]
+        if "logy" in opts.keys():
+            if opts["logy"]: logy = True
+            del opts["logy"]
+        if "logx" in opts.keys():
+            if opts["logx"]: logx = True
+            del opts["logx"]
+
+        if over:
+            plt.autoscale(enable=False)
+        else:
+            plt.autoscale(enable=True)
+            plt.clf()
+
+        # Provide a new view of the data if there is a dimension of length 1
+        if 1 in signal.shape:
+            data, axes = _fixaxes(signal, axes)
+        else:
+            data = signal.nxdata
+
+        # Find the centers of the bins for histogrammed data
+        axis_data = centers(data, axes)
+
+        #One-dimensional Plot
+        if len(data.shape) == 1:
+            plt.ioff()
+            if hasattr(signal, 'units'):
+                if not errors and signal.units == 'counts':
+                    errors = NXfield(np.sqrt(data))
+            if errors:
+                ebars = errors.nxdata
+                plt.errorbar(axis_data[0], data, ebars, fmt=fmt, **opts)
+            else:
+                plt.plot(axis_data[0], data, fmt, **opts)
+            if not over:
+                ax = plt.gca()
+                xlo, xhi = ax.set_xlim(auto=True)        
+                ylo, yhi = ax.set_ylim(auto=True)                
+                if xmin: xlo = xmin
+                if xmax: xhi = xmax
+                ax.set_xlim(xlo, xhi)
+                if ymin: ylo = ymin
+                if ymax: yhi = ymax
+                ax.set_ylim(ylo, yhi)
+                if logx: ax.set_xscale('symlog')
+                if log or logy: ax.set_yscale('symlog')
+                plt.xlabel(label(axes[0]))
+                plt.ylabel(label(signal))
+                plt.title(title)
+            plt.ion()
+
+        #Two dimensional plot
+        else:
+            from matplotlib.image import NonUniformImage
+            from matplotlib.colors import LogNorm
+
+            if len(data.shape) > 2:
+                slab = [slice(None), slice(None)]
+                for _dim in data.shape[2:]:
+                    slab.append(0)
+                data = data[slab].view().reshape(data.shape[:2])
+                print "Warning: Only the top 2D slice of the data is plotted"
+
+            x = axis_data[0]
+            y = axis_data[1]
+            if not zmin: zmin = np.min(data)
+            if not zmax: zmax = np.max(data)
+            z = np.clip(data,zmin,zmax).T
+            
+            if log:
+                opts["norm"] = LogNorm()
+                if z.min() <= 0 and np.issubdtype(z[0,0],int):
+                    z = np.clip(z,0.1,zmax)
+
+            ax = plt.gca()
+            extent = (x[0],x[-1],y[0],y[-1])
+            im = NonUniformImage(ax, extent=extent, origin=None, **opts)
+            im.set_data(x,y,z)
+            ax.images.append(im)
+            xlo, xhi = ax.set_xlim(x[0],x[-1])
+            ylo, yhi = ax.set_ylim(y[0],y[-1])
+            if xmin: 
+                xlo = xmin
+            else:
+                xlo = x[0]
+            if xmax: 
+                xhi = xmax
+            else:
+                xhi = x[-1]
+            if ymin: 
+                yhi = ymin
+            else:
+                yhi = y[0]
+            if ymax: 
+                yhi = ymax
+            else:
+                yhi = y[-1]
+            ax.set_xlim(xlo, xhi)
+            ax.set_ylim(ylo, yhi)
+            plt.xlabel(label(axes[0]))
+            plt.ylabel(label(axes[1]))
+            plt.title(title)
+            plt.colorbar(im)
+
+        plt.gcf().canvas.draw_idle()
+
+    @staticmethod
+    def show():
+        import matplotlib.pyplot as plt
+        plt.show()    
+
+
+class NXgroup(NXobject):
+
+    """
+    A NeXus group object.
+
+    This is a subclass of NXobject and is the base class for the specific
+    NeXus group classes, e.g., NXentry, NXsample, NXdata.
+
+    NXgroup(*items, **opts)
+
+    Parameters
+    ----------
+    The NXgroup parameters consist of a list of positional and/or keyword
+    arguments.
+
+    Positional Arguments : These must be valid NeXus objects, either an NXfield
+    or a NeXus group. These are added without modification as children of this
+    group.
+
+    Keyword Arguments : Apart from a list of special keywords shown below,
+    keyword arguments are used to add children to the group using the keywords
+    as attribute names. The values can either be valid NXfields or NXgroups,
+    in which case the 'name' attribute is changed to the keyword, or they
+    can be numerical or string data, which are converted to NXfield objects.
+
+    Special Keyword Arguments:
+
+    name : string
+        The name of the NXgroup, which is directly accessible as the NXgroup
+        attribute 'name'. If the NXgroup is initialized as the attribute of
+        a parent group, the name is automatically set to the name of this
+        attribute. If 'nxclass' is specified and has the usual prefix 'NX',
+        the default name is the class name without this prefix.
+    nxclass : string
+        The class of the NXgroup.
+    entries : dict
+        A dictionary containing a list of group entries. This is an
+        alternative way of adding group entries to the use of keyword
+        arguments.
+    file : filename
+        The file from which the NXfield has been read.
+    path : string
+        The path to this object with respect to the root of the NeXus tree,
+        using the convention for unix file paths.
+    group : NXobject (NXgroup or subclass of NXgroup)
+        The parent NeXus group, which is accessible as the group attribute
+        'group'. If the group is initialized as the attribute of
+        a parent group, this is set to the parent group.
+
+    Python Attributes
+    -----------------
+    nxclass : string
+        The class of the NXobject.
+    nxname : string
+        The name of the NXfield.
+    entries : dictionary
+        A dictionary of all the NeXus objects contained within an NXgroup.
+    attrs : dictionary
+        A dictionary of all the NeXus attributes, i.e., attribute with class NXattr.
+    entries : dictionary
+        A dictionary of all the NeXus objects contained within the group.
+    attrs : dictionary
+        A dictionary of all the group's NeXus attributes, which all have the
+        class NXattr.
+    nxpath : string
+        The path to this object with respect to the root of the NeXus tree. For
+        NeXus data read from a file, this will be a group of class NXroot, but
+        if the NeXus tree was defined interactively, it can be any valid
+        NXgroup.
+    nxroot : NXgroup
+        The root object of the NeXus tree containing this object. For
+        NeXus data read from a file, this will be a group of class NXroot, but
+        if the NeXus tree was defined interactively, it can be any valid
+        NXgroup.
+
+    NeXus Group Entries
+    -------------------
+    Just as in a NeXus file, NeXus groups can contain either data or other
+    groups, represented by NXfield and NXgroup objects respectively. To
+    distinguish them from regular Python attributes, all NeXus objects are
+    stored in the 'entries' dictionary of the NXgroup. However, they can usually
+    be assigned or referenced as if they are Python attributes, i.e., using the
+    dictionary name directly as the group attribute name, as long as this name
+    is not the same as one of the Python attributes defined above or as one of
+    the NXfield Python attributes.
+
+    a) Assigning a NeXus object to a NeXus group
+
+    In the example below, after assigning the NXgroup, the following three
+    NeXus object assignments to entry.sample are all equivalent:
+
+        >>> entry.sample = NXsample()
+        >>> entry.sample['temperature'] = NXfield(40.0)
+        >>> entry.sample.temperature = NXfield(40.0)
+        >>> entry.sample.temperature = 40.0
+        >>> entry.sample.temperature
+        NXfield(40.0)
+
+    If the assigned value is not a valid NXobject, then it is cast as an NXfield
+    with a type determined from the Python data type.
+
+        >>> entry.sample.temperature = 40.0
+        >>> entry.sample.temperature
+        NXfield(40.0)
+        >>> entry.data.data.x=np.linspace(0,10,11).astype('float32')
+        >>> entry.data.data.x
+        NXfield([  0.   1.   2. ...,   8.   9.  10.])
+
+    b) Referencing a NeXus object in a NeXus group
+
+    If the name of the NeXus object is not the same as any of the Python
+    attributes listed above, or the methods listed below, they can be referenced
+    as if they were a Python attribute of the NXgroup. However, it is only possible
+    to reference attributes with one of the proscribed names using the group
+    dictionary, i.e.,
+
+        >>> entry.sample.tree = 100.0
+        >>> print entry.sample.tree
+        sample:NXsample
+          tree = 100.0
+        >>> entry.sample['tree']
+        NXfield(100.0)
+
+    For this reason, it is recommended to use the group dictionary to reference
+    all group objects within Python scripts.
+
+    NeXus Attributes
+    ----------------
+    NeXus attributes are not currently used much with NXgroups, except for the
+    root group, which has a number of global attributes to store the file name,
+    file creation time, and NeXus and HDF version numbers. However, the
+    mechanism described for NXfields works here as well. All NeXus attributes
+    are stored in the 'attrs' dictionary of the NXgroup, but can be referenced
+    as if they are Python attributes as long as there is no name clash.
+
+        >>> entry.sample.temperature = 40.0
+        >>> entry.sample.attrs['tree'] = 10.0
+        >>> print entry.sample.tree
+        sample:NXsample
+          @tree = 10.0
+          temperature = 40.0
+        >>> entry.sample.attrs['tree']
+        NXattr(10.0)
+
+    Methods
+    -------
+    insert(self, NXobject, name='unknown'):
+        Insert a valid NXobject (NXfield or NXgroup) into the group.
+
+        If NXobject has a 'name' attribute and the 'name' keyword is not given,
+        then the object is inserted with the NXobject name.
+
+    makelink(self, NXobject):
+        Add the NXobject to the group entries as a link (NXlink).
+
+    dir(self, attrs=False, recursive=False):
+        Print the group directory.
+
+        The directory is a list of NeXus objects within this group, either NeXus
+        groups or NXfield data. If 'attrs' is True, NXfield attributes are
+        displayed. If 'recursive' is True, the contents of child groups are also
+        displayed.
+
+    tree:
+        Return the group tree.
+
+        It invokes the 'dir' method with both 'attrs' and 'recursive'
+        set to True.
+
+    save(self, filename, format='w5')
+        Save the NeXus group into a file
+
+        The object is wrapped in an NXroot group (with name 'root') and an
+        NXentry group (with name 'entry'), if necessary, in order to produce
+        a valid NeXus file.
+
+    Examples
+    --------
+    >>> x = NXfield(np.linspace(0,2*np.pi,101), units='degree')
+    >>> entry = NXgroup(x, name='entry', nxclass='NXentry')
+    >>> entry.sample = NXgroup(temperature=NXfield(40.0,units='K'),
+                               nxclass='NXsample')
+    >>> print entry.sample.tree
+    sample:NXsample
+      temperature = 40.0
+        @units = K
+
+    Note: All the currently defined NeXus classes are defined as subclasses
+          of the NXgroup class. It is recommended that these are used
+          directly, so that the above examples become:
+
+    >>> entry = NXentry(x)
+    >>> entry.sample = NXsample(temperature=NXfield(40.0,units='K'))
+
+    or
+
+    >>> entry.sample.temperature = 40.0
+    >>> entry.sample.temperature.units='K'
+
+    """
+
+    # Plotter to use for plot calls
+    _plotter = PylabPlotter()
+
+    def __init__(self, *items, **opts):
+        if "name" in opts.keys():
+            self._name = opts["name"].replace(' ','_')
+            del opts["name"]
+        self._entries = {}
+        if "entries" in opts.keys():
+            for k,v in opts["entries"].items():
+                setattr(self, k, v)
+            del opts["entries"]
+        self._attrs = AttrDict()
+        if "attrs" in opts.keys():
+            self._setattrs(opts["attrs"])
+            del opts["attrs"]
+        if "nxclass" in opts.keys():
+            self._class = opts["nxclass"]
+            del opts["nxclass"]
+        if "group" in opts.keys():
+            self._group = opts["group"]
+            del opts["group"]
+        for k,v in opts.items():
+            setattr(self, k, v)
+        if self.nxclass.startswith("NX"):
+            if self.nxname == "unknown": self._name = self.nxclass[2:]
+            try: # If one exists, set the class to a valid NXgroup subclass
+                self.__class__ = globals()[self.nxclass]
+            except KeyError:
+                pass
+        for item in items:
+            try:
+                setattr(self, item.nxname, item)
+            except AttributeError:
+                raise NeXusError("Non-keyword arguments must be valid NXobjects")
+        self._saved = False
+        self._changed = True
+
+#    def __cmp__(self, other):
+#        """Sort groups by their distances or names."""
+#        try:
+#            return cmp(self.distance, other.distance)
+#        except KeyError:
+#            return cmp(self.nxname, other.nxname)
+
+    def __repr__(self):
+        return "%s('%s')" % (self.__class__.__name__,self.nxname)
+
+    def _str_value(self,indent=0):
+        return ""
+
+    def walk(self):
+        yield self
+        for node in self.entries.values():
+            for child in node.walk():
+                yield child
+
+    def __getattr__(self, key):
+        """
+        Provide direct access to groups via nxclass name.
+        """
+        if key.startswith('NX'):
+            return self.component(key)
+        elif key in self.entries:
+            return self.entries[key]
+        elif key in self.attrs:
+            return self.attrs[key].nxdata
+        raise KeyError(key+" not in "+self.nxclass+":"+self.nxname)
+
+    def __setattr__(self, name, value):
+        """
+        Set an attribute as an object or regular Python attribute.
+
+        It is assumed that attributes starting with 'nx' or '_' are regular
+        Python attributes. All other attributes are converted to valid NXobjects,
+        with class NXfield, NXgroup, or a sub-class of NXgroup, depending on the
+        assigned value.
+
+        The internal value of the attribute name, i.e., 'name', is set to the
+        attribute name used in the assignment.  The parent group of the
+        attribute, i.e., 'group', is set to the parent group of the attribute.
+
+        If the assigned value is a numerical (scalar or array) or string object,
+        it is converted to an object of class NXfield, whose attribute, 'nxdata',
+        is set to the assigned value.
+        """
+        if name.startswith('_') or name.startswith('nx'):
+            object.__setattr__(self, name, value)
+        elif isinstance(value, NXattr):
+            self._attrs[name] = value
+            self._saved = False
+            self._changed = True
+        else:
+            self[name] = value
+
+    def __getitem__(self, index):
+        """
+        Returns a slice from the NXgroup nxsignal attribute (if it exists) as
+        a new NXdata group, if the index is a slice object.
+
+        In most cases, the slice values are applied to the NXfield nxdata array
+        and returned within an NXfield object with the same metadata. However,
+        if the array is one-dimensional and the index start and stop values
+        are real, the nxdata array is returned with values between the limits
+        set by those axis values.
+        This is to allow axis arrays to be limited by their actual value. This
+        real-space slicing should only be used on monotonically increasing (or
+        decreasing) one-dimensional arrays.
+        """
+        if isinstance(index, str): #i.e., requesting a dictionary value
+            return self._entries[index]
+
+        if not self.nxsignal:
+            raise NeXusError("No plottable signal")
+        if not hasattr(self,"nxclass"):
+            raise NeXusError("Indexing not allowed for groups of unknown class")
+        if isinstance(index, int):
+            axes = self.nxaxes
+            axes[0] = axes[0][index]
+            result = NXdata(self.nxsignal[index], axes)
+            if self.nxerrors: result.errors = self.errors[index]
+        elif isinstance(index, slice):
+            axes = self.nxaxes
+            axes[0] = axes[0][index]
+            if isinstance(index.start, float) or isinstance(index.stop, float):
+                index = slice(self.nxaxes[0].index(index.start),
+                              self.nxaxes[0].index(index.stop,max=True)+1)
+                result = NXdata(self.nxsignal[index], axes)
+                if self.nxerrors: result.errors = self.errors[index]
+            else:
+                result = NXdata(self.nxsignal[index], axes)
+                if self.nxerrors: result.errors = self.errors[index]
+        else:
+            i = 0
+            slices = []
+            axes = self.nxaxes
+            for ind in index:
+                axes[i] = axes[i][ind]
+                if isinstance(ind, slice) and \
+                   (isinstance(ind.start, float) or isinstance(ind.stop, float)):
+                    slices.append(slice(self.nxaxes[i].index(ind.start),
+                                        self.nxaxes[i].index(ind.stop)))
+                else:
+                    slices.append(ind)
+                i = i + 1
+            result = NXdata(self.nxsignal.__getitem__(tuple(slices)), axes)
+            if self.nxerrors: result.errors = self.errors.__getitem__(tuple(slices))
+        axes = []
+        for axis in result.nxaxes:
+            if len(axis) > 1: axes.append(axis)
+        result.nxsignal.axes = ":".join([axis.nxname for axis in axes])
+        if self.nxtitle:
+            result.title = self.nxtitle
+        return result
+
+    def __setitem__(self, key, value):
+        """
+        Adds or modifies an item in the NeXus group.
+        """
+        if key in self.entries: 
+            infile = self._entries[key]._infile
+            if isinstance(self._entries[key], NXlink):
+                if self._entries[key].nxlink:
+                    setattr(self._entries[key].nxlink.nxgroup, key, value)
+                return
+            attrs = self._entries[key].attrs
+        else:
+            infile = None
+            attrs = {}
+        if isinstance(value, NXlink):
+            self._entries[key] = value
+        elif isinstance(value, NXobject):
+            if value.nxgroup is not None:
+                memo = {}
+                value = deepcopy(value, memo)
+                value._attrs = copy(value._attrs)
+            value._group = self
+            value._name = key
+            self._entries[key] = value
+        else:
+            self._entries[key] = NXfield(value=value, name=key, group=self, attrs=attrs)
+        if infile is not None: self[key]._infile = infile
+        self._changed = True
+
+    def __deepcopy__(self, memo):
+        dpcpy = self.__class__()
+        memo[id(self)] = dpcpy
+        for k,v in self.items():
+            if isinstance(v, NXgroup):
+                dpcpy[k] = deepcopy(v, memo)
+            else:
+                dpcpy[k] = copy(v)
+        for k, v in self.attrs.items():
+            dpcpy.attrs[k] = copy(v)
+        return dpcpy
+
+    def keys(self):
+        """
+        Returns the names of NeXus objects in the group.
+        """
+        return self._entries.keys()
+
+    def values(self):
+        """
+        Returns the values of NeXus objects in the group.
+        """
+        return self._entries.values()
+
+    def items(self):
+        """
+        Returns a list of the NeXus objects in the group as (key,value) pairs.
+        """
+        return self._entries.items()
+
+    def has_key(self, name):
+        """
+        Returns true if the NeXus object with the specified name is in the group.
+        """
+        return self._entries.has_key(name)
+
+    def insert(self, value, name='unknown'):
+        """
+        Adds an attribute to the group.
+
+        If it is not a valid NeXus object (NXfield or NXgroup), the attribute
+        is converted to an NXfield.
+        """
+        if isinstance(value, NXobject):
+            if name == 'unknown': name = value.nxname
+            if name in self._entries:
+                raise NeXusError("'%s' already exists in group" % name)
+            value._group = self
+            self._entries[name] = value
+        else:
+            self._entries[name] = NXfield(value=value, name=name, group=self)
+
+    def makelink(self, target):
+        """
+        Creates a linked NXobject within the group.
+
+        All attributes are inherited from the parent object including the name
+        """
+        if isinstance(target, NXobject):
+            self[target.nxname] = NXlink(target=target, group=self)
+        else:
+            raise NeXusError("Link target must be an NXobject")
+
+    def read(self):
+        """
+        Read the NXgroup and all its children from the NeXus file.
+        """
+        if self.nxfile:
+            with self as path:
+                n, nxname, nxclass = path.getgroupinfo()
+                if nxclass != self.nxclass:
+                    raise NeXusError("The NeXus group class does not match the file")
+                self._setattrs(path.getattrs())
+                entries = path.entries()
+            for name,nxclass in entries:
+                path = self.nxpath + '/' + name
+                if nxclass == 'SDS':
+                    attrs = self.nxfile.getattrs()
+                    if 'target' in attrs and attrs['target'] != path:
+                        self._entries[name] = NXlinkfield(target=attrs['target'])            
+                    else:
+                        self._entries[name] = NXfield(name=name)
+                else:
+                    attrs = self.nxfile.getattrs()
+                    if 'target' in attrs and attrs['target'] != path:
+                        self._entries[name] = NXlinkgroup(name=name,
+                                                          target=attrs['target'])
+                    else:
+                        self._entries[name] = NXgroup(nxclass=nxclass)
+                self._entries[name]._group = self
+            #Make sure non-linked variables are processed first.
+            for entry in self._entries.values():
+                for node in entry.walk():
+                    if not isinstance(node, NXlink): node.read()
+            for entry in self._entries.values():
+                for node in entry.walk():
+                    if isinstance(node, NXlink): node.read()
+            self._infile = self._saved = self._changed = True
+        else:
+            raise IOError("Data is not attached to a file")
+
+    def write(self):
+        """
+        Write the NXgroup, including its children, to the NeXus file.
+        """
+        if self.nxfile:
+            if self.nxfile.mode == napi.ACC_READ:
+                raise NeXusError("NeXus file is readonly")
+            if not self.infile:
+                with self.nxgroup as path:
+                    path.makegroup(self.nxname, self.nxclass)
+                self._infile = True
+            with self as path:
+                path._writeattrs(self.attrs)
+                for entry in self.walk():
+                    if entry is not self: entry.write()
+                self._infile = self._saved = True
+        else:
+            raise IOError("Group is not attached to a file")
+
+    def sum(self, axis=None):
+        """
+        Return the sum of the NXdata group using the Numpy sum method
+        on the NXdata signal.
+
+        The result contains a copy of all the metadata contained in
+        the NXdata group.
+        """
+        if not self.nxsignal:
+            raise NeXusError("No signal to sum")
+        if not hasattr(self,"nxclass"):
+            raise NeXusError("Summing not allowed for groups of unknown class")
+        if axis is None:
+            return self.nxsignal.sum()
+        else:
+            signal = NXfield(self.nxsignal.sum(axis), name=self.nxsignal.nxname)
+            axes = self.nxaxes
+            summedaxis = axes.pop(axis)
+            units = ""
+            if hasattr(summedaxis, "units"): units = summedaxis.units
+            signal.long_name = "Integral from %s to %s %s" % \
+                               (summedaxis[0], summedaxis[-1], units)
+            average = NXfield(0.5*(summedaxis.nxdata[0]+summedaxis.nxdata[-1]), 
+                                   name=summedaxis.nxname)
+            if units: average.units = units
+            result = NXdata(signal, axes, average)
+            if self.nxerrors:
+                errors = np.sqrt((self.nxerrors.nxdata**2).sum(axis))
+                result.errors = NXfield(errors, name="errors")
+            if self.nxtitle:
+                result.title = self.nxtitle
+            return result
+
+    def moment(self, order=1):
+        """
+        Return an NXfield containing the moments of the NXdata group
+        assuming the signal is one-dimensional.
+
+        Currently, only the first moment has been defined. Eventually, the
+        order of the moment will be defined by the 'order' parameter.
+        """
+        if not self.nxsignal:
+            raise NeXusError("No signal to calculate")
+        elif len(self.nxsignal.shape) > 1:
+            raise NeXusError("Operation only possible on one-dimensional signals")
+        elif order > 1:
+            raise NeXusError("Higher moments not yet implemented")
+        if not hasattr(self,"nxclass"):
+            raise NeXusError("Operation not allowed for groups of unknown class")
+        return (centers(self.nxsignal,self.nxaxes)*self.nxsignal).sum() \
+                /self.nxsignal.sum()
+
+    def component(self, nxclass):
+        """
+        Find all child objects that have a particular class.
+        """
+        return [E for _name,E in self.entries.items() if E.nxclass==nxclass]
+
+    def signals(self):
+        """
+        Return a dictionary of NXfield's containing signal data.
+
+        The key is the value of the signal attribute.
+        """
+        signals = {}
+        for obj in self.entries.values():
+            if 'signal' in obj.attrs:
+                signals[obj.nxsignal.nxdata] = obj
+        return signals
+
+    def _signal(self):
+        """
+        Return the NXfield containing the signal data.
+        """
+        for obj in self.entries.values():
+            if 'signal' in obj.attrs and str(obj.signal) == '1':
+#                if isinstance(self[obj.nxname],NXlink):
+#                    return self[obj.nxname].nxlink
+#                else:
+                return self[obj.nxname]
+        return None
+    
+    def _set_signal(self, signal):
+        """
+        Setter for the signal attribute.
+        
+        The argument should be a valid NXfield within the group.
+        """
+        self[signal.nxname].signal = NXattr(1)
+
+    def _axes(self):
+        """
+        Return a list of NXfields containing the axes.
+        """
+        try:
+            return [getattr(self,name) for name in _readaxes(self.nxsignal.axes)]
+        except KeyError:
+            axes = {}
+            for obj in self.entries:
+                if 'axis' in getattr(self,obj).attrs:
+                    axes[getattr(self,obj).axis] = getattr(self,obj)
+            return [axes[key] for key in sorted(axes.keys())]
+
+    def _set_axes(self, axes):
+        """
+        Setter for the signal attribute.
+        
+        The argument should be a list of valid NXfields within the group.
+        """
+        if not isinstance(axes, list):
+            axes = [axes]
+        self.nxsignal.axes = NXattr(":".join([axis.nxname for axis in axes]))
+
+    def _errors(self):
+        """
+        Return the NXfield containing the signal errors.
+        """
+        try:
+            return self.entries['errors']
+        except KeyError:
+            return None
+
+    def _title(self):
+        """
+        Return the title as a string.
+
+        If there is no title attribute in the string, the parent
+        NXentry group in the group's path is searched.
+        """
+        title = self.nxpath
+        if 'title' in self.entries:
+            return str(self.title)
+        elif self.nxgroup:
+            if 'title' in self.nxgroup.entries:
+                return str(self.nxgroup.title)
+        return self.nxpath
+
+    def _getentries(self):
+        return self._entries
+
+    nxsignal = property(_signal, _set_signal, "Signal NXfield within group")
+    nxaxes = property(_axes, _set_axes, "List of axes within group")
+    nxerrors = property(_errors, "Errors NXfield within group")
+    nxtitle = property(_title, "Title for group plot")
+    entries = property(_getentries,doc="NeXus objects within group")
+
+    def plot(self, fmt='bo', xmin=None, xmax=None, ymin=None, ymax=None,
+             zmin=None, zmax=None, **opts):
+        """
+        Plot data contained within the group.
+
+        The format argument is used to set the color and type of the
+        markers or lines for one-dimensional plots, using the standard 
+        matplotlib syntax. The default is set to blue circles. All 
+        keyword arguments accepted by matplotlib.pyplot.plot can be
+        used to customize the plot.
+        
+        In addition to the matplotlib keyword arguments, the following
+        are defined:
+        
+            log = True     - plot the intensity on a log scale
+            logy = True    - plot the y-axis on a log scale
+            logx = True    - plot the x-axis on a log scale
+            over = True    - plot on the current figure
+
+        Raises NeXusError if the data could not be plotted.
+        """
+
+        group = self
+        if self.nxclass == "NXroot":
+            group = group.NXentry[0]
+        if group.nxclass == "NXentry":
+            try:
+                group = group.NXdata[0]
+            except IndexError:
+                raise NeXusError('No NXdata group found')
+
+        # Find a plottable signal
+        signal = group.nxsignal
+        if not signal:
+            raise NeXusError('No plottable signal defined')
+
+        # Find errors
+        errors= group.nxerrors
+
+        # Find the associated axes
+        axes = group.nxaxes
+
+        # Construct title
+        title = group.nxtitle
+
+        # Plot with the available plotter
+        group._plotter.plot(signal, axes, title, errors, fmt, 
+                            xmin, xmax, ymin, ymax, zmin, zmax, **opts)
+    
+    def oplot(self, fmt='bo', **opts):
+        """
+        Plot the data contained within the group over the current figure.
+        """
+        self.plot(fmt=fmt, over=True, **opts)
+
+    def logplot(self, fmt='bo', xmin=None, xmax=None, ymin=None, ymax=None,
+                zmin=None, zmax=None, **opts):
+        """
+        Plot the data intensity contained within the group on a log scale.
+        """
+        self.plot(fmt=fmt, log=True,
+                  xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,
+                  zmin=zmin, zmax=zmax, **opts)
+
+class NXlink(NXobject):
+
+    """
+    Class for NeXus linked objects.
+
+    The real object will be accessible by following the link attribute.
+    """
+
+    _class = "NXlink"
+
+    def __init__(self, target=None, name='link', group=None):
+        self._group = group
+        self._class = "NXlink"
+        if isinstance(target, NXobject):
+            self._name = target.nxname
+            self._target = target.nxpath
+            self.nxlink.attrs["target"] = target.nxpath
+            if target.nxclass == "NXlink":
+                raise NeXusError("Cannot link to another NXlink object")
+            elif target.nxclass == "NXfield":
+                self.__class__ = NXlinkfield
+            else:
+                self.__class__ = NXlinkgroup
+        else:
+            self._name = name
+            self._target = target
+
+    def __getattr__(self, key):
+        try:
+            try:
+                return self.nxlink.__dict__[key]
+            except KeyError:
+                return self.nxlink.__getattr__(key)
+        except KeyError:
+            raise KeyError((key+" not in %s" % self._target))
+
+    def __setattr__(self, name, value):
+        if name.startswith('_')  or name.startswith('nx'):
+            object.__setattr__(self, name, value)
+        elif self.nxlink:
+            self.nxlink.__setattr__(name, value)
+
+    def __repr__(self):
+        return "NXlink('%s')"%(self._target)
+
+    def __str__(self):
+        return str(self.nxlink)
+
+    def _str_tree(self, indent=0, attrs=False, recursive=False):
+        if self.nxlink:
+            return self.nxlink._str_tree(indent, attrs, recursive)
+        else:
+            return " "*indent+self.nxname+' -> '+self._target
+
+    def _getlink(self):
+        link = self.nxroot
+        if link:
+            try:
+                for level in self._target[1:].split('/'):
+                    link = link.entries[level]
+                return link
+            except AttributeError:
+                return None
+        else:
+            return None
+
+    def _getattrs(self):
+        return self.nxlink.attrs
+
+    nxlink = property(_getlink, "Linked object")
+    attrs = property(_getattrs,doc="NeXus attributes for object")
+
+    def read(self):
+        """
+        Read the linked NXobject.
+        """
+        self.nxlink.read()
+        self._infile = self._saved = self._changed = True
+
+
+class NXlinkfield(NXlink, NXfield):
+
+    """
+    Class for a NeXus linked field.
+
+    The real field will be accessible by following the link attribute.
+    """
+
+    def write(self):
+        """
+        Write the linked NXfield.
+        """
+        self.nxlink.write()
+        if not self.infile:
+            with self.nxlink as path:
+                target = path.getdataID()
+            with self.nxgroup as path:
+                path.makelink(target)
+            self._infile = self._saved = True
+
+    def get(self, offset, size):
+        """
+        Get a slab from the data array.
+
+        Offsets are 0-origin.  Shape can be inferred from the data.
+        Offset and shape must each have one entry per dimension.
+
+        This operation should be performed in a "with group.data"
+        conext.
+
+        Raises ValueError cannot convert units.
+
+        Corresponds to NXgetslab(handle,data,offset,shape)
+        """
+        if self.nxfile:
+            with self.nxlink as path:
+                value = path.getslab(offset,size)
+        else:
+            raise IOError("Data is not attached to a file")
+
+NXlinkdata = NXlinkfield # For backward compatibility
+
+class NXlinkgroup(NXlink, NXgroup):
+
+    """
+    Class for a NeXus linked group.
+
+    The real group will be accessible by following the link attribute.
+    """
+
+    def write(self):
+        """
+        Write the linked NXgroup.
+        """
+        self.nxlink.write()
+        if not self.infile:
+            with self.nxlink as path:
+                target = path.getgroupID()
+            with self.nxgroup as path:
+                path.makelink(target)
+            self._infile = self._saved = True
+
+    def _getentries(self):
+        return self.nxlink.entries
+
+    entries = property(_getentries,doc="NeXus objects within group")
+
+
+class NXentry(NXgroup):
+
+    """
+    NXentry group. This is a subclass of the NXgroup class.
+
+    Each NXdata and NXmonitor object of the same name will be added
+    together, raising an NeXusError if any of the groups do not exist
+    in both NXentry groups or if any of the NXdata additions fail.
+    The resulting NXentry group contains a copy of all the other metadata
+    contained in the first group. Note that other extensible data, such
+    as the run duration, are not currently added together.
+
+    See the NXgroup documentation for more details.
+    """
+
+    def __init__(self, *items, **opts):
+        self._class = "NXentry"
+        NXgroup.__init__(self, *items, **opts)
+
+    def __add__(self, other):
+        """
+        Add two NXentry objects
+        """
+        result = NXentry(entries=self.entries, attrs=self.attrs)
+        try:
+            names = [group.nxname for group in self.component("NXdata")]
+            for name in names:
+                if isinstance(other.entries[name], NXdata):
+                    result.entries[name] = self.entries[name] + other.entries[name]
+                else:
+                    raise KeyError
+            names = [group.nxname for group in self.component("NXmonitor")]
+            for name in names:
+                if isinstance(other.entries[name], NXmonitor):
+                    result.entries[name] = self.entries[name] + other.entries[name]
+                else:
+                    raise KeyError
+            return result
+        except KeyError:
+            raise NeXusError("Inconsistency between two NXentry groups")
+
+    def __sub__(self, other):
+        """
+        Subtract two NXentry objects
+        """
+        result = NXentry(entries=self.entries, attrs=self.attrs)
+        try:
+            names = [group.nxname for group in self.component("NXdata")]
+            for name in names:
+                if isinstance(other.entries[name], NXdata):
+                    result.entries[name] = self.entries[name] - other.entries[name]
+                else:
+                    raise KeyError
+            names = [group.nxname for group in self.component("NXmonitor")]
+            for name in names:
+                if isinstance(other.entries[name], NXmonitor):
+                    result.entries[name] = self.entries[name] - other.entries[name]
+                else:
+                    raise KeyError
+            return result
+        except KeyError:
+            raise NeXusError("Inconsistency between two NXentry groups")
+
+
+class NXsubentry(NXentry):
+
+    """
+    NXsubentry group. This is a subclass of the NXsubentry class.
+
+    See the NXgroup documentation for more details.
+    """
+
+    def __init__(self, *items, **opts):
+        self._class = "NXsubentry"
+        NXgroup.__init__(self, *items, **opts)
+
+
+class NXdata(NXgroup):
+
+    """
+    NXdata group. This is a subclass of the NXgroup class.
+
+    The constructor assumes that the first argument contains the signal and
+    the second contains either the axis, for one-dimensional data, or a list
+    of axes, for multidimensional data. These arguments can either be NXfield
+    objects or Numpy arrays, which are converted to NXfield objects with default
+    names. Alternatively, the signal and axes NXfields can be defined using the
+    'nxsignal' and 'nxaxes' properties. See the examples below.
+    
+    Various arithmetic operations (addition, subtraction, multiplication,
+    and division) have been defined for combining NXdata groups with other
+    NXdata groups, Numpy arrays, or constants, raising a NeXusError if the
+    shapes don't match. Data errors are propagated in quadrature if
+    they are defined, i.e., if the 'nexerrors' attribute is not None,
+
+    Attributes
+    ----------
+    nxsignal : The NXfield containing the attribute 'signal' with value 1
+    nxaxes   : A list of NXfields containing the signal axes
+    nxerrors : The NXfield containing the errors
+
+    Methods
+    -------
+    plot(self, fmt, over=False, log=False, logy=False, logx=False, **opts)
+        Plot the NXdata group using the defined signal and axes. Valid
+        Matplotlib parameters, specifying markers, colors, etc, can be
+        specified using format argument or through keyword arguments.
+
+    logplot(self, fmt, over=False, logy=False, logx=False, **opts)
+        Plot the NXdata group using the defined signal and axes with
+        the intensity plotted on a logarithmic scale. In one-dimensional
+        plots, this is the y-axis. In two-dimensional plots, it is the 
+        color scale.
+
+    oplot(self, fmt, **opts)
+        Plot the NXdata group using the defined signal and axes over
+        the current plot.
+
+    moment(self, order=1)
+        Calculate moments of the NXdata group. This assumes that the
+        signal is one-dimenional. Currently, only the first moment is
+        implemented.
+
+    Examples
+    --------
+    There are three methods of creating valid NXdata groups with the
+    signal and axes NXfields defined according to the NeXus standard.
+    
+    1) Create the NXdata group with Numpy arrays that will be assigned
+       default names.
+       
+    >>> x = np.linspace(0, 2*np.pi, 101)
+    >>> line = NXdata(sin(x), x)
+    data:NXdata
+      signal = float64(101)
+        @axes = x
+        @signal = 1
+      axis1 = float64(101)
+      
+    2) Create the NXdata group with NXfields that have their internal
+       names already assigned.
+
+    >>> x = NXfield(linspace(0,2*pi,101), name='x')
+    >>> y = NXfield(linspace(0,2*pi,101), name='y')    
+    >>> X, Y = np.meshgrid(x, y)
+    >>> z = NXfield(sin(X) * sin(Y), name='z')
+    >>> entry = NXentry()
+    >>> entry.grid = NXdata(z, (x, y))
+    >>> grid.tree()
+    entry:NXentry
+      grid:NXdata
+        x = float64(101)
+        y = float64(101)
+        z = float64(101x101)
+          @axes = x:y
+          @signal = 1
+
+    3) Create the NXdata group with keyword arguments defining the names 
+       and set the signal and axes using the nxsignal and nxaxes properties.
+
+    >>> x = linspace(0,2*pi,101)
+    >>> y = linspace(0,2*pi,101)  
+    >>> X, Y = np.meshgrid(x, y)
+    >>> z = sin(X) * sin(Y)
+    >>> entry = NXentry()
+    >>> entry.grid = NXdata(z=sin(X)*sin(Y), x=x, y=y)
+    >>> entry.grid.nxsignal = entry.grid.z
+    >>> entry.grid.nxaxes = [entry.grid.x.entry.grid.y]
+    >>> grid.tree()
+    entry:NXentry
+      grid:NXdata
+        x = float64(101)
+        y = float64(101)
+        z = float64(101x101)
+          @axes = x:y
+          @signal = 1
+    """
+
+    def __init__(self, signal=None, axes=None, *items, **opts):
+        self._class = "NXdata"
+        NXgroup.__init__(self, *items, **opts)
+        if signal is not None:
+            if isinstance(signal,NXfield):
+                if signal.nxname == "unknown": signal.nxname = "signal"
+                if "signal" not in signal.attrs: signal.signal = 1
+                self[signal.nxname] = signal
+                signalname = signal.nxname
+            else:
+                self["signal"] = signal
+                self["signal"].signal = 1
+                signalname = "signal"
+            if axes is not None:
+                if not isinstance(axes,tuple) and not isinstance(axes,list):
+                    axes = [axes]
+                axisnames = {}
+                i = 0
+                for axis in axes:
+                    i = i + 1
+                    if isinstance(axis,NXfield):
+                        if axis._name == "unknown": axis._name = "axis%s" % i
+                        self[axis.nxname] = axis
+                        axisnames[i] = axis.nxname
+                    else:
+                        axisname = "axis%s" % i
+                        self[axisname] = axis
+                        axisnames[i] = axisname
+                self[signalname].axes = ":".join(axisnames.values())
+
+    def __add__(self, other):
+        """
+        Define a method for adding a NXdata group to another NXdata group
+        or to a number. Only the signal data is affected.
+
+        The result contains a copy of all the metadata contained in
+        the first NXdata group. The module checks that the dimensions are
+        compatible, but does not check that the NXfield names or values are
+        identical. This is so that spelling variations or rounding errors
+        do not make the operation fail. However, it is up to the user to
+        ensure that the results make sense.
+        """
+        result = NXdata(entries=self.entries, attrs=self.attrs)
+        if isinstance(other, NXdata):
+            if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape:
+                result.entries[self.nxsignal.nxname] = self.nxsignal + other.nxsignal
+                if self.nxerrors:
+                    if other.nxerrors:
+                        result.errors = np.sqrt(self.errors.nxdata**2+other.errors.nxdata**2)
+                    else:
+                        result.errors = self.errors
+                return result
+        elif isinstance(other, NXgroup):
+            raise NeXusError("Cannot add two arbitrary groups")
+        else:
+            result.entries[self.nxsignal.nxname] = self.nxsignal + other
+            result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname
+            return result
+
+    def __sub__(self, other):
+        """
+        Define a method for subtracting a NXdata group or a number from
+        the NXdata group. Only the signal data is affected.
+
+        The result contains a copy of all the metadata contained in
+        the first NXdata group. The module checks that the dimensions are
+        compatible, but does not check that the NXfield names or values are
+        identical. This is so that spelling variations or rounding errors
+        do not make the operation fail. However, it is up to the user to
+        ensure that the results make sense.
+        """
+        result = NXdata(entries=self.entries, attrs=self.attrs)
+        if isinstance(other, NXdata):
+            if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape:
+                result.entries[self.nxsignal.nxname] = self.nxsignal - other.nxsignal
+                if self.nxerrors:
+                    if other.nxerrors:
+                        result.errors = np.sqrt(self.errors.nxdata**2+other.errors.nxdata**2)
+                    else:
+                        result.errors = self.errors
+                return result
+        elif isinstance(other, NXgroup):
+            raise NeXusError("Cannot subtract two arbitrary groups")
+        else:
+            result.entries[self.nxsignal.nxname] = self.nxsignal - other
+            result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname
+            return result
+
+    def __mul__(self, other):
+        """
+        Define a method for multiplying the NXdata group with a NXdata group
+        or a number. Only the signal data is affected.
+
+        The result contains a copy of all the metadata contained in
+        the first NXdata group. The module checks that the dimensions are
+        compatible, but does not check that the NXfield names or values are
+        identical. This is so that spelling variations or rounding errors
+        do not make the operation fail. However, it is up to the user to
+        ensure that the results make sense.
+        """
+        result = NXdata(entries=self.entries, attrs=self.attrs)
+        if isinstance(other, NXdata):
+
+            # error here signal not defined in this scope
+            #if self.nxsignal and signal.shape == other.nxsignal.shape:
+            if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape:
+                result.entries[self.nxsignal.nxname] = self.nxsignal * other.nxsignal
+                if self.nxerrors:
+                    if other.nxerrors:
+                        result.errors = np.sqrt((self.errors.nxdata*other.nxsignal.nxdata)**2+
+                                                (other.errors.nxdata*self.nxsignal.nxdata)**2)
+                    else:
+                        result.errors = self.errors
+                return result
+        elif isinstance(other, NXgroup):
+            raise NeXusError("Cannot multiply two arbitrary groups")
+        else:
+            result.entries[self.nxsignal.nxname] = self.nxsignal * other
+            result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname
+            if self.nxerrors:
+                result.errors = self.errors * other
+            return result
+
+    def __rmul__(self, other):
+        """
+        Define a method for multiplying NXdata groups.
+
+        This variant makes __mul__ commutative.
+        """
+        return self.__mul__(other)
+
+    def __div__(self, other):
+        """
+        Define a method for dividing the NXdata group by a NXdata group
+        or a number. Only the signal data is affected.
+
+        The result contains a copy of all the metadata contained in
+        the first NXdata group. The module checks that the dimensions are
+        compatible, but does not check that the NXfield names or values are
+        identical. This is so that spelling variations or rounding errors
+        do not make the operation fail. However, it is up to the user to
+        ensure that the results make sense.
+        """
+        result = NXdata(entries=self.entries, attrs=self.attrs)
+        if isinstance(other, NXdata):
+            if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape:
+                # error here, signal and othersignal not defined here
+                #result.entries[self.nxsignal.nxname] = signal / othersignal
+                result.entries[self.nxsignal.nxname] = self.nxsignal / other.nxsignal
+                resultvalues = result.entries[self.nxsignal.nxname].nxdata
+                if self.nxerrors:
+                    if other.nxerrors:
+                        result.errors = (np.sqrt(self.errors.nxdata**2 +
+                                         (resultvalues*other.errors.nxdata)**2)
+                                         / other.nxsignal)
+                    else:
+                        result.errors = self.errors
+                return result
+        elif isinstance(other, NXgroup):
+            raise NeXusError("Cannot divide two arbitrary groups")
+        else:
+            result.entries[self.nxsignal.nxname] = self.nxsignal / other
+            result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname
+            if self.nxerrors: result.errors = self.errors / other
+            return result
+
+
+class NXmonitor(NXdata):
+
+    """
+    NXmonitor group. This is a subclass of the NXdata class.
+
+    See the NXdata and NXgroup documentation for more details.
+    """
+
+    def __init__(self, signal=None, axes=(), *items, **opts):
+        NXdata.__init__(self, signal=signal, axes=axes, *items, **opts)
+        self._class = "NXmonitor"
+        if "name" not in opts.keys():
+            self._name = "monitor"
+
+
+class NXlog(NXgroup):
+
+    """
+    NXlog group. This is a subclass of the NXgroup class.
+
+    Methods
+    -------
+    plot(self, **opts)
+        Plot the logged values against the elapsed time. Valid
+        Matplotlib parameters, specifying markers, colors, etc, can be
+        specified using the 'opts' dictionary.
+
+    See the NXgroup documentation for more details.
+    """
+
+    def __init__(self, *items, **opts):
+        self._class = "NXlog"
+        NXgroup.__init__(self, *items, **opts)
+
+    def plot(self, **opts):
+        axis = [self.time]
+        title = "%s Log" % self.value.nxname.upper()
+        self._plotter.plot(self.value, axis, title, **opts)
+
+
+#-------------------------------------------------------------------------
+#Add remaining base classes as subclasses of NXgroup and append to __all__
+
+for _class in _nxclasses:
+    if _class not in globals():
+        docstring = """
+                    %s group. This is a subclass of the NXgroup class.
+
+                    See the NXgroup documentation for more details.
+                    """ % _class
+        globals()[_class]=type(_class, (NXgroup,),
+                               {'_class':_class,'__doc__':docstring})
+    __all__.append(_class)
+
+#-------------------------------------------------------------------------
+
+
+def centers(signal, axes):
+    """
+    Return the centers of the axes.
+
+    This works regardless if the axes contain bin boundaries or centers.
+    """
+    def findc(axis, dimlen):
+        if axis.shape[0] == dimlen+1:
+            return (axis.nxdata[:-1] + axis.nxdata[1:])/2
+        else:
+            assert axis.shape[0] == dimlen
+            return axis.nxdata
+    return [findc(a,signal.shape[i]) for i,a in enumerate(axes)]
+
+def setmemory(value):
+    """
+    Set the memory limit for data arrays (in MB).
+    """
+    global NX_MEMORY
+    NX_MEMORY = value
+
+def label(field):
+    """
+    Return a label for a data field suitable for use on a graph axis.
+    """
+    if hasattr(field,'long_name'):
+        return field.long_name
+    elif hasattr(field,'units'):
+        return "%s (%s)"%(field.nxname,field.units)
+    else:
+        return field.nxname
+
+# File level operations
+def load(filename, mode='r'):
+    """
+    Read a NeXus file returning a tree of objects.
+
+    This is aliased to 'read' because of potential name clashes with Numpy
+    """
+    file = NeXusTree(filename,mode)
+    tree = file.readfile()
+    file.close()
+    return tree
+
+#Definition for when there are name clashes with Numpy
+nxload = load
+__all__.append('nxload')
+
+def save(filename, group, format='w5'):
+    """
+    Write a NeXus file from a tree of objects.
+    """
+    if group.nxclass == "NXroot":
+        tree = group
+    elif group.nxclass == "NXentry":
+        tree = NXroot(group)
+    else:
+        tree = NXroot(NXentry(group))
+    file = NeXusTree(filename, format)
+    file.writefile(tree)
+    file.close()
+
+def tree(file):
+    """
+    Read and summarize the named NeXus file.
+    """
+    nxfile = load(file)
+    nxfile.tree
+
+def demo(argv):
+    """
+    Process a list of command line commands.
+
+    'argv' should contain program name, command, arguments, where command is one
+    of the following:
+        copy fromfile.nxs tofile.nxs
+        ls f1.nxs f2.nxs ...
+    """
+    if len(argv) > 1:
+        op = argv[1]
+    else:
+        op = 'help'
+    if op == 'ls':
+        for f in argv[2:]: dir(f)
+    elif op == 'copy' and len(argv)==4:
+        tree = load(argv[2])
+        save(argv[3], tree)
+    elif op == 'plot' and len(argv)==4:
+        tree = load(argv[2])
+        for entry in argv[3].split('.'):
+            tree = getattr(tree,entry)
+        tree.plot()
+        tree._plotter.show()
+
+    else:
+        usage = """
+usage: %s cmd [args]
+    copy fromfile.nxs tofile.nxs
+    ls *.nxs
+    plot file.nxs entry.data
+        """%(argv[0],)
+        print usage
+
+
+if __name__ == "__main__":
+    import sys
+    demo(sys.argv)
+
diff --git a/bindings/python/nxs/unit.py b/bindings/python/nxs/unit.py
new file mode 100644
index 0000000..1bcf807
--- /dev/null
+++ b/bindings/python/nxs/unit.py
@@ -0,0 +1,196 @@
+# This program is public domain
+# Author: Paul Kienzle
+"""
+Define unit conversion support for NeXus style units.
+
+The unit format is somewhat complicated.  There are variant spellings
+and incorrect capitalization to worry about, as well as forms such as
+"mili*metre" and "1e-7 seconds".
+
+This is a minimal implementation of units including only what I happen to
+need now.  It does not support the complete dimensional analysis provided
+by the package udunits on which NeXus is based, or even the units used
+in the NeXus definition files.
+
+Unlike other units modules, this module does not carry the units along 
+with the value, but merely provides a conversion function for 
+transforming values.
+
+Usage example::
+
+    import nxs.unit
+    u = nxs.unit.Converter('mili*metre')  # Units stored in mm
+    v = u(3000,'m')  # Convert the value 3000 mm into meters
+
+NeXus example::
+
+    # Load sample orientation in radians regardless of how it is stored.
+    # 1. Open the path
+    file.openpath('/entry1/sample/sample_orientation')
+    # 2. scan the attributes, retrieving 'units'
+    units = [for attr,value in file.attrs() if attr == 'units']
+    # 3. set up the converter (assumes that units actually exists)
+    u = nxs.unit.Converter(units[0])
+    # 4. read the data and convert to the correct units
+    v = u(file.read(),'radians')
+
+This is a standalone module, not relying on either DANSE or NeXus, and
+can be used for other unit conversion tasks.
+
+Note: minutes are used for angle and seconds are used for time.  We
+cannot tell what the correct interpretation is without knowing something
+about the fields themselves.  If this becomes an issue, we will need to
+allow the application to set the dimension for the units rather than
+getting the dimension from the units as we are currently doing.
+"""
+
+# TODO: Add udunits to NAPI rather than reimplementing it in python
+# TODO: Alternatively, parse the udunits database directly
+# UDUnits:
+#  http://www.unidata.ucar.edu/software/udunits/udunits-1/udunits.txt
+
+# TODO: Allow application to impose the map on the units
+
+from __future__ import division
+
+__all__ = ['Converter']
+
+import math
+
+
+# Limited form of units for returning objects of a specific type.
+# Maybe want to do full units handling with e.g., pyre's
+# unit class. For now lets keep it simple.  Note that
+def _build_metric_units(unit,abbr):
+    """
+    Construct standard SI names for the given unit.
+    Builds e.g.,
+        s, ns
+        second, nanosecond, nano*second
+        seconds, nanoseconds
+    Includes prefixes for femto through peta.
+
+    Ack! Allows, e.g., Coulomb and coulomb even though Coulomb is not
+    a unit because some NeXus files store it that way!
+    
+    Returns a dictionary of names and scales.
+    """
+    prefix = dict(peta=1e15,tera=1e12,giga=1e9,mega=1e6,kilo=1e3,
+                  deci=1e-1,centi=1e-2,milli=1e-3,mili=1e-3,micro=1e-6,
+                  nano=1e-9,pico=1e-12,femto=1e-15)
+    short_prefix = dict(P=1e15,T=1e12,G=1e9,M=1e6,k=1e3,
+                        d=1e-1,c=1e-2,m=1e-3,u=1e-6,
+                        n=1e-9,p=1e-12,f=1e-15)
+    map = {abbr:1}
+    map.update([(P+abbr,scale) for (P,scale) in short_prefix.iteritems()])
+    for name in [unit,unit.capitalize()]:
+        map.update({name:1,name+'s':1})
+        map.update([(P+name,scale) for (P,scale) in prefix.iteritems()])
+        map.update([(P+'*'+name,scale) for (P,scale) in prefix.iteritems()])
+        map.update([(P+name+'s',scale) for (P,scale) in prefix.iteritems()])
+    return map
+
+def _build_plural_units(**kw):
+    """
+    Construct names for the given units.  Builds singular and plural form.
+    """
+    map = {}
+    map.update([(name,scale) for name,scale in kw.iteritems()])
+    map.update([(name+'s',scale) for name,scale in kw.iteritems()])
+    return map
+
+def _build_all_units():
+    # Various distance measures
+    distance = _build_metric_units('meter','m')
+    distance.update(_build_metric_units('metre','m'))
+    distance.update(_build_plural_units(micron=1e-6, Angstrom=1e-10))
+    distance.update({'A':1e-10, 'Ang':1e-10})
+
+    # Various time measures.
+    # Note: minutes are used for angle rather than time
+    time = _build_metric_units('second','s')
+    time.update(_build_plural_units(hour=3600,day=24*3600,week=7*24*3600))
+
+    # Various angle measures.
+    # Note: seconds are used for time rather than angle
+    angle = _build_plural_units(degree=1, minute=1/60.,
+                  arcminute=1/60., arcsecond=1/3600., radian=180/math.pi)
+    angle.update(deg=1, arcmin=1/60., arcsec=1/3600., rad=180/math.pi)
+
+    frequency = _build_metric_units('hertz','Hz')
+    frequency.update(_build_metric_units('Hertz','Hz'))
+    frequency.update(_build_plural_units(rpm=1/60.))
+
+    # Note: degrees are used for angle
+    # Note: temperature needs an offset as well as a scale
+    temperature = _build_metric_units('kelvin','K')
+    temperature.update(_build_metric_units('Kelvin','K'))
+
+    charge = _build_metric_units('coulomb','C')
+    charge.update({'microAmp*hour':0.0036})
+
+    sld = { '10^-6 Angstrom^-2': 1e-6, 'Angstrom^-2': 1}
+    Q = { 'invAng': 1, 'invAngstroms': 1,
+          '10^-3 Angstrom^-1': 1e-3, 'nm^-1': 10 }
+
+    # APS files may be using 'a.u.' for 'arbitrary units'.  Other
+    # facilities are leaving the units blank, using ??? or not even
+    # writing the units attributes.
+    unknown = {None:1, '???':1, '': 1, 'a.u.':1}
+
+    dims = [unknown, distance, time, angle, frequency,
+            temperature, charge, sld, Q]
+    return dims
+
+class Converter(object):
+    """
+    Unit converter for NeXus style units.
+
+    """
+    # Define the units, using both American and European spelling.
+    scalemap = None
+    scalebase = 1
+    dims = _build_all_units()
+
+    def __init__(self,name):
+        self.base = name
+        for map in self.dims:
+            if name in map:
+                self.scalemap = map
+                self.scalebase = self.scalemap[name]
+                break
+        else:
+            self.scalemap = {'': 1}
+            self.scalebase = 1
+            #raise ValueError, "Unknown unit %s"%name
+
+    def scale(self, units=""):
+        if units == "" or self.scalemap is None: return 1
+        return self.scalebase/self.scalemap[units]
+
+    def __call__(self, value, units=""):
+        # Note: calculating a*1 rather than simply returning a would produce
+        # an unnecessary copy of the array, which in the case of the raw
+        # counts array would be bad.  Sometimes copying and other times
+        # not copying is also bad, but copy on modify semantics isn't
+        # supported.
+        if units == "" or self.scalemap is None: return value
+        try:
+            return value * (self.scalebase/self.scalemap[units])
+        except KeyError:
+            raise KeyError("%s not in %s"%(units," ".join(self.scalemap.keys())))
+
+def _check(expect,get):
+    if expect != get: raise ValueError, "Expected %s but got %s"%(expect,get)
+    #print expect,"==",get
+
+def test():
+    _check(2,Converter('mm')(2000,'m')) # 2000 mm -> 2 m
+    _check(0.003,Converter('microseconds')(3,units='ms')) # 3 us -> 0.003 ms
+    _check(45,Converter('nanokelvin')(45))  # 45 nK -> 45 nK
+    # TODO: more tests
+    _check(0.5,Converter('seconds')(1800,units='hours')) # 1800 -> 0.5 hr
+    _check(2.5,Converter('a.u.')(2.5,units=''))
+
+if __name__ == "__main__":
+    test()
diff --git a/bindings/python/nxstest.py b/bindings/python/nxstest.py
new file mode 100644
index 0000000..cc29d09
--- /dev/null
+++ b/bindings/python/nxstest.py
@@ -0,0 +1,429 @@
+# This program is public domain
+
+# Author: Paul Kienzle
+
+"""
+NeXus tests converted to python.
+"""
+
+import nxs,os,numpy,sys
+
+def memfootprint():
+    import gc
+    objs = gc.get_objects()
+    classes = set( c.__class__ for c in gc.get_objects() if hasattr(c,'__class__') )
+    # print "\n".join([c.__name__ for c in classes])
+    print "#objects=",len(objs)
+    print "#classes=",len(classes)
+
+def leak_test1(n = 1000, mode='w5'):
+#    import gc
+#    gc.enable()
+#    gc.set_debug(gc.DEBUG_LEAK)
+    filename = "leak_test1.nxs"
+    try: os.unlink(filename)
+    except OSError: pass
+    file = nxs.open(filename,mode)
+    file.close()
+    print "File should exist now"
+    for i in range(n):
+        if i%100 == 0: 
+            print "loop count %d"%i
+            memfootprint()
+        file.open()
+        file.close()
+#        gc.collect()
+    os.unlink(filename)
+
+def _show(file, indent=0):
+    prefix = ' '*indent
+    link = file.link()
+    if link:
+        print "%(prefix)s-> %(link)s" % locals()
+        return
+    for attr,value in file.attrs():
+        print "%(prefix)s@%(attr)s: %(value)s" % locals()
+    for name,nxclass in file.entries():
+        if nxclass == "SDS":
+            shape,dtype = file.getinfo()
+            dims = "x".join([str(x) for x in shape])
+            print "%(prefix)s%(name)s %(dtype)s %(dims)s" % locals()
+            link = file.link()
+            if link:
+                print "  %(prefix)s-> %(link)s" % locals()
+            else:
+                for attr,value in file.attrs():
+                    print "  %(prefix)s@%(attr)s: %(value)s" % locals()
+                if numpy.prod(shape) < 8:
+                    value = file.getdata()
+                    print "  %s%s"%(prefix,str(value))
+        else:
+            print "%(prefix)s%(name)s %(nxclass)s" % locals()
+            _show(file, indent+2)
+
+def show_structure(filename):
+    file = nxs.open(filename)
+    print "=== File",file.inquirefile()
+    _show(file)
+    
+
+def populate(filename,mode):
+    c1 = numpy.array(['abcd','efgh','ijkl','mnop','qrst'])
+    i1 = numpy.arange(4,dtype='uint8')
+    i2 = numpy.arange(4,dtype='int16')*1000
+    i4 = numpy.arange(4,dtype='int32')*1000000
+    i8 = numpy.arange(4,dtype='int64')*1000000000000
+    r4 = numpy.arange(20,dtype='float32').reshape((5,4))
+    r8 = numpy.arange(20,dtype='float64').reshape((5,4))
+    comp_array=numpy.ones((100,20),dtype='int32')
+    for i in range(100): comp_array[i,:] *= i
+
+    file = nxs.open(filename,mode)
+    file.setnumberformat('float32','%9.3g')
+    file.makegroup("entry","NXentry")
+    file.opengroup("entry","NXentry")
+    file.putattr("hugo","namenlos")
+    file.putattr("cucumber","passion")
+    #file.putattr("embedded_null","embedded\000null")
+
+    # Write character data
+    file.makedata("ch_data",'char',[10])
+    file.opendata("ch_data")
+    file.putdata("NeXus data")
+    file.closedata()
+    file.makedata("c1_data",'char',[5,4])
+    file.opendata("c1_data")
+    file.putdata(c1)
+    file.closedata()
+    
+    # Write numeric data
+    for var in ['i1','i2','i4','i8','r4']:
+        if mode == 'w4' and var == 'i8': continue
+        name = var+'_data'
+        val = locals()[var]
+        file.makedata(name,val.dtype,val.shape)
+        file.opendata(name)
+        file.putdata(val)
+        file.closedata()
+    
+    # Write r8_data
+    file.makedata('r8_data','float64',[5,4])
+    file.opendata('r8_data')
+    file.putslab(r8[4,:],[4,0],[1,4])
+    file.putslab(r8[0:4,:],[0,0],[4,4])
+    file.putattr("ch_attribute","NeXus")
+    file.putattr("i4_attribute",42,dtype='int32')
+    file.putattr("r4_attribute",3.14159265,dtype='float32')
+    ## Oops... NAPI doesn't support array attributes
+    #file.putattr("i4_array",[3,2],dtype='int32')
+    #file.putattr("r4_array",[3.14159265,2.718281828],dtype='float32')
+    dataID = file.getdataID()
+    file.closedata()
+
+    # Create the NXdata group
+    file.makegroup("data","NXdata")
+    file.opengroup("data","NXdata")
+    
+    # .. demonstrate linking
+    file.makelink(dataID)
+
+    # .. demonstrate compressed data
+    file.compmakedata("comp_data",'int32',[100,20],'lzw',[20,20])
+    file.opendata('comp_data')
+    file.putdata(comp_array)
+    file.closedata()
+    file.flush()
+
+    # .. demonstrate extensible data
+    file.makedata('flush_data','int32',[nxs.UNLIMITED])
+    file.opendata('flush_data')
+    for i in range(7):
+        file.putslab(i,[i],[1])
+    file.closedata()
+    file.flush()
+    file.closegroup()
+
+    # Create NXsample group
+    file.makegroup('sample','NXsample')
+    file.opengroup('sample','NXsample')
+    file.makedata('ch_data','char',[20])
+    file.opendata('ch_data')
+    file.putdata('NeXus sample')
+    file.closedata()
+    sampleID = file.getgroupID()
+    file.closegroup()
+    file.closegroup()
+
+    # Demonstrate named links
+    file.makegroup('link','NXentry')
+    file.opengroup('link','NXentry')
+    file.makelink(sampleID)
+    file.makenamedlink('renLinkGroup',sampleID)
+    file.makenamedlink('renLinkData',dataID)
+    file.closegroup()
+    
+    file.close()
+    return filename
+
+failures = 0
+def fail(msg):
+    global failures
+    print "FAIL:",msg
+    failures += 1
+
+def dicteq(a,b):
+    """
+    Compare two dictionaries printing how they differ.
+    """
+    for k,v in a.iteritems():
+        if k not in b:
+            print k,"not in",b
+            return False
+        if v != b[k]: 
+            print v,"not equal",b[k]
+            return False
+    for k,v in b.iteritems():
+        if k not in a: 
+            print k,"not in",a
+            return False
+    return True
+
+def check(filename, mode):
+    global failures
+    failures = 0
+    file = nxs.open(filename,'rw')
+    if filename != file.inquirefile(): fail("Files don't match")
+
+    # check headers
+    num_attrs = file.getattrinfo()
+    wxattrs = ['xmlns','xmlns:xsi','xsi:schemaLocation', 'XML_version']
+    w4attrs = ['HDF_version']
+    w5attrs = ['HDF5_Version']
+    extras = dict(wx=wxattrs,w4=w4attrs,w5=w5attrs)
+    expected_attrs = ['NeXus_version','file_name','file_time']+extras[mode]
+    for i in range(num_attrs):
+        name,dims,type = file.getnextattr()
+        if name not in expected_attrs:
+            fail("attribute %s unexpected"%(name))
+    if num_attrs != len(expected_attrs): 
+        fail("Expected %d root attributes but got %d"
+             % (len(expected_attrs),num_attrs))
+    
+    file.opengroup('entry','NXentry')
+    
+    expect = dict(hugo='namenlos',cucumber='passion')
+    #expect['embedded_null'] = "embedded\000null"
+    get = dict((k,v) for k,v in file.attrs())
+    same = dicteq(get,expect)
+    if not same: fail("/entry attributes are %s"%(get))
+
+    # Check that the numbers are written correctly
+    for name,dtype,shape,scale in \
+        [('i1','int8',(4),1),
+         ('i2','int16',(4),1000),
+         ('i4','int32',(4),1000000),
+         ('i8','int64',(4),1000000000000),
+         ('r4','float32',(5,4),1),
+         ('r8','float64',(5,4),1)
+         ]:
+        if mode == 'w4' and name == 'i8': continue
+        n = numpy.prod(shape)
+        expected = numpy.arange(n,dtype=dtype).reshape(shape)*scale
+        file.opendata(name+'_data')
+        get = file.getdata()
+        file.closedata()
+        if not (get == expected).all(): 
+            fail("%s retrieved %s"%(dtype,get))
+
+
+    # Check attribute types
+    file.opendata('r8_data')
+    get = file.getattr("ch_attribute",5,'char')
+    if not get == "NeXus": fail("ch_attribute retrieved %s"%(get))
+    get = file.getattr("i4_attribute",1,'int32')
+    if not get == numpy.int32(42): fail("i4_attribute retrieved %s"%(get))
+    get = file.getattr("r4_attribute",1,'float32')
+    if ((mode=='wx' and not abs(get-3.14159265) < 1e-6) or
+        (mode!='wx' and not get == numpy.float32(3.14159265))):
+        fail("r4_attribute retrieved %s"%(get))
+    ## Oops... NAPI doesn't support array attributes
+    #expect = numpy.array([3,2],dtype='int32')
+    #get = file.getattr("i4_array",2,'int32')
+    #if not (get==expect).all(): fail('i4_array retrieved %s'%(get))
+    #expect = numpy.array([3.14159265,2.718281828],dtype='float32')
+    #get = file.getattr("r4_array",2,dtype='float32')
+    #if not (get==expect).all(): fail("r4_array retrieved %s"%(get))
+    file.closedata()
+
+    file.opendata('c1_data')
+    rawshape,rawdtype = file.getrawinfo()
+    shape,dtype = file.getinfo()
+    get = file.getdata()
+    file.closedata()
+    if not (shape[0]==5 and shape[1]==4 and dtype=='char'):
+        fail("returned string array info is incorrect")
+    if not (rawshape[0]==5 and rawshape[1]==4 and rawdtype=='char'):
+        fail("returned string array storage info is incorrect")
+        print rawshape,dtype
+    if not (get[0]=="abcd" and get[4]=="qrst"):
+        fail("returned string is incorrect")
+        print shape,dtype
+
+
+    # Check reading from compressed datasets
+    comp_array=numpy.ones((100,20),dtype='int32')
+    for i in range(100): comp_array[i,:] *= i
+    expected = comp_array
+    file.opengroup('data','NXdata') #/entry/data
+    file.opendata('comp_data')      #/entry/data/comp_data
+    get = file.getdata()
+    file.closedata()                #/entry/data/comp_data
+    file.closegroup()               #/entry/data
+    if not (get == expected).all():
+        fail("compressed data differs")
+        print get
+        
+    # Check strings
+    file.opengroup('sample','NXsample') #/entry/sample
+    file.opendata('ch_data')            #/entry/sample/ch_data
+    rawshape,rawdtype = file.getrawinfo()
+    shape,dtype = file.getinfo()
+    get = file.getdata()
+    file.closedata()                    #/entry/sample/ch_data
+    file.closegroup()                   #/entry/sample
+    if not (shape[0]==12 and dtype=='char'):
+        fail("returned string info is incorrect")
+        print shape,dtype
+    if not (rawshape[0]==20 and rawdtype=='char'):
+        fail("returned string storage info is incorrect")
+        print shape,dtype
+    if not (get == "NeXus sample"):
+        fail("returned string is incorrect")
+        print shape,dtype
+
+    file.closegroup() #/entry
+
+    # Check read slab (e.g., from extensible)
+
+    # Check links
+    file.opengroup('entry','NXentry')
+    file.opengroup('sample','NXsample')
+    sampleid = file.getgroupID()
+    file.closegroup() #/entry/sample
+    file.opengroup('data','NXdata') #/entry/data
+    file.opendata('r8_data') #/entry/data/r8_data
+    dataid = file.getdataID()
+    file.closedata() #/entry/data/r8_data
+    file.closegroup() #/entry/data
+    file.opendata('r8_data')
+    data2id = file.getdataID()
+    file.closedata()
+    file.closegroup() #/entry
+    if not (file.sameID(dataid,data2id)):
+        fail("/entry/data/r8_data not linked to /entry/r8_data")
+    
+    # Check openpath and getslab
+    file.openpath('/entry/data/comp_data')
+    get = file.getslab([4,4],[5,3])
+    expected = comp_array[4:(4+5),4:(4+3)]
+    if not (get == expected).all():
+        fail("retrieved compressed slabs differ")
+        print get
+    file.openpath('/entry/data/comp_data')
+    get = file.getslab([4,4],[5,3])
+    expected = comp_array[4:(4+5),4:(4+3)]
+    if not (get == expected).all():
+        fail("after reopen: retrieved compressed slabs differ")
+        print get
+    file.openpath('../r8_data')
+    for k,v in file.attrs():
+        if k == 'target' and v != '/entry/r8_data':
+            fail("relative openpath was not successful")
+
+    return failures == 0
+
+def populate_external(filename,mode):
+    ext = dict(w5='.h5',w4='.hdf',wx='.xml')[mode]
+    file = nxs.open(filename,mode)
+    file.makegroup('entry1','NXentry')
+    file.linkexternal('entry1','NXentry','nxfile://data/dmc01'+ext)
+    file.makegroup('entry2','NXentry')
+    file.linkexternal('entry2','NXentry','nxfile://data/dmc02'+ext)
+    file.makegroup('entry3','NXentry')
+    file.close()
+
+def check_external(filename,mode):
+    ext = dict(w5='.h5',w4='.hdf',wx='.xml')[mode]
+    file = nxs.open(filename,'rw')
+    
+    file.openpath('/entry1/start_time')
+    time = file.getdata()
+    
+    get = file.inquirefile()
+    expected = 'nxfile://data/dmc01'+ext
+    if expected != get: fail("first external file returned %s"%(get))
+    
+    file.openpath('/entry2/sample/sample_name')
+    sample = file.getdata()
+
+    get = file.inquirefile()
+    expected = 'nxfile://data/dmc02'+ext
+    if expected != get: fail("second external file returned %s"%(get))
+
+    file.openpath('/')
+    remote = file.isexternalgroup('entry1','NXentry')
+    if remote is None:
+        fail("failed to identify /entry1 as external")
+    remote = file.isexternalgroup('entry3','NXentry')
+    if remote is not None: 
+        fail('incorrectly identified /entry3 as external')
+    
+    file.close()
+
+def test_external(mode,quiet=True):
+    ext = dict(w5='.h5',w4='.hdf',wx='.xml')[mode]
+    filename = 'nxext'+ext
+    populate_external(external,mode)
+    if not quiet:
+        show_structure(external)
+    failures = check_external(filename,mode)
+    return failures
+
+def test_mode(mode,quiet=True,external=False):
+    ext = dict(w5='.h5',w4='.hdf',wx='.xml')[mode]
+    filename = 'NXtest'+ext
+    populate(filename,mode=mode)
+    if not quiet and 'NX_LOAD_PATH' in os.environ:
+        show_structure('dmc01'+ext)
+    if not quiet:
+        show_structure(filename)
+    failures = check(filename,mode)
+    if external: failures += test_external(mode,quiet)
+    return failures
+
+def test():
+    tests = 0
+    if '-q' in sys.argv:
+        quiet = True
+    else:
+        quiet = False
+    if '-x' in sys.argv:
+        external = True
+        
+    else:
+        external = False
+    if 'hdf4' in sys.argv: 
+        test_mode('w4',quiet,external)
+        tests += 1
+    if 'xml' in sys.argv:
+        test_mode('wx',quiet,external)
+        tests += 1
+    if 'hdf5' in sys.argv: 
+        test_mode('w5',quiet,external)
+        tests += 1
+    if tests == 0: test_mode('w5',quiet,external)
+
+if __name__ == "__main__":
+    test()
+    #leak_test1(n=10000)
+    
diff --git a/bindings/python/pythondoc.cmake b/bindings/python/pythondoc.cmake
new file mode 100644
index 0000000..76af606
--- /dev/null
+++ b/bindings/python/pythondoc.cmake
@@ -0,0 +1,29 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+set (ENV{NEXUSLIB} ${NEXUSLIB})
+execute_process(COMMAND ${PYTHON_DOC} -w ${NXSPYTHON_SOURCE})
diff --git a/bindings/python/run_nxstest b/bindings/python/run_nxstest
new file mode 100755
index 0000000..4dfe79f
--- /dev/null
+++ b/bindings/python/run_nxstest
@@ -0,0 +1,6 @@
+#!/bin/sh
+#
+# this script allows nxstest to be run again the built, rather than installed,
+# version of nexus
+#
+env LD_LIBRARY_PATH=../../src/.libs python nxstest.py $*
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
new file mode 100755
index 0000000..ef2a783
--- /dev/null
+++ b/bindings/python/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+#
+# This file is for a manual install of python on windows
+# If python is already present it should be detected by
+# the windows installer and the nxs directory copied to
+# the python site-packages directory
+#
+# On Linux the Makefile will also install python, but not 
+# using this file - instead it uses the automake python install bits
+#
+# To use this file type:
+#
+#        python setup.py install
+#
+from distutils.core import setup 
+ 
+setup(name='NeXus', 
+       version='4.2', 
+       description='Python Bindings to libNeXus', 
+       author='Paul Kienzle', 
+       packages = ['nxs'], 
+       ) 
diff --git a/bindings/python/test/nxs_napi_lowlevel.py b/bindings/python/test/nxs_napi_lowlevel.py
new file mode 100644
index 0000000..a3c1985
--- /dev/null
+++ b/bindings/python/test/nxs_napi_lowlevel.py
@@ -0,0 +1,215 @@
+#testing low level functionality 
+
+import unittest
+import sys
+import os
+import numpy
+
+sys.path.append("../")
+
+#load the testing module
+import nxs.napi
+
+
+class NAPILowLevelTestCase(unittest.TestCase):
+    #static members
+    _fname = "NAPI_LL_TEST.nxs"
+
+    _shape1 = [20,30]
+    _shape2 = [10,20,30]
+    _dshape = [nxs.UNLIMITED,20,30]
+
+    def setUp(self):
+        self._file = nxs.napi.open(self._fname,"w")
+
+        self._file.makegroup("scan_1","NXentry")
+        
+        pass
+
+    def tearDown(self):
+        self._file.close()
+
+        try:
+            os.remove(self._fname)
+        except:
+            pass
+
+    def test_constants(self):
+        self.assertEqual(nxs.napi.NOSTRIP,128)
+        self.assertEqual(nxs.napi.UNLIMITED,1)
+        self.assertEqual(nxs.napi.MAXRANK,32)
+        self.assertEqual(nxs.napi.MAXNAMELEN,64)
+        self.assertEqual(nxs.napi.MAXPATHLEN,1024)
+
+        d = nxs.napi._compression_code
+        dr = {"none":100,"lzw":200,"rle":300,"huffman":400}
+        self.assertDictEqual(dr,d)
+
+        d = nxs.napi._nxtype_code
+        dr = {"char":4,"float32":5,"float64":6,
+              "int8":20,"uint8":21,"int16":22,"uint16":23,
+              "int32":24,"uint32":25,"int64":26,"uint64":27}
+        self.assertDictEqual(dr,d)
+
+        d = nxs.napi._nxopen_mode
+        dr = {"r":1,"rw":2,"w":3,"w4":4,"w5":5,"wx":6}
+        self.assertDictEqual(d,dr)
+
+        l = nxs.nxapi.H4SKIP
+        lr = ['CDF0.0','_HDF_CHK_TBL_','Attr0.0','RIG0.0','RI0.0',
+                'RIATTR0.0N','RIATTR0.0C']
+        self.assertListEqual(l,lr)
+    
+    def test_file_open(self): 
+        self.assertRaises(nxs.napi.NeXusError,nxs.napi.open,"bla.nxs","r")
+       
+        #should produce no exception
+        f = nxs.napi.open("bla.nxs","w")
+
+        f = nxs.napi.open("bla.nxs","rw")
+
+        f.close()
+        os.remove("bla.nxs")
+
+    def test_file_attributes(self):
+
+        self._file.makegroup("/data","NXentry")
+        self._file.opengroup("/data")
+        self._file.closegroup()
+    
+
+    def test_file_groups(self):
+
+        #should not work - group does not exist
+        self.assertRaises(nxs.napi.NeXusError,self._file.opengroup,"data")
+        self.assertRaises(nxs.napi.NeXusError,self._file.opengroup,"/data/test")
+
+        #this should work
+        self._file.makegroup("data","NXentry")
+
+        #try to open the group in various ways
+        self.assertRaises(nxs.napi.NeXusError,self._file.opengrouppath,"/data/test/dir")
+        self.assertRaises(ValueError,self._file.opengroup,"data","NXinstrument")
+
+        #the documentation and the code is not very consistent with 
+        #its exceptions - NeXusError sometimes ValueError
+
+        self._file.opengrouppath("/data")   #should work
+        self._file.openpath("/data")  #works too
+
+        self.assertRaises(nxs.napi.NeXusError,self._file.openpath,"/data/test/dir")
+
+
+    def test_file_compdata(self):
+        pass
+
+    def test_file_simpledata(self):
+        pass
+
+
+    def __test_slab_data(self,typecode):
+        self._file.opengroup("scan_1")
+       
+        #--------------write data to disk---------------------------
+        def write_slab(np,d,offset,shape):
+            for i in range(np):
+                offset[0] = i*shape[0]
+                d[...] = i
+                self._file.putslab(d,offset,shape)
+        
+        #-------------read data from disk----------------------------
+        def read_slab(np,d,offset,shape):
+            for i in range(np):
+                d[...] = i
+                offset[0] = i*shape[0]
+                o = numpy.squeeze(self._file.getslab(offset,shape))
+                self.assertListEqual(d.flatten().tolist(),o.flatten().tolist())
+
+        #--------------------IO per frame-----------------------------
+        #create and open dataset 
+        self._file.makedata("data",dtype=typecode,shape=self._dshape)
+        self._file.opendata("data")
+
+        #create data 
+        d = numpy.ones(self._shape1,dtype=typecode)
+        offset = [0,0,0]
+        shape = [1]+self._shape1
+
+        #write data
+        write_slab(10,d,offset,shape)
+
+        #read data back
+        d[...] = 1
+        read_slab(10,d,offset,shape)
+    
+        #close dataset
+        self._file.closedata()
+        
+        #--------------------IO per frame with compression-----------------
+        #create and open dataset 
+        self._file.compmakedata("data3",dtype=typecode,shape=self._dshape,
+                mode="lzw",chunks=[1]+self._shape1)
+        self._file.opendata("data")
+
+        #create data 
+        d = numpy.ones(self._shape1,dtype=typecode)
+        offset = [0,0,0]
+        shape = [1]+self._shape1
+
+        #write data
+        write_slab(10,d,offset,shape)
+
+        #read data back
+        d[...] = 1
+        read_slab(10,d,offset,shape)
+    
+        #close dataset
+        self._file.closedata()
+      
+        #------------------volume IO----------------------------------
+        #create new dataset
+        self._file.makedata("data2",dtype=typecode,shape=self._dshape)
+        self._file.opendata("data2")
+
+        #create data 
+        d = numpy.ones(self._shape2,dtype=typecode)
+        offset = [0,0,0]
+        shape = self._shape2
+
+        #write data
+        write_slab(10,d,offset,shape)
+
+        #read data back
+        d[...] = 1
+        read_slab(10,d,offset,shape)
+
+        #close the dataset
+        self._file.closedata()
+
+        self._file.closegroup()
+
+    def test_file_slabdata_uint16(self):
+        self.__test_slab_data("uint16")
+
+    def test_file_slabdata_int16(self):
+        self.__test_slab_data("int16")
+
+    def test_file_slabdata_uint32(self):
+        self.__test_slab_data("uint32")
+        
+    def test_file_slabdata_uint32(self):
+        self.__test_slab_data("int32")
+
+    def test_file_slabdata_float32(self):
+        self.__test_slab_data("float32")
+
+    def test_file_slabdata_float64(self):
+        self.__test_slab_data("float64")
+
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(NAPILowLevelTest('test_constants'))
+
+    return suite
diff --git a/bindings/python/test/runtest.py b/bindings/python/test/runtest.py
new file mode 100755
index 0000000..4ae4928
--- /dev/null
+++ b/bindings/python/test/runtest.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+#run unit tests
+
+import unittest
+
+from nxs_napi_lowlevel import NAPILowLevelTestCase
+
+
+suite1 = unittest.TestLoader().loadTestsFromTestCase(NAPILowLevelTestCase)
+
+alltests = unittest.TestSuite([suite1])
+
+unittest.TextTestRunner(verbosity=2).run(alltests)
+
+
+
+
+
diff --git a/bindings/swig/CMakeLists.txt b/bindings/swig/CMakeLists.txt
new file mode 100644
index 0000000..169e7ca
--- /dev/null
+++ b/bindings/swig/CMakeLists.txt
@@ -0,0 +1,152 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.neutron.anl.gov/NeXus/>
+#
+#
+#====================================================================
+
+if (SWIG_FOUND AND TCL_FOUND)
+
+    set (SWIG_TCL_WRAP nxinter_wrap.c)
+
+    add_definitions(-DIN_NEXUS_LIBRARY ${HDF5_DEFINITIONS} ${HDF5_CPP} ${HDF4_CPP} ${MXML_CPP})
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    ${SWIG_TCL_WRAP}
+        COMMAND   ${SWIG_EXECUTABLE}
+        ARGS      -I$(CMAKE_SOURCE_DIR)/bindings/swig -o ${SWIG_TCL_WRAP} -tcl -ltclsh.i nxinter.i
+        COMMENT   "Generating ${SWIG_TCL_WRAP}"
+    )
+
+    ADD_CUSTOM_TARGET(NexusSwingTCLBuild ALL echo
+        DEPENDS   ${SWIG_TCL_WRAP}
+    )
+
+    add_library (SWIG_TCL_Static_Library STATIC ${SWIG_TCL_WRAP})
+
+    set_target_properties(SWIG_TCL_Static_Library PROPERTIES OUTPUT_NAME libnxtcl)
+
+    target_link_libraries(SWIG_TCL_Static_Library NeXus_Static_Library ${TCL_LIBRARY})
+
+    add_executable (nxinter ${SWIG_TCL_WRAP} ${TCL_INCLUDE_PATH})
+
+    target_link_libraries(nxinter NeXus_Static_Library ${TCL_LIBRARY})
+
+endif (SWIG_FOUND AND TCL_FOUND)
+
+if (SWIG_FOUND AND GUILE_FOUND)
+
+    set (SWIG_GUILE_WRAP nxguile_wrap.c)
+
+    add_definitions(-DSWIGINIT="SCM scm_init_nxinter_module(void); scm_init_nxinter_module();")
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    ${SWIG_GUILE_WRAP}
+        COMMAND   ${SWIG_EXECUTABLE}
+        ARGS      -I$(CMAKE_SOURCE_DIR)/bindings/swig -o ${SWIG_GUILE_WRAP} -guile -lguilemain.i nxinter.i
+        COMMENT   "Generating ${SWIG_GUILE_WRAP}"
+    )
+
+    ADD_CUSTOM_TARGET(NexusSwingGuileBuild ALL echo
+        DEPENDS   ${SWIG_GUILE_WRAP}
+    )
+
+    add_library (SWIG_GUILE_Static_Library STATIC ${SWIG_GUILE_WRAP})
+
+    set_target_properties(SWIG_GUILE_Static_Library PROPERTIES OUTPUT_NAME libnxguile)
+
+    target_link_libraries(SWIG_GUILE_Static_Library NeXus_Static_Library ${GUILE_LIB})
+
+    add_executable (nxguile ${SWIG_GUILE_WRAP} ${GUILE_INCLUDE})
+
+    target_link_libraries(nxguile NeXus_Static_Library ${GUILE_LIB})
+
+endif (SWIG_FOUND AND GUILE_FOUND)
+
+if (SWIG_FOUND AND MZScheme_FOUND)
+
+    set (SWIG_MZScheme_WRAP nxscheme_wrap.c)
+
+    add_definitions(-DSWIGINIT="SCM scm_init_nxinter_module(void); scm_init_nxinter_module();")
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    ${SWIG_MZScheme_WRAP}
+        COMMAND   ${SWIG_EXECUTABLE}
+        ARGS      -I$(CMAKE_SOURCE_DIR)/bindings/swig -o ${SWIG_MZScheme_WRAP} -mzscheme nxinter.i
+        COMMENT   "Generating ${SWIG_MZScheme_WRAP}"
+    )
+
+    ADD_CUSTOM_TARGET(NexusSwingMZSchemeBuild ALL echo
+        DEPENDS   ${SWIG_MZScheme_WRAP}
+    )
+
+    add_library (SWIG_MZScheme_Static_Library STATIC ${SWIG_MZScheme_WRAP})
+
+    set_target_properties(SWIG_MZScheme_Static_Library PROPERTIES OUTPUT_NAME libnxscheme)
+
+    target_link_libraries(testmxml MXML_Static_Library ${PTHREAD_LINK})
+
+endif (SWIG_FOUND AND MZScheme_FOUND)
+
+set (DOC_SRC nxinter.tex)
+
+if (LATEX_FOUND)
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    nxinter.aux
+        COMMAND   ${LATEX_COMPILER}
+        ARGS      ${DOC_SRC}
+        DEPENDS   nxinter.tex
+        COMMENT   "Generating SWIG INTER DVI"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    nxinter.dvi
+        COMMAND   ${LATEX_COMPILER}
+        ARGS      ${DOC_SRC}
+        DEPENDS   nxinter.aux
+        COMMENT   "Generating SWIG INTER DVI"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    nxinter.ps
+        COMMAND   ${DVIPS_CONVERTER}
+        ARGS      -o nxinter.ps nxinter.dvi
+        DEPENDS   nxinter.dvi
+        COMMENT   "Generating SWIG INTER PS"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    nxinter.pdf
+        COMMAND   ${PS2PDF_CONVERTER}
+        ARGS      nxinter.ps nxinter.pdf
+        DEPENDS   nxinter.ps
+        COMMENT   "Generating SWIG INTER PDF"
+    )
+
+    ADD_CUSTOM_TARGET(NexusSwingDOCBuild ALL echo
+        DEPENDS   nxinter.pdf
+    )
+
+endif (LATEX_FOUND)
\ No newline at end of file
diff --git a/bindings/swig/Makefile.am b/bindings/swig/Makefile.am
new file mode 100644
index 0000000..db9ea6a
--- /dev/null
+++ b/bindings/swig/Makefile.am
@@ -0,0 +1,147 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for NeXus SWIG bindings
+#
+#  Automake version Copyright (C) 2004 Freddie Akeroyd
+#  (based on original Makefile by Mark Koennecke, October 2002)
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/src
+lib_LTLIBRARIES=$(LIBNXTCL) $(LIBNXSCHEME) $(LIBNXGUILE) # $(LIBNXPERL)
+bin_PROGRAMS=$(NXINTER) $(NXGUILE)
+
+# old python wrapper
+#python_LTLIBRARIES=$(LIBNXPYTHON)
+#if HAVE_SWIG
+#if HAVE_PYTHON
+#NXPYTHONWRAP=nxpython.py
+#nodist_python_PYTHON=$(NXPYTHONWRAP)
+#LIBNXPYTHON=libnxpython.la
+#libnxpython_la_SOURCES=$(COMMON_SRC)
+#nodist_libnxpython_la_SOURCES=$(PYTHONWRAP)
+#libnxpython_la_CFLAGS=-I$(PYTHONROOT)/include/python$(PYTHON_VERSION) -I$(PYTHONROOT)/include $(CFLAGS)
+#libnxpython_la_LDFLAGS=-L$(PYTHONROOT)/lib/python$(PYTHON_VERSION)/config -lpython$(PYTHON_VERSION) $(top_builddir)/src/libNeXus.la @SHARED_LDFLAGS@ $(LDFLAGS)
+#PYTHONWRAP=nxpython_wrap.c
+#endif
+#nxpython_wrap.c: nxinter.i nxdataset.i
+#	$(SWIG) -I$(srcdir) -o $@ -python -module nxpython -interface libnxpython nxinter.i 
+#endif
+
+# perl wrapper (not working yet)
+#if HAVE_SWIG
+#if HAVE_PERL
+#LIBNXPERL=libnxperl.la
+#libnxperl_la_SOURCES=$(COMMON_SRC)
+#nodist_libnxperl_la_SOURCES=$(PERLWRAP)
+#libnxperl_la_CFLAGS=-I/usr/lib/perl5/5.8.6/i386-linux-thread-multi/CORE/ $(CFLAGS)
+#libnxperl_la_LDFLAGS=$(top_builddir)/src/libNeXus.la $(LDFLAGS)
+#PERLWRAP=nxperl_wrap.c
+#endif
+#nxperl_wrap.c: nxinter.i nxdataset.i
+#	$(SWIG) -I$(srcdir) -o $@ -perl5 -module nxperl nxinter.i 
+#endif
+
+# tcl wrapper
+if HAVE_SWIG
+if HAVE_TCL
+LIBNXTCL=libnxtcl.la
+NXINTER=nxinter
+TCLLIB=-L$(TCLROOT)/lib -ltcl
+libnxtcl_la_SOURCES=$(COMMON_SRC)
+nodist_libnxtcl_la_SOURCES=$(TCLWRAP)
+libnxtcl_la_CFLAGS=-I$(TCLROOT)/include
+libnxtcl_la_LDFLAGS=$(top_builddir)/src/libNeXus.la $(TCLLIB) $(LDFLAGS)
+
+nodist_nxinter_SOURCES=libnxtcl.la
+nxinter_LDFLAGS=-static libnxtcl.la $(top_builddir)/src/libNeXus.la $(TCLLIB) $(LDFLAGS)
+TCLWRAP=nxinter_wrap.c
+endif
+nxinter_wrap.c: nxinter.i nxdataset.i
+	$(SWIG) -I$(srcdir) -o $@ -tcl8 -ltclsh.i nxinter.i 
+endif
+
+# guile wrapper
+if HAVE_SWIG
+if HAVE_GUILE
+LIBNXGUILE=libnxguile.la
+NXGUILE=nxguile
+GGLIB=-L$(GUILEROOT)/lib -lguile
+libnxguile_la_SOURCES=$(COMMON_SRC)
+nodist_libnxguile_la_SOURCES=$(GUILEWRAP)
+libnxguile_la_CFLAGS=-I$(GUILEROOT)/include/guile \
+  -DSWIGINIT="SCM scm_init_nxinter_module(void); scm_init_nxinter_module();"\
+  $(CFLAGS)
+libnxguile_la_LDFLAGS=$(top_builddir)/src/libNeXus.la $(GGLIB) $(LDFLAGS)
+
+nodist_nxguile_SOURCES=libnxguile.la
+nxguile_LDFLAGS=-static libnxguile.la $(top_builddir)/src/libNeXus.la $(GGLIB) $(LDFLAGS)
+GUILEWRAP=nxguile_wrap.c
+endif
+nxguile_wrap.c: nxinter.i nxdataset.i
+	$(SWIG) -I$(srcdir) -o $@ -guile -lguilemain.i $(SWGUILEFLAGS) nxinter.i
+endif
+
+# mzscheme wrapper
+if HAVE_SWIG
+if HAVE_MZSCHEME
+LIBNXSCHEME=libnxscheme.la
+MZINC=/data/koenneck/opt/plt
+MZLIB=-L$(MZINC)/lib -lmzscheme -lmzgc $(MZINC)/lib/mzdyn.o
+libnxscheme_la_SOURCES=$(COMMON_SRC)
+nodist_libnxscheme_la_SOURCES=$(SCHEMEWRAP)
+libnxscheme_la_CFLAGS=-I$(MZINC)/include $(CFLAGS)
+libnxscheme_la_LDFLAGS=$(top_builddir)/src/libNeXus.la $(MZLIB) $(LDFLAGS)
+SCHEMEWRAP=nxscheme_wrap.c
+endif
+nxscheme_wrap.c: nxinter.i nxdataset.i
+	$(SWIG) -I$(srcdir) -o $@ -mzscheme nxinter.i 
+endif
+
+DOC_SRC		= nxinter.tex
+if HAVE_LATEX
+DOC_OUTPUT=nxinter.ps nxinter.pdf
+nxinter.ps: $(DOC_SRC)
+	latex nxinter.tex
+	latex nxinter.tex
+	dvips -f nxinter.dvi > nxinter.ps
+
+nxinter.pdf : nxinter.ps
+	ps2pdf12 nxinter.ps nxinter.pdf
+endif
+swigdocdir 	= $(NXDOCDIR)/swig
+swigdoc_DATA	= $(DOC_OUTPUT)
+
+EXAMPLE_FILES = nxdstest.tcl nxexam.tcl nxintertest.tcl
+swigexampledir	= $(NXEXAMPLEDIR)/swig
+swigexample_DATA = $(EXAMPLE_FILES)
+
+include $(top_srcdir)/build_rules.am
+
+COMMON_SRC=nxinterhelper.c
+
+EXTRA_DIST=nxinter.i nxdataset.i nxinterhelper.h \
+		$(DOC_OUTPUT) $(DOC_SRC) $(EXAMPLE_FILES)
+
+BUILT_SOURCES=$(TCLWRAP) $(GUILEWRAP) $(PYTHONWRAP) $(SCHEMEWRAP) $(NXPYTHONWRAP)
+CLEANFILES=$(TCLWRAP) $(GUILEWRAP) $(PYTHONWRAP) $(SCHEMEWRAP) $(NXPYTHONWRAP)
diff --git a/bindings/swig/README b/bindings/swig/README
new file mode 100644
index 0000000..fc118b5
--- /dev/null
+++ b/bindings/swig/README
@@ -0,0 +1,23 @@
+
+   This directory contains the files for the SWIG interface to the 
+   NeXus-API. SWIG (http://www.swig.org) is a tool which takes as 
+   input a description of a C language interface and creates the wrapper
+   code for the inclusion of the C code into various scripting languages.
+
+   For more information and for procedures how to compile and link the
+   generated scripting language extension please consult the SWIG manual
+   and the example files delivered with the SWIG package.
+
+   Available files:
+   - nxinter.i The SWIG interface description
+   - nxinterhelper.c, nxinterhelper.h helper functions for the interface
+   - nxdataset.h, nxdataset.c  dataset functions
+   - nxdataset.i Interface for the dataset functions.
+   - nxinter.tex  brief documentation.
+   - Makefile Makefile for generating Tcl and mzscheme wrappers.
+   - various test files.
+
+
+   Mark Koennecke, November 2002
+
+
diff --git a/bindings/swig/asciidblib.scm b/bindings/swig/asciidblib.scm
new file mode 100644
index 0000000..02d5190
--- /dev/null
+++ b/bindings/swig/asciidblib.scm
@@ -0,0 +1,213 @@
+;--------------------------------------------------------------------------
+; A couple of utility functions for accessing ASCII data tables 
+; 
+; Mark Koennecke, December 2001
+;--------------------------------------------------------------------------
+
+; The separator to use for splitting lines into columns
+(define separator #\tab)
+
+;-------------------------------------------------------------------------
+; the current row we are working at
+(define currentRow '())
+
+;------------------------------------------------------------------------
+; functifyFields creates functions for each field which allows to 
+; retrieve the field value by a (fieldName) syntax. This is useful for
+; operator doing computations. The row to be accessed must be put into
+; currentRow however before this can work.
+(define functifyFields (lambda (header)
+      (letrec ( (count 0)
+             (funcOne (lambda (fieldList count)
+                (if (eq? fieldList '())
+                    '()
+                    (begin
+		      (eval (read (open-input-string (string-append 
+                        "(define " (car fieldList) 
+                        " (lambda () (list-ref currentRow " 
+                        (number->string count) " )))" ))))
+                      (funcOne (cdr fieldList) (+ count 1)) ) ) )) )
+           (funcOne (vector-ref header 1) count) ) )) 
+;-------------------------------------------------------------------------
+; readheader reads the header information of a database and stores it into
+; a vector. This vector will hold three things: A list of comment
+; lines (recognizable by a # int the first position of the line), a list
+; of field names and the dashline unchanged.
+;-------------------------------------------------------------------------
+ (define readheader (lambda (port) 
+     (letrec ( (fline "")
+               (getcomment (lambda (port)
+		    (let ((l (getline port)))
+                       (if (char=? (list-ref l 0) #\#)
+                         (cons (list->string l) (getcomment port))
+                         (begin
+                           (set! fline (list->string l))
+                           '() ) ) ) ) )
+            (comments (getcomment port))
+            (names (string-split fline (list separator) ))
+            (dash (read-line port))
+          )
+          (vector comments names dash) ) ) )
+;-------------------------------------------------------------------------
+; putdbline writes a database row to the given output port. The row is
+; specified as a list of field values.
+;-------------------------------------------------------------------------
+  (define putdbline (lambda (row port)
+       (letrec ( (putfield (lambda (row port)
+                   (display (list-ref row 0) port)
+                   (cond
+		     ( (eq? (cdr row) '())
+		       (newline port)
+                     )
+                     (else
+                        (display separator port)
+                        (putfield (cdr row) port) ) ) ) ) )
+          (if (not (eq? (cadr row) '()))
+            (putfield row port)) ) ) )  
+;-------------------------------------------------------------------------
+; writeheader writes a database header to a output port
+;-------------------------------------------------------------------------
+  (define writeheader (lambda (h port)
+     (let ( (putcomment (lambda (com port)
+               (if (not (eq? com '()))
+                (begin
+                  (write (car com) port)
+                  (newline port)
+                  (putcomment (cdr com) port) ) ) ) ) )
+          (putcomment (vector-ref h 0) port)
+          (putdbline (vector-ref h 1) port)
+          (display (vector-ref h 2) port)
+          (newline port) ) ))
+;-------------------------------------------------------------------------
+;locatefield determines the index of a field in a list of row values
+;-------------------------------------------------------------------------
+  (define locatefield (lambda (header name)
+      (letrec ( (count -1)
+	      (findindex (lambda (list name)
+                (cond
+                  ( (eq? list '())
+                    -1 )
+                  ( (string=? (car list) name)
+                    (+ count 1) )
+                  (else
+                    (set! count (+ count 1))
+                    (findindex (cdr list) name) ) ) ) ) )
+           (findindex (vector-ref header 1) name) ) ))
+;-------------------------------------------------------------------------
+; getname is a  convenience function for returning the i'th column name
+;------------------------------------------------------------------------
+  (define getname (lambda (header i)
+       (list-ref (vector-ref header 1) i)))
+;--------------------------------------------------------------------------
+; getline reads a line of text and returns the line as a list of characters
+;--------------------------------------------------------------------------
+  (define getline (lambda (port)
+		    (let ((c (read-char port)))
+		      (cond  
+		        ( (eof-object? c) c )
+		        ( (char=? c #\newline) '() )
+		       ; ( (char=? c #\cr) (cons #\space (getline port)) )
+		        (else (cons c (getline port)) ) ) ) ) )
+;-------------------------------------------------------------------------
+; read-line reads a line as a string
+;-------------------------------------------------------------------------
+ (define read-line (lambda (port) (list->string (getline port))))
+;============================================================================
+; A string splitting procedure from the net. Originally written by oleg
+
+; -- procedure: string-null? STRING
+; returns false if the string is the empt string, true else
+(define string-null? (lambda (txt)
+  (if (> 0  (string-length txt))
+	 #t
+         #f ) ) )
+;
+(define ++ (lambda (x) (+ x 1)))
+(define -- (lambda (x) (- x 1)))
+
+; -- procedure+: string-split STRING CHARSET
+; -- procedure+: string-split STRING CHARSET MAXSPLIT
+;
+; Returns a list of words delimited by the characters in CHARSET in
+; STRING. CHARSET is a list of characters that are treated as delimiters.
+; Leading or trailing delimeters are NOT trimmed. That is, the resulting
+; list will have as many initial empty string elements as there are
+; leading delimiters in STRING.
+;
+; If MAXSPLIT is specified and positive, the resulting list will
+; contain at most MAXSPLIT elements, the last of which is the string
+; remaining after (MAXSPLIT - 1) splits. If MAXSPLIT is specified and
+; non-positive, the empty list is returned. "In time critical
+; applications it behooves you not to split into more fields than you
+; really need."
+;
+; This is based on the split function in Python/Perl
+;
+; (string-split " abc d e f  ") ==> ("abc" "d" "e" "f")
+; (string-split " abc d e f  " '() 1) ==> ("abc d e f  ")
+; (string-split " abc d e f  " '() 0) ==> ()
+; (string-split ":abc:d:e::f:" '(#\:)) ==> ("" "abc" "d" "e" "" "f" "")
+; (string-split ":" '(#\:)) ==> ("" "")
+; (string-split "root:x:0:0:Lord" '(#\:) 2) ==> ("root" "x:0:0:Lord")
+; (string-split "/usr/local/bin:/usr/bin:/usr/ucb/bin" '(#\:))
+; ==> ("/usr/local/bin" "/usr/bin" "/usr/ucb/bin")
+; (string-split "/usr/local/bin" '(#\/)) ==> ("" "usr" "local" "bin")
+
+(define (string-split str . rest)
+		; maxsplit is a positive number
+  (define (split-by-whitespace str maxsplit)
+    (define (skip-ws i yet-to-split-count)
+      (cond
+        ((>= i (string-length str)) '())
+        ((char-whitespace? (string-ref str i))
+          (skip-ws (++ i) yet-to-split-count))
+        (else (scan-beg-word (++ i) i yet-to-split-count))))
+    (define (scan-beg-word i from yet-to-split-count)
+      (cond
+        ((zero? yet-to-split-count)
+          (cons (substring str from (string-length str)) '()))
+        (else (scan-word i from yet-to-split-count))))
+    (define (scan-word i from yet-to-split-count)
+      (cond
+        ((>= i (string-length str))
+          (cons (substring str from i) '()))
+        ((char-whitespace? (string-ref str i))
+          (cons (substring str from i) 
+            (skip-ws (++ i) (-- yet-to-split-count))))
+        (else (scan-word (++ i) from yet-to-split-count))))
+    (skip-ws 0 (-- maxsplit)))
+
+		; maxsplit is a positive number
+		; str is not empty
+  (define (split-by-charset str delimeters maxsplit)
+    (define (scan-beg-word from yet-to-split-count)
+      (cond
+        ((>= from (string-length str)) '(""))
+        ((zero? yet-to-split-count)
+          (cons (substring str from (string-length str)) '()))
+        (else (scan-word from from yet-to-split-count))))
+    (define (scan-word i from yet-to-split-count)
+      (cond
+        ((>= i (string-length str))
+          (cons (substring str from i) '()))
+        ((memq (string-ref str i) delimeters)
+          (cons (substring str from i) 
+            (scan-beg-word (++ i) (-- yet-to-split-count))))
+        (else (scan-word (++ i) from yet-to-split-count))))
+    (scan-beg-word 0 (-- maxsplit)))
+
+			; resolver of overloading...
+			; if omitted, maxsplit defaults to
+			; (++ (string-length str))
+  (if (string-null? str) '()
+    (if (null? rest) 
+      (split-by-whitespace str (++ (string-length str)))
+      (let ((charset (car rest))
+          (maxsplit
+            (if (pair? (cdr rest)) (cadr rest) (++ (string-length str)))))
+        (cond 
+          ((not (positive? maxsplit)) '())
+          ((null? charset) (split-by-whitespace str maxsplit))
+          (else (split-by-charset str charset maxsplit))))))
+)
+
diff --git a/bindings/swig/nxdataset.i b/bindings/swig/nxdataset.i
new file mode 100644
index 0000000..2460a82
--- /dev/null
+++ b/bindings/swig/nxdataset.i
@@ -0,0 +1,114 @@
+/*
+  This is a SWIG interface description for the nxdataset functions and
+  some helper code.
+ 
+  copyright: GPL
+
+  Mark Koennecke, October 2002
+*/
+%module nxdataset
+%{
+#include "nxdataset.h"
+
+#define MAXDIM 7
+
+void *create_nxds(int rank, int type, int dim0, int dim1, int dim2, 
+	int dim3, int dim4, int dim5,int dim6){
+	int dim[MAXDIM],i;
+
+	dim[0] = dim0;
+	dim[1] = dim1;
+	dim[2] = dim2;
+	dim[3] = dim3;
+	dim[4] = dim4;
+	dim[5] = dim5;
+	dim[6] = dim6;
+
+	return createNXDataset(rank,type,dim);
+}
+void *create_text_nxds(char *name){
+	return (void *)createTextNXDataset(name);
+}
+
+void drop_nxds(void *ptr){
+	dropNXDataset( (pNXDS) ptr);
+}
+
+int get_nxds_rank(void *ptr){
+	return getNXDatasetRank((pNXDS) ptr);
+}
+
+int get_nxds_type(void *ptr){
+	return getNXDatasetType((pNXDS) ptr);
+}
+
+int get_nxds_dim(void *ptr, int which){
+	return getNXDatasetDim((pNXDS) ptr, which);
+}
+
+double get_nxds_value(void *ptr,int dim0, int dim1, int dim2, 
+	int dim3, int dim4, int dim5,int dim6){
+	int dim[MAXDIM];
+
+	dim[0] = dim0;
+	dim[1] = dim1;
+	dim[2] = dim2;
+	dim[3] = dim3;
+	dim[4] = dim4;
+	dim[5] = dim5;
+	dim[6] = dim6;
+
+	return getNXDatasetValue((pNXDS)ptr,dim);
+}
+
+char *get_nxds_text(void *ptr){
+	return getNXDatasetText((pNXDS) ptr);
+}
+
+int  put_nxds_value(void *ptr, double value, int dim0, int dim1, int dim2, 
+	int dim3, int dim4, int dim5,int dim6){
+	int dim[MAXDIM];
+
+	dim[0] = dim0;
+	dim[1] = dim1;
+	dim[2] = dim2;
+	dim[3] = dim3;
+	dim[4] = dim4;
+	dim[5] = dim5;
+	dim[6] = dim6;
+
+	return putNXDatasetValue((pNXDS)ptr,dim,value);
+}
+
+
+%}
+
+extern void *create_nxds(int rank, int type, int dim0=0,
+	                 int dim1=0,int dim2=0,int dim3=0,
+                         int dim4=0, int dim5=0, int dim6=0);
+extern void *create_text_nxds(char *name);
+
+extern void drop_nxds(void *ptr);
+
+
+extern int get_nxds_rank(void *ptr);
+
+extern  int get_nxds_type(void *ptr);
+
+extern int get_nxds_dim(void *ptr, int which);
+
+extern double get_nxds_value(void *ptr, int dim0=0,
+	                 int dim1=0,int dim2=0,int dim3=0,
+                         int dim4=0, int dim5=0, int dim6=0);
+
+extern char *get_nxds_text(void *ptr);
+
+extern int put_nxds_value(void *ptr, double value,int dim0=0,
+	                 int dim1=0,int dim2=0,int dim3=0,
+                         int dim4=0, int dim5=0, int dim6=0);
+
+
+
+
+
+
diff --git a/bindings/swig/nxdstest.tcl b/bindings/swig/nxdstest.tcl
new file mode 100644
index 0000000..1c9bbc8
--- /dev/null
+++ b/bindings/swig/nxdstest.tcl
@@ -0,0 +1,28 @@
+#-------------------------------------------------------------------------
+# NX_Dataset testing code for Tcl
+#
+# copyright: GPL
+#
+# Mark Koennecke, October 2002
+#-------------------------------------------------------------------------
+
+set ds [create_nxds 2 $NX_FLOAT32 3 3]
+
+put_nxds_value $ds 1 0 0
+put_nxds_value $ds 1 1 1
+put_nxds_value $ds 1 2 2
+
+puts stdout [format "rank = %d" [get_nxds_rank $ds]]
+puts stdout [format "type = %d" [get_nxds_type $ds]]
+puts stdout [format "dim1 = %d" [get_nxds_dim $ds 1]]
+
+for {set i 0} {$i < 3} {incr i} {
+    puts stdout " "
+    for {set j 0} {$j < 3} {incr j} {
+	puts -nonewline stdout [format " %f" [get_nxds_value $ds $i $j]]
+    }
+}
+puts stdout "     "
+puts stdout "Hmmmmmmmhhh......."
+
+ drop_nxds $ds
diff --git a/bindings/swig/nxexam.tcl b/bindings/swig/nxexam.tcl
new file mode 100644
index 0000000..3e08e68
--- /dev/null
+++ b/bindings/swig/nxexam.tcl
@@ -0,0 +1,39 @@
+#--------------------------------------------------------------------------
+proc printDataset {ds} {
+    for {set i 0} {$i < [get-nxds-dim ds 0]} {incr i} {
+	puts stdout " "
+	for {set j 0} {$j < [get-nxds-dim ds 1]} {incr j} {
+	    puts -nonewline stdout [format " %f" [get_nxds_value $ds $i $j]]
+	}
+    }
+    puts stdout "     "
+}
+#------------------------------------------------------------------------
+proc printAttributes {fd} {
+    set run 1
+    while {$run == 1} {
+	set entry [nx_getnextattr $fd / ]
+	if { [string length $entry] < 2 } {
+	    set run 0
+	    continue
+	} 
+	set list [split $entry /]
+	set atData [nx_getattr fd [lindex $list 0] \
+		[lindex $list 2] [lindex $list 1]]
+	puts stdout [format "%s = %s " [lindex $list 0] \
+		[get_nxds_text $atData]]
+	drop_nxds $atData
+    }
+}
+#----------------------------------------------------------------------
+set fd [nx_open "nxinter.hdf" $NXACC_READ]
+printAttributes $fd
+nx_opengroup $fd "fish" "NXentry"
+nx_opendata $fd "fish"
+set tata [nx_getdata $fd]
+printDataset $tata
+drop_nxds $tata
+nx_closedata $fd
+nx_closegroup $fd
+nx_close $fd
+
diff --git a/bindings/swig/nxinter.i b/bindings/swig/nxinter.i
new file mode 100644
index 0000000..685a114
--- /dev/null
+++ b/bindings/swig/nxinter.i
@@ -0,0 +1,95 @@
+/*
+   Interface file for SWIG and the NeXus-API.
+
+   copyright: GPL
+  
+   The criminal act of writing this code was initially commited by:
+	
+   Mark Koennecke in October 2002
+
+   Updated: April 2006, Mark Koennecke
+*/
+%module nxinter
+%{
+#include "nxinterhelper.h"
+
+%}
+%title "NeXus-API Interface Fucntions"
+
+/*-------------------------------- Constants ------------------------*/
+%section "Constants"
+
+/* Access Codes */
+#define NXACC_READ    1
+#define NXACC_RDWR    2
+#define NXACC_CREATE  3
+#define NXACC_CREATE4 4
+#define NXACC_CREATE5 5
+#define NXACC_CREATEXML 6
+
+/* data types */
+#define NX_FLOAT32   5
+#define NX_FLOAT64   6
+#define NX_INT8     20  
+#define NX_UINT8    21
+#define NX_BOOLEAN  21
+#define NX_INT16    22  
+#define NX_UINT16   23
+#define NX_INT32    24
+#define NX_UINT32   25
+#define NX_INT64    26
+#define NX_UINT64   27
+#define NX_CHAR      4
+/*--------------------------------------------------------------------*/
+%include "nxdataset.i"
+/*-------------------- error handling --------------------------------*/
+extern char *nx_getlasterror(void);
+/*------------------------ opening and closing --------------------------*/
+%section "Opening and Closing NeXus Files"
+extern void *nx_open(char *filename, int accessCode);
+extern void *nx_flush(void *handle);
+extern void  nx_close(void *handle);
+
+
+%section "Navigating Groups"
+extern int nx_makegroup(void *handle, char *name, char *nxclass);
+extern int nx_opengroup(void *handle, char *name, char *nxclass);
+extern int nx_openpath(void *handle, char *path);
+extern int nx_opengrouppath(void *handle, char *path);
+extern char *nx_getpath(void *handle);
+extern int nx_closegroup(void *handle);
+extern char *nx_getnextentry(void *handle, char separator);
+extern void *nx_getgroupID(void *handle);
+extern int nx_initgroupdir(void *handle);
+
+%section "Dataset Handling"
+extern int nx_makedata(void *handle, char *name, int rank, int type, 
+		        void *dimPtr);
+extern int nx_compmakedata(void *handle, char *name, int rank, int type, 
+		        void *dimPtr, void *bufPtr);
+extern int nx_opendata(void *handle, char *name);
+extern int nx_closedata(void *handle);
+extern int nx_putslab(void *handle, void *dataset, void *startDim);
+extern void *nx_getslab(void *handle, void *startdim, void *size);
+extern void *nx_getds(void *handle, char *name);
+extern int   nx_putds(void *handle, char *name, void *dataset);
+extern void *nx_getdata(void *handle);
+extern int   nx_putdata(void *handle,void *dataset);
+extern void *nx_getinfo(void *handle);
+extern void *nx_getdataID(void *handle);
+
+
+%section "Attributes"
+extern char *nx_getnextattr(void *handle, char separator);
+extern int   nx_putattr(void *handle, char *name, void *ds);
+extern void *nx_getattr(void *handle, char *name, int type, int length); 
+
+%section "Making Links"
+extern int nx_makelink(void *handle, void *link);
+extern int nx_makenamedlink(void *handle, char *name, void *link);
+extern int nx_opensourcegroup(void *handle);
+
+%section "External Linking"
+extern char *nx_inquirefile(void *handle);
+extern void *nx_isexternalgroup(void *handle, char *name, char* nxclass);
+extern int nx_linkexternal(void *handle, char *name, char *nxclass, char *nxurl);
diff --git a/bindings/swig/nxinter.tex b/bindings/swig/nxinter.tex
new file mode 100644
index 0000000..33bb354
--- /dev/null
+++ b/bindings/swig/nxinter.tex
@@ -0,0 +1,480 @@
+\documentclass[12pt,a4paper]{article}
+%%\usepackage[dvips]{graphics}
+%%\usepackage{epsf}
+\setlength{\textheight}{24cm}
+\setlength{\textwidth}{16cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\oddsidemargin}{0cm}
+\setlength{\evensidemargin}{0cm}
+\setlength{\hoffset}{0cm}
+\setlength{\marginparwidth}{0cm}
+
+\begin{document}
+
+\begin{center}
+{\large NeXus--SWIG Interface}\\
+Mark Koennecke\\
+Laboratory for Neutron Scattering\\
+Paul Scherrer Institute\\
+CH--5232 Villigen--PSI\\
+Switzerland\\
+Mark.Koennecke at psi.ch\\
+November 2002\\
+\end{center}
+
+
+\section{Introduction}
+This is a description of the SWIG interface to the NeXus--API. NeXus
+is a proposal for a common data format for synchrotron and neutron
+diffraction data. NeXus uses HDF, the Hierachical Data Format, from
+the National Center for Super Computing Applications (NCSA) as its
+physical file format. NeXus files are accessed through a NeXus--API
+which sits between application programs and the HDF--libraries and
+then the files themselves. For more information on NeXus see:\\
+\centerline{http://lns00.psi.ch/NeXus}
+
+SWIG is the Simplified Wrapper and Interface Generator. This is a
+software tool which creates the necessary wrapper code needed to access a
+given ANSI--C or C++ library  from a variety of scripting languages
+including: Tcl, Java, Perl, Phyton, scheme etc. For more information
+about SWIG see:\\
+\centerline{http://www.swig.org}
+
+This now is the description of the SWIG interface to the
+NeXus--API. This document is intended for users who are familiar with
+the NeXus--API. The meaning of the functions is the same as for the
+ANSI--C NeXus--API, only function signatures may have changed. Please
+refer to the NeXus--API documentation for further reference. 
+
+
+\section{General Remarks}
+When interfacing an API like NeXus to a scripting language
+a couple of issues have to be handled:
+\begin{description}
+\item[pointers] The NeXus--API uses pointers extensively. Fortunately
+SWIG provides a means for encapsulating pointers in a script language.
+\item[memory management] Most scripting language have some kind of
+automatic variable management or garbage collection. Interfaces
+generated with SWIG however still use the C memory management. This
+imples that if you call C--routines which allocate memory you should
+not forget to free the memory again after you are done. Otherwise you
+may end up with a system out of memory due to memory leakage. 
+\item[datasets] NeXus works on possibly large datasets which may have
+different number types. Support for handling large arrays misses in
+many scripting languages. Therefore this interface system provides its
+own implementation of datasets. 
+\item[return values] Some functions of the NeXus--API return more then
+one value through the call by reference mechanism. These functions had
+to be wrapped such that all necessary return values are passed back
+into the scripting language. 
+\end{description} 
+
+Necessarily the generated interface will look slightly different in
+each target scripting language. For instance the constant NXACC\_READ
+is referred to as:
+\begin{verbatim}
+$NXACC_READ
+\end{verbatim} in Tcl. In scheme this looks like: 
+\begin{verbatim}
+(nxacc-read)
+\end{verbatim}  
+Functions also follow the calling conventions of the target
+language. An example in Tcl and scheme:
+\begin{description}
+\item[Tcl] \verb+ set fd [nx_open ``nxinter.hdf'' $NXACC\_READ] +
+\item[mzScheme] (define fd (nx-open ``nxinter.hdf'' (nxacc-read)))
+\end{description}
+The actual mapping generated for a target scripting language by SWIG
+can be found by studying SWIG's documentation or through browsing the
+generated wrapper file for your interface. All examples in the
+reference below are given in Tcl syntax. 
+
+SWIG goes a long way to help in the creation of scripting language
+interfaces. The user still has to master the process of compiling and
+linking a scripting language extension and loading it into the target
+interpreter. Examples for this are provided in the SWIG package.  
+
+
+\section{The Dataset Interface}
+The dataset interface brings multidimensional datasets  to the
+scripting language. This is necessary because many scripting languages
+do not have a good support for multi dimensional arrays of numbers. 
+If a scripting language supports
+multidimensional  arrays, another extension could be written which
+transfers such data efficiently, either directly from the NeXus file
+or using the NeXus dataset as an intermediary. 
+Currently no such optimisations are provided.  
+
+There usually is a number type associated with a NeXus dataset. In
+order to save effort and for simplification the NeXus number types
+were used. The names are self explaining, if more information about
+the meaning of these types is required, please consult the NeXus
+documentation. The types provided are (in Tcl syntax):
+\begin{verbatim}  
+$NX_FLOAT32
+$NX_FLOAT64
+$NX_INT8  
+$NX_UINT8   
+$NX_INT16
+$NX_UINT16
+$NX_INT32
+$NX_UINT32
+$NX_CHAR
+\end{verbatim}
+
+For notational convenience a symbol {\bf nxdsPtr} is now
+introduced. This symbol stands for a pointer to a NeXus dataset
+wrapped according to the scripting languages conventions.  
+
+
+The dataset interface consists of the following functions. Tcl syntax
+is assumed for this description. 
+
+{\bf nxdsPtr create\_nxds rank type dim0 dim1 dim2 dim3 dim4 dim5 dim6}
+creates a NeXus dataset with the specified rank and type and the
+dimensions given as dim0 - dim6. If you do not need so many
+dimensions, leave the surplus ones out, this sytem will replace the
+values with zeros. The interface can be easily extended to support
+more then 7 dimensions if required.  
+
+{\bf nxdsPtr create\_text\_nxds textdata} convenience function which
+wraps textdata into a NeXus dataset.
+
+{\bf drop\_nxds nxdsPtr} use this function to dispose of datasets which
+are no longer needed.  Do this, otherwise memory leaks occur!
+
+
+{\bf get\_nxds\_rank nxdsPtr} returns the rank of the dataset.
+
+{\bf get\_nxds\_type nxdsPtr} returns the data type of the datset as an
+integer. 
+
+{\bf get\_nxds\_dim nxdsPtr which} returns the dimension of the dataset
+in dimension which. 
+
+{\bf get\_nxds\_value nxdsPtr  dim0 dim1 dim2 dim3 dim4 dim5 dim6}
+returns  the value of the dataset at the index specified by dim0 -
+dim6. Again, leave out unneccessary indexes. 
+
+{\bf get\_nxds\_text nxdsPtr} convenience function which returns the
+content of the dataset as a text string. his works only if the dataset
+has rank 1 and is of type NX\_CHAR, NX\_INT8 or NX\_UINT8. 
+
+{\bf put\_nxds\_value nxdsPtr val dim0 dim1 dim2 dim3 dim4 dim5 dim6}
+sets the value of the dataset at the cell denoted by dim0 -dim6 to the
+value val. Again, you may omit surplu indexes.
+
+	           
+\section{The NeXus--API Interface}
+
+\subsection{Notation}
+After opening them, NeXus files are referred to through a
+handle. This handle is denoted through the symbol {nxFil} in the next
+sections. 
+
+There is another symbol {\bf nxSuccess} which stands for an
+integer. This is 1 if the function returned with success and 0 in case
+of a failure. If a function returns a pointer, failure is indicated
+through the NULL pointer. The encoding of the NULL pointer varies
+between scripting languages. 
+
+
+\subsection{Error Handling}
+Most NeXus-API functions return 1 on success and 0 in case of an
+error. The exception are those functions which return a pointer. These
+return a NULL pointer in case of an error. In each case more
+information about the problem can be obtained by calling:
+{\bf nx\_getlasterror} This call returns a string describing the last
+NeXus error found. 
+
+\subsection{File Creation accessCode Constants}
+The meanings of the constants are as described in the NeXus--API
+documentation.
+\begin{verbatim}
+$NXACC_READ
+$NXACC_RDWR
+$NXACC_CREATE
+$NXACC_CREATE4
+$NXACC_CREATE5
+\end{verbatim}
+
+
+
+\subsection{Opening and Closing of Files} 
+{nxFil nx\_open filename accessCode} opens the NeXus file filename. The
+accessCodes must be one of the constants given above. Returns a new
+handle in the case of a success, NULL in case of failure.
+
+{\bf nxFil nx\_flush nxFil} flushes a NeXus file.
+
+{\bf nx\_close nxFil} closes a NeXus file, The handle nxFil is useless
+after this. his call is necessary, especially when writing files. 
+
+
+\subsection{Group Operations}
+{\bf nxSuccess nx\_makegroup nxFil name nxclass}
+
+{\bf nxSuccess nx\_opengroup nxFil name nxclass}
+
+{\bf nxSuccess nx\_closegroup nxFil}
+
+{\bf nxMulti nx\_getnextentry nxFil separatorChar} performs group
+directory searches. nxMulti is a string containing name and NeXus
+class of the group item separated by the character given as
+separatorChar. If the search ends, NULL is returned.  
+
+{\bf nxSuccess nx\_initgroupdir nxFil}
+ 
+{nxPtr nx\_getgroupID nxFil} returns a pointer to a structure needed
+for linking. 
+
+
+\subsection{Dataset Handling}
+
+{\bf nxSuccess nx\_makedata nxFil  name rank type dimDs}
+makes a new dataset. The dimensions are described through the NeXus
+dataset dimDs.
+ 
+{\bf nxSuccess nx\_compmakedata nxFil  name rank type dimDs bufds}
+as above, but for compressed datasets. The HDF--5 buffering size is
+specified through the NeXus dataset bufDs.
+
+{\bf nx\_opendata nxFil name}
+
+{\bf nx\_closedata nxFil}
+
+{\bf nx\_putslab nxFil nxdsPtr  startDs}  slabbed data writing. The
+data comes from the NeXus dataset nxdsPtr. The start point from the
+NeXus dataset startDS. The size of the dataset to write is the size of
+nxdsPtr.  
+
+{\bf nxdsPtr nx\_getslab nxFil startDs sizeDs} reads a slab. startDS
+and sizeDs are two NeXus datasets describing the slab to read. The
+data is returned as a NeXus dataset. Do not forget to drop this
+dataset once you are done with the data! 
+
+{\bf nxdsPtr nx\_getds nxFil} reads dataset name. This convenience
+function opens the dataset, allocates a NeXus dataset of appropriate
+type and size for you and closes the SDS again.
+
+{\bf nxSuccess nx\_putds nxFil  name nxdsPtr} writes the dataset
+nxdsPtr to the file as name at the current position in the
+hierarchy. Same convenience fatures as above.
+
+{\bf nxdsPtr nx\_getdata nxFil} normal NeXus getdata but returns a
+NeXus dataset.
+
+{\bf nxSuccess nx\_putdata nxFil nxdsPtr} normal NeXus putdata. Data is
+taken from the NeXus dataset nxdsPtr.
+
+{\bf nxdsPtr nx\_getinfo nxFil} returns the current datasets type, rank
+and dimensions in a one dimensional NeXus dataset.
+
+{\bf ptr nx\_getdataID nxFil} retrieves link pointer for linking.
+
+\subsection{Attributes}
+{\bf nxText nx\_getnextattr nxFil  separatorChar}reads the next entry
+of attribute directory. nxText then contains then name, length and
+type of the attribute formatted as a string and separated by the
+character separatorChar.
+
+{\bf nxSuccess nx\_putattr nxFil name nxdsPtr} writes an attribute name
+from the NeXus dataset nxdsPtr.
+
+{\bf nxdsPtr nx\_getattr nxFil name type length} reads an attribute
+into a dataset. The data type and the length of the attribute have to
+specified. 
+
+\subsection{Making Links}
+{bf nxSuccess nx\_makelink nxFil nxLink}  makes a link. nxLink is one
+of the pointers returned from the nx\_getgroupID or nx\_getdataID
+functions. 
+
+\section{Example}
+As an example for the usage of the API see the API test program
+documented below:
+\begin{verbatim}
+#-------------------------------------------------------------------------
+# Test program for the nxinter interface. Also example usage.
+#
+# copyright: GPL
+#
+# Mark Koennecke, October 2002
+#------------------------------------------------------------------------
+
+#load ./nxinter.so
+
+#------------- testing dataset interface
+set ds [create_nxds 2 $NX_FLOAT32 3 3]
+
+put_nxds_value $ds 1 0 0
+put_nxds_value $ds 1 1 1
+put_nxds_value $ds 1 2 2
+
+puts stdout "Testing dataset interface "
+puts stdout [format "rank = %d" [get_nxds_rank $ds]]
+puts stdout [format "type = %d" [get_nxds_type $ds]]
+puts stdout [format "dim1 = %d" [get_nxds_dim $ds 1]]
+
+proc printDS {ds} {
+for {set i 0} {$i < 3} {incr i} {
+    puts stdout " "
+    for {set j 0} {$j < 3} {incr j} {
+	puts -nonewline stdout [format " %f" [get_nxds_value $ds $i $j]]
+    }
+}
+puts stdout "     "
+}
+
+printDS $ds
+puts stdout "Hmmmmmmmhhh....... seems OK"
+
+#-------------- prepare a dimension dataset  
+set dimds [create_nxds 1 $NX_INT32 2]
+put_nxds_value $dimds 3 0
+put_nxds_value $dimds 3 1
+
+#--------- prepare slabbing slabber dimensions
+set start [create_nxds 1 $NX_INT32 2]
+put_nxds_value $start 0 0
+put_nxds_value $start 0 1
+
+
+#----------------------------------- write tests
+puts stdout "Testing writing ..........."
+
+set fd [nx_open "nxinter.hdf" $NXACC_CREATE5]
+puts stdout [format "Opening file worked: %s" $fd]
+
+#---------- write an attribute.....
+set tds [create_text_nxds "Rosa Waschmaschinen sind hip"]
+puts stdout [format "Writing SuperDuper = %s" [get_nxds_text $tds]]
+puts stdout [format "Writing attribute results in: %d " \
+	[nx_putattr $fd "SuperDuper" $tds]]
+drop_nxds $tds
+
+#----------- making groups....
+set status [nx_makegroup $fd fish NXentry]
+if {$status == 1} {
+    puts stdout "Creating vGroup worked"
+}
+
+set status [nx_opengroup $fd fish NXentry]
+if {$status == 1} {
+    puts stdout "Opening vGroup worked"
+}
+
+set lnk [nx_getgroupID $fd]
+puts stdout [format "groupID determined to: %s" $lnk]
+
+#------------ writing tata
+puts stdout "Test Writing data....."
+puts stdout [nx_makedata $fd "fish" 2 $NX_FLOAT32 $dimds]
+puts stdout [nx_opendata $fd "fish"]
+puts stdout [nx_putdata $fd $ds]
+set lnk [nx_getdataID $fd]
+puts stdout $lnk
+puts stdout [nx_closedata $fd]
+
+#--------------- testing slabbed tata writing
+puts stdout "Testing  writing in slabs"
+put_nxds_value $dimds 6 0
+puts stdout [format "Dimensions for slab test: %f, %f"  \
+	[get_nxds_value $dimds 0] [get_nxds_value $dimds 1]]
+ 
+puts stdout [nx_makedata $fd "fish2" 2 $NX_FLOAT32 $dimds]
+puts stdout [nx_opendata $fd "fish2"]
+puts stdout [nx_putslab  $fd $ds $start]
+put_nxds_value $start 3 0
+puts stdout [nx_putslab  $fd $ds $start]
+puts stdout [nx_closedata $fd]
+puts stdout "Finished Writing Slabs........."
+
+puts stdout [format "Linking = %d" [nx_makelink $fd $lnk]]
+
+set status [nx_closegroup $fd]
+if {$status == 1} {
+    puts stdout "Closing vGroup worked"
+}
+
+
+nx_close $fd
+puts stdout "Closed file"
+#---------------- finished writing tests
+
+
+#---------------- trying to read
+puts stdout "Testing Reading files"
+
+set fd [nx_open "nxinter.hdf" $NXACC_READ]
+puts stdout "Opening file for reading worked"
+
+set run 1
+
+#----------------- printing group content
+puts stdout "Group directory listing"
+while {$run == 1} {
+    set entry [nx_getnextentry $fd / ]
+    if { [string length $entry] < 2 } {
+	set run 0
+    } else {
+	puts stdout $entry
+    }
+}
+#--------- printing attributes
+puts stdout "Attributes"
+set run 1
+while {$run == 1} {
+    set entry [nx_getnextattr $fd / ]
+    puts stdout $entry
+    if { [string length $entry] < 2 } {
+	set run 0
+    } 
+}
+
+set rds [nx_getattr $fd "SuperDuper" $NX_CHAR 30]
+puts stdout $rds
+if {[string compare $rds NULL] != 0} {
+    puts stdout [format "SuperDuper = %s" [get_nxds_text $rds]]
+}
+drop_nxds $rds
+
+#---------------- reading tata
+puts stdout [nx_opengroup $fd fish NXentry]
+puts stdout [nx_opendata $fd "fish"]
+set rds [nx_getdata $fd]
+puts stdout $rds
+
+puts stdout "Read data should be a 3x3 unity matrix"
+printDS $rds
+
+puts stdout [nx_closedata $fd]
+
+#----------- reading slabbed data
+puts stdout "Testing slabbed reading......"
+puts stdout [nx_opendata $fd "fish2"]
+set ids [nx_getinfo $fd]
+puts stdout [format "fish2: type %f, rank %f, d1 %f, d2 %f" \
+	[get_nxds_value $ids 0] [get_nxds_value $ids 1] \
+	[get_nxds_value $ids 2] [get_nxds_value $ids 3]]
+drop_nxds $ids
+
+put_nxds_value $dimds 3 0
+set r1 [nx_getslab $fd $start $dimds]
+printDS $r1
+put_nxds_value $start 0 0
+set r2 [nx_getslab $fd $start $dimds]
+printDS $r2
+puts stdout [nx_closedata $fd]
+
+puts stdout [nx_closegroup $fd]
+puts stdout [nx_close $fd]
+
+#--------------- dropping datasets: do not forget!!!
+drop_nxds $ds
+drop_nxds $rds
+drop_nxds $dimds
+\end{verbatim}
+\end{document}
diff --git a/bindings/swig/nxinterhelper.c b/bindings/swig/nxinterhelper.c
new file mode 100644
index 0000000..0fb0aef
--- /dev/null
+++ b/bindings/swig/nxinterhelper.c
@@ -0,0 +1,635 @@
+/*
+  This is a library of support functions and data structures which can be
+  used in order to create interfaces between the NeXus-API and scripting
+  languages or data analysis systems with a native code interface. 
+
+  copyright: GPL
+
+  Mark Koennecke, October 2002
+  Mark Koennecke, November 2002
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "nxinterhelper.h"
+#include "nxdataset.h"
+/*-----------------------------------------------------------------
+  An own error handler. nx_getlasterror will return the test of
+  the last NeXus error.
+  --------------------------------------------------------------------*/
+static char errorText[256]= "";
+
+static void nxinterError(void *pData, char *error){
+  strncpy(errorText,error,255);
+}
+/*-----------------------------------------------------------------------*/
+char *nx_getlasterror(void){
+  return strdup(errorText);
+}
+/*-------------------- opening and closing -------------------------------*/
+void *nx_open(char *filename, int accessMethod){
+  NXhandle handle = NULL;
+  int status;
+
+  NXMSetError(NULL,nxinterError);
+  status = NXopen(filename,(NXaccess)accessMethod, &handle);
+  if(status == NX_OK){
+    return handle;
+  }else{
+    return NULL;
+  }
+}
+/*------------------------------------------------------------------------*/
+void *nx_flush(void *hundle){
+  NXhandle handle;
+  int status;
+
+  handle = (NXhandle)hundle;
+  status = NXflush(&handle);
+  if(status == NX_OK){
+    return handle;
+  } else {
+    return NULL;
+  }
+}
+/*-----------------------------------------------------------------------*/
+void nx_close(void *hundle){
+  NXhandle handle;
+
+  handle = (NXhandle)hundle;
+  NXclose(&handle);
+}
+/*=================== group handling functions ========================*/
+int nx_makegroup(void *handle, char *name, char *nxclass){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXmakegroup(hfil,name, nxclass);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*---------------------------------------------------------------------*/
+int nx_opengroup(void *handle, char *name, char *nxclass){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXopengroup(hfil,name, nxclass);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*---------------------------------------------------------------------*/
+int nx_openpath(void *handle, char *path){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXopenpath(hfil,path);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*---------------------------------------------------------------------*/
+int nx_opengrouppath(void *handle, char *path){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXopengrouppath(hfil,path);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*--------------------------------------------------------------------*/
+char *nx_getpath(void *handle){
+  int status;
+  NXhandle hfil;
+  char path[1024];
+
+  hfil = (NXhandle)handle;
+  status = NXgetpath(hfil,path,1024);
+  if(status == NX_OK){
+    return strdup(path);
+  } else {
+    return strdup("Error in NXgetpath");
+  }
+}
+/*--------------------------------------------------------------------*/
+int nx_closegroup(void *handle){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXclosegroup(hfil);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*-------------------------------------------------------------------*/
+char *nx_getnextentry(void *handle, char separator){
+  int status, length, type;
+  NXhandle hfil;
+  char *resultBuffer = NULL;
+  NXname group,nxclass;
+
+  hfil = (NXhandle)handle;
+  status = NXgetnextentry(hfil,group, nxclass,&type);
+  if(status == NX_OK){
+    length = 30 + strlen(group) + strlen(nxclass);
+    /*
+      This introduces a memory leak. I had hoped, that swig would
+      kill it for me after use, but I'am afraid, this is not the
+      case. Unfortately I do not know how to fix the issue.
+    */
+    resultBuffer = (char *)malloc(length*sizeof(char));
+    if(resultBuffer == NULL){
+      return NULL;
+    }
+    sprintf(resultBuffer,"%s%c%s%c%d",group,separator,nxclass,
+	    separator,type);
+    return resultBuffer;
+  } else {
+    return NULL;
+  }
+}
+/*-------------------------------------------------------------------*/
+void *nx_getgroupID(void *handle){
+  int status;
+  NXhandle hfil;
+  NXlink *linki;
+
+  linki = (NXlink *)malloc(sizeof(NXlink));
+  if(linki == NULL){
+    return NULL;
+  }
+  hfil = (NXhandle)handle;
+  status = NXgetgroupID(hfil,linki);
+  if(status == NX_OK){
+    return linki;
+  } else {
+    return NULL;
+  }
+}
+/*------------------------------------------------------------------*/
+int  nx_initgroupdir(void *handle){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXinitgroupdir(hfil);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*========================== dataset handling =======================*/
+int nx_makedata(void *ptr, char *name, int rank, int type, 
+		    void *dimPtr){
+  int status;
+  NXhandle hfil;
+  pNXDS dimData;
+
+  hfil = (NXhandle)ptr;
+  dimData = (pNXDS)dimPtr;
+  if(dimData->type != NX_INT32){
+    NXReportError("ERROR: dimension data not integer");
+    return 0;
+  }
+  status = NXmakedata(hfil, name, type, rank, 
+		      dimData->u.iPtr);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*--------------------------------------------------------------------*/
+int nx_compmakedata(void *ptr, char *name, int rank, int type, 
+		    void *dimPtr, void *bufPtr){
+  int status;
+  NXhandle hfil;
+  pNXDS dimData, bufData;
+
+  hfil = (NXhandle)ptr;
+  dimData = (pNXDS)dimPtr;
+  if(dimData->type != NX_INT32){
+    NXReportError("ERROR: dimension data not integer");
+    return 0;
+  }
+  bufData = (pNXDS)bufPtr;
+  status = NXcompmakedata(hfil, name, type, rank, 
+			  dimData->u.iPtr, NX_COMP_LZW,bufData->u.iPtr);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*----------------------------------------------------------------------*/
+int nx_opendata(void *handle, char *name){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXopendata(hfil,name);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*----------------------------------------------------------------------*/
+int nx_closedata(void *handle){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXclosedata(hfil);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*------------------------------------------------------------------------*/
+int nx_putslab(void *handle, void *dataset, void *startDim){
+  int status;
+  NXhandle hfil;
+  pNXDS data;
+  pNXDS start;
+  int  end[NX_MAXRANK], i;
+
+  hfil = (NXhandle)handle;
+  data = (pNXDS)dataset;
+  start = (pNXDS)startDim;
+  for(i = 0; i < data->rank;i++){
+    end[i] = data->dim[i];
+  }
+
+  status = NXputslab(hfil,data->u.ptr,start->u.iPtr,end);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*-----------------------------------------------------------------------*/
+void *nx_getslab(void *handle, void *startdim, void *sizedim){
+  pNXDS resultdata;
+  pNXDS start, size;
+  int status, rank, type, dim[NX_MAXRANK];
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  start = (pNXDS)startdim;
+  size =   (pNXDS)sizedim;
+
+  /*
+    get info first, then allocate data
+  */
+  status = NXgetinfo(hfil, &rank,dim,&type);
+  if(status != NX_OK){
+    return NULL;
+  }
+  
+  resultdata = createNXDataset(rank,type,size->u.iPtr);
+  if(resultdata == NULL){
+    return NULL;
+  }
+
+  status = NXgetslab(hfil,resultdata->u.ptr,start->u.iPtr,
+		     size->u.iPtr);
+  if(status == NX_OK){
+    return resultdata;
+  }else{
+    dropNXDataset(resultdata);
+    return NULL;
+  }
+}
+/*------------------------------------------------------------------------*/
+void *nx_getds(void *handle, char *name){
+  pNXDS result = NULL;
+  int rank, type,dim[NX_MAXRANK],status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXopendata(hfil,name);
+  if(status != NX_OK){
+    return NULL;
+  }
+
+  status = NXgetinfo(hfil,&rank,dim,&type);
+  if(status != NX_OK){
+    return NULL;
+  }
+
+  result = createNXDataset(rank,type,dim);
+  if(result == NULL){
+    NXclosedata(hfil);
+    return NULL;
+  }
+
+  status = NXgetdata(hfil,result->u.ptr);
+  if(result == NULL){
+    NXclosedata(hfil);
+    dropNXDataset(result);
+    return NULL;
+  }
+  NXclosedata(hfil);
+  return result;
+}
+/*----------------------------------------------------------------------*/
+int   nx_putds(void *handle, char *name, void *dataset){
+  NXhandle hfil;
+  int status;
+  pNXDS data;
+
+  hfil = (NXhandle)handle;
+  data = (pNXDS)dataset;
+
+  status = NXopendata(hfil,name);
+  if(status != NX_OK){
+    status = NXmakedata(hfil,name,data->type,data->rank,data->dim);
+    if(status != NX_OK){
+      return 0;
+    }
+    NXopendata(hfil,name);
+  }
+
+  status = NXputdata(hfil,data->u.ptr);
+  NXclosedata(hfil);
+  if(status != NX_OK){
+    return 0;
+  }else{
+    return 1;
+  }
+}
+/*------------------------------------------------------------------------*/
+void *nx_getdata(void *handle){
+  pNXDS result = NULL;
+  int rank, type,dim[NX_MAXRANK],status;
+  NXhandle hfil;
+
+
+  hfil = (NXhandle)handle;
+  status = NXgetinfo(hfil,&rank,dim,&type);
+  if(status != NX_OK){
+    return NULL;
+  }
+
+  result = createNXDataset(rank,type,dim);
+  if(result == NULL){
+    NXclosedata(hfil);
+    return NULL;
+  }
+
+  status = NXgetdata(hfil,result->u.ptr);
+  if(result == NULL){
+    dropNXDataset(result);
+    return NULL;
+  }
+  return result;
+}
+/*----------------------------------------------------------------------*/
+int   nx_putdata(void *handle, void *dataset){
+  NXhandle hfil;
+  int status;
+  pNXDS data;
+
+  hfil = (NXhandle)handle;
+  data = (pNXDS)dataset;
+
+  if(data == NULL){
+    NXReportError("ERROR: NULL data pointer in nx_putdata");
+    return 0;
+  }
+
+  status = NXputdata(hfil,data->u.ptr);
+  if(status != NX_OK){
+    return 0;
+  }else{
+    return 1;
+  }
+}
+/*----------------------------------------------------------------------*/
+void *nx_getinfo(void *handle){
+  NXhandle hfil;
+  int status, type, rank, dim[NX_MAXRANK], rdim[1], i;
+  pNXDS data = NULL;
+
+  hfil = (NXhandle)handle;
+
+  status = NXgetinfo(handle,&rank,dim,&type);
+  if(status != NX_OK){
+    return NULL;
+  }
+  rdim[0] = 2 + rank;
+  data = createNXDataset(1,NX_INT32,rdim);
+  data->u.iPtr[0] = type;
+  data->u.iPtr[1] = rank;
+  for(i = 0; i < rank; i++){
+    data->u.iPtr[2+i] = dim[i];
+  }
+  return data;
+}
+/*----------------------------------------------------------------------*/
+void *nx_getdataID(void *handle){
+  NXhandle hfil;
+  int status;
+  NXlink *linki;
+
+  linki = (NXlink *)malloc(sizeof(NXlink));
+  if(linki == NULL){
+    return NULL;
+  }
+
+  hfil = (NXhandle)handle;
+  status = NXgetdataID(hfil,linki);
+  if(status == NX_OK){
+    return linki;
+  } else {
+    free(linki);
+    return NULL;
+  }
+}
+/*-------------------------------------------------------------------*/
+char *nx_getnextattr(void *handle, char separator){
+  int status, length, type;
+  char *result;
+  NXhandle hfil;
+  NXname aName;
+
+  hfil = (NXhandle)handle;
+  status = NXgetnextattr(hfil,aName, &length, &type);
+  if(status == NX_OK){
+    /*
+      This introduces a memory leak. I had hoped, that swig would
+      kill it for me after use, but I'am afraid, this is not the
+      case. Unfortately I do not know how to fix the issue.
+    */
+    result = (char *)malloc((20+strlen(aName))*sizeof(char));
+    if(result == NULL){
+      return NULL;
+    }
+    memset(result,0,(20+strlen(aName))*sizeof(char));
+    sprintf(result,"%s%c%d%c%d", aName,separator,
+	    length,separator,type);
+    return result;
+  } else {
+    return NULL;
+  }
+}
+/*-------------------------------------------------------------------*/
+int   nx_putattr(void *handle, char *name, void *ds){
+  int status;
+  NXhandle hfil;
+  pNXDS data;
+
+  hfil = (NXhandle)handle;
+  data = (pNXDS)ds;
+  status = NXputattr(hfil,name,data->u.ptr,data->dim[0],data->type);
+  if(status == NX_OK){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+/*-------------------------------------------------------------------*/
+void *nx_getattr(void *handle, char *name, int type, int length){
+  NXhandle hfil;
+  int status, tp, ll, dim[1];
+  pNXDS data = NULL;
+
+
+  hfil = (NXhandle)handle;
+
+  /*
+    prepare dataset
+  */
+  dim[0] = length+1;
+  data = createNXDataset(1,type,dim);
+  if(data == NULL){
+    return NULL;
+  }
+  
+  /*
+    finally read the real data
+  */
+  ll = length;
+  tp = type;
+  status = NXgetattr(hfil,name,data->u.ptr,&ll,&tp);
+  if(status != NX_OK){
+    dropNXDataset(data);
+    return NULL;
+  }
+
+  return data;
+}
+/*-----------------------------------------------------------------------*/
+int nx_makelink(void *handle, void *link){
+  NXhandle hfil;
+  NXlink* lk;
+  int status;
+
+  hfil = (NXhandle)handle;
+  lk = (NXlink *)link;
+
+  status = NXmakelink(hfil,lk);
+  if(status == NX_OK){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+/*-----------------------------------------------------------------------*/
+int nx_makenamedlink(void *handle, char *name, void *link){
+  NXhandle hfil;
+  NXlink* lk;
+  int status;
+
+  hfil = (NXhandle)handle;
+  lk = (NXlink *)link;
+
+  status = NXmakenamedlink(hfil,name,lk);
+  if(status == NX_OK){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+/*-----------------------------------------------------------------------*/
+int nx_opensourcegroup(void *handle){
+  NXhandle hfil;
+  int status;
+
+  hfil = (NXhandle)handle;
+
+  status = NXopensourcegroup(hfil);
+  if(status == NX_OK){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+/*-----------------------------------------------------------------------*/
+char *nx_inquirefile(void *handle){
+  int status;
+  NXhandle hfil;
+  char *pPtr = NULL;
+
+  hfil = (NXhandle)handle;
+  pPtr = malloc(1024*sizeof(char));
+  status = NXinquirefile(hfil,pPtr, 1024);
+  if(status == NX_OK){
+    return pPtr;
+  } else {
+    return NULL;
+  }
+}
+/*-----------------------------------------------------------------------*/
+void *nx_isexternalgroup(void *handle, char *name, char *nxclass){
+  int status, length = 1024;
+  NXhandle hfil;
+  char url[1024];
+
+  hfil = (NXhandle)handle;
+  status = NXisexternalgroup(hfil,name, nxclass,url,length);
+  if(status == NX_OK){
+    createTextNXDataset(url);
+  } else {
+    return NULL;
+  }
+  return NULL;/*NOTREACHED*/
+}
+/*-----------------------------------------------------------------------*/
+int nx_linkexternal(void *handle, char *name, char *nxclass, 
+		       char *url){
+  int status;
+  NXhandle hfil;
+
+  hfil = (NXhandle)handle;
+  status = NXlinkexternal(hfil,name, nxclass,url);
+  if(status == NX_OK){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+
+
diff --git a/bindings/swig/nxinterhelper.h b/bindings/swig/nxinterhelper.h
new file mode 100644
index 0000000..2ac4485
--- /dev/null
+++ b/bindings/swig/nxinterhelper.h
@@ -0,0 +1,74 @@
+/*
+  This is a library of support functions and data structures which can be
+  used in order to create interfaces between the NeXus-API and scripting
+  languages or data analysis systems with a native code interface. 
+
+  copyright: GPL
+
+  Mark Koennecke, October 2002
+*/
+
+#ifndef NXINTERHELPER
+#define NXINTERHELPER
+
+#include <napi.h>
+
+/*------------- opening and closing section ---------------------*/
+void *nx_open(char *filename, int accessMethod);
+void *nx_flush(void *handle);
+void  nx_close(void *handle);
+/*--------------- group handling section ------------------------*/
+int nx_makegroup(void *handle, char *name, char *nxclass);
+int nx_opengroup(void *handle, char *name, char *nxclass);
+int nx_opengrouppath(void *handle, char *path);
+int nx_openpath(void *handle, char *path);
+extern char *nx_getpath(void *handle);
+int nx_closegroup(void *handle);
+char *nx_getnextentry(void *handle, char separator);
+void *nx_getgroupID(void *handle);
+int nx_initgroupdir(void *handle);
+
+/*---------------- dataset handling -----------------------------*/
+int nx_makedata(void *ptr, char *name, int rank, int type, void *dimPtr);
+int nx_compmakedata(void *ptr, char *name, int rank, int type, 
+		    void *dimPtr, void *bufPtr);
+
+int nx_opendata(void *handle, char *name);
+int nx_closedata(void *handle);
+
+int nx_putslab(void *handle, void *dataset, void *startDim);
+void *nx_getslab(void *handle, void *startdim, void *size);
+
+void *nx_getds(void *handle, char *name);
+int   nx_putds(void *handle, char *name, void *dataset);
+
+void *nx_getdata(void *handle);
+int   nx_putdata(void *handle,void *dataset);
+
+void *nx_getinfo(void *handle);
+void *nx_getdataID(void *handle);
+
+/*-------------------- attributes --------------------------------*/
+char *nx_getnextattr(void *handle, char separator);
+int   nx_putattr(void *handle, char *name, void *ds);
+void *nx_getattr(void *handle, char *name, int type, int length); 
+
+
+/*---------------------- link -----------------------------------*/
+int nx_makelink(void *handle, void *link);
+int nx_makenamedlink(void *handle, char *name, void *link);
+int nx_opensourcgroup(void *handle);
+void *nx_isexternalgroup(void *handle, char *name, char *nxclass);
+int nx_linkexternal(void *handle, char *name, char *nxclass, char *url);
+char *nx_inquirefile(void *handle);
+int nx_opensourcegroup(void *handle);
+/*----------------- error handling -----------------------------*/
+char *nx_getlasterror(void);
+
+#endif
+
+
+
+
+
+
diff --git a/bindings/swig/nxintertest.tcl b/bindings/swig/nxintertest.tcl
new file mode 100644
index 0000000..4442fef
--- /dev/null
+++ b/bindings/swig/nxintertest.tcl
@@ -0,0 +1,191 @@
+#-------------------------------------------------------------------------
+# Test program for the nxinter interface. Also example usage.
+#
+# copyright: GPL
+#
+# Mark Koennecke, October 2002
+#------------------------------------------------------------------------
+
+#load ./nxinter.so
+
+#------------- testing dataset interface
+set ds [create_nxds 2 $NX_FLOAT32 3 3]
+
+put_nxds_value $ds 1 0 0
+put_nxds_value $ds 1 1 1
+put_nxds_value $ds 1 2 2
+
+puts stdout "Testing dataset interface "
+puts stdout [format "rank = %d" [get_nxds_rank $ds]]
+puts stdout [format "type = %d" [get_nxds_type $ds]]
+puts stdout [format "dim1 = %d" [get_nxds_dim $ds 1]]
+
+proc printDS {ds} {
+for {set i 0} {$i < 3} {incr i} {
+    puts stdout " "
+    for {set j 0} {$j < 3} {incr j} {
+	puts -nonewline stdout [format " %f" [get_nxds_value $ds $i $j]]
+    }
+}
+puts stdout "     "
+}
+
+printDS $ds
+puts stdout "Hmmmmmmmhhh....... seems OK"
+
+#-------------- prepare a dimension dataset  
+set dimds [create_nxds 1 $NX_INT32 2]
+put_nxds_value $dimds 3 0
+put_nxds_value $dimds 3 1
+
+#--------- prepare slabbing slabber dimensions
+set start [create_nxds 1 $NX_INT32 2]
+put_nxds_value $start 0 0
+put_nxds_value $start 0 1
+
+
+#----------------------------------- write tests
+puts stdout "Testing writing ..........."
+
+set fd [nx_open "nxinter.hdf" $NXACC_CREATE5]
+puts stdout [format "Opening file worked: %s" $fd]
+
+#---------- write an attribute.....
+set tds [create_text_nxds "Rosa Waschmaschinen sind hip"]
+puts stdout [format "Writing SuperDuper = %s" [get_nxds_text $tds]]
+puts stdout [format "Writing attribute results in: %d " \
+	[nx_putattr $fd "SuperDuper" $tds]]
+drop_nxds $tds
+
+#----------- making groups....
+set status [nx_makegroup $fd fish NXentry]
+if {$status == 1} {
+    puts stdout "Creating vGroup worked"
+}
+
+set status [nx_opengroup $fd fish NXentry]
+if {$status == 1} {
+    puts stdout "Opening vGroup worked"
+}
+
+set lnk [nx_getgroupID $fd]
+puts stdout [format "groupID determined to: %s" $lnk]
+
+#------------ writing tata
+puts stdout "Test Writing data....."
+puts stdout [nx_makedata $fd "fish" 2 $NX_FLOAT32 $dimds]
+puts stdout [nx_opendata $fd "fish"]
+puts stdout [nx_putdata $fd $ds]
+set lnk [nx_getdataID $fd]
+puts stdout $lnk
+puts stdout [nx_closedata $fd]
+
+#--------------- testing slabbed tata writing
+puts stdout "Testing  writing in slabs"
+put_nxds_value $dimds 6 0
+puts stdout [format "Dimensions for slab test: %f, %f"  \
+	[get_nxds_value $dimds 0] [get_nxds_value $dimds 1]]
+ 
+puts stdout [nx_makedata $fd "fish2" 2 $NX_FLOAT32 $dimds]
+puts stdout [nx_opendata $fd "fish2"]
+puts stdout [nx_putslab  $fd $ds $start]
+put_nxds_value $start 3 0
+puts stdout [nx_putslab  $fd $ds $start]
+puts stdout [nx_closedata $fd]
+puts stdout "Finished Writing Slabs........."
+
+puts stdout [format "Linking = %d" [nx_makelink $fd $lnk]]
+
+set status [nx_closegroup $fd]
+if {$status == 1} {
+    puts stdout "Closing vGroup worked"
+}
+
+
+nx_close $fd
+puts stdout "Closed file"
+#---------------- finished writing tests
+
+
+#---------------- trying to read
+puts stdout "Testing Reading files"
+
+set fd [nx_open "nxinter.hdf" $NXACC_READ]
+puts stdout "Opening file for reading worked"
+
+set run 1
+
+#----------------- printing group content
+puts stdout "Group directory listing"
+while {$run == 1} {
+    set entry [nx_getnextentry $fd / ]
+    if { [string length $entry] < 2 } {
+	set run 0
+    } else {
+	puts stdout $entry
+    }
+}
+#--------- printing attributes
+puts stdout "Attributes"
+set run 1
+while {$run == 1} {
+    set entry [nx_getnextattr $fd / ]
+    puts stdout $entry
+    if { [string length $entry] < 2 } {
+	set run 0
+    } 
+}
+
+set rds [nx_getattr $fd "SuperDuper" $NX_CHAR 30]
+puts stdout $rds
+if {[string compare $rds NULL] != 0} {
+    puts stdout [format "SuperDuper = %s" [get_nxds_text $rds]]
+}
+drop_nxds $rds
+
+#---------------- reading tata
+puts stdout [nx_opengroup $fd fish NXentry]
+puts stdout [nx_opendata $fd "fish"]
+set rds [nx_getdata $fd]
+puts stdout $rds
+
+puts stdout "Read data should be a 3x3 unity matrix"
+printDS $rds
+
+puts stdout [nx_closedata $fd]
+
+#----------- reading slabbed data
+puts stdout "Testing slabbed reading......"
+puts stdout [nx_opendata $fd "fish2"]
+set ids [nx_getinfo $fd]
+puts stdout [format "fish2: type %f, rank %f, d1 %f, d2 %f" \
+	[get_nxds_value $ids 0] [get_nxds_value $ids 1] \
+	[get_nxds_value $ids 2] [get_nxds_value $ids 3]]
+drop_nxds $ids
+
+put_nxds_value $dimds 3 0
+set r1 [nx_getslab $fd $start $dimds]
+printDS $r1
+put_nxds_value $start 0 0
+set r2 [nx_getslab $fd $start $dimds]
+printDS $r2
+puts stdout [nx_closedata $fd]
+
+puts stdout [nx_closegroup $fd]
+puts stdout [nx_close $fd]
+
+#--------------- dropping datasets: do not forget!!!
+drop_nxds $ds
+drop_nxds $rds
+drop_nxds $dimds
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bindings/swig/nxtest.scm b/bindings/swig/nxtest.scm
new file mode 100644
index 0000000..04cd434
--- /dev/null
+++ b/bindings/swig/nxtest.scm
@@ -0,0 +1,56 @@
+;--------------------------------------------------------------------------
+; scheme reading of a NeXus file
+;
+; this version for mzscheme
+;
+; Mark Koennecke, October 2002
+;--------------------------------------------------------------------------
+
+(load-extension "nxscheme.so")
+(load "asciidblib.scm") ; for string-split
+
+;------------------- print attributes -------------------------------------
+(define (print-attrib fd)
+  (let ( (att (nx-getnextattr fd #\@)) )
+    (if (< 2 (string-length att))
+	(let ( (splitlist (string-split att (list #\@))) )
+	  (display (list-ref splitlist 0))
+	  (display "=")
+	  (display (get-nxds-text (nx-getattr fd (list-ref splitlist 0)
+			       (string->number (list-ref splitlist 2))
+			       (string->number (list-ref splitlist 1)))))
+	  (newline)
+	  (print-attrib fd) ) ) ) )
+;----------------------- print a 2d dataset---------------------------
+(define (print2d dataset)
+  (letrec ( (ydim (get-nxds-dim dataset 1))
+	 (printRow (lambda (dataset yval xdim count)
+	     (if (>= count xdim)
+		 (newline)
+		 (begin
+		   (display (get-nxds-value dataset count yval))
+		   (display "  ")
+		   (printRow dataset yval xdim (+ count 1))
+                 )) ))
+	 (printWhole (lambda (dataset ydim count)
+	       (let ( (xdim (get-nxds-dim dataset 0)) )
+		 (if (>= count ydim)
+		     (newline)
+		     (begin
+		       (printRow dataset count xdim 0)
+		       (printWhole dataset ydim (+ count 1)) ) ) ) )) )
+    (printWhole dataset ydim 0) ) )
+;======================================================================
+(define fd (nx-open "nxinter.hdf" (nxacc-read)))
+(print-attrib fd)
+
+(nx-opengroup fd "fish" "NXentry")
+(nx-opendata fd "fish")
+(let
+    ( (ds (nx-getdata fd)) )
+  (print2d ds)
+  (drop-nxds ds) )
+(nx-closedata fd)
+(nx-closegroup fd)
+(nx-close fd)
+
diff --git a/build_rpm.in b/build_rpm.in
new file mode 100755
index 0000000..8af5ce9
--- /dev/null
+++ b/build_rpm.in
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# $Id$
+#
+# Script to build RPMs from current nexus*.tar.gz file
+# Copyright (C) 2004 Freddie Akeroyd
+#
+# $1 is set to any options you want to pass to ./configure
+#
+# get topdir - must find a better way ...
+topdir=`rpm --showrc|grep  " _topdir"| awk '{print $3}' | tail -1`
+if test ! -e "$topdir"; then
+    echo "Unable to determine RPM topdir from rpmrc; assuming $HOME/rpmbuild"
+    topdir="$HOME/rpmbuild"
+fi
+if test ! -w "$topdir"; then
+    echo "ERROR: RPM build directory not writable - check README.rpm"
+    exit
+fi
+#
+nxtop=`pwd`
+rm -fr $nxtop/installroot
+mkdir $nxtop/installroot
+# 
+make dist
+ln -sf $nxtop/@PACKAGE_TARNAME at -@PACKAGE_VERSION at .tar.gz $topdir/SOURCES
+cp $nxtop/nexus.spec $topdir/SPECS
+#
+if test -z "$1"; then
+    build_args='@CONFIGURE_ARGS@'
+else
+    build_args="$1"
+fi
+if ! test -z "$2"; then
+    RESULTS=/tmp/nexus-mock-results
+    mkdir -p $RESULTS
+    mock_args="-r $2 --resultdir=$RESULTS"
+    rm -f $RESULTS/*.src.rpm # clean up so do not pick up wrong .src.rpm later
+    mock ${mock_args} --init
+    mock ${mock_args} --buildsrpm --spec nexus.spec --sources . --define "nexus_config_options $build_args" --define "_source_filedigest_algorithm md5" --define "_binary_filedigest_algorithm md5" 
+    srpm=`ls $RESULTS/*.src.rpm`
+    mock ${mock_args} --rebuild $srpm --define "nexus_config_options $build_args" --define "_source_filedigest_algorithm md5" --define "_binary_filedigest_algorithm md5"
+else
+# buildroot is actually where we install to
+    cd $topdir/SPECS
+    rpmbuild -ba --buildroot $nxtop/installroot --define "nexus_config_options $build_args" --define "_source_filedigest_algorithm md5" --define "_binary_filedigest_algorithm md5" nexus.spec
+fi
diff --git a/build_rules.am b/build_rules.am
new file mode 100644
index 0000000..7495c66
--- /dev/null
+++ b/build_rules.am
@@ -0,0 +1,70 @@
+##====================================================================
+##  NeXus - Neutron & X-ray Common Data Format
+##  
+##  $Id$
+##
+##  This file is included by Makefile.am when automake is run 
+##  to produce the Makefile.in - it includes extra make build rules
+##  needed to e.g. build Fortran 90 files
+##
+##  Copyright (C) 2004 Freddie Akeroyd
+##  
+##  This library is free software; you can redistribute it and/or
+##  modify it under the terms of the GNU Lesser General Public
+##  License as published by the Free Software Foundation; either
+##  version 2 of the License, or (at your option) any later version.
+## 
+##  This library is distributed in the hope that it will be useful,
+##  but WITHOUT ANY WARRANTY; without even the implied warranty of
+##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+##  Lesser General Public License for more details.
+## 
+##  You should have received a copy of the GNU Lesser General Public
+##  License along with this library; if not, write to the Free 
+##  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+##  MA  02111-1307  USA
+##             
+##  For further information, see <http://www.nexusformat.org>
+##
+##====================================================================
+
+#SUFFIXES = .f90 .o .java .i
+
+FCCOMPILE = $(FC) $(AM_FCFLAGS) $(FCFLAGS)
+LTFCCOMPILE = $(LIBTOOL) --mode=compile --tag=F77 $(FC) $(AM_FCFLAGS) $(FCFLAGS)
+FCLD = $(FC)
+FCLINK = $(LIBTOOL) --mode=link --tag=CC $(FCLD) $(AM_FCFLAGS) $(FCFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+
+.f90.o:
+	$(FCCOMPILE) -c $<
+.f90.lo:
+	$(LTFCCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+
+#F77LINK = $(LIBTOOL) --mode=link --tag=CC $(F77LD) $(AM_FFLAGS) \
+#	$(FFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+#
+#.java.class:
+#	$(JAVAC) $<
+#
+#.i.c:
+#	$(SWIG) $(SWIGFLAGS) -o $@ $<
+#
+#F90COMPILE = $(F90) $(AM_F90FLAGS) $(F90FLAGS)
+#LTF90COMPILE = $(LIBTOOL) --mode=compile @LTF90COMPILETAG@ $(F90) $(AM_FFLAGS) $(F90FLAGS)
+#F90LD = $(F90)
+#F90LINK = $(LIBTOOL) --mode=link @LTF90LINKTAG@ $(F90LD) $(AM_F90FLAGS) $(F90FLAGS) \
+#        $(AM_LDFLAGS) $(LDFLAGS) -o $@ $(LIBG2C)
+#
+#	-cpp $(AM_CPPFLAGS) -C -P $< > $*_cpp.f90
+#.f90.o :
+#	-cpp $(AM_CPPFLAGS) -C $< > $*_cpp.f90
+#	perl -p -i.bak -e 's/^\s+(\w)/$$1/' $*_cpp.f90
+#	$(FC) $(AM_FCFLAGS) $(FCFLAGS) -c $*_cpp.f90 -o $@
+#	$(RM) $*_cpp.f90.bak
+#
+#.f90.lo :
+#	-cpp $(AM_CPPFLAGS) -C $< > $*_cpp.f90
+#	perl -p -i.bak -e 's/^\s+(\w)/$$1/' $*_cpp.f90
+#	$(LTFCCOMPILE) -c -o $@ `test -f '$*_cpp.f90' || echo '$(srcdir)/'`$*_cpp.f90
+#	$(RM) $*_cpp.f90.bak
diff --git a/cmake_include/FindAnt.cmake b/cmake_include/FindAnt.cmake
new file mode 100644
index 0000000..9624303
--- /dev/null
+++ b/cmake_include/FindAnt.cmake
@@ -0,0 +1,34 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+find_file(ANT_EXEC NAMES ant ant.sh ant.bat PATHS $ENV{ANT_HOME}/bin)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ANT DEFAULT_MSG ANT_EXEC)
+
+MARK_AS_ADVANCED(ANT_EXEC)
diff --git a/cmake_include/FindCBFLib.cmake b/cmake_include/FindCBFLib.cmake
new file mode 100644
index 0000000..03846b4
--- /dev/null
+++ b/cmake_include/FindCBFLib.cmake
@@ -0,0 +1,29 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+
diff --git a/cmake_include/FindDocbookUtils.cmake b/cmake_include/FindDocbookUtils.cmake
new file mode 100644
index 0000000..6669d2a
--- /dev/null
+++ b/cmake_include/FindDocbookUtils.cmake
@@ -0,0 +1,44 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+
+FIND_PROGRAM(DOCBOOK2PDF_EXECUTABLE
+  docbook2pdf
+)
+
+FIND_PROGRAM(DOCBOOK2TXT_EXECUTABLE
+  docbook2txt
+)
+
+# handle the QUIETLY and REQUIRED arguments and set PYTHONINTERP_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(DocbookUtils DEFAULT_MSG DOCBOOK2PDF_EXECUTABLE DOCBOOK2TXT_EXECUTABLE)
+
+MARK_AS_ADVANCED(DOCBOOK2PDF_EXECUTABLE DOCBOOK2TXT_EXECUTABLE)
+
diff --git a/cmake_include/FindExtraJava.cmake b/cmake_include/FindExtraJava.cmake
new file mode 100644
index 0000000..6f0c5f4
--- /dev/null
+++ b/cmake_include/FindExtraJava.cmake
@@ -0,0 +1,44 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+#In 2.8 findJava and findJNI there is a lack of
+#definition for javah and javadoc 
+FIND_PROGRAM(JAVA_NATIVE
+  NAMES javah
+  PATHS ${JAVA_BIN_PATH}
+)
+
+FIND_PROGRAM(JAVA_DOC
+  NAMES javadoc
+  PATHS ${JAVA_BIN_PATH}
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JAVAEXTRA DEFAULT_MSG JAVA_NATIVE JAVA_DOC)
+
+MARK_AS_ADVANCED(JAVA_NATIVE JAVA_DOC)
diff --git a/cmake_include/FindGuile.cmake b/cmake_include/FindGuile.cmake
new file mode 100644
index 0000000..ffdcdbe
--- /dev/null
+++ b/cmake_include/FindGuile.cmake
@@ -0,0 +1,41 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+find_library(GUILE_LIB NAME guile PATHS $ENV{GUILE_ROOT})
+
+find_path(GUILE_INCLUDE NAME libguile.h PATHS $ENV{GUILE_ROOT} $ENV{GUILE_ROOT}/include)
+
+if(GUILE_LIB AND GUILE_INCLUDE)
+    set(GUILE_LINK "-lguile")
+    include_directories($ENV{GUILE_INCLUDE})
+endif(GUILE_LIB AND GUILE_INCLUDE)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GUILELIB DEFAULT_MSG GUILE_LIB GUILE_INCLUDE)
+
+MARK_AS_ADVANCED(GUILE_LIB GUILE_INCLUDE)
diff --git a/cmake_include/FindHDF4.cmake b/cmake_include/FindHDF4.cmake
new file mode 100644
index 0000000..34faaab
--- /dev/null
+++ b/cmake_include/FindHDF4.cmake
@@ -0,0 +1,73 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+
+# looks in HDF4_ROOT environment variable for hint
+# set HDF4_FOUND HDF4_DEFINITIONS HDF4_INCLUDE_DIRS  HDF4_LIBRARIES  HDF4_ROOT_DIR
+
+if (WIN32)
+#    set(HDF4_SEARCH_DEFAULT "C:/InstallKits/HDF4.2.6_win_x64")
+	set(HDF4_SEARCH_DEFAULT "C:/Program Files/HDF Group/HDF4/4.2.7")
+	set(HD_NAMES hdf hdfdll hd427m hd426m hd425m )
+	set(HM_NAMES mfhdf mfhdfdll hm427m hm426m hm425m )
+	set(JPEG_NAMES libjpeg jpeg )
+	set(XDR_NAMES xdr )
+	find_library(HDF4_HD_LIBRARY NAMES ${HD_NAMES} HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES dll bin lib DOC "location of hd dll" NO_SYSTEM_ENVIRONMENT_PATH)
+	find_library(HDF4_HM_LIBRARY NAMES ${HM_NAMES} HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES dll bin lib DOC "location of hm dll" NO_SYSTEM_ENVIRONMENT_PATH)
+	find_library(JPEG_LIBRARY NAMES ${JPEG_NAMES} HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES dll bin lib DOC "location of jpeg dll" NO_SYSTEM_ENVIRONMENT_PATH)
+	find_library(XDR_LIBRARY NAMES ${XDR_NAMES} HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES dll bin lib DOC "location of xdr dll" NO_SYSTEM_ENVIRONMENT_PATH)
+else(WIN32)
+    set(HDF4_SEARCH_DEFAULT "/usr" "/usr/local" "/usr/local/hdf4" "/sw")
+	set(HD_NAMES df)
+	set(HM_NAMES mfhdf)
+	find_library(HDF4_HD_LIBRARY NAMES ${HD_NAMES} HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES lib DOC "location of hd dll")
+	find_library(HDF4_HM_LIBRARY NAMES ${HM_NAMES} HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES lib DOC "location of hm dll")
+	find_package(JPEG)
+endif(WIN32)
+
+mark_as_advanced(HDF4_HD_LIBRARY HDF4_HM_LIBRARY JPEG_LIBRARY XDR_LIBRARY)
+
+if(WIN32)
+set(WINSOCK ws2_32.lib) # needed for htonl() etc in xdr
+endif(WIN32)
+
+if (HDF4_HM_LIBRARY AND HDF4_HD_LIBRARY)
+    set(HDF4_SHARED_LIBRARIES ${HDF4_HM_LIBRARY} ${HDF4_HD_LIBRARY} ${JPEG_LIBRARY} ${XDR_LIBRARY} ${WINSOCK})
+    set(HDF4_STATIC_LIBRARIES ${HDF4_HM_LIBRARY} ${HDF4_HD_LIBRARY} ${JPEG_LIBRARY} ${XDR_LIBRARY} ${WINSOCK})
+    set(HDF4_LIBRARIES ${HDF4_SHARED_LIBRARIES} CACHE FILEPATH "Location of HDF4 libraries")
+    get_filename_component(_HDF4_LIBDIR ${HDF4_HM_LIBRARY} PATH)
+    get_filename_component(HDF4_ROOT_DIR "${_HDF4_LIBDIR}/.." ABSOLUTE)
+	find_path(HDF4_INCLUDE_DIRS NAMES mfhdf.h HINTS ${HDF4_SEARCH} ENV HDF4_ROOT PATHS ${HDF4_SEARCH_DEFAULT} PATH_SUFFIXES include DOC "location of hdf4 includes" NO_SYSTEM_ENVIRONMENT_PATH)
+endif()
+
+mark_as_advanced(HDF4_LIBRARIES HDF4_INCLUDE_DIRS)
+
+set(HDF4_DEFINITIONS "")
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(HDF4 DEFAULT_MSG HDF4_LIBRARIES HDF4_INCLUDE_DIRS)
diff --git a/cmake_include/FindHDF5.cmake b/cmake_include/FindHDF5.cmake
new file mode 100644
index 0000000..19c0b47
--- /dev/null
+++ b/cmake_include/FindHDF5.cmake
@@ -0,0 +1,59 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+# looks in HDF5_ROOT environment variable for hint
+# set HDF5_FOUND HDF5_DEFINITIONS HDF5_INCLUDE_DIRS  HDF5_C_LIBRARIES HDF5_LIBRARIES  HDF5_LIBRARY_DIRS HDF5_ROOT_DIR
+
+if (WIN32)
+#    set(HDF5_SEARCH_DEFAULT "C:/InstallKits/HDF5-1.8.6-win64")
+	set(HDF5_SEARCH_DEFAULT "C:/Program Files/HDF Group/HDF5/1.8.9")
+	find_library(HDF5_SHARED_LIBRARIES NAMES hdf5dll HINTS ${HDF5_SEARCH} ENV HDF5_ROOT PATHS ${HDF5_SEARCH_DEFAULT} PATH_SUFFIXES dll bin lib DOC "location of hdf5 dll" NO_SYSTEM_ENVIRONMENT_PATH)
+	find_library(HDF5_STATIC_LIBRARIES NAMES hdf5 HINTS ${HDF5_SEARCH} ENV HDF5_ROOT PATHS ${HDF5_SEARCH_DEFAULT} PATH_SUFFIXES lib DOC "location of hdf5 lib" NO_SYSTEM_ENVIRONMENT_PATH)
+else(WIN32)
+    set(HDF5_SEARCH_DEFAULT "/usr" "/usr/local" "/usr/local/hdf5" "/sw")
+	find_library(HDF5_SHARED_LIBRARIES NAMES hdf5 HINTS ${HDF5_SEARCH} ENV HDF5_ROOT PATHS ${HDF5_SEARCH_DEFAULT} PATH_SUFFIXES lib DOC "location of hdf5 dll")
+	find_library(HDF5_STATIC_LIBRARIES NAMES hdf5 HINTS ${HDF5_SEARCH} ENV HDF5_ROOT PATHS ${HDF5_SEARCH_DEFAULT} PATH_SUFFIXES lib DOC "location of hdf5 lib")
+endif(WIN32)
+
+mark_as_advanced(HDF5_SHARED_LIBRARIES HDF5_STATIC_LIBRARIES)
+
+if (HDF5_SHARED_LIBRARIES)
+    set(HDF5_LIBRARIES ${HDF5_SHARED_LIBRARIES} CACHE FILEPATH "Location of HDF5 libraries")
+	get_filename_component(_HDF5_LIBDIR ${HDF5_SHARED_LIBRARIES} PATH)
+elseif (HDF5_STATIC_LIBRARIES)
+    set(HDF5_LIBRARIES ${HDF5_STATIC_LIBRARIES} CACHE FILEPATH "Location of HDF5 libraries")
+	get_filename_component(_HDF5_LIBDIR ${HDF5_STATIC_LIBRARIES} PATH)
+endif()
+set(HDF5_DEFINITIONS "")
+get_filename_component(HDF5_ROOT_DIR "${_HDF5_LIBDIR}/.." ABSOLUTE)
+find_path(HDF5_INCLUDE_DIRS NAMES hdf5.h HINTS ${HDF5_SEARCH} ENV HDF5_ROOT PATHS ${HDF5_SEARCH_DEFAULT} PATH_SUFFIXES include DOC "location of hdf5 includes" NO_SYSTEM_ENVIRONMENT_PATH)
+
+mark_as_advanced(HDF5_LIBRARIES HDF5_INCLUDE_DIRS)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(HDF5 DEFAULT_MSG HDF5_LIBRARIES HDF5_INCLUDE_DIRS)
diff --git a/cmake_include/FindIDL.cmake b/cmake_include/FindIDL.cmake
new file mode 100644
index 0000000..c07ed6a
--- /dev/null
+++ b/cmake_include/FindIDL.cmake
@@ -0,0 +1,28 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
diff --git a/cmake_include/FindJNI.cmake b/cmake_include/FindJNI.cmake
new file mode 100644
index 0000000..d032b3a
--- /dev/null
+++ b/cmake_include/FindJNI.cmake
@@ -0,0 +1,261 @@
+# - Find JNI java libraries.
+# This module finds if Java is installed and determines where the
+# include files and libraries are. It also determines what the name of
+# the library is. This code sets the following variables:
+#   
+#  JNI_INCLUDE_DIRS      = the include dirs to use
+#  JNI_LIBRARIES         = the libraries to use
+#  JNI_FOUND             = TRUE if JNI headers and libraries were found.
+#  JAVA_AWT_LIBRARY      = the path to the jawt library
+#  JAVA_JVM_LIBRARY      = the path to the jvm library
+#  JAVA_INCLUDE_PATH     = the include path to jni.h
+#  JAVA_INCLUDE_PATH2    = the include path to jni_md.h
+#  JAVA_AWT_INCLUDE_PATH = the include path to jawt.h
+#
+
+#=============================================================================
+# Copyright 2001-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# Expand {libarch} occurences to java_libarch subdirectory(-ies) and set ${_var}
+MACRO(java_append_library_directories _var)
+    # Determine java arch-specific library subdir
+    # Mostly based on openjdk/jdk/make/common/shared/Platform.gmk as of openjdk
+    # 1.6.0_18 + icedtea patches. However, it would be much better to base the
+    # guess on the first part of the GNU config.guess platform triplet.
+    IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+        SET(_java_libarch "amd64")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$")
+        SET(_java_libarch "i386")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^alpha")
+        SET(_java_libarch "alpha")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
+        # Subdir is "arm" for both big-endian (arm) and little-endian (armel).
+        SET(_java_libarch "arm")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
+        # mips* machines are bi-endian mostly so processor does not tell
+        # endianess of the underlying system.
+        SET(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "mips" "mipsel" "mipseb")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
+        SET(_java_libarch "ppc64")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
+        SET(_java_libarch "ppc")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^sparc")
+        # Both flavours can run on the same processor
+        SET(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "sparc" "sparcv9")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(parisc|hppa)")
+        SET(_java_libarch "parisc" "parisc64")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^s390")
+        # s390 binaries can run on s390x machines
+        SET(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "s390" "s390x")
+    ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^sh")
+        SET(_java_libarch "sh")
+    ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+        SET(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}")
+    ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+
+    # Append default list architectures if CMAKE_SYSTEM_PROCESSOR was empty or
+    # system is non-Linux (where the code above has not been well tested)
+    IF(NOT _java_libarch OR NOT (CMAKE_SYSTEM_NAME MATCHES "Linux"))
+        LIST(APPEND _java_libarch "i386" "amd64" "ppc")
+    ENDIF(NOT _java_libarch OR NOT (CMAKE_SYSTEM_NAME MATCHES "Linux"))
+
+    # Sometimes ${CMAKE_SYSTEM_PROCESSOR} is added to the list to prefer
+    # current value to a hardcoded list. Remove possible duplicates.
+    LIST(REMOVE_DUPLICATES _java_libarch)
+
+    FOREACH(_path ${ARGN})
+        IF(_path MATCHES "{libarch}")
+            FOREACH(_libarch ${_java_libarch})
+                STRING(REPLACE "{libarch}" "${_libarch}" _newpath "${_path}")
+                LIST(APPEND ${_var} "${_newpath}")
+            ENDFOREACH(_libarch)
+        ELSE(_path MATCHES "{libarch}")
+            LIST(APPEND ${_var} "${_path}")
+        ENDIF(_path MATCHES "{libarch}")
+    ENDFOREACH(_path)
+ENDMACRO(java_append_library_directories)
+
+GET_FILENAME_COMPONENT(java_install_version
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit;CurrentVersion]" NAME)
+
+SET(JAVA_AWT_LIBRARY_DIRECTORIES
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/lib"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/lib"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/lib"
+  )
+
+FILE(TO_CMAKE_PATH "$ENV{JAVA_HOME}" _JAVA_HOME)
+
+JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES
+  ${_JAVA_HOME}/jre/lib/{libarch}
+  ${_JAVA_HOME}/jre/lib
+  ${_JAVA_HOME}/lib
+  ${_JAVA_HOME}
+  /usr/lib
+  /usr/local/lib
+  /usr/lib/jvm/java/lib
+  /usr/lib/java/jre/lib/{libarch}
+  /usr/lib/jvm/jre/lib/{libarch}
+  /usr/local/lib/java/jre/lib/{libarch}
+  /usr/local/share/java/jre/lib/{libarch}
+  /usr/lib/j2sdk1.4-sun/jre/lib/{libarch}
+  /usr/lib/j2sdk1.5-sun/jre/lib/{libarch}
+  /opt/sun-jdk-1.5.0.04/jre/lib/{libarch}
+  /usr/lib/jvm/java-6-sun/jre/lib/{libarch}
+  /usr/lib/jvm/java-1.5.0-sun/jre/lib/{libarch}
+  /usr/lib/jvm/java-6-sun-1.6.0.00/jre/lib/{libarch}       # can this one be removed according to #8821 ? Alex
+  /usr/lib/jvm/java-6-openjdk/jre/lib/{libarch}
+  /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/{libarch}        # fedora
+  # Debian specific paths for default JVM
+  /usr/lib/jvm/default-java/jre/lib/{libarch}
+  /usr/lib/jvm/default-java/jre/lib
+  /usr/lib/jvm/default-java/lib
+  )
+
+SET(JAVA_JVM_LIBRARY_DIRECTORIES)
+FOREACH(dir ${JAVA_AWT_LIBRARY_DIRECTORIES})
+  SET(JAVA_JVM_LIBRARY_DIRECTORIES
+    ${JAVA_JVM_LIBRARY_DIRECTORIES}
+    "${dir}"
+    "${dir}/client"
+    "${dir}/server"
+    )
+ENDFOREACH(dir)
+
+
+SET(JAVA_AWT_INCLUDE_DIRECTORIES
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/include"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/include"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/include"
+  ${_JAVA_HOME}/include
+  /usr/include 
+  /usr/local/include
+  /usr/lib/java/include
+  /usr/local/lib/java/include
+  /usr/lib/jvm/java/include
+  /usr/lib/jvm/java-6-sun/include
+  /usr/lib/jvm/java-1.5.0-sun/include
+  /usr/lib/jvm/java-6-sun-1.6.0.00/include       # can this one be removed according to #8821 ? Alex
+  /usr/lib/jvm/java-6-openjdk/include
+  /usr/local/share/java/include
+  /usr/lib/j2sdk1.4-sun/include
+  /usr/lib/j2sdk1.5-sun/include
+  /opt/sun-jdk-1.5.0.04/include
+  # Debian specific path for default JVM
+  /usr/lib/jvm/default-java/include
+  )
+
+FOREACH(JAVA_PROG "${JAVA_RUNTIME}" "${JAVA_COMPILE}" "${JAVA_ARCHIVE}")
+  GET_FILENAME_COMPONENT(jpath "${JAVA_PROG}" PATH)
+  FOREACH(JAVA_INC_PATH ../include ../java/include ../share/java/include)
+    IF(EXISTS ${jpath}/${JAVA_INC_PATH})
+      SET(JAVA_AWT_INCLUDE_DIRECTORIES ${JAVA_AWT_INCLUDE_DIRECTORIES} "${jpath}/${JAVA_INC_PATH}")
+    ENDIF(EXISTS ${jpath}/${JAVA_INC_PATH})
+  ENDFOREACH(JAVA_INC_PATH)
+  FOREACH(JAVA_LIB_PATH 
+    ../lib ../jre/lib ../jre/lib/i386 
+    ../java/lib ../java/jre/lib ../java/jre/lib/i386 
+    ../share/java/lib ../share/java/jre/lib ../share/java/jre/lib/i386)
+    IF(EXISTS ${jpath}/${JAVA_LIB_PATH})
+      SET(JAVA_AWT_LIBRARY_DIRECTORIES ${JAVA_AWT_LIBRARY_DIRECTORIES} "${jpath}/${JAVA_LIB_PATH}")
+    ENDIF(EXISTS ${jpath}/${JAVA_LIB_PATH})
+  ENDFOREACH(JAVA_LIB_PATH)
+ENDFOREACH(JAVA_PROG)
+
+IF(APPLE)
+  IF(EXISTS ~/Library/Frameworks/JavaVM.framework)
+    SET(JAVA_HAVE_FRAMEWORK 1)
+  ENDIF(EXISTS ~/Library/Frameworks/JavaVM.framework)
+  IF(EXISTS /Library/Frameworks/JavaVM.framework)
+    SET(JAVA_HAVE_FRAMEWORK 1)
+  ENDIF(EXISTS /Library/Frameworks/JavaVM.framework)
+  IF(EXISTS /System/Library/Frameworks/JavaVM.framework)
+    SET(JAVA_HAVE_FRAMEWORK 1)
+  ENDIF(EXISTS /System/Library/Frameworks/JavaVM.framework)
+
+  IF(JAVA_HAVE_FRAMEWORK)
+    IF(NOT JAVA_AWT_LIBRARY)
+      SET (JAVA_AWT_LIBRARY "-framework JavaVM" CACHE FILEPATH "Java Frameworks" FORCE)
+    ENDIF(NOT JAVA_AWT_LIBRARY)
+
+    IF(NOT JAVA_JVM_LIBRARY)
+      SET (JAVA_JVM_LIBRARY "-framework JavaVM" CACHE FILEPATH "Java Frameworks" FORCE)
+    ENDIF(NOT JAVA_JVM_LIBRARY)
+
+    IF(NOT JAVA_AWT_INCLUDE_PATH)
+      IF(EXISTS /System/Library/Frameworks/JavaVM.framework/Headers/jawt.h)
+        SET (JAVA_AWT_INCLUDE_PATH "/System/Library/Frameworks/JavaVM.framework/Headers" CACHE FILEPATH "jawt.h location" FORCE)
+      ENDIF(EXISTS /System/Library/Frameworks/JavaVM.framework/Headers/jawt.h)
+    ENDIF(NOT JAVA_AWT_INCLUDE_PATH)
+
+    # If using "-framework JavaVM", prefer its headers *before* the others in
+    # JAVA_AWT_INCLUDE_DIRECTORIES... (*prepend* to the list here)
+    #
+    SET(JAVA_AWT_INCLUDE_DIRECTORIES
+      ~/Library/Frameworks/JavaVM.framework/Headers
+      /Library/Frameworks/JavaVM.framework/Headers
+      /System/Library/Frameworks/JavaVM.framework/Headers
+      ${JAVA_AWT_INCLUDE_DIRECTORIES}
+      )
+  ENDIF(JAVA_HAVE_FRAMEWORK)
+ELSE(APPLE)
+  FIND_LIBRARY(JAVA_AWT_LIBRARY jawt 
+    PATHS ${JAVA_AWT_LIBRARY_DIRECTORIES}
+  )
+  FIND_LIBRARY(JAVA_JVM_LIBRARY NAMES jvm JavaVM
+    PATHS ${JAVA_JVM_LIBRARY_DIRECTORIES}
+  )
+ENDIF(APPLE)
+
+# add in the include path    
+FIND_PATH(JAVA_INCLUDE_PATH jni.h 
+  ${JAVA_AWT_INCLUDE_DIRECTORIES}
+)
+
+FIND_PATH(JAVA_INCLUDE_PATH2 jni_md.h 
+  ${JAVA_INCLUDE_PATH}
+  ${JAVA_INCLUDE_PATH}/win32
+  ${JAVA_INCLUDE_PATH}/linux
+  ${JAVA_INCLUDE_PATH}/freebsd
+  ${JAVA_INCLUDE_PATH}/solaris
+  ${JAVA_INCLUDE_PATH}/hp-ux
+  ${JAVA_INCLUDE_PATH}/alpha
+)
+
+FIND_PATH(JAVA_AWT_INCLUDE_PATH jawt.h
+  ${JAVA_INCLUDE_PATH}
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JNI  DEFAULT_MSG  JAVA_AWT_LIBRARY JAVA_JVM_LIBRARY
+                                                    JAVA_INCLUDE_PATH  JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH)
+
+MARK_AS_ADVANCED(
+  JAVA_AWT_LIBRARY
+  JAVA_JVM_LIBRARY
+  JAVA_AWT_INCLUDE_PATH
+  JAVA_INCLUDE_PATH
+  JAVA_INCLUDE_PATH2
+)
+
+SET(JNI_LIBRARIES
+  ${JAVA_AWT_LIBRARY}
+  ${JAVA_JVM_LIBRARY}
+)
+
+SET(JNI_INCLUDE_DIRS
+  ${JAVA_INCLUDE_PATH}
+  ${JAVA_INCLUDE_PATH2}
+  ${JAVA_AWT_INCLUDE_PATH}
+)
+
diff --git a/cmake_include/FindJava.cmake b/cmake_include/FindJava.cmake
new file mode 100644
index 0000000..d926c78
--- /dev/null
+++ b/cmake_include/FindJava.cmake
@@ -0,0 +1,207 @@
+# - Find Java
+# This module finds if Java is installed and determines where the
+# include files and libraries are. This code sets the following
+# variables:
+#
+#  Java_JAVA_EXECUTABLE    = the full path to the Java runtime
+#  Java_JAVAC_EXECUTABLE   = the full path to the Java compiler
+#  Java_JAR_EXECUTABLE     = the full path to the Java archiver
+#  Java_JNI_EXECUTABLE     = the full path to the Java JNI command
+#  Java_DOC_EXECUTABLE     = the full path to the Javadoc command
+#  Java_VERSION_STRING     = Version of the package found (java version), eg. 1.6.0_12
+#  Java_VERSION_MAJOR      = The major version of the package found.
+#  Java_VERSION_MINOR      = The minor version of the package found.
+#  Java_VERSION_PATCH      = The patch version of the package found.
+#  Java_VERSION_TWEAK      = The tweak version of the package found (after '_')
+#  Java_VERSION            = This is set to: $major.$minor.$patch(.$tweak)
+#
+# The minimum required version of Java can be specified using the
+# standard CMake syntax, e.g. FIND_PACKAGE(Java 1.5)
+#
+# NOTE: ${Java_VERSION} and ${Java_VERSION_STRING} are not guaranteed to be
+# identical. For example some java version may return:
+# Java_VERSION_STRING = 1.5.0_17
+# and
+# Java_VERSION        = 1.5.0.17
+# 
+# another example is the Java OEM, with:
+# Java_VERSION_STRING = 1.6.0-oem
+# and
+# Java_VERSION        = 1.6.0
+#
+# For these components the following variables are set:
+#
+#  Java_FOUND                    - TRUE if all components are found.
+#  Java_INCLUDE_DIRS             - Full paths to all include dirs.
+#  Java_LIBRARIES                - Full paths to all libraries.
+#  Java_<component>_FOUND        - TRUE if <component> is found.
+#
+# Example Usages:
+#  FIND_PACKAGE(Java)
+#  FIND_PACKAGE(Java COMPONENTS Runtime)
+#  FIND_PACKAGE(Java COMPONENTS Development)
+#
+
+#=============================================================================
+# Copyright 2002-2009 Kitware, Inc.
+# Copyright 2009-2011 Mathieu Malaterre <mathieu.malaterre at gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# The HINTS option should only be used for values computed from the system.
+SET(_JAVA_HINTS
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\2.0;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
+  $ENV{JAVA_HOME}/bin
+  )
+# Hard-coded guesses should still go in PATHS. This ensures that the user
+# environment can always override hard guesses.
+SET(_JAVA_PATHS
+  /usr/lib/java/bin
+  /usr/share/java/bin
+  /usr/local/java/bin
+  /usr/local/java/share/bin
+  /usr/java/j2sdk1.4.2_04
+  /usr/lib/j2sdk1.4-sun/bin
+  /usr/java/j2sdk1.4.2_09/bin
+  /usr/lib/j2sdk1.5-sun/bin
+  /opt/sun-jdk-1.5.0.04/bin
+  )
+FIND_PROGRAM(Java_JAVA_EXECUTABLE
+  NAMES java
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+IF(Java_JAVA_EXECUTABLE)
+    EXECUTE_PROCESS(COMMAND ${Java_JAVA_EXECUTABLE} -version
+      RESULT_VARIABLE res
+      OUTPUT_VARIABLE var
+      ERROR_VARIABLE var # sun-java output to stderr
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_STRIP_TRAILING_WHITESPACE)
+    IF( res )
+      IF(${Java_FIND_REQUIRED})
+        MESSAGE( FATAL_ERROR "Error executing java -version" )
+      ELSE()
+        MESSAGE( STATUS "Warning, could not run java --version")
+      ENDIF()
+    ELSE()
+      # extract major/minor version and patch level from "java -version" output
+      # Tested on linux using 
+      # 1. Sun / Sun OEM
+      # 2. OpenJDK 1.6
+      # 3. GCJ 1.5
+      # 4. Kaffe 1.4.2
+      IF(var MATCHES "java version \"[0-9]+\\.[0-9]+\\.[0-9_.]+[oem-]*\".*")
+        # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer
+        STRING( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_.]+)[oem-]*\".*"
+                "\\1" Java_VERSION_STRING "${var}" )
+      ELSEIF(var MATCHES "java full version \"kaffe-[0-9]+\\.[0-9]+\\.[0-9_]+\".*")
+        # Kaffe style
+        STRING( REGEX REPLACE "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+).*"
+                "\\1" Java_VERSION_STRING "${var}" )
+      ELSE()
+        IF(NOT Java_FIND_QUIETLY)
+          message(WARNING "regex not supported: ${var}. Please report")
+        ENDIF(NOT Java_FIND_QUIETLY)
+      ENDIF()
+      STRING( REGEX REPLACE "([0-9]+).*" "\\1" Java_VERSION_MAJOR "${Java_VERSION_STRING}" )
+      STRING( REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_MINOR "${Java_VERSION_STRING}" )
+      STRING( REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_PATCH "${Java_VERSION_STRING}" )
+      # warning tweak version can be empty:
+      STRING( REGEX REPLACE "[0-9]+\\.[0-9]+\\.[0-9]+\\_?\\.?([0-9]*)$" "\\1" Java_VERSION_TWEAK "${Java_VERSION_STRING}" )
+      if( Java_VERSION_TWEAK STREQUAL "" ) # check case where tweak is not defined
+        set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH})
+      else( )
+        set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}.${Java_VERSION_TWEAK})
+      endif( )
+      # display info
+      #MESSAGE( STATUS "Java version ${Java_VERSION_STRING} configured successfully!" ) # keep me, used for debug
+      IF(NOT Java_FIND_QUIETLY)
+        MESSAGE( STATUS "Java version ${Java_VERSION} configured successfully!" )
+      ENDIF(NOT Java_FIND_QUIETLY)
+    ENDIF()
+
+ENDIF(Java_JAVA_EXECUTABLE)
+
+
+FIND_PROGRAM(Java_JAR_EXECUTABLE
+  NAMES jar
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+FIND_PROGRAM(Java_JAVAC_EXECUTABLE
+  NAMES javac
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+FIND_PROGRAM(Java_JNI_EXECUTABLE
+  NAMES javah
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+FIND_PROGRAM(Java_DOC_EXECUTABLE
+  NAMES javadoc
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+include(FindPackageHandleStandardArgs)
+if(Java_FIND_COMPONENTS)
+  foreach(component ${Java_FIND_COMPONENTS})
+    # User just want to execute some Java byte-compiled
+    if(component STREQUAL "Runtime")
+      find_package_handle_standard_args(Java
+        REQUIRED_VARS Java_JAVA_EXECUTABLE
+        VERSION_VAR Java_VERSION
+        )
+    elseif(component STREQUAL "Development")
+      find_package_handle_standard_args(Java
+        REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE  Java_JNI_EXECUTABLE Java_DOC_EXECUTABLE
+        VERSION_VAR Java_VERSION
+        )
+    else()
+      message(FATAL_ERROR "Comp: ${component} is not handled")
+    endif()
+    set(Java_${component}_FOUND TRUE)
+  endforeach(component)
+else()
+  # Check for everything
+  find_package_handle_standard_args(Java
+    REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE Java_JNI_EXECUTABLE Java_DOC_EXECUTABLE
+    VERSION_VAR Java_VERSION
+    )
+endif()
+
+
+MARK_AS_ADVANCED(
+  Java_JAVA_EXECUTABLE
+  Java_JAR_EXECUTABLE
+  Java_JAVAC_EXECUTABLE
+  Java_JNI_EXECUTABLE
+  Java_DOC_EXECUTABLE
+  )
+
+# LEGACY
+SET(JAVA_RUNTIME ${Java_JAVA_EXECUTABLE})
+SET(JAVA_ARCHIVE ${Java_JAR_EXECUTABLE})
+SET(JAVA_COMPILE ${Java_JAVAC_EXECUTABLE})
+
diff --git a/cmake_include/FindMXML.cmake b/cmake_include/FindMXML.cmake
new file mode 100644
index 0000000..c2dcb38
--- /dev/null
+++ b/cmake_include/FindMXML.cmake
@@ -0,0 +1,66 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+
+# looks in MXML_ROOT environment variable for hint
+# set MXML_FOUND MXML_DEFINITIONS MXML_INCLUDE_DIRS  MXML_LIBRARIES  MXML_ROOT_DIR
+
+if (CMAKE_SIZEOF_VOID_P MATCHES "8")
+    set(ARCH_PREFIX 64)
+else()
+    set(ARCH_PREFIX 32)
+endif()
+
+if (WIN32)
+    set(MXML_SEARCH_DEFAULT "")
+	find_library(MXML_SHARED_LIBRARIES NAMES mxml mxml1 HINTS ${MXML_SEARCH} ENV MXML_ROOT PATHS ${MXML_SEARCH_DEFAULT} PATH_SUFFIXES dll${ARCH_SUFFIX} lib${ARCH_SUFFIX} dll lib DOC "location of mxml dll" )
+	find_library(MXML_STATIC_LIBRARIES NAMES mxml mxml1 HINTS ${MXML_SEARCH} ENV MXML_ROOT PATHS ${MXML_SEARCH_DEFAULT} PATH_SUFFIXES lib${ARCH_SUFFIX} lib DOC "location of mxml lib" )
+else(WIN32)
+    set(MXML_SEARCH_DEFAULT "/usr" "/usr/local" "/sw")
+	find_library(MXML_SHARED_LIBRARIES NAMES mxml HINTS ${MXML_SEARCH} ENV MXML_ROOT PATHS ${MXML_SEARCH_DEFAULT} PATH_SUFFIXES lib${ARCH_SUFFIX} lib DOC "location of mxml dll")
+	find_library(MXML_STATIC_LIBRARIES NAMES mxml HINTS ${MXML_SEARCH} ENV MXML_ROOT PATHS ${MXML_SEARCH_DEFAULT} PATH_SUFFIXES lib${ARCH_SUFFIX} lib DOC "location of mxml lib")
+endif(WIN32)
+
+mark_as_advanced(MXML_SHARED_LIBRARIES MXML_STATIC_LIBRARIES)
+
+if (MXML_SHARED_LIBRARIES)
+    set(MXML_LIBRARIES ${MXML_SHARED_LIBRARIES} CACHE FILEPATH "Location of MXML libraries")
+	get_filename_component(_MXML_LIBDIR ${MXML_SHARED_LIBRARIES} PATH)
+elseif (MXML_STATIC_LIBRARIES)
+    set(MXML_LIBRARIES ${MXML_STATIC_LIBRARIES}  CACHE FILEPATH "Location of MXML libraries")
+	get_filename_component(_MXML_LIBDIR ${MXML_STATIC_LIBRARIES} PATH)
+endif()
+set(MXML_DEFINITIONS "")
+get_filename_component(MXML_ROOT_DIR "${_MXML_LIBDIR}/.." ABSOLUTE)
+
+find_path(MXML_INCLUDE_DIRS NAMES mxml.h HINTS ${MXML_SEARCH} ENV MXML_ROOT PATHS ${MXML_SEARCH_DEFAULT} PATH_SUFFIXES include DOC "location of mxml includes" )
+
+mark_as_advanced(MXML_LIBRARIES MXML_INCLUDE_DIRS)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MXML DEFAULT_MSG MXML_LIBRARIES MXML_INCLUDE_DIRS)
diff --git a/cmake_include/FindMZScheme.cmake b/cmake_include/FindMZScheme.cmake
new file mode 100644
index 0000000..07cb77c
--- /dev/null
+++ b/cmake_include/FindMZScheme.cmake
@@ -0,0 +1,42 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+find_library(MZSCHEME_LIB NAMES mzscheme mzscheme3m PATHS $ENV{MZSCHEME_ROOT} $ENV{MZSCHEME_ROOT}/lib)
+
+find_library(MZDYN_LIB NAMES mzdyn mzdyn3m PATHS $ENV{MZSCHEME_ROOT} $ENV{MZSCHEME_ROOT}/lib $ENV{MZSCHEME_ROOT}/lib/plt)
+
+find_path(MZSCHEME_INCLUDE NAMES scheme.h mzconfig.h schemegc2.h PATHS $ENV{MZSCHEME_ROOT} $ENV{MZSCHEME_ROOT}/include)
+
+if(MZSCHEME_LIB AND MZSCHEME_INCLUDE AND MZDYN_LIB)
+    include_directories($ENV{MZSCHEME_INCLUDE})
+endif(MZSCHEME_LIB AND MZSCHEME_INCLUDE AND MZDYN_LIB)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MZSCHEMELIB DEFAULT_MSG MZSCHEME_LIB MZSCHEME_INCLUDE MZDYN_LIB)
+
+MARK_AS_ADVANCED(MZSCHEME_LIB MZSCHEME_INCLUDE)
diff --git a/cmake_include/FindOpenGenie.cmake b/cmake_include/FindOpenGenie.cmake
new file mode 100644
index 0000000..c07ed6a
--- /dev/null
+++ b/cmake_include/FindOpenGenie.cmake
@@ -0,0 +1,28 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
diff --git a/cmake_include/FindPython.cmake b/cmake_include/FindPython.cmake
new file mode 100644
index 0000000..7f4f660
--- /dev/null
+++ b/cmake_include/FindPython.cmake
@@ -0,0 +1,104 @@
+# - Find python interpreter
+# This module finds if Python interpreter is installed and determines where the
+# executables are. This code sets the following variables:
+#
+#  PYTHONINTERP_FOUND - Was the Python executable found
+#  PYTHON_EXECUTABLE  - path to the Python interpreter
+#  PYTHON_DOC  - path to the Python documentation generator
+#  PYTHON_COMPILE  - path to the Python compilerr
+#
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+#  License text for the above reference.)
+#
+# Updated to find pydoc and pycompile also 2.7. Stephen Rankin (STFC) 2011.
+#
+#
+#
+
+set(MS_PATHS
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath]   
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.2\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.1\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.0\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\1.6\\InstallPath]
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\1.5\\InstallPath])
+
+set(MS_LIB_PATHS
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath]/Lib   
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.2\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.1\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.0\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\1.6\\InstallPath]/Lib
+  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\1.5\\InstallPath]/Lib)
+
+set(PYTHON_NAMES python2.7 python2.6 python2.5 python2.4 python2.3 python2.2
+                 python2.1 python2.0 python1.6 python1.5 python)
+set(PYTHON_DOC_NAMES pydoc2.7 pydoc2.6 pydoc2.5 pydoc2.4 pydoc2.3 pydoc2.2
+                     pydoc2.1 pydoc2.0 pydoc1.6 pydoc1.5 pydoc
+                     pydoc2.7.pyc pydoc2.6.pyc pydoc2.5.pyc pydoc2.4.pyc
+                     pydoc2.3.pyc pydoc2.2.pyc pydoc2.1.pyc pydoc2.0.pyc
+                     pydoc1.6.pyc pydoc1.5.pyc pydoc.pyc)
+
+set(PYTHON_COMPILE_NAMES pycompile2.7 pycompile2.6 pycompile2.5 pycompile2.4
+                         pycompile2.3 pycompile2.2 pycompile2.1 pycompile2.0
+                         pycompile1.6 pycompile1.5 pycompile py_compile
+                         pycompile2.7.py pycompile2.6.py pycompile2.5.py pycompile2.4.py
+                         pycompile2.3.py pycompile2.2.py pycompile2.1.py pycompile2.0.py
+                         pycompile1.6.py pycompile1.5.py pycompile.py py_compile.py)
+
+FIND_PROGRAM(PYTHON_EXECUTABLE
+  NAMES ${PYTHON_NAMES}
+  PATHS
+  ${MS_PATHS} ${MS_LIB_PATHS}
+)
+
+FIND_PROGRAM(PYTHON_DOC
+  NAMES ${PYTHON_DOC_NAMES}
+  PATHS
+  ${MS_PATHS} ${MS_LIB_PATHS}
+)
+
+FIND_FILE(PYTHON_DOC
+  NAMES ${PYTHON_DOC_NAMES}
+  PATHS
+  ${MS_PATHS} ${MS_LIB_PATHS}
+)
+
+FIND_PROGRAM(PYTHON_COMPILE
+  NAMES ${PYTHON_COMPILE_NAMES}
+  PATHS
+  ${MS_PATHS} ${MS_LIB_PATHS}
+)
+
+FIND_FILE(PYTHON_COMPILE
+  NAMES ${PYTHON_COMPILE_NAMES}
+  PATHS
+  ${MS_PATHS} ${MS_LIB_PATHS}
+)
+
+# handle the QUIETLY and REQUIRED arguments and set PYTHONINTERP_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonInterp DEFAULT_MSG PYTHON_EXECUTABLE PYTHON_DOC PYTHON_COMPILE)
+
+MARK_AS_ADVANCED(PYTHON_EXECUTABLE PYTHON_DOC PYTHON_COMPILE)
+
diff --git a/cmake_include/FindSZIP.cmake b/cmake_include/FindSZIP.cmake
new file mode 100644
index 0000000..d9b5336
--- /dev/null
+++ b/cmake_include/FindSZIP.cmake
@@ -0,0 +1,63 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+# looks in SZIP_ROOT environment variable for hint
+# set SZIP_FOUND SZIP_DEFINITIONS SZIP_INCLUDE_DIRS  SZIP_LIBRARIES  SZIP_ROOT_DIR
+
+if (WIN32)
+    set(SZIP_SEARCH_DEFAULT $ENV{HDF5_ROOT})
+	find_library(SZIP_LIBRARIES NAMES libszip szip HINTS ${SZIP_SEARCH} ENV SZIP_ROOT PATHS ${SZIP_SEARCH_DEFAULT} PATH_SUFFIXES bin dll lib DOC "location of szip lib" NO_SYSTEM_ENVIRONMENT_PATH)
+else(WIN32)
+    set(SZIP_SEARCH_DEFAULT $ENV{HDF5_ROOT} "/usr" "/usr/local" "/usr/local/hdf5" "/sw")
+	find_library(SZIP_LIBRARIES NAMES sz HINTS ${SZIP_SEARCH} ENV SZIP_ROOT PATHS ${SZIP_SEARCH_DEFAULT} PATH_SUFFIXES lib DOC "location of szip lib")
+endif(WIN32)
+
+find_path(SZIP_INCLUDE_DIRS NAMES sz.h szlib.h HINTS ${SZIP_SEARCH} ENV SZIP_ROOT PATHS ${SZIP_SEARCH_DEFAULT} PATH_SUFFIXES include DOC "location of szip includes" NO_SYSTEM_ENVIRONMENT_PATH)
+
+#if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+#    find_library(ZIP_LIB NAMES z zlib zdll zlib1 zlibd zlibd1 PATHS $ENV{HDF5_ROOT}/bin $ENV{HDF5_ROOT}/lib)
+#    find_path(ZIP_INCLUDE zlib.h PATHS $ENV{HDF5_ROOT}/include)
+#endif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+
+#if(SZIP_INCLUDE)
+#    include_directories(${SZIP_INCLUDE})
+#endif(SZIP_INCLUDE)
+
+#if(ZIP_INCLUDE)
+#    include_directories(${ZIP_INCLUDE})
+#endif(ZIP_INCLUDE)
+
+set(SZIP_DEFINITIONS "")
+get_filename_component(_SZIP_LIBDIR ${SZIP_LIBRARIES} PATH)
+get_filename_component(SZIP_ROOT_DIR "${_SZIP_LIBDIR}/.." ABSOLUTE)
+
+mark_as_advanced(SZIP_LIBRARIES SZIP_INCLUDE_DIRS)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SZIP DEFAULT_MSG SZIP_LIBRARIES SZIP_INCLUDE_DIRS)
+
diff --git a/cmake_include/Utilities.cmake b/cmake_include/Utilities.cmake
new file mode 100644
index 0000000..41fea3a
--- /dev/null
+++ b/cmake_include/Utilities.cmake
@@ -0,0 +1,69 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Freddie Akeroyd
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+# checks a list of possible compiler flags and adds allowed ones to the current list
+function(check_add_c_compiler_flags)
+    foreach(FLAG ${ARGV})
+        check_c_compiler_flag(${FLAG} RES)
+	    if (RES)
+            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}" PARENT_SCOPE)
+	    endif()
+	endforeach()
+endfunction()
+
+# checks a list of possible compiler flags and adds allowed ones to the current list
+function(check_add_cxx_compiler_flags)
+    foreach(FLAG ${ARGV})
+        check_cxx_compiler_flag(${FLAG} RES)
+	    if (RES)
+            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}" PARENT_SCOPE)
+	    endif()
+	endforeach()
+endfunction()
+
+# define a HAVE_  if both  BUILD_  and  _FOUND  are defined
+# e.g. creates HAVE_HDF5 if both BUILD_HDF5 and HDF5_FOUND are ture
+function(create_have_vars)
+    foreach(NAME ${ARGV})
+        if(${BUILD_${NAME}} AND ${${NAME}_FOUND})
+	        set(HAVE_${NAME} ON PARENT_SCOPE)
+	    else()
+	        set(HAVE_${NAME} OFF PARENT_SCOPE)
+	    endif()
+	endforeach()
+endfunction()
+
+function(install_pdb target)
+#	set (OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR})
+	set (OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/Release)
+	get_target_property (OUT_NAME ${target} OUTPUT_NAME)
+	get_filename_component (OUT_BASE_NAME ${OUT_NAME} NAME_WE)
+#	set(PDB_FILE ${OUT_DIR}/${OUT_BASE_NAME}${CMAKE_DEBUG_POSTFIX}.pdb)
+	set(PDB_FILE ${OUT_DIR}/${OUT_BASE_NAME}.pdb)
+	install (FILES ${PDB_FILE} DESTINATION bin COMPONENT Runtime)  
+endfunction()
diff --git a/cmake_include/WELCOME.txt b/cmake_include/WELCOME.txt
new file mode 100644
index 0000000..5975a00
--- /dev/null
+++ b/cmake_include/WELCOME.txt
@@ -0,0 +1 @@
+Welcome.txt
\ No newline at end of file
diff --git a/cmake_include/nexus_description.txt b/cmake_include/nexus_description.txt
new file mode 100644
index 0000000..350acbe
--- /dev/null
+++ b/cmake_include/nexus_description.txt
@@ -0,0 +1,5 @@
+NeXus is an international standard for exchanging data files
+among Neutron, Muon and X-ray science facilities. The underlying
+data is stored using the HDF format from NCSA. This package provides
+access routines, documentation, examples and a basic NeXus file browser.
+
diff --git a/cmake_modules/NSIS.template.in b/cmake_modules/NSIS.template.in
new file mode 100644
index 0000000..379b7aa
--- /dev/null
+++ b/cmake_modules/NSIS.template.in
@@ -0,0 +1,1317 @@
+; CPack install script designed for a nmake build
+
+; --- begin local mod ---
+/**
+ *  EnvVarUpdate.nsh
+ *    : Environmental Variables: append, prepend, and remove entries
+ *
+ *     WARNING: If you use StrFunc.nsh header then include it before this file
+ *              with all required definitions. This is to avoid conflicts
+ *
+ *  Usage:
+ *    ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
+ *
+ *  Credits:
+ *  Version 1.0 
+ *  * Cal Turney (turnec2)
+ *  * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
+ *    function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
+ *    WriteEnvStr, and un.DeleteEnvStr
+ *  * Diego Pedroso (deguix) for StrTok
+ *  * Kevin English (kenglish_hi) for StrContains
+ *  * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry  
+ *    (dandaman32) for StrReplace
+ *
+ *  Version 1.1 (compatibility with StrFunc.nsh)
+ *  * techtonik
+ *
+ *  http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
+ *
+ */
+ 
+!ifndef ENVVARUPDATE_FUNCTION
+!define ENVVARUPDATE_FUNCTION
+!verbose push
+!verbose 3
+!include "LogicLib.nsh"
+!include "WinMessages.NSH"
+!include "StrFunc.nsh"
+ 
+; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
+!macro _IncludeStrFunction StrFuncName
+  !ifndef ${StrFuncName}_INCLUDED
+    ${${StrFuncName}}
+  !endif
+  !ifndef Un${StrFuncName}_INCLUDED
+    ${Un${StrFuncName}}
+  !endif
+  !define un.${StrFuncName} "${Un${StrFuncName}}"
+!macroend
+
+!insertmacro _IncludeStrFunction StrTok
+!insertmacro _IncludeStrFunction StrRep
+!insertmacro _IncludeStrFunction StrStr
+ 
+; ---------------------------------- Macro Definitions ----------------------------------------
+!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
+  Push "${EnvVarName}"
+  Push "${Action}"
+  Push "${RegLoc}"
+  Push "${PathString}"
+    Call EnvVarUpdate
+  Pop "${ResultVar}"
+!macroend
+!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
+ 
+!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
+  Push "${EnvVarName}"
+  Push "${Action}"
+  Push "${RegLoc}"
+  Push "${PathString}"
+    Call un.EnvVarUpdate
+  Pop "${ResultVar}"
+!macroend
+!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
+; ---------------------------------- Macro Definitions end-------------------------------------
+ 
+;----------------------------------- EnvVarUpdate start----------------------------------------
+!define hklm_all_users     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+!define hkcu_current_user  'HKCU "Environment"'
+ 
+!macro EnvVarUpdate UN
+ 
+Function ${UN}EnvVarUpdate
+ 
+  Push $0
+  Exch 4
+  Exch $1
+  Exch 3
+  Exch $2
+  Exch 2
+  Exch $3
+  Exch
+  Exch $4
+  Push $5
+  Push $6
+  Push $7
+  Push $8
+  Push $9
+  Push $R0
+ 
+  /* After this point:
+  -------------------------
+     $0 = ResultVar     (returned)
+     $1 = EnvVarName    (input)
+     $2 = Action        (input)
+     $3 = RegLoc        (input)
+     $4 = PathString    (input)
+     $5 = Orig EnvVar   (read from registry)
+     $6 = Len of $0     (temp)
+     $7 = tempstr1      (temp)
+     $8 = Entry counter (temp)
+     $9 = tempstr2      (temp)
+     $R0 = tempChar     (temp)  */
+ 
+  ; Step 1:  Read contents of EnvVarName from RegLoc
+  ;
+  ; Check for empty EnvVarName
+  ${If} $1 == ""
+    SetErrors
+    DetailPrint "ERROR: EnvVarName is blank"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Check for valid Action
+  ${If}    $2 != "A"
+  ${AndIf} $2 != "P"
+  ${AndIf} $2 != "R"
+    SetErrors
+    DetailPrint "ERROR: Invalid Action - must be A, P, or R"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ${If} $3 == HKLM
+    ReadRegStr $5 ${hklm_all_users} $1     ; Get EnvVarName from all users into $5
+  ${ElseIf} $3 == HKCU
+    ReadRegStr $5 ${hkcu_current_user} $1  ; Read EnvVarName from current user into $5
+  ${Else}
+    SetErrors
+    DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Check for empty PathString
+  ${If} $4 == ""
+    SetErrors
+    DetailPrint "ERROR: PathString is blank"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+  
+  ;; From http://nsis.sourceforge.net/Environmental_Variables:_append,_prepend,_and_remove_entries
+  ;; faa - remove check for empty original
+  ;; khc - here check if length is going to be greater then max string length
+  ;;       and abort if so - also abort if original path empty - may mean
+  ;;       it was too long as well- write message to say set it by hand 
+   Push $6
+   Push $7
+   Push $8
+   StrLen $7 $4  
+   StrLen $6 $5
+   IntOp $8 $6 + $7
+;;   ${If} $5 == ""  ;; faa
+;;   ${OrIf} $8 >= ${NSIS_MAX_STRLEN}  ;; faa
+   ${If} $8 >= ${NSIS_MAX_STRLEN}
+     SetErrors
+     DetailPrint "Current $1 length ($6) too long to modify in NSIS; set manually if needed"
+     Pop $8
+     Pop $7
+     Pop $6
+     Goto EnvVarUpdate_Restore_Vars
+   ${EndIf}
+   Pop $8
+   Pop $7
+   Pop $6
+ ;;khc 
+
+  ; Make sure we've got some work to do
+  ${If} $5 == ""
+  ${AndIf} $2 == "R"
+    SetErrors
+    DetailPrint "$1 is empty - Nothing to remove"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Step 2: Scrub EnvVar
+  ;
+  StrCpy $0 $5                             ; Copy the contents to $0
+  ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
+  ; after the last one are not removed here but instead in Step 3)
+  ${If} $0 != ""                           ; If EnvVar is not empty ...
+    ${Do}
+      ${${UN}StrStr} $7 $0 " ;"
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 " ;" ";"         ; Remove '<space>;'
+    ${Loop}
+    ${Do}
+      ${${UN}StrStr} $7 $0 "; "
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 "; " ";"         ; Remove ';<space>'
+    ${Loop}
+    ${Do}
+      ${${UN}StrStr} $7 $0 ";;" 
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 ";;" ";"
+    ${Loop}
+ 
+    ; Remove a leading or trailing semicolon from EnvVar
+    StrCpy  $7  $0 1 0
+    ${If} $7 == ";"
+      StrCpy $0  $0 "" 1                   ; Change ';<EnvVar>' to '<EnvVar>'
+    ${EndIf}
+    StrLen $6 $0
+    IntOp $6 $6 - 1
+    StrCpy $7  $0 1 $6
+    ${If} $7 == ";"
+     StrCpy $0  $0 $6                      ; Change ';<EnvVar>' to '<EnvVar>'
+    ${EndIf}
+    ; DetailPrint "Scrubbed $1: [$0]"      ; Uncomment to debug
+  ${EndIf}
+ 
+  /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
+     $6 = bool flag (1 = found and removed PathString)
+     $7 = a string (e.g. path) delimited by semicolon(s)
+     $8 = entry counter starting at 0
+     $9 = copy of $0
+     $R0 = tempChar      */
+ 
+  ${If} $5 != ""                           ; If EnvVar is not empty ...
+    StrCpy $9 $0
+    StrCpy $0 ""
+    StrCpy $8 0
+    StrCpy $6 0
+ 
+    ${Do}
+      ${${UN}StrTok} $7 $9 ";" $8 "0"      ; $7 = next entry, $8 = entry counter
+ 
+      ${If} $7 == ""                       ; If we've run out of entries,
+        ${ExitDo}                          ;    were done
+      ${EndIf}                             ;
+ 
+      ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
+      ${Do}
+        StrCpy $R0  $7 1
+        ${If} $R0 != " "
+          ${ExitDo}
+        ${EndIf}
+        StrCpy $7   $7 "" 1                ;  Remove leading space
+      ${Loop}
+      ${Do}
+        StrCpy $R0  $7 1 -1
+        ${If} $R0 != " "
+          ${ExitDo}
+        ${EndIf}
+        StrCpy $7   $7 -1                  ;  Remove trailing space
+      ${Loop}
+      ${If} $7 == $4                       ; If string matches, remove it by not appending it
+        StrCpy $6 1                        ; Set 'found' flag
+      ${ElseIf} $7 != $4                   ; If string does NOT match
+      ${AndIf}  $0 == ""                   ;    and the 1st string being added to $0,
+        StrCpy $0 $7                       ;    copy it to $0 without a prepended semicolon
+      ${ElseIf} $7 != $4                   ; If string does NOT match
+      ${AndIf}  $0 != ""                   ;    and this is NOT the 1st string to be added to $0,
+        StrCpy $0 $0;$7                    ;    append path to $0 with a prepended semicolon
+      ${EndIf}                             ;
+ 
+      IntOp $8 $8 + 1                      ; Bump counter
+    ${Loop}                                ; Check for duplicates until we run out of paths
+  ${EndIf}
+ 
+  ; Step 4:  Perform the requested Action
+  ;
+  ${If} $2 != "R"                          ; If Append or Prepend
+    ${If} $6 == 1                          ; And if we found the target
+      DetailPrint "Target is already present in $1. It will be removed and"
+    ${EndIf}
+    ${If} $0 == ""                         ; If EnvVar is (now) empty
+      StrCpy $0 $4                         ;   just copy PathString to EnvVar
+      ${If} $6 == 0                        ; If found flag is either 0
+      ${OrIf} $6 == ""                     ; or blank (if EnvVarName is empty)
+        DetailPrint "$1 was empty and has been updated with the target"
+      ${EndIf}
+    ${ElseIf} $2 == "A"                    ;  If Append (and EnvVar is not empty),
+      StrCpy $0 $0;$4                      ;     append PathString
+      ${If} $6 == 1
+        DetailPrint "appended to $1"
+      ${Else}
+        DetailPrint "Target was appended to $1"
+      ${EndIf}
+    ${Else}                                ;  If Prepend (and EnvVar is not empty),
+      StrCpy $0 $4;$0                      ;     prepend PathString
+      ${If} $6 == 1
+        DetailPrint "prepended to $1"
+      ${Else}
+        DetailPrint "Target was prepended to $1"
+      ${EndIf}
+    ${EndIf}
+  ${Else}                                  ; If Action = Remove
+    ${If} $6 == 1                          ;   and we found the target
+      DetailPrint "Target was found and removed from $1"
+    ${Else}
+      DetailPrint "Target was NOT found in $1 (nothing to remove)"
+    ${EndIf}
+    ${If} $0 == ""
+      DetailPrint "$1 is now empty"
+    ${EndIf}
+  ${EndIf}
+ 
+  ; Step 5:  Update the registry at RegLoc with the updated EnvVar and announce the change
+  ;
+  ClearErrors
+  ${If} $3  == HKLM
+    WriteRegExpandStr ${hklm_all_users} $1 $0     ; Write it in all users section
+  ${ElseIf} $3 == HKCU
+    WriteRegExpandStr ${hkcu_current_user} $1 $0  ; Write it to current user section
+  ${EndIf}
+ 
+  IfErrors 0 +4
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
+    DetailPrint "Could not write updated $1 to $3"
+    Goto EnvVarUpdate_Restore_Vars
+ 
+  ; "Export" our change
+  SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ 
+  EnvVarUpdate_Restore_Vars:
+  ;
+  ; Restore the user's variables and return ResultVar
+  Pop $R0
+  Pop $9
+  Pop $8
+  Pop $7
+  Pop $6
+  Pop $5
+  Pop $4
+  Pop $3
+  Pop $2
+  Pop $1
+  Push $0  ; Push my $0 (ResultVar)
+  Exch
+  Pop $0   ; Restore his $0
+ 
+FunctionEnd
+ 
+!macroend   ; EnvVarUpdate UN
+!insertmacro EnvVarUpdate ""
+!insertmacro EnvVarUpdate "un."
+;----------------------------------- EnvVarUpdate end----------------------------------------
+ 
+!verbose pop
+!endif
+; --- end local mod ---
+
+
+;--------------------------------
+; You must define these values
+
+  !define VERSION "@CPACK_PACKAGE_VERSION@"
+  !define PATCH  "@CPACK_PACKAGE_VERSION_PATCH@"
+  !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
+
+;--------------------------------
+;Variables
+
+  Var MUI_TEMP
+  Var STARTMENU_FOLDER
+  Var SV_ALLUSERS
+  Var START_MENU
+  Var DO_NOT_ADD_TO_PATH
+  Var ADD_TO_PATH_ALL_USERS
+  Var ADD_TO_PATH_CURRENT_USER
+  Var INSTALL_DESKTOP
+  Var IS_DEFAULT_INSTALLDIR
+;--------------------------------
+;Include Modern UI
+
+  !include "MUI.nsh"
+
+  ;Default installation folder
+  InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+;--------------------------------
+;General
+
+  ;Name and file
+  Name "@CPACK_NSIS_PACKAGE_NAME@"
+  OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
+
+  ;Set compression
+  SetCompressor @CPACK_NSIS_COMPRESSOR@
+
+ at CPACK_NSIS_DEFINES@   
+
+  !include Sections.nsh
+
+;--- Component support macros: ---
+; The code for the add/remove functionality is from:
+;   http://nsis.sourceforge.net/Add/Remove_Functionality
+; It has been modified slightly and extended to provide
+; inter-component dependencies.
+Var AR_SecFlags
+Var AR_RegFlags
+ at CPACK_NSIS_SECTION_SELECTED_VARS@
+
+; Loads the "selected" flag for the section named SecName into the
+; variable VarName.
+!macro LoadSectionSelectedIntoVar SecName VarName
+ SectionGetFlags ${${SecName}} $${VarName}
+ IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits
+!macroend
+
+; Loads the value of a variable... can we get around this?
+!macro LoadVar VarName
+  IntOp $R0 0 + $${VarName}
+!macroend
+
+; Sets the value of a variable
+!macro StoreVar VarName IntValue
+  IntOp $${VarName} 0 + ${IntValue}
+!macroend
+
+!macro InitSection SecName
+  ;  This macro reads component installed flag from the registry and
+  ;changes checked state of the section on the components page.
+  ;Input: section index constant name specified in Section command.
+   
+  ClearErrors
+  ;Reading component status from registry
+  ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed"
+  IfErrors "default_${SecName}"
+    ;Status will stay default if registry value not found
+    ;(component was never installed)
+  IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits
+  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags
+  IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off
+  IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit
+
+  ; Note whether this component was installed before
+  !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags
+  IntOp $R0 $AR_RegFlags & $AR_RegFlags
+  
+  ;Writing modified flags
+  SectionSetFlags ${${SecName}} $AR_SecFlags
+  
+ "default_${SecName}:"
+ !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
+!macroend
+ 
+!macro FinishSection SecName
+  ;  This macro reads section flag set by user and removes the section
+  ;if it is not selected.
+  ;Then it writes component installed flag to registry
+  ;Input: section index constant name specified in Section command.
+ 
+  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags
+  ;Checking lowest bit:
+  IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
+  IntCmp $AR_SecFlags 1 "leave_${SecName}"
+    ;Section is not selected:
+    ;Calling Section uninstall macro and writing zero installed flag
+    !insertmacro "Remove_${${SecName}}"
+    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
+  "Installed" 0
+    Goto "exit_${SecName}"
+ 
+ "leave_${SecName}:"
+    ;Section is selected:
+    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
+  "Installed" 1
+ 
+ "exit_${SecName}:"
+!macroend
+ 
+!macro RemoveSection SecName
+  ;  This macro is used to call section's Remove_... macro
+  ;from the uninstaller.
+  ;Input: section index constant name specified in Section command.
+ 
+  !insertmacro "Remove_${${SecName}}"
+!macroend
+
+; Determine whether the selection of SecName changed
+!macro MaybeSelectionChanged SecName
+  !insertmacro LoadVar ${SecName}_selected
+  SectionGetFlags ${${SecName}} $R1
+  IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits
+  
+  ; See if the status has changed:
+  IntCmp $R0 $R1 "${SecName}_unchanged"
+  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
+  
+  IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected"
+  !insertmacro "Deselect_required_by_${SecName}"
+  goto "${SecName}_unchanged"
+  
+  "${SecName}_was_selected:"
+  !insertmacro "Select_${SecName}_depends"
+  
+  "${SecName}_unchanged:"
+!macroend
+;--- End of Add/Remove macros ---
+
+;--------------------------------
+;Interface Settings
+
+  !define MUI_HEADERIMAGE
+  !define MUI_ABORTWARNING
+    
+;--------------------------------
+; path functions
+
+!verbose 3
+!include "WinMessages.NSH"
+!verbose 4
+
+;----------------------------------------
+; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02"
+;----------------------------------------
+!verbose 3
+!include "WinMessages.NSH"
+!verbose 4
+;====================================================
+; get_NT_environment 
+;     Returns: the selected environment
+;     Output : head of the stack
+;====================================================
+!macro select_NT_profile UN
+Function ${UN}select_NT_profile
+   StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single
+      DetailPrint "Selected environment for all users"
+      Push "all"
+      Return
+   environment_single:
+      DetailPrint "Selected environment for current user only."
+      Push "current"
+      Return
+FunctionEnd
+!macroend
+!insertmacro select_NT_profile ""
+!insertmacro select_NT_profile "un."
+;----------------------------------------------------
+!define NT_current_env 'HKCU "Environment"'
+!define NT_all_env     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+
+!ifndef WriteEnvStr_RegKey
+  !ifdef ALL_USERS
+    !define WriteEnvStr_RegKey \
+       'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+  !else
+    !define WriteEnvStr_RegKey 'HKCU "Environment"'
+  !endif
+!endif
+ 
+; AddToPath - Adds the given dir to the search path.
+;        Input - head of the stack
+;        Note - Win9x systems requires reboot
+ 
+Function AddToPath
+  Exch $0
+  Push $1
+  Push $2
+  Push $3
+ 
+  # don't add if the path doesn't exist
+  IfFileExists "$0\*.*" "" AddToPath_done
+ 
+  ReadEnvStr $1 PATH
+  ; if the path is too long for a NSIS variable NSIS will return a 0 
+  ; length string.  If we find that, then warn and skip any path
+  ; modification as it will trash the existing path.
+  StrLen $2 $1
+  IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done
+    CheckPathLength_ShowPathWarning:
+    Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!"
+    Goto AddToPath_done
+  CheckPathLength_Done:
+  Push "$1;"
+  Push "$0;"
+  Call StrStr1
+  Pop $2
+  StrCmp $2 "" "" AddToPath_done
+  Push "$1;"
+  Push "$0\;"
+  Call StrStr1
+  Pop $2
+  StrCmp $2 "" "" AddToPath_done
+  GetFullPathName /SHORT $3 $0
+  Push "$1;"
+  Push "$3;"
+  Call StrStr1
+  Pop $2
+  StrCmp $2 "" "" AddToPath_done
+  Push "$1;"
+  Push "$3\;"
+  Call StrStr1
+  Pop $2
+  StrCmp $2 "" "" AddToPath_done
+ 
+  Call IsNT
+  Pop $1
+  StrCmp $1 1 AddToPath_NT
+    ; Not on NT
+    StrCpy $1 $WINDIR 2
+    FileOpen $1 "$1\autoexec.bat" a
+    FileSeek $1 -1 END
+    FileReadByte $1 $2
+    IntCmp $2 26 0 +2 +2 # DOS EOF
+      FileSeek $1 -1 END # write over EOF
+    FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n"
+    FileClose $1
+    SetRebootFlag true
+    Goto AddToPath_done
+ 
+  AddToPath_NT:
+    StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey
+      ReadRegStr $1 ${NT_current_env} "PATH"
+      Goto DoTrim
+    ReadAllKey:
+      ReadRegStr $1 ${NT_all_env} "PATH"
+    DoTrim:
+    StrCmp $1 "" AddToPath_NTdoIt
+      Push $1
+      Call Trim
+      Pop $1
+      StrCpy $0 "$1;$0"
+    AddToPath_NTdoIt:
+      StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey
+        WriteRegExpandStr ${NT_current_env} "PATH" $0
+        Goto DoSend
+      WriteAllKey:
+        WriteRegExpandStr ${NT_all_env} "PATH" $0
+      DoSend:
+      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ 
+  AddToPath_done:
+    Pop $3
+    Pop $2
+    Pop $1
+    Pop $0
+FunctionEnd
+
+ 
+; RemoveFromPath - Remove a given dir from the path
+;     Input: head of the stack
+ 
+Function un.RemoveFromPath
+  Exch $0
+  Push $1
+  Push $2
+  Push $3
+  Push $4
+  Push $5
+  Push $6
+ 
+  IntFmt $6 "%c" 26 # DOS EOF
+ 
+  Call un.IsNT
+  Pop $1
+  StrCmp $1 1 unRemoveFromPath_NT
+    ; Not on NT
+    StrCpy $1 $WINDIR 2
+    FileOpen $1 "$1\autoexec.bat" r
+    GetTempFileName $4
+    FileOpen $2 $4 w
+    GetFullPathName /SHORT $0 $0
+    StrCpy $0 "SET PATH=%PATH%;$0"
+    Goto unRemoveFromPath_dosLoop
+ 
+    unRemoveFromPath_dosLoop:
+      FileRead $1 $3
+      StrCpy $5 $3 1 -1 # read last char
+      StrCmp $5 $6 0 +2 # if DOS EOF
+        StrCpy $3 $3 -1 # remove DOS EOF so we can compare
+      StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine
+      StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine
+      StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine
+      StrCmp $3 "" unRemoveFromPath_dosLoopEnd
+      FileWrite $2 $3
+      Goto unRemoveFromPath_dosLoop
+      unRemoveFromPath_dosLoopRemoveLine:
+        SetRebootFlag true
+        Goto unRemoveFromPath_dosLoop
+ 
+    unRemoveFromPath_dosLoopEnd:
+      FileClose $2
+      FileClose $1
+      StrCpy $1 $WINDIR 2
+      Delete "$1\autoexec.bat"
+      CopyFiles /SILENT $4 "$1\autoexec.bat"
+      Delete $4
+      Goto unRemoveFromPath_done
+ 
+  unRemoveFromPath_NT:
+    StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey
+      ReadRegStr $1 ${NT_current_env} "PATH"
+      Goto unDoTrim
+    unReadAllKey:
+      ReadRegStr $1 ${NT_all_env} "PATH"
+    unDoTrim:
+    StrCpy $5 $1 1 -1 # copy last char
+    StrCmp $5 ";" +2 # if last char != ;
+      StrCpy $1 "$1;" # append ;
+    Push $1
+    Push "$0;"
+    Call un.StrStr1 ; Find `$0;` in $1
+    Pop $2 ; pos of our dir
+    StrCmp $2 "" unRemoveFromPath_done
+      ; else, it is in path
+      # $0 - path to add
+      # $1 - path var
+      StrLen $3 "$0;"
+      StrLen $4 $2
+      StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
+      StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
+      StrCpy $3 $5$6
+ 
+      StrCpy $5 $3 1 -1 # copy last char
+      StrCmp $5 ";" 0 +2 # if last char == ;
+        StrCpy $3 $3 -1 # remove last char
+ 
+      StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey
+        WriteRegExpandStr ${NT_current_env} "PATH" $3
+        Goto unDoSend
+      unWriteAllKey:
+        WriteRegExpandStr ${NT_all_env} "PATH" $3
+      unDoSend:
+      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ 
+  unRemoveFromPath_done:
+    Pop $6
+    Pop $5
+    Pop $4
+    Pop $3
+    Pop $2
+    Pop $1
+    Pop $0
+FunctionEnd
+ 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Uninstall sutff
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+###########################################
+#            Utility Functions            #
+###########################################
+ 
+;====================================================
+; IsNT - Returns 1 if the current system is NT, 0
+;        otherwise.
+;     Output: head of the stack
+;====================================================
+; IsNT
+; no input
+; output, top of the stack = 1 if NT or 0 if not
+;
+; Usage:
+;   Call IsNT
+;   Pop $R0
+;  ($R0 at this point is 1 or 0)
+ 
+!macro IsNT un
+Function ${un}IsNT
+  Push $0
+  ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
+  StrCmp $0 "" 0 IsNT_yes
+  ; we are not NT.
+  Pop $0
+  Push 0
+  Return
+ 
+  IsNT_yes:
+    ; NT!!!
+    Pop $0
+    Push 1
+FunctionEnd
+!macroend
+!insertmacro IsNT ""
+!insertmacro IsNT "un."
+ 
+; StrStr1
+; input, top of stack = string to search for
+;        top of stack-1 = string to search in
+; output, top of stack (replaces with the portion of the string remaining)
+; modifies no other variables.
+;
+; Usage:
+;   Push "this is a long ass string"
+;   Push "ass"
+;   Call StrStr1
+;   Pop $R0
+;  ($R0 at this point is "ass string")
+ 
+!macro StrStr1 un
+Function ${un}StrStr1
+Exch $R1 ; st=haystack,old$R1, $R1=needle
+  Exch    ; st=old$R1,haystack
+  Exch $R2 ; st=old$R1,old$R2, $R2=haystack
+  Push $R3
+  Push $R4
+  Push $R5
+  StrLen $R3 $R1
+  StrCpy $R4 0
+  ; $R1=needle
+  ; $R2=haystack
+  ; $R3=len(needle)
+  ; $R4=cnt
+  ; $R5=tmp
+  loop:
+    StrCpy $R5 $R2 $R3 $R4
+    StrCmp $R5 $R1 done
+    StrCmp $R5 "" done
+    IntOp $R4 $R4 + 1
+    Goto loop
+done:
+  StrCpy $R1 $R2 "" $R4
+  Pop $R5
+  Pop $R4
+  Pop $R3
+  Pop $R2
+  Exch $R1
+FunctionEnd
+!macroend
+!insertmacro StrStr1 ""
+!insertmacro StrStr1 "un."
+
+Function Trim ; Added by Pelaca
+	Exch $R1
+	Push $R2
+Loop:
+	StrCpy $R2 "$R1" 1 -1
+	StrCmp "$R2" " " RTrim
+	StrCmp "$R2" "$\n" RTrim
+	StrCmp "$R2" "$\r" RTrim
+	StrCmp "$R2" ";" RTrim
+	GoTo Done
+RTrim:	
+	StrCpy $R1 "$R1" -1
+	Goto Loop
+Done:
+	Pop $R2
+	Exch $R1
+FunctionEnd
+
+Function ConditionalAddToRegisty
+  Pop $0
+  Pop $1
+  StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
+    WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \
+    "$1" "$0"
+    ;MessageBox MB_OK "Set Registry: '$1' to '$0'"
+    DetailPrint "Set install registry entry: '$1' to '$0'"
+  ConditionalAddToRegisty_EmptyString:
+FunctionEnd
+
+;--------------------------------
+
+!ifdef CPACK_USES_DOWNLOAD
+Function DownloadFile
+    IfFileExists $INSTDIR\* +2
+    CreateDirectory $INSTDIR
+    Pop $0
+
+    ; Skip if already downloaded
+    IfFileExists $INSTDIR\$0 0 +2
+    Return
+
+    StrCpy $1 "@CPACK_DOWNLOAD_SITE@"
+
+  try_again:
+    NSISdl::download "$1/$0" "$INSTDIR\$0"
+    
+    Pop $1
+    StrCmp $1 "success" success
+    StrCmp $1 "Cancelled" cancel
+    MessageBox MB_OK "Download failed: $1"
+  cancel:
+    Return
+  success:
+FunctionEnd
+!endif
+
+;--------------------------------
+; Installation types
+ at CPACK_NSIS_INSTALLATION_TYPES@
+
+;--------------------------------
+; Component sections
+ at CPACK_NSIS_COMPONENT_SECTIONS@
+
+;--------------------------------
+; Define some macro setting for the gui
+ at CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
+ at CPACK_NSIS_INSTALLER_ICON_CODE@
+ at CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@
+ at CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@
+
+;--------------------------------
+;Pages
+  !insertmacro MUI_PAGE_WELCOME
+
+  !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
+  Page custom InstallOptionsPage
+  !insertmacro MUI_PAGE_DIRECTORY
+  
+  ;Start Menu Folder Page Configuration
+  !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" 
+  !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" 
+  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
+
+  @CPACK_NSIS_PAGE_COMPONENTS@
+
+  !insertmacro MUI_PAGE_INSTFILES
+  !insertmacro MUI_PAGE_FINISH
+
+  !insertmacro MUI_UNPAGE_CONFIRM
+  !insertmacro MUI_UNPAGE_INSTFILES
+
+;--------------------------------
+;Languages
+
+  !insertmacro MUI_LANGUAGE "English" ;first language is the default language
+  !insertmacro MUI_LANGUAGE "Albanian"
+  !insertmacro MUI_LANGUAGE "Arabic"
+  !insertmacro MUI_LANGUAGE "Basque"
+  !insertmacro MUI_LANGUAGE "Belarusian"
+  !insertmacro MUI_LANGUAGE "Bosnian"
+  !insertmacro MUI_LANGUAGE "Breton"
+  !insertmacro MUI_LANGUAGE "Bulgarian"
+  !insertmacro MUI_LANGUAGE "Croatian"
+  !insertmacro MUI_LANGUAGE "Czech"
+  !insertmacro MUI_LANGUAGE "Danish"
+  !insertmacro MUI_LANGUAGE "Dutch"
+  !insertmacro MUI_LANGUAGE "Estonian"
+  !insertmacro MUI_LANGUAGE "Farsi"
+  !insertmacro MUI_LANGUAGE "Finnish"
+  !insertmacro MUI_LANGUAGE "French"
+  !insertmacro MUI_LANGUAGE "German"
+  !insertmacro MUI_LANGUAGE "Greek"
+  !insertmacro MUI_LANGUAGE "Hebrew"
+  !insertmacro MUI_LANGUAGE "Hungarian"
+  !insertmacro MUI_LANGUAGE "Icelandic"
+  !insertmacro MUI_LANGUAGE "Indonesian"
+  !insertmacro MUI_LANGUAGE "Irish"
+  !insertmacro MUI_LANGUAGE "Italian"
+  !insertmacro MUI_LANGUAGE "Japanese"
+  !insertmacro MUI_LANGUAGE "Korean"
+  !insertmacro MUI_LANGUAGE "Kurdish"
+  !insertmacro MUI_LANGUAGE "Latvian"
+  !insertmacro MUI_LANGUAGE "Lithuanian"
+  !insertmacro MUI_LANGUAGE "Luxembourgish"
+  !insertmacro MUI_LANGUAGE "Macedonian"
+  !insertmacro MUI_LANGUAGE "Malay"
+  !insertmacro MUI_LANGUAGE "Mongolian"
+  !insertmacro MUI_LANGUAGE "Norwegian"
+  !insertmacro MUI_LANGUAGE "Polish"
+  !insertmacro MUI_LANGUAGE "Portuguese"
+  !insertmacro MUI_LANGUAGE "PortugueseBR"
+  !insertmacro MUI_LANGUAGE "Romanian"
+  !insertmacro MUI_LANGUAGE "Russian"
+  !insertmacro MUI_LANGUAGE "Serbian"
+  !insertmacro MUI_LANGUAGE "SerbianLatin"
+  !insertmacro MUI_LANGUAGE "SimpChinese"
+  !insertmacro MUI_LANGUAGE "Slovak"
+  !insertmacro MUI_LANGUAGE "Slovenian"
+  !insertmacro MUI_LANGUAGE "Spanish"
+  !insertmacro MUI_LANGUAGE "Swedish"
+  !insertmacro MUI_LANGUAGE "Thai"
+  !insertmacro MUI_LANGUAGE "TradChinese"
+  !insertmacro MUI_LANGUAGE "Turkish"
+  !insertmacro MUI_LANGUAGE "Ukrainian"
+  !insertmacro MUI_LANGUAGE "Welsh"
+
+
+;--------------------------------
+;Reserve Files
+
+  ;These files should be inserted before other files in the data block
+  ;Keep these lines before any File command
+  ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)
+
+  ReserveFile "NSIS.InstallOptions.ini"
+  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
+
+;--------------------------------
+;Installer Sections
+
+Section "-Core installation"
+  ;Use the entire tree produced by the INSTALL target.  Keep the
+  ;list of directories here in sync with the RMDir commands below.
+  SetOutPath "$INSTDIR"
+  @CPACK_NSIS_FULL_INSTALL@
+  
+  ;Store installation folder
+  WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
+  
+  ;Create uninstaller
+  WriteUninstaller "$INSTDIR\Uninstall.exe"
+  Push "DisplayName"
+  Push "@CPACK_NSIS_DISPLAY_NAME@"
+  Call ConditionalAddToRegisty
+  Push "DisplayVersion"
+  Push "@CPACK_PACKAGE_VERSION@"
+  Call ConditionalAddToRegisty
+  Push "Publisher"
+  Push "@CPACK_PACKAGE_VENDOR@"
+  Call ConditionalAddToRegisty
+  Push "UninstallString"
+  Push "$INSTDIR\Uninstall.exe"
+  Call ConditionalAddToRegisty
+  Push "NoRepair"
+  Push "1"
+  Call ConditionalAddToRegisty
+  
+  !ifdef CPACK_NSIS_ADD_REMOVE
+  ;Create add/remove functionality
+  Push "ModifyPath"
+  Push "$INSTDIR\AddRemove.exe"
+  Call ConditionalAddToRegisty
+  !else
+  Push "NoModify"
+  Push "1"
+  Call ConditionalAddToRegisty
+  !endif
+  
+  ; Optional registration
+  Push "DisplayIcon"
+  Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
+  Call ConditionalAddToRegisty
+  Push "HelpLink"
+  Push "@CPACK_NSIS_HELP_LINK@"
+  Call ConditionalAddToRegisty
+  Push "URLInfoAbout"
+  Push "@CPACK_NSIS_URL_INFO_ABOUT@"
+  Call ConditionalAddToRegisty
+  Push "Contact"
+  Push "@CPACK_NSIS_CONTACT@"
+  Call ConditionalAddToRegisty
+  !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State"
+  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+  
+  ;Create shortcuts
+  CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
+ at CPACK_NSIS_CREATE_ICONS@
+ at CPACK_NSIS_CREATE_ICONS_EXTRA@
+  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
+
+  ;Read a value from an InstallOptions INI file
+  !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State"
+  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State"
+  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State"
+
+  ; Write special uninstall registry entries
+  Push "StartMenu"
+  Push "$STARTMENU_FOLDER"
+  Call ConditionalAddToRegisty
+  Push "DoNotAddToPath"
+  Push "$DO_NOT_ADD_TO_PATH"
+  Call ConditionalAddToRegisty
+  Push "AddToPathAllUsers"
+  Push "$ADD_TO_PATH_ALL_USERS"
+  Call ConditionalAddToRegisty
+  Push "AddToPathCurrentUser"
+  Push "$ADD_TO_PATH_CURRENT_USER"
+  Call ConditionalAddToRegisty
+  Push "InstallToDesktop"
+  Push "$INSTALL_DESKTOP"
+  Call ConditionalAddToRegisty
+
+  !insertmacro MUI_STARTMENU_WRITE_END
+
+ at CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
+
+SectionEnd
+
+Section "-Add to path"
+  Push $INSTDIR\bin
+  StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
+  StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0  
+    Call AddToPath
+  doNotAddToPath:
+SectionEnd
+
+;--------------------------------
+; Create custom pages
+Function InstallOptionsPage
+  !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@"
+  !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini"
+
+FunctionEnd
+
+;--------------------------------
+; determine admin versus local install
+Function un.onInit
+
+  ClearErrors
+  UserInfo::GetName
+  IfErrors noLM
+  Pop $0
+  UserInfo::GetAccountType
+  Pop $1
+  StrCmp $1 "Admin" 0 +3
+    SetShellVarContext all
+    ;MessageBox MB_OK 'User "$0" is in the Admin group'
+    Goto done
+  StrCmp $1 "Power" 0 +3
+    SetShellVarContext all
+    ;MessageBox MB_OK 'User "$0" is in the Power Users group'
+    Goto done
+    
+  noLM:
+    ;Get installation folder from registry if available
+
+  done:
+    
+FunctionEnd
+
+;--- Add/Remove callback functions: ---
+!macro SectionList MacroName
+  ;This macro used to perform operation on multiple sections.
+  ;List all of your components in following manner here.
+ at CPACK_NSIS_COMPONENT_SECTION_LIST@
+!macroend
+ 
+Section -FinishComponents
+  ;Removes unselected components and writes component status to registry
+  !insertmacro SectionList "FinishSection"
+  
+!ifdef CPACK_NSIS_ADD_REMOVE  
+  ; Get the name of the installer executable
+  System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'
+  StrCpy $R3 $R0
+  
+  ; Strip off the last 13 characters, to see if we have AddRemove.exe
+  StrLen $R1 $R0
+  IntOp $R1 $R0 - 13
+  StrCpy $R2 $R0 13 $R1
+  StrCmp $R2 "AddRemove.exe" addremove_installed
+  
+  ; We're not running AddRemove.exe, so install it
+  CopyFiles $R3 $INSTDIR\AddRemove.exe
+  
+  addremove_installed:
+!endif
+SectionEnd
+;--- End of Add/Remove callback functions ---
+
+;--------------------------------
+; Component dependencies
+Function .onSelChange
+  !insertmacro SectionList MaybeSelectionChanged
+FunctionEnd
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+  ReadRegStr $START_MENU SHCTX \
+   "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu"
+  ;MessageBox MB_OK "Start menu is in: $START_MENU"
+  ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \
+    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath"
+  ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \
+    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers"
+  ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \
+    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser"
+  ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
+  ReadRegStr $INSTALL_DESKTOP SHCTX \
+    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop"
+  ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "
+
+ at CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@
+
+  ;Remove files we installed.
+  ;Keep the list of directories here in sync with the File commands above.
+ at CPACK_NSIS_DELETE_FILES@
+ at CPACK_NSIS_DELETE_DIRECTORIES@
+
+!ifdef CPACK_NSIS_ADD_REMOVE  
+  ;Remove the add/remove program
+  Delete "$INSTDIR\AddRemove.exe"
+!endif
+
+  ;Remove the uninstaller itself.
+  Delete "$INSTDIR\Uninstall.exe"
+  DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+  ;Remove the installation directory if it is empty.
+  RMDir "$INSTDIR"
+
+  ; Remove the registry entries.
+  DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+  ; Removes all optional components
+  !insertmacro SectionList "RemoveSection"
+  
+  !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
+    
+  Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
+ at CPACK_NSIS_DELETE_ICONS@
+ at CPACK_NSIS_DELETE_ICONS_EXTRA@
+  
+  ;Delete empty start menu parent diretories
+  StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
+ 
+  startMenuDeleteLoop:
+    ClearErrors
+    RMDir $MUI_TEMP
+    GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
+    
+    IfErrors startMenuDeleteLoopDone
+  
+    StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop
+  startMenuDeleteLoopDone:
+
+  ; If the user changed the shortcut, then untinstall may not work. This should
+  ; try to fix it.
+  StrCpy $MUI_TEMP "$START_MENU"
+  Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
+ at CPACK_NSIS_DELETE_ICONS_EXTRA@
+  
+  ;Delete empty start menu parent diretories
+  StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
+ 
+  secondStartMenuDeleteLoop:
+    ClearErrors
+    RMDir $MUI_TEMP
+    GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
+    
+    IfErrors secondStartMenuDeleteLoopDone
+  
+    StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop
+  secondStartMenuDeleteLoopDone:
+
+  DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+  Push $INSTDIR\bin
+  StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
+    Call un.RemoveFromPath
+  doNotRemoveFromPath:
+SectionEnd
+
+;--------------------------------
+; determine admin versus local install
+; Is install for "AllUsers" or "JustMe"?
+; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
+; This function is used for the very first "custom page" of the installer.
+; This custom page does not show up visibly, but it executes prior to the
+; first visible page and sets up $INSTDIR properly...
+; Choose different default installation folder based on SV_ALLUSERS...
+; "Program Files" for AllUsers, "My Documents" for JustMe...
+
+Function .onInit
+; --- begin local mod ---
+  IfSilent +7
+    IfFileExists $INSTDIR\uninstall.exe +4 0 ;If there is an uninstall.exe, then the machine is already using the new installers, which is fine, so continue
+	  IfFileExists $INSTDIR\*.* 0 +3 ; The user appears not to have the uninstaller.exe and already has an install directory, indicates old installer is present
+        MessageBox MB_YESNO "This looks like your first install with the new installer. Have you removed the previous install?$\r$\n$\r$\nIf you have not yet removed NeXus, click No, which aborts the install, and then remove it using Windows program manager." IDYES NoAbort
+        Abort "Cancelled. Remove old NeXus install then retry."
+      NoAbort:
+    MessageBox MB_OK "NeXus installer will try to run any existing uninstallers first. Please click OK and be patient, the installer will start soon"
+    ExecWait '"$INSTDIR\uninstall.exe" /S _?=$INSTDIR'
+; --- end local mod ---
+
+  ; Reads components status for registry
+  !insertmacro SectionList "InitSection"
+
+  ; check to see if /D has been used to change 
+  ; the install directory by comparing it to the 
+  ; install directory that is expected to be the
+  ; default
+  StrCpy $IS_DEFAULT_INSTALLDIR 0
+  StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2
+    StrCpy $IS_DEFAULT_INSTALLDIR 1
+  
+  StrCpy $SV_ALLUSERS "JustMe"
+  ; if default install dir then change the default
+  ; if it is installed for JustMe
+  StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
+    StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+  ClearErrors
+  UserInfo::GetName
+  IfErrors noLM
+  Pop $0
+  UserInfo::GetAccountType
+  Pop $1
+  StrCmp $1 "Admin" 0 +4
+    SetShellVarContext all
+    ;MessageBox MB_OK 'User "$0" is in the Admin group'
+    StrCpy $SV_ALLUSERS "AllUsers"
+    Goto done
+  StrCmp $1 "Power" 0 +4
+    SetShellVarContext all
+    ;MessageBox MB_OK 'User "$0" is in the Power Users group'
+    StrCpy $SV_ALLUSERS "AllUsers"
+    Goto done
+    
+  noLM:
+    StrCpy $SV_ALLUSERS "AllUsers"
+    ;Get installation folder from registry if available
+
+  done:
+  StrCmp $SV_ALLUSERS "AllUsers" 0 +3
+    StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
+      StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+  StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage
+    !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini"
+
+  noOptionsPage:
+FunctionEnd
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..5d1d7a9
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,977 @@
+dnl====================================================================
+dnl  NeXus - Neutron & X-ray Common Data Format
+dnl  
+dnl  Autoconf (configure script) generation file
+dnl  
+dnl  $Id$
+dnl
+dnl  Copyright (C) 2004 Freddie Akeroyd
+dnl  
+dnl  This library is free software; you can redistribute it and/or
+dnl  modify it under the terms of the GNU Lesser General Public
+dnl  License as published by the Free Software Foundation; either
+dnl  version 2 of the License, or (at your option) any later version.
+dnl 
+dnl  This library is distributed in the hope that it will be useful,
+dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl  Lesser General Public License for more details.
+dnl 
+dnl  You should have received a copy of the GNU Lesser General Public
+dnl  License along with this library; if not, write to the Free 
+dnl  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+dnl  MA  02111-1307  USA
+dnl             
+dnl  For further information, see <http://www.nexusformat.org>
+dnl
+dnl                       -*- Autoconf -*-
+dnl Process this file with autoconf to produce a configure script.
+dnl
+
+AC_PREREQ(2.61)
+AC_REVISION($Revision$)
+
+m4_define([ISODATE],m4_esyscmd([date +%Y%m%d | tr -d '\n' ]))dnl
+dnl m4_define([SVNREV],m4_esyscmd_s([`svnversion`]))
+m4_define([SVNREV],m4_esyscmd([if test -r svn_revision.txt; then cat svn_revision.txt; else svn info | grep Revision | awk '{print $2}' | tr -d '\n'; fi ]))dnl
+m4_define([SVN_RELEASE],m4_join([],ISODATE,[svn],SVNREV)))dnl
+
+## main version we are based on
+m4_define([NEXUS_VERSION],[4.3.2])dnl
+
+## things like  rc1   or  20100903svn1734
+m4_define([NEXUS_REL],SVN_RELEASE)dnl
+#m4_define([NEXUS_RELEASE],[rc1])dnl
+
+# 0.* for pre release; 1, 2, ... post releas
+m4_define([PACKAGE_REL],[0])dnl
+
+AC_INIT([NeXus Library], m4_join([],NEXUS_VERSION,[-],NEXUS_REL), [nexus-developers at nexusformat.org], [nexus])
+AC_COPYRIGHT([Copyright (C) 2004 NeXus International Advisory Committee
+This software is covered by the GNU LESSER GENERAL PUBLIC LICENSE
+see file COPYING for further information])
+
+m4_join([],[NEXUS_VERSION=],"NEXUS_VERSION")
+m4_join([],[NEXUS_RELEASE=],"NEXUS_REL")
+m4_join([],[SVN_REVISION=],"SVN_REVISION")
+m4_join([],[PACKAGE_RELEASE=],"PACKAGE_REL")
+AC_SUBST([NEXUS_VERSION])
+AC_SUBST([NEXUS_RELEASE])
+AC_SUBST([SVN_REVISION])
+AC_SUBST([PACKAGE_RELEASE])
+# AC_DEFINE([NEXUS_VERSION], "NEXUS_VERSION", [NeXus Version])dnl
+AC_DEFINE([NEXUS_RELEASE], ["NEXUS_REL"], [NeXus Release])dnl
+AC_DEFINE([PACKAGE_RELEASE], "PACKAGE_REL", [Package Release])dnl
+AC_DEFINE([SVN_REVISION], "SVNREV", [SVN Revision])dnl
+
+
+# used by libtool - need to get if from 4.3.0 better
+#NXLTVERSINFO="1:0:1"
+#NXLTVERSINFO="4:3:4"
+NXLTVERSINFO="5:0:5"
+
+AC_CONFIG_AUX_DIR(config)
+AC_CONFIG_SRCDIR([src/napi.c])
+AC_CANONICAL_TARGET
+AC_CANONICAL_BUILD
+
+dnl $EGREP is used in macros included from acinclude.m4
+AC_PROG_EGREP
+
+dnl check for correct autoconf version - the same check is done in autogen.sh
+if test ! -z "$srcdir"; then
+    . $srcdir/autoversion.sh
+else
+    . ./autoversion.sh
+fi
+
+FCFLAGS="$F90FLAGS $FCFLAGS" # for compatibility with nexus-3.0
+
+# default is tar-v7 but this only supports paths up to 99 characters
+# and the doxygen doc has longer than this.
+AM_INIT_AUTOMAKE([1.6 tar-pax])
+
+AC_SUBST(NXLTVERSINFO)
+
+AM_CONFIG_HEADER(include/nxconfig.h:include/nxconfig_h.in)
+
+AC_ARG_ENABLE([debug], AC_HELP_STRING([--enable-debug],[Turn off optimisation]), [enable_debug=$enableval],[enable_debug=no])
+
+AC_ARG_ENABLE([32bit], AC_HELP_STRING([--enable-32bit],[build 32bit binary on 64 bit computer]), [enable_32bit=$enableval],[enable_32bit=no])
+
+dnl Checks for programs.
+AC_ARG_WITH([cc], AC_HELP_STRING([--with-cc=c compiler], [Specify name of C compiler]),
+	[with_cc=$withval], [with_cc=yes])
+if test x"$with_cc" != x"no" ; then
+	if test x"$with_cc" != x"yes" ; then CC="$with_cc"; fi
+	AC_PROG_CC
+	dnl Check C compiler options
+	AC_CHECK_CPP_OPTION([-fno-common])
+else
+	AC_MSG_ERROR([You need a C compiler to compile this package])
+fi
+
+AC_ARG_WITH([cxx], AC_HELP_STRING([--with-cxx=c++ compiler], [Specify name of C++ compiler]), [with_cxx=$withval], [with_cxx=yes])
+if test x"$with_cxx" != x"no" ; then
+	if test x"$with_cxx" != x"yes" ; then CXX="$with_cxx"; fi
+	AC_PROG_CXX
+else
+	CXX=
+fi
+
+AC_SUBST(WITH_F77)
+AC_ARG_WITH([f77], AC_HELP_STRING([--with-f77=f77 compiler], [Specify name of FORTRAN 77 compiler]),
+	[], [with_f77=no])
+if test ! -z "$with_f77" -a x"$with_f77" != x"no" ; then
+	if test x"$with_f77" != x"yes" ; then F77="$with_f77"; fi
+	AC_PROG_F77
+	dnl Check FORTRAN compiler options
+	dnl 	AC_CHECK_F77_OPTION([-Wno-globals])
+	dnl 	AC_CHECK_F77_OPTION([-fno-common])  # use with caution
+	mytop=`pwd`
+	dnl get right F77 include option
+	AC_CHECK_F77_OPTION([-I$mytop/bindings/f77],[      INCLUDE 'napif.inc'])
+	FFLAGS="$FFLAGS -g"
+	AC_F77_LIBRARY_LDFLAGS
+	WITH_F77=yes
+else
+	F77=
+	WITH_F77=no
+fi
+
+AC_SUBST(WITH_F90)
+AC_ARG_WITH([f90], AC_HELP_STRING([--with-f90=f90 compiler], [Specify name of FORTRAN 90 compiler]),
+	[], [with_f90=no])
+if test ! -z "$with_f90" -a x"$with_f90" != x"no" ; then
+	if test x"$with_f90" = x"yes" ; then
+		AC_CHECK_PROGS(FC, [g95 gfortran f90 f95 ifort])
+	else
+		FC="$with_f90"
+		AC_CHECK_PROGS(FC, [$with_f90])
+	fi
+	dnl f90 has a "module path" option - hard to get as you really need a
+	dnl ready compiled module to point the option at so for now we are just
+	dnl check that the option takes a directory and the compiler works
+	mytop=`pwd`
+	FCFLAGS="$FCFLAGS -g -I$mytop/bindings/f90"
+	dnl AC_CHECK_F90_OPTION([-p $mytop/bindings/f90],[      INCLUDE 'NXmodule.f90'])
+	dnl AC_CHECK_F90_OPTION([-p $mytop/bindings/f90],[      INCLUDE 'NXmodule.f90'])
+	dnl AC_CHECK_F90_OPTION([-qextname])
+	AC_FC_LIBRARY_LDFLAGS
+#        if test x$with_f77=xno; then with_f77=$FC; fi
+#        if test x$with_f77=xno; then with_f77=yes; fi
+	WITH_F90=yes
+else
+	FC=
+	WITH_F90=no
+fi
+
+AC_ARG_WITH([matlabroot], AC_HELP_STRING([--with-matlabroot=path to matlab install dir], [Specify location of matlab installation directory]),
+        [], [with_matlabroot=no])
+if test x"$with_matlabroot" != x"no" ; then
+    MATLABROOT="$with_matlabroot"
+fi
+AC_PATH_PROG(MATLAB,matlab,[],[$MATLABROOT/bin:/usr/local/matlab/bin:/opt/matlab/bin:$PATH])
+if test x"$MATLABROOT" = x -a x"$MATLAB" != x; then
+    MATLABROOT=`dirname $MATLAB`/..
+fi
+
+dnl thread local storage
+AC_MSG_CHECKING([for __thread])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC__MINOR__ < 1) || (__GNUC__ == 4 && __GNUC__MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
+#endif], [static __thread int p = 0])],
+               [AC_DEFINE(HAVE_TLS, 1,
+                      Define to 1 if compiler supports __thread)
+                AC_MSG_RESULT([yes])],
+               [AC_MSG_RESULT([no])])
+
+java_host="linux"
+JAVAROOT=""
+AC_ARG_WITH([java-home], AC_HELP_STRING([--with-java-home=JAVA SDK Home], [Specify location of top directory of JAVA SDK i.e. where the bin, lib and include directories live]),
+	[], [with_java_home=$withval])
+AC_ARG_WITH([java], AC_HELP_STRING([--with-java=path to java executable], [Specify location of JAVA executable]),
+	[], [with_java=no])
+if test -z "$with_java_home" -a x$with_java != xno; then
+    def_javac=`which javac`
+    link_javac=`readlink -e "$def_javac"`
+    with_java_home=`dirname "$link_javac"`/..
+fi
+if test -d "$with_java_home"; then
+	JAVAROOT="$with_java_home"
+	AC_MSG_NOTICE([Java SDK home is $JAVAROOT])
+	JAVAINCLUDE="-I$JAVAROOT/include"
+	AC_PATH_PROGS(JAVAC,javac gcj,,[$JAVAROOT/bin])
+	if test `basename "$JAVAC"` = "gcj"; then
+	    JAVACFLAGS="-C"	# force creation of .class files
+	fi
+	AC_PATH_PROGS(JAVA,java gij,,[$JAVAROOT/bin])
+	AC_PATH_PROGS(JAVAH,javah gcjh,,[$JAVAROOT/bin])
+	AC_PATH_PROGS(JAVADOC,javadoc,,[$JAVAROOT/bin:$PATH])
+	AC_PATH_PROGS(JAR,jar fastjar,,[$JAVAROOT/bin:$PATH])
+	AX_CHECK_JUNIT
+fi
+
+AC_ARG_WITH([contrib], AC_HELP_STRING([--with-contrib=names_of_apps_to_build], [Specify a list of targets from the contrib directory to build]),
+	[CONTRIB=$withval], [CONTRIB=no])
+AM_CONDITIONAL(BUILD_CONTRIB, [test "$CONTRIB" != "no"])
+AC_SUBST(CBFLIBROOT)
+AC_ARG_WITH([cbflib],
+	AC_HELP_STRING([--with-cbflib=/path/to/cbflib],
+                       [Specify location of CBFLib files]),
+	[if test $withval != no; then CBFLIBROOT=$withval; fi])
+AM_CONDITIONAL(HAVE_CBFLIB, [test "$CBFLIBROOT" != ""])
+
+AC_SUBST(IDLROOT)
+AC_ARG_WITH([idlroot],
+	AC_HELP_STRING([--with-idlroot=/path/to/idlroot],
+                       [Specify root directory of system idl installation]),
+	[if test $withval != no; then IDLROOT=$withval; fi])
+AM_CONDITIONAL(HAVE_IDL, [test "$IDLROOT" != ""])
+
+IDLDLM="\${prefix}/lib"
+AC_SUBST(IDLDLM)
+AC_ARG_WITH([idldlm],
+	AC_HELP_STRING([--with-idldlm=/path/to/idldlm],
+                       [Specify location ito install idl dlm files to]),
+	[if test $withval != no; then IDLDLM=$withval; fi])
+
+AC_ARG_WITH([doxygen], AC_HELP_STRING([--with-doxygen=/path/to/doxygen], [Specify path to doxygen]), [with_doxygen=$withval], [with_doxygen=no])
+if test x"$with_doxygen" != x"no" ; then
+	if test x"$with_doxygen" != x"yes" ; then DOXYGEN="$with_doxygen"; fi
+	AC_CHECK_PROGS(DOXYGEN,[doxygen])
+	AC_CHECK_PROGS(DOT,[dot])
+	AC_CHECK_PROGS(PDFLATEX,[pdflatex])
+	AC_PROG_CXX
+else
+	DOXYGEN=
+	PDFLATEX=
+	DOT=
+fi
+
+AC_SUBST(FCFLAGS)
+AC_SUBST(JAVACFLAGS)
+AC_SUBST(SHARED_LDFLAGS)
+AC_SUBST(JAVAINCLUDE)
+
+SHARED_LDFLAGS=""
+
+NXDOCDIR='${datadir}/nexus/doc'
+NXEXAMPLEDIR='${datadir}/nexus/examples'
+NXTESTDIR='${prefix}/nexus/tests'
+AC_SUBST(NXDOCDIR)
+AC_SUBST(NXEXAMPLEDIR)
+AC_SUBST(NXTESTDIR)
+
+AM_PROG_GCJ
+AM_PROG_CC_C_O
+
+AC_PROG_LIBTOOL
+dnl AC_LIBTOOL_WIN32_DLL
+
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+if test x$with_tcl != xno; then
+    AC_CHECK_ROOT([tcl],[TCLROOT],[/usr /usr/local],[include/tcl.h],[no])
+fi
+if test x$with_guile != xno; then
+    AC_CHECK_ROOT([guile],[GUILEROOT],[/usr /usr/local],[include/libguile.h],[no])
+fi
+if test x$with_opengenie != xno; then
+    AC_CHECK_ROOT([opengenie],[OPENGENIEROOT],[/usr/local],[genie/genie.so],[no])
+fi
+if test x$with_python != xno; then
+    AC_CHECK_ROOT([python],[PYTHONROOT],[/usr /usr/local],[bin/python],[yes])
+    if test x$PYTHONROOT != x; then
+	if test -r "$PYTHONROOT/bin/python"; then PYTHON="$PYTHONROOT/bin/python"; fi
+	if test -r "$PYTHONROOT/python"; then PYTHON="$PYTHONROOT/python"; fi
+    fi
+    AM_PATH_PYTHON(,, :)
+    AC_CHECK_PYTHON_MODULE(numpy)
+    AC_CHECK_PYTHON_MODULE(ctypes)
+fi
+
+AC_ARG_WITH([swig], AC_HELP_STRING([--with-swig=swig compiler], [Specify path of swig compiler]), [with_swig=$withval], [with_swig=])
+if test x$with_tcl != xno -o x$with_guile != xno; then
+    if test x$with_swig != xyes; then
+	SWIG=$with_swig
+    fi
+    AC_CHECK_PROGS(SWIG,[swig])
+else
+    SWIG=
+fi
+
+AC_CHECK_PROGS(DOCBOOK2PDF,[docbook2pdf])
+AC_CHECK_PROGS(DOCBOOK2TXT,[docbook2txt])
+AC_CHECK_PROGS(TCLSH,[tclsh])
+AC_CHECK_PROGS(GUILE,[guile])
+AC_CHECK_PROGS(LATEX,[latex])
+AC_CHECK_PROGS(WGET,[wget])
+AC_CHECK_PROGS(XMLLINT,[xmllint])
+AC_CHECK_PROGS(SVN2CL,[svn2cl])
+
+
+dnl  flags for building swig guile bindings
+AC_SUBST(SWGUILEFLAGS)  
+if test x$GUILEROOT != x -a x$SWIG != x; then
+    if test `$SWIG -guile -help 2>&1 | grep -i '\-linkage' | wc -l` -gt 0; then
+	SWGUILEFLAGS="-Linkage ltdlmod"
+    else
+	SWGUILEFLAGS=""
+    fi
+fi
+
+dnl These are used in build_rules.am to pass any approptiate 
+dnl tag to libtool for f90 building
+#if test `$EGREP "available_tags=.*F77" libtool | wc -l` -gt 0; then
+#    LTF90COMPILETAG="--tag=F77"
+#    LTF90LINKTAG="--tag=CC"
+#else
+#    LTF90COMPILETAG=""
+#    LTF90LINKTAG=""
+#fi
+#AC_SUBST(LTF90COMPILETAG)
+#AC_SUBST(LTF90LINKTAG)
+
+dnl
+dnl First any host specific bits
+dnl
+MINGW_MSYS=no
+
+dnl microsoft LIB command (used in MinGW makefile to create .LIB file)
+AC_CHECK_PROGS(MS_LIB, [LIB])
+AM_CONDITIONAL(HAVE_MS_LIB, [test ! -z "$MS_LIB"])
+
+# strict aliasing causes issues with casts from NXmalloc()
+CFLAGS="$CFLAGS -fno-strict-aliasing"
+CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"
+
+# check for debug
+if test "$enable_debug" = "yes"; then
+    CFLAGS="$CFLAGS -O0 -g"
+    CXXFLAGS="$CXXFLAGS -O0 -g"
+fi
+
+if test "$enable_32bit" = "yes"; then
+    CFLAGS="$CFLAGS -m32"
+    CXXFLAGS="$CXXFLAGS -m32"
+fi
+
+# enable compiler warnings if gcc
+if test "$CC" = "gcc"; then
+#    CFLAGS="$CFLAGS -Wall -Wno-unused-variable -Wno-sign-compare -Wno-comment"
+    CFLAGS="$CFLAGS -Wall"
+fi
+
+if test "$CXX" = "g++"; then
+#    CXXFLAGS="$CXXFLAGS -Wall -Wno-unused-variable -Wno-sign-compare -Wno-comment"
+    CXXFLAGS="$CXXFLAGS -Wall"
+fi
+
+dnl extra FCFLAGS for Absoft f90
+if test ! -z "$FC"; then
+    fcpathlc=`which $FC 2>/dev/null | tr 'A-Z' 'a-z'`
+    case "$fcpathlc" in
+	*absoft*)
+	    echo "Absoft f90 compiler detected - adjusting FCFLAGS"
+	    FCFLAGS="$FCFLAGS -p$mytop/bindings/f90 -g -cons -YEXT_NAMES=LCS -YEXT_SFX=_"
+	    case "$host_cpu" in
+		*powerpc*)
+	    	    FCFLAGS="$FCFLAGS -N11"
+		    ;;
+	    esac
+	    ;;
+    esac
+fi
+
+dnl extra FFLAGS for Absoft f77
+if test ! -z "$F77"; then
+    f77pathlc=`which $F77 2>/dev/null | tr 'A-Z' 'a-z'`
+    case "$f77pathlc" in
+	*absoft*)
+	    echo "Absoft f77 compiler detected - adjusting FFLAGS"
+	    FFLAGS="$FFLAGS -g -f -N15"
+	    ;;
+    esac
+fi
+
+HDF_EXT=a # library file extent to look for with HDF libraries
+HDF5_EXT=so # library file extent to look for with HDF5 libraries
+SHARED_EXT=so
+AC_SUBST(SHARED_EXT)
+
+SAVE_LIBS="$LIBS"
+AC_CHECK_LIB(xml2, [xmlParseFile])
+if test "x$ac_cv_lib_xml2_xmlParseFile" = xyes; then
+    LIBXML2_CFLAGS='`xml2-config --cflags`'
+    LIBXML2_LDFLAGS='`xml2-config --libs`'
+    LIBXML2_MESSAGE="yes"
+else
+    LIBXML2_CFLAGS=''
+    LIBXML2_LDFLAGS=''
+    LIBXML2_MESSAGE="no (will not build NXsummary or NXtranslate)"
+fi
+LIBS="$SAVE_LIBS"
+AC_SUBST(LIBXML2_CFLAGS)
+AC_SUBST(LIBXML2_LDFLAGS)
+
+# set up for linux here - mac is covered in the case $host statement
+AS_CASE([$build_cpu], [x86|i386|i686], [IDLCPU=x86], [IDLCPU=$build_cpu])
+if test $enable_32bit = yes; then
+    IDL_HOST="bin.linux.x86"	# force 32 bit on a 64 bit machine
+else
+    IDL_HOST="bin.linux.$IDLCPU"
+fi
+AC_SUBST(IDL_HOST)
+
+case $host in
+    alpha*-dec-osf*)
+	java_host="alpha"
+	if test "$CC" = "cc" -o "$CC" = "c89"; then
+	    CPPFLAGS="$CPPFLAGS -pthread"
+	fi
+	if test "$CXX" = "cxx"; then
+	    CPPFLAGS="$CPPFLAGS -pthread -D__USE_STD_IOSTREAM"
+	    CXXFLAGS="$CXXFLAGS -std gnu"
+	fi
+	;;
+
+    *mingw*)
+	SHARED_LDFLAGS="$SHARED_LDFLAGS -no-undefined" #  -Wl,--add-stdcall-alias
+	MINGW_MSYS=yes
+	HDF_EXT=dll
+	HDF5_EXT=dll
+	SHARED_EXT=dll
+	LIBXML2_CFLAGS=-I/usr/local/include
+	java_host="win32"
+	;;
+
+    *cygwin*)
+#	SHARED_LDFLAGS="$SHARED_LDFLAGS -no-undefined" #  -Wl,--add-stdcall-alias
+	;;
+
+    *darwin*)
+	dnl -no-cpp-precomp needed on MacOS-X (and others?)
+	AC_CHECK_C_OPTION([-no-cpp-precomp])
+	CPPFLAGS="$CPPFLAGS -D__unix"
+	CFLAGS="$CFLAGS -g"
+	FFLAGS="$FFLAGS -g"
+	HDF5_EXT=dylib
+	SHARED_EXT=dylib
+dnl This is a hack for libtool - for some reason the F77 tag
+dnl does not get set with the commands to create a shared library
+	AC_MSG_NOTICE([Patching libtool for F77 shared linking])
+	sed -e "s/^archive_cmds=\"\"//" < libtool > libtool.$$
+	mv -f libtool.$$ libtool
+	chmod +x libtool
+	JAVAINCLUDE="-I/System/Library/Frameworks/JavaVM.framework/Headers"
+dnl	F90FLAGS="$F90FLAGS -g -cons -YEXT_NAMES=LCS -YEXT_SFX=_"
+dnl	FCFLAGS="$FCFLAGS -qextname"
+	SHARED_LDFLAGS="$SHARED_LDFLAGS -Wl,-single_module"
+#	LTF90COMPILETAG="--tag=F77"
+#	LTF90LINKTAG="--tag=CC"
+dnl	LDFLAGS="$LDFLAGS -flat_namespace"
+dnl     if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+dnl           lt_int_apple_cc_single_mod=yes
+dnl     fi
+dnl     if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+dnl           archive_cmds='$CC -dynamiclib -single_module'
+dnl	fi
+	if test $enable_32bit = yes; then
+	    IDL_HOST="bin.darwin.i386" # force 32bit build
+	else
+	    IDL_HOST="bin.darwin.x86_64"
+	fi
+	;;
+esac
+
+if test ! -z "$JAVAINCLUDE" -a ! -z "$java_host"; then
+# avoid adding /usr/include/linux to include path
+    if test "$JAVAROOT" != "/usr" -a "$JAVAROOT" != "/usr/"; then
+        JAVAINCLUDE="$JAVAINCLUDE -I$JAVAROOT/include/$java_host"
+    fi
+fi
+
+if test "x$JAVAROOT" != x; then
+    echo "looking for ant"
+    AC_PATH_PROG(ANT_PROG,ant)
+else
+    ANT_PROG=""
+fi
+AC_SUBST(ANT_PROG)
+AM_CONDITIONAL(HAVE_ANT, [ test "x$ANT_PROG" != "x" ])
+
+dnl
+dnl * locate path to HDF libraries *
+dnl
+dnl first see if one has been given
+dnl
+H4ROOT=""
+H4INCSUBROOT=""
+H4LIBSUBROOT=""
+H5ROOT=""
+MXMLROOT=""
+AC_SUBST(H4ROOT)
+AC_SUBST(H5ROOT)
+AC_SUBST(MXMLROOT)
+AC_ARG_WITH([hdf4],
+	AC_HELP_STRING([--with-hdf4=/path/to/hdf4],
+                       [Specify location of HDF4 files]),
+	[if test $withval != no -a $withval != yes; then H4ROOT=$withval; fi])
+AC_ARG_WITH([hdf5],
+	AC_HELP_STRING([--with-hdf5=/path/to/hdf5],
+                       [Specify location of HDF5 files]),
+	[if test $withval != no -a $withval != yes; then H5ROOT=$withval; fi])
+AC_ARG_WITH([xml],
+	AC_HELP_STRING([--with-xml=/path/to/mxml],
+                       [Specify location of MXML library files]),
+	[if test $withval != no -a $withval != yes; then MXMLROOT=$withval; fi])
+dnl otherwise try and find HDF path, but not if
+dnl e.g. --without-hdf4 has been specified (hence check on $with_hdf4 != no )
+dnl first HDF4
+EXTRA_LDPATH=""
+EXTRA_LD_LIBRARY_PATH=""
+AC_SUBST(EXTRA_LD_LIBRARY_PATH)
+HDF4SEARCH="/usr/local/hdf4 /usr/local/hdf /usr/local /sw /opt/local /usr"
+if test "$with_hdf4" != "no" -a -z "$H4ROOT"; then
+    AC_MSG_CHECKING(for location of HDF4 libraries)
+    for i in $HDF4SEARCH; do
+        for j in lib64 lib; do
+	    if test -z "$H4ROOT" -a -r ${i}/$j/libdf.$HDF_EXT; then H4ROOT=$i; fi
+        done
+    done
+    for i in lib64 lib; do
+        if test -r /usr/$i/hdf/libdf.$HDF_EXT; then
+	    H4ROOT=/usr
+	    H4LIBSUBROOT=hdf
+        fi
+    done
+    if test -r $H4ROOT/include/hdf; then
+        H4INCSUBROOT=hdf
+    fi
+    if test -z "$H4ROOT"; then 
+	AC_MSG_RESULT(unknown)
+    else 
+	AC_MSG_RESULT($H4ROOT)
+    fi
+fi
+if test "$H4ROOT"; then
+    H4MAJORVERSION=`grep LIBVER_MAJOR ${H4ROOT}/include/${H4INCSUBROOT}/hfile.h | awk '{ print $3}'`
+    H4MINORVERSION=`grep LIBVER_MINOR ${H4ROOT}/include/${H4INCSUBROOT}/hfile.h | awk '{ print $3}'`
+    H4RELEASE=`grep LIBVER_RELEASE ${H4ROOT}/include/${H4INCSUBROOT}/hfile.h | awk '{ print $3}'`
+    H4VERSION=$H4MAJORVERSION.$H4MINORVERSION.$H4RELEASE
+    case $H4VERSION in
+	4.[[12]]*) 
+    		HDF4_LDFLAGS="";
+		for j in lib lib64; do
+		    if test -d $H4ROOT/$j/$H4LIBSUBROOT; then 
+			HDF4_LDFLAGS="-L$H4ROOT/$j/$H4LIBSUBROOT $HDF4_LDFLAGS"
+		        EXTRA_LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:$H4ROOT/$j/$H4LIBSUBROOT
+		    fi
+		done
+		EXTRA_LDPATH="$EXTRA_LDPATH $HDF4_LDFLAGS"
+    		HDF4_LDFLAGS="$HDF4_LDFLAGS -lmfhdf -ldf";
+		if test -z "$H4INCSUBROOT"; then
+    		    HDF4_CPPFLAGS="-I$H4ROOT/include -DHDF4"
+		else
+    		    HDF4_CPPFLAGS="-I$H4ROOT/include/$H4INCSUBROOT -DHDF4"
+		fi
+		;;
+	*) 	AC_MSG_WARN([The HDF 4 installation has not the right version ($H4VERSION). You need at least 4.1])
+		H4ROOT=""
+		;;
+    esac		
+fi
+AC_SUBST(HDF4_LDFLAGS)
+AC_SUBST(HDF4_CPPFLAGS)
+
+dnl HDF5
+HDF5SEARCH="/usr/local/hdf5 /usr/local/hdf /usr/local /sw /opt/local /usr"
+if test "$with_hdf5" != "no" -a -z "$H5ROOT"; then
+    AC_MSG_CHECKING(for location of HDF5 libraries)
+    for i in $HDF5SEARCH; do
+	for j in lib lib64; do
+	    if test -z "$H5ROOT" -a -r ${i}/$j/libhdf5.$HDF5_EXT; then H5ROOT=$i; fi
+        done
+    done
+    for i in $HDF5SEARCH; do
+	for j in lib lib64; do
+	    if test -z "$H5ROOT" -a -r ${i}/$j/libhdf5.a; then H5ROOT=$i; fi
+        done
+    done
+    if test -z "$H5ROOT"; then 
+	AC_MSG_RESULT(unknown)
+    else 
+	AC_MSG_RESULT($H5ROOT)
+    fi
+fi
+# these are needed if HDF5 1.8 has been instaleld with H5_USE_16_API_DEFAULT 
+HDF5_API_DEFS="-DH5Acreate_vers=2 -DH5Aiterate_vers=2 -DH5Dcreate_vers=2 -DH5Dopen_vers=2 -DH5Eclear_vers=2 -DH5Eprint_vers=2 -DH5Epush_vers=2 -DH5Eset_auto_vers=2 -DH5Eget_auto_vers=2 -DH5Ewalk_vers=2 -DH5Gcreate_vers=2 -DH5Gopen_vers=2 -DH5Pget_filter_vers=2 -DH5Pget_filter_by_id_vers=2 -DH5Pinsert_vers=2 -DH5Pregister_vers=2 -DH5Rget_obj_type_vers=2 -DH5Tarray_create_vers=2 -DH5Tcommit_vers=2 -DH5Tget_array_dims_vers=2 -DH5Topen_vers=2"
+if test "$H5ROOT"; then
+    H5VERSION=`grep H5_VERS_INFO ${H5ROOT}/include/H5public.h | cut -d '"' -f 2 | cut -d ' ' -f 4`
+    case $H5VERSION in
+	1.[[89]]*)
+    		HDF5_LDFLAGS=""
+		for j in lib lib64; do
+		    if test -d $H5ROOT/$j; then 
+			HDF5_LDFLAGS="-L$H5ROOT/$j $HDF5_LDFLAGS"
+		    	EXTRA_LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:$H5ROOT/$j
+		    fi
+		done
+		EXTRA_LDPATH="$EXTRA_LDPATH $HDF5_LDFLAGS"
+    		HDF5_LDFLAGS="$HDF5_LDFLAGS -lhdf5 -lz"
+    		HDF5_CPPFLAGS="-I$H5ROOT/include -DHDF5 -DH5_NO_DEPRECATED_SYMBOLS ${HDF5_API_DEFS}"
+		;;
+	*)	
+		AC_MSG_WARN([The HDF 5 installation at $H5ROOT is not the right version ($H5VERSION). You need at least 1.8])
+		H5ROOT=""
+		;;
+    esac
+fi
+AC_SUBST(HDF5_LDFLAGS)
+AC_SUBST(HDF5_CPPFLAGS)
+
+dnl XML
+MXMLSEARCH="/usr /usr/local"
+if test "$with_xml" != "no" -a -z "$MXMLROOT"; then
+    AC_MSG_CHECKING(for location of mxml package)
+    for i in $MXMLSEARCH; do
+	if test -z "$MXMLROOT" -a -r ${i}/include/mxml.h; then MXMLROOT=$i; fi
+    done
+    if test -z "$MXMLROOT"; then 
+	AC_MSG_RESULT(unknown)
+    else 
+	AC_MSG_RESULT($MXMLROOT)
+    fi
+fi
+if test ! -z "$MXMLROOT"; then
+    XML_LDFLAGS="-lmxml"
+    XML_LDFLAGS="-L$MXMLROOT/lib $XML_LDFLAGS"
+    XML_CPPFLAGS="-I$MXMLROOT/include -DNXXML"
+# meed to allow for lib64
+#    EXTRA_LDPATH="$EXTRA_LDPATH $XML_LDFLAGS"
+#    export LD_LIBRARY_PATH=$MXMLROOT/lib:$LD_LIBRARY_PATH
+fi
+AC_SUBST(XML_LDFLAGS)
+AC_SUBST(XML_CPPFLAGS)
+
+if test ! -z "$EXTRA_LDPATH"; then
+    LDFLAGS="$LDFLAGS $EXTRA_LDPATH"
+fi
+if test -d /usr/local/lib; then
+    LDFLAGS="$LDFLAGS -L/usr/local/lib"
+fi
+# for Mac/fink when hdf and hdf5 are not taken from fink, but jpeg is
+if test -d /sw/lib; then
+    LDFLAGS="$LDFLAGS -L/sw/lib"
+fi
+# for Mac/Macports when you are not using fink at all.
+if test -d /opt/local/lib; then
+    LDFLAGS="$LDFLAGS -L/opt/local/lib"
+fi
+
+# remove initial :
+if test ! -z "$EXTRA_LD_LIBRARY_PATH"; then
+    EXTRA_LD_LIBRARY_PATH=`expr substr "$EXTRA_LD_LIBRARY_PATH" 2 1024`
+fi
+if test ! -z "$LD_LIBRARY_PATH"; then
+    export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${EXTRA_LD_LIBRARY_PATH}
+else
+    export LD_LIBRARY_PATH=${EXTRA_LD_LIBRARY_PATH}
+fi
+
+CPPFLAGS="$CPPFLAGS -DHAVE_NAPICONFIG_H"
+
+AC_SUBST(LIBG2C)
+
+dnl finally set LIBS variable if we 
+#AC_CHECK_LIB(g2c,c_sqrt,LIBG2C="-lg2c",LIBG2C="")
+AC_CHECK_LIB(SystemStubs, fprintf$LDBLStub)
+case $host in
+    *mingw*)
+	;;
+    *)
+	AC_CHECK_LIB(m, log)
+esac
+AC_CHECK_LIB(rpc, xdr_float)
+AC_CHECK_LIB(dl, dlopen)
+AC_CHECK_LIB(pthread, pthread_create)
+AC_CHECK_LIB(z, gzopen)
+AC_CHECK_LIB(jpeg, jpeg_CreateCompress)
+AC_CHECK_LIB(sz, SZ_Compress)
+AC_CHECK_LIB(df, Hopen)
+AC_CHECK_LIB(mfhdf, SDcreate)
+AC_CHECK_LIB(hdf5, H5open)
+SAVE_LIBS="$LIBS"
+AC_CHECK_LIB(termcap, tputs)
+AC_CHECK_LIB(readline, readline)
+#AC_CHECK_LIB(history, add_history)
+if test x$ac_cv_lib_termcap_tputs = xyes; then READLINE_LDFLAGS="-ltermcap $READLINE_LDFLAGS"; fi
+#if test x$ac_cv_lib_history_add_history = xyes; then READLINE_LDFLAGS="-lhistory $READLINE_LDFLAGS"; fi
+if test x$ac_cv_lib_readline_readline = xyes; then READLINE_LDFLAGS="-lreadline $READLINE_LDFLAGS"; fi
+AC_SUBST(READLINE_LDFLAGS)
+LIBS="$SAVE_LIBS"
+dnl AC_LANG_PUSH([C++])
+dnl AC_CHECK_LIB(mxmlplus, _ZN4MXML4NodeD2Ev)
+dnl AC_LANG_POP([C++])
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([stdlib.h string.h stdint.h])
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_TYPE_INT8_T
+AC_TYPE_UINT8_T
+AC_TYPE_INT16_T
+AC_TYPE_UINT16_T
+AC_TYPE_INT32_T
+AC_TYPE_UINT32_T
+AC_TYPE_INT64_T
+AC_TYPE_UINT64_T
+AC_TYPE_LONG_LONG_INT
+AC_TYPE_UNSIGNED_LONG_LONG_INT
+AC_CHECK_SIZEOF([int])
+AC_CHECK_SIZEOF([long int])
+AC_CHECK_SIZEOF([long long int])
+AC_STRUCT_TM
+
+AC_SYS_LARGEFILE
+case "$ac_cv_sys_file_offset_bits" in
+  "no" | "unknown" | "") 
+    ;;
+  *)
+    CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits"
+    CXXFLAGS="$CXXFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits"
+    ;;
+esac
+
+dnl Checks for library functions.
+#this can cause link errors with rpl_malloc undefined
+#AC_FUNC_MALLOC
+#this no needed
+#AC_FUNC_MEMCMP
+#this hangs on FC9 at the moment
+#AC_FUNC_MKTIME
+
+#AC_FUNC_STRFTIME
+
+AC_CHECK_FUNCS([ftime memset strchr strdup strrchr strstr tzset mkstemp])
+
+AM_CONDITIONAL(HAVE_CPP, [test ! -z "$CXX"])
+AM_CONDITIONAL(HAVE_F77, [test "$with_f77" != "no"])
+AM_CONDITIONAL(HAVE_F90, [test "$with_f90" != "no"])
+AM_CONDITIONAL(HAVE_PYTHON, [test ! -z "$PYTHONROOT" -a "$PYTHON_numpy_found"  = "yes" -a "$PYTHON_ctypes_found"  = "yes"])
+AM_CONDITIONAL(HAVE_TCL, [test ! -z "$TCLROOT"])
+AM_CONDITIONAL(HAVE_GUILE, [test ! -z "$GUILEROOT"])
+AM_CONDITIONAL(HAVE_SWIG, [test ! -z "$SWIG"])
+AM_CONDITIONAL(HAVE_JAVA, [test ! -z "$JAVA" -a ! -z "$JAVAROOT"])
+AM_CONDITIONAL(HAVE_JAVAC, [test ! -z "$JAVAC" -a ! -z "$JAVAROOT"])
+AM_CONDITIONAL(HAVE_JAVADOC, [test ! -z "$JAVADOC" -a ! -z "$JAVAROOT"])
+AM_CONDITIONAL(HAVE_HDF4, [test ! -z "$H4ROOT"])
+AM_CONDITIONAL(HAVE_HDF5, [test ! -z "$H5ROOT"])
+AM_CONDITIONAL(HAVE_XML, [test ! -z "$MXMLROOT"])
+AM_CONDITIONAL(HAVE_LIBXML2, [ test "$ac_cv_lib_xml2_xmlParseFile" = "yes" ])
+dnl AM_CONDITIONAL(HAVE_LIBMXMLPLUS, [ test "$ac_cv_lib_mxmlplus__ZN4MXML4NodeD2Ev" = "yes" ])
+AM_CONDITIONAL(HAVE_DOCBOOK, [test ! -z "$DOCBOOK2TXT" -a ! -z "$DOCBOOK2PDF"])
+AM_CONDITIONAL(HAVE_LATEX, [test ! -z "$LATEX"])
+#AM_CONDITIONAL(INSTALL_NXPYTHON, [test ! -z "$INSTALL_NXPYTHON"])
+AM_CONDITIONAL(HAVE_MZSCHEME, [test ! -z "$INSTALL_NXPYTHON"])
+AM_CONDITIONAL(MINGW_MSYS, [test x$MINGW_MSYS = xyes])
+AM_CONDITIONAL(HAVE_OPENGENIE, [test ! -z "$OPENGENIEROOT"])
+AM_CONDITIONAL(HAVE_DOXYGEN, [test ! -z "$DOXYGEN"])
+AM_CONDITIONAL(HAVE_MATLAB, [test ! -z "$MATLAB"])
+AM_CONDITIONAL(HAVE_PDFLATEX, [test ! -z "$PDFLATEX"])
+AM_CONDITIONAL(HAVE_DOT, [test ! -z "$DOT"])
+
+AM_CONDITIONAL(HAVE_WGET, [test ! -z "$WGET"])
+AM_CONDITIONAL(HAVE_XMLLINT, [test ! -z "$XMLLINT"])
+AM_CONDITIONAL(HAVE_SVN2CL, [test ! -z "$SVN2CL"])
+
+AC_CONFIG_TESTDIR(test)
+AC_CONFIG_FILES(test/Makefile test/atlocal)
+AM_MISSING_PROG([AUTOM4TE], [autom4te])
+
+if test X$MATLAB != X; then
+    for i in glnxa64 glnxi64 glnx86 maci maci64; do
+        if test -r "$MATLABROOT/bin/$i"; then
+                MATLAB_ARCH="$i"
+        fi
+    done
+    case $MATLAB_ARCH in
+        glnx86)
+            MATLAB_MEXSUFFIX=mexglx
+            ;;
+        glnxa64)
+            MATLAB_MEXSUFFIX=mexa64
+            ;;
+        glnxi64)
+            MATLAB_MEXSUFFIX=mexi64
+            ;;
+        maci)
+            MATLAB_MEXSUFFIX=mexmaci
+            ;;
+    esac
+    AC_SUBST(MATLAB_MEXSUFFIX)
+    AC_SUBST(MATLAB_ARCH)
+    AC_SUBST(MATLABROOT)
+fi
+
+LINUX_DISTRIBUTION
+
+CONFIGURE_ARGS="$ac_configure_args"
+AC_SUBST(CONFIGURE_ARGS)
+
+AC_CONFIG_FILES([Makefile
+		nexus.spec:nexus_spec.in
+		build_rpm
+		include/Makefile
+		src/Makefile 
+		applications/Makefile
+		applications/NXdir/Makefile
+		applications/NXbrowse/Makefile
+                applications/NXtraverse/Makefile
+		applications/NXconvert/Makefile
+		applications/NXvalidate/Makefile
+		applications/NXvalidate/nxvalidate
+		applications/NXdump/Makefile
+		applications/nxingest/Makefile
+		applications/NXsummary/Makefile
+		applications/NXtranslate/Makefile
+		applications/NXtranslate/FRM2/Makefile
+		applications/NXtranslate/opengenie/Makefile
+		applications/NXtranslate/text_collist/Makefile
+		applications/NXtranslate/text_plain/Makefile
+		applications/NXtranslate/text_xml/Makefile
+		applications/NXtranslate/sns_histogram/Makefile
+		applications/NXtranslate/loopy/Makefile
+		applications/NXtranslate/binary/Makefile
+		applications/NXtranslate/spec/Makefile
+		applications/NXtranslate/esrf_edf/Makefile
+		applications/NXtranslate/docs/Makefile
+		examples/Makefile
+		doc/Makefile
+		doc/doxygen/Makefile
+		doc/api/Makefile
+		doc/nxdict/Makefile
+		doc/tech_ref/Makefile
+		bindings/Makefile 
+		bindings/cpp/Makefile
+		bindings/f77/Makefile
+		bindings/f90/Makefile
+		bindings/java/Makefile
+		bindings/swig/Makefile
+		bindings/idl/Makefile
+		bindings/python/Makefile
+		third_party/Makefile
+		third_party/tclap/Makefile
+		contrib/Makefile
+		contrib/applications/Makefile
+		contrib/applications/NXextract/Makefile
+		contrib/applications/NXextract/src/Makefile
+		contrib/applications/CBFLib/Makefile
+		contrib/bindings/Makefile
+		contrib/bindings/python/Makefile
+		macosx_install_kit/Makefile
+		macosx_install_kit/pkg.config
+		scripts/Makefile
+		scripts/nexus-config
+		scripts/nexus.pc
+		scripts/nexus-cpp.pc
+		scripts/nxbuild])
+dnl src/nxdict/Makefile
+AC_OUTPUT
+
+if test ! -z "$DOXYGEN" -a ! -z "$PDFLATEX" -a ! -z "$DOT"; then
+    DOXYGENDOCS="yes"
+else
+    if test x"$with_doxygen" != x"no" ; then
+        DOXYGENDOCS="no  - missing "
+        if test -z "$DOXYGEN"; then DOXYGENDOCS="$DOXYGENDOCS doxygen"; fi
+        if test -z "$PDFLATEX"; then DOXYGENDOCS="$DOXYGENDOCS pdflatex"; fi
+        if test -z "$DOT"; then DOXYGENDOCS="$DOXYGENDOCS graphviz"; fi
+    else
+        DOXYGENDOCS="no    --with-doxygen  not specified"
+    fi
+fi
+
+if test ! -z "$DOCBOOK2TXT" -a ! -z "$DOCBOOK2PDF"; then
+    DOCBOOKDOCS="yes"
+else
+    DOCBOOKDOCS="no  - missing "
+    if test -z "$DOCBOOK2TXT"; then DOCBOOKDOCS="$DOCBOOKDOCS docbook2txt"; fi
+    if test -z "$DOCBOOK2PDF"; then DOCBOOKDOCS="$DOCBOOKDOCS docbook2pdf"; fi
+fi
+
+HDF4SUPPORT=`if test -n "$H4ROOT" ; then echo yes ; else echo no ; echo "                found version $H4VERSION"; fi`
+HDF5SUPPORT=`if test -n "$H5ROOT" ; then echo yes ; else echo no ; echo "                found version $H5VERSION"; fi`
+XMLSUPPORT=`if test -n "$MXMLROOT" ; then echo yes ; else echo no ; fi`
+CPPBINDING=`if test -n "$CXX" ; then echo yes ; else echo no ; fi`
+F77BINDING=`if test -n "$F77" ; then echo yes ; else echo no ; fi`
+F90BINDING=`if test -n "$FC" ; then echo yes ; else echo no ; fi`
+JAVABINDING=`if test -n "$JAVAROOT" ; then echo yes ; else echo no ; fi` 
+IDLBINDING=`if test -n "$IDLROOT" ; then echo yes ; else echo no ; fi` 
+PYTHONBINDING=`if test -n "$HAVE_PYTHON_FALSE" ; then echo yes; else echo no ; fi` 
+MATLABBINDING=`if test -n "$MATLAB" ; then echo "yes (matlabroot=$MATLABROOT)"; else echo no ; fi`
+
+if test -n "$SWIG" ; then 
+    SWIGBINDING="yes ("
+    test -n "$TCLROOT" && SWIGBINDING="$SWIGBINDING tcl"
+    test -n "$GUILEROOT" && SWIGBINDING="$SWIGBINDING guile"
+    SWIGBINDING="$SWIGBINDING ) SWIG=${SWIG}"
+else
+    SWIGBINDING=no
+fi
+
+if test -z "$JAVAROOT"; then
+    JAVAROOT="not specified"
+fi
+
+if test "x$ac_cv_lib_readline_readline" = xyes; then
+    HAVE_READLINE="yes"
+else
+    HAVE_READLINE="no (optional)"
+fi
+
+AC_MSG_RESULT([
+
+Configuration (NeXus):
+
+	Install prefix:        ${prefix}
+        Source code location:  ${srcdir}
+        Version:               ${VERSION}
+        Compiler:              ${CC},${CXX},${F77},${FC}
+
+build:
+        NeXus with:
+                HDF4 support:  ${HDF4SUPPORT} ($H4VERSION)
+                HDF5 support:  ${HDF5SUPPORT} ($H5VERSION)
+                XML support:   ${XMLSUPPORT}
+
+        bindings:
+                C++ :          ${CPPBINDING} (--with-cxx=${CXX})
+                F77 :          ${F77BINDING} (--with-f77=${F77})
+            F90/F95 :          ${F90BINDING} (--with-f90=${FC})
+                JAVA:          ${JAVABINDING} (--with-java-home=${JAVAROOT}, JAVA=${JAVA}, JAVAC=${JAVAC}, JAVAH=${JAVAH})
+		SWIG:	       ${SWIGBINDING}
+		 IDL:	       ${IDLBINDING} (--with-idlroot=${IDLROOT}, --with-idldlm=${IDLDLM})
+		 MATLAB:	       ${MATLABBINDING} (--with-matlabroot=${MATLABROOT})
+	      PYTHON:	       ${PYTHONBINDING} (PYTHONROOT=${PYTHONROOT}, numpy found: $PYTHON_numpy_found, ctypes found: $PYTHON_ctypes_found)
+
+	application tools:
+	     ant:	       ${ANT_PROG}
+	     libxml2:          ${LIBXML2_MESSAGE}
+	     readline:	       ${HAVE_READLINE}
+
+	documentation:
+	     Doxygen:	       ${DOXYGENDOCS}
+	     Docbook:	       ${DOCBOOKDOCS}
+
+Please check whether the configuration I detected matches what you would
+like to have. If not, re-run configure adding the appropriate  --with  option
+or setting the relevant environment variable.
+
+For a list of available options type    ./configure --help
+])
diff --git a/configure_cmake_build.bat b/configure_cmake_build.bat
new file mode 100644
index 0000000..d5fe1c5
--- /dev/null
+++ b/configure_cmake_build.bat
@@ -0,0 +1,55 @@
+ at echo off
+set NEXUS_THIRD_PARTY=C:\development\nexus-third-party
+
+set HDF5_ROOT64=C:\Program Files\HDF_Group\HDF5\1.8.10
+set HDF4_ROOT64=C:\Program Files\HDF_Group\HDF\4.2.8
+set MXML_ROOT64=c:\Program Files\mxml
+
+set HDF5_ROOT32=C:\Program Files (x86)\HDF_Group\HDF5\1.8.10
+set HDF4_ROOT32=C:\Program Files (x86)\HDF_Group\HDF\4.2.8
+set MXML_ROOT32=c:\Program Files (x86)\mxml
+
+cmake -DNATIVE:PATH="%NEXUS_THIRD_PARTY%" -P dir_syntax.cmake
+set /P NEXUS_THIRD_PARTY_CMAKE= < dir_syntax.txt
+del /q dir_syntax.txt
+
+cmake -DNATIVE:PATH="%HDF5_ROOT64%" -P dir_syntax.cmake
+set /P HDF5_ROOT64_CMAKE= < dir_syntax.txt
+del /q dir_syntax.txt
+
+cmake -DNATIVE:PATH="%HDF5_ROOT32%" -P dir_syntax.cmake
+set /P HDF5_ROOT32_CMAKE= < dir_syntax.txt
+del /q dir_syntax.txt
+
+rmdir /s /q build_win64
+mkdir build_win64
+cd build_win64
+set HDF5_ROOT=%HDF5_ROOT64%
+set HDF4_ROOT=%HDF4_ROOT64%
+set MXML_ROOT=%MXML_ROOT64%
+REM -DBUILD_TESTING:BOOL=ON -DUSE_SHARED_LIBS:BOOL=ON
+cmake -G "Visual Studio 10 Win64" ^
+   -DZLIB_ROOT="%HDF5_ROOT64_CMAKE%" ^
+   -DNEXUS_THIRD_PARTY="%NEXUS_THIRD_PARTY_CMAKE%" ^
+   -DCMAKE_PREFIX_PATH="%NEXUS_THIRD_PARTY_CMAKE%/win64" ^
+   ..    
+cd ..
+
+rmdir /s /q build_win32
+mkdir build_win32
+cd build_win32
+set HDF5_ROOT=%HDF5_ROOT32%
+set HDF4_ROOT=%HDF4_ROOT32%
+set MXML_ROOT=%MXML_ROOT32%
+REM -DBUILD_TESTING:BOOL=ON -DUSE_SHARED_LIBS:BOOL=ON
+cmake -G "Visual Studio 10" ^
+   -DZLIB_ROOT="%HDF5_ROOT32_CMAKE%" ^
+   -DNEXUS_THIRD_PARTY="%NEXUS_THIRD_PARTY_CMAKE%" ^
+   -DCMAKE_PREFIX_PATH="%NEXUS_THIRD_PARTY_CMAKE%/win32" ^
+   ..       
+cd ..
+
+ at echo Now enter either build_win32 or build_win64 and type
+ at echo
+ at echo     cmake  --build .  --config RelWihDebInfo  --clean-first
+ at echo     cpack  -C RelWihDebInfo  CPackConfig.cmake
diff --git a/configure_mingw_kit b/configure_mingw_kit
new file mode 100755
index 0000000..b213dcc
--- /dev/null
+++ b/configure_mingw_kit
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+# this is just for building the mingw nexus kit on my machine
+#
+env am_cv_python_pythondir='${prefix}/lib/python' am_cv_python_pyexecdir='${prefix}/lib/python' ./configure --prefix=/c/nxinstall --with-python=/c/Python25 --with-java-home=/c/mingw
diff --git a/contrib/.cvsignore b/contrib/.cvsignore
new file mode 100644
index 0000000..282522d
--- /dev/null
+++ b/contrib/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt
new file mode 100644
index 0000000..255da15
--- /dev/null
+++ b/contrib/CMakeLists.txt
@@ -0,0 +1,31 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_subdirectory (applications)
+add_subdirectory (bindings)
+
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
new file mode 100644
index 0000000..a93d62b
--- /dev/null
+++ b/contrib/Makefile.am
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  
+# $Id$
+#
+# @configure_input@
+#====================================================================
+SUBDIRS = bindings applications
diff --git a/contrib/README b/contrib/README
new file mode 100644
index 0000000..d2ca46d
--- /dev/null
+++ b/contrib/README
@@ -0,0 +1,6 @@
+This directory contains software contributed by the neutron community that
+is not (yet) part of the official NeXus distribution. Its structure should 
+mirror that of the top directory i.e. have bindings, test and applications
+sub-directories.
+
+$Id$
diff --git a/contrib/applications/.cvsignore b/contrib/applications/.cvsignore
new file mode 100644
index 0000000..282522d
--- /dev/null
+++ b/contrib/applications/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/contrib/applications/CBFLib/Makefile.am b/contrib/applications/CBFLib/Makefile.am
new file mode 100644
index 0000000..b359ac4
--- /dev/null
+++ b/contrib/applications/CBFLib/Makefile.am
@@ -0,0 +1,38 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 942 2007-05-29 09:01:20Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -I$(CBFLIBROOT)/include/cbflib -I$(CBFLIBROOT)/include
+
+bin_PROGRAMS = cbf2nx
+
+cbf2nx_SOURCES = cbf2nx.c
+cbf2nx_LDADD = $(LIBNEXUS) -L$(CBFLIBROOT)/lib -lcbf -limg $(LDFLAGS)
+cbf2nx_LDFLAGS = -static
+
+include $(top_srcdir)/build_rules.am
diff --git a/contrib/applications/CBFLib/README b/contrib/applications/CBFLib/README
new file mode 100644
index 0000000..3f2bac6
--- /dev/null
+++ b/contrib/applications/CBFLib/README
@@ -0,0 +1,13 @@
+This directory contains files being developed as part of the 
+NeXus / medsbio collaboration to provide a link between NeXus files
+and imgCIF/CBF. For further details see:
+
+http://www.medsbio.org/ 
+http://www.bernstein-plus-sons.com/software/CBF/
+
+Building
+--------
+
+* Install CBFLib from //www.bernstein-plus-sons.com/software/CBF/
+* At the top level directory configure nexus with     
+          ./configure --with-contrib --with-cbflib=/path/to/cbflib/dir
diff --git a/contrib/applications/CBFLib/cbf2nx.c b/contrib/applications/CBFLib/cbf2nx.c
new file mode 100644
index 0000000..30aedf1
--- /dev/null
+++ b/contrib/applications/CBFLib/cbf2nx.c
@@ -0,0 +1,1528 @@
+/**********************************************************************
+ *          cif2nx -- convert a cif or cbf to a NeXus file            *
+ *                                                                    *
+ * Part of CBFlib Version 0.7.8 20 September 2007                     *
+ * Rev 25 Jan 2010, HJB -- drop CIF down below NXcif group            *
+ *                                                                    *
+ *                          Paul Ellis and                            *
+ *         Herbert J. Bernstein (yaya at bernstein-plus-sons.com)        *
+ *                                                                    *
+ * (C) Copyright 2006, 2007 Herbert J. Bernstein                      *
+ *                                                                    *
+ **********************************************************************/
+
+/**********************************************************************
+ *                                                                    *
+ * YOU MAY REDISTRIBUTE THE CBFLIB PACKAGE UNDER THE TERMS OF THE GPL *
+ * WHILE YOU MAY ALTERNATIVE DISTRIBUTE THE API UNDER THE LGPL        *
+ * YOU MAY ***NOT*** DISTRBUTE THIS PROGRAM UNDER THE LGPL            *
+ *                                                                    *                                                                    *
+ **********************************************************************/
+
+/*************************** GPL NOTICES ******************************
+ *                                                                    *
+ * This program is free software; you can redistribute it and/or      *
+ * modify it under the terms of the GNU General Public License as     *
+ * published by the Free Software Foundation; either version 2 of     *
+ * (the License, or (at your option) any later version.               *
+ *                                                                    *
+ * This program is distributed in the hope that it will be useful,    *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
+ * GNU General Public License for more details.                       *
+ *                                                                    *
+ * You should have received a copy of the GNU General Public License  *
+ * along with this program; if not, write to the Free Software        *
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA           *
+ * 02111-1307  USA                                                    *
+ *                                                                    *
+ **********************************************************************/
+
+/**********************************************************************
+ *                                SYNOPSIS                            *
+ *                                                                    *
+ *  cif2nx [-i input_cif] [-o output_nx] \                            *
+ *    [-e [4|5|x]] [-c [n|g|h|r]]        \                            *
+ *    [-v dictionary]*                   \                            *
+ *    [input_cif] [output_nx]                                         *
+ *                                                                    *
+ *  the options are:                                                  *
+ *                                                                    *
+ *  -i input_cif (default: stdin)                                     *
+ *    the input  file in CIF or CBF  format.  If input_cif is not     *
+ *    specified or is given as "-", it is copied from stdin to a      *
+ *    temporary file.                                                 *
+ *                                                                    *
+ *  -o output_nx                                                      *
+ *    the output NeXus file                                           *
+ *                                                                    *
+ *  -e [4|5|x] (default x)                                            *
+ *    output_nx NeXus encoding to use: 4 for hdf4, 5 for hdf5,        *
+ *              x for XML                                             *
+ *                                                                    *
+ *  -c [n|g|h|r] (default n)                                          *
+ *    output dataset compression to use for datasets over 1K          *
+ *    n for none, g for gzip, h for Huffman, r for run length         *
+ *    encoding                                                        *
+ *                                                                    *
+ *  -v dictionary specifies a dictionary to be used to validate       *
+ *    the input cif and to apply aliases to the output cif.           *
+ *    This option may be specified multiple times, with dictionaries  *
+ *    layered in the order given.                                     *
+ *                                                                    *
+ *                                                                    *
+ **********************************************************************/
+
+/**********************************************************************
+ *                                CREDITS                             *
+ *                                                                    *
+ *  This program is a Crystallographic Information File (CIF)         *
+ *  application.  Please see the IUCR Policy below.   See the IUCR    *
+ *  web page (http://www.iucr.org) or its mirrors for background      *
+ *  and references on CIF.                                            *
+ *                                                                    *
+ *  This program is a Crystallographic Binary File (CBF) application. *
+ *  Please see the ImgCIF/CBF web page at                             *
+ *                                                                    *
+ *            http://ndbserver.rutgers.edu/mmcif/cbf                  *
+ *                                                                    *
+ *  for background and references.  The CBF definition is available   *
+ *  on the web page created by Andy Hammersley at                     *
+ *                                                                    *
+ *     http://www.ersf.fr/computing/Forum/imgCIF/cbf_definition.html  *
+ *                                                                    *
+ *  This program is a CBFlib application.  See "CBFLIB, An ANSI-C     *
+ *  API for Crystallographic Binary Files", Version 0.1, April 1998   *
+ *  by Paul J. Ellis, Stanford Synchrotron Radiation Laboratory,      *
+ *  ellis at ssrl.slac.stanford.edu                                      *
+ *                                                                    *
+ *  This program uses routines derived from mpack/munpack version     *
+ *  1.5, ftp://ftp.andrew.cmu.edu/pub/mpack by John G. Myers,         *
+ *  jgm+ at cmu.edu.  "Mpack and munpack are utilties for encoding and   *
+ *  decoding ... binary files in MIME ... format."  Please see the    *
+ *  copyright notices and disclaimers in the mpack/munpack routines   *
+ *                                                                    *
+ *  This program uses routines derived from the "RSA Data Security,   *
+ *  Inc. MD5 Message-Digest Algorithm."  Please see the copyright     *
+ *  notice and disclaimer in md5c.c                                   *
+ **********************************************************************/
+
+
+/**********************************************************************
+ *                                                                    *
+ *                    Stanford University Notices                     *
+ *  for the CBFlib software package that incorporates SLAC software   *
+ *                 on which copyright is disclaimed                   *
+ *                                                                    *
+ * This software                                                      *
+ * -------------                                                      *
+ * The term 'this software', as used in these Notices, refers to      *
+ * those portions of the software package CBFlib that were created by *
+ * employees of the Stanford Linear Accelerator Center, Stanford      *
+ * University.                                                        *
+ *                                                                    *
+ * Stanford disclaimer of copyright                                   *
+ * --------------------------------                                   *
+ * Stanford University, owner of the copyright, hereby disclaims its  *
+ * copyright and all other rights in this software.  Hence, anyone    *
+ * may freely use it for any purpose without restriction.             *
+ *                                                                    *
+ * Acknowledgement of sponsorship                                     *
+ * ------------------------------                                     *
+ * This software was produced by the Stanford Linear Accelerator      *
+ * Center, Stanford University, under Contract DE-AC03-76SFO0515 with *
+ * the Department of Energy.                                          *
+ *                                                                    *
+ * Government disclaimer of liability                                 *
+ * ----------------------------------                                 *
+ * Neither the United States nor the United States Department of      *
+ * Energy, nor any of their employees, makes any warranty, express or *
+ * implied, or assumes any legal liability or responsibility for the  *
+ * accuracy, completeness, or usefulness of any data, apparatus,      *
+ * product, or process disclosed, or represents that its use would    *
+ * not infringe privately owned rights.                               *
+ *                                                                    *
+ * Stanford disclaimer of liability                                   *
+ * --------------------------------                                   *
+ * Stanford University makes no representations or warranties,        *
+ * express or implied, nor assumes any liability for the use of this  *
+ * software.                                                          *
+ *                                                                    *
+ * Maintenance of notices                                             *
+ * ----------------------                                             *
+ * In the interest of clarity regarding the origin and status of this *
+ * software, this and all the preceding Stanford University notices   *
+ * are to remain affixed to any copy or derivative of this software   *
+ * made or distributed by the recipient and are to be affixed to any  *
+ * copy of software made or distributed by the recipient that         *
+ * contains a copy or derivative of this software.                    *
+ *                                                                    *
+ * Based on SLAC Software Notices, Set 4                              *
+ * OTT.002a, 2004 FEB 03                                              *
+ **********************************************************************/
+
+
+/**********************************************************************
+ *                                 NOTICE                             *
+ * Creative endeavors depend on the lively exchange of ideas. There   *
+ * are laws and customs which establish rights and responsibilities   *
+ * for authors and the users of what authors create.  This notice     *
+ * is not intended to prevent you from using the software and         *
+ * documents in this package, but to ensure that there are no         *
+ * misunderstandings about terms and conditions of such use.          *
+ *                                                                    *
+ * Please read the following notice carefully.  If you do not         *
+ * understand any portion of this notice, please seek appropriate     *
+ * professional legal advice before making use of the software and    *
+ * documents included in this software package.  In addition to       *
+ * whatever other steps you may be obliged to take to respect the     *
+ * intellectual property rights of the various parties involved, if   *
+ * you do make use of the software and documents in this package,     *
+ * please give credit where credit is due by citing this package,     *
+ * its authors and the URL or other source from which you obtained    *
+ * it, or equivalent primary references in the literature with the    *
+ * same authors.                                                      *
+ *                                                                    *
+ * Some of the software and documents included within this software   *
+ * package are the intellectual property of various parties, and      *
+ * placement in this package does not in any way imply that any       *
+ * such rights have in any way been waived or diminished.             *
+ *                                                                    *
+ * With respect to any software or documents for which a copyright    *
+ * exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.   *
+ *                                                                    *
+ * Even though the authors of the various documents and software      *
+ * found here have made a good faith effort to ensure that the        *
+ * documents are correct and that the software performs according     *
+ * to its documentation, and we would greatly appreciate hearing of   *
+ * any problems you may encounter, the programs and documents any     *
+ * files created by the programs are provided **AS IS** without any   *
+ * warranty as to correctness, merchantability or fitness for any     *
+ * particular or general use.                                         *
+ *                                                                    *
+ * THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF    *
+ * PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE   *
+ * PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS   *
+ * OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE          *
+ * PROGRAMS OR DOCUMENTS.                                             *
+ **********************************************************************/
+
+/**********************************************************************
+ *                                                                    *
+ *                           The IUCr Policy                          *
+ *      for the Protection and the Promotion of the STAR File and     *
+ *     CIF Standards for Exchanging and Archiving Electronic Data     *
+ *                                                                    *
+ * Overview                                                           *
+ *                                                                    *
+ * The Crystallographic Information File (CIF)[1] is a standard for   *
+ * information interchange promulgated by the International Union of  *
+ * Crystallography (IUCr). CIF (Hall, Allen & Brown, 1991) is the     *
+ * recommended method for submitting publications to Acta             *
+ * Crystallographica Section C and reports of crystal structure       *
+ * determinations to other sections of Acta Crystallographica         *
+ * and many other journals. The syntax of a CIF is a subset of the    *
+ * more general STAR File[2] format. The CIF and STAR File approaches *
+ * are used increasingly in the structural sciences for data exchange *
+ * and archiving, and are having a significant influence on these     *
+ * activities in other fields.                                        *
+ *                                                                    *
+ * Statement of intent                                                *
+ *                                                                    *
+ * The IUCr's interest in the STAR File is as a general data          *
+ * interchange standard for science, and its interest in the CIF,     *
+ * a conformant derivative of the STAR File, is as a concise data     *
+ * exchange and archival standard for crystallography and structural  *
+ * science.                                                           *
+ *                                                                    *
+ * Protection of the standards                                        *
+ *                                                                    *
+ * To protect the STAR File and the CIF as standards for              *
+ * interchanging and archiving electronic data, the IUCr, on behalf   *
+ * of the scientific community,                                       *
+ *                                                                    *
+ * * holds the copyrights on the standards themselves,                *
+ *                                                                    *
+ * * owns the associated trademarks and service marks, and            *
+ *                                                                    *
+ * * holds a patent on the STAR File.                                 *
+ *                                                                    *
+ * These intellectual property rights relate solely to the            *
+ * interchange formats, not to the data contained therein, nor to     *
+ * the software used in the generation, access or manipulation of     *
+ * the data.                                                          *
+ *                                                                    *
+ * Promotion of the standards                                         *
+ *                                                                    *
+ * The sole requirement that the IUCr, in its protective role,        *
+ * imposes on software purporting to process STAR File or CIF data    *
+ * is that the following conditions be met prior to sale or           *
+ * distribution.                                                      *
+ *                                                                    *
+ * * Software claiming to read files written to either the STAR       *
+ * File or the CIF standard must be able to extract the pertinent     *
+ * data from a file conformant to the STAR File syntax, or the CIF    *
+ * syntax, respectively.                                              *
+ *                                                                    *
+ * * Software claiming to write files in either the STAR File, or     *
+ * the CIF, standard must produce files that are conformant to the    *
+ * STAR File syntax, or the CIF syntax, respectively.                 *
+ *                                                                    *
+ * * Software claiming to read definitions from a specific data       *
+ * dictionary approved by the IUCr must be able to extract any        *
+ * pertinent definition which is conformant to the dictionary         *
+ * definition language (DDL)[3] associated with that dictionary.      *
+ *                                                                    *
+ * The IUCr, through its Committee on CIF Standards, will assist      *
+ * any developer to verify that software meets these conformance      *
+ * conditions.                                                        *
+ *                                                                    *
+ * Glossary of terms                                                  *
+ *                                                                    *
+ * [1] CIF:  is a data file conformant to the file syntax defined     *
+ * at http://www.iucr.org/iucr-top/cif/spec/index.html                *
+ *                                                                    *
+ * [2] STAR File:  is a data file conformant to the file syntax       *
+ * defined at http://www.iucr.org/iucr-top/cif/spec/star/index.html   *
+ *                                                                    *
+ * [3] DDL:  is a language used in a data dictionary to define data   *
+ * items in terms of "attributes". Dictionaries currently approved    *
+ * by the IUCr, and the DDL versions used to construct these          *
+ * dictionaries, are listed at                                        *
+ * http://www.iucr.org/iucr-top/cif/spec/ddl/index.html               *
+ *                                                                    *
+ * Last modified: 30 September 2000                                   *
+ *                                                                    *
+ * IUCr Policy Copyright (C) 2000 International Union of              *
+ * Crystallography                                                    *
+ **********************************************************************/
+
+#include "napi.h"
+#include "cbf.h"
+#include "cbf_string.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#ifdef GNUGETOPT
+#include "getopt.h"
+#endif
+#include <unistd.h>
+
+#define C2CBUFSIZ 8192
+#define NUMDICTS 50
+
+#ifdef __MINGW32__
+#define NOMKSTEMP
+#define NOTMPDIR
+#endif
+
+
+
+int local_exit (int status);
+int outerror(int err);
+
+int outerror(int err) 
+{
+	
+  if ((err&CBF_FORMAT)==CBF_FORMAT)
+    fprintf(stderr, " cif2nx: The file format is invalid.\n");
+  if ((err&CBF_ALLOC)==CBF_ALLOC)
+    fprintf(stderr, " cif2nx Memory allocation failed.\n");
+  if ((err&CBF_ARGUMENT)==CBF_ARGUMENT)
+    fprintf(stderr, " cif2nx: Invalid function argument.\n");
+  if ((err&CBF_ASCII)==CBF_ASCII)
+    fprintf(stderr, " cif2nx: The value is ASCII (not binary).\n");
+  if ((err&CBF_BINARY)==CBF_BINARY)
+    fprintf(stderr, " cif2nx: The value is binary (not ASCII).\n");
+  if ((err&CBF_BITCOUNT)==CBF_BITCOUNT)
+    fprintf(stderr, " cif2nx: The expected number of bits does" 
+      " not match the actual number written.\n");
+  if ((err&CBF_ENDOFDATA)==CBF_ENDOFDATA)
+    fprintf(stderr, " cif2nx: The end of the data was reached"
+     " before the end of the array.\n");
+  if ((err&CBF_FILECLOSE)==CBF_FILECLOSE)
+    fprintf(stderr, " cif2nx: File close error.\n");
+  if ((err&CBF_FILEOPEN)==CBF_FILEOPEN)
+    fprintf(stderr, " cif2nx: File open error.\n");
+  if ((err&CBF_FILEREAD)==CBF_FILEREAD)
+    fprintf(stderr, " cif2nx: File read error.\n");
+  if ((err&CBF_FILESEEK)==CBF_FILESEEK)
+    fprintf(stderr, " cif2nx: File seek error.\n");
+  if ((err&CBF_FILETELL)==CBF_FILETELL)
+    fprintf(stderr, " cif2nx: File tell error.\n");
+  if ((err&CBF_FILEWRITE)==CBF_FILEWRITE)
+    fprintf(stderr, " cif2nx: File write error.\n");
+  if ((err&CBF_IDENTICAL)==CBF_IDENTICAL)
+    fprintf(stderr, " cif2nx: A data block with the new name already exists.\n");
+  if ((err&CBF_NOTFOUND)==CBF_NOTFOUND)
+    fprintf(stderr, " cif2nx: The data block, category, column or"
+      " row does not exist.\n");
+  if ((err&CBF_OVERFLOW)==CBF_OVERFLOW)
+    fprintf(stderr, " cif2nx: The number read cannot fit into the "
+      "destination argument.\n        The destination has been set to the nearest value.\n");
+  if ((err& CBF_UNDEFINED)==CBF_UNDEFINED)
+    fprintf(stderr, " cif2nx: The requested number is not defined (e.g. 0/0).\n");
+  if ((err&CBF_NOTIMPLEMENTED)==CBF_NOTIMPLEMENTED)
+    fprintf(stderr, " cif2nx: The requested functionality is not yet implemented.\n");
+    return 0;
+
+}
+
+#undef cbf_failnez
+#define cbf_failnez(x) \
+ {int err; \
+  err = (x); \
+  if (err) { \
+    fprintf(stderr," cif2nx: CBFlib fatal error %d\n",err); \
+    outerror(err); \
+    local_exit (-1); \
+  } \
+ }
+
+/* format a value into a properly quoted, newly allocated string
+   according to type:
+   
+     "sglq"  -- put '\'' before and after the value
+     "dblq"  -- put '"'  before and after the value
+     "text"  -- put "\n;" before and "\n;\n" after the value
+     for other types ("word" and "null") copy the string unchanged
+     unless it is empty, in which case deliver "."     
+     
+  Note that the newly allocated itembuf must eventually be freed
+  to avoid a memory leak */
+
+
+int cbf_format_dataitem(char ** itembuf, const char* value, const char* type) {
+
+  size_t numchars, slen;
+  char * strbuf;
+  char * pchar;
+  
+  slen = strlen(value);
+  numchars = slen+1;
+  if (slen == 0) numchars++;
+  if (!cbf_cistrcmp(type,"sglq") || !cbf_cistrcmp(type,"dblq")) numchars +=2;
+  if (!cbf_cistrcmp(type,"text") ) numchars +=5;
+  
+  if (!(strbuf = (char *)malloc(numchars) ) ) return CBF_ALLOC;
+  
+  pchar = strbuf;
+  
+  if (!cbf_cistrcmp(type,"sglq")) {
+  	*pchar++='\'';
+    strcpy(pchar,value);
+    pchar+=slen;
+    *pchar++='\'';
+  } else if (!cbf_cistrcmp(type,"dblq")) {
+  	*pchar++='"';
+    strcpy(pchar,value);
+    pchar+=slen;
+    *pchar++='"';
+  } else if (!cbf_cistrcmp(type,"text")) {
+    *pchar++='\n'; *pchar++=';';
+    strcpy(pchar,value);
+    pchar+=slen;
+    *pchar++='\n'; *pchar++=';'; *pchar++='\n';
+  } else {
+    if (slen == 0) {
+      strcpy(pchar,".");
+      pchar++;
+    } else {
+    strcpy(pchar,value);
+    pchar+=slen;  	    	
+    }
+  }
+  *pchar++ = '\0';
+  *itembuf = strbuf;
+  return 0;	
+}
+
+int main (int argc, char *argv [])
+{
+  FILE *in, *out=NULL, *file, *dict;
+  clock_t a,b;
+  cbf_handle cif;
+  NXhandle nxf=NULL;
+  int nxf_access=NXACC_CREATEXML;
+  int nxrank[3];
+  int nexus_compression;
+  cbf_handle dic;
+  cbf_handle odic;
+  int devnull = 0;
+  int c;
+  int errflg = 0;
+  char *cifin, *nxout;
+  char *dictionary[NUMDICTS];
+  char *nxprefix;
+  char nxcifbuf[90];
+  char nxcifrow[90];
+  char *ciftmp=NULL;
+#ifndef NOMKSTEMP
+  int ciftmpfd;
+#endif
+  int ciftmpused;
+  int padflag;
+  int nbytes;
+  int ndict = 0;
+  int kd;
+  int wide = 0;
+  int nxcifbufbase = 6;
+  int nxcifrowbase = 6;
+  char buf[C2CBUFSIZ];
+  unsigned int blocks, categories, blocknum, catnum, blockitems, itemnum;
+  CBF_NODETYPE itemtype;
+  const char *datablock_name;
+  const char *saveframe_name;
+  const char *category_name;
+  const char *column_name;
+  const char *value;
+  char *cifname;
+  unsigned int colnum, rownum;
+  unsigned int columns;
+  unsigned int rows;
+
+  int mime, digest, encoding, compression, bytedir, cbforcif, term;
+
+
+     /* Extract options */
+
+/**********************************************************************
+ *  cif2nx [-i input_cif] [-o output_nx] \                            *
+ *    [-e [4|5|x]] [-c [n|g|h|r]]        \                            *
+ *    [-n cifname] [-p prefix ]          \                                                  *
+ *    [-v dictionary]* \                                              *
+ *    [input_cif] [output_nx]                                         *
+ *                                                                    *
+ **********************************************************************/
+
+   mime = 0;
+   digest = 0;
+   encoding = 0;
+   compression = 0;
+   nexus_compression=NX_COMP_LZW;
+   bytedir = 0;
+   ndict = 0;
+   padflag = 0;
+
+   cifin = NULL;
+   nxout = NULL;
+   cifname = NULL;
+   nxprefix = NULL;
+   ciftmpused = 0;
+   
+   
+   
+   while ((c = getopt(argc, argv, "i:o:v:e:c:n:p:")) != EOF) {
+     switch (c) {
+       case 'i':
+         if (cifin) errflg++;
+         else cifin = optarg;
+         break;
+       case 'o':
+         if (nxout) errflg++;
+         else nxout = optarg;
+         break;
+       case 'n':
+         if (cifname) errflg++;
+         else cifname = optarg;
+         break;
+       case 'p':
+         if (nxprefix) errflg++;
+         else nxprefix = optarg;
+         break;
+       case 'v':
+         if (ndict < NUMDICTS)
+           dictionary[ndict++] = optarg;
+         else if (ndict == NUMDICTS) {
+           errflg++;
+           ndict++;
+           fprintf(stderr, " cif2nx: Too many dictionaries, increase NUMDICTS");
+         }
+         break;
+       case 'e':
+         if (optarg[0]=='4')  {
+         	nxf_access=NXACC_CREATE4;
+         } else if (optarg[0]=='5') {
+         	nxf_access=NXACC_CREATE5;
+         } else if (optarg[0]=='x') {
+         	nxf_access=NXACC_CREATEXML;
+         } else errflg++;
+     	 break;
+       case 'c':
+         if (optarg[0]=='n')  {
+         	compression=0;
+         } else if (optarg[0]=='g') {
+            compression=1; nexus_compression=NX_COMP_LZW;
+         } else if (optarg[0]=='h') {
+            compression=1; nexus_compression=NX_COMP_HUF;
+         } else if (optarg[0]=='r') {
+            compression=1; nexus_compression=NX_COMP_RLE;
+         } else errflg++;
+         break;
+       default:
+         errflg++;
+         break;
+      }
+    }
+   for (; optind < argc; optind++) {
+     if (!cifin) {
+        cifin = argv[optind];
+     } else {
+       if (!nxout) {
+         nxout = argv[optind];
+       } else {
+         errflg++;
+       }
+     }
+   }
+   if (errflg) {
+     fprintf(stderr," cif2nx:  Usage: \n");
+     fprintf(stderr,
+       "  cif2nx [-i input_cif] [-o output_nx] \\\n");
+     fprintf(stderr,
+       "    [-e [4|5|x]] [-c [n|g|h|r]] \\\n");
+     fprintf(stderr,
+       "    [-n cifname] [-p nxprefix]  \\\n");
+     fprintf(stderr,
+       "    [-v dictionary]* \\\n");
+     fprintf(stderr,
+       "    [input_cif] [output_nx] \n\n");
+     exit(2);
+   }
+
+
+    /* Use "NXcif_" as a prefix if nothing has been specified */
+    
+    if (!nxprefix) nxprefix = "NXcif_";
+    strncpy(nxcifbuf,nxprefix,75);
+    nxcifbuf[75] = '\0';
+    strcpy(nxcifrow,nxprefix);
+    nxcifbufbase=strlen(nxcifbuf);
+    nxcifrowbase=strlen(nxcifrow);
+    
+
+    /* Read the cif */
+
+   if (!cifin || strcmp(cifin?cifin:"","-") == 0) {
+     ciftmp = (char *)malloc(strlen("/tmp/cif2nxXXXXXX")+1);
+#ifdef NOTMPDIR
+     strcpy(ciftmp, "cif2nxXXXXXX");
+#else
+     strcpy(ciftmp, "/tmp/cif2nxXXXXXX");
+#endif
+#ifdef NOMKSTEMP
+     if ((ciftmp = mktemp(ciftmp)) == NULL ) {
+       fprintf(stderr," cif2nx: Can't create temporary file name %s.\n", ciftmp);
+       fprintf(stderr,"%s\n",strerror(errno));
+       local_exit (1);
+     }
+     if ( (file = fopen(ciftmp,"wb+")) == NULL) {
+       fprintf(stderr," cif2nx: Can't open temporary file %s.\n", ciftmp);
+       fprintf(stderr,"%s\n",strerror(errno));
+       local_exit (1);     	
+     }
+#else
+     if ((ciftmpfd = mkstemp(ciftmp)) == -1 ) {
+       fprintf(stderr," cif2nx: Can't create temporary file %s.\n", ciftmp);
+       fprintf(stderr,"%s\n",strerror(errno));
+       local_exit (1);
+     }
+     if ( (file = fdopen(ciftmpfd, "w+")) == NULL) {
+       fprintf(stderr," cif2nx: Can't open temporary file %s.\n", ciftmp);
+       fprintf(stderr,"%s\n",strerror(errno));
+       local_exit (1);
+     }
+#endif
+     while ((nbytes = fread(buf, 1, C2CBUFSIZ, stdin))) {
+       if(nbytes != fwrite(buf, 1, nbytes, file)) {
+         fprintf(stderr," cif2nx: Failed to write %s.\n", ciftmp);
+         local_exit (1);
+       }
+     }
+     fclose(file);
+     cifin = ciftmp;
+     ciftmpused = 1;
+   }
+   if ( cbf_make_handle (&cif) ) {
+     fprintf(stderr," cif2nx: Failed to create handle for input_cif\n");
+     local_exit (1);
+   }
+   
+   if ( cbf_make_handle (&dic) ) {
+     fprintf(stderr," cif2nx: Failed to create handle for dictionary\n");
+     local_exit (1);
+   }
+
+
+   for (kd=0; kd< ndict; kd++) {
+   
+     if (!(dict = fopen (dictionary[kd], "rb")))  {
+     	fprintf (stderr," cif2nx: Couldn't open the dictionary %s\n", dictionary[kd]);
+        exit (1);
+     }
+     cbf_failnez(cbf_read_widefile(dic, dict, MSG_DIGEST))
+     cbf_failnez(cbf_convert_dictionary(cif,dic))
+   	
+   }
+   
+   a = clock ();
+
+   /* Read the file */
+   if (!(in = fopen (cifin, "rb"))) {
+     fprintf (stderr," cif2nx: Couldn't open the input CIF file %s\n", cifin);
+     exit (1);
+   }
+
+   if (ciftmpused) {
+     if (unlink(ciftmp) != 0 ) {
+       fprintf(stderr," cif2cif:  Can't unlink temporary file %s.\n", ciftmp);
+       fprintf(stderr,"%s\n",strerror(errno));
+       local_exit (1);
+     }
+   }
+
+   cbf_failnez (cbf_read_widefile (cif, in, MSG_DIGEST))
+   
+   /* Open the output file */
+   
+   if (NXopen (nxout, nxf_access, &nxf) != NX_OK) {
+     fprintf (stderr," cif2nx: Couldn't open the output NeXus file %s\n", nxout);
+   }
+   
+   if (!cifname) cifname = "NXcif";
+       
+   if (NXmakegroup (nxf, cifname, "NXcif") != NX_OK) {
+     	fprintf(stderr," cif2nx: Failed to create group NXcif::%s\n",cifname);
+        local_exit (1);
+   }
+   if (NXopengroup (nxf, cifname, "NXcif") != NX_OK) {
+     	fprintf(stderr," cif2nx: Failed to open group NXcif::%s\n",cifname);
+        local_exit (1);
+   }
+    
+
+   cbf_failnez (cbf_rewind_datablock(cif))
+
+   cbf_failnez (cbf_count_datablocks(cif, &blocks))
+
+   for (blocknum = 0; blocknum < blocks;  blocknum++ )
+   { /* start of copy loop */
+       
+       char ** columnarray = NULL; 
+       char ** columnarraytype; 
+       
+       cbf_failnez (cbf_select_datablock(cif, blocknum))
+       cbf_failnez (cbf_datablock_name(cif, &datablock_name))
+       strcpy(nxcifbuf+nxcifbufbase,"datablock");
+       if (NXmakegroup (nxf, datablock_name, nxcifbuf) != NX_OK) {
+           fprintf(stderr," cif2nx: Failed to create datablock %s\n",datablock_name);
+           local_exit (1);
+       }
+       if (NXopengroup (nxf, datablock_name, nxcifbuf) != NX_OK) {
+           fprintf(stderr," cif2nx: Failed to open datablock %s\n",datablock_name);
+           local_exit (1);
+       }
+       
+       if ( !cbf_rewind_blockitem(cif, &itemtype) ) {
+           cbf_failnez (cbf_count_blockitems(cif, &blockitems))
+           
+           for (itemnum = 0; itemnum < blockitems;  itemnum++) {
+               cbf_select_blockitem(cif, itemnum, &itemtype);
+               if (itemtype == CBF_CATEGORY) {
+                   cbf_category_name(cif,&category_name);
+                   /* Create the category group for this category */
+                   strcpy(nxcifbuf+nxcifbufbase,"category");
+                   if (NXmakegroup (nxf, category_name, nxcifbuf) != NX_OK) {
+                       fprintf(stderr," cif2nx: Failed to create category %s\n",category_name);
+                       local_exit (1);
+                   }
+                   /*  Open the category group for this category */
+                   if (NXopengroup (nxf, category_name, nxcifbuf) != NX_OK) {
+                       fprintf(stderr," cif2nx: Failed to open category %s\n",category_name);
+                       local_exit (1);
+                   }
+                   cbf_count_rows(cif,&rows);
+                   nxrank[0]=rows;
+                   nxrank[1]=2;
+                   if (rows) columnarray = (char **)malloc(rows*sizeof(char *)*2);
+                   if (rows && !columnarray) {
+                       fprintf(stderr," cif2nx: Failed to allocate columnarray %s\n",category_name);
+                       local_exit (1);
+                   }
+                   columnarraytype = columnarray+rows;
+                   cbf_count_columns(cif,&columns);
+                   
+                   /*  Transfer the columns names from cif to nexus */
+                   if (columns && ! cbf_rewind_column(cif) ) {
+                       int somebinary;
+                       unsigned int irn=0;
+                       int irnrank=1;
+                       char scratchbuf[40];
+                       do {
+                           cbf_failnez(cbf_column_name(cif, &column_name))
+                           cbf_rewind_row(cif);
+                           somebinary=0;
+                           /* Transfer column from cif to nexus */
+                           for (rownum = 0; rownum < rows; rownum++) {
+                               const char *typeofvalue;
+                               columnarray[rownum]=NULL;
+                               columnarraytype[rownum]=NULL;
+                               cbf_failnez(cbf_select_row(cif,rownum))
+                               if ( ! cbf_get_value(cif, &value) ) {
+                                   cbf_failnez (cbf_get_typeofvalue(cif, &typeofvalue))
+                                   columnarray[rownum]=(char *)value;
+                                   columnarraytype[rownum]=(char *)typeofvalue;
+                                   if (!columnarray[rownum]) {
+                                       columnarray[rownum] = ".";
+                                       columnarraytype[rownum] = "null";
+                                   }
+                                   if (columnarraytype[rownum]==NULL) columnarraytype[rownum]= "undefined";
+                                   
+                                   /* DEBUG:  fprintf(stderr,"Column %s, row %d, value %s, type %s\n",
+                                    column_name, rownum, columnarray[rownum], columnarraytype[rownum] ); */
+                                   
+                                   if (somebinary) {
+                                       char * strbuf;
+                                       sprintf(nxcifrow,"data[%-d]",rownum);
+                                       if (rows==1)sprintf(nxcifrow,"data");
+                                       cbf_failnez(cbf_format_dataitem(&strbuf,columnarray[rownum],columnarraytype[rownum]))
+                                       irnrank=strlen(strbuf)+1;
+                                       if (irnrank < 4096 || !compression){
+                                           if (NXmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1);
+                                           }
+                                       } else {
+                                           if (NXcompmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank, nexus_compression, &irnrank) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1);
+                                           }                 	
+                                       }
+                                       if (NXopendata (nxf, nxcifrow) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to open row %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);
+                                       }
+                                       if (NXputdata (nxf, strbuf ) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1); 	
+                                       } 
+                                       free(strbuf);
+                                       if (NXputattr(nxf,"items","1",1,NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store itemcount of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       NXclosedata(nxf);
+                                   }
+                               } else {
+                                   char * typebuffer;
+                                   void * array;
+                                   int binary_id, elsigned, elunsigned;
+                                   size_t elements,elements_read, elsize;
+                                   int minelement, maxelement;
+                                   unsigned int cifcompression;
+                                   int realarray;
+                                   const char *byteorder;
+                                   size_t dim1, dim2, dim3, padding;
+                                   
+                                   /* If this is the first encounter with a binary in the column
+                                    we need to create a group for the column and move whatever rows
+                                    were being saved in columnarray into individual datasets  */
+                                   
+                                   if (!somebinary) {
+                                       
+                                       strcpy(nxcifbuf+nxcifbufbase,"column");
+                                       if (NXmakegroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                           local_exit (1);
+                                       }
+                                       if (NXopengroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to open column %s\n",column_name);
+                                           local_exit (1);
+                                       }
+                                       /* copy the rows that were already done */
+                                       for (irn = 0; irn < rownum; irn++) {
+                                           char * strbuf;
+                                           sprintf(nxcifrow,"data[%-d]",irn);
+                                           if (rows==1) sprintf(nxcifrow,"data");
+                                           cbf_failnez(cbf_format_dataitem(&strbuf,columnarray[irn],columnarraytype[irn]))
+                                           irnrank=strlen(strbuf)+1;
+                                           if (irnrank < 4096 || !compression){
+                                               if (NXmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);
+                                               }
+                                           } else {
+                                               if (NXcompmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank, nexus_compression, &irnrank) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);
+                                               }                 	
+                                           }
+                                           
+                                           if (NXopendata (nxf, nxcifrow) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to open %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1);
+                                           }
+                                           if (NXputdata (nxf, strbuf ) != NX_OK ) {
+                                               fprintf(stderr," cif2nx: Failed to store %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1); 	
+                                           } 
+                                           free(strbuf);
+                                           if (NXputattr(nxf,"items","1",1,NX_CHAR) != NX_OK ) {
+                                               fprintf(stderr," cif2nx: Failed to store itemcount of %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1);	
+                                           }
+                                           NXclosedata(nxf);
+                                       }
+                                       somebinary = 1;
+                                   }
+                                   
+                                   
+                                   /* The data we get from CIF may be an integer array of up to 3 dimensions
+                                    or a real array of up to 3 dimensions.  (Note that the limit to 3 dimensions
+                                    is just a matter of the current CBFlib API.  CBF itself may have any number
+                                    of dimensions, and this should be allowed for in anything we do here) */
+                                   
+                                   cbf_failnez(cbf_get_arrayparameters_wdims(
+                                                                             cif, &cifcompression,
+                                                                             &binary_id, &elsize, &elsigned, &elunsigned,
+                                                                             &elements, &minelement, &maxelement, &realarray,
+                                                                             &byteorder, &dim1, &dim2, &dim3, &padding))
+                                   if ((array=malloc(elsize*elements))) {
+                                       
+                                       int ii, arrayrank, nexustype;
+                                       
+                                       if (!realarray)  {
+                                           cbf_failnez (cbf_get_integerarray(
+                                                                             cif, &binary_id, array, elsize, elsigned,
+                                                                             elements, &elements_read))
+                                       } else {
+                                           cbf_failnez (cbf_get_realarray(
+                                                                          cif, &binary_id, array, elsize,
+                                                                          elements, &elements_read))
+                                           elsigned = 1;
+                                       }
+                                       nxrank[0] = dim1;
+                                       nxrank[1] = dim2;
+                                       nxrank[2] = dim3;
+                                       
+                                       nexustype = NX_UINT8;
+                                       if (realarray) {
+                                           if (elsize == 4) nexustype = NX_FLOAT32;
+                                           else if (elsize == 8) nexustype = NX_FLOAT64;
+                                       } else {
+                                           if (elunsigned) {
+                                               if (elsize == 1) nexustype = NX_UINT8;
+                                               else if (elsize == 2) nexustype = NX_UINT16;
+                                               else if (elsize == 4) nexustype = NX_UINT32;                       	
+                                           } else {
+                                               if (elsize == 1) nexustype = NX_INT8;
+                                               else if (elsize == 2) nexustype = NX_INT16;
+                                               else if (elsize == 4) nexustype = NX_INT32;                       	
+                                               
+                                           }
+                                           
+                                       }
+                                       
+                                       arrayrank=1;
+                                       for (ii=0; ii< 3; ii++)  {
+                                           if (nxrank[ii] == 0) nxrank[ii] = 1;
+                                           if (nxrank[ii] > 1) arrayrank = ii+1;
+                                       }
+                                       if (nexustype == NX_UINT8) nxrank[0] *= elsize;
+                                       
+                                       
+                                       /* Now we have already made the column into a group and the rows into
+                                        data sets, the group for the column is open.  We need to create and
+                                        populate the data set as the next row */ 
+                                       
+                                       sprintf(nxcifrow,"data[%-d]",rownum);
+                                       if (rows==1)sprintf(nxcifrow,"data");
+                                       if (!compression)  {
+                                           if (NXmakedata (nxf, nxcifrow, nexustype, arrayrank, nxrank) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1);
+                                           }
+                                       } else  {
+                                           if (NXcompmakedata (nxf, nxcifrow, nexustype, arrayrank, nxrank,nexus_compression,nxrank) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                               local_exit (1);
+                                           }                   	
+                                       }
+                                       if (NXopendata (nxf, nxcifrow) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to open %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);
+                                       }
+                                       if (NXputdata (nxf,array) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to put data in open %s in column %s\n",nxcifrow,column_name);
+                                       }
+                                       free(array);
+                                       if (NXputattr(nxf,"items","1",1,NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store itemcount of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       if (NXputattr(nxf,"NXciftype","binary",strlen("binary"),NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store CIF type of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       if (NXputattr(nxf,"NXcifarrayelementtype",
+                                                     realarray?"real":"integer",
+                                                     strlen(realarray?"real":"integer"),NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store CIF arrayelementtype of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       sprintf(scratchbuf,"%-ld",elsize);
+                                       if (NXputattr(nxf,"NXcifarrayelementsize",scratchbuf,strlen(scratchbuf),NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store CIF arrayelementsize of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       if (NXputattr(nxf,"NXcifarrayelementsign",
+                                                     elunsigned?"unsigned":"signed",
+                                                     strlen(elunsigned?"unsigned":"signed"),NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store CIF arrayelementsign of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       if (NXputattr(nxf,"NXcifarraybyteorder", (char *)byteorder, strlen(byteorder),NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store CIF arraybyteorder of %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       NXclosedata(nxf);
+                                       
+                                       NXflush(&nxf);
+                                       
+                                       
+                                   } else {
+                                       fprintf(stderr,
+                                               "\nFailed to allocate memory %ld bytes",
+                                               (long) elsize*elements);
+                                       local_exit (1);
+                                   }
+                                   
+                               }
+                           }
+                           for (rownum = 0; rownum < rows; rownum++) {
+                               if (columnarraytype[rownum]==NULL) columnarraytype[rownum]= "null";
+                               /* DEBUG:  fprintf(stderr,"Column %s, row %d, value %s, type %s\n",
+                                column_name, rownum, columnarray[rownum], columnarraytype[rownum] ); */
+                               
+                           }
+                           
+                           if (!somebinary) {
+                               
+                               int numchars;
+                               char * strbuf;
+                               char * pchar;
+                               
+                               /* Create and open a column group to hold the entire column */
+                               
+                               strcpy(nxcifbuf+nxcifbufbase,"column");
+                               if (NXmakegroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                   fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                   local_exit (1);
+                               }
+                               if (NXopengroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                   fprintf(stderr," cif2nx: Failed to open column %s\n",column_name);
+                                   local_exit (1);
+                               }
+                               
+                               /* The rows have not been transferred.  We will convert to one
+                                large concatenated string, putting a newline between rows */
+                               
+                               numchars = 0;
+                               for (rownum = 0; rownum < rows;rownum++) {
+                                   numchars++;
+                                   numchars+=strlen(columnarray[rownum]);
+                                   if (!cbf_cistrcmp(columnarraytype[rownum],"sglq") || 
+                                       !cbf_cistrcmp(columnarraytype[rownum],"dblq")) numchars+=2;
+                                   if (!cbf_cistrcmp(columnarraytype[rownum],"text")) numchars+=5;
+                               }
+                               
+                               numchars++;
+                               
+                               if (!(strbuf = (char *)malloc(numchars) ) ) {
+                                   fprintf(stderr," cbf2nx -- Failed to allocate memory for category %s column %s\n",
+                                           category_name,column_name);
+                               }
+                               
+                               pchar = strbuf;
+                               if (rows > 1) *pchar++='\n';
+                               
+                               for (rownum = 0; rownum < rows; rownum++) {
+                                   if (rownum > 0)  *pchar++='\n';
+                                   if (!cbf_cistrcmp(columnarraytype[rownum],"sglq")) {
+                                       *pchar++='\'';
+                                       strcpy(pchar,columnarray[rownum]);
+                                       pchar+=strlen(columnarray[rownum]);
+                                       *pchar++='\'';
+                                       continue;
+                                   }
+                                   if (!cbf_cistrcmp(columnarraytype[rownum],"dblq")) {
+                                       *pchar++='\"';
+                                       strcpy(pchar,columnarray[rownum]);
+                                       pchar+=strlen(columnarray[rownum]);
+                                       *pchar++='\"';
+                                       continue;
+                                   }
+                                   if (!cbf_cistrcmp(columnarraytype[rownum],"text")) {
+                                       *pchar++='\n'; *pchar++=';';
+                                       strcpy(pchar,columnarray[rownum]);
+                                       pchar+=strlen(columnarray[rownum]);
+                                       *pchar++='\n'; *pchar++=';';
+                                       continue;
+                                   }
+                                   strcpy(pchar,columnarray[rownum]);
+                                   pchar+=strlen(columnarray[rownum]);
+                               }
+                               *pchar++='\0';
+                               numchars = strlen(strbuf)+1;
+                               
+                               if (numchars < 4096 || !compression) {
+                                   if (NXmakedata (nxf, "data", NX_CHAR, 1, &numchars) != NX_OK) {
+                                       fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                       local_exit (1);
+                                   }	
+                               } else  {
+                                   if (NXcompmakedata (nxf, "data", NX_CHAR, 1, &numchars,nexus_compression, &numchars) != NX_OK) {
+                                       fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                       local_exit (1);
+                                   }
+                               }
+                               if (NXopendata (nxf, "data") != NX_OK) {
+                                   fprintf(stderr," cif2nx: Failed to open column %s\n",column_name);
+                                   local_exit (1);
+                               }
+                               if (NXputdata (nxf, strbuf) != NX_OK ) {
+                                   fprintf(stderr," cif2nx: Failed to store column %s\n",column_name);
+                                   local_exit (1);	
+                               }
+                               sprintf(nxcifrow,"%-d",rows);
+                               if (NXputattr(nxf,"items",nxcifrow,strlen(nxcifrow),NX_CHAR) != NX_OK ) {
+                                   fprintf(stderr," cif2nx: Failed to store itemcount %s in column %s\n",nxcifrow,column_name);
+                                   local_exit (1);	
+                               }
+                               free(strbuf);
+                               NXclosedata( nxf ); /* close the columns as a data set */
+                           }
+                           NXclosegroup( nxf); /* close the columns as a group */
+                       } while ( ! cbf_next_column(cif) );
+                       if (rows) free(columnarray);
+                   }
+                   NXclosegroup( nxf ); /* close the category */
+               } else {
+                   cbf_saveframe_name(cif,&saveframe_name);
+                   strcpy(nxcifbuf+nxcifbufbase,"saveframe");
+                   if (NXmakegroup (nxf, saveframe_name, nxcifbuf) != NX_OK) {
+                       fprintf(stderr," cif2nx: Failed to create saveframe %s\n",saveframe_name);
+                       local_exit (1);
+                   }
+                   if (NXopengroup (nxf, saveframe_name, nxcifbuf) != NX_OK) {
+                       fprintf(stderr," cif2nx: Failed to open saveframe %s\n",saveframe_name);
+                       local_exit (1);
+                   }
+                   if ( !cbf_rewind_category(cif) ) {
+                       cbf_failnez (cbf_count_categories(cif, &categories))
+                       
+                       for (catnum = 0; catnum < categories;  catnum++) {
+                           cbf_select_category(cif, catnum);
+                           cbf_category_name(cif,&category_name);
+                           strcpy(nxcifbuf+nxcifbufbase,"category");
+                           if (NXmakegroup (nxf, category_name, nxcifbuf) != NX_OK) {
+                               fprintf(stderr," cif2nx: Failed to create category %s\n",category_name);
+                               local_exit (1);
+                           }
+                           if (NXopengroup (nxf, category_name, nxcifbuf) != NX_OK) {
+                               fprintf(stderr," cif2nx: Failed to open category %s\n",category_name);
+                               local_exit (1);
+                           }
+                           cbf_count_rows(cif,&rows);
+                           nxrank[0]=rows;
+                           nxrank[1]=2;
+                           if (rows) columnarray = (char **)malloc(rows*sizeof(char *)*2);
+                           if (rows && !columnarray) {
+                               fprintf(stderr," cif2nx: Failed to allocate columnarray %s\n",category_name);
+                               local_exit (1);
+                           }
+                           columnarraytype = columnarray+rows;
+                           cbf_count_columns(cif,&columns);
+                           
+                           /*  Transfer the columns names from cif to nexus */
+                           if (columns && ! cbf_rewind_column(cif) ) {
+                               int somebinary;
+                               somebinary = 0;
+                               unsigned int irn;
+                               int irnrank=1;
+                               char scratchbuf[40];
+                               do {
+                                   cbf_failnez(cbf_column_name(cif, &column_name))
+                                   cbf_rewind_row(cif);
+                                   /* Transfer column from cif to nexus */
+                                   for (rownum = 0; rownum < rows; rownum++) {
+                                       const char *typeofvalue;
+                                       columnarray[rownum]=NULL;
+                                       columnarraytype[rownum]=NULL;
+                                       cbf_failnez(cbf_select_row(cif,rownum))
+                                       if ( ! cbf_get_value(cif, &value) ) {
+                                           cbf_failnez (cbf_get_typeofvalue(cif, &typeofvalue))
+                                           columnarray[rownum]=(char *)value;
+                                           columnarraytype[rownum]=(char *)typeofvalue;
+                                           if (!columnarray[rownum]) {
+                                               columnarray[rownum] = ".";
+                                               columnarraytype[rownum] = "null";
+                                           }
+                                           if (columnarraytype[rownum]==NULL) columnarraytype[rownum]= "undefined";
+                                           if (somebinary) {
+                                               char * strbuf;
+                                               sprintf(nxcifrow,"data[%-d]",rownum);
+                                               if (rows==1)sprintf(nxcifrow,"data");
+                                               cbf_failnez(cbf_format_dataitem(&strbuf,columnarray[rownum],columnarraytype[rownum]))
+                                               irnrank=strlen(strbuf)+1;
+                                               if (irnrank < 4096 || !compression){
+                                                   if (NXmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank) != NX_OK) {
+                                                       fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1);
+                                                   }
+                                               } else {
+                                                   if (NXcompmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank, nexus_compression, &irnrank) != NX_OK) {
+                                                       fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1);
+                                                   }                 	
+                                               }
+                                               if (NXopendata (nxf, nxcifrow) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to open%s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);
+                                               }
+                                               if (NXputdata (nxf, strbuf ) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1); 	
+                                               } 
+                                               free(strbuf);
+                                               if (NXputattr(nxf,"items","1",1,NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store itemcount of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               NXclosedata(nxf);
+                                           }
+                                       } else {
+                                           char * typebuffer;
+                                           void * array;
+                                           int binary_id, elsigned, elunsigned;
+                                           size_t elements,elements_read, elsize;
+                                           int minelement, maxelement;
+                                           unsigned int cifcompression;
+                                           int realarray;
+                                           const char *byteorder;
+                                           size_t dim1, dim2, dim3, padding;
+                                           
+                                           /* If this is the first encounter with a binary in the column
+                                            we need to create a group for the column and move whatever rows
+                                            were being saved in columnarray into individual datasets  */
+                                           
+                                           if (!somebinary) {
+                                               
+                                               strcpy(nxcifbuf+nxcifbufbase,"column");
+                                               if (NXmakegroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                                   local_exit (1);
+                                               }
+                                               if (NXopengroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to open column %s\n",column_name);
+                                                   local_exit (1);
+                                               }
+                                               /* copy the rows that were already done */
+                                               for (irn = 0; irn < rownum; irn++) {
+                                                   char* strbuf;
+                                                   sprintf(nxcifrow,"data[%-d]",irn);
+                                                   if (rows==1) sprintf(nxcifrow,"data");
+                                                   cbf_failnez(cbf_format_dataitem(&strbuf,columnarray[irn],columnarraytype[irn]))
+                                                   irnrank=strlen(strbuf)+1;
+                                                   if (irnrank < 4096 || !compression){
+                                                       if (NXmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank) != NX_OK) {
+                                                           fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                           local_exit (1);
+                                                       }
+                                                   } else {
+                                                       if (NXcompmakedata (nxf, nxcifrow, NX_CHAR, 1, &irnrank, nexus_compression, &irnrank) != NX_OK) {
+                                                           fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                           local_exit (1);
+                                                       }                 	
+                                                   }
+                                                   if (NXopendata (nxf, nxcifrow) != NX_OK) {
+                                                       fprintf(stderr," cif2nx: Failed to open %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1);
+                                                   }
+                                                   if (NXputdata (nxf, strbuf ) != NX_OK ) {
+                                                       fprintf(stderr," cif2nx: Failed to store %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1); 	
+                                                   } 
+                                                   free(strbuf);
+                                                   
+                                                   if (NXputattr(nxf,"items","1",1,NX_CHAR) != NX_OK ) {
+                                                       fprintf(stderr," cif2nx: Failed to store rowspan of row %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1);	
+                                                   }
+                                                   NXclosedata(nxf);
+                                               }
+                                               somebinary = 1;
+                                           }
+                                           
+                                           
+                                           /* The data we get from CIF may be an integer array of up to 3 dimensions
+                                            or a real array of up to 3 dimensions.  (Note that the limit to 3 dimensions
+                                            is just a matter of the current CBFlib API.  CBF itself may have any number
+                                            of dimensions, and this should be allowed for in anything we do here) */
+                                           
+                                           cbf_failnez(cbf_get_arrayparameters_wdims(
+                                                                                     cif, &cifcompression,
+                                                                                     &binary_id, &elsize, &elsigned, &elunsigned,
+                                                                                     &elements, &minelement, &maxelement, &realarray,
+                                                                                     &byteorder, &dim1, &dim2, &dim3, &padding))
+                                           if ((array=malloc(elsize*elements))) {
+                                               
+                                               int ii, arrayrank, nexustype;
+                                               
+                                               if (!realarray)  {
+                                                   cbf_failnez (cbf_get_integerarray(
+                                                                                     cif, &binary_id, array, elsize, elsigned,
+                                                                                     elements, &elements_read))
+                                               } else {
+                                                   cbf_failnez (cbf_get_realarray(
+                                                                                  cif, &binary_id, array, elsize,
+                                                                                  elements, &elements_read))
+                                                   elsigned = 1;
+                                               }
+                                               nxrank[0] = dim1;
+                                               nxrank[1] = dim2;
+                                               nxrank[2] = dim3;
+                                               
+                                               nexustype = NX_UINT8;
+                                               if (realarray) {
+                                                   if (elsize == 4) nexustype = NX_FLOAT32;
+                                                   else if (elsize == 8) nexustype = NX_FLOAT64;
+                                               } else {
+                                                   if (elunsigned) {
+                                                       if (elsize == 1) nexustype = NX_UINT8;
+                                                       else if (elsize == 2) nexustype = NX_UINT16;
+                                                       else if (elsize == 4) nexustype = NX_UINT32;                       	
+                                                   } else {
+                                                       if (elsize == 1) nexustype = NX_INT8;
+                                                       else if (elsize == 2) nexustype = NX_INT16;
+                                                       else if (elsize == 4) nexustype = NX_INT32;
+                                                   }
+                                               }
+                                               
+                                               arrayrank=1;
+                                               for (ii=0; ii< 3; ii++)  {
+                                                   if (nxrank[ii] == 0) nxrank[ii] = 1;
+                                                   if (nxrank[ii] > 1) arrayrank = ii+1;
+                                               }
+                                               if (nexustype == NX_UINT8) nxrank[0] *= elsize;
+                                               
+                                               /* Now we have already made the column into a group and the rows into
+                                                data sets, the group for the column is open.  We need to create and
+                                                populate the data set as the next row */ 
+                                               
+                                               
+                                               sprintf(nxcifrow,"data[%-d]",rownum);
+                                               if (rows==1)sprintf(nxcifrow,"data");
+                                               if (!compression) {
+                                                   if (NXmakedata (nxf, nxcifrow, nexustype, 1, nxrank) != NX_OK) {
+                                                       fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1);
+                                                   }	
+                                               } else {
+                                                   if (NXcompmakedata (nxf, nxcifrow, nexustype, 1, nxrank, nexus_compression,nxrank) != NX_OK) {
+                                                       fprintf(stderr," cif2nx: Failed to create %s in column %s\n",nxcifrow,column_name);
+                                                       local_exit (1);
+                                                   }	
+                                               }
+                                               if (NXopendata (nxf, nxcifrow) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to open %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);
+                                               }
+                                               if (NXputdata (nxf,array) != NX_OK) {
+                                                   fprintf(stderr," cif2nx: Failed to put data in open %s in column %s\n",nxcifrow,column_name);
+                                               }
+                                               free(array);
+                                               if (NXputattr(nxf,"items","1",1,NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store rowspan of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               if (NXputattr(nxf,"NXciftype","binary",strlen("binary"),NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store CIF type of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               if (NXputattr(nxf,"NXcifarrayelementtype",
+                                                             realarray?"real":"integer",
+                                                             strlen(realarray?"real":"integer"),NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store CIF arrayelementtype of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               sprintf(scratchbuf,"%-ld",elsize);
+                                               if (NXputattr(nxf,"NXcifarrayelementsize",scratchbuf,strlen(scratchbuf),NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store CIF arrayelementsize of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               if (NXputattr(nxf,"NXcifarrayelementsign",
+                                                             elunsigned?"unsigned":"signed",
+                                                             strlen(elunsigned?"unsigned":"signed"),NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store CIF arrayelementsign of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               if (NXputattr(nxf,"NXcifarraybyteorder", (char *)byteorder, strlen(byteorder),NX_CHAR) != NX_OK ) {
+                                                   fprintf(stderr," cif2nx: Failed to store CIF arraybyteorder of %s in column %s\n",nxcifrow,column_name);
+                                                   local_exit (1);	
+                                               }
+                                               NXclosedata(nxf);  /* Close the data set, leave the column open */
+                                               
+                                           } else {
+                                               fprintf(stderr,
+                                                       "\nFailed to allocate memory %ld bytes",
+                                                       (long) elsize*elements);
+                                               local_exit (1);
+                                           } 
+                                       }
+                                   } /* for (rownum = 0; rownum < rows; rownum++) */
+                                   
+                                   /* See if we got to the end without hitting a binary */
+                                   if (!somebinary) {
+                                       
+                                       int numchars;
+                                       char * strbuf;
+                                       char * pchar;
+                                       
+                                       /* Create and open an column group to hold the entire column */
+                                       
+                                       strcpy(nxcifbuf+nxcifbufbase,"column");
+                                       if (NXmakegroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                           local_exit (1);
+                                       }
+                                       if (NXopengroup (nxf, column_name, nxcifbuf) != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to open column %s\n",column_name);
+                                           local_exit (1);
+                                       }
+                                       
+                                       /* The rows have not been transferred.  We will convert to one
+                                        large concatenated string, putting a newline between rows */
+                                       
+                                       for (rownum = 0; rownum < rows;rownum++) {
+                                           numchars++;
+                                           numchars+=strlen(columnarray[rownum]);
+                                           if (!cbf_cistrcmp(columnarraytype[rownum],"sglq") || 
+                                               !cbf_cistrcmp(columnarraytype[rownum],"dblq")) numchars+=2;
+                                           if (!cbf_cistrcmp(columnarraytype[rownum],"text")) numchars+=5;
+                                       }
+                                       
+                                       numchars++;
+                                       
+                                       if (!(strbuf = (char *)malloc(numchars) ) ) {
+                                           fprintf(stderr," cbf2nx -- Failed to allocate memory for category %s column %s\n",
+                                                   category_name,column_name);
+                                       }
+                                       
+                                       pchar = strbuf;
+                                       if (rows > 1) *pchar++='\n';
+                                       
+                                       for (rownum = 0; rownum < rows; rownum++) {
+                                           if (rownum > 0)  *pchar++='\n';
+                                           if (!cbf_cistrcmp(columnarraytype[rownum],"sglq")) {
+                                               *pchar++='\'';
+                                               strcpy(pchar,columnarray[rownum]);
+                                               pchar+=strlen(columnarray[rownum]);
+                                               *pchar++='\'';
+                                               continue;
+                                           }
+                                           if (!cbf_cistrcmp(columnarraytype[rownum],"dblq")) {
+                                               *pchar++='\"';
+                                               strcpy(pchar,columnarray[rownum]);
+                                               pchar+=strlen(columnarray[rownum]);
+                                               *pchar++='\"';
+                                               continue;
+                                           }
+                                           if (!cbf_cistrcmp(columnarraytype[rownum],"text")) {
+                                               *pchar++='\n'; *pchar++=';';
+                                               strcpy(pchar,columnarray[rownum]);
+                                               pchar+=strlen(columnarray[rownum]);
+                                               *pchar++='\n'; *pchar++=';';
+                                               continue;
+                                           }
+                                           strcpy(pchar,columnarray[rownum]);
+                                           pchar+=strlen(columnarray[rownum]);
+                                       }
+                                       *pchar++='\0';
+                                       numchars = strlen(strbuf)+1;
+                                       
+                                       if (numchars < 4096 || !compression) {
+                                           if (NXmakedata (nxf, "data", NX_CHAR, 1, &numchars) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                               local_exit (1);
+                                           }	
+                                       } else {
+                                           if (NXcompmakedata (nxf, "data", NX_CHAR, 1, &numchars, nexus_compression, &numchars) != NX_OK) {
+                                               fprintf(stderr," cif2nx: Failed to create column %s\n",column_name);
+                                               local_exit (1);
+                                           }	
+                                           
+                                       }
+                                       if (NXopendata (nxf, "data") != NX_OK) {
+                                           fprintf(stderr," cif2nx: Failed to open column %s\n",column_name);
+                                           local_exit (1);
+                                       }
+                                       if (NXputdata (nxf, strbuf) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store column %s\n",column_name);
+                                           local_exit (1);	
+                                       }
+                                       sprintf(nxcifrow,"%-d",rows);
+                                       if (NXputattr(nxf,"items",nxcifrow,strlen(nxcifrow),NX_CHAR) != NX_OK ) {
+                                           fprintf(stderr," cif2nx: Failed to store itemcount %s in column %s\n",nxcifrow,column_name);
+                                           local_exit (1);	
+                                       }
+                                       
+                                       free(strbuf);
+                                       NXclosedata( nxf );  /* Close the column as a dataset */
+                                   } 
+                                   NXclosegroup( nxf );  /* Close the column as a group */
+                                   somebinary = 0;
+                               } while ( ! cbf_next_column(cif) );
+                               if (rows) free(columnarray);
+                           }
+                           NXclosegroup( nxf );  /* close the category */
+                       }
+                   }
+                   NXclosegroup( nxf ); /* close the save frame */
+               }
+           }
+           NXclosegroup( nxf ); /* close the data block */
+       }
+       
+   }
+   NXclosegroup( nxf ); /* close the NXcif group */
+
+   b = clock ();
+   fprintf (stderr,
+     " Time to read input_cif: %.3fs\n",
+       ((b - a) * 1.0) / CLOCKS_PER_SEC);
+   a = clock ();
+
+   NXclose( &nxf );
+   b = clock ();
+   fprintf (stderr, " Time to write the NeXus file: %.3fs\n",
+       ((b - a) * 1.0) / CLOCKS_PER_SEC);
+
+   exit(0);
+
+}
+
+int local_exit (int status)
+{
+  exit(status);
+  return 1; /* avoid warnings */
+}
+
+
+
+
+
diff --git a/contrib/applications/CMakeLists.txt b/contrib/applications/CMakeLists.txt
new file mode 100644
index 0000000..c5f105d
--- /dev/null
+++ b/contrib/applications/CMakeLists.txt
@@ -0,0 +1,32 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_subdirectory (CBFLib)
+add_subdirectory (NXextract)
+
+
diff --git a/contrib/applications/Makefile.am b/contrib/applications/Makefile.am
new file mode 100644
index 0000000..b2b9b08
--- /dev/null
+++ b/contrib/applications/Makefile.am
@@ -0,0 +1,19 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  
+# $Id$
+#
+# @configure_input@
+#
+#====================================================================
+#if HAVE_LIBXML2
+#NXTRANSLATE=NXtranslate
+#endif
+#SUBDIRS = NXdir $(NXTRANSLATE)
+if HAVE_CBFLIB
+CBFLIB=CBFLib
+endif
+#if HAVE_LIBMXMLPLUS
+NXEXTRACT=NXextract
+#endif
+SUBDIRS=$(CBFLIB) $(NXEXTRACT)
diff --git a/contrib/applications/NXextract/Makefile.am b/contrib/applications/NXextract/Makefile.am
new file mode 100644
index 0000000..41e2d49
--- /dev/null
+++ b/contrib/applications/NXextract/Makefile.am
@@ -0,0 +1,30 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1251 2009-05-01 15:41:53Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+SUBDIRS = src
+EXTRA_DIST=readme.txt $(srcdir)/example/*.nxe $(srcdir)/example/template_2/*.nxe
diff --git a/contrib/applications/NXextract/example/nxsans2.nxe b/contrib/applications/NXextract/example/nxsans2.nxe
new file mode 100755
index 0000000..9a67c9b
--- /dev/null
+++ b/contrib/applications/NXextract/example/nxsans2.nxe
@@ -0,0 +1,71 @@
+> $(dir)/test2.txt
+
+% text = %File
+"%s\n" $(text)
+"Type=SANSDRaw\n"
+"DataSize=16384\n"
+"FileName= %s\n" $(filename)
+"FileDate=%s\n" nxs:/entry1/start_time
+"Instrument= %s\n" nxs:/entry1/SANS/name
+"Owner= %s\n" nxs:/.owner
+"User= %s\n" nxs:/.owner
+"Telephone=%s\n" nxs:/.owner_telephone_number
+"Fax=%s\n" nxs:/.owner_fax_number
+"Email=%s\n" nxs:/.owner_email
+"Title= %s\n" nxs:/entry1/title
+"FromDate= %s\n" nxs:/entry1/start_time
+"ToDate= %s\n" nxs:/entry1/end_time
+%text = %Sample
+"%s\n" $(text)
+"SampleName= %s\n" nxs:/entry1/sample/name
+"Environment= %s\n" nxs:/entry1/sample/environment
+"PositionName= %s\n" nxs:/entry1/sample/named_position
+"XPos= %f\n" nxs:/entry1/sample/x_position
+"YPos= %f\n" nxs:/entry1/sample/y_position
+"ZPos= %f\n" nxs:/entry1/sample/z_position
+"Omega= %f\n" nxs:/entry1/sample/omega
+"Phi= %f\n" nxs:/entry1/sample/goniometer_phi
+"Theta= %f\n" nxs:/entry1/sample/goniometer_theta
+"Z_Magnet= %f\n" nxs:/entry1/sample/magnet_z
+"Omega_Magnet= %f\n" nxs:/entry1/sample/magnet_omega
+"Position= %f\n" nxs:/entry1/sample/position
+%text = %Setup
+"%s\n" $(text)
+"LambdaC= %f\n" nxs:/entry1/SANS/Dornier-VS/rotation_speed
+"Tilting= %f\n" nxs:/entry1/SANS/Dornier-VS/tilt_angle
+"Lambda= %f\n" nxs:/entry1/SANS/Dornier-VS/lambda
+"Collimation= %f\n" nxs:/entry1/SANS/collimator/length
+?( nxs:/entry1/SANS/polarizer/state
+"Polarization= %s\n" nxs:/entry1/SANS/polarizer/state
+?)
+"Attenuator= %f\n" nxs:/entry1/SANS/attenuator/selection
+"SD= %f\n" nxs:/entry1/SANS/detector/x_position
+"SY= %f\n" nxs:/entry1/SANS/detector/y_position
+"SDChi= %f\n" nxs:/entry1/SANS/detector/chi_position
+"BeamstopX= %f\n" nxs:/entry1/SANS/beam_stop/x_position
+"BeamstopY= %f \n" nxs:/entry1/SANS/beam_stop/y_position
+%text = %Counter
+"%s\n" $(text)
+"Moni3=%ld\n" nxs:/entry1/SANS/integrated_beam/counts
+"Moni4=%ld\n" nxs:/entry1/SANS/integrated_beam/counts
+"Moni5=%ld\n" nxs:/entry1/SANS/detector/monitor_counts
+"Time=%f\n" nxs:/entry1/SANS/detector/counting_time
+%text = %Counts
+"%s\n" $(text)
+
+@( i = 0, nxs:/entry1/data1/counts._size_(1)
+
+  @( j = 0, nxs:/entry1/data1/counts._size_(2), 8
+  
+    "%ld" nxs:/entry1/data1/counts[i][j]
+
+    @( k = $(j) + 1, $(j) + 8
+      ",%ld" nxs:/entry1/data1/counts[i][k]	  
+    @)
+
+    "\n"
+	
+  @)
+  
+@)
+
diff --git a/contrib/applications/NXextract/example/sans2009n012333.hdf b/contrib/applications/NXextract/example/sans2009n012333.hdf
new file mode 100755
index 0000000..d6e5304
Binary files /dev/null and b/contrib/applications/NXextract/example/sans2009n012333.hdf differ
diff --git a/contrib/applications/NXextract/example/template_1.nxe b/contrib/applications/NXextract/example/template_1.nxe
new file mode 100644
index 0000000..18f5b85
--- /dev/null
+++ b/contrib/applications/NXextract/example/template_1.nxe
@@ -0,0 +1,119 @@
+#==============================================================================
+# File: 
+#	Multiframes_to_EDF.nxe
+#
+# @desc	Produce a EDF (ESRF Data Format) file for each image captured in 'multiframe' CCD camera mode
+#
+# @param dir directory 'Target directory for extracted data' $(_data_extraction_folder_)
+# @param header_length number 'EDF file header length' 4096
+#
+# Usage:
+#	nxextractor -t Multiframes_to_EDF.nxe -D dir=<destination directory> [-m <mode>] [-w uid:gid] <NeXus source file>
+#
+# $Author: poirier $
+#
+# $Revision: 1.7 $
+#==============================================================================
+
+# output to console
+>
+"%s\n" $(_FILE_NAME_)
+
+# loop other all entries
+# variable $(entry) will contain current entry path (ex: '/entry1')
+# variable $(entry_name) will contain curren tentry name (ex: 'entry1')
+@( entry = [nxs:/<NXentry>/]
+
+	# loop other range [0, n[
+	@( i = 0, nxs:$(entry)<NXentry>/<NXinstrument>/<NXdetector>/Frames/data
+
+		# define a new variable
+		% image_grp = $(entry)<NXentry>/image#$(i)<NXdata>
+		
+		# define image name for edf file name using a data bloc named 'image_name'
+		( image_name
+			"im_%02d" $(i)
+		)
+		
+		# define variable
+		% image_full_name = $(entry_name)_$(image_name)
+
+		# Test data dimensions
+		?( nxs:$(image_grp)/<SDS-signal>._rank_ = 2
+
+			# Define data bloc for image data
+			( binarydata
+				# output into this bloc as 2 bytes unsigned integers
+				'ui2' nxs:$(image_grp)/<SDS-signal> 
+			)
+			
+			# Define data bloc in memory for EDF header base content
+			( edf_header
+			
+				"EDF_DataBlockID = 1.Image.Psd ;\n"
+				"EDF_BinarySize = %s ;\n" $(binarydata_size)
+				"EDF_HeaderSize = %s ;\n" $(header_length)
+				"ByteOrder = LowByteFirst ;\n"
+				"DataType = UnsignedShort ;\n"
+				"Dim_1 = %d ;\n" nxs:$(image_grp)/data._size_(1)
+				"Dim_2 = %d ;\n" nxs:$(image_grp)/data._size_(2)
+				"Title = %s ;\n" $(image_full_name)
+				"Time =  ;\n"
+				"HeaderID = EH:000001:000000:000000 ;\n"
+				"Compression = None ;\n"
+				"Image = 1 ;\n"
+				"Size = %s ;\n" $(binarydata_size)
+			)
+
+			# Define data bloc for specific metadata
+			( specific_metadata
+				# loop other all NXintensity_monitor groups inside first (and unique) NXinstrument group
+				@( mi_channel = [nxs:$(entry)/<NXinstrument>/<NXintensity_monitor>]
+					"Intensity(%s) = %g ;\n" $(mi_channel_name), nxs:$(mi_channel)/intensity[i]
+					"Gain(%s) = %g ;\n" $(mi_channel_name), nxs:$(mi_channel)/Gain/data
+					"Offset(%s) = %g ;\n" $(mi_channel_name), nxs:$(mi_channel)/offset/data
+				@)
+				
+				"Machine_Current = %? ;\n" nxs:$(entry)/<NXinstrument>/<NXsource>/current
+				"Monochromator_energy = %?%s ;\n" nxs:$(entry)/<NXinstrument>/<NXmonochromator>/energy, nxs:$(entry)/<NXinstrument>/<NXmonochromator>/energy.units
+				"Distance_sample-detector = %?mm ;\n" nxs:$(entry)/<NXinstrument>/<NXdetector>/distance
+				
+				# aviex parameters
+				"_diffrn_detector.detector = %s ;\n" nxs:$(entry)/<NXinstrument>/<NXdetector>/type
+				"Exposure_time  = %?%s ;\n" nxs:$(entry)/<NXinstrument>/<NXdetector>/Exposure/data, nxs:$(entry)/<NXinstrument>/<NXdetector>/Exposure/data.units
+				"Shutter_close_delay  = %?%s ;\n" nxs:$(entry)/<NXinstrument>/<NXdetector>/ShutterCloseDelay/data, nxs:$(entry)/<NXinstrument>/<NXdetector>/ShutterCloseDelay/data.units
+				"Xbin = %? ;\n" nxs:$(entry)/<NXinstrument>/<NXdetector>/Xbin/data
+				"Ybin = %? ;\n" nxs:$(entry)/<NXinstrument>/<NXdetector>/Ybin/data
+				
+				# motors
+				@( motor_data = [nxs:$(entry)/<NXinstrument>/<NXpositioner>]
+					"Position(%s) = %g ;\n" $(motor_data_name), nxs:$(motor_data)/raw_value
+				@)
+			)
+
+			# Define a data bloc with a fixed size given by 'header_length' parameter
+			# the default value for 'header_length' (4096) is given in the header of this file
+			# the lines begining with '@param' are interpreted by the parsor
+			( header $(header_length)              
+
+				"{\n"
+				'b' edf_header
+				'b' specific_metadata
+				# padding pattern (default is a 80 blank spaces string terminating with a CR)
+				...
+				"\n}\n"
+			)
+
+			# Define output as binary file
+			b> $(dir)/$(image_full_name).edf
+
+			# Output header bloc as binary data
+			'b' header
+			# Output data bloc as binary data
+			'b' binarydata
+			
+		?)
+		
+	@)
+	
+@)
diff --git a/contrib/applications/NXextract/example/template_2.nxe b/contrib/applications/NXextract/example/template_2.nxe
new file mode 100644
index 0000000..906eb35
--- /dev/null
+++ b/contrib/applications/NXextract/example/template_2.nxe
@@ -0,0 +1,54 @@
+#==============================================================================
+# File: 
+#	scan.nxe
+#
+# @desc	Generic scan extractor. Extract either 1d or 2D scans from each NXentry group
+#		in NeXus source file
+#
+# @param dir directory 'Target directory for extracted data' .
+#
+# Usage:
+#	nxextractor -t scan.nxe -D dir=<destination directory> [-m <mode>] [-w uid:gid] <NeXus source file>
+#
+# $Author: poirier $
+#
+# $Revision: 1.2 $
+#==============================================================================
+
+# loop other all entries
+# variable $(entry) will contain current entry path (ex: '/entry1')
+# variable $(entry_name) will contain curren tentry name (ex: 'entry1')
+@( entry = [nxs:/<NXentry>/]
+
+	# define output
+	> $(dir)/$(_FILE_NAME_)_$(entry_name).txt
+
+	# new variable
+	% datagrp = $(entry_name)/<NXdata>
+
+	# Writes data
+	"# NeXus source file: %s\n" $(_FILE_NAME_)
+	"# NXentry name     : %s\n" $(entry_name)
+	"# Start time       : %?\n" nxs:$(entry)/start_time
+	"# End time         : %?\n" nxs:$(entry)/end_time
+	# Writes a CR
+	"\n"
+
+	# 1D Scan ?
+	?( nxs:/$(datagrp)/<SDS-signal>._scandim_ = 1
+
+		# sub-template: extract scalar data as text columns
+		+ 'template_2/scan_1d_extract_scalar.nxe'
+	
+		# sub-template: extract images as bmp and raw files
+		+ 'template_2/scan_1d_extract_image.nxe'
+	?)
+
+	# 2D Scan ?
+	?( nxs:/$(datagrp)/<SDS-signal>._scandim_ = 2
+
+		# sub-template: extract scalar data as text columns
+		+ 'template_2/scan_2d_extract_scalar.nxe'	
+	?)
+@)
+
diff --git a/contrib/applications/NXextract/example/template_2/scan_1d_extract_image.nxe b/contrib/applications/NXextract/example/template_2/scan_1d_extract_image.nxe
new file mode 100644
index 0000000..af705bf
--- /dev/null
+++ b/contrib/applications/NXextract/example/template_2/scan_1d_extract_image.nxe
@@ -0,0 +1,43 @@
+#==============================================================================
+# File: 
+#	extract_2D.nxe
+#
+# @desc	Generic scan extractor. Extract either 1d or 2D scans from each NXentry group
+#		in NeXus source file
+#
+# @param dir directory 'Target directory for extracted data' $(_root_folder_)/$(_sub_folder_)
+#
+# $Author: poirier $
+#
+#==============================================================================
+
+# loop other all signal datasets with rank=2 (scan-data2)
+@( signal_2D = [nxs:/$(datagrp)/<scan-data2>]
+
+	# loop over actuators arrays dimension
+	@( i = 0, nxs:/$(signal_2D)._size_(1)
+
+		# defining a data bloc in memory
+		( output_filename
+			"%04d-" $(i)
+			"%6.3f" nxs:/$(datagrp)/<SDS-axis1>[i]
+		)
+
+		# Re-define output in binary mode
+		# the content of the variable 'dir' is passed through a argument of the command line
+		# the content of the variable 'output_filename' is defining by the data bloc above
+		b> $(dir)/$(entry_name)/$(output_filename).bmp
+
+		# output 2D data slice of 3D array as a bmp image
+		'bmp' nxs:/$(signal_2D)[i]
+
+		# Re-define output
+		b> $(dir)/$(entry_name)/$(output_filename).raw
+
+		# output same data as a binary bloc of 2 bytes integers
+		'i2' nxs:/$(signal_2D)[i]
+
+	@)
+@)
+
+
diff --git a/contrib/applications/NXextract/example/template_2/scan_1d_extract_scalar.nxe b/contrib/applications/NXextract/example/template_2/scan_1d_extract_scalar.nxe
new file mode 100644
index 0000000..e897da9
--- /dev/null
+++ b/contrib/applications/NXextract/example/template_2/scan_1d_extract_scalar.nxe
@@ -0,0 +1,44 @@
+#==============================================================================
+# File: 
+#	scan_1d_extract_scalar.nxe
+#
+# @desc	Generic scan extractor. Extract either 1d or 2D scans from each NXentry group
+#		in NeXus source file
+#
+# $Author: poirier $
+#
+# $Revision: 1.2 $
+#==============================================================================
+
+		
+# column names for each dimension
+"# Column names and device attributes correspondance:\n"
+# Loop other all axis datasets representing time
+@( axe0 = [nxs:/$(datagrp)/<SDS-axis0>]
+	"# %-20s = %s\n" $(axe0_name), nxs:$(axe0).long_name
+@)
+# Loop other all axis datasets of 1st scan dimension
+@( axe1 = [nxs:/$(datagrp)/<SDS-axis1>]
+	"# %-20s = %s\n" $(axe1_name), nxs:$(axe1).long_name
+@)
+# Loop other all signal datasets matching scalar detectors (detectors that returns a single measured value)
+@( data = [nxs:/$(datagrp)/<scan-data0>]
+	"# %-20s = %s\n" $(data_name), nxs:$(data).long_name
+@)
+"\n"
+
+# print columns titles : actuators first
+# [nxs:/$(datagrp)/<SDS-axis0>] means this argument will be expanded (and the corresponding string
+#                               format: '%-20s   ') with the list of all axis datasets along the
+#                               time dimension (SDS-axis0)
+# [nxs:/$(datagrp)/<SDS-axis1>] is similar to the one above for axis datasets along 1st scan dimension
+# [nxs:/$(datagrp)/<scan-data0>] is similar and is expanded with the list of scalar detectors read
+#                                during the scan and resulting as 1d array for a 1d scan
+"%-20s  %-20s  %-20s" [nxs:/$(datagrp)/<SDS-axis0>]._name_, [nxs:/$(datagrp)/<SDS-axis1>]._name_, [nxs:/$(datagrp)/<scan-data0>]._name_
+"\n"
+# loop over data using size of first actuator data array
+@( i = 1, nxs:/$(datagrp)/<SDS-axis0>._size_(1)	
+	"%-20lf  %-20.6g  %-20.6g" [nxs:/$(datagrp)/<SDS-axis0>][i], [nxs:/$(datagrp)/<SDS-axis1>][i], [nxs:/$(datagrp)/<scan-data0>][i]
+	"\n"
+@)
+
diff --git a/contrib/applications/NXextract/example/template_2/scan_2d_extract_scalar.nxe b/contrib/applications/NXextract/example/template_2/scan_2d_extract_scalar.nxe
new file mode 100644
index 0000000..5df7248
--- /dev/null
+++ b/contrib/applications/NXextract/example/template_2/scan_2d_extract_scalar.nxe
@@ -0,0 +1,54 @@
+#==============================================================================
+# File: 
+#	scan_1d_extract_scalar.nxe
+#
+# @desc	Generic scan extractor. Extract either 1d or 2D scans from each NXentry group
+#		in NeXus source file
+#
+# $Author: poirier $
+#
+# $Revision: 1.2 $
+#==============================================================================
+
+		
+# column names for each dimension
+"# Column names and device attributes correspondance:\n"
+# Loop other all axis datasets representing time
+@( axe0 = [nxs:/$(datagrp)/<SDS-axis0>]
+	"# %-20s = %s\n" $(axe0_name), nxs:$(axe0).long_name
+@)
+# Loop other all axis datasets of 1st scan dimension
+@( axe1 = [nxs:/$(datagrp)/<SDS-axis1>]
+	"# %-20s = %s\n" $(axe1_name), nxs:$(axe1).long_name
+@)
+# Loop other all axis datasets of 2nd scan dimension
+@( axe2 = [nxs:/$(datagrp)/<SDS-axis2>]
+	"# %-20s = %s\n" $(axe2_name), nxs:$(axe2).long_name
+@)
+# Loop other all signal datasets
+@( signal = [nxs:/$(datagrp)/<SDS-signal>]
+	"# %-20s = %s\n" $(signal_name), nxs:$(signal).long_name
+@)
+"\n"
+
+# print columns titles : actuators first
+#
+# [nxs:/$(datagrp)/<SDS-axis0>] means this argument will be expanded (and the corresponding string
+#                               format: '%-20s   ') with the list of all axis datasets along the
+#                               time dimension (SDS-axis0)
+# [nxs:/$(datagrp)/<SDS-axis1>] is similar to the one above for axis datasets along 1st scan dimension
+# [nxs:/$(datagrp)/<SDS-axis2>] is similar to the one above for axis datasets along 2nd scan dimension
+# [nxs:/$(datagrp)/<SDS-signal>] is expanded with the list signal datasets
+"%-20s  %-20s  %-20s  %-20s" [nxs:/$(datagrp)/<SDS-axis0>]._name_, [nxs:/$(datagrp)/<SDS-axis1>]._name_, [nxs:/$(datagrp)/<SDS-axis2>]._name_, [nxs:/$(datagrp)/<SDS-signal>]._name_
+"\n"
+
+# loop over data using size of first actuator data array
+#
+# Loop over the range [0, size of 2nd dimension of the 1st axis dataset along 1st dimension[
+@( i = 1, nxs:/$(datagrp)/<SDS-axis1>._size_(2)
+	# Loop over the range [0, size of 1st dimension of the 1st axis dataset along 2nd dimension[
+	@( j = 1, nxs:/$(datagrp)/<SDS-axis2>._size_(1)
+		"%-20.6f  %-20.6f  %-20.6f  %-20.6f" [nxs:/$(datagrp)/<SDS-axis0>][j][i], [nxs:/$(datagrp)/<SDS-axis1>][j][i], [nxs:/$(datagrp)/<SDS-axis2>][j], [nxs:/$(datagrp)/<SDS-signal>][j][i]
+		"\n"
+	@)
+@)
diff --git a/contrib/applications/NXextract/example/template_3.nxe b/contrib/applications/NXextract/example/template_3.nxe
new file mode 100644
index 0000000..f358bc4
--- /dev/null
+++ b/contrib/applications/NXextract/example/template_3.nxe
@@ -0,0 +1,66 @@
+#==============================================================================
+# File: 
+#	scan1D_bmp_raw.nxe
+#
+# @desc	Bmp and raw data extractor. Extract 2D data (images) from 1D scan
+#
+# @param dir directory 'Target directory for extracted data' $(_data_extraction_folder_)
+
+# @usage
+#	nxextractor -t scan1D_bmp_raw.nxe -D dir=<destination_directory> [-m <mode>] [-w uid:gid] <NeXus source file>
+#
+# $Author: poirier $
+#
+# $Revision: 1.6 $
+#==============================================================================
+
+# Loop over NXentry groups.
+# Variables 'entry_name' and 'entry' will respectively contains the name and the full path of
+# the current NXentry group
+@( entry = [nxs:/<NXentry>/]
+
+	# define a variable
+	% datagrp = $(entry_name)<NXentry>/scan_data<NXdata>
+
+	# define output file in ASCII mode
+	> $(dir)/$(_FILE_NAME_)_$(entry_name).txt
+
+	# output some text data
+	"# NeXus source file: $(_FILE_NAME_)\n"
+	"# Creation time: %?\n" nxs:.file_time
+	"# NXentry: name = %s\n" $(entry_name)
+	"\n"
+
+	# Loop over datasets containing the 'signal' attribute in the NXdata group
+	@( signal = [nxs:/$(datagrp)/<SDS-signal>]
+
+		# Checking dataset rank
+		?( nxs:$(signal)._rank_ = 3
+
+			# loop over actuators arrays dimension
+			@( i = 0, nxs:/$(signal)._size_(1)
+	  
+				# defining a data bloc in memory
+				( output_filename
+					"%04d-" $(i)
+					"%6.3f" nxs:/$(datagrp)/<SDS-axis1>[i]
+				)
+
+				# Re-define output in binary mode
+				# the content of the variable 'dir' is passed through a argument of the command line
+				# the content of the variable 'output_filename' is defining by the data bloc above
+				b> $(dir)/$(entry_name)/$(output_filename).bmp
+
+				# output 2D data slice of 3D array as a bmp image
+				'bmp' nxs:/$(signal)[i]
+
+				# Re-define output
+				b> $(dir)/$(entry_name)/$(output_filename).raw
+
+				# output same data as a binary bloc of 2 bytes integers
+				'i2' nxs:/$(signal)[i]
+
+			@)
+		?)
+	@)
+@)
diff --git a/contrib/applications/NXextract/readme.txt b/contrib/applications/NXextract/readme.txt
new file mode 100644
index 0000000..7274474
--- /dev/null
+++ b/contrib/applications/NXextract/readme.txt
@@ -0,0 +1,34 @@
+NXEXTRACT v1.12.0
+-----------------
+
+LOOP operator:
+
+1. A few math capabilities were added in loop declaration. It's now possible to use
+basic arythmetic operators, like:
+@( i = $(param) + 1, nxs:/entry1/foo/bar - 1
+...
+@)
+
+Note: the spaces before and after math operators are mandatory. This is incorrect:
+@( i = $(param)+ 1, nxs:/entry1/foo/bar-1
+
+2. Step parameter 
+An optionnal third parameter may be used to specify step value, e.g.:
+@( i = 0, nxs:/entry1/foo/bar - 1, 4
+NXEXTRACT v1.12.0
+-----------------
+
+LOOP operator:
+
+1. A few math capabilities were added in loop declaration. It's now possible to use
+basic arythmetic operators, like:
+@( i = $(param) + 1, nxs:/entry1/foo/bar - 1
+...
+@)
+
+Note: the spaces before and after math operators are mandatory. This is incorrect:
+@( i = $(param)+ 1, nxs:/entry1/foo/bar-1
+
+2. Step parameter 
+An optionnal third parameter may be used to specify step value, e.g.:
+@( i = 0, nxs:/entry1/foo/bar - 1, 4
diff --git a/contrib/applications/NXextract/src/Makefile.am b/contrib/applications/NXextract/src/Makefile.am
new file mode 100644
index 0000000..16aa9ff
--- /dev/null
+++ b/contrib/applications/NXextract/src/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1239 2009-04-15 14:37:08Z Freddie Akeroyd $
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include
+
+#EXTRA_DIST=SConscript
+
+bin_PROGRAMS = nxextract
+
+nxextract_SOURCES = extractorapp.cpp extractor.cpp templateparsor.cpp \
+			nexusevaluator.cpp jpegwrap.cpp nxfile.cpp base.cpp \
+			date.cpp bmp.cpp file.cpp membuf.cpp \
+			base.h bmp.h date.h extractor.h file.h \
+			jpegwrap.h membuf.h nexusevaluator.h nxfile.h \
+			templateparsor.h variant.h variant.cpp
+nxextract_LDADD = $(LIBNEXUS)
+nxextract_LDFLAGS = -static @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ $(LDFLAGS)
+
+include $(top_srcdir)/build_rules.am
diff --git a/contrib/applications/NXextract/src/base.cpp b/contrib/applications/NXextract/src/base.cpp
new file mode 100644
index 0000000..970d0c2
--- /dev/null
+++ b/contrib/applications/NXextract/src/base.cpp
@@ -0,0 +1,2718 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Some useful definitions and shortcuts
+//
+// Creation : 18/02/2005
+// Author   : S. Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "date.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <list>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __WIN32__
+  #include <windows.h>
+  #include <shellapi.h>
+  #include <stdio.h>
+#elif defined (__LINUX__)
+  #include <sys/types.h>
+  #include <sys/wait.h>
+  #include <stdlib.h>
+  #include <string.h>
+  #include <unistd.h>
+  #include <sys/stat.h>
+  #include <fcntl.h>
+  #include <errno.h>
+  #include <pwd.h>
+  #include <signal.h>
+#endif
+
+using namespace gdshare;
+
+// Empty string
+const String gdshare::g_strEmpty = "";
+
+// Simple scratch buffer (not thread safe)
+const int gdshare::g_iScratchLen = 262144;
+char gdshare::g_acScratchBuf[g_iScratchLen];
+
+// vsnprintf function
+#ifdef __WIN32__
+  #define VSNPRINTF _vsnprintf_s
+#else
+  #define VSNPRINTF vsnprintf
+#endif
+
+// stricmp function
+#ifdef __WANT_STRICMP__
+int stricmp(pcsz s1, pcsz s2)
+{
+  while( *s1 )
+  {
+    if( *s2 == 0 )
+      return 1;
+
+    if( toupper(*s1) < toupper(*s2) )
+      return -1;
+    if( toupper(*s1) > toupper(*s2) )
+      return 1;
+    s1++;
+    s2++;
+}
+
+  if( *s2 == 0 )
+    return 0;
+  return -1;
+}
+
+int strnicmp(pcsz s1, pcsz s2, int maxlen)
+{
+  int i = 0;
+  while( i<maxlen )
+  {
+    if( *s2 == 0 || *s1 == 0 )
+      return 1;
+
+    if( toupper(*s1) < toupper(*s2) )
+      return -1;
+    if( toupper(*s1) > toupper(*s2) )
+      return 1;
+    s1++;
+    s2++;
+    i++;
+  }
+  return 0;
+}
+#endif
+
+#ifdef _DEBUG
+//---------------------------------------------------------------------------
+// Output formatting debug info
+//---------------------------------------------------------------------------
+  void PrintfDebug(pcsz pszFormat, ...)
+  {
+#ifdef _THREAD_SUPPORT
+	LOCK(&g_acScratchBuf);
+#endif
+    va_list argptr;
+    va_start(argptr, pszFormat);
+    VSNPRINTF(g_acScratchBuf, g_iScratchLen, pszFormat, argptr);
+    va_end(argptr);
+    OutputDebug(g_acScratchBuf);
+  }
+  void OutputDebug(pcsz pcsz)
+  {
+    #ifdef __WIN32__
+      OutputDebugString(pcsz);
+      OutputDebugString("\n");
+    #else
+      fprintf(stderr, pcsz);
+      fprintf(stderr, "\n");
+    #endif
+  }
+#else
+  void PrintfDebug(pcsz /*pszFormat*/, ...)
+  {
+  }
+  void OutputDebug(pcsz /*psz*/)
+  {
+  }
+#endif
+
+//----------------------------------------------------------------------------
+// IsRoot
+//----------------------------------------------------------------------------
+bool gdshare::IsRoot()
+{
+#ifdef __LINUX__
+  if( 0 == geteuid() )
+    return true;
+  return false;
+#endif
+  return false;
+}
+
+//=============================================================================
+// Error
+//
+//=============================================================================
+String Error::ToString() const
+{
+  return StrFormat("%s. Reason: %s. Origin: %s.", PSZ(m_strDesc), PSZ(m_strReason), PSZ(m_strOrigin));
+}
+
+//=============================================================================
+// ErrorStack
+//
+//=============================================================================
+ErrorStack *ErrorStack::ms_pTheInstance = NULL;
+Error ErrorStack::s_EmptyError("OK", "No error", "nowhere");
+
+//----------------------------------------------------------------------------
+// ErrorStack::Push
+//----------------------------------------------------------------------------
+void ErrorStack::Push(const String &strReason, const String &strDesc, 
+                  const String &strOrigin, Error::ELevel eLevel)
+{
+  if( !Instance()->m_bIgnoreError )
+  {
+    Instance()->m_stkErrors.push(Error(strReason, strDesc, strOrigin, eLevel));
+    if( Instance()->m_bLogError )
+      LogError("gdshare", "%s. Reason: %s. Origin: %s.", PSZ(strDesc), PSZ(strReason), PSZ(strOrigin));
+  }
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::SetLogError
+//----------------------------------------------------------------------------
+void ErrorStack::SetLogError(bool bLog)
+{
+  Instance()->m_bLogError = bLog;
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::SetIgnoreErrors
+//----------------------------------------------------------------------------
+void ErrorStack::SetIgnoreErrors(bool bIgnore)
+{
+  Instance()->m_bIgnoreError = bIgnore;
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::Instance
+//----------------------------------------------------------------------------
+ErrorStack *ErrorStack::Instance()
+{
+  if( NULL == ms_pTheInstance )
+  {
+    ms_pTheInstance = new ErrorStack;
+    ms_pTheInstance->m_bIgnoreError = false;
+    ms_pTheInstance->m_bLogError = true;
+  }
+  return ms_pTheInstance;
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::Top
+//----------------------------------------------------------------------------
+Error &ErrorStack::Top()
+{
+  if( false == Instance()->IsEmpty() )
+    return Instance()->m_stkErrors.top();
+  return s_EmptyError;
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::Pop
+//----------------------------------------------------------------------------
+void ErrorStack::Pop()
+{
+  if( false == Instance()->IsEmpty() )
+    Instance()->m_stkErrors.pop();
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::IsEmpty
+//----------------------------------------------------------------------------
+bool ErrorStack::IsEmpty()
+{
+  return Instance()->m_stkErrors.empty();
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::Clear
+//----------------------------------------------------------------------------
+void ErrorStack::Clear()
+{
+  while( !IsEmpty() )
+    Instance()->m_stkErrors.pop();
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::Size
+//----------------------------------------------------------------------------
+int ErrorStack::Size()
+{
+  return Instance()->m_stkErrors.size();
+}
+
+//----------------------------------------------------------------------------
+// ErrorStack::Size
+//----------------------------------------------------------------------------
+String ErrorStack::ToString(char cSep)
+{
+  String strStack;
+  while( !IsEmpty() )
+  {
+    strStack = StrFormat("%s%s%c", PSZ(strStack), PSZ(Top().ToString()), cSep);
+    Pop();
+  }
+  return strStack;
+}
+
+//=============================================================================
+// Basic exception class
+//
+//=============================================================================
+//---------------------------------------------------------------------------
+// ExceptionBase::ExceptionBase
+//---------------------------------------------------------------------------
+ExceptionBase::ExceptionBase(const char *pcszError, const char *pcszReason,
+                             const char *pcszMethod)
+{
+  if( pcszError )
+    m_strError = pcszError;
+  if( pcszReason )
+    m_strReason = pcszReason;
+  if( pcszMethod )
+  m_strMethod = pcszMethod;
+
+  // put error on top of stack
+  gdshare::ErrorStack::Push(pcszReason, pcszError, pcszMethod);
+}
+
+//---------------------------------------------------------------------------
+// ExceptionBase::~ExceptionBase
+//---------------------------------------------------------------------------
+ExceptionBase::~ExceptionBase()
+{
+
+}
+
+//---------------------------------------------------------------------------
+// ExceptionBase::ErrorTitle
+//---------------------------------------------------------------------------
+const char *ExceptionBase::ErrorTitle()
+{
+  return "A exception occured";
+}
+
+//---------------------------------------------------------------------------
+// ExceptionBase::PrintMessage
+//---------------------------------------------------------------------------
+void ExceptionBase::PrintMessage()
+{
+  std::cout << ErrorTitle() << std::endl
+            << m_strError  << std::endl
+            << "Reason: " << m_strReason << std::endl
+            << "Origin: " << m_strMethod  << '.' << std::endl;
+}
+
+//---------------------------------------------------------------------------
+// ExceptionBase::Message
+//---------------------------------------------------------------------------
+String ExceptionBase::Message()
+{
+  String strMsg;
+  strMsg  = ErrorTitle() + string(": ") + m_strError 
+          + ". Cause: " + m_strReason
+          + ". In: " + m_strMethod
+          + ".";
+  return strMsg;
+}
+
+//---------------------------------------------------------------------------
+// ExtractToken
+//---------------------------------------------------------------------------
+int gdshare::ExtractToken(String *pstrSource, char c, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( pstrSource == pstrToken )
+    return 0;
+
+  int iSrcLength = pstrSource->length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for separator
+  int iPos = pstrSource->find_first_of(c);
+  if( iPos < 0 )
+  {
+    // Not found
+    *pstrToken = *pstrSource;
+    *pstrSource = g_strEmpty;
+    return 2;
+  }
+
+  // Separator found
+  *pstrToken = pstrSource->substr(0, iPos);
+  pstrSource->erase(0, iPos+1);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// ExtractTokenRight
+//---------------------------------------------------------------------------
+int gdshare::ExtractTokenRight(String *pstrSource, char c, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( pstrSource == pstrToken )
+    return 0;
+
+  int iSrcLength = pstrSource->length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for separator
+  int iPos = pstrSource->find_last_of(c);
+  if( iPos < 0 )
+  {
+    // Not found
+    *pstrToken = *pstrSource;
+    *pstrSource = g_strEmpty;
+    return 2;
+  }
+
+  // Separator found
+  *pstrToken = pstrSource->substr(iPos+1);
+  pstrSource->erase(iPos);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// ExtractToken
+//---------------------------------------------------------------------------
+int gdshare::ExtractToken(String *pstrSource, char cLeft, char cRight, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( pstrSource == pstrToken )
+    return 0;
+
+  int iSrcLength = pstrSource->length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for enclosing characters
+  int iLeftPos = pstrSource->find(cLeft);
+  int iRightPos = pstrSource->find(cRight, iLeftPos + 1);
+  if( iLeftPos < 0 || iRightPos < 0 || iRightPos < iLeftPos )
+  {
+    // Not found
+    *pstrToken = g_strEmpty;
+    return 2;
+  }
+
+  // Enclosing characters found
+  *pstrToken = pstrSource->substr(iLeftPos + 1, iRightPos - iLeftPos - 1);
+  pstrSource->erase(0, iRightPos + 1);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// ExtractTokenRight
+//---------------------------------------------------------------------------
+int gdshare::ExtractTokenRight(String *pstrSource, char cLeft, char cRight, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( pstrSource == pstrToken )
+    return 0;
+
+  int iSrcLength = pstrSource->length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for enclosing characters
+  int iRightPos = pstrSource->rfind(cRight);
+  int iLeftPos = pstrSource->rfind(cLeft, iRightPos - 1);
+  if( iLeftPos < 0 || iRightPos < 0 || iRightPos < iLeftPos )
+  {
+    // Not found
+    *pstrToken = g_strEmpty;
+    return 2;
+  }
+
+  // Enclosing characters found
+  *pstrToken = pstrSource->substr(iLeftPos+1, iRightPos - iLeftPos - 1);
+  pstrSource->erase(iLeftPos);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// IsEquals
+//---------------------------------------------------------------------------
+bool gdshare::IsEquals(const String &str1, const String &str2)
+{
+  return MAKEBOOL(str1 == str2);
+}
+
+//---------------------------------------------------------------------------
+// IsEqualsNoCase
+//---------------------------------------------------------------------------
+bool gdshare::IsEqualsNoCase(const String &str1, const String &str2)
+{
+  return MAKEBOOL(!stricmp(str1.c_str(), str2.c_str()));
+}
+
+//---------------------------------------------------------------------------
+// StartWith - first character only
+//---------------------------------------------------------------------------
+bool gdshare::StartWith(const String &str, char c)
+{
+  if( str.size() == 0 )
+    return false;
+
+  if( c == str[0] )
+    return true;
+
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// StartWith - string comparaison
+//---------------------------------------------------------------------------
+bool gdshare::StartWith(const String &str, pcsz pcszStart, bool bNoCase)
+{
+  if( str.size() < strlen(pcszStart) )
+    return false;
+
+  if( bNoCase )
+  {
+    return MAKEBOOL(!strnicmp(PSZ(str), pcszStart, strlen(pcszStart)));
+  }
+  else
+  {
+    return MAKEBOOL(!strncmp(PSZ(str), pcszStart, strlen(pcszStart)));
+  }
+}
+
+//---------------------------------------------------------------------------
+// EndWith - last character only
+//---------------------------------------------------------------------------
+bool gdshare::EndWith(const String &str, char c)
+{
+  if( str.size() == 0 )
+    return false;
+
+  if( c == str[str.size()-1] )
+    return true;
+
+  return false;
+}
+
+
+//---------------------------------------------------------------------------
+// Remove white space and begining and end of string
+//---------------------------------------------------------------------------
+void gdshare::Trim(String *pstr)
+{
+  if( pstr->size() > 0 )
+  {
+    int iFirstNoWhite = 0;
+    int iLastNoWhite = pstr->size()-1;
+
+    // Search for first non-white character
+    for( ; iFirstNoWhite <= iLastNoWhite; iFirstNoWhite++ )
+    {
+      if( !isspace((*pstr)[iFirstNoWhite]) )
+        break;
+    }
+
+    // Search for last non-white character
+    for( ; iLastNoWhite > iFirstNoWhite; iLastNoWhite-- )
+    {
+      if( !isspace((*pstr)[iLastNoWhite]) )
+        break;
+    }
+
+    // Extract sub-string
+    (*pstr) = pstr->substr(iFirstNoWhite, iLastNoWhite - iFirstNoWhite + 1);
+  }
+}
+
+//---------------------------------------------------------------------------
+// Build a string with format
+//---------------------------------------------------------------------------
+String gdshare::StrFormat(pcsz pszFormat, ...)
+{
+  va_list argptr;
+  va_start(argptr, pszFormat);
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+  VSNPRINTF(g_acScratchBuf, g_iScratchLen, pszFormat, argptr);
+  va_end(argptr);
+
+  String str = g_acScratchBuf;
+  return str;
+}
+
+//---------------------------------------------------------------------------
+// ExportDict
+//---------------------------------------------------------------------------
+void StringDict::Export(String *pstrDest)
+{
+  pstrDest->erase();
+
+  const_iterator it = begin();
+  for( ; it != end(); it++ )
+  {
+    String strName = it->first;
+    String strValue = it->second;
+
+    strName.Trim();
+
+    if( !pstrDest->empty() )
+      (*pstrDest) += '|';
+
+    pstrDest->Printf("%s%s=%d,%s", PSZ(*pstrDest), PSZ(strName), strValue.size(), PSZ(strValue));
+  }
+}
+
+//---------------------------------------------------------------------------
+// ImportDict
+//---------------------------------------------------------------------------
+void StringDict::Import(const String &_strSrc)
+{
+  clear();
+  String strSrc = _strSrc;
+  String strSize, strName, strValue;
+  int iStatus = 0;
+  while( strSrc.size() > 0 )
+  {
+    // Extrat name
+    iStatus = strSrc.ExtractToken('=', &strName);
+    if( iStatus )
+    {
+      // Extract size
+      iStatus = strSrc.ExtractToken(',', &strSize);
+      if( iStatus )
+      {
+        // Extract value
+        strValue = strSrc.substr(0, atoi(PSZ(strSize)));
+        (*this)[strName] = strValue;
+        // Suppress separator
+        strSrc.erase(0, 1);
+      }
+    }
+  }
+}
+
+//---------------------------------------------------------------------------
+// StringDict::ConcatValue
+//---------------------------------------------------------------------------
+void StringDict::ConcatValue(const String &strKey, const String &strValue, char cSep)
+{
+  // Get already stored value
+  String strStoredValue;
+  if( find(strKey) != end() )
+    strStoredValue = (*this)[strKey] + cSep;
+
+  // Concat with given value
+  strStoredValue += strValue;
+
+  // Store new value
+  (*this)[strKey] = strStoredValue;
+}
+
+//---------------------------------------------------------------------------
+// StringDict::Value
+//---------------------------------------------------------------------------
+const String &StringDict::Value(const String &strKey) const
+{
+  StringDict::const_iterator itDict;
+
+  itDict = find(strKey);
+  if( itDict != end() )
+    return itDict->second;
+ 
+  return g_strEmpty;
+}
+
+//---------------------------------------------------------------------------
+// StringDict::HasKey
+//---------------------------------------------------------------------------
+bool StringDict::HasKey(const String &strKey) const
+{
+  StringDict::const_iterator itDict = find(strKey);
+  if( itDict != end() )
+    return true;
+  return false;
+}
+
+//=============================================================================
+//
+// String
+//
+//=============================================================================
+//---------------------------------------------------------------------------
+// String::ExtractToken
+//---------------------------------------------------------------------------
+int String::ExtractToken(char c, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( this == pstrToken )
+    return 0;
+
+  int iSrcLength = length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for separator
+  int iPos = find_first_of(c);
+  if( iPos < 0 )
+  {
+    // Not found
+    *pstrToken = *this;
+    *this = g_strEmpty;
+    return 2;
+  }
+
+  // Separator found
+  *pstrToken = substr(0, iPos);
+  erase(0, iPos+1);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// String::Split
+//---------------------------------------------------------------------------
+void String::Split(char c, String *pstrLeft, String *pstrRight, bool bPreserve)
+{
+  if( bPreserve )
+  {
+    String strSaved(*this);
+    ExtractTokenRight(c, pstrRight);
+    (*pstrLeft) = *this;
+    *this = strSaved;
+  }
+  else
+  {
+    ExtractTokenRight(c, pstrRight);
+    (*pstrLeft) = *this;
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::ExtractTokenRight
+//---------------------------------------------------------------------------
+int String::ExtractTokenRight(char c, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( this == pstrToken )
+    return 0;
+
+  int iSrcLength = length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for separator
+  int iPos = find_last_of(c);
+  if( iPos < 0 )
+  {
+    // Not found
+    *pstrToken = *this;
+    *this = g_strEmpty;
+    return 2;
+  }
+
+  // Separator found
+  *pstrToken = substr(iPos+1);
+  erase(iPos);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// String::ExtractToken
+//---------------------------------------------------------------------------
+int String::ExtractToken(char cLeft, char cRight, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( this == pstrToken )
+    return 0;
+
+  int iSrcLength = length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for enclosing characters
+  int iLeftPos = find(cLeft);
+  int iRightPos = find(cRight, iLeftPos + 1);
+  if( iLeftPos < 0 || iRightPos < 0 || iRightPos < iLeftPos )
+  {
+    // Not found
+    *pstrToken = g_strEmpty;
+    return 2;
+  }
+
+  // Enclosing characters found
+  *pstrToken = substr(iLeftPos + 1, iRightPos - iLeftPos - 1);
+  erase(0, iRightPos + 1);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// String::ExtractTokenRight
+//---------------------------------------------------------------------------
+int String::ExtractTokenRight(char cLeft, char cRight, String *pstrToken)
+{
+  // Cannot extract a substring a put it in the same string !
+  if( this == pstrToken )
+    return 0;
+
+  int iSrcLength = length();
+
+  if( 0 == iSrcLength )
+  {
+    // Nothing else
+    pstrToken->erase();
+    return 0;
+  }
+
+  // Search for enclosing characters
+  int iRightPos = rfind(cRight);
+  int iLeftPos = iRightPos > 0 ? (int)rfind(cLeft, iRightPos - 1) : -1;
+  if( iLeftPos < 0 || iRightPos < 0 || iRightPos < iLeftPos )
+  {
+    // Not found
+    *pstrToken = g_strEmpty;
+    return 2;
+  }
+
+  // Enclosing characters found
+  *pstrToken = substr(iLeftPos+1, iRightPos - iLeftPos - 1);
+  erase(iLeftPos);
+  return 1;
+}
+
+//---------------------------------------------------------------------------
+// String::RemoveEnclosure
+//---------------------------------------------------------------------------
+bool String::RemoveEnclosure(pcsz pszLeft, pcsz pszRight)
+{
+  // pcszLeft & pcszRight must have the same length
+  if( strlen(pszLeft) != strlen(pszRight) )
+    return false;
+  
+  for( uint ui = 0; ui < strlen(pszLeft); ui++ )
+  {
+    string strMask;
+    strMask += pszLeft[ui];
+    strMask += '*';
+    strMask += pszRight[ui];
+    if( Match(strMask) )
+    {
+      *this = substr(strlen(pszLeft), size() - (strlen(pszLeft) + strlen(pszRight)));
+      return true;
+    }
+  }
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// String::RemoveEnclosure
+//---------------------------------------------------------------------------
+bool String::RemoveEnclosure(char cLeft, char cRight)
+{
+  string strMask;
+  strMask += cLeft;
+  strMask += '*';
+  strMask += cRight;
+  if( Match(strMask) )
+  {
+    *this = substr(1, size() - 2);
+    return true;
+  }
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// String::IsEquals
+//---------------------------------------------------------------------------
+bool String::IsEquals(const String &str) const
+{
+  return MAKEBOOL(*this == str);
+}
+
+//---------------------------------------------------------------------------
+// String::IsEqualsNoCase
+//---------------------------------------------------------------------------
+bool String::IsEqualsNoCase(const String &str) const
+{
+  return MAKEBOOL(!stricmp(c_str(), str.c_str()));
+}
+
+//---------------------------------------------------------------------------
+// String::StartWith
+//---------------------------------------------------------------------------
+bool String::StartWith(char c) const
+{
+  if( size() == 0 )
+    return false;
+
+  if( c == (*this)[0] )
+    return true;
+
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// String::StartWith
+//---------------------------------------------------------------------------
+bool String::StartWith(pcsz pcszStart, bool bNoCase) const
+{
+  if( size() < strlen(pcszStart) )
+    return false;
+
+  if( bNoCase )
+  {
+    return MAKEBOOL(!strnicmp(c_str(), pcszStart, strlen(pcszStart)));
+  }
+  else
+  {
+    return MAKEBOOL(!strncmp(c_str(), pcszStart, strlen(pcszStart)));
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::EndWith
+//---------------------------------------------------------------------------
+bool String::EndWith(pcsz pcszEnd, bool bNoCase) const
+{
+  if( size() < strlen(pcszEnd) )
+    return false;
+
+  if( bNoCase )
+  {
+    return MAKEBOOL(!strnicmp(c_str()+strlen(c_str())-strlen(pcszEnd), pcszEnd, strlen(pcszEnd)));
+  }
+  else
+  {
+    return MAKEBOOL(!strncmp(c_str()+strlen(c_str())-strlen(pcszEnd), pcszEnd, strlen(pcszEnd)));
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::EndWith
+//---------------------------------------------------------------------------
+bool String::EndWith(char c) const
+{
+  if( size() == 0 )
+    return false;
+
+  if( c == (*this)[size()-1] )
+    return true;
+
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// Look for occurence for a string in another
+// Take care of '?' that match any character
+//---------------------------------------------------------------------------
+static pcsz FindSubStrWithJoker(pcsz pszSrc, pcsz pMask, uint uiLenMask)
+{
+  if (strlen(pszSrc) < uiLenMask)
+    return NULL; // No hope
+
+  // while mask len < string len 
+  while( *(pszSrc + uiLenMask - 1) ) 
+  {
+    uint uiOffSrc = 0; // starting offset in mask and sub-string
+    
+    // Tant qu'on n'est pas au bout du masque
+    while (uiOffSrc < uiLenMask)
+    {
+      char cMask = pMask[uiOffSrc];
+      
+      if (cMask != '?') // In case of '?' it always match
+      {
+        if (pszSrc[uiOffSrc] != cMask)
+          break;
+      }
+  
+      // Next char
+      uiOffSrc++;
+    }
+
+    // String matched !
+    if (uiOffSrc == uiLenMask)
+      return pszSrc + uiLenMask;
+
+    // Next sub-string
+    pszSrc++;
+  }
+
+  // Not found
+  return NULL;
+}
+
+//---------------------------------------------------------------------------
+// String::Match
+//---------------------------------------------------------------------------
+bool String::Match(const String &strMask) const
+{
+  return Match(PSZ(strMask));
+}
+
+//---------------------------------------------------------------------------
+// String::Match
+//---------------------------------------------------------------------------
+bool String::Match(pcsz pszMask) const
+{
+  pcsz pszTxt = c_str();
+  while (*pszMask)
+  {
+    switch (*pszMask)
+    {
+
+      case '\\':
+        // escape next special mask char (e.g. '?' or '*')
+        pszMask++;
+        if( *pszMask )
+        {
+          if( *(pszMask++) != *(pszTxt++) )
+            return false;
+        }
+        break;
+
+      case '?': // joker at one position
+        if (!*pszTxt)
+          return true; // no match
+
+        pszTxt++;
+        pszMask++;
+        break;
+
+      case '*': // joker on one or more positions
+        {
+          // Pass through others useless joker characters
+          while (*pszMask == '*' || *pszMask == '?')
+            pszMask++;
+
+          if (!*pszMask)
+            return true; // Fin
+
+          // end of mask
+          uint uiLenMask;
+          const char *pEndMask = strchr(pszMask, '*');
+
+          if (pEndMask)
+            // other jokers characters => look for bloc between the two jokers in source string
+            uiLenMask = pEndMask - pszMask;
+          else
+            // string must be end with mask
+            return (NULL != FindSubStrWithJoker(pszTxt + strlen(pszTxt)-strlen(pszMask), pszMask, strlen(pszMask)))?
+                           true : false;
+
+          // Search first uiLenMask characters from mask in text
+          pcsz pEnd = FindSubStrWithJoker(pszTxt, pszMask, uiLenMask);
+
+          if (!pEnd)
+            // Mask not found
+            return false;
+
+          pszTxt = pEnd;
+          pszMask += uiLenMask;
+        }
+        break;
+
+      default:
+        if( *(pszMask++) != *(pszTxt++) )
+          return false;
+        break;
+    }
+  }
+
+  if( *pszTxt )
+    // End of string not reached
+    return false;
+
+  return true;
+}
+
+//---------------------------------------------------------------------------
+// String::Trim
+//---------------------------------------------------------------------------
+void String::Trim()
+{
+  if( size() > 0 )
+  {
+    int iFirstNoWhite = 0;
+    int iLastNoWhite = size()-1;
+
+    // Search for first non-white character
+    for( ; iFirstNoWhite <= iLastNoWhite; iFirstNoWhite++ )
+    {
+      if( !isspace((*this)[iFirstNoWhite]) )
+        break;
+    }
+
+    // Search for last non-white character
+    for( ; iLastNoWhite > iFirstNoWhite; iLastNoWhite-- )
+    {
+      if( !isspace((*this)[iLastNoWhite]) )
+        break;
+    }
+
+    // Extract sub-string
+    (*this) = substr(iFirstNoWhite, iLastNoWhite - iFirstNoWhite + 1);
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::Printf
+//---------------------------------------------------------------------------
+int String::Printf(pcsz pszFormat, ...)
+{
+  va_list argptr;
+  va_start(argptr, pszFormat);
+#ifdef THREAD_SUPPORT
+	LOCK(&g_acScratchBuf)
+#endif
+  VSNPRINTF(g_acScratchBuf, g_iScratchLen, pszFormat, argptr);
+  va_end(argptr);
+
+  *this = g_acScratchBuf;
+  return size();
+}
+
+//---------------------------------------------------------------------------
+// String::Split
+//---------------------------------------------------------------------------
+void String::Split(char c, vector<String> *pvecstr)
+{
+  // Clear vector
+  pvecstr->clear();
+  String strToken;
+  while( !empty() )
+  {
+    if( 0 != ExtractToken(c, &strToken) )
+      pvecstr->push_back(strToken);
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::Split (const version)
+//---------------------------------------------------------------------------
+void String::Split(char c, vector<String> *pvecstr) const
+{
+  // Clear vector
+  pvecstr->clear();
+  String strToken;
+  String strTmp(*this);
+  while( !strTmp.empty() )
+  {
+    if( 0 != strTmp.ExtractToken(c, &strToken) )
+      pvecstr->push_back(strToken);
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::Join
+//---------------------------------------------------------------------------
+void String::Join(const vector<String> &vecStr, char cSep)
+{
+  erase();
+  for( uint ui=0; ui < vecStr.size(); ui++ )
+  {
+    if( 0 < ui )
+      *this += cSep;
+    *this += vecStr[ui];
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::RemoveItem
+//---------------------------------------------------------------------------
+bool String::RemoveItem(const String &strItem, char cSep)
+{
+  uint uiPos = find(strItem);
+  if( uiPos == string::npos )
+    return false;
+
+  if( *this == strItem )
+  {
+    erase();
+    return true;
+  }
+
+  vector<String> vecstr;
+  Split(cSep, &vecstr);
+  for( vector<String>::iterator it = vecstr.begin(); it != vecstr.end(); it++ )
+  {
+    if( *it == strItem )
+    {
+      vecstr.erase(it);
+      Join(vecstr, cSep);
+      return true;
+    }
+  }
+  Join(vecstr, cSep);
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// String::ToLower
+//---------------------------------------------------------------------------
+void String::ToLower()
+{
+  for(uint ui=0; ui < size(); ui++)
+    replace(ui, 1, 1, tolower(c_str()[ui]));
+}
+
+//---------------------------------------------------------------------------
+// String::ToUpper
+//---------------------------------------------------------------------------
+void String::ToUpper()
+{
+  for(uint ui=0; ui < size(); ui++)
+    replace(ui, 1, 1, toupper(c_str()[ui]));
+}
+
+//---------------------------------------------------------------------------
+// String::Replace
+//---------------------------------------------------------------------------
+void String::Replace(pcsz pszSrc, pcsz pszDst)
+{
+  pcsz pBeg = NULL, pFind = NULL;
+
+  int iLenSrc = strlen(pszSrc);
+  if( iLenSrc == 0 )
+    // Avoid infinite loop
+    return;
+
+  int iLenDst = strlen(pszDst);
+  int iOffset = 0;
+  for(;;)
+  {
+    pBeg = c_str() + iOffset;
+    pFind = strstr(pBeg, pszSrc);
+
+    if( !pFind )
+      return;
+
+    // Do replace
+    replace(pFind - pBeg + iOffset, iLenSrc, pszDst);
+    // replace again after replacement
+    iOffset += pFind - pBeg + iLenDst;
+  }
+}
+
+//---------------------------------------------------------------------------
+// String::Replace
+//---------------------------------------------------------------------------
+void String::Replace(char cSrc, char cDst)
+{
+  if (!strchr(c_str(), cSrc))
+    return; // Nothing to do
+
+  for( uint uiPos = 0; uiPos < size(); uiPos++ )
+    if( cSrc == (*this)[uiPos] )
+      replace(uiPos, 1, 1, cDst);
+}
+
+//---------------------------------------------------------------------------
+// String::Hash
+//---------------------------------------------------------------------------
+ulong String::Hash() const
+{
+  int64 i64Modulo = (int64(2) << 31) - 1;
+  int64 Hash64 = 0;
+  uint length = size();
+  for( uint uiPos = 0; uiPos < length; uiPos++ )
+    Hash64 = (31 * Hash64 + (*this)[uiPos]) % i64Modulo;
+
+  return (ulong)(Hash64); 
+}
+
+//=============================================================================
+//
+// Other free functions
+//
+//=============================================================================
+
+//----------------------------------------------------------------------------
+// GetEnv
+//----------------------------------------------------------------------------
+bool gdshare::GetEnv(const char *pszVar, String *pstrValue, const char *pszDef)
+{
+#ifdef __WIN32__
+  #ifdef _THREAD_SUPPORT
+    LOCK(&g_acScratchBuf)
+  #endif
+  if ( ::GetEnvironmentVariable(pszVar, g_acScratchBuf, g_iScratchLen) == 0 )
+#else
+  char *pszBuf = ::getenv(pszVar);
+  if ( pszBuf == NULL )
+#endif
+  { // if the variable  is undefined, use default value
+    if ( pszDef )
+      *pstrValue = pszDef;
+    return false;
+  }
+
+#ifdef __WIN32__
+  *pstrValue = g_acScratchBuf;
+#else
+  *pstrValue = pszBuf;
+#endif
+  return true;
+}
+
+//----------------------------------------------------------------------------
+// Exec
+//----------------------------------------------------------------------------
+int gdshare::Exec(const char* pszCmdLine, const char *pszDefDir, int bBackground, bool bThrow, ulong *pulReturnCode)
+{
+  int rc = 0;
+
+#ifdef __WIN32__
+  // JA 1996/05/02 Support des documents, avec les associations (.TXT lance NOTEPAD,...)
+  // A priori ShellExecute fait exactement ce que l'on veut, sauf pour
+  //  le probleme du GetMessage() -> c'est pourquoi on veut savoir
+  //  *a priori* si la commande est un executable ou un fichier. Note:
+  //  si pas d'extension on considere que c'est un executable)
+  bool bIsExecutable;
+  String strCommandLine = pszCmdLine;
+  String strCmd;
+  strCommandLine.Trim();
+
+  if ( strCommandLine.StartWith('"') )
+  { // the executable name of path may contains spaces. Normaly the method caller have
+    // demilited the command with quotes.
+    int iQuotIndex = strCmd.find('"');
+    if( iQuotIndex == -1 )
+    {
+      if ( bThrow )
+        throw Exception("ERR_FILE", "Missing quotes", "Exec");
+    }
+
+    strCmd = strCommandLine.substr(1, iQuotIndex);
+  }
+  else
+    strCommandLine.ExtractToken(' ', &strCmd);
+
+  // strCmd vaut le premier argument (= le nom de l'exe ou du document)
+  // extraction de l'extension :
+  String strExt;
+  String strCmdDummy = strCmd;
+  rc = strCmdDummy.ExtractTokenRight('.', &strExt );
+  // Seul le cas rc = 1 (chaine extraite et separateur trouv�) indique
+  //  que l'on a une extension.
+  if( rc != 1 )
+  {
+    strExt = g_strEmpty;
+    bIsExecutable = true;
+  }
+  else
+  {
+    // On pourrait aussi tester l'entree programs= du win.ini pour les
+    //  extensions correspondant a des executables, mais bon, cela
+    //  ralentirait pour des extensions futures de l'os tres lointaines...
+    if(   stricmp( PSZ(strExt), "exe" ) == 0
+       || stricmp( PSZ(strExt), "com" ) == 0
+       || stricmp( PSZ(strExt), "bat" ) == 0
+       || stricmp( PSZ(strExt), "pif" ) == 0
+       || stricmp( PSZ(strExt), "cmd" ) == 0
+      )
+    {
+      // On exclue les URL
+      if (strstr(PSZ(strCmd), "://") == NULL)
+        bIsExecutable = true;
+      else
+        bIsExecutable = false;
+    }
+    else
+      bIsExecutable = false;
+  }
+
+  bool bIsError = false;
+
+  // WinExec attend que le process fils appelle GetMessage()
+  // On utilise plutot CreateProcess, dans le cas d'un executable
+  PROCESS_INFORMATION aProcessInformation;
+  memset(&aProcessInformation, 0, sizeof(PROCESS_INFORMATION));
+  if( bIsExecutable )
+  {
+    STARTUPINFO         aStartupInfo;
+    memset(&aStartupInfo, 0, sizeof(aStartupInfo));
+    aStartupInfo.cb = sizeof(aStartupInfo);
+    rc = 0;
+    if( !::CreateProcess(NULL, (char*)pszCmdLine, NULL, NULL,
+                         FALSE, CREATE_NO_WINDOW, NULL,
+                         pszDefDir,
+                         &aStartupInfo, &aProcessInformation) )
+    {
+      rc = ::GetLastError();
+      bIsError = true;
+    }
+  }
+  else
+  {
+    // Ce n'est pas un executable -> il faut forcement utiliser l'API
+    //  ShellExecute
+    rc = (int)::ShellExecute( HWND_DESKTOP, NULL,
+                              PSZ(strCmd),
+                              PSZ(strCommandLine),
+                              pszDefDir,
+                              SW_SHOW );
+    if( rc >= 0 && rc < 32 )
+      bIsError = true;
+  }
+
+  // Une erreur est intervenue dans le ShellExecute
+  if( bIsError && bThrow )
+    throw Exception("ERR_FILE", "Error while executing command", "Exec");
+
+  if( !bBackground && bIsExecutable)
+  {
+    // Attente de la fin du process puis on r�cup�re son code retour
+    ulong ulReturnCode;
+    ::WaitForSingleObject( aProcessInformation.hProcess, INFINITE);
+    ::GetExitCodeProcess(aProcessInformation.hProcess, &ulReturnCode);
+    if( pulReturnCode )
+      *pulReturnCode = ulReturnCode;
+    return 0;
+  }
+
+  if ( bIsExecutable )
+  { // Il faut d�cr�menter le usecount des handles contenues dans
+    // PROCESS_INFORMATION, sinon les informations sur le process
+    // ne seront jamais lib�r�es par le syst�me...
+    ::CloseHandle(aProcessInformation.hProcess);
+    ::CloseHandle(aProcessInformation.hThread);
+  }
+  return 0;
+
+#else
+  String sCmd = pszCmdLine;
+  if( bBackground )
+    // Background task
+    sCmd += "&";
+
+  // Execute shell command then exit
+  int iChildReturnCode = system(PSZ(sCmd));
+
+  // Parent process, let's wait for the child to finish
+  LogVerbose("sys", "return code %d", iChildReturnCode);
+  return iChildReturnCode;
+#endif
+}
+
+//----------------------------------------------------------------------------
+// Exec
+//----------------------------------------------------------------------------
+int gdshare::ExecAs(const char* pszCmdLine, const char *pszDefDir, int bBackground, bool bThrow, ulong *pulReturnCode, uid_t uid, gid_t gid)
+{
+  int rc = 0;
+
+#ifdef __WIN32__
+  // JA 1996/05/02 Support des documents, avec les associations (.TXT lance NOTEPAD,...)
+  // A priori ShellExecute fait exactement ce que l'on veut, sauf pour
+  //  le probleme du GetMessage() -> c'est pourquoi on veut savoir
+  //  *a priori* si la commande est un executable ou un fichier. Note:
+  //  si pas d'extension on considere que c'est un executable)
+  bool bIsExecutable;
+  String strCommandLine = pszCmdLine;
+  String strCmd;
+  strCommandLine.Trim();
+
+  if ( strCommandLine.StartWith('"') )
+  { // the executable name of path may contains spaces. Normaly the method caller have
+    // demilited the command with quotes.
+    int iQuotIndex = strCmd.find('"');
+    if( iQuotIndex == -1 )
+    {
+      if ( bThrow )
+        throw Exception("ERR_FILE", "Missing quotes", "Exec");
+    }
+
+    strCmd = strCommandLine.substr(1, iQuotIndex);
+  }
+  else
+    strCommandLine.ExtractToken(' ', &strCmd);
+
+  // strCmd vaut le premier argument (= le nom de l'exe ou du document)
+  // extraction de l'extension :
+  String strExt;
+  String strCmdDummy = strCmd;
+  rc = strCmdDummy.ExtractTokenRight('.', &strExt );
+  // Seul le cas rc = 1 (chaine extraite et separateur trouv�) indique
+  //  que l'on a une extension.
+  if( rc != 1 )
+  {
+    strExt = g_strEmpty;
+    bIsExecutable = true;
+  }
+  else
+  {
+    // On pourrait aussi tester l'entree programs= du win.ini pour les
+    //  extensions correspondant a des executables, mais bon, cela
+    //  ralentirait pour des extensions futures de l'os tres lointaines...
+    if(   stricmp( PSZ(strExt), "exe" ) == 0
+       || stricmp( PSZ(strExt), "com" ) == 0
+       || stricmp( PSZ(strExt), "bat" ) == 0
+       || stricmp( PSZ(strExt), "pif" ) == 0
+       || stricmp( PSZ(strExt), "cmd" ) == 0
+      )
+    {
+      // On exclue les URL
+      if (strstr(PSZ(strCmd), "://") == NULL)
+        bIsExecutable = true;
+      else
+        bIsExecutable = false;
+    }
+    else
+      bIsExecutable = false;
+  }
+
+  bool bIsError = false;
+
+  // WinExec attend que le process fils appelle GetMessage()
+  // On utilise plutot CreateProcess, dans le cas d'un executable
+  PROCESS_INFORMATION aProcessInformation;
+  memset(&aProcessInformation, 0, sizeof(PROCESS_INFORMATION));
+  if( bIsExecutable )
+  {
+    STARTUPINFO         aStartupInfo;
+    memset(&aStartupInfo, 0, sizeof(aStartupInfo));
+    aStartupInfo.cb = sizeof(aStartupInfo);
+    rc = 0;
+    if( !::CreateProcess(NULL, (char*)pszCmdLine, NULL, NULL,
+                         FALSE, CREATE_NO_WINDOW, NULL,
+                         pszDefDir,
+                         &aStartupInfo, &aProcessInformation) )
+    {
+      rc = ::GetLastError();
+      bIsError = true;
+    }
+  }
+  else
+  {
+    // Ce n'est pas un executable -> il faut forcement utiliser l'API
+    //  ShellExecute
+    rc = (int)::ShellExecute( HWND_DESKTOP, NULL,
+                              PSZ(strCmd),
+                              PSZ(strCommandLine),
+                              pszDefDir,
+                              SW_SHOW );
+    if( rc >= 0 && rc < 32 )
+      bIsError = true;
+  }
+
+  // Une erreur est intervenue dans le ShellExecute
+  if( bIsError && bThrow )
+    throw Exception("ERR_FILE", "Error while executing command", "Exec");
+
+  if( !bBackground && bIsExecutable)
+  {
+    // Attente de la fin du process puis on r�cup�re son code retour
+    ulong ulReturnCode;
+    ::WaitForSingleObject( aProcessInformation.hProcess, INFINITE);
+    ::GetExitCodeProcess(aProcessInformation.hProcess, &ulReturnCode);
+    if( pulReturnCode )
+      *pulReturnCode = ulReturnCode;
+    return 0;
+  }
+
+  if ( bIsExecutable )
+  { // Il faut d�cr�menter le usecount des handles contenues dans
+    // PROCESS_INFORMATION, sinon les informations sur le process
+    // ne seront jamais lib�r�es par le syst�me...
+    ::CloseHandle(aProcessInformation.hProcess);
+    ::CloseHandle(aProcessInformation.hThread);
+  }
+  return 0;
+
+#else
+  String sCmd = pszCmdLine;
+  if( bBackground )
+    // Background task
+    sCmd += "&";
+
+  LogVerbose("sys", "Shell exec with effective uid %d", uid);
+  LogVerbose("sys", "Shell exec with effective gid %d", gid);
+  int iChildReturnCode = 0;
+  // fork a new process
+  pid_t pid = fork();
+  if( 0 == pid )
+  {
+    // Child process
+    if( gid > 0 )
+    {
+      // Set new gid
+      rc = setgid(gid);
+      if( rc )
+        exit(-1);
+    }
+    if( uid > 0 )
+    {
+      // Set new uid
+      rc = setuid(uid);
+      if( rc )
+        exit(-1);
+    }
+    // Execute shell command then exit
+    exit(system(PSZ(sCmd)));
+  }
+  else if( pid < 0 )
+    throw Exception("ERR_FILE", "Error cannot execute shell command", "Exec");
+//  iChildReturnCode = system(PSZ(sCmd));
+
+  // Parent process, let's wait for the child to finish
+  waitpid(pid, &iChildReturnCode, WEXITSTATUS(iChildReturnCode));
+  LogVerbose("sys", "return code %d", iChildReturnCode);
+  return iChildReturnCode;
+#endif
+}
+
+//=============================================================================
+//
+// Command line argument
+//
+//=============================================================================
+CommandLine *CommandLine::ms_pTheInstance = NULL;
+
+//----------------------------------------------------------------------------
+// CommandLine::Instance
+//----------------------------------------------------------------------------
+CommandLine *CommandLine::Instance()
+{
+  if( NULL == ms_pTheInstance )
+    ms_pTheInstance = new CommandLine;
+
+  return ms_pTheInstance;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::FindShortOpt
+//----------------------------------------------------------------------------
+SCommandLineOpt *CommandLine::FindShortOpt(const char cOpt)
+{
+  vecOpts::iterator itOpt;
+  for( itOpt = m_vecOptDefs.begin(); itOpt != m_vecOptDefs.end(); itOpt++ )
+  {
+    if( (*itOpt).cShortName == cOpt )
+      return &(*itOpt);
+  }
+  return NULL;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::FindLongOpt
+//----------------------------------------------------------------------------
+SCommandLineOpt *CommandLine::FindLongOpt(const String &strOpt)
+{
+  vecOpts::iterator itOpt;
+  for( itOpt = m_vecOptDefs.begin(); itOpt != m_vecOptDefs.end(); itOpt++ )
+  {
+    if( IsEquals((*itOpt).strLongName, strOpt) )
+      return &(*itOpt);
+  }
+  return NULL;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::AddOpt
+//----------------------------------------------------------------------------
+void CommandLine::AddOpt(char cShortName, pcsz pszLongName, pcsz pszValue, pcsz pszDesc)
+{
+  // Get a reference to the singleton object
+  CommandLine &o = *Instance();
+
+  SCommandLineOpt opt;
+  opt.cShortName = cShortName;
+  opt.strLongName = pszLongName;
+  opt.strDesc = pszDesc;
+  opt.strValue = pszValue ? pszValue : g_strEmpty;
+
+  o.m_vecOptDefs.push_back(opt);
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::AddArg
+//----------------------------------------------------------------------------
+void CommandLine::AddArg(pcsz pszDesc, bool bSingle)
+{
+  // Get a reference to the singleton object
+  CommandLine &o = *Instance();
+
+  SCommandLineArg arg;
+  arg.strDesc = pszDesc;
+  arg.bSingle = bSingle; // if not single Several argument can follow
+
+  o.m_vecArgDefs.push_back(arg);
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::BadOption
+//----------------------------------------------------------------------------
+bool CommandLine::BadOption(const String &strOpt)
+{
+  std::cerr << "Unrecognized option '" << strOpt << "'" << std::endl;
+  return ShowUsage(std::cerr);
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::Read
+//----------------------------------------------------------------------------
+bool CommandLine::Read(int iArgc, char **ppszArgv)
+{
+  // Get a reference to the singleton object
+  CommandLine &o = *Instance();
+
+  // Special options that ignore all others
+  CommandLine::AddOpt('h', "help", "", "Show this usage");
+  CommandLine::AddOpt('v', "version", "", "Program version");
+  
+  for(int i = 1; i < iArgc; i++ )
+  {
+    String strArg = ppszArgv[i];
+    if( StartWith(strArg, "--") )
+    {
+      // Supress "--" before option name
+      strArg.erase(0, 2);
+      SCommandLineOpt *pOpt = o.FindLongOpt(strArg);
+      if( !pOpt )
+        // Bad option
+        return BadOption("--" + strArg);
+      if( !pOpt->strValue.empty() && i < iArgc - 1 )
+        // Store value
+        o.m_dictOptValues[pOpt->strLongName] = ppszArgv[++i];
+      else
+        o.m_dictOptValues[pOpt->strLongName] = "dummy";
+    }
+    else if( StartWith(strArg, '-') )
+    {
+      // Supress "-" before option name
+      SCommandLineOpt *pOpt = o.FindShortOpt(strArg[1]);
+      if( NULL == pOpt )
+        // Bad option
+        return BadOption(strArg);
+      if( !pOpt->strValue.empty() && i < iArgc - 1 )
+        // Store value
+        o.m_dictOptValues[pOpt->strLongName] = ppszArgv[++i];
+      else
+        o.m_dictOptValues[pOpt->strLongName] = "dummy";
+    }
+    else
+    {
+      if( o.m_vecArgDefs.empty() )
+      {
+        std::cerr << "Unexpected argument \"" << strArg << "\"" << std::endl;
+        return ShowUsage(std::cerr);
+      }
+
+      // Simple argument
+      o.m_vecArgs.push_back(strArg);
+    }
+  }
+
+  // Check for "version" or "help" options
+  if( IsOption("version") )
+  {
+    std::cout << o.m_strCmdName << " V" << o.m_strCmdVersion << std::endl;
+    return false;
+  }
+
+  else if( IsOption("help") )
+    return ShowUsage(std::cout);
+
+  // Check arguments
+  else if( o.m_vecArgDefs.size() > o.m_vecArgs.size() )
+  {
+    std::cerr << "Argument missing." << std::endl;
+    return ShowUsage(std::cerr);
+  }
+
+
+  return true;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::IsOption
+//----------------------------------------------------------------------------
+bool CommandLine::IsOption(const String &strOpt)
+{
+  // Get a reference to the singleton object
+  CommandLine &o = *Instance();
+
+  StringDict::iterator it = o.m_dictOptValues.find(strOpt);
+  if( it != o.m_dictOptValues.end() )
+    return true;
+  return false;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::OptionValue
+//----------------------------------------------------------------------------
+String CommandLine::OptionValue(const String &strOpt)
+{
+  // Get a reference to the singleton object
+  CommandLine &o = *Instance();
+
+  StringDict::iterator it = o.m_dictOptValues.find(strOpt);
+  if( o.m_dictOptValues.end() == it )
+    return g_strEmpty;
+
+  return it->second;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::ArgCount
+//----------------------------------------------------------------------------
+int CommandLine::ArgCount()
+{
+  return Instance()->m_vecArgs.size();
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::Arg
+//----------------------------------------------------------------------------
+String CommandLine::Arg(int i)
+{
+  if( i >= 0 || i < ArgCount() )
+    return Instance()->m_vecArgs[i];
+  return g_strEmpty;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::SetCmdNameVersion
+//----------------------------------------------------------------------------
+void CommandLine::SetCmdNameVersion(const String &strName, const String &strVersion)
+{
+  Instance()->m_strCmdName = strName;
+  Instance()->m_strCmdVersion = strVersion;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::ShowUsage
+//----------------------------------------------------------------------------
+bool CommandLine::ShowUsage(std::ostream &os)
+{
+  // Get a reference to the singleton object
+  CommandLine &o = *Instance();
+  
+  os << "Usage:" << std::endl;
+  os << o.m_strCmdName;
+  if( o.m_vecOptDefs.size() > 0 )
+    os << " [options]";
+  if( o.m_vecArgDefs.size() > 0 )
+    for( uint ui = 0; ui < o.m_vecArgDefs.size(); ui++ )
+    {
+      os << " " << o.m_vecArgDefs[ui].strDesc;
+      if( !o.m_vecArgDefs[ui].bSingle )
+        os << "...";
+    }
+  os << std::endl;
+  if( o.m_vecOptDefs.size() > 0 )
+  {
+    os << "Options:";
+    for( uint ui = 0; ui < o.m_vecOptDefs.size(); ui++ )
+    {
+      std::ostringstream oss;
+      oss << std::endl << "-" << o.m_vecOptDefs[ui].cShortName << ", --" << o.m_vecOptDefs[ui].strLongName;
+      if( !o.m_vecOptDefs[ui].strValue.empty() )
+        oss << " <" << o.m_vecOptDefs[ui].strValue << ">";
+      // Format Output
+      os.width(40);
+      os << std::left << oss.str();
+      os << o.m_vecOptDefs[ui].strDesc;
+    }
+  }
+  os << std::endl;
+  return false;
+}
+
+//----------------------------------------------------------------------------
+// CommandLine::ShowUsage
+//----------------------------------------------------------------------------
+void CommandLine::ShowUsage(const String &strAppInfo)
+{
+  if( !strAppInfo.empty() )
+    cout << strAppInfo << endl;
+  ShowUsage(cout);
+}
+
+//=============================================================================
+//
+// App
+//
+//=============================================================================
+App::App(const String &strName)
+{
+  static App *s_pApp = NULL;
+  if( s_pApp )
+    throw  Exception("Can't allocate more than one application object", "App object already allocated", "App::App");
+
+  m_strName = strName;
+  s_pApp = this;
+}
+
+#ifdef __LINUX__
+// Signal handler
+static void child_handler(int signum)
+{
+    switch(signum) {
+    case SIGALRM: exit(EXIT_FAILURE); break;
+    case SIGUSR1: exit(EXIT_SUCCESS); break;
+    case SIGCHLD: exit(EXIT_FAILURE); break;
+    }
+}
+#define RUN_AS_USER "root"
+#endif
+//----------------------------------------------------------------------------
+// App::Deamonize
+//----------------------------------------------------------------------------
+void App::Deamonize()
+{
+#ifdef __LINUX__
+  LogInfo("app", "Deamonize process");
+
+  pid_t pid, sid, parent;
+  int lfp = -1;
+
+  String strLockFile = String("/var/lock/subsys/") + m_strName;
+  String strPidFile = String("/var/run/") + m_strName + String(".pid");
+
+  /* already a daemon */
+  if( getppid() == 1 ) return;
+
+  /* Drop user if there is one, and we were run as root */
+  if( getuid() == 0 || geteuid() == 0 )
+  {
+    struct passwd *pw = getpwnam(RUN_AS_USER);
+    if( pw ) 
+    {
+      LogNotice("app", "setting user to " RUN_AS_USER );
+      setuid( pw->pw_uid );
+    }
+  }
+
+  /* Trap signals that we expect to recieve */
+  signal(SIGCHLD,child_handler);
+  signal(SIGUSR1,child_handler);
+  signal(SIGALRM,child_handler);
+
+  /* Fork off the parent process */
+  pid = fork();
+  if( pid < 0 )
+  {
+    LogError("app", "unable to fork daemon, code=%d (%s)",
+              errno, strerror(errno) );
+    exit(EXIT_FAILURE);
+  }
+  /* If we got a good PID, then we can exit the parent process. */
+  if( pid > 0 )
+  {
+    /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
+       for two seconds to elapse (SIGALRM).  pause() should not return. */
+    alarm(2);
+    pause();
+    exit(EXIT_FAILURE);
+  }
+
+  /* Create the lock and pid files */
+  lfp = open(PSZ(strLockFile),O_RDWR|O_CREAT,0640);
+  if( lfp < 0 )
+  {
+    LogError("app", "unable to create lock file %s, code=%d (%s)",
+            PSZ(strLockFile), errno, strerror(errno) );
+    exit(EXIT_FAILURE);
+  }
+  if( lockf(lfp, F_TLOCK, 0) < 0 )
+  {
+    LogError("app", "Cannot lock file '%s'. Exiting", PSZ(strLockFile));
+    exit(EXIT_FAILURE);
+  }
+  int iPidFile = open(PSZ(strPidFile), O_RDWR|O_CREAT, 0640);
+  if( iPidFile < 0 )
+  {
+    LogError("app", "unable to create pid file %s, code=%d (%s)",
+            PSZ(strPidFile), errno, strerror(errno) );
+    exit(EXIT_FAILURE);
+  }
+  String strPid;
+  strPid.Printf("%d\n",getpid());
+	if( write(iPidFile,PSZ(strPid),strPid.size()) < 0 )
+  {
+    LogError("app", "unable to write into pid file %s, code=%d (%s)",
+            PSZ(strPidFile), errno, strerror(errno) );
+    exit(EXIT_FAILURE);
+  }
+
+  /* At this point we are executing as the child process */
+  parent = getppid();
+
+  /* Cancel certain signals */
+  signal(SIGCHLD,SIG_DFL); /* A child process dies */
+  signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
+  signal(SIGTTOU,SIG_IGN);
+  signal(SIGTTIN,SIG_IGN);
+  signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
+  signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
+
+  /* Change the file mode mask */
+  umask(0);
+
+  /* Create a new SID for the child process */
+  sid = setsid();
+  if (sid < 0)
+  {
+    LogError( "app", "unable to create a new session, code %d (%s)",
+            errno, strerror(errno) );
+    exit(EXIT_FAILURE);
+  }
+
+  /* Change the current working directory.  This prevents the current
+     directory from being locked; hence not being able to remove it. */
+  if ((chdir("/")) < 0)
+  {
+      LogError("app", "unable to change directory to %s, code %d (%s)",
+              "/", errno, strerror(errno) );
+      exit(EXIT_FAILURE);
+  }
+
+  /* Redirect standard files to /dev/null */
+  freopen( "/dev/null", "r", stdin);
+  freopen( "/dev/null", "w", stdout);
+  freopen( "/dev/null", "w", stderr);
+
+  /* Tell the parent process that we are A-okay */
+  kill( parent, SIGUSR1 );
+
+  LogNotice("app", "Process started");
+#endif
+}
+
+//=============================================================================
+//
+// Basic tree node
+//
+//=============================================================================
+//----------------------------------------------------------------------------
+// BasicTreeNode::BasicTreeNode
+//----------------------------------------------------------------------------
+BasicTreeNode::BasicTreeNode()
+{
+  m_pFirstChildNode = NULL;
+  m_pLastChildNode = NULL;
+  m_pNextSiblingNode = NULL;
+  m_pParentNode = NULL;
+}
+
+//----------------------------------------------------------------------------
+// BasicTreeNode::~BasicTreeNode
+//----------------------------------------------------------------------------
+BasicTreeNode::~BasicTreeNode()
+{
+  if( NULL != m_pFirstChildNode )
+    delete m_pFirstChildNode;
+  if( NULL != m_pNextSiblingNode )
+    delete m_pNextSiblingNode;
+}
+
+//----------------------------------------------------------------------------
+// BasicTreeNode::AddNode
+//----------------------------------------------------------------------------
+void BasicTreeNode::AddNode(BasicTreeNode *pNode)
+{
+  if( NULL == m_pFirstChildNode )
+  {
+    m_pFirstChildNode = pNode;
+    m_pLastChildNode = pNode;
+  }
+  else
+  {
+    m_pLastChildNode->m_pNextSiblingNode = pNode;
+    m_pLastChildNode = pNode;
+  }
+
+  pNode->m_pParentNode = this;
+  pNode->m_pNextSiblingNode = NULL;
+}
+
+//=============================================================================
+//
+// CEnvVariableEvaluator
+//
+//=============================================================================
+bool CEnvVariableEvaluator::Evaluate(String *pstrVar)
+{
+  return GetEnv(PSZ(*pstrVar), pstrVar);
+}
+
+//=============================================================================
+//
+// LogManager
+//
+//=============================================================================
+LogManager *LogManager::ms_pTheInstance = NULL;
+
+//----------------------------------------------------------------------------
+// LogManager::LogManager
+//----------------------------------------------------------------------------
+LogManager::LogManager() : m_iMinLevel(LOG_INFO)
+{
+}
+
+//----------------------------------------------------------------------------
+// LogManager::Instance
+//----------------------------------------------------------------------------
+LogManager *LogManager::Instance()
+{
+  if( NULL == ms_pTheInstance )
+    ms_pTheInstance = new LogManager;
+
+  return ms_pTheInstance;
+}
+
+//----------------------------------------------------------------------------
+// LogManager::PushLogTarget
+//----------------------------------------------------------------------------
+void LogManager::PushLogTarget(ILogTarget *pLogTarget)
+{
+  Instance()->m_stkCatchLogTarget.push(pLogTarget);
+}
+
+//----------------------------------------------------------------------------
+// LogManager::PopLogTarget
+//----------------------------------------------------------------------------
+void LogManager::PopLogTarget()
+{
+  // Get a reference to the singleton object
+  LogManager &o = *Instance();
+
+  if( !o.m_stkCatchLogTarget.empty() )
+    o.m_stkCatchLogTarget.pop();
+  else
+    throw LogException("Can't pop log target", "Log target stack is empty", "LogManager::PopLogTarget");
+}
+
+//----------------------------------------------------------------------------
+// LogManager::CurrentLogTarget
+//----------------------------------------------------------------------------
+ILogTarget *LogManager::CurrentLogTarget()
+{
+  // Get a reference to the singleton object
+  LogManager &o = *Instance();
+
+  if( !o.m_stkCatchLogTarget.empty() )
+    return o.m_stkCatchLogTarget.top();
+
+  return &o.m_defLogHandler;
+}
+
+//----------------------------------------------------------------------------
+// LogManager::Init
+//----------------------------------------------------------------------------
+void LogManager::Init(int iMinLevel, const String &_strFilter)
+{
+  // Get a reference to the singleton object
+  LogManager &o = *Instance();
+
+  o.m_iMinLevel = iMinLevel;
+
+  String strFilter = _strFilter, strType;
+  while( strFilter.size() > 0 )
+  {
+    ExtractToken(&strFilter, '|', &strType);
+    if( strType.size() > 0 )
+      o.m_setTypes.insert(strType);
+  }
+}
+
+//----------------------------------------------------------------------------
+// LogManager::Log
+//----------------------------------------------------------------------------
+void LogManager::Log(ELogLevel eLevel, pcsz pszType, const String &strMsg)
+{
+  // Get a reference to the singleton
+  LogManager &o = *Instance();
+
+  if( int(eLevel) < o.m_iMinLevel )
+    // Do nothing
+    return;
+
+  if( o.m_setTypes.size() > 0 &&
+      o.m_setTypes.find(String(pszType)) == o.m_setTypes.end() && 0 == eLevel )
+    // Type not found in filter set
+    return;
+  
+  // Notify log tarteg
+  if( CurrentLogTarget() )
+    CurrentLogTarget()->Log(eLevel, pszType, strMsg);
+}
+
+//=============================================================================
+//
+// DefaultLogHandler
+//
+//=============================================================================
+//----------------------------------------------------------------------------
+// DefaultLogHandler::Log
+//----------------------------------------------------------------------------
+void DefaultLogHandler::Log(ELogLevel eLevel, pcsz pszType, const String &strMsg)
+{
+  // Formatting message
+  CurrentDate dtCur;
+  String strLogDate = StrFormat("%4d-%02d-%02d,%02d:%02d:%02.3f", 
+                            dtCur.Year(), dtCur.Month(), dtCur.Day(),
+                            dtCur.Hour(), dtCur.Min(), dtCur.Sec());
+  
+  String strLevel;
+  switch( eLevel )
+  {
+    case LOG_EMERGENCY:
+      strLevel = "EMERGENCY";
+      break;
+    case LOG_ALERT:
+      strLevel = "ALERT";
+      break;
+    case LOG_CRITICAL:
+      strLevel = "CRITICAL";
+      break;
+    case LOG_ERROR:
+      strLevel = "ERROR";
+      break;
+    case LOG_WARNING:
+      strLevel = "WARNING";
+      break;
+    case LOG_NOTICE:
+      strLevel = "NOTICE";
+      break;
+    case LOG_INFO:
+      strLevel = "INFO";
+      break;
+    case LOG_VERBOSE:
+      strLevel = "DEBUG";
+      break;
+    case LOG_LEVEL_COUNT:
+    default:
+      break;
+  }
+  std::clog << strLogDate << ' ' << strLevel << ' ' << '[' << pszType << "]:" << strMsg << '\n';
+};
+
+//=============================================================================
+//
+// LogCatcher
+//
+//=============================================================================
+//----------------------------------------------------------------------------
+// LogCatcher::LogCatcher
+//----------------------------------------------------------------------------
+LogCatcher::LogCatcher(ILogTarget *pLogTarget)
+{
+  LogManager::PushLogTarget(pLogTarget);
+};
+
+//----------------------------------------------------------------------------
+// LogCatcher::~LogCatcher
+//----------------------------------------------------------------------------
+LogCatcher::~LogCatcher()
+{
+  LogManager::PopLogTarget();
+};
+
+//=============================================================================
+//
+// LogForward
+//
+//=============================================================================
+//----------------------------------------------------------------------------
+// LogForward::LogForward
+//----------------------------------------------------------------------------
+LogForward::LogForward(pfn_log_fwd pfn_log_fwd)
+{
+  m_pfn_log_fwd = pfn_log_fwd;
+}
+
+//----------------------------------------------------------------------------
+// LogForward::Log
+//----------------------------------------------------------------------------
+void LogForward::Log(ELogLevel eLevel, pcsz pszType, const String &strMsg)
+{
+	if( m_pfn_log_fwd != NULL )
+		m_pfn_log_fwd(eLevel, pszType, PSZ(strMsg));
+}
+
+//=============================================================================
+// Macro for Log functions
+//=============================================================================
+#define LOG_MSG(level)                                          \
+  va_list argptr;                                               \
+  va_start(argptr, pszFormat);                                  \
+  VSNPRINTF(g_acScratchBuf, g_iScratchLen, pszFormat, argptr);  \
+  va_end(argptr);                                               \
+  String strErr = g_acScratchBuf;                               \
+  LogManager::Log(level, pszType, strErr);
+
+// Log functions
+void gdshare::LogEmergency(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_EMERGENCY) 
+}
+
+void gdshare::LogAlert(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_ALERT) 
+}
+
+void gdshare::LogCritical(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_CRITICAL) 
+}
+
+void gdshare::LogError(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_ERROR) 
+}
+
+void gdshare::LogWarning(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_WARNING) 
+}
+
+void gdshare::LogNotice(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_NOTICE) 
+}
+
+void gdshare::LogInfo(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_INFO) 
+}
+
+void gdshare::LogVerbose(pcsz pszType, pcsz pszFormat, ...)
+{
+#ifdef _THREAD_SUPPORT
+  LOCK(&g_acScratchBuf)
+#endif
+ LOG_MSG(LOG_VERBOSE) 
+}
+
+
+//=============================================================================
+//
+// TemplateProcessor
+//
+//=============================================================================
+//----------------------------------------------------------------------------
+// TemplateProcessor::AddEvaluator
+//----------------------------------------------------------------------------
+void TemplateProcessor::AddEvaluator(IVariableEvaluator *pEvaluator)
+{
+  m_lstEvaluator.push_back(pEvaluator);
+}
+
+//----------------------------------------------------------------------------
+// TemplateProcessor::RemoveEvaluator
+//----------------------------------------------------------------------------
+void TemplateProcessor::RemoveEvaluator(IVariableEvaluator *pEvaluator)
+{
+  std::list<IVariableEvaluator *>::iterator itEvaluator = m_lstEvaluator.begin();
+
+  while( m_lstEvaluator.end() != itEvaluator )
+  {
+    if( *itEvaluator == pEvaluator )
+    {
+      m_lstEvaluator.erase(itEvaluator);
+      break;
+    }
+    itEvaluator++;
+  }
+}
+
+//----------------------------------------------------------------------------
+// TemplateProcessor::ProcessNoRecursion
+//----------------------------------------------------------------------------
+bool TemplateProcessor::ProcessNoRecursion(String *pstrTemplate)
+{
+  String strEval, strTmp;
+  String strTmpl = *pstrTemplate;
+  String strVar, strValue;
+  bool bNotReturnValue = false;
+
+  while( strTmpl.size() > 0 )
+  {
+    // Search for a variable
+    uint uiFirstPos = strTmpl.find("$(");
+    if( String::npos != uiFirstPos )
+    {
+      // Search for matching ')'. Take care of nested variables
+      uint uiMatchPos = strTmpl.find_first_of(')', uiFirstPos + 2);
+
+      if( String::npos != uiMatchPos )
+      {
+        // complete result string
+        strEval += strTmpl.substr(0, uiFirstPos);
+
+        // Delete up to '$(' characters
+        strTmpl.erase(0, uiFirstPos + 2);
+
+        // Extract variable content
+        strVar = strTmpl.substr(0, uiMatchPos - uiFirstPos - 2);
+        // Delete up to matching end parenthesis
+        strTmpl.erase(0, uiMatchPos - uiFirstPos - 1);
+
+        // Variable evaluation
+        bNotReturnValue = !ProcessVar(&strVar);
+        strEval += strVar;
+      }
+      else
+      {
+        // Missing close bracket
+        // Copying up to the end of template string
+        strEval += strTmpl;
+        strTmpl.erase();
+      }
+    }
+    else
+    {
+      // Copying up to the end of template string
+      strEval += strTmpl;
+      strTmpl.erase();
+    }
+  }
+
+  (*pstrTemplate) = strEval;
+  return !bNotReturnValue;
+}
+
+//----------------------------------------------------------------------------
+// TemplateProcessor::Process
+//----------------------------------------------------------------------------
+bool TemplateProcessor::Process(String *pstrTemplate, bool bRecurse)
+{
+  set<String> setSymbols;
+  return PrivProcess(pstrTemplate, bRecurse, setSymbols);
+}
+
+//----------------------------------------------------------------------------
+// TemplateProcessor::Process
+//----------------------------------------------------------------------------
+bool TemplateProcessor::PrivProcess(String *pstrTemplate, bool bRecurse, set<String> &setPrevSymbols)
+{
+  String strEval, strTmp;
+  String strTmpl = *pstrTemplate;
+  String strVar, strValue;
+  bool bNotReturnValue = false;
+
+  set<String> setSymbols = setPrevSymbols;
+
+  while( strTmpl.size() > 0 )
+  {
+    // Search for a variable
+    uint uiFirstPos = strTmpl.find("$(");
+    if( String::npos != uiFirstPos )
+    {
+      // Search for matching ')'. Take care of nested variables
+      uint uiMatchPos = uiFirstPos+1, nVar = 1;
+      while( nVar > 0 )
+      {
+        uiMatchPos = strTmpl.find_first_of("()", uiMatchPos + 1);
+        if( String::npos == uiMatchPos )
+          break;
+        if( ')' == strTmpl[uiMatchPos] )
+          nVar--;
+        else if( '$' == strTmpl[uiMatchPos-1] && '(' == strTmpl[uiMatchPos] )
+          nVar++;
+      }
+
+      if( String::npos != uiMatchPos )
+      {
+        // complete result string
+        strEval += strTmpl.substr(0, uiFirstPos);
+
+        // Delete up to '$(' characters
+        strTmpl.erase(0, uiFirstPos + 2);
+
+        // Extract variable content
+        strVar = strTmpl.substr(0, uiMatchPos - uiFirstPos - 2);
+        // Delete up to matching end parenthesis
+        strTmpl.erase(0, uiMatchPos - uiFirstPos - 1);
+
+        if( bRecurse )
+          // Evaluate variable name himself
+          // Ignore return value since the important is the evaluation below
+          PrivProcess(&strVar, true, setPrevSymbols);
+
+        // Keep track of searched symbol for subsequents recursives calls
+        setSymbols.insert(strVar);
+
+        // Evaluate variable only if it hasn't been evaluated in a previous call during recursive process
+        if( setPrevSymbols.find(strVar) == setPrevSymbols.end() )
+          bNotReturnValue |= !PrivProcessVar(&strVar, bRecurse, true, setSymbols);
+
+        // Variable evaluation
+        strEval += strVar;
+      }
+      else
+      {
+        // Missing close bracket
+        // Copying up to the end of template string
+        strEval += strTmpl;
+        strTmpl.erase();
+      }
+    }
+    else
+    {
+      // Copying up to the end of template string
+      strEval += strTmpl;
+      strTmpl.erase();
+    }
+  }
+
+  (*pstrTemplate) = strEval;
+  return !bNotReturnValue;
+}
+
+//----------------------------------------------------------------------------
+// TemplateProcessor::Process
+//----------------------------------------------------------------------------
+bool TemplateProcessor::ProcessVar(String *pstrVar)
+{
+  set<String> emptySet;
+  return PrivProcessVar(pstrVar, false, false, emptySet);
+}
+
+//----------------------------------------------------------------------------
+// TemplateProcessor::Process
+//----------------------------------------------------------------------------
+bool TemplateProcessor::PrivProcessVar(String *pstrVar, bool bRecurse, 
+                          bool bDeepEvaluation, set<String> &setEvaluatedSymbols)
+{
+  std::list<IVariableEvaluator *>::iterator itEvaluator = m_lstEvaluator.begin();
+
+  while( m_lstEvaluator.end() != itEvaluator )
+  {
+    if( (*itEvaluator)->Evaluate(pstrVar) )
+    {
+      if( bDeepEvaluation )
+        // Evaluate result himself
+        return PrivProcess(pstrVar, bRecurse, setEvaluatedSymbols);
+      else
+        return true;
+    }
+    itEvaluator++;
+  }
+
+  switch( m_eNotFoundReplacement )
+  {
+    case EMPTY_STRING:
+      *pstrVar = "";
+      break;
+    case VARIABLE_NAME:
+      break;
+    case UNCHANGE_STRING:
+      *pstrVar = string("$(") + *pstrVar + ')';
+      break;
+  }
+  return false;
+}
+
+//=============================================================================
+// MReferencable
+//=============================================================================
+
+//---------------------------------------------------------------------------
+// MReferencable::MReferencable
+//---------------------------------------------------------------------------
+MReferencable::MReferencable()
+{
+  m_iUseCount = 0;
+}
+
+//---------------------------------------------------------------------------
+// MReferencable::~MReferencable
+//---------------------------------------------------------------------------
+MReferencable::~MReferencable()
+{
+}
+
+//---------------------------------------------------------------------------
+// MReferencable::AddRef
+//---------------------------------------------------------------------------
+void MReferencable::AddRef() const
+{
+#ifdef _THREAD_SUPPORT
+    LOCK((void *)this);
+#endif
+  ++m_iUseCount;
+}
+
+//---------------------------------------------------------------------------
+// MReferencable::Release
+//---------------------------------------------------------------------------
+void MReferencable::Release() const
+{
+#ifdef _THREAD_SUPPORT
+    LOCK((void *)this);
+#endif
+
+  if( 0 == --m_iUseCount )
+    delete this;
+}
+
+//=============================================================================
+// MMetadata
+//=============================================================================
+//------------------------------------------------------------------------
+// MMetadata::AddMetadata
+//------------------------------------------------------------------------
+void MMetadata::AddMetadata(const String &strKey, const String &strValue)
+{
+  m_mapString[strKey] = strValue;
+}
+void MMetadata::AddMetadata(const String &strKey, const char *pszValue)
+{
+  if( pszValue )
+    m_mapString[strKey] = String(pszValue);
+  else
+    throw NullPointerException("Null pointer passed as metadata value", "MMetadata::AddMetadata");
+}
+void MMetadata::AddMetadata(const String &strKey, int iValue)
+{
+  m_mapInteger[strKey] = iValue;
+  // Also store metadata as string
+  String strTmp;
+  strTmp.Printf("%d", iValue);
+  m_mapString[strKey] = strTmp;
+}
+void MMetadata::AddMetadata(const String &strKey, double dValue)
+{
+  m_mapDouble[strKey] = dValue;
+  // Also store metadata as string
+  String strTmp;
+  strTmp.Printf("%g", dValue);
+  m_mapString[strKey] = strTmp;
+}
+
+//------------------------------------------------------------------------
+// MMetadata::HasMetadata
+//------------------------------------------------------------------------
+bool MMetadata::HasMetadata(const String &strKey) const
+{
+  std::map<String, String>::const_iterator it = m_mapString.find(strKey);
+  if( it != m_mapString.end() )
+    return true;
+  return false;
+}
+
+//------------------------------------------------------------------------
+// MMetadata::GetMetadata
+//------------------------------------------------------------------------
+bool MMetadata::GetMetadata(const String &strKey, String *pstrValue, bool bThrow) const
+{
+  std::map<String, String>::const_iterator it = m_mapString.find(strKey);
+  if( it == m_mapString.end() )
+  {
+    if( bThrow )
+      throw NoDataException("metadata not found", "MMetadata::GetMetadata");
+    else
+      return false;
+  }
+  *pstrValue = it->second;
+  return true;
+}
+
+//------------------------------------------------------------------------
+// MMetadata::GetIntegerMetadata
+//------------------------------------------------------------------------
+bool MMetadata::GetIntegerMetadata(const String &strKey, int *piValue, bool bThrow) const
+{
+  std::map<String, int>::const_iterator it = m_mapInteger.find(strKey);
+  if( it == m_mapInteger.end() )
+  {
+    if( bThrow )
+      throw NoDataException("metadata not found", "MMetadata::GetMetadata");
+    else
+      return false;
+  }
+  *piValue = it->second;
+  return true;
+}
+
+//------------------------------------------------------------------------
+// MMetadata::GetDoubleMetadata
+//------------------------------------------------------------------------
+bool MMetadata::GetDoubleMetadata(const String &strKey, double *pdValue, bool bThrow) const
+{
+  std::map<String, double>::const_iterator it = m_mapDouble.find(strKey);
+  if( it == m_mapDouble.end() )
+  {
+    if( bThrow )
+      throw NoDataException("metadata not found", "MMetadata::GetMetadata");
+    else
+      return false;
+  }
+  *pdValue = it->second;
+  return true;
+}
+
diff --git a/contrib/applications/NXextract/src/base.h b/contrib/applications/NXextract/src/base.h
new file mode 100644
index 0000000..76bcf42
--- /dev/null
+++ b/contrib/applications/NXextract/src/base.h
@@ -0,0 +1,1202 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Some useful definitions and shortcuts
+//
+// Creation : 18/02/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __BASE_H__
+#define __BASE_H__
+
+#ifdef WIN32
+  #define __WIN32__
+  #pragma warning(disable:4786)
+#elif defined(__linux__)
+  #define __UNIX__
+  #define __LINUX__
+  #define __WANT_STRICMP__  // undefined function
+#endif
+
+#include <iostream>
+
+// STL headers
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+#include <stack>
+#include <set>
+
+#ifdef __WANT_TREE_CLASS__
+  // include stl-like 'tree' class from Kasper Peeters (k.peeters at damtp.cam.ac.uk)
+  // (http://www.damtp.cam.ac.uk/user/kp229/index.html)
+  #ifdef  __WIN32__
+    #if _MSC_VER < 1300 // 1200 => vc 6.0
+      #include "tree_msvc.h"
+    #else
+      #include "tree.h"
+    #endif
+  #else
+    #include "tree.h"
+  #endif
+#endif
+
+#if defined(__WIN32__) && _MSC_VER > 1200
+    // Deprecated POSX definitions with VC8+
+    #define stricmp   _stricmp
+    #define strnicmp  _strnicmp
+    #define mkdir     _mkdir
+#endif
+
+#include <sys/types.h>
+
+#ifdef __WIN32__
+  // Fake definitions
+  typedef int mode_t;
+  typedef long uid_t;
+  typedef long gid_t;
+  typedef int fsid_t;
+#endif
+
+// Cast a string object to a const char *
+#define PSZ(s) (s).c_str()
+
+#if defined(__UNIX__) || (defined(__WIN32__) && _MSC_VER > 1200)
+  // Variadic macro supported starting in C99
+  #define PSZ_FMT(...) StrFormat(__VA_ARGS__).c_str()
+#endif
+
+// Usefull macro
+#define MAKEBOOL(a) (a)?true:false
+
+#ifdef __WANT_STRICMP__
+  int stricmp(const char *s1, const char *s2);
+  int strnicmp(const char *s1, const char *s2, int maxlen);
+#endif
+
+#ifdef _DEBUG
+  void PrintfDebug(const char *pcszFormat, ...);
+  void OutputDebug(const char *pcszString);
+  void checkmem();
+#endif
+
+// To ensure backward compatibility of the name space
+#define soleil gdshare
+
+using namespace std;
+
+namespace gdshare
+{
+
+//===========================================================================
+// Usual types
+//===========================================================================
+
+// Mapping 64 bit integers
+#ifdef _MSC_VER
+  #ifdef __WIN32__
+    typedef __int64 int64;
+  #endif
+#elif defined (__LINUX__)
+  typedef long long int64;
+#endif
+
+/// Other types
+typedef unsigned char  uint8;
+typedef unsigned char  byte;
+typedef unsigned char  uchar;
+typedef const char *   pcsz;
+typedef char *         psz;
+
+#ifdef __WIN32__
+  typedef unsigned short ushort;
+  typedef unsigned long  ulong;
+  typedef unsigned int   uint;
+#endif
+
+/// Make int64 from the long integers pair [highpart, lowpart]
+inline int64 int64FromHLPair(long lHigh, unsigned long ulLow) 
+{ 
+  int64 i64 = 1;
+  i64 = i64 << 32;
+  i64 = i64 * lHigh + ulLow;
+  return i64;
+}
+
+// Generic pointer to obj
+typedef void * obj_ptr;
+
+// Useful values for interpret 'ExtractToken' family methods
+#define EXTRACT_TOKEN_FOUND 1
+#define EXTRACT_TOKEN_NOT_FOUND 2
+#define EXTRACT_TOKEN_EMPTY_SOURCE 0
+
+//=============================================================================
+/// free functions
+//=============================================================================
+
+/// Returns true if process is running as root
+bool IsRoot();
+
+//=============================================================================
+/// Extended string class
+///
+//=============================================================================
+class String : public string
+{
+public:
+
+  /// ExtractToken methods result
+  enum ExtractRes
+  {
+    EMPTY_STRING=0,
+    SEP_FOUND,
+    SEP_NOT_FOUND
+  };
+	
+  //@{ Constructors
+  String() : string()
+  {}
+
+  String(const char *psz)
+  {
+    if( NULL == psz )
+      erase();
+    else
+      append(psz);
+  }
+
+  String(const char *psz, int iSize)
+  {
+    if( NULL == psz )
+      erase();
+    else
+      append(psz, iSize);
+  }
+
+  String(const String &str) : string(str)
+  {}
+
+  String(const string &str) : string(str)
+  {}
+  //@}
+
+  /// Compare strings
+  bool IsEquals(const String &str) const;
+
+  /// Compare string in a no case sensitive way
+  bool IsEqualsNoCase(const String &str) const;
+
+  /// Test first character
+  bool StartWith(char c) const;
+  /// Test first characters with other string
+  bool StartWith(pcsz pcszStart, bool bNoCase=false) const;
+  /// Test last character
+  bool EndWith(char c) const;
+  /// Test last character
+  bool EndWith(pcsz pcszEnd, bool bNoCase=false) const;
+
+  /// @name Extracting token from a string
+  ///
+  /// @param pstrSource The string to extract from
+  /// @param c Separator
+  /// @param pstrToken string receiving the extracted token
+  /// @return
+  /// 0 : nothing extracted
+  /// 1 : string extracted and separator found
+  /// 2 : string extracted and separator not found
+  ///
+
+  //@{ Extraction methods
+  /// Search token from left to right
+  int ExtractToken(char c, String *pstrToken);
+  /// Search token from right to left
+  int ExtractTokenRight(char c, String *pstrToken);
+  /// Search enclosed token from left to right
+  int ExtractToken(char cLeft, char cRight, String *pstrToken);
+  /// Search enclosed token from right to left
+  int ExtractTokenRight(char cLeft, char cRight, String *pstrToken);
+  //@}
+
+  /// Remove characters that enclose string: quotes, paranthesis, etc...
+  /// ex: RemoveEnclosure("'", "'") -> removes quotes in a string like 'string'
+  /// ex: RemoveEnclosure("([", ")]") -> removes paranthesis in a string like (string) or [string]
+  ///                                    but not in string like (string]
+  /// @param pcszLeft list of possible left enclosure chars
+  /// @param pcszRight list of possible right enclosure chars
+  /// @return true if enclosure was removed
+  bool RemoveEnclosure(pcsz pszLeft, pcsz pszRight);
+  bool RemoveEnclosure(char cLeft, char cRight);
+
+  /// Match string with mask containing '*' and '?' jokers
+  bool Match(pcsz pszMask) const;
+  bool Match(const String &strMask) const;
+
+  /// Remove white space and begining and end of string
+  void Trim();
+
+  /// Build a string with format
+  int Printf(pcsz pszFormat, ...);
+
+  /// Split string
+  ///
+  /// @param c Separator
+  /// @param pvecstr pointer to a vector of strings
+  ///
+  void Split(char c, vector<String> *pvecstr);
+  void Split(char c, vector<String> *pvecstr) const;
+  void Split(char c, String *pstrLeft, String *pstrRight, bool bPreserve=false);
+
+  /// Join strings from string vector
+  ///
+  /// @param cSep Items separator
+  ///
+  void Join(const vector<String> &vecStr, char cSep=',');
+
+  /// Remove item in a string like "item1,item2,item3,..."
+  ///
+  /// @param cSep Items separator
+  ///
+  /// @return true if the item was found, otherwise false
+  bool RemoveItem(const String &strItem, char cSep=',');
+
+  /// Convert characters to lowercase
+  void ToLower();
+
+  /// Convert string to uppercase
+  void ToUpper();
+
+  /// Find and replace
+  ///
+  /// @param pszSrc Substring to replace
+  /// @param pszDst Substitution string
+  ///
+  void Replace(pcsz pszSrc, pcsz pszDst);
+
+  /// Find and replace one character
+  ///
+  /// @param cSrc Character to replace
+  /// @param cDst Substitution Character
+  ///
+  void Replace(char cSrc, char cDst);
+
+  /// Crypting
+  ///
+  /// @param pszXorKey XOR key
+  /// @param pszRotKey ROT key
+  ///
+  void Crypt(const char* pszXorKey=NULL, const char* pszRotKey=NULL);
+
+  /// Decrypting
+  ///
+  /// @param pszXorKey XOR key
+  /// @param pszRotKey ROT key
+  ///
+  void Decrypt(const char* pszXorKey=NULL, const char* pszRotKey=NULL);
+
+  /// Returns hash code
+  ///
+  ulong Hash() const;
+};
+
+//## Will be removed when all String object will be replaced with String
+typedef String CString;
+
+// Empty string - useful when need a const string &
+extern const String g_strEmpty;
+
+// Simple scratch buffer (not thread safe)
+extern const int g_iScratchLen;
+extern char g_acScratchBuf[];
+
+//==============================================================================
+/// Error handling
+///
+//==============================================================================
+class Error
+{
+public:
+  enum ELevel
+  {
+    _WARNING = 0,
+    _ERROR = 1,
+    _CRITICAL = 2,
+    _ALERT = 3,
+    _EMERGENCY = 4,
+    _LEVEL_COUNT  // Not a error level, just the total number of levels
+  };
+
+private:
+  String m_strReason;  /**< Error reason (e.g. "OUT_OF_MEMORY") */
+  String m_strDesc;    /**< Error description */
+  String m_strOrigin;  /**< Origin of error */
+  ELevel  m_eLevel;     /**< Error level */
+
+public:
+  Error(const String &strReason, const String &strDesc, const String &strOrigin, ELevel eLevel = _ERROR)
+  : m_strReason(strReason), m_strDesc(strDesc), m_strOrigin(strOrigin), m_eLevel(eLevel)
+  {}
+
+  const String &Reason() const { return m_strReason; }
+  const String &Desc() const { return m_strDesc; }
+  const String &Origin() const { return m_strOrigin; }
+  const ELevel Level() const { return m_eLevel; }
+  String ToString() const;
+};
+
+// For deprecated class name CError
+typedef Error CError;
+
+//==============================================================================
+/// Error stack : singleton object
+///
+//==============================================================================
+class ErrorStack 
+{
+friend class IgnoreErrors;
+private:
+  static ErrorStack *ms_pTheInstance;
+  static Error s_EmptyError;
+  std::stack<Error> m_stkErrors;
+  bool   m_bLogError;
+  bool   m_bIgnoreError;
+
+  /// Give back a real object
+  static ErrorStack *Instance();
+  
+
+public:
+  static void Push(const String &strReason, const String &strDesc, 
+                   const String &strOrigin, CError::ELevel eLevel = CError::_ERROR);
+
+  /// Activate logging when a error is pushed
+  static void SetLogError(bool bLog = true);
+
+  /// Ignore errors
+  static void SetIgnoreErrors(bool bIgnore = true);
+
+  /// Return top error
+  static CError &Top();
+
+  /// Pop top error
+  static void Pop();
+
+  /// Returns true if stack is empty
+  static bool IsEmpty();
+
+  /// Clear stack
+  static void Clear();
+
+  /// Returns stack size
+  static int Size();
+
+  /// Returns all error msg in a single string
+  static String ToString(char cSep='\n');
+};
+// For deprecated class name CError
+#define CErrorStack ErrorStack
+
+//==============================================================================
+/// Instance this object to suspend error collecting from the errors stack
+///
+//==============================================================================
+class IgnoreErrors
+{
+  IgnoreErrors()  { CErrorStack::SetIgnoreErrors(); }
+  ~IgnoreErrors() { CErrorStack::SetIgnoreErrors(false); }
+};
+
+//==============================================================================
+/// Basic exception class
+///
+//==============================================================================
+class ExceptionBase
+{
+protected:
+  String m_strError;   // Error text
+  String m_strReason;  // Reason
+  String m_strMethod;  // Method name
+
+  virtual const char *ErrorTitle();
+
+public:
+  ExceptionBase(const char *pcszError, const char *pcszReason, const char *pcszMethod);
+
+  virtual ~ExceptionBase();
+
+  /// Prints error message on console
+  void PrintMessage();
+
+  /// Copies error message in a pre-allocated string buffer
+  ///
+  /// @param pBuf Buffer (allocated by caller) to copy the message in
+  /// @param iLen Buffer length
+  ///
+  String Message();
+
+  const String &Error() const { return m_strError; }
+  const String &Reason() const { return m_strReason; }
+  const String &Method() const { return m_strMethod; }
+};
+
+//==============================================================================
+/// Simple exception class
+///
+//==============================================================================
+class Exception : public ExceptionBase
+{
+protected:
+  const char *ErrorTitle()
+  {
+    return "A exception occured";
+  }
+public:
+  Exception(const char *pcszError=NULL, const char *pcszReason=NULL, const char *pcszMethod=NULL):
+  ExceptionBase(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//==============================================================================
+/// Null pointer exception
+///
+//==============================================================================
+class NullPointerException : public ExceptionBase
+{
+protected:
+  const char *ErrorTitle()
+  {
+    return "Null pointer exception";
+  }
+public:
+  NullPointerException(const char *pcszReason, const char *pcszMethod):
+  ExceptionBase("NULL_POINTER", pcszReason, pcszMethod)
+  { }
+};
+
+//==============================================================================
+/// No data exception
+///
+//==============================================================================
+class NoDataException : public ExceptionBase
+{
+protected:
+  const char *ErrorTitle()
+  {
+    return "No data exception";
+  }
+public:
+  NoDataException(const char *pcszReason, const char *pcszMethod):
+  ExceptionBase("NO_DATA", pcszReason, pcszMethod)
+  { }
+};
+
+//===========================================================================
+/// A few string algorithms
+//===========================================================================
+
+/// Compare strings
+bool IsEquals(const String &str1, const String &str2);
+
+/// Compare string in a no case sensitive way
+bool IsEqualsNoCase(const String &str1, const String &str2);
+
+/// @name Extracting token from a string
+///
+/// @param pstrSource The string to extract from
+/// @param c Separator
+/// @param pstrToken string receiving the extracted token
+/// @return
+/// 0 : nothing extracted
+/// 1 : string extracted and separator found
+/// 2 : string extracted and separator not found
+///
+
+//@{ Token extraction functions
+/// Search token from left to right
+int ExtractToken(String *pstrSource, char c, String *pstrToken);
+/// Search token from right to left
+int ExtractTokenRight(String *pstrSource, char c, String *pstrToken);
+/// Search enclosed token from left to right
+int ExtractToken(String *pstrSource, char cLeft, char cRight, String *pstrToken);
+/// Search enclosed token from right to left
+int ExtractTokenRight(String *pstrSource, char cLeft, char cRight, String *pstrToken);
+//@}
+
+/// Remove white space and begining and end of string
+void Trim(String *pstr);
+
+/// Test first character
+bool StartWith(const String &str, char c);
+/// Test first characters with other string
+bool StartWith(const String &str, pcsz pcszStart, bool bNoCase=false);
+/// Test last character
+bool EndWith(const String &str, char c);
+
+// Build a string with format
+String StrFormat(pcsz pszFormat, ...);
+
+//=============================================================================
+/// Simple strings dictionnary
+//=============================================================================
+class StringDict : public std::map<String, String>
+{
+public:
+  /// Export dictionary items to a string
+  ///
+  /// @param pstrDest destination string
+  ///        string format is : "name,<value size>=value|..."
+  ///
+  void Export(String *pstrDest);
+
+  /// Build a dictionnary from a string
+  ///
+  /// @param pstrSrc Source string
+  ///
+  void Import(const String &strSrc);
+
+  /// Complete StringDict entry
+  ///
+  /// @param strKey Entry name
+  /// @param strValue Value to add
+  /// @param cSep Values separator
+  ///
+  void ConcatValue(const String &strKey, const String &strValue, char cSep='|');
+
+  /// Return the value associated with the given key
+  ///
+  /// @param strKey Entry name
+  const String &Value(const String &strKey) const;
+
+  /// Return true if the given key exists in the dictionnary
+  ///
+  /// @param strKey Key name
+  ///
+  bool HasKey(const String &strKey) const;
+};
+
+//=============================================================================
+/// Command line option
+//=============================================================================
+struct SCommandLineOpt
+{
+  char   cShortName;
+  String strLongName;
+  bool   bMandatory;
+  String strDesc;
+  String strValue;
+};
+typedef std::vector<SCommandLineOpt> vecOpts;
+
+//=============================================================================
+/// Command line argument
+//=============================================================================
+struct SCommandLineArg
+{
+  String strDesc;
+  bool   bMandatory;
+  bool   bSingle;
+};
+
+typedef std::vector<SCommandLineArg> vecArgs;
+
+//=============================================================================
+/// Command line argument
+//=============================================================================
+class CommandLine
+{
+private:
+  static CommandLine *ms_pTheInstance;
+  static CommandLine *Instance();
+
+  StringDict m_dictOptValues;     // Current options values
+  std::vector<String> m_vecArgs;  // Simples arguments (not options)
+  vecOpts    m_vecOptDefs;        // Valid options list
+  vecArgs    m_vecArgDefs;        // Valid arguments list
+  StringDict m_dictOpts;          // Argument dictionnary
+  String     m_strCmdName;        // Command name
+  String     m_strCmdVersion;     // Version
+
+  /// Constructor
+  CommandLine() {}
+
+  /// Find option def from short form
+  SCommandLineOpt *FindShortOpt(const char cOpt);
+
+  /// Find option definition from long form
+  SCommandLineOpt *FindLongOpt(const String &strOpt);
+
+  /// Display "bad option" error message
+  ///
+  /// @return always false
+  static bool BadOption(const String &strOpt);
+
+  /// Show usage
+  ///
+  /// @return false
+  static bool ShowUsage(std::ostream &os = std::cout);
+
+public:
+  /// Set command name (displayed in ShowUsage() )
+  ///
+  static void SetCmdNameVersion(const String &strName, const String &strVersion);
+
+  /// Add a option
+  static void AddOpt(char cShortName, pcsz pszLongName, pcsz pszValue, pcsz pszDesc);
+
+  /// Add a argument
+  static void AddArg(pcsz pszDesc, bool bSingle=true);
+
+  /// Initializing with command line arguments
+  ///
+  /// @param iArgc, ppszArgv main() arguments
+  /// @return true if arguments are valid, otherwise false
+  ///
+  static bool Read(int iArgc, char **ppszArgv);
+
+  /// Showing Usage
+  ///
+  /// @param strAppInfo Additionnal information about the application
+  ///
+  static void ShowUsage(const String &strAppInfo);
+
+  /// Retreiving options, arguments and theirs values
+  static bool IsOption(const String &strArg);
+  static String OptionValue(const String &strOpt);
+  static int ArgCount();
+  static String Arg(int i);
+};
+
+// For deprecated class name CCommandLine
+typedef CommandLine CCommandLine;
+
+//=============================================================================
+/// Application object
+//=============================================================================
+class App
+{
+private:
+  String m_strName;
+
+protected:
+
+  /// Constructor
+  App(const String &strName);
+
+public:
+
+  virtual ~App() {}
+
+  /// Application entry point
+  virtual int OnRun()=0;
+  
+  /// Make the application a system deamon
+  void Deamonize();
+};
+
+//=============================================================================
+/// Logging messages
+///
+/// TODO : sending syslog messages
+//=============================================================================
+
+//=============================================================================
+///
+/// LogException
+///
+//=============================================================================
+class LogException : public ExceptionBase
+{
+protected:
+  const char *ErrorTitle()
+  {
+    return "Exception in logging system";
+  }
+public:
+  LogException(const char *pcszError=NULL, const char *pcszReason=NULL, const char *pcszMethod=NULL):
+  ExceptionBase(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+/// ELogLevel
+/// Define severity types using syslog levels definitions
+//=============================================================================
+enum ELogLevel
+{
+  LOG_VERBOSE = 0,
+  LOG_INFO,
+  LOG_NOTICE,
+  LOG_WARNING,
+  LOG_ERROR,
+  LOG_CRITICAL,
+  LOG_ALERT,
+  LOG_EMERGENCY,
+  LOG_LEVEL_COUNT  // Not a log level, just the total number of levels
+};
+
+//=============================================================================
+/// ILogTarget log target interface 
+///
+//=============================================================================
+class ILogTarget
+{
+public:
+  /// Log message
+  virtual void Log(ELogLevel eLevel, pcsz pszType, const String &strMsg)=0;
+};
+
+/// Log target stack, for logging redirection
+typedef std::stack<class ILogTarget *> LogTargetStack;
+
+//=============================================================================
+/// default log handler : print log on console using clog stream
+///
+//=============================================================================
+class DefaultLogHandler: public ILogTarget
+{
+public:
+  /// Log message
+  virtual void Log(ELogLevel eLevel, pcsz pszType, const String &strMsg);
+};
+
+/// Log forwarding function type declaration
+typedef void (*pfn_log_fwd)(int iLevel, const char *pszType, const char *pszMsg);
+
+// For deprecated class name CDefaultLogHandler
+typedef DefaultLogHandler CDefaultLogHandler;
+
+//=============================================================================
+/// log forwarding object : forward log to a specified function
+///
+//=============================================================================
+class LogForward: public ILogTarget
+{
+private:
+	/// Function to forward log to
+  pfn_log_fwd m_pfn_log_fwd;
+
+public:
+	/// Constructor
+  LogForward(pfn_log_fwd pfn_log_fwd);
+
+  /// ILogTarget
+  virtual void Log(ELogLevel eLevel, pcsz pszType, const String &strMsg);
+};
+
+// For deprecated class name CLogForward
+typedef LogForward CLogForward;
+
+//=============================================================================
+/// log utility class
+///
+//=============================================================================
+class LogManager
+{
+friend class LogCatcher;
+private:
+  static LogManager *ms_pTheInstance;
+  static LogManager *Instance();
+  DefaultLogHandler  m_defLogHandler;
+
+  /// Log target
+  LogTargetStack      m_stkCatchLogTarget;
+
+  /// Min severity level of logged messages
+  int         m_iMinLevel;
+
+  /// Logged messages types
+  std::set<String>  m_setTypes;
+
+  /// Add a new log target to the stack
+  static void PushLogTarget(ILogTarget *pLogTarget);
+
+  /// Remove top log target
+  static void PopLogTarget();
+
+public:
+  /// Constructor
+  LogManager();
+
+  /// Initialize LogHandler.
+  ///
+  /// @param eMinLevel Min severity level
+  /// @param strFilter List (separator = '|') of source types used for message filtering
+  ///
+  static void Init(int iMinLevel, const String &strFilter=g_strEmpty);
+
+  /// Log message
+  static void Log(ELogLevel eLevel, pcsz pszType, const String &strMsg);
+
+  /// Min log level take in account
+  static int MinLevel() { return Instance()->m_iMinLevel; }
+
+  /// Return current log target
+  static ILogTarget *CurrentLogTarget();
+};
+
+// For deprecated class name CLogManager
+typedef LogManager CLogManager;
+
+//=============================================================================
+/// Class used to define object that catch log, during CLogCatcher live time
+///
+//=============================================================================
+class LogCatcher
+{
+public:
+  /// Constructor : Push log target in ClogHandler stack
+  LogCatcher(ILogTarget *pLogTarget);
+
+  /// Destructor : remove top log target from the stack
+  ~LogCatcher();
+};
+
+// For deprecated class name CLogManager
+typedef LogCatcher CLogCatcher;
+
+//=============================================================================
+///
+/// Log functions
+///
+//=============================================================================
+
+void LogVerbose(pcsz pszType, pcsz pszFormat, ...);
+void LogInfo(pcsz pszType, pcsz pszFormat, ...);
+void LogNotice(pcsz pszType, pcsz pszFormat, ...);
+void LogWarning(pcsz pszType, pcsz pszFormat, ...);
+void LogError(pcsz pszType, pcsz pszFormat, ...);
+void LogCritical(pcsz pszType, pcsz pszFormat, ...);
+void LogAlert(pcsz pszType, pcsz pszFormat, ...);
+void LogEmergency(pcsz pszType, pcsz pszFormat, ...);
+
+//=============================================================================
+/// Free functions
+///
+//=============================================================================
+
+/// Reading a environnement variable
+///
+/// @param pszVar Variable name
+/// @param pstrValue string to store result to
+/// @param bBackground if true execute shell command in background (i.e. don't wait for a return code)
+/// @param uid used for shell execution (don't have any effect under Windows OS)
+/// @param gid used for shell execution (don't have any effect under Windows OS)
+/// @param bThrow if true may throw a exception in case if failure
+/// @param pszDef default value
+/// @return true in case of a defined variable, otherwire false
+///
+bool GetEnv(const char *pszVar, String *pstrValue, const char *pszDef = NULL);
+
+/// Execute command line
+int Exec(const char* pszCmdLine, const char *pszDefDir = NULL,
+         int bBackground = true, bool bThrow = true, ulong* pulReturnCode = NULL);
+int ExecAs(const char* pszCmdLine, const char *pszDefDir = NULL,
+         int bBackground = true, bool bThrow = true, ulong* pulReturnCode = NULL, uid_t uid = -1, gid_t gid = -1);
+
+//===========================================================================
+/// A simple template evaluator
+///
+/// This class is a interface so it can't be directly instancied
+/// @see TemplateString
+//===========================================================================
+class IVariableEvaluator
+{
+protected:
+  /// Constructor
+  IVariableEvaluator() { }
+
+public:
+  /// Attempts to evaluate a variable 
+  ///
+  /// @param pstrVar Variable to evaluate
+  /// @return true if template has been evaluated, or false
+  ///
+  virtual bool Evaluate(String *pstrVar)=0;
+};
+
+//===========================================================================
+/// Template processor
+///
+/// A TemplateString is a string that contains items to be replace with
+/// there real value
+/// example : in the string 'date is $(date)', '$(date)' will be replaced
+/// with the current date when processed
+//===========================================================================
+class TemplateProcessor
+{
+public:
+  enum NotFoundReplacement
+  {
+    EMPTY_STRING,
+    VARIABLE_NAME,
+    UNCHANGE_STRING
+  };
+
+private:
+  std::list<IVariableEvaluator *> m_lstEvaluator;
+  NotFoundReplacement m_eNotFoundReplacement;
+  bool PrivProcess(String *pstrTemplate, bool bRecurse, set<String> &setEvaluatedSymbols);
+  bool PrivProcessVar(String *pstrVar, bool bRecurse, bool bDeepEvaluation, set<String> &setEvaluatedSymbols);
+
+public:
+  ///
+  /// Constructor
+  ///
+  TemplateProcessor(NotFoundReplacement eNotFoundReplacement = VARIABLE_NAME) : m_eNotFoundReplacement(eNotFoundReplacement) {}
+
+  /// Add evaluator
+  ///
+  /// @param pEvaluator Evaluator object
+  ///
+  void AddEvaluator(IVariableEvaluator *pEvaluator);
+
+  /// Remove evaluator
+  ///
+  /// @param pEvaluator Evaluator object
+  ///
+  void RemoveEvaluator(IVariableEvaluator *pEvaluator);
+
+  /// Evaluate a variable
+  ///
+  /// @param pstrVar Variable to evaluate, will contains the result
+  /// @return true if evaluation is done, or false
+  ///
+  bool ProcessVar(String *pstrVar);
+
+  /// Process a template string
+  ///
+  /// @param strTemplate String to evaluate
+  /// @param pstrEvaluated Resulting string
+  /// @return true if evaluation is done, or false
+  ///
+  bool Process(String *pstrTemplate, bool bRecurse=true);
+  bool ProcessNoRecursion(String *pstrTemplate);
+};
+
+// CTemplateProcessor => deprecated name
+typedef TemplateProcessor CTemplateProcessor;
+
+//===========================================================================
+/// A template evaluator based of environnement variables
+///
+//===========================================================================
+class EnvVariableEvaluator : public IVariableEvaluator
+{
+public:
+  /// @param pstrVar Variable to evaluate
+  /// @return true if evaluation is done, or false
+  virtual bool Evaluate(String *pstrVar);
+};
+
+// CEnvVariableEvaluator => deprecated name
+#define CEnvVariableEvaluator EnvVariableEvaluator
+
+//=============================================================================
+///
+/// Basic tree node
+///
+/// note : already obsolete, rather use stl-like 'tree' class
+///
+//=============================================================================
+class BasicTreeNode
+{
+protected:
+  BasicTreeNode  *m_pFirstChildNode;
+  BasicTreeNode  *m_pLastChildNode;
+  BasicTreeNode  *m_pNextSiblingNode;
+  BasicTreeNode  *m_pParentNode;
+
+public:
+  /// Constructor
+  BasicTreeNode();
+
+  /// Destructor
+  virtual ~BasicTreeNode();
+
+  /// Add a node to the tree
+  void AddNode(BasicTreeNode *pNode);
+
+  /// Navigation
+  BasicTreeNode  *FirstChild() { return m_pFirstChildNode; }
+  BasicTreeNode  *NextSibling() { return m_pNextSiblingNode; }
+  BasicTreeNode  *Parent() { return m_pParentNode; }
+};
+
+
+//=============================================================================
+/// Mix-in class for pointer with use counts. Make your class derive from
+/// this mixin to make it support intelligent pointers
+//=============================================================================
+class MReferencable
+{
+private:
+  /// number of references on this instance
+  mutable int m_iUseCount;
+
+protected:
+  /// constructor / destructor
+  MReferencable();
+  virtual ~MReferencable();
+
+public:
+  /// Increase the ref count (const since mutable like)
+  void AddRef() const;
+  /// Decrease the ref count (const since mutable like)
+  void Release() const;
+  /// Returns the use count
+  int UseCount() const { return m_iUseCount; }
+};
+
+//=============================================================================
+/// The reference pointer itself
+/// To be used as
+///   RefPtr<CMyClass> ref;
+///   ref = new CMyClass;
+///   ref->Method();
+//=============================================================================
+template <class TYPE> class RefPtr
+{
+private:
+  TYPE* m_pRefObject;
+  void Free()
+  {
+    if( m_pRefObject )
+    {
+      m_pRefObject->Release();
+      m_pRefObject = NULL;
+    }
+  }
+
+public:
+  RefPtr(TYPE *pObj = NULL)             
+    : m_pRefObject(pObj)
+  {
+    if( m_pRefObject )
+      m_pRefObject->AddRef();
+  }
+
+  RefPtr(const RefPtr<TYPE>& ref)
+    : m_pRefObject(NULL)
+
+  {
+    operator=(ref.m_pRefObject);
+  }
+
+  ~RefPtr()                                   
+  {  Free(); }                                        
+                                                      
+  TYPE* operator->()                             
+  {                                                   
+    return m_pRefObject;                              
+  }                                                   
+                                                      
+  const TYPE* operator->() const                 
+  {                                                   
+    return (const TYPE*)m_pRefObject;           
+  }                                                   
+                                                      
+  bool operator==(const RefPtr<TYPE>& ref) const     
+    { return m_pRefObject == ref.m_pRefObject; }      
+                                                      
+  /// Comparaison operator that allow to use STL objects to maintain
+  /// a reference collection of uniques pointers
+  bool operator<(const RefPtr<TYPE>& ref) const     
+    { return (int)m_pRefObject < (int)ref.m_pRefObject; }      
+                                                      
+  RefPtr<TYPE>& operator=(TYPE* pObj)
+  {
+    if( m_pRefObject != pObj )
+    {
+      Free();
+      m_pRefObject = pObj;
+      if( m_pRefObject )
+        m_pRefObject->AddRef();
+    }
+    return *this;
+  }
+                                                      
+  RefPtr<TYPE>& operator=(const RefPtr<TYPE>& ref)
+    { return operator=(ref.m_pRefObject); }           
+                                                      
+  TYPE& operator*()                              
+    { return *m_pRefObject; }                         
+                                                      
+  operator TYPE*() const                        
+    { return m_pRefObject; }                          
+
+  TYPE *ObjectPtr() const                        
+    { return m_pRefObject; }                          
+                                                      
+  int IsNull() const                                 
+    { return m_pRefObject == NULL; }
+                      
+  void Clear()                                        
+    { Free(); }                                       
+};
+
+//=============================================================================
+/// Mix-in that add metadata capabilitie to objects
+//=============================================================================
+class MMetadata
+{
+private:
+  std::map<String, String> m_mapString; // "String" type metadata
+  std::map<String, int> m_mapInteger;   // "Integer" type metadata
+  std::map<String, double> m_mapDouble; // "Float" type metadata
+
+public:
+  /// Add String metadata
+  void AddMetadata(const String &strKey, const String &strValue);
+  /// Add C-ansi string metadata
+  void AddMetadata(const String &strKey, const char *pszValue);
+  /// Add integer matedata
+  void AddMetadata(const String &strKey, int iValue);
+  /// Add float metadata
+  void AddMetadata(const String &strKey, double dValue);
+
+  /// Check metadata
+  bool HasMetadata(const String &strKey) const;
+
+  /// Get metadata as string
+  /// Implicitely convert integer and float metadata as string value
+  /// @param  bThrow if true throw a exception in case of no data
+  /// @return true if metadata was found, otherwise false (if bThrow == false)
+  bool GetMetadata(const String &strKey, String *pstrValue, bool bThrow=true) const;
+
+  /// Get string metadata
+  /// @param  bThrow if true throw a exception in case of no data
+  /// @return true if metadata was found, otherwise false (if bThrow == false)
+  bool GetStringMetadata(const String &strKey, String *pstrValue, bool bThrow=true) const;
+
+  /// Get integer metadata
+  /// @param  bThrow if true throw a exception in case of no data
+  /// @return true if metadata was found, otherwise false (if bThrow == false)
+  bool GetIntegerMetadata(const String &strKey, int *piValue, bool bThrow=true) const;
+
+  /// Get float metadata
+  /// @param  bThrow if true throw a exception in case of no data
+  /// @return true if metadata was found, otherwise false (if bThrow == false)
+  bool GetDoubleMetadata(const String &strKey, double *pdValue, bool bThrow=true) const;
+};
+
+} // namespace soleil
+
+#ifdef _THREAD_SUPPORT
+	// Threading supported through YAT library
+	#define _YAT_THREADS
+	#include <yat/threading/Thread.h>
+	#include "threadutil.h"
+#endif
+
+#endif // __BASE_H__
diff --git a/contrib/applications/NXextract/src/bmp.cpp b/contrib/applications/NXextract/src/bmp.cpp
new file mode 100644
index 0000000..4bbafe4
--- /dev/null
+++ b/contrib/applications/NXextract/src/bmp.cpp
@@ -0,0 +1,143 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 01/12/2006
+// Author   : S. Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
+#include "base.h"
+#include "file.h"
+#include "membuf.h"
+#include "bmp.h"
+
+#define BMP_MAX_DIMENSION 65536
+
+using namespace gdshare;
+//=============================================================================
+// BmpEncoder
+//=============================================================================
+
+//------------------------------------------------------------------------
+// BmpEncoder::EncodeGrayScaleToFile
+//------------------------------------------------------------------------
+void BmpEncoder::EncodeGrayScaleToFile(MemBufPtr ptrMembuf, const String &strOutputFile)
+{
+  // Create output file
+  FILE * outfile;
+  if ((outfile = fopen(PSZ(strOutputFile), "wb")) == NULL) 
+  {
+	  fprintf(stderr, "can't open %s\n", PSZ(strOutputFile));
+	  exit(1);
+	}
+  
+  // Encode into a MemBuf object
+  MemBufPtr ptrDestBuf(new MemBuf);
+  EncodeGrayScaleToMemBuf(ptrMembuf, ptrDestBuf);
+
+  // flush Data to the file
+  fwrite(ptrDestBuf->Buf(), 1, ptrDestBuf->Len(), outfile);
+
+  // Close output file
+  fclose(outfile);
+}
+
+//------------------------------------------------------------------------
+// BmpEncoder::EncodeHeader
+//------------------------------------------------------------------------
+void BmpEncoder::EncodeHeader(MemBufPtr ptrmbDst, int iBitDepth, int iWidth, int iHeight, int *piBytePaddingPerRow)
+{
+  int iBytesPerPixel = iBitDepth / 8;
+  int iBytesPerRow = iBytesPerPixel * iWidth;
+
+  *piBytePaddingPerRow = (4 - iBytesPerRow % 4) % 4;
+  int iActualBytesPerRow = iBytesPerRow + *piBytePaddingPerRow;
+
+  int iTotalPixelBytes = iHeight * iActualBytesPerRow;
+
+  int iPaletteSize = 0;
+  if( iBitDepth == 8 )
+    iPaletteSize = (1 << iBitDepth) * 4;
+
+  // leave some room for 16-bit masks 
+  if( iBitDepth == 16 )
+    iPaletteSize = 3*4;
+
+  int iTotalFileSize = 14 + 40 + iPaletteSize + iTotalPixelBytes;
+  int iOffBits = 14 + 40 + iPaletteSize;
+  
+  // Encode file header
+  (*ptrmbDst) << 'B';                  // file marker
+  (*ptrmbDst) << 'M';                  // file marker
+  (*ptrmbDst) << (long)iTotalFileSize;  // Size
+  (*ptrmbDst) << (short)0;              // Reserved1
+  (*ptrmbDst) << (short)0;              // Reserved2
+  (*ptrmbDst) << (long)iOffBits;        // Offset bits
+
+  // Encode info header
+  (*ptrmbDst) << (long)40;              // Header size
+  (*ptrmbDst) << (long)iWidth;          // Image width
+  (*ptrmbDst) << (long)iHeight;         // Image height
+  (*ptrmbDst) << (short)1;              // Planes
+  (*ptrmbDst) << (short)iBitDepth;      // Bit count per pixel
+  (*ptrmbDst) << (long)0;               // Compression
+  (*ptrmbDst) << (long)iTotalPixelBytes;// Image size
+  (*ptrmbDst) << (long)3780;            // X pixels per meter
+  (*ptrmbDst) << (long)3780;            // Y pixels per meter
+  (*ptrmbDst) << (long)0;               // Colors used
+  (*ptrmbDst) << (long)0;               // Important colors
+
+  // Create B&W palette
+  for( int i = 0; i < 256; i++ )
+  {
+    (*ptrmbDst) << (uchar)i;               // Red
+    (*ptrmbDst) << (uchar)i;               // Green
+    (*ptrmbDst) << (uchar)i;               // Blue
+    (*ptrmbDst) << (uchar)0;               // Alpha
+  }
+}
+
+//------------------------------------------------------------------------
+// BmpEncoder::EncodeGrayScaleToMemBuf
+//------------------------------------------------------------------------
+void BmpEncoder::EncodeGrayScaleToMemBuf(MemBufPtr ptrmbSrc, MemBufPtr ptrmbDst)
+{
+  int iWidth, iHeight;
+  try
+  {
+    ptrmbSrc->GetIntegerMetadata("width", &iWidth);
+    ptrmbSrc->GetIntegerMetadata("height", &iHeight);
+  }
+  catch( NoDataException e )
+  {
+    // Transform exception into a jpeg exception
+    throw BmpEncoder::Exception(PSZ(e.Error()), PSZ(e.Reason()), "BmpEncoder::EncodeGrayScaleToMemBuf");
+  }
+
+  if( iWidth < 1 || iWidth > BMP_MAX_DIMENSION )
+    throw Exception("BAD_PARAMETER", "Wrongs image dimensions. Must be in [1, 65000]", "BmpEncoder::EncodeGrayScaleToMemBuf");
+
+  int iBytePaddingPerRow = 0;
+  EncodeHeader(ptrmbDst, 8, iWidth, iHeight, &iBytePaddingPerRow);
+
+  // Image data
+  for( int y = 0; y < iHeight; y++ )
+  {
+    ptrmbDst->PutBloc((uint8 *)(ptrmbSrc->Buf()) + (iHeight - y - 1) * iWidth, iWidth);
+    for( int i = 0; i < iBytePaddingPerRow; i++ )
+      (*ptrmbDst) << (uint8)0;
+  }
+}
+
diff --git a/contrib/applications/NXextract/src/bmp.h b/contrib/applications/NXextract/src/bmp.h
new file mode 100644
index 0000000..52ef522
--- /dev/null
+++ b/contrib/applications/NXextract/src/bmp.h
@@ -0,0 +1,68 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 01/12/2006
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __BMP_H__
+#define __BMP_H__
+
+namespace gdshare
+{
+
+
+#ifdef __WIN32__
+  #define CONVCALL __cdecl
+#else
+  #define CONVCALL
+#endif
+
+//==============================================================================
+/// Class BmpEncoder
+/// Class that take a MemBuxEx and a output file name to encode a grayscale bmp
+//==============================================================================
+class BmpEncoder
+{
+public:
+
+  //---------------------------------------------------------------------------
+  /// Bmp encoder exception
+  //---------------------------------------------------------------------------
+  class Exception : public ExceptionBase
+  {
+    protected:
+      const char *ErrorTitle()
+      {
+        return "Bmp encoder exception";
+      }
+
+    public:
+      Exception(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+      ExceptionBase(pcszError, pcszReason, pcszMethod)
+      { }
+  };
+
+private:
+  static void EncodeHeader(MemBufPtr ptrmbDst, int iBitDepth, int iWidth, int iHeight, int *piBytePaddingPerRow);
+
+public:
+  BmpEncoder();
+
+  static void EncodeGrayScaleToMemBuf(MemBufPtr ptrmbSrc, MemBufPtr ptrmbDst);
+  static void EncodeGrayScaleToFile(MemBufPtr ptrMembuf, const String &strOutputFile);
+};
+
+} // namespace
+
+#endif
diff --git a/contrib/applications/NXextract/src/date.cpp b/contrib/applications/NXextract/src/date.cpp
new file mode 100644
index 0000000..0cf074e
--- /dev/null
+++ b/contrib/applications/NXextract/src/date.cpp
@@ -0,0 +1,948 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// 'Date' class
+//
+// Creating : 22/03/2005
+// Author   : S. Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+
+#ifndef __DATE_H__
+  #include "date.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#if defined(WIN32)
+  #include <sys\timeb.h>
+  #define _X86_
+  #include <windef.h>
+  #include <winbase.h>
+  #include <winnls.h>
+//  #include "syswin.cpp"
+#elif defined(__LINUX__)
+  #include <sys/time.h>
+#endif
+
+// standard library objets
+#include <iostream>
+#include <time.h>
+
+/// Absolute reference : 0 january 4713 b JC at 12h ( -> -4712 for the calculations )
+const int REF_YEAR = -4712;
+
+/// Julian date for UNIX reference
+const int JULIAN_REF_UNIX = 2440588;
+
+// Error msgs
+const char DATE_SET_ERR[]        = "Cannot Setting Date object";
+
+// Reasons msgs
+const char DATE_BAD_ARGS[]        = "Bad arguments";
+
+using namespace soleil;
+
+//============================================================================
+// Internal functions
+//============================================================================
+
+// Number of days between 1th march 0 and 1th march iY
+long DeltaDaysYear(int iY)
+{
+  return 365l * iY +
+   ((long)iY/4l) -     // leap year
+   ((long)iY/100l) +   // 100th are not leap
+   ((long)iY/400l);    // 400th are leap years
+}
+
+// Number of days from 1th march to 1th <iM>
+long DeltaDaysMonth(int iM)
+{
+  return (306l*iM + 4l)/10l;
+}
+
+//----------------------------------------------------------------------------
+// Calculate julian date for a day at 12.
+// piDeltaDays : pointer to delta with julian calendar without the reform (in 1582)
+//----------------------------------------------------------------------------
+long CalcJulianDate(int iY, int iM, int iD, int *piDeltaDays=NULL)
+{
+  int flGregLeap = 0;
+  int flJulianLeap = 0;
+  int iYMod = iY % 4;
+  int iYFromRef = iY - REF_YEAR;
+  int iDeltaDays = 0;
+  // Number of days in Julian calendar
+  long lNbDays = iYFromRef * 365L + ((iYFromRef + 3) / 4);
+
+  // Leap year candidate
+  if( iYMod == 0 )
+  {
+    flJulianLeap = 1;
+    flGregLeap = 1;
+  }
+
+  // Year in Gregorian calendar
+  // Applying reform : 
+  if( iY > 1582 || (iY == 1582 && iM > 12 ) || (iY == 1582 && iM == 12 && iD > 19) )
+    iDeltaDays = 10;
+
+  // Calculating delta
+  int iDM = 0;
+  if( iY >= 1700 )
+    iDM = -((iY - 1) / 100) + ((iY - 1) / 400) + 12;
+
+  if( (iY % 400) && !(iY % 100) )
+    flGregLeap = 0;
+
+  iDeltaDays -= iDM;
+
+  // Add number of days
+  if( iM <= 8 )
+    lNbDays += (iM-1) * 30 + iM/2;
+  else
+    lNbDays += (iM-1) * 30 + (iM-1) / 2 + 1;
+
+  if( iM >= 3 && flGregLeap )
+    lNbDays--;
+  else if( iM >= 3 && !flGregLeap )
+  {
+    lNbDays += flJulianLeap - 2;
+    iDeltaDays += flJulianLeap;
+  }
+
+  if( piDeltaDays )
+    // Returns delta between Gregorian et Julian calandar
+    *piDeltaDays = iDeltaDays;
+
+  // Julian day in right calendar
+  return lNbDays + iD - 1 - iDeltaDays;
+}
+
+//----------------------------------------------------------------------------
+// Calculate Julian day date
+//----------------------------------------------------------------------------
+void JJToDate(long lJJ, int *piYear, uint *puiMonth, uint *puiDay)
+{
+  int iYear, iMonth=0, iDay;
+  // Retreive year
+  int iJulianYear = (int)(lJJ / 365.25);
+  iYear =  iJulianYear + REF_YEAR;
+  int iDeltaDays;
+  // Retreive le julian day for first day of this year
+  long lJJBegYear = CalcJulianDate(iYear, 1, 1, &iDeltaDays);
+
+  // Position in respect to the reform
+  int iDJ = int(lJJ - lJJBegYear);
+  int flLeap = 0;
+
+  if( lJJ < 2299226.5 )
+  {
+    iDJ -= iDeltaDays;
+
+    if( (iYear % 4) == 0 )
+      flLeap = 1;
+  }
+  else if( iYear == 1582 ) // && dJJ >= 2299226.5
+    iDJ += 10;
+
+  if( flLeap == 0 )
+  {
+    if( (iYear % 4) == 0 )
+      flLeap = 1;
+  }
+
+  if( lJJ >= 2299226.5 && (iYear % 100) == 0 && (iYear % 400) != 0 )
+    flLeap = 0;
+
+  int iDM = 0;
+  if( flLeap && iDJ == 59 )
+  {
+    // 29th februar
+    iDM = 30;
+    iMonth = 2;
+  }
+
+  if( flLeap && iDJ > 59 )
+    // Substract leap day
+    iDJ -= 1;
+
+  // Retreive month
+  iDJ -= 1;
+  if( iDJ >= 333 )
+  {
+    iMonth = 12;
+    iDM = 333;
+  }
+  else if( iDJ >= 303 )
+  {
+    iMonth = 11;
+    iDM = 303;
+  }
+  else if( iDJ >= 272 )
+  {
+    iMonth = 10;
+    iDM = 272;
+  }
+  else if( iDJ >= 242 )
+  {
+    iMonth = 9;
+    iDM = 242;
+  }
+  else if( iDJ >= 211 )
+  {
+    iMonth = 8;
+    iDM = 211;
+  }
+  else if( iDJ >= 180 )
+  {
+    iMonth = 7;
+    iDM = 180;
+  }
+  else if( iDJ >= 150 )
+  {
+    iMonth = 6;
+    iDM = 150;
+  }
+  else if( iDJ >= 119 )
+  {
+    iMonth = 5;
+    iDM = 119;
+  }
+  else if( iDJ >= 89 )
+  {
+    iMonth = 4;
+    iDM = 89;
+  }
+  else if( iDJ >= 58 && iDM == 0 )
+  {
+    iMonth = 3;
+    iDM = 58;
+  }
+  else if( iDJ >= 30 && iDM == 0 )
+  {
+    iMonth = 2;
+    iDM = 30;
+  }
+  else if( iDM == 0 )
+  {
+    iMonth = 1;
+    iDM = -1;
+  }
+
+  // Retreive day
+  iDay = iDJ - iDM + 1;
+
+  if( iDJ > 333 && iDay > 31 )
+  {
+    iYear += 1;
+    iDay -= 31;
+    iMonth = 1;
+  }
+
+  *piYear = iYear;
+  *puiMonth = iMonth;
+  *puiDay = iDay;
+}
+
+//----------------------------------------------------------------------------
+// TimeZoneBias
+//----------------------------------------------------------------------------
+double TimeZoneBias()
+{
+  #ifdef WIN32
+    TIME_ZONE_INFORMATION TimeZoneInformation;
+    GetTimeZoneInformation(&TimeZoneInformation);
+    double dSec = - (double)TimeZoneInformation.Bias * SEC_PER_MIN;
+    return dSec;
+  #else
+    struct timeval tv;
+    #ifdef __SVR4__
+      #ifdef _SVID_GETTOD
+        gettimeofday(&tv);
+      #else
+        gettimeofday(&tv, NULL);
+      #endif
+    #else
+      struct timezone tzp;
+      gettimeofday(&tv, &tzp);
+    #endif
+ 
+    // Calculer l'heure universelle
+    time_t tGM = tv.tv_sec;
+    struct tm tmGM;    
+    tGM = mktime(gmtime_r(&tGM, &tmGM));
+
+    // Calculer l'heure locale
+    time_t tLocal = tv.tv_sec;
+    struct tm tmLocal;        
+    tLocal = mktime(localtime_r(&tLocal, &tmLocal));
+
+    double dDiff = difftime(tLocal, tGM);
+    return dDiff;
+  #endif
+}
+
+//=============================================================================
+// SDateFields structure
+//
+//=============================================================================
+//----------------------------------------------------------------------------
+// SDateFields::Clear
+//----------------------------------------------------------------------------
+void SDateFields::Clear()
+{
+  memset(this, 0, sizeof(*this));
+}
+
+//----------------------------------------------------------------------------
+// SDateFields::IsEmpty
+//----------------------------------------------------------------------------
+int SDateFields::IsEmpty() const
+{
+  return iYear == 0 && 
+         uiMonth == 0 && 
+         uiDay == 0 && 
+         uiHour == 0 && 
+         uiMin == 0 &&
+         dSec == 0.;
+}
+
+//=============================================================================
+// Date class
+//
+//=============================================================================
+
+//----------------------------------------------------------------------------
+// Date::NbDaysInMonth
+//----------------------------------------------------------------------------
+int Date::NbDaysInMonth(int iMonth, int iYear)
+{
+  switch( iMonth )
+  {
+    case 1: // january
+    case 3: // march
+    case 5: // may
+    case 7: // july
+    case 8: // august
+    case 10:// october
+    case 12:// december
+      return 31;
+   
+    case 2: // februar : depend of year
+      if( (iYear%4 == 0 && iYear < 1582) ||
+           iYear%4 == 0 && ( (iYear%100) || !(iYear%400) ) )
+        return 29; // leap years
+      else 
+        return 28; // ordinary years
+
+    default : // other months
+      return 30;
+  }
+}
+
+//----------------------------------------------------------------------------
+// Date::NbDaysInYear
+//----------------------------------------------------------------------------
+int Date::NbDaysInYear(int iYear)
+{
+  if( !(iYear%4) && ( (iYear%100) || !(iYear%400) ) )
+    // Leap year
+    return 366;
+
+  return 365;
+}
+
+//----------------------------------------------------------------------------
+// Date::MonthName
+//----------------------------------------------------------------------------
+pcsz Date::MonthName(int iMonth)
+{
+  if( iMonth > 1 && iMonth < 13 )
+    return s_pszMonth[iMonth-1];
+
+  return "";
+}
+
+//----------------------------------------------------------------------------
+// Mise � l'heure courante
+// - bUt : si vrai, on utilise l'heure universelle (UTC)
+//----------------------------------------------------------------------------
+void Date::SetCurrent(bool bUt)
+{  
+  #ifdef WIN32
+    SYSTEMTIME sysTm;
+    if( bUt )
+      GetSystemTime(&sysTm);
+    else
+      GetLocalTime(&sysTm);
+    Set(sysTm.wYear, sysTm.wMonth, sysTm.wDay, sysTm.wHour, sysTm.wMinute, 
+        (double)sysTm.wSecond + ((double)sysTm.wMilliseconds)/1000.0);
+
+  #else
+    long lTm, lMs;
+    struct timeval tv;
+    struct timezone tzp;
+    gettimeofday(&tv, &tzp);
+    lTm = tv.tv_sec;
+    lMs = tv.tv_usec/1000;
+
+    // Convert from 'time_t' format to 'struct tm' format
+    struct tm tmCurrent;
+    if (bUt)
+      gmtime_r(&lTm, &tmCurrent);
+    else
+      localtime_r(&lTm, &tmCurrent);
+
+    Set(tmCurrent.tm_year+1900, tmCurrent.tm_mon+1, tmCurrent.tm_mday, tmCurrent.tm_hour, 
+        tmCurrent.tm_min, (double)tmCurrent.tm_sec + ((double)lMs /1000.));
+  #endif
+}
+
+//----------------------------------------------------------------------------
+// Date::LocalToUT
+//----------------------------------------------------------------------------
+void Date::LocalToUT()
+{
+  *this -= TimeZoneBias();
+}
+
+//----------------------------------------------------------------------------
+// Date::UTToLocal
+//----------------------------------------------------------------------------
+void Date::UTToLocal()
+{
+  *this += TimeZoneBias();
+}
+
+//----------------------------------------------------------------------------
+// Date::Get
+//----------------------------------------------------------------------------
+void Date::Get(SDateFields *pDF) const
+{              
+  // Retreive Julian date
+  long lJJ = JulianDate();
+
+  // Day of week
+  pDF->iDayOfWeek = (int)(lJJ % 7) + 2;
+  if( pDF->iDayOfWeek > 7 )
+    pDF->iDayOfWeek -= 7;
+
+  // Set monday as first day of week
+  pDF->iDayOfWeek -= 1;
+  if( pDF->iDayOfWeek == 0 )
+    pDF->iDayOfWeek = 7;
+
+  // Retreive date
+  JJToDate(lJJ, &pDF->iYear, &pDF->uiMonth, &pDF->uiDay);
+
+  // Hour, minutes, seconds
+  ulong ulSec = long((m_llDate / int64(MICROSEC_PER_SEC)) % int64(SEC_PER_DAY));
+  pDF->uiHour = (uint)(ulSec / SEC_PER_HOUR);
+  ulSec -= pDF->uiHour * SEC_PER_HOUR;
+  pDF->uiMin = (uint)(ulSec / SEC_PER_MIN);
+  int iSec = (uint)(ulSec - pDF->uiMin * SEC_PER_MIN);
+  // Retreive micro-seconds
+  double dMicro = double(m_llDate % MICROSEC_PER_SEC);
+  pDF->dSec = iSec + dMicro / (double)MICROSEC_PER_SEC;
+
+  // Calculate day of year
+  pDF->iDayOfYear = (int)(JulianDate() - CalcJulianDate(pDF->iYear, 1, 1)) + 1;
+
+  // Week of year
+  int iDay = pDF->iDayOfYear - pDF->iDayOfWeek;
+  pDF->iWeekOfYear = iDay / 7; 
+  if( iDay >= 0 )
+    pDF->iWeekOfYear++;
+}
+
+//----------------------------------------------------------------------------
+// Date::Set
+//----------------------------------------------------------------------------
+void Date::Set(const SDateFields &df)
+{
+  if( df.IsEmpty() )
+    // Empty date
+    m_llDate = 0;
+  else
+  {
+    uint uiMonth = df.uiMonth;
+    int iYear  = df.iYear;
+
+    // Check fields
+    if( uiMonth > 12 ||  
+        df.uiDay < 1 || df.uiDay > (uint)NbDaysInMonth(uiMonth, iYear) || 
+        df.uiHour > 24 ||
+        df.uiMin > 59 || 
+        df.dSec < 0 || df.dSec >= 60. )
+    {
+      throw DateException(DATE_SET_ERR, DATE_BAD_ARGS, "Date::Set");
+    }
+
+    // Julian day at 12.
+    double dJJ = CalcJulianDate(df.iYear, df.uiMonth , df.uiDay);
+    m_llDate = int64(dJJ * SEC_PER_DAY) * int64(MICROSEC_PER_SEC) + 
+               int64(df.uiHour * SEC_PER_HOUR) * int64(MICROSEC_PER_SEC) +
+               int64(df.uiMin * SEC_PER_MIN) * int64(MICROSEC_PER_SEC) +
+               int64(df.dSec * MICROSEC_PER_SEC);
+  }
+}
+ 
+//----------------------------------------------------------------------------
+// Date::Set
+//----------------------------------------------------------------------------
+void Date::Set(int iYear, uint uiMonth, uint uiDay, 
+                uint uiHour, uint uiMin, double dSec)
+{
+  SDateFields df;
+  df.iYear  = iYear;
+  df.uiMonth = uiMonth;
+  df.uiDay   = uiDay;
+  df.uiHour  = uiHour;
+  df.uiMin   = uiMin;
+  df.dSec   = dSec;
+  Set(df);
+}
+
+//----------------------------------------------------------------------------
+// Date::SetDayOfYear
+//----------------------------------------------------------------------------
+void Date::SetDayOfYear(int iDayOfYear, int iYear)
+{
+  SDateFields df;
+  Get(&df);
+  Set(iYear, 1, 1, df.uiHour, df.uiMin, df.dSec);
+  AddSec((iDayOfYear - 1) * SEC_PER_DAY);
+}
+
+// Macro for implementing access to date fields
+#define IMPLEMENT_DATEFIELD(Name)     \
+void Date::Set##Name(uint ui)          \
+{                                     \
+  SDateFields df;                     \
+  Get(&df);                           \
+  df.ui##Name = ui;                     \
+  Set(df);                            \
+}                                     \
+                                      \
+uint Date::Name() const               \
+{                                     \
+  SDateFields df;                     \
+  Get(&df);                           \
+  return df.ui##Name;                  \
+}                                     
+
+IMPLEMENT_DATEFIELD(Min)
+IMPLEMENT_DATEFIELD(Hour)
+IMPLEMENT_DATEFIELD(Day)
+IMPLEMENT_DATEFIELD(Month)
+
+//----------------------------------------------------------------------------
+// Date::SetYear
+//----------------------------------------------------------------------------
+void Date::SetYear(int iYear)
+{
+  SDateFields df;
+  Get(&df);
+  df.iYear = iYear;
+  Set(df);
+}
+
+//----------------------------------------------------------------------------
+// Date::Year
+//----------------------------------------------------------------------------
+int Date::Year() const
+{
+  SDateFields df;
+  Get(&df);
+  return df.iYear;
+}
+ 
+//----------------------------------------------------------------------------
+// Date::SetSec
+//----------------------------------------------------------------------------
+void Date::SetSec(double dSec)
+{
+  SDateFields df;
+  Get(&df);
+  df.dSec = dSec;
+  Set(df);
+}
+
+//----------------------------------------------------------------------------
+// Date::Sec 
+//----------------------------------------------------------------------------
+double Date::Sec() const
+{
+  SDateFields df;
+  Get(&df);
+  return df.dSec;
+}
+
+//----------------------------------------------------------------------------
+// Date::Micro
+//----------------------------------------------------------------------------
+long Date::Micro() const
+{
+  return long(m_llDate % MICROSEC_PER_SEC);
+}
+
+//----------------------------------------------------------------------------
+// Date::Ms
+//----------------------------------------------------------------------------
+long Date::Ms() const
+{
+  return long(m_llDate % MICROSEC_PER_SEC) / 1000;
+}
+
+//----------------------------------------------------------------------------
+// Date::JulianDate
+//----------------------------------------------------------------------------
+long Date::JulianDate() const
+{
+  return long(m_llDate / MICROSEC_PER_DAY);
+}
+
+//----------------------------------------------------------------------------
+// Date::SetJulianDate
+//----------------------------------------------------------------------------
+void Date::SetJulianDate(long lJulianDate)
+{
+  m_llDate = lJulianDate * MICROSEC_PER_DAY;
+}
+
+//----------------------------------------------------------------------------
+// Date::DayOfWeek 
+//----------------------------------------------------------------------------
+int Date::DayOfWeek() const
+{
+  SDateFields df;
+  Get(&df);
+  return df.iDayOfWeek;
+}
+
+//----------------------------------------------------------------------------
+// Date::DayOfYear
+//----------------------------------------------------------------------------
+int Date::DayOfYear() const
+{
+  long lJStartDate = CalcJulianDate(Year(), 1, 1);
+  return (int)(JulianDate() - lJStartDate) + 1;
+}
+
+//----------------------------------------------------------------------------
+// Date::WeekOfYear
+//----------------------------------------------------------------------------
+int Date::WeekOfYear() const
+{
+  SDateFields df;
+  Get(&df);
+  return df.iWeekOfYear;
+}
+
+//----------------------------------------------------------------------------
+// Date::LongUnix()
+//----------------------------------------------------------------------------
+long Date::LongUnix() const
+{
+  return (long)(((m_llDate / MICROSEC_PER_SEC) - int64(JULIAN_REF_UNIX) * int64(SEC_PER_DAY)));
+}
+
+//----------------------------------------------------------------------------
+// Date::SetLongUnix
+//----------------------------------------------------------------------------
+void Date::SetLongUnix(long lRefSec)
+{
+  m_llDate = (int64(JULIAN_REF_UNIX) * int64(SEC_PER_DAY) + int64(lRefSec)) * int64(MICROSEC_PER_SEC);
+}
+
+//----------------------------------------------------------------------------
+// Date::DoubleUnix()
+//----------------------------------------------------------------------------
+double Date::DoubleUnix() const
+{
+  return double(((m_llDate / MICROSEC_PER_SEC) - int64(JULIAN_REF_UNIX) * int64(SEC_PER_DAY)))
+         + Ms() / 1000.0;
+}
+
+//----------------------------------------------------------------------------
+// Date::SetDoubleUnix
+//----------------------------------------------------------------------------
+void Date::SetDoubleUnix(double dRefSec)
+{
+  m_llDate = (int64(JULIAN_REF_UNIX) * int64(SEC_PER_DAY) * int64(1000) + 
+             int64(dRefSec * 1000)) * int64(1000);
+}
+
+//----------------------------------------------------------------------------
+// Date::ISO8601
+//----------------------------------------------------------------------------
+String Date::ToLocalISO8601() const
+{
+  String strDate;
+  String strFmt;
+
+  double dTZ = TimeZoneBias();
+  if( dTZ < 0 )
+    strFmt = "%04d-%02d-%02dT%02d:%02d:%02d-%02d%02d";
+  else
+    strFmt = "%04d-%02d-%02dT%02d:%02d:%02d+%02d%02d";
+
+  // Prevent any rounding error
+  if( dTZ < 0 )
+    dTZ = -dTZ;
+
+  int iSec = int(dTZ + 0.5);
+   
+  int iHourBias = iSec / 3600;
+  int iMinBias = (iSec - (3600 * iHourBias)) / 60;
+
+  // Split date into fields
+  SDateFields df;
+  Get(&df);
+  
+  strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, long(df.dSec + 0.5), iHourBias, iMinBias);
+  return strDate;
+}
+
+//----------------------------------------------------------------------------
+// Date::ToISO8601
+//----------------------------------------------------------------------------
+String Date::ToISO8601() const
+{
+  String strDate;
+  String strFmt = "%04d-%02d-%02dT%02d:%02d:%02dZ";
+
+  // Split date into fields
+  SDateFields df;
+  Get(&df);
+  
+  strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, long(df.dSec + 0.5));
+  return strDate;
+}
+
+//----------------------------------------------------------------------------
+// Date::ToISO8601ms
+//----------------------------------------------------------------------------
+String Date::ToISO8601msTU() const
+{
+  String strDate;
+  String strFmt = "%04d-%02d-%02dT%02d:%02d:%06.3lfZ";
+
+  // Split date into fields
+  SDateFields df;
+  Get(&df);
+  
+  strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, df.dSec);
+  return strDate;
+}
+
+//----------------------------------------------------------------------------
+// Date::ToISO8601ms
+//----------------------------------------------------------------------------
+String Date::ToISO8601ms() const
+{
+  String strDate;
+  String strFmt;
+
+  strFmt = "%04d-%02d-%02dT%02d:%02d:%06.3lf";
+
+  // Split date into fields
+  SDateFields df;
+  Get(&df);
+  
+  strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, df.dSec);
+  return strDate;
+}
+
+//----------------------------------------------------------------------------
+// Date::ToLocalISO8601ms
+//----------------------------------------------------------------------------
+String Date::ToLocalISO8601ms() const
+{
+  String strDate;
+  String strFmt;
+
+  double dTZ = TimeZoneBias();
+  if( dTZ < 0 )
+    strFmt = "%04d-%02d-%02dT%02d:%02d:%06.3lf-%02d%02d";
+  else
+    strFmt = "%04d-%02d-%02dT%02d:%02d:%06.3lf+%02d%02d";
+
+  // Prevent any rounding error
+  if( dTZ < 0 )
+    dTZ = -dTZ;
+
+  int iSec = int(dTZ + 0.5);
+   
+  int iHourBias = iSec / 3600;
+  int iMinBias = (iSec - (3600 * iHourBias)) / 60;
+
+  // Split date into fields
+  SDateFields df;
+  Get(&df);
+  
+  strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, df.dSec, iHourBias, iMinBias);
+  return strDate;
+}
+
+//----------------------------------------------------------------------------
+// Date::ToInter
+//----------------------------------------------------------------------------
+String Date::ToInter(bool bMillis) const
+{
+  String strDate;
+  String strFmt;
+
+  if( bMillis )
+    strFmt = "%04d-%02d-%02d %02d:%02d:%06.3lf";
+  else
+    strFmt = "%04d-%02d-%02d %02d:%02d:%02d";
+
+  // Split date into fields
+  SDateFields df;
+  Get(&df);
+  
+  if( bMillis )
+    strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, df.dSec);
+  else
+    strDate = StrFormat(PSZ(strFmt), df.iYear, df.uiMonth, df.uiDay,
+                              df.uiHour, df.uiMin, int(df.dSec+0.5));
+
+  return strDate;
+}
+
+//----------------------------------------------------------------------------
+// Date::UnixTime
+//----------------------------------------------------------------------------
+ulong Date::UnixTime()
+{
+  return CurrentDate().LongUnix();
+}
+
+//===========================================================================
+//
+// CurrentDate
+//
+//===========================================================================
+//----------------------------------------------------------------------------
+// CurrentDate::CurrentDate
+//----------------------------------------------------------------------------
+CurrentDate::CurrentDate(bool bUT)
+{
+  SetCurrent(bUT);
+}
+
+//===========================================================================
+//
+// CurrentDate
+//
+//===========================================================================
+//----------------------------------------------------------------------------
+// DateVariableEvaluator::DateVariableEvaluator
+//----------------------------------------------------------------------------
+DateVariableEvaluator::DateVariableEvaluator(const Date &aDate) :
+m_tDate(aDate), m_bFixedDate(true), m_bUT(false)
+{
+
+}
+DateVariableEvaluator::DateVariableEvaluator(bool bFixedDate, bool bUT) :
+m_bFixedDate(bFixedDate), m_bUT(bUT)
+{
+  if( bFixedDate )
+    m_tDate.SetCurrent();
+}
+
+//----------------------------------------------------------------------------
+// DateVariableEvaluator::DateVariableEvaluator
+//----------------------------------------------------------------------------
+bool DateVariableEvaluator::Evaluate(String *pstrVar)
+{
+  if( !m_bFixedDate )
+    m_tDate.SetCurrent(m_bUT);
+
+  if( IsEqualsNoCase(*pstrVar, "ISO8601" ) )
+  {
+    *pstrVar = m_tDate.ToLocalISO8601();
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "UNIXDATE" ) )
+  {
+    *pstrVar = StrFormat("%ld", m_tDate.LongUnix());
+    return true;
+  }
+
+  SDateFields df;
+  m_tDate.Get(&df);
+
+  if( IsEqualsNoCase(*pstrVar, "YEAR" ) )
+  {
+    *pstrVar = StrFormat("%d", df.iYear);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "YEAR100" ) )
+  {
+    *pstrVar = StrFormat("%02d", df.iYear % 100);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "MONTH" ) )
+  {
+    *pstrVar = StrFormat("%02d", df.uiMonth);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "DAY" ) )
+  {
+    *pstrVar = StrFormat("%02d", df.uiDay);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "DAY-OF-YEAR" ) )
+  {
+    *pstrVar = StrFormat("%03d", df.iDayOfYear);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "HOUR" ) )
+  {
+    *pstrVar = StrFormat("%02d", df.uiHour);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "MIN" ) )
+  {
+    *pstrVar = StrFormat("%02d", df.uiMin);
+    return true;
+  }
+
+  else if( IsEqualsNoCase(*pstrVar, "SEC" ) )
+  {
+    *pstrVar = StrFormat("%02d", int(df.dSec + 0.5));
+    return true;
+  }
+
+  return false;
+}
diff --git a/contrib/applications/NXextract/src/date.h b/contrib/applications/NXextract/src/date.h
new file mode 100644
index 0000000..241be55
--- /dev/null
+++ b/contrib/applications/NXextract/src/date.h
@@ -0,0 +1,441 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// 'Date' class
+//
+// Creating : 22/03/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __DATE_H__
+#define __DATE_H__
+
+#ifndef __BASE_H__
+  #include "base.h"
+#endif
+
+namespace gdshare
+{
+
+//============================================================================
+// Constantes
+//============================================================================
+
+// Usual durations
+#define SEC_PER_MIN         60L
+#define SEC_PER_HOUR        3600L
+#define SEC_PER_DAY         86400L
+#define SEC_PER_MONTH       (SEC_PER_DAY*30)     // logical month (30 days)
+#define SEC_PER_YEAR        (SEC_PER_DAY*30*12)  // logical year (12 logicals months)
+
+#ifndef MS_SEC
+  #define MS_SEC              1000L              // milliseconds per second
+#endif
+#define MICROSEC_PER_SEC      1000000L           // microseconds per second
+
+#define MICROSEC_PER_DAY_H    20L
+#define MICROSEC_PER_DAY_L    500654080UL
+#define MICROSEC_PER_DAY      int64FromHLPair(MICROSEC_PER_DAY_H, MICROSEC_PER_DAY_L) // microseconds per day 
+
+#ifndef MS_OVERFLOW
+  // Nombre de ms indiquant un depassement de capacite d'un int64 lors du calcul
+  // de difference entre deux dates
+  #define MS_OVERFLOW	(int64FromHLPair(0x80000000, 0x0) - int64(1))
+#endif
+
+// 1970/01/01 at 0h
+#define REF_UNIX        int64FromHLPair(0x2ed263d, 0x83a88000)
+
+// Flags pour les noms de jours, mois et unit�s
+// - on a 4 combinaisons pour les jours/mois et 6 pour les unit�s avec le pluriel
+// - ABBR, LONG, LONGPL, OTHERS sont exclusifs ; on peut ajouter inter
+#define TM_ABBR     0 // pas vraiment utile
+#define TM_INTER    1 // international
+#define TM_LONG     2 // long
+#define TM_LONGPL   4 // long pluriel (pour les dur�es)
+#define TM_OTHERS   6 // autres abbr�viations autoris�es en parsing (s�par�es par |)
+#define TM_DEFAULT 16 // unit� par d�faut (pour les dur�es)
+
+// identifiant des unit�s dans le tableau
+#define TS_UNIT_SEC   0
+#define TS_UNIT_MIN   1
+#define TS_UNIT_HOUR  2
+#define TS_UNIT_DAY   3
+#define TS_UNIT_MONTH 4  // mois logique (=30 jours)
+#define TS_UNIT_YEAR  5  // ann�e logique (=12 mois logiques)
+
+// Month names
+static const pcsz s_pszMonth[] = 
+{
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+//=============================================================================
+/// Date exceptions
+///
+/// This class is designed to hold date exceptions
+//=============================================================================
+class DateException : public ExceptionBase
+{
+  const char *ErrorTitle()
+  {
+    return "Date class Error: ";
+  }
+public:
+  DateException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  ExceptionBase(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//============================================================================
+/// SDateFields
+/// Date splitted in fields
+//============================================================================
+struct SDateFields
+{
+  int iYear;
+  uint uiMonth;
+  uint uiDay;
+
+  uint uiHour;
+  uint uiMin;
+  double dSec;      // Seconds with microsec precision
+
+  int iDayOfYear;   // Day of year (1-366)
+  int iDayOfWeek;   // Day of week (1=lundi, 7=dimanche)
+  int iWeekOfYear;  // Week of year (1-53)
+
+  /// Clears all field
+  void Clear();
+
+  /// Accessor
+  int IsEmpty() const;
+};
+
+//===========================================================================
+/// The class CDate represents a specific instant in time, with 
+/// microsecond precision
+//===========================================================================
+class Date
+{
+private:
+  int64 m_llDate;   // Complete date with microsec precision
+
+  // For debugging purpose only
+  // NEVER USE THIS METHOD IN REAL CODE !!
+  void txt() const;
+
+public:
+  /// Constructors
+  Date() { m_llDate = 0; }
+
+  /// Constructor from fields
+  ///
+  /// @param iYear Year from -4712 to ?
+  /// @param uiMonth Month in range [1, 12]
+  /// @param uiDay Day in range [1, 31]
+  /// @param uiHour Hour in range [0, 23]
+  /// @param uiMin Minute in range [0, 59]
+  /// @param dSec Seconds in range [0, 59] with microsec precision
+  /// 
+  Date(int iYear, uint uiMonth, uint uiDay, uint uiHour=0, uint uiMin=0, double dSec=0)
+  { Set(iYear, uiMonth, uiDay, uiHour, uiMin, dSec); }
+
+  //-----------------------------------------------------------------
+  /// @name Accessors
+  //@{
+
+  /// Returns data internal value
+  int64 RawValue() const { return m_llDate; }
+  void SetRawValue(int64 i) { m_llDate = i; }
+
+  /// return 'true' if date is empty
+  bool IsEmpty() const { return m_llDate == 0; }
+
+  /// return 'true' if date is 1970/01/01 0h
+  int IsEmptyUnix() const { return REF_UNIX == m_llDate; }
+
+  /// Splittes date in fields
+  ///
+  /// @param pTm structure to fill in
+  ///
+  void Get(SDateFields *pTm) const;
+
+  /// Returns the microseconds part
+  long Micro() const;
+
+  /// Returns the milliseconds part
+  long Ms() const;
+
+  /// Returns the seconds part with microsecond precision
+  double Sec() const;
+
+  /// Returns the minutes part
+  uint Min() const;
+
+  /// Return the hour part
+  uint Hour() const;
+
+  /// Returns the Day part
+  uint Day() const;
+
+  /// Returns the hour part
+  uint Month() const;
+
+  /// Return the year part
+  int Year() const;
+
+  /// Returns the day number of the week, starting from monday (1) to sunday (7)
+  int DayOfWeek() const;
+
+  /// Returns the day number in the range [1, 366]
+  int DayOfYear() const;
+
+  /// Returns the week number in the range [1, 53]
+  int WeekOfYear() const;
+
+  /// Gets Julian day at 12h
+  long JulianDate() const;  // Jour julien de la date a 12h
+
+  /// Gets real Julian day with respect with time
+  double JulianDay() const;
+
+  //@} Accessors
+
+  //-----------------------------------------------------------------
+  /// @name Setting date
+  //@{
+
+  /// Empties Date
+  void SetEmpty() { m_llDate = 0; }
+
+  /// Empties Date in unix sense
+  void SetEmptyUnix() { m_llDate = REF_UNIX; }
+
+  /// Initialize date
+  ///
+  /// @param sTm structure containing splitted date
+  ///
+  void Set(const SDateFields& sTm);
+
+  /// Initializes date from explicit values
+  ///
+  /// @param iYear Year from -4712 to ?
+  /// @param uiMonth Month in range [1, 12]
+  /// @param uiDay Day in range [1, 31]
+  /// @param uiHour Hour in range [0, 23]
+  /// @param uiMin Minute in range [0, 59]
+  /// @param dSec Seconds in range [0, 59] with microsec precision
+  ///
+  void Set(int iYear, uint uiMonth, uint uiDay, 
+           uint uiHour=0, uint uiMin=0, double dSec=0);
+
+  // Fixe la partie date depuis le num�ro de jour dans l'ann�e / clear le time
+  void SetDayOfYear(int iDayOfYear, int iYear);
+
+  /// Sets the seconds part with microsecond precision
+  void SetSec(double dSec);
+
+  /// Sets the minute part
+  void SetMin(uint uiMin);
+
+  /// Sets the hour part
+  void SetHour(uint uiHour);
+
+  /// Sets the day part
+  void SetDay(uint uiDay);
+
+  /// Sets the month part
+  void SetMonth(uint uiMonth);
+
+  /// Sets the year part
+  void SetYear(int iYear);
+
+  /// Sets the Julian date
+  void SetJulianDate(long lJulianDate);
+
+  /// Sets the internal value
+  void Set(int64 ui64) { m_llDate = ui64; }
+
+  /// Clears the time part (hour, min, sec)
+  void ClearTime();
+
+  /// Clears the date part (year, month, day)
+  void ClearDate();
+  
+  /// Sets to current time
+  /// 
+  /// @param bUT if true sets to the universal time (UTC)
+  ///        otherwise sets to local time
+  void SetCurrent(bool bUT=false);
+
+  /// Convert from local time to universal time (UTC)
+  void LocalToUT();
+
+  /// Convert from universal time (UTC) to local time
+  void UTToLocal();
+
+  /// Adds seconds
+  void AddSec(double dSec) { m_llDate += int64(dSec * 1e6); }
+  void operator +=(double dSec) { AddSec(dSec); }
+  void operator -=(double dSec) { AddSec(-dSec); }
+  
+  //@}
+
+  //-----------------------------------------------------------------
+  /// @name Text methods
+  //@{
+
+  /// Gets date from a ISO8601 string
+  void FromISO8601(const char* pszISO8601);
+
+  /// Gets local time in ISO8601 format
+  String ToLocalISO8601() const;
+
+  /// Gets a ISO8601 string with milliseconds
+  String ToLocalISO8601ms() const;
+
+  /// Gets universal time in ISO8601 format
+  String ToISO8601() const;
+
+  /// Gets time with milliseconds in ISO8601 format
+  String ToISO8601ms() const;
+
+  /// Gets universal time with milliseconds in ISO8601 format
+  String ToISO8601msTU() const;
+
+  /// Gets a string in the international format
+  ///
+  /// @param bMillis with milliseconds if true
+  ///
+  String ToInter(bool bMillis=true) const;
+
+  //@} Text methods
+
+  //-----------------------------------------------------------------
+  /// @name UNIX reference
+  ///
+  /// @note UNIX dates start from 1970/01/01. So theses methods
+  /// are conveniance methods to set and get a number of seconds since
+  /// the UNIX reference
+  ///
+  //@{
+  
+  /// Gets a (integer) number of second since 1970/01/01 0h
+  long LongUnix() const;
+  /// Sets the date from a (integer) number of seconds since 1970/01/01 0h
+  void SetLongUnix(long lRefSec);
+  /// Gets a (double) number of seconds since 1970/01/01 0h with microseconds precision
+  double DoubleUnix() const;
+  /// Sets the date from a (double) number seconds since 1970/01/01 0h with microseconds precision
+  void SetDoubleUnix(double dRefSec);
+
+  //@} UNIX reference
+
+  //-----------------------------------------------------------------
+  /// @name Compare operators
+  //@{
+
+  int operator ==(const Date& tm) const
+    { return m_llDate == tm.m_llDate; }
+  int operator >(const Date& tm) const
+    { return m_llDate > tm.m_llDate; }
+  int operator >=(const Date& tm) const
+    { return m_llDate >= tm.m_llDate; }
+  int operator <(const Date& tm) const
+    { return m_llDate < tm.m_llDate; }
+  int operator <=(const Date& tm)  const
+    { return m_llDate <= tm.m_llDate; }
+  int operator !=(const Date& tm) const
+    { return m_llDate != tm.m_llDate; }
+
+  //@} Compare operators
+
+  //-----------------------------------------------------------------
+  /// @name Static methods
+  //@{
+
+  /// Number of days for a given month
+  static int NbDaysInMonth(int iMonth, int iYear);
+
+  /// Number of days in a given year
+  static int NbDaysInYear(int iYear);
+
+  /// Month name
+  static pcsz MonthName(int iMonth);
+
+  /// Unix time
+  static ulong UnixTime();
+
+  //@} Static methods
+
+};
+
+/// Create synonyme for convenience
+typedef Date Time;
+typedef Date CDate;
+
+//===========================================================================
+/// CCurrentDate is CDate initialized with current date and time
+//===========================================================================
+class CurrentDate : public Date
+{
+public:
+  /// Constructor
+  ///
+  /// @param bUT if true hte date is initialized with Universal Time instead of local time
+  ///
+  CurrentDate(bool bUT=false);
+};
+
+/// Create synonyme for convenience
+typedef CurrentDate CurrentTime;
+typedef CurrentDate CCurrentDate;
+
+//===========================================================================
+/// Date template evaluator
+///
+/// This class is a interface so it can't be directly instancied
+/// @see TemplateString
+//===========================================================================
+class DateVariableEvaluator : public IVariableEvaluator
+{
+private:
+  CDate m_tDate;
+  bool  m_bFixedDate;
+  bool  m_bUT;
+
+public:
+  /// Constructors
+  /// @param bFixedDate if true the date used for evaluations is never change
+  ///                   if false the evaluation is made using the current date
+  /// @param bUT        Use universal time instead of local time
+  DateVariableEvaluator(bool bFixedDate=true, bool bUT=false);
+  DateVariableEvaluator(const CDate &aDate);
+  
+  // Set a new date
+  void SetDate(const Date &aDate) { m_tDate = aDate; }
+
+  /// Attempts to evaluate a variable contained in this set :
+  /// __YEAR__, __DAY-OF-YEAR__, __MONTH__, __DAY__, __HOUR__, __MIN__, __SEC__
+  ///
+  /// @param pstrVar Variable to evaluate
+  /// @return true if evaluation is done, or false
+  virtual bool Evaluate(String *pstrVar);
+};
+
+typedef DateVariableEvaluator CDateVariableEvaluator;
+
+} // namespace soleil
+
+#endif
diff --git a/contrib/applications/NXextract/src/extractor.cpp b/contrib/applications/NXextract/src/extractor.cpp
new file mode 100644
index 0000000..10756b9
--- /dev/null
+++ b/contrib/applications/NXextract/src/extractor.cpp
@@ -0,0 +1,1875 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 20/07/2005
+// Author   : S. Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "file.h"
+#include "membuf.h"
+#include "nxfile.h"
+#include "variant.h"
+
+#ifdef __JPEG_SUPPORT__
+  #include "jpegwrap.h"
+#endif
+
+#include "bmp.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>  
+#include <vector>
+#include <cstring>
+#include <cstdlib>
+
+#include "nexusevaluator.h"
+#include "extractor.h"
+#include "templateparsor.h"
+
+using namespace gdshare;
+
+//-----------------------------------------------------------------------------
+// PrintFormat::PrintFormat
+//-----------------------------------------------------------------------------
+PrintFormat::PrintFormat()
+{
+  Init();
+}
+
+//-----------------------------------------------------------------------------
+// PrintFormat::PrintFormat
+//-----------------------------------------------------------------------------
+PrintFormat::PrintFormat(const String &strFormat)
+{
+  Init();
+  Set(strFormat);
+}
+
+//-----------------------------------------------------------------------------
+// PrintFormat::Set
+//-----------------------------------------------------------------------------
+void PrintFormat::Set(const String &strFormat)
+{
+  // First search for format type
+  int iTypePos = strFormat.find_first_of("cdieEfgGosuxXpn?");
+  if( string::npos == (uint)iTypePos )
+  {
+    cerr << "Error : bad format: '" << strFormat << "'; Exiting." << endl;
+  }
+  m_cType = strFormat[iTypePos];
+
+  int iWidthBegPos = 1;
+  int iWidthEndPos = iTypePos;
+
+  // Look for a modifier
+  if( strFormat.find_first_of("hlL", iTypePos - 1, 2) != string::npos )
+  {
+    m_cModifier = strFormat[iTypePos-1];
+    iWidthEndPos--;
+  }
+
+  // Look for precision
+  int iPrecisionPos = strFormat.find('.');
+  if( (uint)iPrecisionPos != string::npos && iPrecisionPos < iTypePos )
+  {
+    m_iPrecision = atoi(strFormat.substr(iPrecisionPos + 1, iTypePos - iPrecisionPos - 1).c_str());
+    iWidthEndPos = iPrecisionPos;
+  }
+
+  // Look for a flag
+  int iFlagPos = strFormat.find_first_of("-+ #");
+  if( 1 == iFlagPos )
+  {
+    m_cFlag = strFormat[1];
+    iWidthBegPos++;
+  }
+
+  // Width argument
+  m_strWidth = strFormat.substr(iWidthBegPos, iWidthEndPos - iWidthBegPos);
+
+  // Rest
+  m_strRest = strFormat.substr(iTypePos + 1);
+}
+
+//-----------------------------------------------------------------------------
+// PrintFormat::Get
+//-----------------------------------------------------------------------------
+String PrintFormat::Get()
+{
+  ostringstream ossFmt;
+  ossFmt << '%';
+  if( m_cFlag != -1 )
+    ossFmt << m_cFlag;
+  ossFmt << m_strWidth;
+  if( m_iPrecision != -1 )
+    ossFmt << '.' << m_iPrecision;
+  if( m_cModifier != -1 )
+    ossFmt << m_cModifier;
+  ossFmt << m_cType << m_strRest;
+  return ossFmt.str();
+}
+
+//-----------------------------------------------------------------------------
+// PrintFormat::GetNoRest
+//-----------------------------------------------------------------------------
+String PrintFormat::GetNoRest()
+{
+  ostringstream ossFmt;
+  ossFmt << '%';
+  if( m_cFlag != -1 )
+    ossFmt << m_cFlag;
+  ossFmt << m_strWidth;
+  if( m_iPrecision != -1 )
+    ossFmt << '.' << m_iPrecision;
+  if( m_cModifier != -1 )
+    ossFmt << m_cModifier;
+  ossFmt << m_cType;
+  return ossFmt.str();
+}
+
+//-----------------------------------------------------------------------------
+// DataBuf:SetTypeFromNeXusType
+//-----------------------------------------------------------------------------
+void DataBuf::SetTypeFromNeXusType(int iNxType)
+{
+  switch( iNxType )
+  {
+    case NX_UINT8:
+    case NX_INT8:
+      m_eType = DataBuf::BYTE;
+      m_uiTypeSize = 1;
+      break;
+    case NX_INT16:
+      m_eType = DataBuf::SHORT;
+      m_uiTypeSize = sizeof(short);
+      break;
+    case NX_UINT16:
+      m_eType = DataBuf::USHORT;
+      m_uiTypeSize = sizeof(unsigned short);
+      break;
+    case NX_INT32:
+      m_eType = DataBuf::LONG;
+      m_uiTypeSize = sizeof(long);
+      break;
+    case NX_UINT32:
+      m_eType = DataBuf::ULONG;
+      m_uiTypeSize = sizeof(unsigned long);
+      break;
+    case NX_FLOAT32:
+      m_eType = DataBuf::FLOAT;
+      m_uiTypeSize = sizeof(float);
+      break;
+    case NX_FLOAT64:
+      m_eType = DataBuf::DOUBLE;
+      m_uiTypeSize = sizeof(double);
+      break;
+    case NX_CHAR:
+      m_eType = DataBuf::CHAR;
+      m_uiTypeSize = 1;
+      break;
+    default:
+      m_eType = DataBuf::UNKNOWN;
+      m_uiTypeSize = 0;
+   }
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Extractor
+//-----------------------------------------------------------------------------
+Extractor::Extractor(const String &strNeXusFile, VecToken *pvecToken,
+                     IVariableEvaluator *pAppContext,
+                     const String &strMode, const String &strOwnership)
+          :m_vecToken(*pvecToken), m_strMode(strMode), m_strOwnership(strOwnership)
+{
+  m_bSilentMode = false;
+
+  // Default output stream is stdout
+  m_fiOut = NULL;
+
+  m_pNxEval = new NexusEvaluator(strNeXusFile, this);
+  m_TempParsor.AddEvaluator(this);
+  m_TempParsor.AddEvaluator(pAppContext);
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Extractor
+//-----------------------------------------------------------------------------
+Extractor::~Extractor()
+{
+  delete m_pNxEval;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Uid
+//-----------------------------------------------------------------------------
+uid_t Extractor::Uid()
+{
+  String strUser = m_strOwnership, strGroup;
+  strUser.ExtractTokenRight(':', &strGroup);
+  if( strUser.empty() )
+      return uid_t(-1);
+  return uid_t(atoi(PSZ(strUser)));
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Uid
+//-----------------------------------------------------------------------------
+gid_t Extractor::Gid()
+{
+  String strUser = m_strOwnership, strGroup;
+  strUser.ExtractTokenRight(':', &strGroup);
+  if( strGroup.empty() )
+      return gid_t(-1);
+  return gid_t(atoi(PSZ(strGroup)));
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ConvertBinaryValue
+//-----------------------------------------------------------------------------
+#define CASE(TDstName, TDST, TSRC) \
+        case TDstName: \
+        *(TDST*)(pDst) = (TDST)(*(TSRC*)(pSrc));\
+        return true;
+bool Extractor::ConvertBinaryValue(void *pSrc, DataBuf::Type eSrcType, void *pDst, TemplateToken::BinaryDataType eDstType)
+{
+  switch( eSrcType )
+  {
+    case DataBuf::BYTE:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::BYTE, uint8, uint8)
+        CASE(TemplateToken::SHORT, short, uint8)
+        CASE(TemplateToken::LONG, long, uint8)
+        CASE(TemplateToken::FLOAT, float, uint8)
+        CASE(TemplateToken::DOUBLE, double, uint8)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::SHORT:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::SHORT, short, short)
+        CASE(TemplateToken::LONG, long, short)
+        CASE(TemplateToken::FLOAT, float, short)
+        CASE(TemplateToken::DOUBLE, double, short)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::USHORT:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::SHORT, short, unsigned short)
+        CASE(TemplateToken::USHORT, unsigned short, unsigned short)
+        CASE(TemplateToken::LONG, long, unsigned short)
+        CASE(TemplateToken::FLOAT, float, unsigned short)
+        CASE(TemplateToken::DOUBLE, double, unsigned short)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::INT:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::SHORT, short, int)
+        CASE(TemplateToken::LONG, long, int)
+        CASE(TemplateToken::FLOAT, float, int)
+        CASE(TemplateToken::DOUBLE, double, int)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::LONG:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::LONG, long, long)
+        CASE(TemplateToken::FLOAT, float, long)
+        CASE(TemplateToken::DOUBLE, double, long)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::ULONG:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::LONG, long, unsigned long)
+        CASE(TemplateToken::FLOAT, float, unsigned long)
+        CASE(TemplateToken::DOUBLE, double, unsigned long)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::FLOAT:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::LONG, long, float)
+        CASE(TemplateToken::FLOAT, float, float)
+        CASE(TemplateToken::DOUBLE, double, float)
+        default:
+          return false;
+      }
+      break;
+    }
+    case DataBuf::DOUBLE:
+    {
+      switch( eDstType )
+      {
+        CASE(TemplateToken::LONG, long, double)
+        CASE(TemplateToken::FLOAT, float, double)
+        CASE(TemplateToken::DOUBLE, double, double)
+        default:
+          return false;
+      }
+      break;
+    }
+    default:
+      return false;
+  }
+  return false;
+}
+
+//------------------------------------------------------------------------
+// ExtractorApp::ConvertImageToByte
+//------------------------------------------------------------------------
+#define CONVERT_IMAGE_TO_BYTE(T, buf, buf_size)\
+{\
+  T MaxValue=T(0), MinValue=T(0);\
+  T *pInBuf = (T *)(buf);\
+  uint ui;\
+  for( ui = 0; ui < buf_size; ui++ )\
+  {\
+    if( 0 == ui )\
+    { \
+      MinValue = pInBuf[ui];\
+      MaxValue = pInBuf[ui];\
+    }\
+    else\
+    {\
+      if( MaxValue < pInBuf[ui] )\
+        MaxValue = pInBuf[ui];\
+      if( MinValue > pInBuf[ui] )\
+        MinValue = pInBuf[ui];\
+    }\
+  }\
+  double dRange = double(MaxValue - MinValue);\
+  uint8 uiVal;\
+  for( ui = 0; ui < buf_size; ui++ )\
+  {\
+    uiVal = uint8(((double)(pInBuf[ui] - MinValue) * 255.) / dRange);\
+    puiBuf[ui] = uiVal;\
+  }\
+}
+
+//------------------------------------------------------------------------
+// ExtractorApp::ConvertImageToByte
+//------------------------------------------------------------------------
+#define RAW_CONVERT_IMAGE_TO_BYTE(T, buf, buf_size)\
+{\
+  T *pInBuf = (T *)(buf);\
+  uint ui;\
+  for( ui = 0; ui < buf_size; ui++ )\
+  {\
+    if( pInBuf[ui] < 0 )\
+      puiBuf[ui] = 0;\
+    else if( pInBuf[ui] > 255 )\
+      puiBuf[ui] = 255;\
+    else\
+    puiBuf[ui] = (uint8)(pInBuf[ui]);\
+  }\
+}
+
+#ifdef __JPEG_SUPPORT__
+//------------------------------------------------------------------------
+// Extractor::ValueToJpeg
+//------------------------------------------------------------------------
+void Extractor::ValueToJpeg(DataBuf *pDataBuf, MemBufPtr ptrmbDest)
+{
+  // Allocate membuf with metadata capability
+  MemBufPtr ptrMemBuf(new CMemBuf);
+  uint8 *puiBuf = new uint8[pDataBuf->Len() / pDataBuf->TypeSize()];
+
+  // Converting data into 0..255 range
+  switch( pDataBuf->DataType() )
+  {
+    case DataBuf::FLOAT:
+      CONVERT_IMAGE_TO_BYTE(float, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::DOUBLE:
+      CONVERT_IMAGE_TO_BYTE(double, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::LONG:
+      CONVERT_IMAGE_TO_BYTE(long, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::ULONG:
+      CONVERT_IMAGE_TO_BYTE(ulong, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::SHORT:
+      CONVERT_IMAGE_TO_BYTE(short, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::USHORT:
+      CONVERT_IMAGE_TO_BYTE(ushort, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    default:
+      LogError("data", "Bad image datatype. Unable to convert");
+      break;   
+  } 
+
+  // Attach dataset buffer to our buffer to avoid a allocation and a copy
+  ptrMemBuf->Attach((char *)puiBuf, pDataBuf->Len() / pDataBuf->TypeSize(), false);
+
+  // Set metadata
+  ptrMemBuf->AddMetadata("width", pDataBuf->GetDimSize(0));
+  ptrMemBuf->AddMetadata("height", pDataBuf->GetDimSize(1));
+
+  // Invoke jpeg encoder
+  JpegEncoder::EncodeGrayScaleToMemBuf(ptrMemBuf, ptrmbDest);
+}
+#endif
+
+//------------------------------------------------------------------------
+// Extractor::ValueToBmp
+//------------------------------------------------------------------------
+void Extractor::ValueToBmp(DataBuf *pDataBuf, MemBufPtr ptrmbDest)
+{
+  // Allocate membuf with metadata capability
+  MemBufPtr ptrMemBuf(new CMemBuf);
+  uint8 *puiBuf = new uint8[pDataBuf->Len() / pDataBuf->TypeSize()];
+
+  // Converting data into 0..255 range
+  switch( pDataBuf->DataType() )
+  {
+    case DataBuf::FLOAT:
+      RAW_CONVERT_IMAGE_TO_BYTE(float, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::DOUBLE:
+      RAW_CONVERT_IMAGE_TO_BYTE(double, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::LONG:
+      RAW_CONVERT_IMAGE_TO_BYTE(long, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::ULONG:
+      RAW_CONVERT_IMAGE_TO_BYTE(ulong, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::SHORT:
+      RAW_CONVERT_IMAGE_TO_BYTE(short, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    case DataBuf::USHORT:
+      RAW_CONVERT_IMAGE_TO_BYTE(ushort, pDataBuf->Buf(), pDataBuf->Len() / pDataBuf->TypeSize());
+      break;
+    default:
+      LogError("data", "Bad image datatype. Unable to convert");
+      break;   
+  } 
+
+  // Attach dataset buffer to our buffer to avoid a allocation and a copy
+  ptrMemBuf->Attach((char *)puiBuf, pDataBuf->Len() / pDataBuf->TypeSize(), false);
+
+  // Set metadata
+  ptrMemBuf->AddMetadata("width", pDataBuf->GetDimSize(0));
+  ptrMemBuf->AddMetadata("height", pDataBuf->GetDimSize(1));
+
+  // Invoke bmp encoder
+  BmpEncoder::EncodeGrayScaleToMemBuf(ptrMemBuf, ptrmbDest);
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ValueToInteger
+//-----------------------------------------------------------------------------
+int Extractor::ValueToInteger()
+{
+  switch( m_aValue.DataType() )
+  {
+    case DataBuf::BYTE:
+      return int(*((uint8 *)(m_aValue.Buf())));
+    case DataBuf::UBYTE:
+      return int(*((uint8 *)(m_aValue.Buf())));
+    case DataBuf::CHAR:
+      return 0;
+    case DataBuf::SHORT:
+      return int(*((short *)(m_aValue.Buf())));
+    case DataBuf::USHORT:
+      return int(*((short *)(m_aValue.Buf())));
+    case DataBuf::LONG:
+      return int(*((long *)(m_aValue.Buf())));
+    case DataBuf::ULONG:
+      return int(*((long *)(m_aValue.Buf())));
+    case DataBuf::INT:
+      return int(*((int *)(m_aValue.Buf())));
+    case DataBuf::FLOAT:
+      return int(*((float *)(m_aValue.Buf())));
+    case DataBuf::DOUBLE:
+      return int(*((double *)(m_aValue.Buf())));
+    case DataBuf::NO_TYPE:
+    case DataBuf::UNKNOWN:
+      break;
+  }
+  return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ValueToString
+//-----------------------------------------------------------------------------
+String Extractor::ValueToString(DataBuf &aValue)
+{
+  String strValue;
+  switch( aValue.DataType() )
+  {
+    case DataBuf::BYTE:
+      strValue.Printf("%d", int(*((uint8 *)(aValue.Buf()))));
+      break;
+    case DataBuf::UBYTE:
+      strValue.Printf("%d", (*((uint8 *)(aValue.Buf()))));
+      break;
+    case DataBuf::CHAR:
+      strValue.Printf("%s", m_aValue.Buf());
+      break;
+    case DataBuf::SHORT:
+      strValue.Printf("%h", (*((short *)(aValue.Buf()))));
+      break;
+    case DataBuf::USHORT:
+      strValue.Printf("%h", (*((unsigned short *)(aValue.Buf()))));
+      break;
+    case DataBuf::LONG:
+      strValue.Printf("%ld", (*((long *)(aValue.Buf()))));
+      break;
+    case DataBuf::ULONG:
+      strValue.Printf("%ld", (*((unsigned long *)(aValue.Buf()))));
+      break;
+    case DataBuf::INT:
+      strValue.Printf("%d", (*((int *)(aValue.Buf()))));
+      break;
+    case DataBuf::FLOAT:
+      strValue.Printf("%g", (*((float *)(aValue.Buf()))));
+      break;
+    case DataBuf::DOUBLE:
+      strValue.Printf("%g", (*((double *)(aValue.Buf()))));
+      break;
+    case DataBuf::NO_TYPE:
+    case DataBuf::UNKNOWN:
+      break;
+  }
+  return strValue;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecLoopOver
+//-----------------------------------------------------------------------------
+int Extractor::ExecLoopOver(int iCurrentPos)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+
+  String strCollection = Token.m_strParam2;
+  m_TempParsor.ProcessNoRecursion(&strCollection);
+  ItemList *pList = NULL;
+  ItemList *pCachedList = NULL;
+  ItemList lstItems;
+
+  if( strCollection.StartWith("nxs:") )
+    // NeXus collection
+    pCachedList = m_pNxEval->GetItemsList(&strCollection, Token.m_strParam1);
+  else
+  {
+    // The collection is a variable containing a list of value with '|' as separator
+    m_TempParsor.ProcessNoRecursion(&strCollection);
+    String strItem;
+    while( !strCollection.empty() )
+    {
+      strCollection.ExtractToken('|', &strItem);
+      lstItems.push_back(NxItem(strItem, strItem));
+    }
+  }
+
+  if( pCachedList )
+    pList = pCachedList;
+  else
+    pList = &lstItems;
+
+  // First variable name is whoise indicated in script
+  // Second (and implicite) variable is the same followed by "_name"
+  String strName = Token.m_strParam1 + "_name";
+
+  ItemList::iterator it = pList->begin();
+  // Loop over list items pairs
+  for(; it != pList->end(); it++)
+  {
+    String strValue = (*it).first;
+    m_dictVar[strName] = strValue;
+    if( !(*it).second.empty() )
+    {
+      String strValue = (*it).second;
+      m_dictVar[Token.m_strParam1] = strValue;
+    }
+    Exec(iCurrentPos+1, Token.m_iEndBlockPos+1);
+  }
+
+  // Return next token pos
+  return Token.m_iEndBlockPos;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecBlock
+//-----------------------------------------------------------------------------
+int Extractor::ExecBlock(int iCurrentPos)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+  String strLimit = Token.m_strParam2;
+  m_TempParsor.ProcessNoRecursion(&strLimit);
+
+  // Get parameters
+  String strBlockName = Token.m_strParam1;
+  uint uiMaxSize = (uint)atoi(PSZ(strLimit));
+  
+  // Get Membuf
+  MemBufPtr ptrBuf = GetBuf(strBlockName);
+  ptrBuf->Reset();
+
+  // Push new output object
+  MemBufOutput *pOutBuf = new MemBufOutput(ptrBuf);
+  m_stkOut.push(pOutBuf);
+
+  Exec(iCurrentPos+1, Token.m_iEndBlockPos+1);
+
+  // Check buffer size
+  if( uiMaxSize != 0 )
+  {
+    if( uiMaxSize < ptrBuf->Len() )
+      // Buffer size exceed limit, cut !
+      ptrBuf->SetLen(uiMaxSize);
+    
+    if( uiMaxSize > ptrBuf->Len() )
+    {
+      // Padding
+      int iInsertPos = pOutBuf->PaddingPos() == -1 ? ptrBuf->Len() : pOutBuf->PaddingPos();
+      while( uiMaxSize - ptrBuf->Len() >= pOutBuf->PaddingPattern().size() )
+      {
+        ptrBuf->InsertBloc(PSZ(pOutBuf->PaddingPattern()), pOutBuf->PaddingPattern().size(), iInsertPos);
+        iInsertPos += pOutBuf->PaddingPattern().size();
+      }
+
+      if( uiMaxSize > ptrBuf->Len() )
+        ptrBuf->InsertBloc(PSZ(pOutBuf->PaddingPattern()), uiMaxSize - ptrBuf->Len(), iInsertPos);
+    }
+  }
+
+  // Remove output object
+  m_stkOut.pop();
+
+  // Make new variables with bloc name and size
+  String strVar = strBlockName + "_size";
+  String strSize;
+  strSize.Printf("%d", ptrBuf->Len());
+  m_dictVar[strVar] = strSize;
+  m_dictVar[strBlockName] = String(ptrBuf->Buf(), ptrBuf->Len());
+
+  // Return next token pos
+  return Token.m_iEndBlockPos;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecPadding
+//-----------------------------------------------------------------------------
+void Extractor::ExecPadding(int iCurrentPos)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+  // Check Output object type
+  MemBufOutput *pBufOutput = dynamic_cast<MemBufOutput *>(m_stkOut.top().ObjectPtr());
+  if( !pBufOutput )
+  {
+    cerr << "Padding don't make sense in the current context (at line " << Token.m_iTemplateLine << ")." << endl;
+  }
+
+  // Store current buffer position for padding and pattern
+  pBufOutput->SetPaddingPattern(Token.m_strParam1);
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::OutBinaryScalarFromString
+//-----------------------------------------------------------------------------
+void Extractor::OutBinaryScalarFromString(const TemplateToken &Token, const String &strData)
+{
+  int iBase = 10;
+  if( strData.StartWith("0x") )
+    iBase = 16;
+
+  switch( Token.m_eBinaryDataType )
+  {
+    case TemplateToken::CHAR:
+    {
+      char c = strData[0];
+      m_stkOut.top()->Out(NULL, c);
+      break;
+    }
+    case TemplateToken::BYTE:
+    {
+      uint8 ui8 = strtol(PSZ(strData), (char **)NULL, iBase);
+      m_stkOut.top()->Out(NULL, ui8);
+      break;
+    }
+    case TemplateToken::SHORT:
+    {
+      short s = strtol(PSZ(strData), (char **)NULL, iBase);
+      m_stkOut.top()->Out(NULL, s);
+      break;
+    }
+    case TemplateToken::LONG:
+    {
+      long l = strtol(PSZ(strData), (char **)NULL, iBase);
+      m_stkOut.top()->Out(NULL, l);
+      break;
+    }
+    case TemplateToken::FLOAT:
+    {
+      float f = atof(PSZ(strData));
+      m_stkOut.top()->Out(NULL, f);
+      break;
+    }
+    case TemplateToken::DOUBLE:
+    {
+      double d = atof(PSZ(strData));
+      m_stkOut.top()->Out(NULL, d);
+      break;
+    }
+    case TemplateToken::RAW:
+    {
+      // Search for buffer
+      MemBufPtr ptrBuf = GetBuf(strData, false);
+      if( ptrBuf.IsNull() )
+      {
+        cerr << "Error : bloc '" << strData << "' not found; Exiting." << endl;
+      }
+      m_stkOut.top()->Out((void *)ptrBuf->Buf(), ptrBuf->Len());
+      break;  
+    }
+    default:
+      cerr << "Error: bad syntax at line " << Token.m_iTemplateLine << " : bloc '" << strData << "' not found; Exiting." << endl;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecBinary
+//-----------------------------------------------------------------------------
+void Extractor::ExecBinary(int iCurrentPos)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+
+  // Evaluate target
+  String strData = GetTokenArgument(&Token);
+
+  // Evaluate data by NeXus evaluator
+  bool bEvaluation = m_pNxEval->Evaluate(strData, &m_aValue);
+  if( bEvaluation )
+  {
+    if( TemplateToken::RAW == Token.m_eBinaryDataType )
+      // Raw data type => just push value content to output buffer
+      m_stkOut.top()->Out((void *)m_aValue.Buf(), m_aValue.Len());
+
+#ifdef __JPEG_SUPPORT__
+    else if( TemplateToken::JPEG_IMAGE == Token.m_eBinaryDataType )
+    {
+      // Write a jpeg image
+      MemBufPtr ptrMemBuf(new CMemBuf);
+      try
+      {
+        ValueToJpeg(&m_aValue, ptrMemBuf);
+        m_stkOut.top()->Out((void *)ptrMemBuf->Buf(), ptrMemBuf->Len());
+      }
+      catch( JpegEncoder::Exception e )
+      {
+        cerr << e.Message();
+      }
+    }
+#endif
+
+    else if( TemplateToken::BMP_IMAGE == Token.m_eBinaryDataType )
+    {
+      // Write a bmp image
+      MemBufPtr ptrMemBuf(new CMemBuf);
+      try
+      {
+        ValueToBmp(&m_aValue, ptrMemBuf);
+        m_stkOut.top()->Out((void *)ptrMemBuf->Buf(), ptrMemBuf->Len());
+      }
+      catch( BmpEncoder::Exception e )
+      {
+        cerr << e.Message();
+      }
+    }
+    else
+    {
+      // Convert buffer to asked type
+      CMemBuf mbDst;
+      // Pre-allocation
+      mbDst.SetLen(Token.m_uiTypeSize * m_aValue.Len() / m_aValue.TypeSize());
+    
+      // Get pointers to data
+      char *pDst = mbDst.Buf();
+      char *pSrc = (char *)m_aValue.Buf();
+
+      bool bConverted = true;
+
+      if( m_aValue.DataType() == Token.m_eBinaryDataType )
+        // no conversion
+        mbDst.Attach(pSrc, mbDst.Len());
+      else
+      { // conversion needed
+        for( pSrc = (char *)m_aValue.Buf(); pSrc < (char *)m_aValue.Buf() + m_aValue.Len() && bConverted; 
+             pSrc += m_aValue.TypeSize(), pDst += Token.m_uiTypeSize )
+        {
+          bConverted = ConvertBinaryValue(pSrc, m_aValue.DataType(), pDst, Token.m_eBinaryDataType);
+        }
+      }
+
+      if( !bConverted )
+      {
+        cerr << "Error: conversion not possible at line " << Token.m_iTemplateLine << ". Extraction aborted." << endl;
+      }
+      m_stkOut.top()->Out((void *)mbDst.Buf(), mbDst.Len());
+    }
+  }
+  else 
+    OutBinaryScalarFromString(Token, strData);    
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecComp
+//-----------------------------------------------------------------------------
+int Extractor::ExecComp(int iCurrentPos, bool bInf, bool bNot)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+
+  DataBuf aValue1, aValue2;
+  String strParam1 = Token.m_strParam1;
+  m_TempParsor.ProcessNoRecursion(&strParam1);
+  if( m_pNxEval->Evaluate(strParam1, &aValue1) )
+    strParam1 = ValueToString(aValue1);
+  String strParam2 = Token.m_strParam2;
+  m_TempParsor.ProcessNoRecursion(&strParam2);
+  if( m_pNxEval->Evaluate(strParam2, &aValue2) )
+    strParam2 = ValueToString(aValue2);
+
+  bool bComp = false;
+  if( !bInf )
+    bComp = atoi(PSZ(strParam1)) > atoi(PSZ(strParam2));
+  else
+    bComp = atoi(PSZ(strParam1)) < atoi(PSZ(strParam2));
+
+  if( (bComp && !bNot) || (!bComp && bNot ) )
+    // Condition is satisfyed
+    Exec(iCurrentPos+1, Token.m_iEndBlockPos+1);
+
+  // Return next token pos
+  return Token.m_iEndBlockPos;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecIfEq
+//-----------------------------------------------------------------------------
+int Extractor::ExecIfEq(int iCurrentPos, bool bNot)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+
+  DataBuf aValue1, aValue2;
+  String strParam1 = Token.m_strParam1;
+  m_TempParsor.ProcessNoRecursion(&strParam1);
+  if( m_pNxEval->Evaluate(strParam1, &aValue1) )
+    strParam1 = ValueToString(aValue1);
+  String strParam2 = Token.m_strParam2;
+  m_TempParsor.ProcessNoRecursion(&strParam2);
+  if( m_pNxEval->Evaluate(strParam2, &aValue2) )
+    strParam2 = ValueToString(aValue2);
+
+  bool bCond = strParam1.Match(PSZ(strParam2));
+  if( (bCond && !bNot) || (!bCond && bNot ) )
+    // Condition is satisfyed
+    Exec(iCurrentPos+1, Token.m_iEndBlockPos+1);
+
+  // Return next token pos
+  return Token.m_iEndBlockPos;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecIfExists
+//-----------------------------------------------------------------------------
+int Extractor::ExecIfExists(int iCurrentPos)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+  bool bExists = false;
+  if( !Token.m_strData.empty() )
+  {
+    String strItemPath = Token.m_strData;
+    m_TempParsor.ProcessNoRecursion(&strItemPath);
+    bExists = m_pNxEval->CheckItem(strItemPath);
+  }
+  else // Check for variable
+    bExists = (m_dictVar.find(Token.m_strParam1) != m_dictVar.end());
+
+  if( bExists )
+    Exec(iCurrentPos+1, Token.m_iEndBlockPos+1);
+
+  // Return next token pos
+  return Token.m_iEndBlockPos;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecSet
+//-----------------------------------------------------------------------------
+void Extractor::ExecSet(int iCurrentPos)
+{
+  TokenSet &Token = *((TokenSet *)(m_vecToken[iCurrentPos].ObjectPtr()));
+  String strValue = Token.m_strParam2;
+  if( Token.m_bEvalArgument )
+    m_TempParsor.Process(&strValue);
+  m_dictVar[Token.m_strParam1] = strValue;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecSetList
+//-----------------------------------------------------------------------------
+void Extractor::ExecSetList(int iCurrentPos)
+{
+  TokenSet &Token = *((TokenSet *)(m_vecToken[iCurrentPos].ObjectPtr()));
+  String strCollection = Token.m_strParam2;
+  m_TempParsor.ProcessNoRecursion(&strCollection);
+  ItemList *pList = NULL;
+  ItemList *pCachedList=NULL;
+  ItemList lstItems;
+  bool bNexusItem = false;
+
+  if( strCollection.StartWith("nxs:") )
+  {
+    // NeXus collection
+    pList = m_pNxEval->GetItemsList(&strCollection, Token.m_strParam1);
+    bNexusItem = true;
+  }
+
+  String strValueList;
+  ItemList::iterator it = pList->begin();
+  // Loop over list items pairs
+  for(; it != pList->end(); it++)
+  {
+    String strValue = (*it).first;
+    if( !(*it).second.empty() )
+    {
+      if( !strValueList.empty() )
+        strValueList += "|";  // List separator
+      if( !Token.m_strParam3.empty() && bNexusItem )
+      {
+        // Value to be evaluated
+        String strToEvaluate = "nxs:" + (*it).second + Token.m_strParam3;
+        m_pNxEval->Evaluate(strToEvaluate, &m_aValue);
+        strValueList += ScalarValueToString();
+
+      }
+      else
+        strValueList += (*it).second;
+    }
+  }
+
+  m_dictVar[Token.m_strParam1] = strValueList;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecLoop
+//-----------------------------------------------------------------------------
+int Extractor::ExecLoop(int iCurrentPos)
+{
+  TemplateToken &Token = *(m_vecToken[iCurrentPos]);
+  TokenLoop *pToken = dynamic_cast<TokenLoop *>(&Token);
+  Expression::s_pValueEval = this;
+
+  int iInit = pToken->ptrExprBegin->Eval();
+  int iEnd = pToken->ptrExprEnd->Eval();
+  int iStep = 1;
+  if( iInit > iEnd )
+    iStep = -1;
+  if( !pToken->ptrExprStep.IsNull() )
+    iStep = pToken->ptrExprStep->Eval();
+
+  // Add counter
+  pair<MapCounters::iterator, bool> 
+    prItBool = m_dictCounters.insert(MapCounters::value_type(Token.m_strParam1, 0));
+
+  if( iInit < iEnd )
+    for(int i = iInit; i < iEnd; i += iStep)
+    {
+      (prItBool.first)->second = i;              // Update counter value
+      Exec(iCurrentPos+1, Token.m_iEndBlockPos+1); // Execute code until next end-loop
+    }
+  else
+    for(int i = iInit; i > iEnd; i += iStep)
+    {
+      (prItBool.first)->second = i;              // Update counter value
+      Exec(iCurrentPos+1, Token.m_iEndBlockPos+1); // Execute code until next end-loop
+    }
+
+  // Remove counter
+  m_dictCounters.erase(prItBool.first);
+  // Return next token pos
+  return Token.m_iEndBlockPos;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::GetTokenArgument
+//-----------------------------------------------------------------------------
+String Extractor::GetTokenArgument(TemplateToken *pToken)
+{
+  String strTxt = pToken->m_strData;
+  if( strTxt.empty() )
+  {
+    strTxt.reserve(256);
+    // Build request from fragments
+    for( DataFragmentsList::const_iterator it = pToken->lstDataFragments.begin();
+         it != pToken->lstDataFragments.end(); it++ )
+    {
+      if( DataFragment::TEXT == it->Type() )
+        // Text fragment
+        strTxt += it->Content();
+      else
+      { // Fragment is a variable name to replace with its current value
+        String strVar = it->Content();
+        Evaluate(&strVar);
+        strTxt += strVar;
+      }
+    }
+  }
+  return strTxt;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ExecPrintData
+//-----------------------------------------------------------------------------
+void Extractor::ExecPrintData(TemplateToken *pToken)
+{
+  String strData = GetTokenArgument(pToken);
+  try
+  {
+    bool bEvaluation = m_pNxEval->Evaluate(strData, &m_aValue);
+    if( bEvaluation )
+      PrintData(pToken);
+    else
+    {
+      switch( pToken->m_Format.Type() )
+      {
+        case 'd':
+          m_stkOut.top()->Out(PSZ(pToken->m_Format.Get()), atol(PSZ(strData)));
+          break;
+        case 'f':
+        case 'e':
+        case 'g':
+          m_stkOut.top()->Out(PSZ(pToken->m_Format.Get()), atof(PSZ(strData)));
+          break;
+        default:
+          m_stkOut.top()->Out(PSZ(pToken->m_Format.Get()), PSZ(strData));
+      }
+    }
+  }
+  catch(...)
+  {
+    m_stkOut.top()->Out("%s", PSZ(strData));
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Execute
+//-----------------------------------------------------------------------------
+void Extractor::Execute()
+{
+  m_stkOut.push(new StandardOutput);
+  Exec(0, m_vecToken.size());
+  SetOutputFile(g_strEmpty, false); // To set properties and close current file
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Exec
+//-----------------------------------------------------------------------------
+void Extractor::Exec(int iStartPos, int iEndPos)
+{
+  TemplateToken *pToken = NULL;
+  
+  for(int iPos = iStartPos; iPos < iEndPos; iPos++ )
+  {
+    pToken = m_vecToken[iPos];
+
+    switch( pToken->m_TokenType )
+    {
+      case TemplateToken::PRINT_DATA:
+        ExecPrintData(pToken);
+        break;
+
+      case TemplateToken::PRINT_TEXT:
+      {
+        String strTxt = pToken->m_strData;
+        m_TempParsor.Process(&strTxt, false);
+        m_stkOut.top()->Out("%s", PSZ(strTxt));
+        break;
+      }
+      case TemplateToken::LOOP:
+        iPos = ExecLoop(iPos);
+        break;
+
+      case TemplateToken::LOOP_OVER:
+        iPos = ExecLoopOver(iPos);
+        break;
+
+      case TemplateToken::BINARY:
+        ExecBinary(iPos);
+        break;
+
+      case TemplateToken::BLOCK_START:
+        iPos = ExecBlock(iPos);
+        break;
+
+      case TemplateToken::IF_EXISTS:
+        iPos = ExecIfExists(iPos);
+        break;
+
+      case TemplateToken::IF_SUP:
+        iPos = ExecComp(iPos, false, false);
+        break;
+
+      case TemplateToken::IF_INF:
+        iPos = ExecComp(iPos, true, false);
+        break;
+
+      case TemplateToken::IF_EQ:
+        iPos = ExecIfEq(iPos, false);
+        break;
+
+      case TemplateToken::IF_NOT_EQ:
+        iPos = ExecIfEq(iPos, true);
+        break;
+
+      case TemplateToken::SET:
+        ExecSet(iPos);
+        break;
+
+      case TemplateToken::SET_LIST:
+        ExecSetList(iPos);
+        break;
+
+      case TemplateToken::OUTPUT:
+      {
+        String strFile = pToken->m_strParam1;
+        m_TempParsor.Process(&strFile);
+        SetOutputFile(strFile, pToken->m_iParam1 ? true : false);
+        break;
+      }
+
+      case TemplateToken::PADDING:
+        ExecPadding(iPos);
+        break;
+
+      case TemplateToken::END_LOOP:
+      case TemplateToken::BLOCK_END:
+      case TemplateToken::END_IF:
+      default:
+        break;
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::SetOutputFile
+//-----------------------------------------------------------------------------
+void Extractor::SetOutputFile(const String &strFile, bool bBinary)
+{
+  if( m_fiOut != NULL )
+  {
+    if( m_stkOut.size() > 1 )
+      m_stkOut.pop();
+    fclose(m_fiOut);
+  }
+
+  if( !m_strCurrentFile.empty() )
+  {
+    // Set file ownership and access mode
+#ifdef __LINUX__
+    if( !m_strMode.empty() )
+      chmod(PSZ(m_strCurrentFile), AccessFromString(m_strMode));
+    chown(PSZ(m_strCurrentFile), Uid(), Gid());
+#endif
+    m_strCurrentFile = strFile;
+  }
+
+  if( strFile.empty() )
+  {
+    // Output stream redirection on console
+#ifdef __WIN32__
+    freopen_s(&m_fiOut, "CON", "w", stdout);
+#else // UNIX
+    m_fiOut = freopen("/dev/tty", "w", stdout);
+#endif
+    return;
+  }
+
+  m_strCurrentFile = strFile;
+
+  // Replace blank characters to avoid problems
+  m_strCurrentFile.Replace(' ', '_');
+
+  // Create folder tree, with correct rights
+  FileName fn(m_strCurrentFile);
+
+  long lMode = 0;
+  if( !m_strMode.empty() )
+    // Allow directory access for everyone
+    lMode = atoi(PSZ(m_strMode)) + 111;
+
+  fn.MkDir(AccessFromString(StrFormat("%d", lMode)), Uid(), Gid());
+
+  if( !bBinary )
+    // Output stream redirection
+#ifdef __WIN32__
+    freopen_s(&m_fiOut, PSZ(m_strCurrentFile), "w", stdout);
+#else // UNIX
+    m_fiOut = freopen(PSZ(m_strCurrentFile), "w", stdout);
+#endif
+  else
+  {
+    // Open binary file
+#ifdef __WIN32__
+    fopen_s(&m_fiOut, PSZ(m_strCurrentFile), "wb");
+#else // UNIX
+    m_fiOut = fopen(PSZ(m_strCurrentFile), "wb");
+#endif
+    BinaryFileOutput *pOut = new BinaryFileOutput(m_fiOut);
+    m_stkOut.push(pOut);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::AddVar
+//-----------------------------------------------------------------------------
+void Extractor::AddVar(const String &strVar, const String &strVal)
+{
+  // add the string strVar to our dict with the value strVal.
+  m_dictVar.insert(StringDict::value_type(strVar, strVal));
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::SetVar
+//-----------------------------------------------------------------------------
+void Extractor::SetVar(const String &strVar, const String &strVal)
+{
+  // Search variable
+  StringDict::iterator it = m_dictVar.find(strVar);
+  if( it != m_dictVar.end())
+    (it->second) = strVal;
+  else 
+    m_dictVar.insert(StringDict::value_type(strVar, strVal));
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::HasVar
+//-----------------------------------------------------------------------------
+bool Extractor::HasVar(const String &strVar)
+{
+  // Search variable
+  StringDict::iterator it = m_dictVar.find(strVar);
+  if( it != m_dictVar.end() )
+    return true;
+  else 
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::RemoveVar
+//-----------------------------------------------------------------------------
+void Extractor::RemoveVar(const String &strVar)
+{
+  // we remove the string var from our dict.
+  m_dictVar.erase(strVar);
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Evalutate
+//-----------------------------------------------------------------------------
+bool Extractor::Evaluate(String *pstrVar)
+{ 
+  // To preserve performance, use pointer to avoid useless allocation of a big object
+  String *pstrDefValue = NULL;
+  if( pstrVar->find('=') != string::npos )
+  {
+    // Use def value if variable is not found
+    pstrDefValue = new String;
+    pstrVar->ExtractTokenRight('=', pstrDefValue);
+  }
+
+  // evalute a variable by giving its value stocked in the dict.
+  StringDict::iterator it = m_dictVar.find(*pstrVar);
+  if( it != m_dictVar.end())
+  {
+    *pstrVar=(it->second);
+    return true;
+  }
+  // Search in counters
+  MapCounters::const_iterator it2 = m_dictCounters.find(*pstrVar);
+  if( it2 != m_dictCounters.end())
+  {
+    (*pstrVar).Printf("%d", (it2->second));
+    return true;
+  }
+
+  if( pstrDefValue )
+  {
+    // Apply default value
+    *pstrVar = *pstrDefValue;
+    delete pstrDefValue;
+    return true;
+  }
+
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::GetBuf
+//-----------------------------------------------------------------------------
+MemBufPtr Extractor::GetBuf(const String &strName, bool bCreate)
+{
+  MapBufPtr::iterator it = m_dictBuf.find(strName);
+  if( it != m_dictBuf.end() )
+    // found
+    return it->second;
+
+  // Create new buffer
+  if( bCreate )
+  {
+    MemBufPtr ptrBuf(new CMemBuf);
+    m_dictBuf[strName] = ptrBuf;
+    return ptrBuf;
+  }
+  
+  return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::ScalarValueToString
+//-----------------------------------------------------------------------------
+String Extractor::ScalarValueToString()
+{
+  String strValue;
+  switch( m_aValue.DataType() )
+  {
+    // if we have a string format.
+    case DataBuf::CHAR:
+      strValue.append((char *)m_aValue.Buf(), m_aValue.Len());
+      break;
+    // the case of int,long,unsigned char or short.
+    case DataBuf::BYTE:
+      strValue.Printf("%d", *((uint8 *)m_aValue.Buf()));
+      break;
+    case DataBuf::SHORT:
+      strValue.Printf("%h", *((short *)m_aValue.Buf()));
+      break;
+    case DataBuf::USHORT:
+      strValue.Printf("%hu", *((unsigned short *)m_aValue.Buf()));
+      break;
+    case DataBuf::LONG:
+      strValue.Printf("%ld", *((long *)m_aValue.Buf()));
+      break;
+    case DataBuf::INT:
+      strValue.Printf("%ld", *((int *)m_aValue.Buf()));
+      break;
+    case DataBuf::ULONG:
+      strValue.Printf("%lu", *((unsigned long *)m_aValue.Buf()));
+      break;
+    case DataBuf::FLOAT:
+      strValue.Printf("%g", *((float *)m_aValue.Buf()));
+      break;
+    case DataBuf::DOUBLE:
+      strValue.Printf("%lg", *((double *)m_aValue.Buf()));
+      break;
+    default:
+      break;
+  }
+  return strValue;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::PrintData
+//-----------------------------------------------------------------------------
+void Extractor::PrintData(TemplateToken *pToken)
+{
+  // Check format
+  if( m_aValue.DataType() != pToken->m_eOutputType )
+  {
+    ostringstream ossWarn;
+    ossWarn << "Warning: Mismatching format types at line " <<
+                pToken->m_iTemplateLine << ". Format " << pToken->m_Format.GetNoRest();
+    // Set the right type according to the value to be printed
+    switch( m_aValue.DataType() )
+    {
+      // if we have a string format.
+      case DataBuf::CHAR:
+        pToken->m_Format.SetType('s');
+        pToken->m_eOutputType = DataBuf::CHAR;
+        break;
+        // the case of int,long,unsigned char or short.
+      case DataBuf::BYTE:
+        pToken->m_Format.SetType('d');
+        pToken->m_Format.SetModifier('h');
+        pToken->m_eOutputType = DataBuf::BYTE;
+        break;
+      case DataBuf::SHORT:
+        pToken->m_Format.SetType('d');
+        pToken->m_Format.SetModifier('h');
+        pToken->m_eOutputType = DataBuf::SHORT;
+        break;
+      case DataBuf::USHORT:
+        pToken->m_Format.SetType('d');
+        pToken->m_Format.SetModifier('h');
+        pToken->m_eOutputType = DataBuf::USHORT;
+        break;
+      case DataBuf::LONG:
+        pToken->m_Format.SetType('d');
+        pToken->m_Format.SetModifier('l');
+        pToken->m_eOutputType = DataBuf::LONG;
+        break;
+      case DataBuf::ULONG:
+        pToken->m_Format.SetType('d');
+        pToken->m_Format.SetModifier('l');
+        pToken->m_eOutputType = DataBuf::ULONG;
+        break;
+     case DataBuf::INT:
+        pToken->m_Format.SetType('d');
+        pToken->m_eOutputType = DataBuf::INT;
+        break;
+      case DataBuf::FLOAT:
+      {
+        if( pToken->m_eOutputType != DataBuf::FLOAT &&
+            pToken->m_eOutputType != DataBuf::DOUBLE)
+          pToken->m_Format.SetType('f');
+        pToken->m_Format.SetModifier(-1);
+        pToken->m_eOutputType = DataBuf::FLOAT;
+        break;
+      }
+      case DataBuf::DOUBLE:
+      {
+        if( pToken->m_eOutputType != DataBuf::FLOAT &&
+            pToken->m_eOutputType != DataBuf::DOUBLE)
+          pToken->m_Format.SetType('f');
+        pToken->m_Format.SetModifier('l');
+        pToken->m_eOutputType = DataBuf::DOUBLE;
+        break;
+      }
+      default:
+        break;
+    }
+    ossWarn << " replaced with " << pToken->m_Format.GetNoRest() << "." << endl;
+    if( !m_bSilentMode )
+      // Show warning only if silent mode is off
+      cerr << ossWarn.str();
+
+    // Update format string
+    pToken->m_strPrintFmt = pToken->m_Format.Get();
+  }
+
+  switch( m_aValue.DataType() )
+  {
+    // if we have a string format.
+    case DataBuf::CHAR:
+    {
+      String strBuf;
+      strBuf.append((char *)m_aValue.Buf(), m_aValue.Len());
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), PSZ(strBuf));
+      break;
+    }
+      // the case of int,long,unsigned char or short.
+    case DataBuf::BYTE:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((uint8 *)m_aValue.Buf()));
+      break;
+    case DataBuf::SHORT:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((short *)m_aValue.Buf()));
+      break;
+    case DataBuf::USHORT:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((unsigned short *)m_aValue.Buf()));
+      break;
+    case DataBuf::LONG:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((long *)m_aValue.Buf()));
+      break;
+    case DataBuf::ULONG:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((unsigned long *)m_aValue.Buf()));
+      break;
+    case DataBuf::INT:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((int *)m_aValue.Buf()));
+      break;
+    case DataBuf::FLOAT:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((float *)m_aValue.Buf()));
+      break;
+    case DataBuf::DOUBLE:
+      m_stkOut.top()->Out(PSZ(pToken->m_strPrintFmt), *((double *)m_aValue.Buf()));
+      break;
+    default:
+      break;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::GetValue
+//-----------------------------------------------------------------------------
+bool Extractor::GetValue(const String &strVar, int *piValue)
+{
+  // evalute a variable by giving its value stocked in the dict.
+  MapCounters::const_iterator it = m_dictCounters.find(strVar);
+  if( it != m_dictCounters.end())
+  {
+    *piValue = it->second;
+    return true;
+  }
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+// Extractor::Evaluate
+//-----------------------------------------------------------------------------
+Variant Extractor::Evaluate(const String &str)
+{
+  String strToEval = str;
+  int iValue = 0;
+  m_TempParsor.ProcessNoRecursion(&strToEval);
+  if( m_pNxEval->Evaluate(strToEval, &m_aValue) )
+    iValue = ValueToInteger();
+  else
+    iValue = atoi(PSZ(strToEval));
+  return iValue;
+}
+
+//===========================================================================
+/// class StandardOutput
+//===========================================================================
+void StandardOutput::Out(const char *pcszFormat, const char *psz)
+{
+  printf(pcszFormat, psz);
+}
+
+void StandardOutput::Out(const char *pcszFormat, char c)
+{
+  printf(pcszFormat, c);
+}
+
+void StandardOutput::Out(const char *pcszFormat, uint8 ui8)
+{
+  printf(pcszFormat, ui8);
+}
+
+void StandardOutput::Out(const char *pcszFormat, short s)
+{
+  printf(pcszFormat, s);
+}
+
+void StandardOutput::Out(const char *pcszFormat, unsigned short s)
+{
+  printf(pcszFormat, s);
+}
+
+void StandardOutput::Out(const char *pcszFormat, long l)
+{
+  printf(pcszFormat, l);
+}
+
+void StandardOutput::Out(const char *pcszFormat, unsigned long l)
+{
+  printf(pcszFormat, l);
+}
+
+void StandardOutput::Out(const char *pcszFormat, int i)
+{
+  printf(pcszFormat, i);
+}
+
+void StandardOutput::Out(const char *pcszFormat, float f)
+{
+  printf(pcszFormat, f);
+}
+
+void StandardOutput::Out(const char *pcszFormat, double d)
+{
+  printf(pcszFormat, d);
+}
+
+void StandardOutput::Out(void * /*pData*/, int /*iDataLen*/)
+{
+  cerr << "Error: Cannot print binary data as ascii text" << endl;
+}
+
+//===========================================================================
+/// class MemBufOutput
+//===========================================================================
+void MemBufOutput::Out(const char *pcszFormat, const char *psz)
+{
+  sprintf(g_acScratchBuf, pcszFormat, psz);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, char c)
+{
+  sprintf(g_acScratchBuf, pcszFormat, c);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, uint8 ui8)
+{
+  sprintf(g_acScratchBuf, pcszFormat, ui8);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, short s)
+{
+  sprintf(g_acScratchBuf, pcszFormat, s);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, unsigned short us)
+{
+  sprintf(g_acScratchBuf, pcszFormat, us);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, long l)
+{
+  sprintf(g_acScratchBuf, pcszFormat, l);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, unsigned long ul)
+{
+  sprintf(g_acScratchBuf, pcszFormat, ul);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, int i)
+{
+  sprintf(g_acScratchBuf, pcszFormat, i);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, float f)
+{
+  sprintf(g_acScratchBuf, pcszFormat, f);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(const char *pcszFormat, double d)
+{
+  sprintf(g_acScratchBuf, pcszFormat, d);
+  m_ptrMemBuf->PutBloc(g_acScratchBuf, strlen((const char *)g_acScratchBuf));
+}
+
+void MemBufOutput::Out(void *pData, int iDataLen)
+{
+  m_ptrMemBuf->PutBloc(pData, iDataLen);
+}
+
+//===========================================================================
+/// class BinaryFileOutput
+//===========================================================================
+BinaryFileOutput::~BinaryFileOutput()
+{
+//  if( m_pFile )
+//    fclose( m_pFile);
+}
+void BinaryFileOutput::Out(const char *pcszFormat, const char *psz)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, psz);
+  else
+    fwrite(pcszFormat, strlen(psz), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, char c)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, c);
+  else
+    fwrite(&c, sizeof(char), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, uint8 ui8)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, ui8);
+  else
+    fwrite(&ui8, sizeof(uint8), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, short s)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, s);
+  else
+    fwrite(&s, sizeof(short), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, unsigned short us)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, us);
+  else
+    fwrite(&us, sizeof(unsigned short), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, long l)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, l);
+  else
+    fwrite(&l, sizeof(long), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, unsigned long ul)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, ul);
+  else
+    fwrite(&ul, sizeof(unsigned long), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, int i)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, i);
+  else
+    fwrite(&i, sizeof(int), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, float f)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, f);
+  else
+    fwrite(&f, sizeof(float), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(const char *pcszFormat, double d)
+{
+  if( pcszFormat )
+    fprintf(m_pFile, pcszFormat, d);
+  else
+    fwrite(&d, sizeof(double), 1, m_pFile);
+}
+
+void BinaryFileOutput::Out(void *pData, int iDataLen)
+{
+  fwrite(pData, iDataLen, 1, m_pFile);
+}
+
+//===========================================================================
+/// class Constant
+//===========================================================================
+//-----------------------------------------------------------------------------
+// Expression::Constant::GetValue
+//-----------------------------------------------------------------------------
+Variant Expression::Constant::GetValue()
+{
+  return m_vValue;
+}
+Expression::Constant::~Constant()
+{}
+
+//===========================================================================
+/// class Expression
+//===========================================================================
+IValueEvaluator *Expression::s_pValueEval = NULL;
+
+Expression::~Expression()
+{}
+
+//-----------------------------------------------------------------------------
+// Expression::Eval
+//-----------------------------------------------------------------------------
+double Expression::Eval()
+{
+  return double(GetValue());
+}
+
+//-----------------------------------------------------------------------------
+// Expression::GetValue
+//-----------------------------------------------------------------------------
+Variant Expression::GetValue()
+{
+  double dResult = 0;
+  for( list<FragmentPtr>::iterator it = m_lstFragment.begin(); it != m_lstFragment.end(); it++ )
+  {
+    Variant v = (*it)->Value();
+    double dVal = 0;
+    if( v.Type() == Variant::STRING )
+    {
+      if( s_pValueEval != NULL )
+        dVal = s_pValueEval->Evaluate(v);
+    }
+
+    if( (*it)->UnaryOp() != NOP )
+    {
+      // Unary evaluation: not implemented yet
+    }
+
+    switch( (*it)->BinaryOp() )
+    {
+      case ADD:
+        dResult += dVal;
+        break;
+      case SUB:
+        dResult -= dVal;
+        break;
+      case MUL:
+        dResult *= dVal;
+        break;
+      case DIV:
+        dResult /= dVal;
+        break;
+      case NOP:
+      default:
+        dResult = dVal;
+    }
+  }
+  return dResult;
+}
+
+//-----------------------------------------------------------------------------
+// Expression::CharToOp
+//-----------------------------------------------------------------------------
+Expression::Operation Expression::CharToOp(char c)
+{
+  switch( c )
+  {
+    case '+':
+      return ADD;
+    case '-':
+      return SUB;
+    case '*':
+      return MUL;
+    case '/':
+      return DIV;
+    case 'N':
+      return NOP;
+    default:
+      //## should throw an exception
+      return NOP;
+  }
+}
diff --git a/contrib/applications/NXextract/src/extractor.h b/contrib/applications/NXextract/src/extractor.h
new file mode 100644
index 0000000..8202cb9
--- /dev/null
+++ b/contrib/applications/NXextract/src/extractor.h
@@ -0,0 +1,557 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 20/07/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __EXTRACTOR_H__
+#define __EXTRACTOR_H__
+
+//-----------------------------------------------------------------------------
+// Class PrintFormat
+//-----------------------------------------------------------------------------
+class PrintFormat
+{
+private:
+  String m_strWidth;    // min chars to output
+  char   m_cFlag;       // -, +, # or ' '
+  int    m_iPrecision;  // for floating point representations
+  char   m_cModifier;   // h, l, or L
+  char   m_cType;       // one of these chars : cdieEfgGosuxXpn?
+  String m_strRest;     // will be printed together with argument
+
+  void Init() { m_cFlag = m_cModifier = m_cType = m_iPrecision = -1; }
+
+public:
+  // Constructors
+  PrintFormat();
+  PrintFormat(const String &strFormat);
+
+  // Modifiers
+  void Set(const String &strFormat);
+  void SetFlag(char cFlag) { m_cFlag = cFlag; }
+  void SetWidth(const String &strWidth) { m_strWidth = strWidth; }
+  void SetPrecision(int iPrecision) { m_iPrecision = iPrecision; }
+  void SetModifier(char cModifier) { m_cModifier = cModifier; }
+  void SetType(char cType) { m_cType = cType; }
+
+  char Type() const { return m_cType; }
+  char Modifier() const { return m_cModifier; }
+
+  // Get format string in the form %[flags][width][.precision][modifiers]type[rest]
+  String Get();
+  String GetNoRest();
+};
+
+//-----------------------------------------------------------------------------
+// Class DataBuf
+//-----------------------------------------------------------------------------
+class DataBuf
+{
+public:
+  enum Type
+  { 
+    CHAR = 0,
+    UBYTE,
+    BYTE,
+    SHORT,
+    USHORT,
+    LONG,
+    ULONG,
+    INT,
+    FLOAT,
+    DOUBLE,
+    UNKNOWN,
+    NO_TYPE
+  };
+
+private:
+  MemBufPtr m_ptrmb;
+  Type m_eType;
+  uint  m_uiTypeSize; // in octets
+  String m_strFormat; // print format, used if no format is given
+  int    m_aiDim[32];    // size of each dimensions
+  int    m_iRank; // number of dimensions
+
+public:
+
+  DataBuf(): m_ptrmb(new CMemBuf) { memset(m_aiDim, 0, 32*sizeof(int)); }
+  void SetTypeFromNeXusType(int iNxType);
+
+  inline void *Buf() { return (void *)(m_ptrmb->Buf()); }
+  inline MemBufPtr MemBufRef() { return m_ptrmb; }
+  inline int Len() { return m_ptrmb->Len(); }
+  inline void Reset() { m_ptrmb->Reset(); }
+  inline void Empty() { m_ptrmb->Empty(); }
+  inline Type &DataType() { return m_eType; }
+  inline uint TypeSize() { return m_uiTypeSize; }
+  inline void SetRank(int iRank) { m_iRank = iRank; }
+  inline void SetSize(int iDim, int iSize) { m_aiDim[iDim] = iSize; }
+  inline int Rank() { return m_iRank; }
+  inline int GetDimSize(int iDim) { return m_aiDim[iDim]; }
+};
+
+//-----------------------------------------------------------------------------
+// class SDataFragment
+// to boost performances requests are divided in several fragments which store
+// references to variables and plain text
+// a full request is the concatenation of all the snippets
+//-----------------------------------------------------------------------------
+class DataFragment
+{
+public:
+  enum Type
+  {
+    VARIABLE = 0,
+    TEXT,
+  };
+
+private:
+  Type   m_eType;
+  String m_strContent;
+
+public:
+  DataFragment(Type eType, const String &strContent) : m_eType(eType), m_strContent(strContent) {}
+  inline Type Type() const { return m_eType; }
+  inline const String &Content() const { return m_strContent; }
+};
+typedef list<DataFragment> DataFragmentsList;
+
+//-----------------------------------------------------------------------------
+// Interface IOperand
+//
+// Used in Expression class (see below)
+//-----------------------------------------------------------------------------
+class IOperand: public MReferencable
+{
+public:
+  virtual Variant GetValue() = 0;
+};
+
+typedef RefPtr<IOperand> OperandPtr;
+typedef list<OperandPtr> OperandPtrList;
+
+//-----------------------------------------------------------------------------
+// Interface IValueEvaluator
+// 
+// Used in Expression class (see below)
+//-----------------------------------------------------------------------------
+class IValueEvaluator
+{
+public:
+  virtual Variant Evaluate(const String &str) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Class Expression
+//
+// Basic expression evaluator:
+// - can do recursive evaluation
+// - all values are converted to double float type
+// - unary operators not implemented yet
+//-----------------------------------------------------------------------------
+class Expression : public IOperand
+{
+public:
+  enum Operation
+  {
+    NOP = 0, // no operation
+    ADD, 
+    SUB,
+    MUL,
+    DIV
+  };
+
+  // Object that can evaluate a value like a variable
+  static IValueEvaluator *s_pValueEval;
+
+  // Convenience method: return Op code from char in [+-*/]
+  static Operation CharToOp(char c);
+
+  // Class Constant
+  //
+  class Constant: public IOperand
+  {
+  private:
+    Variant m_vValue; // The value
+    TemplateProcessor *m_pTmplProc;
+  public:
+
+    Constant(const Variant &v): m_vValue(v) {}
+    virtual ~Constant();
+
+    // IOperand
+    virtual Variant GetValue();
+  };
+
+  // Class Fragment
+  //
+  class Fragment: public MReferencable
+  {
+  private:
+    OperandPtr m_ptrOperand;
+    Operation m_opUnary;
+    Operation m_opBinary;
+
+  public:
+    Fragment(OperandPtr ptrOperand, Operation Op2=NOP, Operation Op1=NOP)
+    { m_ptrOperand = ptrOperand; m_opBinary = Op2; m_opUnary = Op1; }
+
+    Operation UnaryOp() const { return m_opUnary; }
+    Operation BinaryOp() const { return m_opBinary; }
+    Variant Value() { return m_ptrOperand->GetValue(); }
+  };
+  typedef RefPtr<Fragment> FragmentPtr;
+
+private:
+  
+  list<FragmentPtr> m_lstFragment;
+
+public:
+
+  virtual ~Expression();
+
+  void AddFragment(FragmentPtr ptrFragment) { m_lstFragment.push_back(ptrFragment); }
+
+  double Eval();
+
+  // IOperand
+  virtual Variant GetValue();
+};
+typedef RefPtr<Expression> ExpressionPtr;
+
+//-----------------------------------------------------------------------------
+// class TemplateToken
+//-----------------------------------------------------------------------------
+class TemplateToken : public MReferencable
+{
+public:
+  enum Type
+  {
+    PRINT = 0,
+    PRINT_DATA,
+    PRINT_TEXT,
+    LOOP,
+    LOOP_OVER,
+    END_LOOP,
+    OUTPUT,
+    SET,
+    SET_LIST,
+    IF,
+    IF_EXISTS,
+    IF_SUP,
+    IF_INF,
+    IF_EQ,
+    IF_NOT_EQ,
+    END_IF,
+    BLOCK_START,
+    BLOCK_END,
+    BINARY,
+    BINARY_OUTPUT,
+    PADDING,
+    INCLUDE,
+    NO_TYPE
+  };
+
+  // Used to dump in binary format
+  enum BinaryDataType
+  {
+    CHAR = 0,
+    UBYTE,
+    BYTE,
+    SHORT,
+    USHORT,
+    LONG,
+    ULONG,
+    INT,
+    FLOAT,
+    DOUBLE,
+    RAW,
+    JPEG_IMAGE,
+    BMP_IMAGE
+  };
+
+  Type   m_TokenType;
+  uint   m_uiTypeSize;
+  int    m_iEndBlockPos;
+  int    m_iTemplateLine;
+  String m_strTemplateFile;
+  int    m_iParam1;    // block max length
+  BinaryDataType m_eBinaryDataType;
+  String m_strPrintFmt;
+  PrintFormat m_Format;
+  DataBuf::Type m_eOutputType;
+  DataFragmentsList lstDataFragments;
+  String m_strData;
+  String m_strParam1;  // loop on / output file
+  String m_strParam2;  // loop begin
+  String m_strParam3;  // loop end
+  String m_strParam4;  // loop step
+
+  virtual ~TemplateToken() {}
+};
+
+//-----------------------------------------------------------------------------
+// struct TemplateToken
+//-----------------------------------------------------------------------------
+class TokenLoop : public TemplateToken
+{
+public:
+  ExpressionPtr ptrExprBegin, ptrExprEnd, ptrExprStep;
+};
+
+typedef RefPtr<TemplateToken> TemplateTokenPtr;
+typedef vector<TemplateTokenPtr> VecToken;
+
+//-----------------------------------------------------------------------------
+// class TokenSet
+//-----------------------------------------------------------------------------
+class TokenSet: public TemplateToken
+{
+public:
+  bool m_bEvalArgument;
+};
+
+//===========================================================================
+/// Interface for counter variables type
+///
+/// This class is a interface so it can't be directly instancied
+//===========================================================================
+class ICounterVars
+{
+protected:
+  /// Constructor
+  ICounterVars() { }
+
+public:
+  /// Attempts to evaluate a counter value 
+  ///
+  /// @param pstrVar Counter to get value from
+  ///
+  virtual bool GetValue(const String &strVar, int *piValue)=0;
+};
+
+//===========================================================================
+/// Interface for data output
+///
+/// This class is a interface so it can't be directly instancied
+//===========================================================================
+class IDataOutput : public MReferencable
+{
+protected:
+  IDataOutput() {}
+
+public:
+  virtual ~IDataOutput() {}
+  virtual void Out(const char *pcszFormat, const char *psz) =0;
+  virtual void Out(const char *pcszFormat, char c) =0;
+  virtual void Out(const char *pcszFormat, uint8 ui8) =0;
+  virtual void Out(const char *pcszFormat, short s) =0;
+  virtual void Out(const char *pcszFormat, unsigned short s) =0;
+  virtual void Out(const char *pcszFormat, long l) =0;
+  virtual void Out(const char *pcszFormat, unsigned long l) =0;
+  virtual void Out(const char *pcszFormat, int i) =0;
+  virtual void Out(const char *pcszFormat, float f) =0;
+  virtual void Out(const char *pcszFormat, double d) =0;
+  virtual void Out(void *pData, int iDataLen) =0;
+};
+
+typedef RefPtr<IDataOutput> DataOutputPtr;
+typedef stack<DataOutputPtr> DataOutputPtrStack;
+
+//===========================================================================
+/// Output data to standard output
+///
+//===========================================================================
+class StandardOutput : public IDataOutput
+{
+public:
+  StandardOutput() {}
+  void Out(const char *pcszFormat, const char *psz);
+  void Out(const char *pcszFormat, char c);
+  void Out(const char *pcszFormat, uint8 ui8);
+  void Out(const char *pcszFormat, short s);
+  void Out(const char *pcszFormat, unsigned short s);
+  void Out(const char *pcszFormat, long l);
+  void Out(const char *pcszFormat, unsigned long l);
+  void Out(const char *pcszFormat, int i);
+  void Out(const char *pcszFormat, float f);
+  void Out(const char *pcszFormat, double d);
+  void Out(void *pData, int iDataLen);
+};
+
+//===========================================================================
+/// Output data to standard output
+///
+//===========================================================================
+class MemBufOutput : public IDataOutput
+{
+private:
+  MemBufPtr m_ptrMemBuf;
+  int       m_iPaddingPos;
+  String   m_strPaddingPattern;
+
+public:
+  MemBufOutput(MemBufPtr ptrMemBuf) : m_ptrMemBuf(ptrMemBuf), m_iPaddingPos(-1) {}
+  void Out(const char *pcszFormat, const char *psz);
+  void Out(const char *pcszFormat, char c);
+  void Out(const char *pcszFormat, uint8 ui8);
+  void Out(const char *pcszFormat, short s);
+  void Out(const char *pcszFormat, unsigned short s);
+  void Out(const char *pcszFormat, long l);
+  void Out(const char *pcszFormat, unsigned long l);
+  void Out(const char *pcszFormat, int i);
+  void Out(const char *pcszFormat, float f);
+  void Out(const char *pcszFormat, double d);
+  void Out(void *pData, int iDataLen);
+  void SetPaddingPattern(const String &strPattern) { m_iPaddingPos = m_ptrMemBuf->Len(); m_strPaddingPattern = strPattern; }
+  int PaddingPos() const { return m_iPaddingPos; }
+  const String &PaddingPattern() const { return m_strPaddingPattern; }
+};
+
+//===========================================================================
+/// Output data to binary file
+///
+//===========================================================================
+class BinaryFileOutput : public IDataOutput
+{
+private:
+  FILE    *m_pFile;
+
+public:
+  BinaryFileOutput(FILE *pFile): m_pFile(pFile) {}
+  ~BinaryFileOutput();
+
+  void Out(const char *pcszFormat, const char *psz);
+  void Out(const char *pcszFormat, char c);
+  void Out(const char *pcszFormat, uint8 ui8);
+  void Out(const char *pcszFormat, short s);
+  void Out(const char *pcszFormat, unsigned short s);
+  void Out(const char *pcszFormat, long l);
+  void Out(const char *pcszFormat, unsigned long l);
+  void Out(const char *pcszFormat, int i);
+  void Out(const char *pcszFormat, float f);
+  void Out(const char *pcszFormat, double d);
+  void Out(void *pData, int iDataLen);
+};
+
+typedef map<String, int> MapCounters;
+typedef map<String, MemBufPtr> MapBufPtr;
+
+//-----------------------------------------------------------------------------
+// Class CTemplateFileParsor
+//
+//-----------------------------------------------------------------------------
+class Extractor : public IVariableEvaluator, public ICounterVars, public IValueEvaluator
+{
+private:
+  VecToken           &m_vecToken;       // Tokenized template file
+  StringDict          m_dictVar;        // Variables dictionnary
+  MapCounters         m_dictCounters;   // Counters dictionnary
+  CTemplateProcessor  m_TempParsor;     // Template parsor (used to evaluate variables)
+  NexusEvaluator     *m_pNxEval;        // Nexus data evaluator
+  DataBuf             m_aValue;         // Objet used to transport output values
+  FILE               *m_fiOut;          // Output File
+  String              m_strMode;        // Access mode of output files
+  String              m_strOwnership;   // Ownership of output files
+  String              m_strCurrentFile; // Currently wrilted file
+  bool                m_bSilentMode;    // If true disable warnings
+  MapBufPtr           m_dictBuf;        // Named data buffers
+  MemBufPtr           m_ptrCurrentBuf;  // Current buffer
+  DataOutputPtrStack  m_stkOut;         // Output objects stack
+
+  uid_t Uid();
+  gid_t Gid();
+
+  int  ValueToInteger();
+  String  ValueToString(DataBuf &aValue);
+
+  // remove the variable var from the stringDict.
+  void RemoveVar(const String &strVar);
+  // Get type id according to specified print format spec
+  DataBuf::Type GetTypeFromFormat(char cType, char cMod);
+  // Obtain a data buffer
+  MemBufPtr GetBuf(const String &strName, bool bCreate=true);
+
+  // Executing script
+  int  ExecLoopOver(int iCurrentPos);
+  void ExecPrintData(TemplateToken *pToken);
+  int  ExecBlock(int iCurrentPos);
+  int  ExecLoop(int iCurrentPos);
+  void Exec(int iStartPos, int iEndPos);
+  int  ExecIfExists(int iCurrentPos);
+  int  ExecIfEq(int iCurrentPos, bool bNot);
+  int  ExecComp(int iCurrentPos, bool bInf, bool bNot);
+  void ExecPadding(int iCurrentPos);
+  void ExecBinary(int iCurrentPos);
+  void ExecSet(int iCurrentPos);
+  void ExecSetList(int iCurrentPos);
+
+  String GetTokenArgument(TemplateToken *pToken);
+  void PrintData(TemplateToken *pToken);
+  void OutBinaryScalarFromString(const TemplateToken &Token, const String &strData);
+  String ScalarValueToString();
+
+public:
+  // @param pstrVar Variable to evaluate
+  // @return true if evaluation is done, or false
+  Extractor(const String &strNeXusFile, VecToken *pvecToken, IVariableEvaluator *pAppContext, const String &strMode, const String &strOwnership);
+  virtual ~Extractor();
+
+  // Set variable value
+  void SetVar(const String &strVar, const String &strVal);
+
+  // associate the value val to the variable var in the stringDict.
+  void AddVar(const String &strVar, const String &strVal);
+
+  // Test variable
+  bool HasVar(const String &strVar);
+
+  // Set silent mode
+  void SetSilent(bool bSilent=true) { m_bSilentMode = bSilent; }
+
+  // Specify output file
+  void SetOutputFile(const String &strFile, bool bBinary);
+
+  // Parsing and script executing
+  void Execute();
+
+  // ICounterVars
+  bool GetValue(const String &strVar, int *piValue);
+
+  // IValueEvaluator
+  Variant Evaluate(const String &str);
+
+#ifdef __JPEG_SUPPORT__
+  /// Convert image embedded in a Nxextract DataBuf into jpeg format
+  static void ValueToJpeg(DataBuf *pDataBuf, MemBufPtr ptrmbDest);
+#endif
+
+  /// Convert image embedded in a Nxextract DataBuf into bmp format
+  static void ValueToBmp(DataBuf *pDataBuf, MemBufPtr ptrmbDest);
+
+  /// Convert a numerical value for one type to another
+  /// @param pSrc Adress of initial value
+  /// @param eSrcType Type of initial value
+  /// @param pDst Adress of final value
+  /// @param eDstType Type of final value
+  /// @return true if conversion was possible
+  static bool ConvertBinaryValue(void *pSrc, DataBuf::Type eSrcType, void *pDst, TemplateToken::BinaryDataType eDstType);
+
+  // Evaluate a variable and give its value if it has been stocked 
+  // in the DictVar.
+  virtual bool Evaluate(String *pstrVar);
+};
+
+#endif
diff --git a/contrib/applications/NXextract/src/extractorapp.cpp b/contrib/applications/NXextract/src/extractorapp.cpp
new file mode 100644
index 0000000..2d0acfb
--- /dev/null
+++ b/contrib/applications/NXextract/src/extractorapp.cpp
@@ -0,0 +1,257 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 01/12/2006
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "file.h"
+#include "membuf.h"
+#include "nxfile.h"
+#include "variant.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>  
+#include <vector>
+#include <cstdlib>
+#include <cstring>
+
+#include "nexusevaluator.h"
+#include "extractor.h"
+#include "templateparsor.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+/// Class ExtractorApp
+/// Main class for NeXus extractor application
+//-----------------------------------------------------------------------------
+class ExtractorApp: public IVariableEvaluator
+{
+private:
+  StringDict  m_dictParam;        // Parameters dictionnary
+
+public:
+
+  /// Setting command line options
+  void OnCommandLineOpts();
+
+  /// Entry point
+  int OnRun();
+
+  /// Program exit
+  int OnEnd();
+
+  /// Get collection of input files
+  void GetInputFiles(std::set<String> *psetSources);
+
+  /// Add template parameters
+  void AddParameters(const String &strParamList);
+
+  /// Evaluate a variable and give its value if it has been stocked in the DictVar.
+  virtual bool Evaluate(String *pstrVar);
+};
+
+//-----------------------------------------------------------------------------
+// ExtractorApp::AddParameters
+//-----------------------------------------------------------------------------
+void ExtractorApp::AddParameters(const String &strParamList)
+{
+  String strList = strParamList;
+  String strParamDef, strParamName, strParamSubtitution;
+  while( !strList.empty() )
+  {
+    strList.ExtractToken(',', &strParamDef);
+    if( strParamDef.find('=') != string::npos )
+    {
+      strParamDef.ExtractToken('=', &strParamName);
+      strParamSubtitution = strParamDef;
+    }
+    else
+    {
+      strParamName = strParamDef;
+      strParamSubtitution = "<defined>";
+    }
+    // Add paramater only if not always defined
+    if( !m_dictParam.HasKey(strParamName) )
+        m_dictParam.insert(StringDict::value_type(strParamName, strParamSubtitution));
+  }
+}
+
+//-----------------------------------------------------------------------------
+// ExtractorApp::Evalutate
+//-----------------------------------------------------------------------------
+bool ExtractorApp::Evaluate(String *pstrVar)
+{ 
+  // Look into the application dictionnary
+  StringDict::iterator it = m_dictParam.find(*pstrVar);
+  if( it != m_dictParam.end())
+  {
+    *pstrVar=(it->second);
+    return true;
+  }
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+// ExtractorApp::OnCommandLineOpts
+//-----------------------------------------------------------------------------
+void ExtractorApp::OnCommandLineOpts()
+{
+  CCommandLine::SetCmdNameVersion("nxextract", "1.12.0");
+  CCommandLine::AddOpt('t', "template", "file", "Template file");
+  CCommandLine::AddOpt('D', "Define", "symbols", "Symbols list");
+  CCommandLine::AddOpt('s', "silent", NULL, "Silent mode");
+#ifdef __LINUX__
+  CCommandLine::AddOpt('m', "mode", "octal value", "Access mode of output files in octal ex:'755'");
+  CCommandLine::AddOpt('w', "ownership", "user_id:group_id", "User and group in the form 'user:group'");
+#endif
+  CCommandLine::AddArg("input NeXus Files and/or directories");
+}
+
+//-----------------------------------------------------------------------------
+// ExtractorApp::GetInputFiles
+//-----------------------------------------------------------------------------
+void ExtractorApp::GetInputFiles(std::set<String> *psetSources)
+{
+  FileName fnPathArg;
+
+  for( int i = 0; i < CommandLine::ArgCount(); i++ )
+  {
+    String strPattern;
+    bool bDoEnum = false;
+
+    // Reads next argument
+    fnPathArg.Set(CommandLine::Arg(i));
+
+    if( fnPathArg.IsPathName() )
+      // Consider full directory content
+      bDoEnum = true;
+    else if( fnPathArg.NameExt().find_first_of("*?") != string::npos )
+    {
+      // Consider only file whose name match the given pattern
+      bDoEnum = true;
+      strPattern = fnPathArg.NameExt();
+    }
+
+    if( bDoEnum )
+    { // Directory enumeration
+      FileEnum feDir(fnPathArg.Path(), FileEnum::ENUM_FILE);
+      while( feDir.Find() )
+      {
+        if( strPattern.empty() || feDir.NameExt().Match(PSZ(strPattern)) )
+          psetSources->insert(feDir.FullName());
+      }
+    }
+    else
+    {
+      if( fnPathArg.FileExists() )
+        psetSources->insert(fnPathArg.FullName());
+      else
+        cerr << "Input file '" << fnPathArg.FullName() << " not found." << endl;
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+// ExtractorApp::OnRun
+//-----------------------------------------------------------------------------
+int ExtractorApp::OnRun()
+{
+  String strTemplate = CommandLine::OptionValue("template");
+
+  if( !gdshare::FileExists(PSZ(strTemplate)) )
+  {
+    cerr << "Template file '" << strTemplate << " not found." << endl;
+    return 1;
+  }
+
+  // Build input files list from command line arguments
+  std::set<String> setInputFiles;
+  GetInputFiles(&setInputFiles);
+
+  // Look for file properties options
+  CString strMode, strOwnerShip;
+  if( CommandLine::IsOption("mode") )
+    strMode = CommandLine::OptionValue("mode");
+  if( CommandLine::IsOption("ownership") )
+    strOwnerShip = CommandLine::OptionValue("ownership");
+
+  if( CCommandLine::IsOption("Define") )
+    // Adds parameters found in command line
+    AddParameters(CommandLine::OptionValue("Define"));
+
+  // For execution time
+  CurrentDate tmStart;
+
+  // Script tokens vector
+  VecToken vecToken;
+
+  // Script parsor
+  TemplateFileParsor Parsor(&vecToken);
+  // Get default values for template parameters
+  String strParams;
+  Parsor.ReadHeader(strTemplate, &strParams);
+  AddParameters(strParams);
+  // Parse the script and build tokens
+  Parsor.Parse(strTemplate, this);
+
+  // For each input files run the script
+  for( std::set<String>::const_iterator cit = setInputFiles.begin(); cit != setInputFiles.end(); cit++ )
+  {
+    try
+    {
+      // Script execution object
+      Extractor Extractor(*cit, &vecToken, this, strMode, strOwnerShip);
+
+      // Create specifics parameters
+      FileName fn(*cit);
+      Extractor.SetVar("_FILE_NAME_", fn.Name());
+
+      if( CommandLine::IsOption("silent") )
+        // Set silent mode
+        Extractor.SetSilent();
+
+      // Run the script
+      Extractor.Execute();
+    }
+    catch( NexusException e )
+    {
+      e.PrintMessage();
+    }
+  }
+
+  if( !CommandLine::IsOption("silent") )
+    LogInfo("proc", "Elapsed time : %.3lf sec.", CurrentDate().DoubleUnix() - tmStart.DoubleUnix());
+  return 0;
+}
+
+//-----------------------------------------------------------------------------
+// main
+//-----------------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+  ExtractorApp App;
+  App.OnCommandLineOpts();
+
+  if( !CommandLine::Read(argc, argv) )
+    return 1;
+
+  int iRc = App.OnRun();
+  if( iRc )
+    return iRc;
+
+  return 0;
+}
diff --git a/contrib/applications/NXextract/src/file.cpp b/contrib/applications/NXextract/src/file.cpp
new file mode 100644
index 0000000..1be5929
--- /dev/null
+++ b/contrib/applications/NXextract/src/file.cpp
@@ -0,0 +1,1608 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Files manipulations
+//
+// Creation : 25/05/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "base.h"
+#include "membuf.h"
+#include "date.h"
+#include "file.h"
+
+using namespace gdshare;
+
+// Error msgs
+const char ERR_CANNOT_CREATE_FOLDER[]     = "Cannot create directory '%s'";
+const char ERR_CANNOT_CREATE_LINK[]       = "Cannot create link; name = '%s', target='%s'";
+const char ERR_CANNOT_ENUM_DIR[]          = "Cannot enumerate directory '%s'";
+const char ERR_CANNOT_REMOVE_FILE[]       = "Cannot remove file '%s'";
+const char ERR_CANNOT_FETCH_INFO[]        = "Cannot fetch informations for file '%s'";
+const char ERR_CANNOT_RENAME_FILE[]       = "Cannot rename file '%s'";
+const char ERR_FILE_NOT_FOUND[]           = "File '%s' not found";
+const char ERR_DIR_NOT_FOUND[]            = "Directory '%s' not found";
+const char ERR_COPY_FAILED[]              = "A error has occured while copying from '%s' to '%s'";
+const char ERR_OPEN_FILE[]                = "Cannot open file '%s'";
+const char ERR_CANNOT_CREATE_WIN32[]      = "Cannot get handle for '%s' (Win32 API)";
+const char ERR_CANNOT_CHANGE_FILE_TIME[]  = "Cannot change file time for '%s'";
+const char ERR_CANNOT_GET_FILE_TIME[]     = "Cannot get file time for '%s'";
+const char ERR_READING_FILE[]             = "Error while reading file '%s'";
+const char ERR_WRITING_FILE[]             = "Error while writing file '%s'";
+const char ERR_STAT_FAILED[]              = "Cannot get informations about file '%s'";
+const char ERR_CHMOD_FAILED[]             = "Cannot change access for '%s' to '%o'";
+const char ERR_CHOWN_FAILED[]             = "Cannot change owner for '%s' to %d:%d";
+const char ERR_FSTYPE[]                   = "Error gathering file system information on '%s'";
+const char ERR_NOT_A_DIRECTORY[]          = "Is not a directory";
+const char ERR_DELETE_DIRECTORY[]         = "Cannot delete directory '%s'";
+const char ERR_BAD_DEST_PATH[]            = "Bad destination path '%s'";
+
+// Begining of cygwin absolute file names
+const char FILE_CYGDRIVE[] = "\\cygdrive\\";
+
+//-------------------------------------------------------------------
+// PathExists
+//-------------------------------------------------------------------
+bool gdshare::PathExists(pcsz pszPath)
+{
+  if( strchr(pszPath, '*') || strchr(pszPath, '?') )
+    // there are wildcard. this is not a valid path
+    return false;
+ 
+  uint uiLen = strlen(pszPath) ;
+  if (uiLen == 0)
+     return false;
+ 
+#ifdef __WIN32__
+  WIN32_FIND_DATA find;
+  HANDLE          h;
+  if( pszPath[uiLen-1] == '\\' )
+  {
+    if( uiLen >= 2 && pszPath[uiLen-2] == ':' )
+    {
+      // Path is a disque drive name
+      uint uiRc = ::GetDriveType( pszPath );
+      if( uiRc == 0 || uiRc == 1 )
+        return false;
+      return true;
+    }
+    // Path ends with '\' => remove '\'
+    String strPath = pszPath;
+    strPath = strPath.substr(0, strPath.size()-1);
+    h = FindFirstFile( PSZ(strPath), &find );
+  }
+  else
+    h = FindFirstFile( pszPath, &find );
+ 
+  if( h == INVALID_HANDLE_VALUE )
+    return false;
+  FindClose( h );
+  return MAKEBOOL(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+#else
+  struct stat  st ;
+  int          iRc ;
+
+  if( uiLen>=2 && IsSepPath(pszPath[uiLen-1]) && pszPath[uiLen-2] != ':' )
+  {
+    // Path ends with '\' => remove '\'
+    String strPath = pszPath;
+    strPath = strPath.substr(0, strPath.size()-1);
+    iRc = stat(PSZ(strPath), &st);
+  }
+  else
+    iRc = stat(pszPath, &st);
+  return !iRc && (st.st_mode & S_IFDIR);
+#endif
+}
+
+//----------------------------------------------------------------------------
+// FileExists
+//----------------------------------------------------------------------------
+bool gdshare::FileExists(pcsz pcszFullName)
+{
+#ifdef __WIN32__ // Windows version
+
+  WIN32_FIND_DATA find;
+  HANDLE h = FindFirstFile(pcszFullName, &find);
+  if( h == INVALID_HANDLE_VALUE )
+    return false;
+  FindClose( h );
+  return MAKEBOOL(!(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
+
+#else // Linux version
+
+  struct stat st;
+  return MAKEBOOL(!access(pcszFullName, 0) &&
+         !stat(pcszFullName, &st) &&
+         (st.st_mode & S_IFREG));
+
+#endif
+}
+
+//----------------------------------------------------------------------------
+// AccessFromString
+//----------------------------------------------------------------------------
+mode_t gdshare::AccessFromString(const String &strAccess)
+{
+  mode_t mode = 0;
+#ifdef __LINUX__
+  sscanf(PSZ(strAccess), "%o", &mode);
+#endif
+	return mode;
+}
+
+///===========================================================================
+/// FileName
+///
+/// File name manipulations
+///===========================================================================
+
+//----------------------------------------------------------------------------
+// FileName::Set
+//----------------------------------------------------------------------------
+void FileName::Set(const String &strFullName)
+{
+  SetFullName(PSZ(strFullName));
+
+  if( PathExists() && !IsPathName() )
+    // Add missing path separator
+    m_strFile += SEP_PATH;
+}
+
+void FileName::Set(const String &_strPath, const String &_strName)
+{
+  String strPath = _strPath;
+  String strName = _strName;
+
+  // Evaluate env variables
+  CTemplateProcessor tproc;
+  CEnvVariableEvaluator aObject;
+  tproc.AddEvaluator(&aObject);
+  tproc.Process(&strName);
+  tproc.Process(&strPath);
+
+  ConvertSeparators(&strPath);
+  ConvertSeparators(&strName);
+
+  String strFullName;
+
+  if( EndWith(strPath, SEP_PATH) )
+    strFullName = strPath + strName;
+  else
+    strFullName = strPath + SEP_PATH + strName;
+  Set(strFullName);
+}
+
+void FileName::Set(const String &strPath, const String &strName, const  String &strExt)
+{
+  Set(strPath, strName + "." + strExt);
+}
+
+//----------------------------------------------------------------------------
+// FileName::IsPathName
+//----------------------------------------------------------------------------
+bool FileName::IsPathName() const
+{
+  if( EndWith(m_strFile, SEP_PATH) )
+    return true;
+  return false;
+}
+
+//-------------------------------------------------------------------
+// Indique si le nom entre correspond a un path existant
+//-------------------------------------------------------------------
+bool FileName::PathExists() const
+{
+  return gdshare::PathExists(PSZ(FullName()));
+}
+
+//-------------------------------------------------------------------
+// Indique si le nom correspond a un fichier existant
+//-------------------------------------------------------------------
+bool FileName::FileExists() const
+{
+  return gdshare::FileExists(PSZ(FullName()));
+}
+
+//----------------------------------------------------------------------------
+// FileName::SetFullName
+//----------------------------------------------------------------------------
+void FileName::SetFullName(pcsz pszFileName)
+{
+  if( !pszFileName || !pszFileName[0] )
+  {
+    m_strFile = g_strEmpty;
+    return;
+  }
+
+  String strFileName = pszFileName;
+
+  // Evaluate env variables
+  CTemplateProcessor tproc;
+  CEnvVariableEvaluator aObject;
+  tproc.AddEvaluator(&aObject);
+  tproc.Process(&strFileName);
+
+  // Convert separators
+  ConvertSeparators(&strFileName);
+
+  #ifdef __UNIX__
+
+    if (IsSepPath(strFileName[0u]))
+    {
+      // Absolute name
+      m_strFile = strFileName;
+    }
+    else
+    {
+      // relative name: add current working directory
+      char cbuf[_MAX_PATH];
+      getcwd(cbuf, _MAX_PATH);
+      m_strFile = StrFormat("%s/%s", cbuf, PSZ(strFileName));
+    }
+
+  #elif defined(__WIN32__)
+
+    m_strFile = strFileName;
+   
+    // Warning: strFile may be empty
+    if( m_strFile.size() > 0 && 
+          ((IsSepPath(m_strFile[0u] && IsSepPath(m_strFile[1u])) || // UNC '\\'
+          m_strFile[1u] == SEP_DSK )))                              // Drive letter: 'X:'
+    { 
+      // Absolute name
+
+    }
+    else
+    {
+      _getcwd(g_acScratchBuf, _MAX_PATH);
+      String strDir = g_acScratchBuf;
+ 
+      // Convert path into full name in windows format.
+      // 3 cases :
+      // - path begin with /cygdrive/<letter>/ => absolute path name
+      //   We replace this part by the drive letter
+      // - The path name begins with a '/' => UNIX absolute path name.
+      //   We insert current media name at begining
+      // - For all other cases it's a relative path name
+      if( StartWith(m_strFile, FILE_CYGDRIVE) && m_strFile[11u] == '\\' )
+      {
+        // Case of paths like '/cygdrive/<letter>/'
+        strDir = StrFormat("%c:\\", m_strFile[10u]);
+        m_strFile = StrFormat("%c:\\%s", m_strFile[10u], m_strFile.substr(12, std::string::npos));
+      }
+      else if( IsSepPath(m_strFile[0u]) )
+      {
+        // Absolute path without drive letter:
+        // - add drive letter coming from getcwd
+        m_strFile = StrFormat("%c:\\%s", strDir[0u], PSZ(m_strFile));
+      }
+      else
+      {
+        // getcwd may not add the traling path separator
+        if( !EndWith(strDir, SEP_PATH) )
+          strDir += SEP_PATH;
+
+        if( IsEquals(m_strFile, ".") )
+          m_strFile = strDir;
+        else
+          m_strFile = strDir + m_strFile;
+      }
+    }
+  #endif
+}
+
+//----------------------------------------------------------------------------
+// FileName::Path
+//----------------------------------------------------------------------------
+String FileName::Path() const
+{
+  String strPath = g_strEmpty;
+
+  // Backward search for first separator
+  String::size_type iLastSepPos = m_strFile.find_last_of(SEP_PATH);
+  if( String::npos != iLastSepPos )
+   // Found
+   strPath = m_strFile.substr(0, iLastSepPos + 1);
+
+  return strPath;
+}
+
+//----------------------------------------------------------------------------
+// FileName::Name
+//----------------------------------------------------------------------------
+String FileName::Name() const
+{
+  String strName = g_strEmpty;
+
+  // Backward search for first separator
+  String::size_type iLastSepPos = m_strFile.find_last_of(SEP_PATH);
+  if( String::npos == iLastSepPos )
+    // If not found  : no path
+    iLastSepPos = 0;
+
+  String::size_type iExtPos = m_strFile.find_last_of(SEP_EXT);
+  if( String::npos == iExtPos )
+    iExtPos = m_strFile.length();
+
+  strName = m_strFile.substr(iLastSepPos + 1, iExtPos - iLastSepPos - 1);
+
+  return strName;
+}
+
+//----------------------------------------------------------------------------
+// FileName::DirName
+//----------------------------------------------------------------------------
+String FileName::DirName() const
+{
+  String strName = g_strEmpty;
+
+  // Backward search for last separator
+  int iLastSepPos = (int)m_strFile.find_last_of(SEP_PATH);
+  if( String::npos == iLastSepPos )
+    return g_strEmpty;
+  int iPreviousSepPos = (int)m_strFile.rfind(SEP_PATH, iLastSepPos-1);
+  if( String::npos == iPreviousSepPos )
+    iPreviousSepPos = -1;
+
+  strName = m_strFile.substr(iPreviousSepPos + 1, iLastSepPos - iPreviousSepPos - 1);
+
+  return strName;
+}
+
+//-------------------------------------------------------------------
+// FileName::RelName
+//-------------------------------------------------------------------
+String FileName::RelName(const char* pszPath) const
+{
+  FileName fnRef(pszPath);
+
+  // On windows check if both paths are on the same disk
+  // Otherwise we return the full name
+  #ifdef __WIN__
+    // On ne peut pas comparer les caracteres a cause du case
+    if( strnicmp(m_strFile.Buf(), fnRef.FullName(), 1) )
+      return m_strFile;
+  #endif
+
+  // Search for first separator. If not => return full name
+  const char* p = strchr(PSZ(m_strFile), SEP_PATH);
+  const char* pRef = strchr(PSZ(fnRef.FullName()), SEP_PATH);
+  if (!p || !pRef)
+    return m_strFile;
+
+  String str;
+  bool bClimbStarted = false;
+  for(;;)
+  {
+    const char* p1 = strchr(p+1, SEP_PATH);
+    const char* pRef1 = strchr(pRef+1, SEP_PATH);
+
+    if( !p1 )
+    {
+      // No more parts in file name
+      while( pRef1 )
+      {
+        #ifdef __UNIX__
+          str = string("../") + str;
+        #else
+          str = string("..\\") + str;
+        #endif
+        pRef1 = strchr(pRef1+1, SEP_PATH);
+      }
+      str += string(p+1);
+      return str;
+    }
+
+    if( !pRef1 )
+    {
+      // No more reference
+      str += string(p+1);
+      return str;
+    }
+
+    // Compare directories
+    if( (p1-p != pRef1-pRef) || bClimbStarted ||
+        #ifdef __UNIX__
+          // Unix : le case est important
+          strncmp(p, pRef, p1-p) )
+        #else
+          _strnicmp(p, pRef, p1-p) )
+        #endif
+    {
+      // Different directory
+      #ifdef __UNIX__
+        str = string("../") + str;
+      #else
+        str = string("..\\") + str;
+      #endif
+      bClimbStarted = true;
+      str.append(p+1, p1-p);
+    }
+    p = p1;
+    pRef = pRef1;
+  }
+}
+
+//----------------------------------------------------------------------------
+// FileName::NameExt
+//----------------------------------------------------------------------------
+String FileName::NameExt() const
+{
+  String strFileName = Name();
+  if( Ext().size() > 0 )
+    strFileName += '.' + Ext();
+  return strFileName;
+}
+
+//----------------------------------------------------------------------------
+// FileName::Ext
+//----------------------------------------------------------------------------
+String FileName::Ext() const
+{
+  String strExt = g_strEmpty;
+
+  // Search backward for extension separator
+  String::size_type iExtPos = m_strFile.find_last_of(SEP_EXT);
+  if( String::npos != iExtPos )
+    // Separator found
+    strExt = m_strFile.substr(iExtPos + 1);
+
+  return strExt;
+}
+
+//----------------------------------------------------------------------------
+// FileName::ConvertSeparators
+//----------------------------------------------------------------------------
+void FileName::ConvertSeparators(String *pstr)
+{
+  char *ptc = new char[pstr->length()+1];
+  char *pStart = ptc;
+  strcpy(ptc, PSZ(*pstr));
+
+  #ifdef __UNIX__
+
+    // Convert from DOS to UNIX
+    while (*ptc)
+    {
+      if (*ptc == SEP_PATHDOS)
+        *ptc = SEP_PATHUNIX;
+      ptc++;
+    }
+
+  #elif defined(__WIN32__)
+
+    // Convert from UNIX to DOS
+    char* ptcStart = ptc;
+    while (*ptc)
+    {
+      if (*ptc == SEP_PATHUNIX)
+        *ptc = SEP_PATHDOS;
+
+      // If there are two consecutive separators, remove the second but not if it's the begining of the path => UNC
+      if (*ptc == SEP_PATHDOS && (ptc - 1) > ptcStart && *(ptc - 1) == SEP_PATHDOS)
+      {
+        // Removing second sep
+        strcpy(ptc - 1, ptc);
+      }
+      ptc++;
+    }
+  #endif
+
+  *pstr = pStart;
+  delete [] pStart;
+}
+
+//----------------------------------------------------------------------------
+// FileName::MkDir
+//----------------------------------------------------------------------------
+void FileName::MkDir(mode_t mode, uid_t uid, gid_t gid) const
+{
+  LogVerbose("file", "Creating directory '%s'...", PSZ(Path()));
+  String str = Path();
+  if( str.empty() )
+    return;
+
+  const char   *p;
+#ifdef __WIN32__
+  // Skeep UNC starting if it exists
+  if( str[0u] == SEP_PATH && str[1u] == SEP_PATH )
+  {
+    // Saute le nom de la machine (qui suit les '\\' du debut)
+    char *p1 = const_cast<char*>(strchr( PSZ(str) + 2, SEP_PATH ));
+    if( p1 == NULL || p1 == PSZ(str) + 2 )
+    {
+      String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+      throw BadPathException(PSZ(strErr), "Bad path", "FileName::MkDir");
+    }
+    // Saute le nom du share
+    p = strchr( p1 + 1, SEP_PATH );
+    if( p == NULL || p == p1 + 1 )
+    {
+      String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+      throw BadPathException(PSZ(strErr), "Bad path", "FileName::MkDir");
+    }
+  }
+  else
+  {
+    p = const_cast<char*>(strchr(PSZ(str), SEP_PATH));
+  }
+#else
+  p = strchr(PSZ(str), SEP_PATH);
+#endif
+
+  if( !p )
+  {
+    String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+    throw BadPathException(PSZ(strErr), "Bad path", "FileName::MkDir");
+  }
+  p = strchr(p+1, SEP_PATH);
+  if( !p )
+  {
+    #ifdef __WIN32__
+      // Check drive
+      if( str[1u] != ':' )
+      {
+        String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+        throw BadDriveException(PSZ(strErr), "Bad path", "FileName::MkDir");
+      }
+
+      if( ::GetDriveType(PSZ(str)) <= 1 )
+      {
+        String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+        throw BadDriveException(PSZ(strErr), "Bad path", "FileName::MkDir");
+      }
+
+    #endif
+    // path = racine ; exist
+    return;
+  }
+
+  do
+  {
+    str[p - PSZ(str)] = '\0';  // *p = 0;
+    struct stat st;
+    if( ::stat(PSZ(str), &st) )
+    {
+      #ifdef __UNIX__
+
+        if( errno != ENOENT )
+          // stat call report error != file not found
+          ThrowExceptionFromErrno(PSZ(StrFormat(ERR_STAT_FAILED, PSZ(str))), "FileName::MkDir");
+        else
+          LogInfo("file", "Create directory '%s'", PSZ(str));
+
+        if( mkdir(PSZ(str), 0000777) )
+        {
+          // failure
+          ThrowExceptionFromErrno(PSZ(StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str))), "FileName::MkDir");
+        }
+
+        // Change access mode if needed
+        if( mode != 0 )
+        {
+          if( chmod(PSZ(str), mode) )
+          {
+            // changing access mode failed
+            ThrowExceptionFromErrno(PSZ(StrFormat(ERR_CHMOD_FAILED, PSZ(str), mode)), "FileName::MkDir");
+          }
+        }
+        // Change owner if needed
+        if( (int)uid != -1 || (int)gid != -1 )
+        {
+          if( chown(PSZ(str), uid, gid) )
+          {
+            // changing owner mode failed
+            ThrowExceptionFromErrno(PSZ(StrFormat(ERR_CHOWN_FAILED, PSZ(str), uid, gid)), "FileName::MkDir");
+          }
+        }
+
+      #else // !__UNIX__
+
+        if( mkdir(PSZ(str)) )
+        {
+          // creation error
+          String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+          throw FileFailureException(PSZ(strErr), "Operation failed", "FileName::MkDir");
+        }
+
+      #endif
+    }
+    else
+    {
+      if( !(st.st_mode & S_IFDIR) )
+      {
+        // c'est un fichier : erreur
+        String strErr = StrFormat(ERR_CANNOT_CREATE_FOLDER, PSZ(str));
+        throw BadPathException(PSZ(strErr), "Path is a file path", "FileName::MkDir");
+      }
+      // Directory : ok
+    }
+    // Next path component
+    str[p - PSZ(str)] = SEP_PATH;   // *p = SEP_PATH;
+    p = strchr(p+1, SEP_PATH);
+  } while( p );
+}
+
+//----------------------------------------------------------------------------
+// FileName::LinkExists
+//----------------------------------------------------------------------------
+bool FileName::LinkExists() const
+{
+#ifdef __LINUX__
+  struct stat st;
+  String strFullName = FullName();
+  if( IsPathName() )
+    strFullName.erase(strFullName.size()-1, 1);
+  int iRc = lstat(PSZ(strFullName), &st);
+  if( !iRc && S_ISLNK(st.st_mode) )
+    return true;
+#endif
+  return false;
+}
+
+//----------------------------------------------------------------------------
+// FileName::MakeSymLink
+//----------------------------------------------------------------------------
+void FileName::MakeSymLink(const String &strTarget, uid_t uid, gid_t gid) const
+{
+#ifdef __LINUX__
+  int iRc = symlink(PSZ(strTarget), PSZ(FullName()));
+  if( iRc )
+  {
+    String strErr = StrFormat(ERR_CANNOT_CREATE_LINK, PSZ(FullName()), PSZ(strTarget));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::MakeSymLink");
+  }
+  // Change owner if needed
+  if( (int)uid != -1 || (int)gid != -1 )
+  {
+    if( lchown(PSZ(FullName()), uid, gid) )
+    {
+      // changing owner mode failed
+      String strErr = StrFormat(ERR_CHOWN_FAILED, PSZ(FullName()), uid, gid);
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::MakeSymLink");
+    }
+  }
+
+#endif
+}
+
+//----------------------------------------------------------------------------
+// FileName::Delete
+//----------------------------------------------------------------------------
+void FileName::Delete()
+{
+  if( !m_strFile.empty() )
+  {
+    LogVerbose("file", "Deleting file '%s'...", PSZ(FullName()));
+    if( unlink(PSZ(FullName())) )
+    {
+      String strErr = StrFormat(ERR_CANNOT_REMOVE_FILE, PSZ(FullName()));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::Delete");
+    }
+  }
+}
+
+//----------------------------------------------------------------------------
+// FileName::Rmdir
+//----------------------------------------------------------------------------
+void FileName::Rmdir(bool bRecursive, bool bContentOnly)
+{
+  if( !IsPathName() )
+    throw BadPathException(PSZ(StrFormat(ERR_DELETE_DIRECTORY, PSZ(FullName()))),
+                           ERR_NOT_A_DIRECTORY, "FileName::Rmdir");
+
+  if( !m_strFile.empty() )
+  {
+    LogVerbose("file", "Deleting content of directory '%s'...", PSZ(FullName()));
+    if( !bRecursive )
+    {
+      if( rmdir(PSZ(FullName())) )
+      {
+        String strErr = StrFormat(ERR_CANNOT_REMOVE_FILE, PSZ(FullName()));
+        ThrowExceptionFromErrno(PSZ(strErr), "FileName::Rmdir");
+      }
+    }
+    else
+    { // Recursively delete directory content
+      FileEnum dirEnum(FullName(), FileEnum::ENUM_DIR);
+      while( dirEnum.Find() )
+        dirEnum.Rmdir(true);
+      // Delete files & symbolic links
+      FileEnum fileEnum(FullName(), FileEnum::ENUM_FILE);
+      while( fileEnum.Find() )
+        fileEnum.Delete();
+
+      if( !bContentOnly )
+      {
+        LogVerbose("file", "Deleting directory '%s'...", PSZ(FullName()));
+        // And finally the direcory himself
+        Rmdir();
+      }
+    }
+  }
+}
+
+//----------------------------------------------------------------------------
+// FileName::Size
+//----------------------------------------------------------------------------
+ulong FileName::Size() const
+{
+#ifdef __WIN32__
+  WIN32_FIND_DATA find;
+  HANDLE h = FindFirstFile(PSZ(m_strFile), &find);
+  if( h == INVALID_HANDLE_VALUE )
+  {
+    String strErr = StrFormat(ERR_CANNOT_FETCH_INFO, PSZ(m_strFile));
+    throw FileFailureException(PSZ(strErr), "Invalid handle", "FileName::Size");
+  }
+  FindClose(h);
+  return (ulong)find.nFileSizeLow;
+#else
+  struct stat sStat;
+  if( stat(PSZ(FullName()), &sStat) == -1 )
+  {
+    String strErr = StrFormat(ERR_CANNOT_FETCH_INFO, PSZ(m_strFile));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::Size");
+  }
+  return sStat.st_size;
+#endif
+}
+
+//----------------------------------------------------------------------------
+// FileName::Size64
+//----------------------------------------------------------------------------
+int64 FileName::Size64() const
+{
+#ifdef __WIN32__
+  WIN32_FIND_DATA find;
+  HANDLE h = FindFirstFile(PSZ(m_strFile), &find);
+  if( h == INVALID_HANDLE_VALUE )
+  {
+    String strErr = StrFormat(ERR_CANNOT_FETCH_INFO, PSZ(m_strFile));
+    throw FileFailureException(PSZ(strErr), "Invalid handle", "FileName::Size");
+  }
+  FindClose(h);
+  return (ulong)find.nFileSizeLow;
+#else
+  struct stat sStat;
+  if( stat(PSZ(FullName()), &sStat) == -1 )
+  {
+    String strErr = StrFormat(ERR_CANNOT_FETCH_INFO, PSZ(m_strFile));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::Size");
+  }
+  return sStat.st_size;
+#endif
+}
+
+//----------------------------------------------------------------------------
+// FileName::Rename
+//----------------------------------------------------------------------------
+void FileName::Rename(const String &strNewName)
+{
+  if( !m_strFile.empty() )
+    if( rename(PSZ(m_strFile), PSZ(strNewName)) )
+    {
+      String strErr = StrFormat(ERR_CANNOT_RENAME_FILE, PSZ(m_strFile));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::Rename");
+    }
+ 
+  // Change internal name
+  Set(strNewName);
+}
+
+//----------------------------------------------------------------------------
+// FileName::ModTime
+//----------------------------------------------------------------------------
+void FileName::ModTime(Time *pTm, bool bLocalTime) const
+{
+#ifdef __WIN32__
+  HANDLE hFile = CreateFile(PSZ(FullName()), GENERIC_READ, FILE_SHARE_READ,
+                           NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+  if( hFile == INVALID_HANDLE_VALUE )
+	{
+      String strErr = StrFormat(ERR_CANNOT_CREATE_WIN32, PSZ(m_strFile));
+      throw FileFailureException(PSZ(strErr), "Invalid handle", "FileName::ModTime");
+	}
+  FILETIME fileTime;
+  GetFileTime(hFile, NULL, NULL, &fileTime);
+  FileTimeToLocalFileTime(&fileTime, &fileTime);
+  CloseHandle(hFile);
+  SYSTEMTIME sysTime;
+  FileTimeToSystemTime(&fileTime, &sysTime);
+  pTm->Set(sysTime.wYear, sysTime.wMonth, sysTime.wDay,
+           sysTime.wHour, sysTime.wMinute, 
+           (double)sysTime.wSecond + sysTime.wMilliseconds/1000.);
+#else
+  struct stat sStat;
+  if( stat(PSZ(FullName()), &sStat) == -1 )
+	{
+      String strErr = StrFormat(ERR_CANNOT_GET_FILE_TIME, PSZ(m_strFile));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::ModTime");
+	}
+  
+  if( bLocalTime )
+  {
+    struct tm tmLocal;       
+    localtime_r(&sStat.st_mtime, &tmLocal);
+    pTm->SetLongUnix(mktime(&tmLocal) + tmLocal.tm_gmtoff);
+  }
+  else
+    pTm->SetLongUnix(sStat.st_mtime);
+
+#endif
+}
+
+//----------------------------------------------------------------------------
+// FileName::SetModTime
+//----------------------------------------------------------------------------
+void FileName::SetModTime(const Time& tm) const
+{
+#ifdef __WIN32__
+  SDateFields sTm;
+  tm.Get(&sTm);
+  SYSTEMTIME sysTime;
+  sysTime.wDay    = (ushort)sTm.uiDay;
+  sysTime.wYear   = (ushort)sTm.iYear;
+  sysTime.wMonth  = (ushort)sTm.uiMonth;
+  sysTime.wHour   = (ushort)sTm.uiHour;
+  sysTime.wMinute = (ushort)sTm.uiMin;
+  sysTime.wSecond = (ushort)sTm.dSec;
+  sysTime.wMilliseconds = (ushort)((long)(sTm.dSec*1000) % 1000);
+  FILETIME fileTime;
+  SystemTimeToFileTime(&sysTime, &fileTime);
+  LocalFileTimeToFileTime(&fileTime, &fileTime);
+
+  int iAttribute;
+  // In order to modify a directory date under Win32, we have to position the correct flag
+  // otherwise windows returns a invalid handle.
+  // Then we can call SetFileTime even if the handle is not a file handle 
+  if( IsPathName() )
+    iAttribute = FILE_FLAG_BACKUP_SEMANTICS;
+  else 
+    iAttribute = FILE_ATTRIBUTE_NORMAL;
+  
+  HANDLE hFile = CreateFile(PSZ(FullName()), GENERIC_WRITE,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE,
+                            NULL, OPEN_EXISTING, iAttribute, NULL);
+    
+  if( hFile == INVALID_HANDLE_VALUE )
+	{
+      String strErr = StrFormat(ERR_CANNOT_CREATE_WIN32, PSZ(m_strFile));
+      throw FileFailureException(PSZ(strErr), "Invalid handle", "FileName::SetModTime");
+	}
+  if( !SetFileTime(hFile, NULL, NULL, &fileTime) )
+	{
+      CloseHandle(hFile);
+      String strErr = StrFormat(ERR_CANNOT_CHANGE_FILE_TIME, PSZ(m_strFile));
+      throw FileFailureException(PSZ(strErr), "Operation failed", "FileName::SetModTime");
+	}
+  CloseHandle(hFile);
+
+#else
+  struct utimbuf sTm;
+  struct stat sStat;
+
+  if( stat(PSZ(FullName()), &sStat) != -1 )
+    // Get access time, in order to preserve it
+    sTm.actime = sStat.st_atime;
+  else
+    // stat function failed, use the new mod time
+    sTm.actime = tm.LongUnix();
+
+  sTm.modtime = tm.LongUnix();
+  if( utime(PSZ(FullName()), &sTm) )
+	{
+      String strErr = StrFormat(ERR_CANNOT_CHANGE_FILE_TIME, PSZ(m_strFile));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::SetModTime");
+	}
+
+#endif
+}
+
+// 1Mo
+#define MAX_SIZE  1048576LL
+//-------------------------------------------------------------------
+// FileName::Copy
+//-------------------------------------------------------------------
+void FileName::Copy(const String &strDst, bool bKeepMetaData)
+{
+  LogVerbose("file", "Copying file '%s' to '%s'...", PSZ(FullName()), PSZ(strDst));
+  if( bKeepMetaData )
+    LogVerbose("file", "Keep Metadata");
+
+  if( !FileExists() )
+  { // File doesn't exists
+      String strErr = StrFormat(ERR_FILE_NOT_FOUND, PSZ(m_strFile));
+      throw FileNotFoundException(PSZ(strErr), "File not found", "FileName::Copy");
+  }
+
+  FileName fDst(strDst);
+  if( fDst.IsPathName() )
+    // Take source name
+    fDst.Set(fDst.Path(), NameExt());
+
+  LogVerbose("file", "Destination file is '%s'", PSZ(fDst.FullName()));
+
+#ifdef __WIN32__
+  if (!CopyFile(PSZ(FullName()), PSZ(fDst.FullName()), FALSE))
+  {
+    String strErr = StrFormat(ERR_COPY_FAILED, PSZ(FullName()), PSZ(fDst.FullName()), (long)GetLastError());
+    throw FileFailureException(PSZ(strErr), "Operation failed", "FileName::Copy");
+  }
+#else
+
+  // Self copy ?
+  if( FullName().IsEquals(fDst.FullName()) )
+  {
+    String strErr = StrFormat(ERR_COPY_FAILED, PSZ(FullName()), PSZ(fDst.FullName()));
+    throw FileFailureException(PSZ(strErr), "Operation failed", "FileName::Copy");
+  }
+
+  struct stat st;
+  if( bKeepMetaData && IsRoot() )
+  {
+    int iRc = stat(PSZ(FullName()), &st);
+    if( iRc )
+    {
+      String strErr = StrFormat(ERR_COPY_FAILED, PSZ(FullName()), PSZ(fDst.FullName()));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::Copy");
+    }
+
+  }
+
+  // Open source file
+  FILE *fiSrc = fopen(PSZ(FullName()), "r");
+  if( NULL == fiSrc )
+  {
+    String strErr = StrFormat(ERR_OPEN_FILE, PSZ(FullName()));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::Copy");
+  }
+
+  // Buffer
+  char aBuf[MAX_SIZE];
+
+  // Get last modified time
+  Time tmLastMod;
+  ModTime(&tmLastMod);
+  
+  // Opens destination file
+  FILE *fiDst = fopen(PSZ(fDst.FullName()), "w");
+  if( NULL == fiDst )
+  {
+    String strErr = StrFormat(ERR_OPEN_FILE, PSZ(fDst.FullName()));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::Copy");
+  }
+  
+  // Copy by blocs
+  int64 llSize = Size64();
+  long lReaded=0, lWritten=0;
+  while( llSize )
+  {
+    long lToRead = 0;
+
+    if( llSize > MAX_SIZE )
+      lToRead = MAX_SIZE;
+    else
+      lToRead = (long)llSize;
+      
+    lReaded = fread(aBuf, 1, lToRead, fiSrc);
+    if( ferror(fiSrc) )
+    {
+      String strErr = StrFormat(ERR_READING_FILE, PSZ(FullName()));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::Copy");
+    }
+	
+    lWritten = fwrite(aBuf, 1, lToRead, fiDst);
+    if( ferror(fiDst) || lWritten != lReaded )
+    {
+      String strErr = StrFormat(ERR_WRITING_FILE, PSZ(fDst.FullName()));
+      ThrowExceptionFromErrno(PSZ(strErr), "FileName::Copy");
+    }
+    
+    llSize -= lReaded;
+  }
+
+  fclose(fiSrc);
+  fclose(fiDst);
+
+  // Copy last modifitation date
+  fDst.SetModTime(tmLastMod);
+
+  // Copy file metadata: access mode, owner & group
+  if( bKeepMetaData && IsRoot() )
+  {
+    fDst.Chown(st.st_uid, st.st_gid);
+    fDst.Chmod(st.st_mode);
+  }
+#endif // !WIN32
+}
+
+//-------------------------------------------------------------------
+// FileName::DirCopy
+//-------------------------------------------------------------------
+void FileName::DirCopy(const String &strDest, bool bCreateDir, mode_t modeDir, uid_t uid, gid_t gid)
+{
+  LogVerbose("file", "Copying directory '%s' to '%s'...", PSZ(FullName()), PSZ(strDest));
+  LogVerbose("file", "Set directory mode '%o'", modeDir);
+  LogVerbose("file", "Set ownership to %d:%d", uid, gid);
+  FileName fnDst;
+
+  // Create destination path
+  fnDst.Set(strDest);
+  fnDst.MkDir(modeDir, uid, gid);
+
+  if( bCreateDir )
+  {
+    // Create source directory name inside destination path
+    fnDst.Set(strDest + DirName() + SEP_PATH);
+    fnDst.MkDir(modeDir, uid, gid);
+  }
+
+  if( !fnDst.IsPathName() )
+    throw BadPathException(PSZ(StrFormat(ERR_BAD_DEST_PATH, PSZ(fnDst.FullName()))),
+                           ERR_NOT_A_DIRECTORY, "FileName::DirCopy");
+
+  // Recursively copying sub-directories
+  FileEnum dirEnum(FullName(), FileEnum::ENUM_DIR);
+  while( dirEnum.Find() )
+    dirEnum.DirCopy(fnDst.Path(), true, modeDir, uid, gid);
+
+  // Copying directory files
+  FileEnum fileEnum(FullName(), FileEnum::ENUM_FILE);
+  while( fileEnum.Find() )
+    // Copy with metadata
+    fileEnum.Copy(fnDst.Path(), true);
+}
+
+//-------------------------------------------------------------------
+// FileName::RecursiveChmod
+//-------------------------------------------------------------------
+void FileName::RecursiveChmod(mode_t modeFile, mode_t modeDir, bool bCurrentLevel)
+{
+  LogVerbose("file", "Recursively set access mode for content of directory '%s'...", PSZ(FullName()));
+  LogVerbose("file", "Set file mode to '%o'", modeFile);
+  LogVerbose("file", "Set directory mode '%o'", modeDir);
+
+  if( !PathExists() )
+  { // File doesn't exists
+    String strErr = StrFormat(ERR_DIR_NOT_FOUND, PSZ(FullName()));
+    throw FileNotFoundException(PSZ(strErr), "Directory not found", "FileName::RecursiveChmod");
+  }
+
+  // Recursively change rights on sub-directories
+  FileEnum dirEnum(FullName(), FileEnum::ENUM_DIR);
+  while( dirEnum.Find() )
+    dirEnum.RecursiveChmod(modeFile, modeDir, true);
+
+  // Change mode on files
+  FileEnum fileEnum(FullName(), FileEnum::ENUM_FILE);
+  while( fileEnum.Find() )
+    // Copy with metadata
+    fileEnum.Chmod(modeFile);
+
+  if( bCurrentLevel )
+    // Change mode to directory itself
+    Chmod(modeDir);
+}
+
+//-------------------------------------------------------------------
+// FileName::RecursiveChmodFile
+//-------------------------------------------------------------------
+void FileName::RecursiveChmodFile(mode_t mode)
+{
+  LogVerbose("file", "Recusrsively set access mode for directory '%s' to '%o'...", PSZ(FullName()), mode);
+
+  if( !PathExists() )
+  { // File doesn't exists
+    String strErr = StrFormat(ERR_DIR_NOT_FOUND, PSZ(FullName()));
+    throw FileNotFoundException(PSZ(strErr), "Directory not found", "FileName::RecursiveChmodFile");
+  }
+
+  // Recursively change rights on sub-directories
+  FileEnum dirEnum(FullName(), FileEnum::ENUM_DIR);
+  while( dirEnum.Find() )
+    dirEnum.RecursiveChmodFile(mode);
+
+  // Change mode on files
+  FileEnum fileEnum(FullName(), FileEnum::ENUM_FILE);
+  while( fileEnum.Find() )
+    // Copy with metadata
+    fileEnum.Chmod(mode);
+}
+
+//-------------------------------------------------------------------
+// FileName::RecursiveChmodDir
+//-------------------------------------------------------------------
+void FileName::RecursiveChmodDir(mode_t mode)
+{
+  LogVerbose("file", "Recusrsively set access mode for directory '%s' to '%o'...", PSZ(FullName()), mode);
+
+  if( !PathExists() )
+  { // File doesn't exists
+    String strErr = StrFormat(ERR_DIR_NOT_FOUND, PSZ(FullName()));
+    throw FileNotFoundException(PSZ(strErr), "Directory not found", "FileName::RecursiveChmodDir");
+  }
+
+  // Recursively change rights on sub-directories
+  FileEnum dirEnum(FullName(), FileEnum::ENUM_DIR);
+  while( dirEnum.Find() )
+    dirEnum.RecursiveChmodDir(mode);
+
+  // Change mode to directory itself
+  Chmod(mode);
+}
+
+//-------------------------------------------------------------------
+// FileName::RecursiveChown
+//-------------------------------------------------------------------
+void FileName::RecursiveChown(uid_t uid, gid_t gid)
+{
+  LogVerbose("file", "Recursively set owner mode for directory '%s' to '%d':'%d'...", PSZ(FullName()), uid, gid);
+
+  if( !PathExists() )
+  { // File doesn't exists
+    String strErr = StrFormat(ERR_DIR_NOT_FOUND, PSZ(FullName()));
+    throw FileNotFoundException(PSZ(strErr), "Directory not found", "FileName::RecursiveChmod");
+  }
+
+  // Recursively change rights on sub-directories
+  FileEnum dirEnum(FullName(), FileEnum::ENUM_DIR);
+  while( dirEnum.Find() )
+    dirEnum.RecursiveChown(uid, gid);
+
+  // Change mode on files
+  FileEnum fileEnum(FullName(), FileEnum::ENUM_FILE);
+  while( fileEnum.Find() )
+    // Copy with metadata
+    fileEnum.Chown(uid, gid);
+
+  // Change mode to directory itself
+  Chown(uid, gid);
+}
+
+//-------------------------------------------------------------------
+// FileName::Move
+//-------------------------------------------------------------------
+void FileName::Move(const String &strDest)
+{
+  if( !FileExists() )
+  { // File doesn't exists
+      String strErr = StrFormat(ERR_FILE_NOT_FOUND, PSZ(m_strFile));
+      throw FileNotFoundException(PSZ(strErr), "File not found", "FileName::Move");
+  }
+
+  FileName fDst(strDest);
+  if( fDst.IsPathName() )
+    // Take source name
+    fDst.Set(fDst.Path(), NameExt());
+
+  // Remove destination
+  if( fDst.FileExists() )
+    fDst.Delete();
+
+#ifdef __UNIX__
+  // Check filesystem id, if it's the same, we can try to rename file
+  fsid_t idSrc = FileSystemId();
+  fsid_t idDst = fDst.FileSystemId();
+  if( idSrc.__val[0] == idDst.__val[0] && idSrc.__val[1] == idDst.__val[1] )
+  {
+    try
+    {
+      CErrorStack::SetIgnoreErrors();
+      Rename(fDst.FullName());
+      CErrorStack::SetIgnoreErrors(false);
+    }
+    catch( FileFailureException e )
+    {
+      CErrorStack::SetIgnoreErrors(false);
+      // Unable to rename => make a copy
+      Copy(fDst.FullName(), true);
+
+      // Deletes source file and changes name
+      Delete();
+      Set(fDst.FullName());
+    }
+  }
+  else
+#endif
+  {
+    CErrorStack::SetIgnoreErrors(false);
+    Copy(fDst.FullName(), true);
+
+    // Deletes source file and changes name
+    Delete();
+    Set(fDst.FullName());
+  }
+}
+
+//-------------------------------------------------------------------
+// FileName::FileSystemType
+//-------------------------------------------------------------------
+FileName::FSType FileName::FileSystemType() const
+{
+#ifdef __UNIX__
+  struct statfs buf;
+  int iRc = statfs(PSZ(Path()), &buf);
+  if( iRc )
+  {
+    String strErr = StrFormat(ERR_FSTYPE, PSZ(Path()));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::FileSystemType");
+  }
+  return FSType(buf.f_type);
+  
+#else
+  // Not implemented yet on windows
+  return FSType(MS);
+#endif
+
+}
+
+//-------------------------------------------------------------------
+// FileName::FileSystemId
+//-------------------------------------------------------------------
+fsid_t FileName::FileSystemId() const
+{
+#ifdef __UNIX__
+  struct statfs buf;
+  int iRc = statfs(PSZ(Path()), &buf);
+  if( iRc )
+  {
+    String strErr = StrFormat(ERR_FSTYPE, PSZ(Path()));
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::FileSystemType");
+  }
+  return buf.f_fsid;
+  
+#else
+  // Not implemented yet on windows
+  return 0;
+#endif
+
+}
+
+//-------------------------------------------------------------------
+// FileName::Chmod
+//-------------------------------------------------------------------
+void FileName::Chmod(mode_t mode)
+{
+  LogVerbose("file", "Set access mode for '%s' to '%o'...", PSZ(FullName()), mode);
+
+#ifdef __UNIX__
+  int iRc = chmod(PSZ(FullName()), mode);
+  if( iRc )
+  {
+    String strErr = StrFormat(ERR_CHMOD_FAILED, PSZ(FullName()), mode);
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::Chmod");
+  }
+#else
+  // Not implemented yet on windows
+#endif
+}
+
+//-------------------------------------------------------------------
+// FileName::Chown
+//-------------------------------------------------------------------
+void FileName::Chown(uid_t uid, gid_t gid)
+{
+  LogVerbose("file", "Set owner mode for '%s' to '%d:%d'...", PSZ(FullName()), uid, gid);
+#ifdef __UNIX__
+  int iRc = chown(PSZ(FullName()), uid, gid);
+  if( iRc )
+  {
+    String strErr = StrFormat(ERR_CHOWN_FAILED, PSZ(FullName()), uid, gid);
+    ThrowExceptionFromErrno(PSZ(strErr), "FileName::Chown");
+  }
+#else
+  // Not implemented yet on windows
+#endif
+}
+
+//-------------------------------------------------------------------
+// FileName::ThrowExceptionFromErrno
+//-------------------------------------------------------------------
+void FileName::ThrowExceptionFromErrno(const char *pszError, const char *pszMethod) const
+{
+#ifdef __UNIX__
+  switch( errno )
+  {
+    case EIO:
+      throw IOException(pszError, strerror(errno), pszMethod);
+    case EPERM:
+    case EACCES:
+    case EROFS:
+      throw PermissionException(pszError, strerror(errno), pszMethod);
+    case ENOTEMPTY:
+      throw BadPathConditionException(pszError, strerror(errno), pszMethod);
+    case ENAMETOOLONG:
+    case ELOOP:
+    case EISDIR:
+    case ENOTDIR:
+      throw BadPathException(pszError, strerror(errno), pszMethod);
+    case ENOENT:
+      throw FileNotFoundException(pszError, strerror(errno), pszMethod);
+    default:
+      throw FileFailureException(pszError, strerror(errno), pszMethod);     
+  }
+#else
+      throw FileFailureException(pszError, "IO error", pszMethod);     
+#endif
+}
+
+//===========================================================================
+// Class FileEnum
+//===========================================================================
+
+#ifdef __UNIX__
+
+//-------------------------------------------------------------------
+// Initialisation
+//-------------------------------------------------------------------
+FileEnum::FileEnum(const String &strPath, EEnumMode eMode)
+{
+  m_dirDir = NULL;
+  Init(strPath, eMode);
+}
+//-------------------------------------------------------------------
+// Destructeur
+//-------------------------------------------------------------------
+FileEnum::~FileEnum()
+{
+  Close();
+}
+
+//-------------------------------------------------------------------
+// FileEnum::Init
+//-------------------------------------------------------------------
+void FileEnum::Init(const String &strPath, EEnumMode eMode)
+{
+  Close();
+  m_eMode = eMode;
+  Set(PSZ(strPath));
+  
+  // Initialize enumeration
+  m_dirDir = opendir(PSZ(Path()));
+  if( NULL == m_dirDir )
+  {
+    String strErr = StrFormat(ERR_CANNOT_ENUM_DIR, PSZ(Path()));
+    throw BadPathException(PSZ(strErr), "Bad path", "FileEnum::Init");
+  }
+  m_strPath = strPath; // Save initial path.
+}
+
+//-------------------------------------------------------------------
+// FileEnum::Find
+//-------------------------------------------------------------------
+bool FileEnum::Find()
+{
+  struct dirent *dirEntry;
+  String str;
+  while( (dirEntry = readdir(m_dirDir)) != NULL )
+  {
+    str = dirEntry->d_name;
+    if( IsEquals(str, ".") == false && IsEquals(str, "..") == false )
+    {
+      // Set new file name
+      Set(m_strPath, dirEntry->d_name);
+
+      // Check file
+      if( (m_eMode & ENUM_FILE) && FileExists() )
+        return true;
+      if( (m_eMode & ENUM_DIR) && PathExists() )
+        return true;
+    }
+  }
+
+  // Not found
+  return false;
+}
+
+void FileEnum::Close()
+{
+  if(m_dirDir)
+    closedir(m_dirDir);
+}
+ 
+#elif defined(__WIN32__)
+
+//-------------------------------------------------------------------
+// FileEnum::FileEnum
+//-------------------------------------------------------------------
+FileEnum::FileEnum(const String &strPath, EEnumMode eMode)
+{
+  // Dynamic allocation of WIN32_FIND_DATA => no need to include winbase.h
+  m_pfindData = new WIN32_FIND_DATA;
+
+  m_bFirst = true;
+  m_hFind = INVALID_HANDLE_VALUE;
+  Init(strPath, eMode);
+}
+
+//-------------------------------------------------------------------
+// FileEnum::~FileEnum
+//-------------------------------------------------------------------
+FileEnum::~FileEnum()
+{
+  Close();
+  delete m_pfindData;
+}
+
+//-------------------------------------------------------------------
+// FileEnum::Init
+//-------------------------------------------------------------------
+void FileEnum::Init(const String &strPath, EEnumMode eMode)
+{
+  Close();
+  m_eMode = eMode;
+  m_strPath = strPath;
+  m_strFile = strPath;
+}
+
+//-------------------------------------------------------------------
+// FileEnum::Find()
+//-------------------------------------------------------------------
+bool FileEnum::Find()
+{
+  String str;
+
+  while(true)
+  {
+    if( m_bFirst )
+    {
+      str = Path();
+      str += '*' ;
+      m_hFind = (HANDLE)FindFirstFile(PSZ(str), (WIN32_FIND_DATA *)m_pfindData);
+      if( m_hFind == INVALID_HANDLE_VALUE )
+        // not fount
+        return false;
+      m_bFirst = false;
+    }
+    else if( !FindNextFile((HANDLE)m_hFind, (WIN32_FIND_DATA *)m_pfindData) )
+      // not found
+      return false;
+
+    str = ((WIN32_FIND_DATA *)m_pfindData)->cFileName;
+    if( IsEquals(str, ".") == false && IsEquals(str, "..") == false )
+    {
+      // Set new file name
+      Set(m_strPath, str);
+
+      // Check file type
+      if( (m_eMode & ENUM_FILE) &&
+          !(((WIN32_FIND_DATA *)m_pfindData)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
+        return true;
+
+      // Add directory separator if needed
+      if( (m_eMode & ENUM_DIR) &&
+          (((WIN32_FIND_DATA *)m_pfindData)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
+      {
+        if( !IsSepPath(m_strFile[m_strFile.size()-1]) )
+          m_strFile += (char)SEP_PATH;
+        return true;
+      }
+    }
+  }
+}
+
+void FileEnum::Close()
+{
+   if( m_hFind != INVALID_HANDLE_VALUE )
+   {
+     FindClose((HANDLE)m_hFind);
+     m_hFind = INVALID_HANDLE_VALUE;
+   }
+   m_bFirst = true;
+}
+#endif
+
+//===========================================================================
+// Class TempFileName
+//===========================================================================
+long TempFileName::s_lLastNumber = 0;
+
+//-------------------------------------------------------------------
+// TempFileName::GenerateRandomName
+//-------------------------------------------------------------------
+String TempFileName::GenerateRandomName()
+{
+  if( !s_lLastNumber )
+    // Initialize random sequence
+    s_lLastNumber = CurrentTime().LongUnix();
+
+  return StrFormat("temp%lx", s_lLastNumber++);
+}
+
+//-------------------------------------------------------------------
+// TempFileName::TempFileName
+//-------------------------------------------------------------------
+TempFileName::TempFileName()
+{
+#ifdef __WIN32__
+  Set("C:\\Temp", GenerateRandomName());
+#else
+  Set("/tmp", GenerateRandomName());
+#endif
+}
+
+//-------------------------------------------------------------------
+// TempFileName::TempFileName(path)
+//-------------------------------------------------------------------
+TempFileName::TempFileName(const String &strPath)
+{
+  Set(strPath, GenerateRandomName());
+}
+
+//===========================================================================
+// Class File
+//===========================================================================
+
+//-------------------------------------------------------------------
+// File::Load
+//-------------------------------------------------------------------
+void File::Load(MemBuf *pBuf)
+{
+  // Open source file
+  FILE *fi = fopen(PSZ(FullName()), "r");
+  if( NULL == fi )
+  {
+    String strErr = StrFormat(ERR_OPEN_FILE, PSZ(FullName()));
+    throw FileFailureException(PSZ(strErr), "Operation failed", "File::Load");
+  }
+
+  // Buffer
+  pBuf->SetLen(Size()+1);
+
+  // Read
+  long lSize = Size();
+  long lReaded = fread(pBuf->Buf(), 1, lSize, fi);
+  if( ferror(fi) || lSize != lReaded )
+  {
+    String strErr = StrFormat(ERR_READING_FILE, PSZ(FullName()));
+    throw FileFailureException(PSZ(strErr), "Operation failed", "File::Load");
+  }
+  memset(pBuf->Buf() + lSize, 0, 1);
+  fclose(fi);
+}
+void File::Load(String *pString)
+{
+  MemBuf buf;
+  Load(&buf);
+  buf >> (*pString);
+}
+
+//-------------------------------------------------------------------
+// File::Save
+//-------------------------------------------------------------------
+void File::Save(const String &strContent)
+{
+  // Open destination file
+  FILE *fi = fopen(PSZ(FullName()), "wb");
+  if( NULL == fi )
+  {
+    String strErr = StrFormat(ERR_OPEN_FILE, PSZ(FullName()));
+    throw FileFailureException(PSZ(strErr), "Operation failed", "File::Load");
+  }
+
+  // Write text content
+  int iRc = fputs(PSZ(strContent), fi);
+  if( EOF == iRc )
+  {
+    String strErr;
+    strErr.Printf("Cannot write in file '%s'", PSZ(FullName()));
+    throw FileFailureException(PSZ(strErr), "Operation failed", "File::Save");
+  }
+  fclose(fi);
+}
diff --git a/contrib/applications/NXextract/src/file.h b/contrib/applications/NXextract/src/file.h
new file mode 100644
index 0000000..b976c8b
--- /dev/null
+++ b/contrib/applications/NXextract/src/file.h
@@ -0,0 +1,478 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Files manipulations
+//
+// Cr�ation : 25/05/2005
+// Auteur   : S. Poirier
+//
+//*****************************************************************************
+
+#ifndef __FILE_H__
+#define __FILE_H__
+
+#ifndef __BASE_H__
+  #include "base.h"
+#endif
+
+#ifndef __DATE_H__
+  #include "date.h"
+#endif
+
+#ifndef __MEMBUF_H__
+  #include "membuf.h"
+#endif
+
+#if defined(_MSC_VER)
+  #include <sys\utime.h>
+#else
+  #include <utime.h>
+#endif
+
+#if defined (__WIN32__) && !defined(_CSTDIO_)
+  #include <cstdio>
+#endif
+
+#ifdef __UNIX__
+	#include <dirent.h>
+  #include <unistd.h>
+  #include <sys/stat.h>
+  #include <errno.h>
+  #include <sys/vfs.h>
+#else
+  #include <sys\stat.h>
+  #include <ctype.h>
+  #include <direct.h>
+  #include <errno.h>
+  #ifdef __WIN32__
+    #include <windows.h>
+  #endif
+#endif
+
+namespace gdshare
+{
+
+#define SEP_PATHDOS     '\\'
+#define SEP_PATHUNIX    '/'
+#ifdef __UNIX__
+  #define SEP_PATH      SEP_PATHUNIX
+#else
+  #define SEP_PATH      SEP_PATHDOS
+#endif
+#define SEP_EXT         '.'
+#define SEP_DSK         ':'
+
+#ifndef _MAX_PATH
+  #define _MAX_PATH 260
+#endif
+
+//=============================================================================
+// Free functions
+//=============================================================================
+
+/// Check for a path (pszPath peut etre termine ou non par un /)
+///
+/// @param pcszPath Path to check, can be ended by a '/'
+///
+bool PathExists(pcsz pcszPath);
+
+/// Check for a file
+///
+/// @param pcszPath File to check
+bool FileExists(pcsz pcszFullName);
+
+/// Get access mode from a string in the form "rwxrwxrwx"
+///
+/// @param strAccess Input string
+mode_t AccessFromString(const String &strAccess);
+
+
+/// Make symbolic link
+///
+/// @param strFileName opbject to link
+int MakeLink(const String &strLink, const String &strTarget);
+
+//=============================================================================
+///
+/// Exceptions
+///
+//=============================================================================
+class FileException : public ExceptionBase
+{
+protected:
+  const char *ErrorTitle()
+  {
+    return "File Exception: ";
+  }
+
+public:
+  FileException(const char *pcszError=NULL, const char *pcszReason=NULL, const char *pcszMethod=NULL):
+  ExceptionBase(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+///
+/// Exceptions
+///
+//=============================================================================
+class IOException : public FileException
+{
+public:
+  IOException(const char *pcszError=NULL, const char *pcszReason=NULL, const char *pcszMethod=NULL):
+  FileException(pcszError, pcszReason, pcszMethod)
+  {  }
+};
+
+//=============================================================================
+///
+/// creating, accessing file/folder failure
+///
+//=============================================================================
+class FileFailureException : public FileException
+{
+public:
+  FileFailureException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  FileException(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+///
+/// Bad path specification
+///
+//=============================================================================
+class BadPathException : public FileException
+{
+public:
+  BadPathException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  FileException(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+///
+/// Current conditions doesn't allow to perform the action
+///
+//=============================================================================
+class BadPathConditionException : public FileException
+{
+public:
+  BadPathConditionException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  FileException(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+///
+/// Path or file not found
+///
+//=============================================================================
+class FileNotFoundException : public FileException
+{
+public:
+  FileNotFoundException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  FileException(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+///
+/// Permission
+///
+//=============================================================================
+class PermissionException : public FileException
+{
+public:
+  PermissionException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  FileException(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+//=============================================================================
+///
+/// bad drive name
+///
+//=============================================================================
+class BadDriveException : public FileException
+{
+public:
+  BadDriveException(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+  FileException(pcszError, pcszReason, pcszMethod)
+  { }
+};
+
+
+//============================================================================
+/// Free function
+//============================================================================
+inline int IsSepPath(char c)
+ { return c == SEP_PATHDOS || c == SEP_PATHUNIX; }
+
+//============================================================================
+/// Classe FileName
+///
+/// File name manipulations
+//============================================================================
+class FileName
+{
+protected:
+  String m_strFile;  /// File name
+public:
+  
+  // File system types
+  enum FSType
+  {
+    // Defaut value for Microsoft partition type
+    MS = 0,
+
+    // Microsoft partitions types
+    FAT16 = 0x04,
+    FAT32 = 0x0B,
+    IFS = 0x07,
+    
+    // Unix file system types
+    AFFS = 0xADFF,
+    EFS = 0x00414A53,
+    EXT = 0x137D,
+    EXT2 = 0xEF53,
+    HPFS = 0xF995E849,
+    ISOFS = 0x9660,
+    MSDOS = 0x4d44,
+    NFS = 0x6969,
+    PROC = 0x9fa0,
+    SMB = 0x517B
+  };
+
+private:
+
+  void ThrowExceptionFromErrno(const char *pszError, const char *pszMethod) const;
+
+public:
+  /// Constructor
+  FileName()
+  { }
+  FileName(const String &strFileName)
+  { Set(strFileName); }
+  FileName(const String &strPath, const String &strName)
+  { Set(strPath, strName); }
+
+  /// Returns true if the filename is a path
+  bool IsPathName() const;
+
+  /// Returns true if the file name is a existing path
+  bool PathExists() const;
+
+  /// Returns true if file exists
+  bool FileExists() const;
+
+  /// Set file name
+  /// Convert separators
+  void Set(const String &strFullName);
+  void Set(const String &strPath, const String &strName);
+  void Set(const String &strPath, const String &strName, const  String &strExt);
+
+  void SetFullName(pcsz pszFileName);
+
+  /// Convert separator according to the current operating system
+  static void ConvertSeparators(String *pstr);
+
+  /// Return full name
+  const String &FullName() const { return m_strFile; }
+
+  /// Return path
+  String Path() const;
+
+  /// Return filename without path and extension
+  String Name() const;
+
+  /// Return directory name (last path component before file name)
+  String DirName() const;
+
+  /// Return filename relative to specified path
+  String RelName(const char* pszPath) const;
+
+  /// Return filename without path
+  String NameExt() const;
+
+  /// Return extension
+  String Ext() const;
+
+  /// Create directory
+  void MkDir(mode_t mode = 0, uid_t uid = (uid_t)-1, gid_t gid = (uid_t)-1) const;
+
+  /// Return true the file name is a existing link
+  bool LinkExists() const;
+
+  /// Make a symbolic link
+  void MakeSymLink(const String &strTarget, uid_t uid = (uid_t)-1, gid_t gid = (uid_t)-1) const;
+
+  /// Delete file
+  void Delete();
+
+  /// Remove directory
+  void Rmdir(bool bRecursive=false, bool bContentOnly=false);
+
+  /// Copy a directory and its whole content inside the destination dir
+  /// if bCreateDir is false the destination directory must already exists
+  void DirCopy(const String &strDest, bool bCreateDir=false, mode_t modeDir = 0, uid_t uid = (uid_t)-1, gid_t gid = (uid_t)-1);
+
+  /// Return size in octets
+  ulong Size() const;
+
+  /// Return size in octets: 64bits version for files bigger than 2GB
+  int64 Size64() const;
+  
+  /// Rename the file
+  void Rename(const String &strNewName);
+  
+  /// Copy the file to the specified destination with given 
+  void Copy(const String &strDest, bool bKeepMetaData=false);
+  
+  /// Move file
+  void Move(const String &strDest);
+
+  // Returns last modification date & time
+  void ModTime(Time *pTm, bool bLocalTime=false) const;
+
+  // Sets last modification date & time
+  void SetModTime(const Time& tm) const;
+
+  /// Change file rights
+  void Chmod(mode_t mode);
+
+  /// Recursively change rights for directory and files
+  void RecursiveChmod(mode_t modeFile, mode_t modeDir, bool bCurrentLevel=true);
+
+  /// Recursively change directory rights
+  void RecursiveChmodDir(mode_t mode);
+
+  /// Recursively change file rights
+  void RecursiveChmodFile(mode_t mode);
+
+  /// Change file owner
+  void Chown(uid_t uid, gid_t gid = (uid_t)-1);
+
+  /// Recursively change file owner
+  void RecursiveChown(uid_t uid, gid_t gid = (uid_t)-1);
+
+  // Returns filesystem type
+  FSType FileSystemType() const;
+
+  // Returns filesystem type
+  fsid_t FileSystemId() const;
+};
+
+///===========================================================================
+/// Classe File
+///
+/// Name for temporary file
+///===========================================================================
+class File: public FileName
+{
+  public:
+  File()
+  { }
+  File(const String &strFileName)
+  { Set(strFileName); }
+  File(const String &strPath, const String &strName)
+  { Set(strPath, strName); }
+
+  // Load file to the given MemBuf object
+  void Load(MemBuf *pMemBuf);
+
+  // Load file to the given String
+  void Load(String *pString);
+
+  // Save file from the given String
+  void Save(const String &strContent);
+};
+
+
+///===========================================================================
+/// Classe TempFileName
+///
+/// Name for temporary file
+///===========================================================================
+class TempFileName : public FileName
+{
+private:
+  static long s_lLastNumber;
+
+  // Generate file name
+  String GenerateRandomName();
+
+public:
+  /// Constructors
+  TempFileName();
+  TempFileName(const String &strPath);
+};  
+
+///===========================================================================
+/// Classe FileEnum
+///
+/// Enumerate all file of a given path
+///===========================================================================
+class FileEnum : public FileName
+{
+public:
+  enum EEnumMode
+  {
+     ENUM_FILE = 1,
+     ENUM_DIR = 2,
+     ENUM_ALL = 3
+  };
+
+protected: 
+
+  EEnumMode m_eMode;  // Find mode (FILE or DIR)
+
+#ifdef __UNIX__
+  DIR *m_dirDir;
+#else
+  #ifdef __WIN32__
+    void* m_hFind;
+    /// WIN32_FIND_DATA pointer
+    void* m_pfindData;
+    /// Indicate if a error occured since last find action
+    int m_bErrorOnLastFind;
+  #else
+    struct find_t mscDir;
+  #endif
+  bool m_bFirst;
+#endif
+
+  /// Path
+  String m_strPath;    
+
+public:
+  ///-------------------------------------------------------------------------
+  /// @group Constructeur/Destructeur
+  ///-------------------------------------------------------------------------
+
+  FileEnum(const String &strPath, EEnumMode eMode=ENUM_FILE);
+  ~FileEnum();
+
+  ///-------------------------------------------------------------------------
+  /// @group M�thodes standards
+  ///-------------------------------------------------------------------------
+
+  /// Initializing search mask
+  /// 
+  /// @param strPath Path to enumerate
+  /// @param eMode enum mode: ENUM_FILE => files, ENUM_DIR => directories, ENUM_ALL => files & directories
+  void Init(const String &strPath, EEnumMode eMode=ENUM_FILE);
+
+  /// Find next file
+  /// @param pointer to a string to put the file name
+  /// @return true if a file has been found, false if not
+  bool Find();
+
+  // Ferme enumeration
+  void Close();
+};
+
+
+}
+
+#endif
diff --git a/contrib/applications/NXextract/src/jpegwrap.cpp b/contrib/applications/NXextract/src/jpegwrap.cpp
new file mode 100644
index 0000000..aa5af83
--- /dev/null
+++ b/contrib/applications/NXextract/src/jpegwrap.cpp
@@ -0,0 +1,252 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 01/12/2006
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
+#include "base.h"
+#include "file.h"
+#include "membuf.h"
+#include "jpegwrap.h"
+
+using namespace soleil;
+//=============================================================================
+// JpegEncoder
+//=============================================================================
+
+/// Declaration of static map between jpeg_compress_struct and DestMemBuf object pointers
+map<struct jpeg_compress_struct *, class JpegEncoder::DestMemBuf *> JpegEncoder::s_mapCinfoToOutput;
+
+//------------------------------------------------------------------------
+// JpegEncoder::EncodeGrayScaleToFile
+//------------------------------------------------------------------------
+void JpegEncoder::EncodeGrayScaleToFile(MemBufPtr ptrMembuf, const String &strOutputFile)
+{
+  // Allocate jpeg structures
+  struct jpeg_compress_struct cinfo;
+	struct jpeg_error_mgr jerr;
+  cinfo.err = jpeg_std_error(&jerr);
+
+  // Create output file
+  FILE * outfile;
+  if ((outfile = fopen(PSZ(strOutputFile), "wb")) == NULL) 
+  {
+	  fprintf(stderr, "can't open %s\n", PSZ(strOutputFile));
+	  exit(1);
+	}
+  
+  // Generic initialization
+  InitCompressor(ptrMembuf, &cinfo);
+
+  // comress to file
+  jpeg_stdio_dest(&cinfo, outfile);
+
+  // Do the compression
+  Compress(ptrMembuf, &cinfo);
+
+  // Close output file
+  fclose(outfile);
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::EncodeGrayScaleToMemBuf
+//------------------------------------------------------------------------
+void JpegEncoder::EncodeGrayScaleToMemBuf(MemBufPtr ptrmbSrc, MemBufPtr ptrmbDst)
+{
+  // Allocate jpeg structures
+  struct jpeg_compress_struct cinfo;
+	struct jpeg_error_mgr jerr;
+  cinfo.err = jpeg_std_error(&jerr);
+
+  // Generic initialization
+  InitCompressor(ptrmbSrc, &cinfo);
+
+  // Prepare encoder destination
+  JpegEncoder::DestMemBuf mbEncoderDest(ptrmbDst);
+  cinfo.dest = mbEncoderDest.libjpegStruct();
+
+  // Add Destination buffer object to static map
+  s_mapCinfoToOutput[&cinfo] = &mbEncoderDest;
+
+  // Do the compression
+  Compress(ptrmbSrc, &cinfo);
+
+  // Remove Destination buffer object from map
+  map<struct jpeg_compress_struct *,  class DestMemBuf *>::iterator it;
+  it = s_mapCinfoToOutput.find(&cinfo);
+  if( it != s_mapCinfoToOutput.end() )
+    s_mapCinfoToOutput.erase(it);
+  else
+    throw JpegEncoder::Exception("INVALID_STATE", "Destination buffer not found", "JpegEncoder::EncodeGrayScaleToMemBuf");
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::InitCompressor
+//------------------------------------------------------------------------
+void JpegEncoder::InitCompressor(MemBufPtr ptrmbSrc, struct jpeg_compress_struct *pcinfo)
+{
+  int iWidth, iHeight;
+  try
+  {
+    ptrmbSrc->GetIntegerMetadata("width", &iWidth);
+    ptrmbSrc->GetIntegerMetadata("height", &iHeight);
+  }
+  catch( NoDataException e )
+  {
+    // Transform exception into a jpeg exception
+    throw JpegEncoder::Exception(PSZ(e.Error()), PSZ(e.Reason()), "JpegEncoder::InitCompressor");
+  }
+
+  if( iWidth < 1 ||iWidth > JPEG_MAX_DIMENSION )
+    throw JpegEncoder::Exception("BAD_PARAMETER", "Wrongs image dimensions. Must be in [1, 65000]", "JpegEncoder::Encode");
+
+  // create context
+  jpeg_create_compress(pcinfo);
+
+  // Put cinfo values
+  pcinfo->image_width = iWidth;
+  pcinfo->image_height = iHeight;
+  pcinfo->input_components = 1; // grayscale image
+  pcinfo->in_color_space = JCS_GRAYSCALE;
+
+  // Set compression parameters to default values
+  jpeg_set_defaults(pcinfo);
+
+  // Set quality to max
+  jpeg_set_quality(pcinfo, 100, TRUE);
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::Compress
+//------------------------------------------------------------------------
+void JpegEncoder::Compress(MemBufPtr ptrmbSrc, struct jpeg_compress_struct *pcinfo)
+{
+  // Start compressor
+  jpeg_start_compress(pcinfo, TRUE);
+
+  JSAMPROW *row_pointer = new JSAMPROW[pcinfo->image_height];
+  for( uint ui = 0; ui < pcinfo->image_height; ui++ )
+    row_pointer[ui] = (unsigned char *)(ptrmbSrc->Buf() + ui * pcinfo->image_width);
+  // Write all rows in one single pass
+  jpeg_write_scanlines(pcinfo, row_pointer, pcinfo->image_height);
+
+  // Terminate encoding process
+  jpeg_finish_compress(pcinfo);
+  jpeg_destroy_compress(pcinfo);
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::GetDestBuf
+//------------------------------------------------------------------------
+JpegEncoder::DestMemBuf *JpegEncoder::GetDestBuf(struct jpeg_compress_struct *pcinfo)
+{
+  map<struct jpeg_compress_struct *,  class DestMemBuf *>::iterator it;
+  it = s_mapCinfoToOutput.find(pcinfo);
+  if( it != s_mapCinfoToOutput.end() )
+    return it->second;
+  return NULL;
+}
+
+//=============================================================================
+// JpegEncoder::DestMemBuf
+//=============================================================================
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::DestinationManager
+//------------------------------------------------------------------------
+JpegEncoder::DestMemBuf::DestMemBuf(MemBufPtr ptrmbOuput, int iBufferSize)
+{
+  m_ptrmbOutput = ptrmbOuput;
+
+  // Allocate destination buffer
+  m_mbEncoderDest.SetLen(iBufferSize);
+
+  // Allocation libjpeg structure
+  m_pDestinationManager = new jpeg_destination_mgr;
+
+  // Set callback function pointers
+  m_pDestinationManager->init_destination = init_destination_wrapper;
+  m_pDestinationManager->empty_output_buffer = empty_output_buffer_wrapper;
+  m_pDestinationManager->term_destination = term_destination_wrapper;
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::init_destination_wrapper
+//------------------------------------------------------------------------
+void JpegEncoder::DestMemBuf::init_destination_wrapper(struct jpeg_compress_struct *pcinfo)
+{
+  // Search in JpegEncoder::s_mapCinfoToOutput on which instance of DestMemBuf we should call InitDestination
+  JpegEncoder::DestMemBuf *pOutputBuf = JpegEncoder::GetDestBuf(pcinfo);
+  if( pOutputBuf != NULL )
+    pOutputBuf->InitDestination(pcinfo);
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::InitDestination
+//------------------------------------------------------------------------
+void JpegEncoder::DestMemBuf::InitDestination(struct jpeg_compress_struct *pcinfo)
+{
+  pcinfo->dest->next_output_byte = (unsigned char *)m_mbEncoderDest.Buf();
+  pcinfo->dest->free_in_buffer = m_mbEncoderDest.Len();
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::empty_output_buffer_wrapper
+//------------------------------------------------------------------------
+#ifdef __WIN32__
+uint8 JpegEncoder::DestMemBuf::empty_output_buffer_wrapper(struct jpeg_compress_struct *pcinfo)
+#else
+int JpegEncoder::DestMemBuf::empty_output_buffer_wrapper(struct jpeg_compress_struct *pcinfo)
+#endif
+{
+  // Search in JpegEncoder::s_mapCinfoToOutput on which instance of DestMemBuf
+  // we should call EmptyOutputBuffer
+  JpegEncoder::DestMemBuf *pOutputBuf = JpegEncoder::GetDestBuf(pcinfo);
+  if( pOutputBuf != NULL )
+    return uint8(pOutputBuf->EmptyOutputBuffer(pcinfo));
+  return 0;
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::EmptyOutputBuffer
+//------------------------------------------------------------------------
+int JpegEncoder::DestMemBuf::EmptyOutputBuffer(struct jpeg_compress_struct *pcinfo)
+{
+  m_ptrmbOutput->PutBloc(m_mbEncoderDest.Buf(), m_mbEncoderDest.Len());
+  pcinfo->dest->next_output_byte = (unsigned char *)m_mbEncoderDest.Buf();
+  pcinfo->dest->free_in_buffer = m_mbEncoderDest.Len();
+  return 1;
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::term_destination_wrapper
+//------------------------------------------------------------------------
+void JpegEncoder::DestMemBuf::term_destination_wrapper(struct jpeg_compress_struct *pcinfo)
+{
+  // Search in JpegEncoder::s_mapCinfoToOutput on which instance of DestMemBuf
+  // we should call TermDestination
+  JpegEncoder::DestMemBuf *pOutputBuf = JpegEncoder::GetDestBuf(pcinfo);
+  if( pOutputBuf != NULL )
+    pOutputBuf->TermDestination(pcinfo);
+}
+
+//------------------------------------------------------------------------
+// JpegEncoder::DestMemBuf::TermDestination
+//------------------------------------------------------------------------
+void JpegEncoder::DestMemBuf::TermDestination(struct jpeg_compress_struct *pcinfo)
+{
+  m_ptrmbOutput->PutBloc(m_mbEncoderDest.Buf(), m_mbEncoderDest.Len() - pcinfo->dest->free_in_buffer);
+}
diff --git a/contrib/applications/NXextract/src/jpegwrap.h b/contrib/applications/NXextract/src/jpegwrap.h
new file mode 100644
index 0000000..eb6c9b7
--- /dev/null
+++ b/contrib/applications/NXextract/src/jpegwrap.h
@@ -0,0 +1,132 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 01/12/2006
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __JPEG_WRAP_H__
+#define __JPEG_WRAP_H__
+
+namespace soleil
+{
+
+extern "C"
+{
+  #undef FAR
+  #include "jpeglib.h"
+}
+
+#ifdef __WIN32__
+  #define CONVCALL __cdecl
+#else
+  #define CONVCALL
+#endif
+
+//==============================================================================
+/// Class JpegEncoder
+/// Class that take a MemBuxEx and a output file name to encode a grayscale jpeg
+//==============================================================================
+class JpegEncoder
+{
+public:
+
+  //---------------------------------------------------------------------------
+  /// Jpeg encoder exception
+  //---------------------------------------------------------------------------
+  class Exception : public ExceptionBase
+  {
+    protected:
+      const char *ErrorTitle()
+      {
+        return "Jpeg encoder exception";
+      }
+
+    public:
+      Exception(const char *pcszError, const char *pcszReason, const char *pcszMethod):
+      ExceptionBase(pcszError, pcszReason, pcszMethod)
+      { }
+  };
+
+  //---------------------------------------------------------------------------
+  /// DestMemBuf
+  /// manage output to a MemBuf object
+  //---------------------------------------------------------------------------
+  class DestMemBuf
+  {
+    private:
+      /// Destination buffer for libjpeg encoder
+      CMemBuf m_mbEncoderDest;
+
+      /// Reference to the final destination
+      MemBufPtr m_ptrmbOutput;
+
+      /// libjpeg structure who maintain pointer to next output byte 
+      /// and free bytes in buffer
+      struct jpeg_destination_mgr *m_pDestinationManager;
+
+      /// Method called by init_destination_wrapper
+      void InitDestination(struct jpeg_compress_struct * cinfo);
+
+      /// Method called by empty_output_buffer_wrapper
+      int EmptyOutputBuffer(struct jpeg_compress_struct * cinfo);
+
+      /// Method called by term_destination_wrapper
+      void TermDestination(struct jpeg_compress_struct * cinfo);
+
+      /// Method called by libjpeg at compressor initialization
+      static void CONVCALL init_destination_wrapper(struct jpeg_compress_struct * cinfo);
+
+      /// Method called by libjpeg when output buffer is full
+#ifdef __WIN32__
+      static uint8 CONVCALL empty_output_buffer_wrapper(struct jpeg_compress_struct * cinfo);
+#else
+      static int CONVCALL empty_output_buffer_wrapper(struct jpeg_compress_struct * cinfo);
+#endif
+
+      /// Method called by libjpeg when compressor has finished
+      static void CONVCALL term_destination_wrapper(struct jpeg_compress_struct * cinfo);
+
+    public:
+      /// Constructor
+      /// @param iBufferSize destination buffer size on bytes
+      DestMemBuf(MemBufPtr mbOuput, int iBufferSize = 65536);
+      
+      /// Accessors
+      jpeg_destination_mgr *libjpegStruct() { return m_pDestinationManager; }
+  };
+
+private:
+  ///# In a multithread environment, we should use a lock for controlling the access to this map
+  static map<struct jpeg_compress_struct *, class DestMemBuf *> s_mapCinfoToOutput;
+
+  /// Method called to perform generic initialization of the compressor
+  static void InitCompressor(MemBufPtr ptrmbSrc, struct jpeg_compress_struct * cinfo);
+
+  /// Method called to perform generic initialization of the compressor
+  static void Compress(MemBufPtr ptrmbSrc, struct jpeg_compress_struct * cinfo);
+
+public:
+  JpegEncoder();
+
+  /// Methode called from JpegEncoder::DestMemBuf static callback wrappers class to retreive
+  /// right instance of JpegEncoder::DestMemBuf object
+  static DestMemBuf *GetDestBuf(struct jpeg_compress_struct * cinfo);
+
+  static void EncodeGrayScaleToFile(MemBufPtr ptrmbSrc, const String &strOutputFile);
+  static void EncodeGrayScaleToMemBuf(MemBufPtr ptrmbSrc, MemBufPtr ptrmbDst);
+};
+
+} // namespace
+
+#endif
diff --git a/contrib/applications/NXextract/src/membuf.cpp b/contrib/applications/NXextract/src/membuf.cpp
new file mode 100644
index 0000000..9e7199a
--- /dev/null
+++ b/contrib/applications/NXextract/src/membuf.cpp
@@ -0,0 +1,973 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Creation : 20/03/2006
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "date.h"
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "membuf.h"
+
+using namespace soleil;
+
+//----------------------------------------------------------------------------
+// Constantes
+//----------------------------------------------------------------------------
+
+#define CMemBuf_MAXDELTA    1048576
+
+// Buffer allocation min size
+#define MEMBUF_MINSIZE   16
+
+
+//-------------------------------------------------------------------
+// Conversion hexadecimal to decimal
+//-------------------------------------------------------------------
+char HexToDec (char ch)
+{
+  if (ch >= '0' && ch <= '9')
+    return (char)(ch - '0');
+  if (ch >= 'A' && ch <= 'F')
+    return (char)(ch - 'A' + 10);
+  if (ch >= 'a' && ch <= 'f')
+    return (char)(ch - 'a' + 10);
+
+  return 0;
+}
+
+//===================================================================
+// Class CMemBuf
+//===================================================================
+
+//-------------------------------------------------------------------
+// CMemBuf::CMemBuf
+//-------------------------------------------------------------------
+CMemBuf::CMemBuf(uint uiLenBuf)
+ : m_uiLenBuf(uiLenBuf),m_bOwner(true)
+{
+  
+  if( m_uiLenBuf )
+  {
+    m_pBuf = new char[m_uiLenBuf];
+  }
+  else
+    m_pBuf = NULL;
+  m_uiLen = 0;
+  m_uiPos = 0;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::CMemBuf
+//-------------------------------------------------------------------
+CMemBuf::CMemBuf(const CMemBuf& buf)
+  : m_uiLen(buf.Len()), m_bOwner(true)
+{
+  if( m_uiLen != 0 )
+  {
+    m_uiLenBuf = m_uiLen;
+    m_pBuf = new char[m_uiLenBuf];
+    memcpy(m_pBuf, buf.Buf(), m_uiLen);
+  }
+  else
+  { 
+    // Empty buffer
+    m_uiLenBuf = 0;
+    m_pBuf = NULL;
+  }
+  m_uiPos = 0;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::~CMemBuf
+//-------------------------------------------------------------------
+CMemBuf::~CMemBuf()
+{
+  if( (m_uiLenBuf != 0) && m_bOwner )
+    delete [] m_pBuf;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::operator=
+//-------------------------------------------------------------------
+CMemBuf& CMemBuf::operator=(const CMemBuf& buf)
+{
+  if( !m_bOwner )
+    Reset();
+  uint uiNb = buf.Len();
+  if( uiNb > m_uiLenBuf )
+  {
+    // pas assez de place : realloue
+    if( m_uiLenBuf != 0 )
+      delete [] m_pBuf;
+
+    m_uiLenBuf = uiNb;
+    m_pBuf = new char[m_uiLenBuf];
+  }
+  memcpy(m_pBuf, buf.Buf(), uiNb);
+  m_uiLen = uiNb;
+  m_uiPos = buf.Pos();
+  return *this;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::operator==
+//-------------------------------------------------------------------
+bool CMemBuf::operator==(const CMemBuf &mb) const
+{
+  if ( m_uiLen == mb.Len() )
+    return !memcmp(m_pBuf, mb.Buf(), m_uiLen);
+  return false;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::ReallocWithMargin
+//-------------------------------------------------------------------
+void CMemBuf::ReallocWithMargin(uint uiNewSize)
+{
+  // Min size
+  if( uiNewSize < MEMBUF_MINSIZE )
+    uiNewSize = MEMBUF_MINSIZE;
+
+  // Not enough space : The buffer grow with CMEMBUF_MAXDELTA bytes max
+  uint uiDelta = uiNewSize / 2;
+  if (uiDelta > CMEMBUF_MAXDELTA)
+    uiDelta = CMEMBUF_MAXDELTA;
+
+  uint uiNewLenBuf = uiNewSize + uiDelta;
+  Realloc(uiNewLenBuf);
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::Realloc
+//-------------------------------------------------------------------
+void CMemBuf::Realloc(uint uiNewLenBuf)
+{
+  if (uiNewLenBuf < m_uiLen)
+  {
+    // Wished size smaller than current one!
+//##    ASSERT_FAILURE;
+    return;
+  }
+  char *pNewBuf = new char[uiNewLenBuf];
+  if( m_pBuf )
+    memcpy(pNewBuf, m_pBuf, m_uiLen);
+  if( m_uiLenBuf != 0 && m_pBuf && m_bOwner )
+    delete [] m_pBuf;
+  m_pBuf     = pNewBuf;
+  m_uiLenBuf = uiNewLenBuf;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::Reset
+//-------------------------------------------------------------------
+void CMemBuf::Reset()
+{
+  if (m_uiLenBuf != 0)
+  {
+    if( m_bOwner )
+      delete [] m_pBuf;
+    m_uiPos = 0;
+    m_uiLen = 0;
+    m_uiLenBuf = 0;
+    m_pBuf = NULL;
+    m_bOwner = true;
+  }
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::SetLen
+//-------------------------------------------------------------------
+void CMemBuf::SetLen(uint uiNb)
+{
+  if( uiNb > m_uiLenBuf )
+    // Not enough space : re-alloc
+    Realloc(uiNb);
+  m_uiLen = uiNb;
+  m_uiPos = 0;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::PutBloc
+//-------------------------------------------------------------------
+void CMemBuf::PutBloc(const void* p, uint uiNb)
+{
+//##  ASSERT( (ulong)m_uiLen + (ulong)uiNb <= (ulong)MAX_ALLOC_NEW)
+  uint uiTotalLen = m_uiLen + uiNb;
+  if( uiTotalLen > m_uiLenBuf )
+  {
+    // Not enough space : re-alloc with margin
+    ReallocWithMargin(uiTotalLen);
+  }
+  memcpy(m_pBuf+m_uiLen, p, uiNb);
+  m_uiLen = uiTotalLen;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::InsertBloc
+//-------------------------------------------------------------------
+void CMemBuf::InsertBloc(const void* p, uint uiNb, uint uiInsPos)
+{
+//##  ASSERT(uiInsPos <= m_uiLen)
+//##  ASSERT( (ulong)m_uiLen + (ulong)uiNb <= (ulong)MAX_ALLOC_NEW)
+  uint uiTotalLen = m_uiLen + uiNb;
+  if( uiTotalLen > m_uiLenBuf )
+  {
+    // Not enough space : re-alloc with margin
+    ReallocWithMargin(uiTotalLen);
+  }
+
+  // Not enough space
+  memmove(m_pBuf+uiInsPos+uiNb, m_pBuf+uiInsPos, m_uiLen-uiInsPos);
+  memcpy(m_pBuf+uiInsPos, p, uiNb);
+  m_uiLen = uiTotalLen;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::GetBloc
+//-------------------------------------------------------------------
+int CMemBuf::GetBloc(void* p, uint uiNb)
+{
+  if( m_uiLen - m_uiPos < uiNb )
+  {
+    // Plus assez de place
+    //##ASSERT_FAILURE
+    return 1;
+  }
+
+  memcpy(p, m_pBuf+m_uiPos, uiNb);
+  m_uiPos += uiNb;
+  return 0;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::MoveBloc
+//-------------------------------------------------------------------
+void CMemBuf::MoveBloc(uint uiDst, uint uiSrc, uint uiSize)
+{
+//##  ASSERT( (uiDst+uiSize) <= m_uiLen );
+//##  ASSERT( (uiSrc+uiSize) <= m_uiLen );
+  memmove(m_pBuf + uiDst, m_pBuf + uiSrc, uiSize);
+}
+
+//-------------------------------------------------------------------
+// CRC computing
+//-------------------------------------------------------------------
+// Table des CRC-32 (engendree par un utilitaire, on s'en doute !)
+ulong crc_32_tab[] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+
+
+//***************************************************************************
+// @func API de calcul de CRC 32 bits.
+// Deux utilisations possibles de cette API : 
+//  soit on laisse pulInitValue a NULL, auquel cas elle calcule le crc
+//  global du buffer. Soit pulInitValue n'est pas NULL, et cela permet de
+//  calcul un crc global sur un ensemble de buffers. Par exemple si p1 et
+//  p2 sont deux pointeurs vers des buffers, il faut ecrire :
+//    ulong ulCrc = 0xFFFFFFFFL;
+//    ulCrc = Crc( p1, uiP1Len, &ulCrc );
+//    ulCrc = Crc( p2, uiP2Len, &ulCrc );
+//    ulCrc = ulCrc ^ 0xFFFFFFFFL;
+//***************************************************************************
+ulong soleil::Crc( const byte *pBuf, uint uiLen, ulong *pulInitValue )
+{
+  ulong ulVal;
+  if( pulInitValue != NULL )
+    ulVal = *pulInitValue;
+  else
+    ulVal = 0L;
+
+  if( uiLen == 0 )
+    return ulVal;
+ 
+  if( pulInitValue == NULL )
+    ulVal = 0xffffffffL;
+
+  // Main loop : under Visual C++, use assembly language
+  #if defined(_MSC_VER)
+      _asm 
+      {
+        mov   ecx, uiLen
+        jecxz AsmEnd
+
+        push  esi
+        mov   esi, pBuf
+        mov   ebx, ulVal
+        AsmLoop:
+
+        lodsb
+        xor   al, bl
+        movzx eax, al
+        mov   eax, Dword Ptr [crc_32_tab + eax*4]
+
+        shr   ebx, 8
+        xor   ebx, eax
+
+        loop AsmLoop
+        mov   ulVal, ebx
+        pop   esi
+
+        AsmEnd:
+      }
+  #else
+    while( uiLen-- )
+      ulVal = crc_32_tab[((int)ulVal ^ (*pBuf++)) & 0xff] ^ (ulVal >> 8);
+  #endif
+
+  if( pulInitValue == NULL )
+    ulVal = ulVal ^ 0xffffffffL;
+  return ulVal;
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::GetCrc
+//-------------------------------------------------------------------
+ulong CMemBuf::GetCrc() const
+{
+  return soleil::Crc( (byte *)m_pBuf, m_uiLen );
+}
+
+//-------------------------------------------------------------------
+// CMemBuf::LoadFile
+//-------------------------------------------------------------------
+/*
+int CMemBuf::LoadFile(const char *pszFile)
+{
+  int rc = 0;
+  CFileEx f (pszFile);
+
+  rc = f.Open ("r");
+  if (rc)
+    return rc;
+
+  long lSize = f.Size ();
+  SetLen (lSize);
+  rc = f.ReadBloc (Buf(), lSize);
+  return rc;
+}
+
+//---------------------------------------------------------------------------
+// CMemBuf::SaveToFile
+//---------------------------------------------------------------------------
+int CMemBuf::SaveToFile(const CFileName& fnFile, const char *pszMode,
+  uint uiShareMode) const
+{
+  int iRc = 0;
+  CFileEx f(fnFile);
+  iRc = f.Open( pszMode, uiShareMode );
+  if( iRc )
+    return iRc;
+
+  iRc = f.WriteBloc( *this );
+  if( iRc )
+    return iRc;
+
+  iRc = f.Close();
+  if( iRc )
+    return iRc;
+
+  return 0;
+}
+*/
+
+//---------------------------------------------------------------------------
+// CMemBuf::Attach
+//---------------------------------------------------------------------------
+void CMemBuf::Attach(char* pBuf,uint uiLen,bool bOwner)
+{
+  Reset();
+  m_uiLen = uiLen;
+  m_uiLenBuf = uiLen;
+  m_pBuf = pBuf;
+  m_bOwner = bOwner;
+}
+
+//---------------------------------------------------------------------------
+// CMemBuf::GiveOwnership
+//---------------------------------------------------------------------------
+int CMemBuf::GiveOwnership(CMemBuf* pToHaveOwnership)
+{
+  if( !m_bOwner )
+  {
+//##    ASSERT_FAILURE;
+    return -1;
+  }
+  pToHaveOwnership->Attach( m_pBuf, m_uiLen, true );
+  SetOwner(false);
+  return 0;
+}
+
+//-------------------------------------------------------------------
+// Stream oparators
+//-------------------------------------------------------------------
+CMemBuf& CMemBuf::operator<<(char c)
+{
+  PutBloc(&c, sizeof(c)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(char &c)
+{
+  GetBloc(&c, sizeof(c));           
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(uchar uc)
+{
+  PutBloc(&uc, sizeof(uc)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(uchar &uc)
+{
+  GetBloc(&uc, sizeof(uc));           
+  return *this;
+}
+
+
+CMemBuf& CMemBuf::operator<<(short s)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertShort(&s);
+  #endif
+  PutBloc(&s, sizeof(s)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(short &s)
+{
+  GetBloc(&s, sizeof(s));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertShort(&s);
+  #endif
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(ushort us)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertShort((short*)&us);
+  #endif
+  PutBloc(&us, sizeof(us)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(ushort &us)
+{
+  GetBloc(&us, sizeof(us));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertShort((short*)&us);
+  #endif
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(long l)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertLong(&l);
+  #endif
+  PutBloc(&l, sizeof(l)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(long &l)
+{
+  GetBloc(&l, sizeof(l));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertLong(&l);
+  #endif
+  return *this;
+}
+CMemBuf& CMemBuf::operator<<(ulong ul)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertLong((long*)&ul);
+  #endif
+  PutBloc(&ul, sizeof(ul)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(ulong &ul)
+{
+  GetBloc(&ul, sizeof(ul));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertLong((long*)&ul);
+  #endif
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(int64 &i64)
+{
+  GetBloc(&i64, sizeof(int64));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertInt64(&i64);
+  #endif
+  return *this;
+}
+CMemBuf& CMemBuf::operator<<(int64 i64)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertInt64((long*)&ul);
+  #endif
+  PutBloc(&i64, sizeof(i64)); 
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(float f)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertFloat(&f);
+  #endif
+  PutBloc(&f, sizeof(f)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(float &f)
+{
+  GetBloc(&f, sizeof(f));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertFloat(&f);
+  #endif
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(double d)
+{
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertDouble(&d);
+  #endif
+  PutBloc(&d, sizeof(d)); 
+  return *this;
+}
+CMemBuf& CMemBuf::operator>>(double &d)
+{
+  GetBloc(&d, sizeof(d));           
+  #ifdef __MOTOROLA_ENDIAN__
+    InvertDouble(&d);
+  #endif
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(const char* psz)
+{
+  PutBloc(psz, strlen(psz)+1);
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(const string& string)
+{
+  PutBloc(string.c_str(), string.size()+1);
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator>>(string& string)
+{
+  if ( m_pBuf != NULL )
+  {
+    uint uiNb = strlen(CurPointer());
+    string.reserve(uiNb);
+    string.append(CurPointer(), uiNb);
+  }
+  return *this;
+}
+
+CMemBuf& CMemBuf::operator<<(const CMemBuf& membuf)
+{
+  PutBloc( membuf.Buf(), membuf.Len() );
+  return *this;
+}
+
+//---------------------------------------------------------------------------
+// CMemBuf::HexString
+//---------------------------------------------------------------------------
+String CMemBuf::HexString() const
+{
+  static const char *pszHexa = "0123456789ABCDEF";
+  ostringstream oss;
+  String str;
+  str.reserve(2 * m_uiLen);
+  for (uint ui = 0; ui < m_uiLen; ui++)
+    oss << (pszHexa[(uchar)m_pBuf[ui] >> 4]) 
+        << (pszHexa[(uchar)m_pBuf[ui] & 0x0F]);
+
+  return oss.str();
+}
+
+//---------------------------------------------------------------------------
+// CMemBuf::PutHexString
+//---------------------------------------------------------------------------
+void CMemBuf::PutHexString(const char *pszHex, int iLen)
+{
+  if( iLen == -1 )
+    iLen = strlen(pszHex);
+//##  ASSERT(!(iLen & 1)) // Only even value are valid
+  
+  for (int i = 0; i < iLen; i+=2)
+    *this << (char)((char)(HexToDec(pszHex[i]) << 4) + HexToDec(pszHex[i+1]));
+}
+
+//---------------------------------------------------------------------------
+// CMemBuf::ReversibleCrypt
+//---------------------------------------------------------------------------
+#define REVCRYPT_MAGIC 0x20544212
+
+#define PSW_HEADER "CmjBlurp"
+#define PSW_FOOTER "ZnortGnap"
+#define DEFAULT_XOR_KEY "�gTy7�_iuljkR4-)9qsE�-|�@-nU02;#(&z&e�)=3aZ#bT�$<?Y@#)pT$*��%')�eQ4~{^>|�_�Fp9/+-�H"
+#define DEFAULT_ROT_KEY "T;#T�$|p9/+=�*gTy@�_iz3$s�)pE2%<_')�aZun.0�lj#b�ekR4?Y�#H(&�{^>|�)9-Q4~@Z�qF�*1"
+
+uchar BinRotLeft(uchar chOctet, uint uiRotCoeff );
+uchar BinRotRight(uchar chOctet, uint uiRotCoeff );
+
+int CMemBuf::ReversibleCrypt(const void* pXorKey, uint uiXorKeyLen,
+                             const void* pRotKey, uint uiRotKeyLen,
+                             short sVersion)
+{
+  // !!! Attention, si version vaut REVCRYPT_LATEST_VERSION, utiliser la 
+  // derni�re version de cryptage
+  if (sVersion==REVCRYPT_LATEST_VERSION)
+    sVersion = 2;
+
+  static bool s_bsRandCalled = false;
+  if( !s_bsRandCalled )
+  {
+    CCurrentDate dtCur;
+    srand ((uint)((dtCur.Sec()*1000)));
+    s_bsRandCalled = true;
+  }
+	
+  switch (sVersion)
+  {
+    case 2:
+    { // Add a variable length header and footer
+      short sl1 = (short)(((double)(rand()) * strlen(PSW_HEADER))/RAND_MAX);
+      short sl2 = (short)(((double)(rand()) * strlen(PSW_FOOTER))/RAND_MAX);
+
+      // Header
+      InsertBloc(PSW_HEADER,sl1, 0);
+      #ifdef __MOTOROLA_ENDIAN__
+        InvertShort(&sl1);
+      #endif
+      InsertBloc(&sl1, sizeof(short), 0);
+      // Footer
+      PutBloc(PSW_FOOTER,sl2);
+      operator<<((short)sl2);
+      operator<<((long)GetCrc());
+    }
+    case 0:
+    case 1:
+    {
+      // Compute a key
+      short asKey[4] = { 0, 0, 0, 0 };
+      asKey[0] = (short)(rand() & 0x7FFF);
+      asKey[1] = (short)(rand() & 0x7FFF);
+      asKey[2] = (short)(rand() & 0x7FFF);
+      asKey[3] = (short)(rand() & 0x7FFF);
+      // Crypt using computed key
+      Xor(asKey, sizeof(asKey));
+      BinRotLeft(asKey, sizeof(asKey));
+      // Add key at the end of the buffer
+      PutBloc(asKey, sizeof(asKey));
+      // Crypt using given keys
+      if( pXorKey )
+        Xor(pXorKey, uiXorKeyLen);
+      else
+        Xor(DEFAULT_XOR_KEY, strlen(DEFAULT_XOR_KEY));
+      if( pRotKey )
+        BinRotLeft(pRotKey, uiRotKeyLen);
+      else
+        BinRotLeft(DEFAULT_ROT_KEY, strlen(DEFAULT_ROT_KEY));
+      break;
+    }
+  }
+
+  if (sVersion>0)
+  {
+    operator <<((long)REVCRYPT_MAGIC);
+    operator <<(sVersion);
+  }
+  return 0;
+}
+
+//---------------------------------------------------------------------------
+// CMemBuf::ReversibleDecrypt
+//---------------------------------------------------------------------------
+int CMemBuf::ReversibleDecrypt(const void* pXorKey, uint uiXorKeyLen,
+                                        const void* pRotKey, uint uiRotKeyLen,
+                                        short *psVersion)
+{
+  if (Len()==0)
+    return 0;
+
+  // Get crypting version
+  long lMagic;
+  short sVersion=0;
+  ulong ulMinSize = sizeof(sVersion)+sizeof(lMagic);
+
+  if (Len()<ulMinSize)
+    return -1;
+
+  ulong ulPos = Len()-ulMinSize;
+  SetPos(ulPos);
+  operator >> (lMagic);
+  if (lMagic==REVCRYPT_MAGIC)
+  {
+    // Magic is found, crypting version is in next short value
+    operator >> (sVersion);
+    Rewind();
+    SetLen(ulPos); // Cut buffer
+  }
+  if (psVersion)
+    *psVersion = sVersion;
+
+  // Decrypt
+  switch (sVersion)
+  {
+    case 2:
+    case 0:
+    case 1:
+    {
+      short asKey[4] = { 0, 0, 0, 0 };
+      if (Len()>=sizeof(asKey))
+      {
+        // Decrypt using given keys
+        if( pRotKey )
+          BinRotRight(pRotKey, uiRotKeyLen);
+        else
+          BinRotRight(DEFAULT_ROT_KEY, strlen(DEFAULT_ROT_KEY));
+        if( pXorKey )
+          Xor(pXorKey, uiXorKeyLen);
+        else
+          Xor(DEFAULT_XOR_KEY, strlen(DEFAULT_XOR_KEY));
+        // Get computed key
+        SetPos(Len()-sizeof(asKey));
+        GetBloc(asKey, sizeof(asKey));
+        Rewind();
+        SetLen(Len()-sizeof(asKey));
+        // Decrypt using computed key
+        BinRotRight(asKey, sizeof(asKey));
+        Xor(asKey, sizeof(asKey));
+      }
+      if( sVersion == 2 )
+      {
+        // Get CRC value
+        long lStoredCRC;
+        memcpy(&lStoredCRC, Buf() + Len() - sizeof(long), sizeof(long));
+        #ifdef __MOTOROLA_ENDIAN__
+          // Invert long value
+          InvertLong(&lStoredCRC);
+        #endif
+        SetLen(Len() - sizeof(long));
+        // Gete buffer CRC for comparison
+        long lCRC = GetCrc();
+        if( lCRC != lStoredCRC )
+          return -1;
+
+        // Remove header
+        short sGarbageLength;
+        operator>>(sGarbageLength);
+        memmove(Buf(), Buf() + Pos() + sGarbageLength, Len() - Pos() - sGarbageLength);
+        // La nouvelle longueur est : la longueur de donnees copiees
+        SetLen(Len()-Pos()-sGarbageLength);
+
+        // Remove footer
+        memcpy(&sGarbageLength, Buf() + Len() - sizeof(short), sizeof(short));
+        #ifdef __MOTOROLA_ENDIAN__
+          // Invert long value
+          InvertShort(&sGarbageLength);
+        #endif
+        SetLen(Len() - sizeof(short) - sGarbageLength);
+        Rewind();
+      }
+    }
+
+  }
+  return 0;
+}
+
+//------------------------------------------------------------------------
+// CMemBuf::Xor
+//------------------------------------------------------------------------
+void CMemBuf::Xor(const void* pXor, uint uiXorLen)
+{   
+  char *pcXor = (char *)pXor;
+  char *pHuge = m_pBuf;
+  uint uiXor = 0;
+
+  for (ulong ul = 0; ul < Len(); ul++ )
+  {     
+    pHuge[ul] ^= pcXor[uiXor ];
+    uiXor++;  
+    if ( uiXor >= uiXorLen)
+      uiXor = 0;
+  }
+}
+
+//------------------------------------------------------------------------
+// CMemBuf::BinRotLeft
+//------------------------------------------------------------------------
+void CMemBuf::BinRotLeft(const void* pRot, uint uiRotLen)
+{
+  char *pcRot = (char *)pRot;
+  char *pHuge = m_pBuf;
+
+  uint uiRot = 0;
+  for ( ulong ul = 0; ul<Len(); ul++ )
+  {
+    pHuge[ul] = ::BinRotLeft(pHuge[ul], pcRot[uiRot]&7);
+    uiRot++;
+    if ( uiRot >= uiRotLen)
+      uiRot = 0;
+  }
+}
+
+//------------------------------------------------------------------------
+// CMemBuf::BinRotRight
+//------------------------------------------------------------------------
+void CMemBuf::BinRotRight(const void* pRot, uint uiRotLen)
+{
+  char *pcRot = (char *)pRot;
+  char *pHuge = m_pBuf;
+
+  uint uiRot = 0;
+  for ( ulong ul = 0; ul<Len(); ul++ )
+  {
+    pHuge[ul] = ::BinRotRight(pHuge[ul], pcRot[uiRot]&7);
+    uiRot++;
+    if ( uiRot >= uiRotLen)
+      uiRot = 0;
+  }
+}
+
+//------------------------------------------------------------------------
+// Binary shifting
+//------------------------------------------------------------------------
+uchar BinRotLeft(uchar chOctet, uint uiRotCoeff )
+{
+  uchar chLeftShift = (uchar ) (chOctet << uiRotCoeff);
+  uchar chRightShift = (uchar ) (chOctet >> (8 - uiRotCoeff));
+  return (uchar ) (chLeftShift | chRightShift); 
+}
+
+//------------------------------------------------------------------------
+// Binary shifting
+//------------------------------------------------------------------------
+uchar BinRotRight(uchar chOctet, uint uiRotCoeff )
+{
+  uchar chRightShift = (uchar ) (chOctet >> uiRotCoeff);
+  uchar chLeftShift  = (uchar ) (chOctet << (8 - uiRotCoeff));
+  return (uchar ) (chLeftShift | chRightShift); 
+}
+
+//------------------------------------------------------------------------
+// Binary shifting
+//------------------------------------------------------------------------
+void CMemBuf::KeyGen(CMemBuf *pmbCryptedKey, int iKeyLen, bool bInitRand)
+{
+  if( bInitRand )
+  {
+    CCurrentDate dtCur;
+    srand ((uint)((dtCur.Sec()*1000)));
+  }
+
+  CMemBuf mbKey;
+  for(int i = 0; i < iKeyLen; i++ )
+  {
+    uchar uc = rand() & 0xFF;
+    mbKey << uc;
+  }
+  mbKey.ReversibleCrypt();
+
+  // Give crypted key to caller
+  *pmbCryptedKey = mbKey;
+}
+
+//=============================================================================
+//
+// String methods
+//
+//=============================================================================
+
+//---------------------------------------------------------------------------
+// String::Crypt
+//---------------------------------------------------------------------------
+void String::Crypt(const char* pszXorKey, const char* pszRotKey)
+{
+  CMemBuf membuf;
+	membuf << *this;
+  membuf.ReversibleCrypt(pszXorKey, pszXorKey ? strlen(pszXorKey) : 0, pszRotKey, pszRotKey ? strlen(pszRotKey) : 0);
+	*this = membuf.HexString();
+}
+
+//---------------------------------------------------------------------------
+// String::Decrypt
+//---------------------------------------------------------------------------
+void String::Decrypt(const char* pszXorKey, const char* pszRotKey)
+{
+  CMemBuf membuf;
+  membuf.PutHexString(c_str(), size());
+  membuf.ReversibleDecrypt(pszXorKey, pszXorKey ? strlen(pszXorKey) : 0, pszRotKey, pszRotKey ? strlen(pszRotKey) : 0);
+  erase();
+  membuf >> *this;
+}
+
diff --git a/contrib/applications/NXextract/src/membuf.h b/contrib/applications/NXextract/src/membuf.h
new file mode 100644
index 0000000..58aadf4
--- /dev/null
+++ b/contrib/applications/NXextract/src/membuf.h
@@ -0,0 +1,288 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Autosized buffer
+//
+// Creation : 20/03/2006
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __MEMBUF_H__
+#define __MEMBUF_H__
+
+namespace gdshare
+{
+
+// CRC computation
+ulong Crc( const byte *pBuf, uint uiLen, ulong *pulInitValue = NULL );
+
+//===========================================================================
+// endian management
+//===========================================================================
+
+inline void InvertShort(short *pS)
+{
+  // AB -> BA
+  char *p = (char*)pS;
+  char c = *p;
+  *p = *(p+1);
+  *(p+1) = c;
+}
+
+inline void InvertLong(long *pL)
+{
+  // ABCD -> DCBA
+  char *p = (char*)pL;
+  char c = *p;
+  *p = *(p+3);
+  *(p+3) = c;
+  c = *(p+1);
+  *(p+1) = *(p+2);
+  *(p+2) = c;
+}
+inline void InvertInt64(int64 *pi64)
+{
+  // ABCDEFGH -> HGFEDCBA
+  char *p = (char*)pi64;
+  char c = *p;
+  *p = *(p+7);
+  *(p+7) = c;
+  c = *(p+1);
+  *(p+1) = *(p+6);
+  *(p+6) = c;
+  c = *(p+5);
+  *(p+2) = *(p+5);
+  *(p+5) = c;
+  c = *(p+4);
+  *(p+4) = *(p+3);
+  *(p+3) = c;
+}
+
+inline void InvertFloat(float *pF)
+{
+  // ABCD -> DCBA
+  InvertLong((long*)pF);
+}
+
+inline void InvertDouble(double *pD)
+{
+  // ABCDEFGH -> HGFEDCBA
+  char *p = (char*)pD;
+  char c = *p;
+  *p = *(p+7);
+  *(p+7) = c;
+
+  c = *(p+1);
+  *(p+1) = *(p+6);
+  *(p+6) = c;
+
+  c = *(p+2);
+  *(p+2) = *(p+5);
+  *(p+5) = c;
+
+  c = *(p+3);
+  *(p+3) = *(p+4);
+  *(p+4) = c;
+}
+
+//===================================================================
+// Constantes
+//===================================================================
+
+// Re-allocation delta
+#define CMEMBUF_MAXDELTA    8192
+
+// Latest crypying version
+#define REVCRYPT_LATEST_VERSION -1
+#define VARLENGTH_CRYPT          2
+
+#define OFFSET(type,field) \
+  (int)&(((type*)NULL)->field)
+
+//===========================================================================
+// Class CMemBuf
+//
+// Auto-sized binary buffer with cryptographic capabilities
+//===========================================================================
+class CMemBuf : public MReferencable, public MMetadata
+{
+private:
+  uint m_uiPos;             ///< Position (for reading)
+  uint m_uiLen;             ///< Buffer size
+  uint m_uiLenBuf;          ///< Allocated size
+  char *m_pBuf;             ///< The buffer!
+  bool m_bOwner;            ///< if true the instance own the buffer
+
+  // Re-allocation
+  void ReallocWithMargin(uint uiNewSize) ;
+
+public:
+  /// Constructor
+  CMemBuf(uint uiLenBuf=0) ;
+  CMemBuf(const CMemBuf& buf) ;
+  /// Destructor
+  ~CMemBuf() ;
+
+  /// Copy operator
+  CMemBuf& operator=(const CMemBuf& buf);
+
+  // Comparaison operator
+  bool operator==(const CMemBuf &mb) const;
+  
+  /// Attachment from a external buffer
+  ///
+  /// @param pBuf memory area to attach
+  /// @param uiLen area size
+  /// @param bOwner if true this instance will own the buffer
+  ///
+  void Attach(char* pBuf, uint uiLen, bool bOwner = false);
+
+  /// Length
+  uint Len() const  { return m_uiLen; }
+
+  /// Is empty ?
+  int IsEmpty() const { return m_uiLen==0; }
+
+  // Buffer size
+  uint BufLen() const { return m_uiLenBuf; }
+
+  /// buffer pointer
+  char* Buf() const   { return m_pBuf; }
+
+  /// buffer pointer in *bytes* data type
+  byte *Bytes() const { return (byte *)m_pBuf; }
+   
+  /// Position in buffer
+  uint Pos() const    { return m_uiPos; }
+
+  /// Set length
+  void SetLen(uint ui);
+
+  /// Reallocation
+  void Realloc(uint uiNewLenBuf);
+
+  /// Add a binary bloc
+  void PutBloc(const void* p, uint uiNb);
+
+  /// Get a binary bloc from the buffer
+  int GetBloc(void* p, uint uiNb);
+
+  /// Insert a binary bloc at given offset
+  void InsertBloc(const void* p, uint uiNb, uint uiPos);
+
+  /// Move a part of the buffer
+  void MoveBloc(uint uiDst, uint uiSrc, uint uiSize);
+
+  /// Set current read point to the begining
+  void Rewind()  { m_uiPos = 0; }
+
+  /// Set the current read point
+  void SetPos(uint ui)
+    {
+//##      ASSERT(ui <= m_uiLen)
+      m_uiPos = ui;
+    }
+
+  /// Reset without free buffer memory
+  void Empty()
+  {
+    m_uiPos = 0 ;
+    m_uiLen = 0 ;
+  }
+
+  /// Give buffer ownership to *this* instance
+  void SetOwner(bool bOwner) { m_bOwner = bOwner; }
+
+  /// Give buffer ownership to another instance
+  int GiveOwnership(CMemBuf* pToHaveOwnership);
+
+  /// Reset with memory freeing
+  void Reset();
+
+  /// Compute CRC
+  ulong GetCrc() const;
+
+  // Reading from file
+  // @in pszFileName: file name
+//  int LoadFile(const char *pszFileName);
+  
+  // Saving to a file
+// int SaveToFile(const CFileName& fnFile, const char *pszMode= "w",
+//    uint uiShareMode = CFILE_SHARE_COMPAT) const;
+
+  /// Pointer to current position
+  char *CurPointer() const  { return (m_pBuf + m_uiPos); }
+
+  /// Stream methods
+  CMemBuf& operator<<(char c);
+  CMemBuf& operator>>(char &c);
+  CMemBuf& operator<<(uchar uc);
+  CMemBuf& operator>>(uchar &uc);
+  CMemBuf& operator<<(short s);
+  CMemBuf& operator>>(short &s);
+  CMemBuf& operator<<(ushort us);
+  CMemBuf& operator>>(ushort &us);
+  CMemBuf& operator<<(long l);
+  CMemBuf& operator>>(long &l);
+  CMemBuf& operator<<(int64 i64);
+  CMemBuf& operator>>(int64 &i64);
+  CMemBuf& operator<<(ulong ul);
+  CMemBuf& operator>>(ulong &ul);
+  CMemBuf& operator<<(float f);
+  CMemBuf& operator>>(float &f);
+  CMemBuf& operator<<(double d);
+  CMemBuf& operator>>(double &d);
+  CMemBuf& operator<<(const char* psz);
+  CMemBuf& operator<<(const string& string);
+  CMemBuf& operator>>(string& string);
+  CMemBuf& operator<<(const CMemBuf& membuf);
+
+  // Get buffer content as hexadecimal string
+  String HexString() const;
+
+  /// Put a haxadecimal string into the buffer
+  void PutHexString(const char *pszHex, int iLen = -1);
+  
+  /// Reversible crypting
+  int ReversibleCrypt(const void* pXorKey=NULL, uint uiXorKeyLen=0,
+                      const void* pRotKey=NULL, uint uiRotKeyLen=0,
+                      short sVersion=REVCRYPT_LATEST_VERSION);
+
+  /// Decrypting
+  int ReversibleDecrypt(const void* pXorKey=NULL, uint uiXorKeyLen=0,
+                        const void* pRotKey=NULL, uint uiRotKeyLen=0, 
+                        short *psVersion=NULL);
+
+  /// Do xor logical encoding
+  void Xor(const void* pXor, uint uiXorLen);
+
+  /// Binary shifting using shift key
+  void BinRotLeft(const void* pRot, uint uiRotLen);
+  void BinRotRight(const void* pRot, uint uiRotLen);
+
+  /// Random key generation
+  ///
+  /// @param iKeyLen key length
+  /// @param bInitRand initialize random serie
+  /// @return crypted key
+  static void KeyGen(CMemBuf *pmbKey, int iKeyLen, bool bInitRand=false);
+};
+
+// In order to rename CMemBuf type to MemBuf
+typedef  CMemBuf MemBuf;
+
+// Reference pointer to CMembuf type definition
+typedef RefPtr<CMemBuf> MemBufPtr;
+
+} // namespace soleil
+
+#endif // __MEMBUF_H___
diff --git a/contrib/applications/NXextract/src/nexusevaluator.cpp b/contrib/applications/NXextract/src/nexusevaluator.cpp
new file mode 100644
index 0000000..81d6a07
--- /dev/null
+++ b/contrib/applications/NXextract/src/nexusevaluator.cpp
@@ -0,0 +1,1052 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 20/07/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "date.h"
+#include "file.h"
+#include "nxfile.h"
+#include "membuf.h"
+#include "variant.h"
+
+#include <sstream>
+#include <cstdlib>
+#include <cstring>
+#include "nexusevaluator.h"
+#include "extractor.h"
+#include "templateparsor.h"
+
+// special attributes
+const char SIZE_ATTR[] = "_size_";
+const char RANK_ATTR[] = "_rank_";
+const char NAME_ATTR[] = "_name_";
+const char SCANDIM_ATTR[] = "_scandim_";
+const char COUNT_ATTR[] = "_count_";
+
+const int  MAX_RANK = 32; // Maximum array rank in NeXus files
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::NexusEvaluator
+//-----------------------------------------------------------------------------
+NexusEvaluator::NexusEvaluator(const String &strNeXusFile, ICounterVars *pCounterVars)
+{
+  m_nxf.OpenRead(PSZ(strNeXusFile));
+  m_pCounterVars = pCounterVars;
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::~NexusEvaluator
+//-----------------------------------------------------------------------------
+NexusEvaluator::~NexusEvaluator()
+{
+  m_nxf.Close();
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetSizeAttribute
+//-----------------------------------------------------------------------------
+bool NexusEvaluator::GetSizeAttribute(const NexusDataSet &nds, const String &_strAttrSpec, DataBuf *pValue)
+{
+  String strDim, strAttrSpec = _strAttrSpec;
+  // get dim
+  int iRc = ExtractToken(&strAttrSpec, '(', ')', &strDim);
+  if( 1 != iRc )
+    return false;
+  int iDim = atoi(PSZ(strDim))-1;
+  if( iDim < nds.Rank() && iDim >= 0 )
+  {
+    int iValue = nds.DimArray()[iDim];
+    pValue->DataType() = DataBuf::INT;
+    pValue->Reset();
+    *(pValue->MemBufRef()) << (long)iValue;
+    return true;
+  }
+  else
+  {
+    cerr << "Warning: Dimension(s) out of bounds!" << endl;
+    return false;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetDataSetInfo
+//-----------------------------------------------------------------------------
+bool NexusEvaluator::GetDataSetInfo(SSplittedRequest *pRequest, NexusDataSet **ppNxDataSet)
+{
+  // Get data set from NeXus data file
+  *ppNxDataSet = new NexusDataSet;
+
+  // Open data group in NeXus file
+  bool bOpened = m_nxf.OpenGroupPath(PSZ(pRequest->strGroupPath), false);
+  if( !bOpened )
+  {
+    cerr << "Warning: Cannot open group from path '" << pRequest->strGroupPath << "'" << endl;
+    return false;
+  }
+
+  String strDataSet = pRequest->strDataSet;
+
+  // open data set, if needed
+  if( !pRequest->strDataSet.empty() )
+  {
+    if( pRequest->strDataSet.StartWith('<') && pRequest->strDataSet.EndWith('>') )
+    {
+      // Special case : signal or axis dataset
+      strDataSet = pRequest->strDataSet.substr(1, pRequest->strDataSet.size()-2);
+      if( strDataSet.IsEqualsNoCase("SDS-signal") )
+        // Search for first signal
+        m_nxf.SearchFirstDataSetFromAttr("signal", &strDataSet);
+      else if( strDataSet.IsEqualsNoCase("SDS-axis") )
+        // Search for first axis
+        m_nxf.SearchFirstDataSetFromAttr("axis", &strDataSet);
+      else if( strDataSet.StartWith("SDS-axis", true) )
+      {
+        // Search for first axis along given dimension
+        String strDim = strDataSet.substr(strlen("SDS-axis"));
+        m_nxf.SearchFirstDataSetFromAttr("axis", &strDataSet, strDim);
+      }
+    }
+    // May be empty if 'SearchFirstDataSetFromAttr' didn't find any dataset
+    if( strDataSet.empty() )
+      return false;
+
+    bOpened = m_nxf.OpenDataSet(PSZ(strDataSet), false);
+
+    if( !bOpened )
+      return false;
+  }
+
+  if( SSplittedRequest::DATASET_ATTRIBUTE != pRequest->eType &&
+      SSplittedRequest::GLOBAL_ATTRIBUTE != pRequest->eType )
+  {
+    // Read data set content
+    m_nxf.GetDataSetInfo(*ppNxDataSet, PSZ(strDataSet));
+  }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetDataSet
+//-----------------------------------------------------------------------------
+bool NexusEvaluator::GetDataSet(SSplittedRequest *pRequest, NexusDataSet **ppNxDataSet, bool bUseCache)
+{
+  // Check if requested dataset in the same as previous time
+ /* if( pRequest->strDataSetPath.IsEquals(m_pairLastNamedDataSet.first) )
+  {
+      *ppNxDataSet = m_pairLastNamedDataSet.second;
+      return true;
+  }
+  else*/ 
+  if( !m_mapDataSetCache.empty() )
+  { // Search in cache.
+    DataSetMap::iterator i = m_mapDataSetCache.find(pRequest->strDataSetPath);
+    if( i != m_mapDataSetCache.end() )
+    {
+      // if we find it: we get the associated NexusDataSet and return true.  
+      *ppNxDataSet = (i->second);
+      return true;
+    }
+  }
+
+  // Get data set from NeXus data file
+  *ppNxDataSet = new NexusDataSet;
+
+  // Open data group in NeXus file
+  bool bOpened = m_nxf.OpenGroupPath(PSZ(pRequest->strGroupPath), false);
+  if( !bOpened )
+  {
+    cerr << "Warning: Cannot open group from path '" << pRequest->strGroupPath << "'" << endl;
+    return false;
+  }
+
+  String strDataSet = pRequest->strDataSet;
+
+  // open data set, if needed
+  if( !pRequest->strDataSet.empty() )
+  {
+    if( pRequest->strDataSet.StartWith('<') && pRequest->strDataSet.EndWith('>') )
+    {
+      // Special case : signal or axis dataset
+      strDataSet = pRequest->strDataSet.substr(1, pRequest->strDataSet.size()-2);
+      if( strDataSet.IsEqualsNoCase("SDS-signal") )
+        // Search for first signal
+        m_nxf.SearchFirstDataSetFromAttr("signal", &strDataSet);
+      else if( strDataSet.IsEqualsNoCase("SDS-axis") )
+        // Search for first axis
+        m_nxf.SearchFirstDataSetFromAttr("axis", &strDataSet);
+      else if( strDataSet.StartWith("SDS-axis", true) )
+      {
+        // Search for first axis along given dimension
+        String strDim = strDataSet.substr(strlen("SDS-axis"));
+        m_nxf.SearchFirstDataSetFromAttr("axis", &strDataSet, strDim);
+      }
+    }
+    // May be empty if 'SearchFirstDataSetFromAttr' didn't find any dataset
+    if( strDataSet.empty() )
+      return false;
+
+    bOpened = m_nxf.OpenDataSet(PSZ(strDataSet), false);
+
+    if( !bOpened )
+      return false;
+  }
+
+  if( SSplittedRequest::DATASET_ATTRIBUTE != pRequest->eType &&
+      SSplittedRequest::GLOBAL_ATTRIBUTE != pRequest->eType )
+  {
+    // Read data set content
+    m_nxf.GetData(*ppNxDataSet, PSZ(strDataSet));
+
+    if( bUseCache )
+      // Add dataset in cache
+      m_mapDataSetCache.insert(DataSetMap::value_type(pRequest->strDataSetPath, *ppNxDataSet));
+//    m_pairLastNamedDataSet.first = pRequest->strDataSetPath;
+//    m_pairLastNamedDataSet.second = *ppNxDataSet;
+  }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::Evaluate
+//-----------------------------------------------------------------------------
+bool NexusEvaluator::Evaluate(const String &strRequest, DataBuf *pValue)
+{
+  try
+  {
+    if( StartWith(strRequest, "nxs") == false )
+      return false;
+
+    // Search for request
+    SSplittedRequest *pRequest = GetSplittedRequest(strRequest); // 4 = strlen("nxs:")
+
+    // For array access  
+    int aiDim[MAX_RANK] = {1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+                          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+    NexusDataSet *pNxData = NULL;
+
+    // Emptying output buffer
+    pValue->Reset();
+
+    bool bUseCache = false;
+    switch( pRequest->eType )
+    {
+      case SSplittedRequest::GLOBAL_ATTRIBUTE:
+      case SSplittedRequest::DATASET_ATTRIBUTE:
+      case SSplittedRequest::DATASET_ARRAY_ELEMENT:
+        bUseCache = true;
+        if( !GetDataSet(pRequest, &pNxData) )
+          return false;
+        break;
+      case SSplittedRequest::DATASET:
+        // In case of reading a entire dataset, don't put it in cache after reading
+        if( !GetDataSet(pRequest, &pNxData, false) )
+          return false;
+        break;
+      case SSplittedRequest::NAME_ATTRIBUTE:
+      case SSplittedRequest::RANK_ATTRIBUTE:
+      case SSplittedRequest::SIZE_ATTRIBUTE:
+        if( !GetDataSetInfo(pRequest, &pNxData) )
+          return false;
+        break;
+      default:
+        break;
+    }
+
+    switch( pRequest->eType )
+    {
+      case SSplittedRequest::DATASET_ARRAY_ELEMENT:
+        // Fill dim array
+        GetCoordinates(*pRequest, aiDim, pNxData->Rank());
+        GetDataEx(*pNxData, aiDim, pValue);
+        break;
+
+      case SSplittedRequest::DATASET:
+        // get datas
+        GetData(*pNxData, aiDim, pValue, true);
+        break;
+
+      case SSplittedRequest::GLOBAL_ATTRIBUTE:
+      case SSplittedRequest::DATASET_ATTRIBUTE:
+      {
+        if( pNxData->Data() == NULL )
+        {
+          NexusDataType nxType = NX_NONE;
+          if( ReadAttribute(pRequest->strAttr, pValue, &nxType) )
+          {
+            // Put value into a fake data set
+            pNxData->SetInfo(nxType, 1);
+            if( NX_CHAR == nxType )
+              pNxData->SetDimension(0, pValue->MemBufRef()->Len());
+            else
+              pNxData->SetDimension(0, 1);
+            char *pBuf = new char[pValue->MemBufRef()->Len()];
+            memcpy(pBuf, pValue->Buf(), pValue->MemBufRef()->Len());
+            pNxData->SetData(pBuf);
+          }
+          else
+            return false;
+        }
+        else
+          GetData(*pNxData, aiDim, pValue);
+        break;
+      }
+
+      case SSplittedRequest::NAME_ATTRIBUTE:
+      {
+        pValue->DataType() = DataBuf::CHAR;
+        pValue->MemBufRef()->PutBloc(PSZ(pRequest->strDataSet), pRequest->strDataSet.size());
+        *(pValue->MemBufRef()) << char('\0');
+        break;
+      }
+
+      case SSplittedRequest::RANK_ATTRIBUTE:
+      {
+        int iRank = pNxData->Rank();
+        pValue->DataType() = DataBuf::INT;
+        pValue->MemBufRef()->PutBloc(&iRank, sizeof(int));
+        break;
+      }
+
+      case SSplittedRequest::SIZE_ATTRIBUTE:
+        return GetSizeAttribute(*pNxData, pRequest->strLastPart, pValue);
+
+      case SSplittedRequest::SCANDIM_ATTRIBUTE:
+      {
+        int iDim = m_nxf.GetScanDim(PSZ(pRequest->strGroupPath));
+        pValue->DataType() = DataBuf::INT;
+        pValue->MemBufRef()->PutBloc(&iDim, sizeof(int));
+        break;
+      }
+
+      default:
+        break;
+    }
+
+    // If the NeXus dataset is not put in cache it ban be deleted since no longer referenced
+    if( !bUseCache && pNxData )
+      delete pNxData;
+  }
+  catch(Exception e)
+  {
+    e.PrintMessage();
+    throw e;
+  }
+  catch(NexusException e)
+  {
+    e.PrintMessage();
+    throw e;
+  }
+
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetCoordinates
+//-----------------------------------------------------------------------------
+void NexusEvaluator::GetCoordinates(const SSplittedRequest &Request, int *piDim, int iRank)
+{
+  for(uint ui = 0; ui < Request.vecArrayCoordinates.size(); ui++ )
+  {
+    if( ui > (uint)iRank )
+    {
+      cerr << "Warning: Ignore coordinates in excessive number" << endl;
+      break;
+    }
+    bool bVal = m_pCounterVars->GetValue(Request.vecArrayCoordinates[ui], &piDim[ui]);
+    if( !bVal )
+      piDim[ui] = atoi(PSZ(Request.vecArrayCoordinates[ui]));
+  }
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetSplittedRequest
+//-----------------------------------------------------------------------------
+SSplittedRequest *NexusEvaluator::GetSplittedRequest(const String &strRequest)
+{
+ /* if( strRequest.IsEquals(m_pairLastRequest.first) )
+    return &(*m_pairLastRequest.second).second;
+  else */
+  if( !m_mapRequestCache.empty() )
+  { // Search in cache first
+    MapRequests::iterator it = m_mapRequestCache.find(strRequest);
+    if( it != m_mapRequestCache.end() )
+      return &(it->second);
+  }
+
+  SSplittedRequest aRequest;
+  aRequest.strGroupPath = strRequest.substr(strlen("nxs:"));
+  uint uiSep = aRequest.strGroupPath.find_last_of('/');
+  // Extract Attribute part
+  uint uiLastDot = aRequest.strGroupPath.find_last_of('.');
+  if( uiLastDot != String::npos && 
+      ((uiLastDot > 0 && '\\' != aRequest.strGroupPath[uiLastDot-1]) 
+      || 0 == uiLastDot) && (uiSep == String::npos || (uiSep != String::npos && uiSep < uiLastDot)) )
+  {
+    // Get Attribute name
+    aRequest.strAttr = aRequest.strGroupPath.substr(uiLastDot+1);
+    if( uiLastDot != String::npos )
+      aRequest.strGroupPath.erase(uiLastDot);
+    // Extract extra information
+    uint uiBrace = aRequest.strAttr.find_first_of('(');
+    if( uiBrace != String::npos && uiBrace > 0 )
+    {
+      aRequest.strLastPart = aRequest.strAttr.substr(uiBrace);
+      aRequest.strAttr.erase(uiBrace);
+    }
+  }
+
+  // Extract data set part
+  if( uiSep != String::npos )
+  {
+    aRequest.strDataSet = aRequest.strGroupPath.substr(uiSep+1);
+    if( !aRequest.strDataSet.empty() )
+    {
+      aRequest.strGroupPath.erase(uiSep);
+      uint uiBrace = aRequest.strDataSet.find_first_of('[');
+      if( uiBrace != String::npos && uiBrace > 0 )
+      {
+        aRequest.strLastPart = aRequest.strDataSet.substr(uiBrace);
+        aRequest.strDataSet.erase(uiBrace);
+      }
+    }
+  }
+
+  // Check for request type
+  if( !aRequest.strAttr.empty() )
+  {
+    if( IsEqualsNoCase(aRequest.strAttr, SIZE_ATTR) )
+      aRequest.eType = SSplittedRequest::SIZE_ATTRIBUTE;
+    else if( IsEqualsNoCase(aRequest.strAttr, RANK_ATTR) )
+      aRequest.eType = SSplittedRequest::RANK_ATTRIBUTE;
+    else if( IsEqualsNoCase(aRequest.strAttr, NAME_ATTR) )
+      aRequest.eType = SSplittedRequest::NAME_ATTRIBUTE;
+    else if( IsEqualsNoCase(aRequest.strAttr, SCANDIM_ATTR) )
+      aRequest.eType = SSplittedRequest::SCANDIM_ATTRIBUTE;
+    else if( !aRequest.strDataSet.empty() )
+      aRequest.eType = SSplittedRequest::DATASET_ATTRIBUTE;
+    else
+      aRequest.eType = SSplittedRequest::GLOBAL_ATTRIBUTE;
+  }
+  else if( !aRequest.strDataSet.empty() )
+  {
+    if( !aRequest.strLastPart.empty() )
+      aRequest.eType = SSplittedRequest::DATASET_ARRAY_ELEMENT;
+    else
+      aRequest.eType = SSplittedRequest::DATASET;
+  }
+  else
+    // Bad request
+    return NULL;
+
+  // Compute data set path
+  aRequest.strDataSetPath = aRequest.strGroupPath;
+  if( !aRequest.strDataSet.empty() )
+    aRequest.strDataSetPath += '/' + aRequest.strDataSet;
+
+  if( SSplittedRequest::DATASET_ATTRIBUTE == aRequest.eType ||
+      SSplittedRequest::GLOBAL_ATTRIBUTE == aRequest.eType )
+    aRequest.strDataSetPath += '.' + aRequest.strAttr;
+
+  if( SSplittedRequest::DATASET_ARRAY_ELEMENT == aRequest.eType )
+  {
+    // Extract coordinates for array access
+    String strCoord, str = aRequest.strLastPart;
+    while( !str.empty() )
+    {
+      ExtractToken(&str, '[', ']', &strCoord);
+      aRequest.vecArrayCoordinates.insert(aRequest.vecArrayCoordinates.begin(), strCoord);
+    }
+  }
+
+  // Insert request in cache
+  pair<MapRequests::iterator, bool> pair = m_mapRequestCache.insert(MapRequests::value_type(strRequest, aRequest));
+//  m_pairLastRequest.first = strRequest;
+//  m_pairLastRequest.second = pair.first;
+
+  return &((pair.first)->second);
+  //## todo: Replace escaped '.' characters
+}
+
+#define TData(T, type) {\
+  pValue->DataType() = type;\
+  pValue->MemBufRef()->PutBloc((T *)(nxDataSet.Data()) + iOffset,  sizeof(T));}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetScalarDataFromArray
+//-----------------------------------------------------------------------------
+void NexusEvaluator::GetScalarDataFromArray(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue)
+{
+  // Check coordinates & calculate rank
+  int iRank = nxDataSet.Rank();
+  // Calculate data offset in case of array access
+  int iOffset = 0;
+  for( int i = 0; i < iRank; i++ )
+  {
+    int iBase = 1;
+    for( int j = 0; j < i; j++ )
+      iBase *= nxDataSet.DimArray()[iRank - j - 1];
+    iOffset += iBase * piDim[i];
+  }
+
+  // Get data according to its type
+  switch( nxDataSet.DataType() )
+  {
+    case NX_INT8:
+      TData(uint8, DataBuf::BYTE);
+      break;
+    case NX_INT16:
+      TData(short, DataBuf::SHORT)
+      break;
+    case NX_UINT16:
+      TData(unsigned short, DataBuf::USHORT)
+      break;
+    case NX_INT32:
+      TData(long, DataBuf::LONG)
+      break;
+    case NX_UINT32:
+      TData(unsigned long, DataBuf::ULONG)
+      break;
+    case NX_FLOAT32:
+      TData(float, DataBuf::FLOAT)
+      break;
+    case NX_FLOAT64:
+      TData(double, DataBuf::DOUBLE)
+      break;
+    case NX_CHAR:
+    {
+      if( nxDataSet.Data() != NULL )
+      {
+        pValue->DataType() = DataBuf::CHAR;
+        // Copy char array
+        pValue->MemBufRef()->PutBloc(nxDataSet.Data(), nxDataSet.DimArray()[0]);
+        *(pValue->MemBufRef()) << char('\0');
+      }
+    }
+    break;
+    default:
+	  break;
+  }
+
+  pValue->SetRank(1);
+  pValue->SetSize(0, 1);
+}
+
+#define TData1D(T, type) {\
+  pValue->DataType() = type;\
+  pValue->MemBufRef()->PutBloc((T *)(nxDataSet.Data()) + iOffset,  iDataDim * sizeof(T));}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::Get1DDataFromArray
+//-----------------------------------------------------------------------------
+void NexusEvaluator::Get1DDataFromArray(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue)
+{
+  // Check coordinates & calculate rank
+  int iRank = nxDataSet.Rank();
+  // Calculate data offset
+  int iOffset = 0;
+  int iDataDim = nxDataSet.DimArray()[iRank - 1];
+  for( int i = 0; i < iRank-1; i++ )
+  {
+    int iBase = iDataDim;
+    for( int j = 0; j < i; j++ )
+      iBase *= nxDataSet.DimArray()[iRank - j - 2];
+    iOffset += iBase * piDim[i];
+  }
+
+  // Get data according to its type
+  switch( nxDataSet.DataType() )
+  {
+    case NX_INT8:
+      TData1D(uint8, DataBuf::BYTE);
+      break;
+    case NX_INT16:
+      TData1D(short, DataBuf::SHORT)
+      break;
+    case NX_UINT16:
+      TData1D(unsigned short, DataBuf::USHORT)
+      break;
+    case NX_INT32:
+      TData1D(long, DataBuf::LONG)
+      break;
+    case NX_UINT32:
+      TData1D(unsigned long, DataBuf::ULONG)
+      break;
+    case NX_FLOAT32:
+      TData1D(float, DataBuf::FLOAT)
+      break;
+    case NX_FLOAT64:
+      TData1D(double, DataBuf::DOUBLE)
+      break;
+    break;
+    default:
+	  break;
+  }
+
+  pValue->SetRank(1);
+  pValue->SetSize(0, iDataDim);
+}
+
+#define TData2D(T, type) {\
+  pValue->DataType() = type;\
+  pValue->MemBufRef()->PutBloc((T *)(nxDataSet.Data()) + iOffset,  iDataDim * sizeof(T));}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::Get2DDataFromArray
+//-----------------------------------------------------------------------------
+void NexusEvaluator::Get2DDataFromArray(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue)
+{
+  // Check coordinates & calculate rank
+  int iRank = nxDataSet.Rank();
+  // Calculate data offset
+  int iOffset = 0;
+  int iDataDim = nxDataSet.DimArray()[iRank - 1] * nxDataSet.DimArray()[iRank - 2];
+  for( int i = 0; i < iRank-2; i++ )
+  {
+    int iBase = iDataDim;
+    for( int j = 0; j < i; j++ )
+      iBase *= nxDataSet.DimArray()[iRank - j - 3];
+    iOffset += iBase * piDim[i];
+  }
+
+  // Get data according to its type
+  switch( nxDataSet.DataType() )
+  {
+    case NX_INT8:
+      TData2D(uint8, DataBuf::BYTE);
+      break;
+    case NX_INT16:
+      TData2D(short, DataBuf::SHORT)
+      break;
+    case NX_UINT16:
+      TData2D(unsigned short, DataBuf::USHORT)
+      break;
+    case NX_INT32:
+      TData2D(long, DataBuf::LONG)
+      break;
+    case NX_UINT32:
+      TData2D(unsigned long, DataBuf::ULONG)
+      break;
+    case NX_FLOAT32:
+      TData2D(float, DataBuf::FLOAT)
+      break;
+    case NX_FLOAT64:
+      TData2D(double, DataBuf::DOUBLE)
+      break;
+    break;
+    default:
+	  break;
+  }
+
+  pValue->SetRank(1);
+  pValue->SetSize(0, nxDataSet.DimArray()[iRank - 1]);
+  pValue->SetSize(1, nxDataSet.DimArray()[iRank - 2]);
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetDataEx
+//-----------------------------------------------------------------------------
+void NexusEvaluator::GetDataEx(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue, bool bGetAllBuffer)
+{
+  // Emptying buffer first
+  pValue->Reset();
+
+  if( bGetAllBuffer )
+  { //
+    // In the case of number values array with no given index get entire dataset
+    //
+    // Emptying buffer
+    pValue->Reset();
+
+    // Fill buffer with data
+    pValue->MemBufRef()->PutBloc(nxDataSet.Data(), nxDataSet.BufferSize());
+
+    pValue->SetTypeFromNeXusType(nxDataSet.DataType());
+    pValue->SetRank(nxDataSet.Rank());
+    for( int i = 0; i < nxDataSet.Rank(); i++ )
+      pValue->SetSize(i, nxDataSet.DimArray()[i]);
+    return;
+  }
+
+  // Check coordinates & calculate rank
+  int iRank = nxDataSet.Rank(), i=0;
+
+  for(i = 0; i < iRank; i++ )
+  {
+    if( -1 == piDim[i] )
+      break;
+
+
+//## 29/01/10 : � v�rifier
+//    if( piDim[i] < 0 || piDim[i] > nxDataSet.DimArray()[iRank - i - 1] )
+    if( piDim[i] < 0 || piDim[i] > nxDataSet.DimArray()[i] )
+    {
+      throw Exception(PSZ(StrFormat("Cannot read array at index %d on dimension %d. Dimension size is %d", piDim[i], i+1, nxDataSet.DimArray()[i])), "ARRAY_OUT_OF_BOUNDS", "NexusEvaluator::GetData");
+    }
+  }
+  int iDimMax = i;
+  // Dimension of data returned
+  int iDataDim = iRank - i;
+
+  switch( iDataDim )
+  {
+    case 0:
+      GetScalarDataFromArray(nxDataSet, piDim, pValue);
+      break;
+    case 1:
+      Get1DDataFromArray(nxDataSet, piDim, pValue);
+      break;
+    case 2:
+      Get2DDataFromArray(nxDataSet, piDim, pValue);
+      break;
+    default:
+      throw Exception(PSZ(StrFormat("Array slicing in more than 2D is not yet supported", "BAD_PARAMETERS", "NexusEvaluator::GetData")));
+  }
+  pValue->SetTypeFromNeXusType(nxDataSet.DataType());
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetData
+//-----------------------------------------------------------------------------
+void NexusEvaluator::GetData(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue, bool bGetAllBuffer)
+{
+  // Emptying buffer first
+  pValue->Reset();
+
+  if( bGetAllBuffer )
+  { //
+    // In the case of number values array with no given index get entire dataset
+    //
+    // Emptying buffer
+    pValue->Reset();
+
+    // Fill buffer with data
+    pValue->MemBufRef()->PutBloc(nxDataSet.Data(), nxDataSet.BufferSize());
+
+    pValue->SetTypeFromNeXusType(nxDataSet.DataType());
+    pValue->SetRank(nxDataSet.Rank());
+    for( int i = 0; i < nxDataSet.Rank(); i++ )
+      pValue->SetSize(i, nxDataSet.DimArray()[i]);
+    return;
+  }
+
+  // Check coordinates & calculate rank
+  int iRank = nxDataSet.Rank();
+
+  for( int i = 0; i < iRank; i++ )
+  {
+    if( -1 == piDim[i] )
+      break;
+
+//## 29/01/10 : � v�rifier
+//    if( piDim[i] < 0 || piDim[i] > nxDataSet.DimArray()[iRank - i - 1] )
+    if( piDim[i] < 0 || piDim[i] > nxDataSet.DimArray()[i] )
+    {
+      throw Exception(PSZ(StrFormat("Cannot read array at index %d on dimension %d. Dimension size is %d", piDim[i], i+1, nxDataSet.DimArray()[iRank])), "ARRAY_OUT_OF_BOUNDS", "NexusEvaluator::GetData");
+    }
+  }
+
+  // Calculate data offset in case of array access
+  int iOffset = 0;
+  switch( iRank )
+  {
+    case 1:
+      iOffset = piDim[0];
+      break;
+    case 2:
+      iOffset = nxDataSet.DimArray()[iRank-1] * (piDim[1]) + (piDim[0]);
+      break;
+    default:
+    {    
+      int iBase, j;
+      for( int i = 0; i < iRank; i++ )
+      {
+        iBase = 1;
+        for( j = 0; j < i; j++ )
+          iBase *= nxDataSet.DimArray()[iRank - j - 1];
+        iOffset += iBase * piDim[i];
+      }
+      break;
+    }
+  }
+
+  // Get data according to its type
+  switch( nxDataSet.DataType() )
+  {
+    case NX_INT8:
+      TData(uint8, DataBuf::BYTE);
+      break;
+    case NX_INT16:
+      TData(short, DataBuf::SHORT)
+      break;
+    case NX_UINT16:
+      TData(unsigned short, DataBuf::USHORT)
+      break;
+    case NX_INT32:
+      TData(long, DataBuf::LONG)
+      break;
+    case NX_UINT32:
+      TData(unsigned long, DataBuf::ULONG)
+      break;
+    case NX_FLOAT32:
+      TData(float, DataBuf::FLOAT)
+      break;
+    case NX_FLOAT64:
+      TData(double, DataBuf::DOUBLE)
+      break;
+    case NX_CHAR:
+    {
+      if( nxDataSet.Data() != NULL )
+      {
+        pValue->DataType() = DataBuf::CHAR;
+        // Copy char array
+        pValue->MemBufRef()->PutBloc(nxDataSet.Data(), nxDataSet.DimArray()[0]);
+        *(pValue->MemBufRef()) << char('\0');
+      }
+    }
+    break;
+    default:
+	  break;
+  }
+
+  pValue->SetRank(1);
+  pValue->SetSize(0, 1);
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::GetItems
+//-----------------------------------------------------------------------------
+ItemList *NexusEvaluator::GetItemsList(String *pstrPath, const String &strName)
+{
+  // First search in cache
+  ListCache::iterator itCache = m_mapListCache.find(*pstrPath);
+  if( itCache != m_mapListCache.end() )
+    return &(itCache->second);
+
+  else
+  {
+    String strTypeName;
+    String strAxisDimension;
+    String strPath = *pstrPath;
+    int    iSignalDimension = -1;
+
+    // NeXus dataset ?
+    if( pstrPath->StartWith("nxs:") )
+      pstrPath->erase(0, strlen("nxs:"));
+
+    while( pstrPath->EndWith('/') )
+      // Suppress leading slashes
+      pstrPath->erase(pstrPath->size()-1);
+
+    // Get item on which iterate
+    pstrPath->ExtractTokenRight('<', '>', &strTypeName);
+
+    bool bAxis = false, bSignal = false, bGroup = false;
+    if( strTypeName.IsEqualsNoCase("SDS-signal") || strTypeName.IsEqualsNoCase("scan-data"))
+      bSignal = true;
+    else if( strTypeName.StartWith("SDS-signal", true) )
+    {
+      bSignal = true;
+      // Read the specified signal dimension
+      String strSignalDimension = strTypeName.substr(strlen("SDS-signal"));
+      iSignalDimension = atoi(PSZ(strSignalDimension));
+    }
+    else if( strTypeName.StartWith("scan-data", true) )
+    {
+      bSignal = true;
+      // Read the specified signal dimension
+      String strSignalDimension = strTypeName.substr(strlen("scan-data"));
+      iSignalDimension = atoi(PSZ(strSignalDimension)) + m_nxf.GetScanDim(PSZ(*pstrPath));
+    }
+    else if( strTypeName.IsEqualsNoCase("SDS-axis") )
+      bAxis = true;
+    else if( strTypeName.StartWith("SDS-axis", true) )
+    {
+      bAxis = true;
+      // Read the specified dimension
+      strAxisDimension = strTypeName.substr(strlen("sds-axis"));
+    }
+    else if( strTypeName.IsEqualsNoCase("Dataset") || strTypeName.IsEqualsNoCase("SDS") )
+     ;
+    else
+      bGroup = true;
+
+    // Get Items
+    ItemList lstItems;
+
+    // Check for wildcard
+    uint uiQMarkPos = pstrPath->find("/?/");
+    if( uiQMarkPos != string::npos )
+    {
+      if( bAxis || bSignal )
+      {
+        cerr << "To Iterate over SDS-Axis or SDS-signal, parent group type must be fully determined" << endl;
+        return NULL;
+      }
+
+      vector<string> vecPaths;
+      m_nxf.SearchGroup(NULL, PSZ(strTypeName), &vecPaths, PSZ(pstrPath->substr(0, uiQMarkPos)));
+      for( uint ui = 0; ui < vecPaths.size(); ui++ )
+      {
+        // Build item pair : (name ,path)
+        String strTmp = vecPaths[ui], strName;
+        strTmp.ExtractTokenRight('<', '>', &strName);
+        strTmp.ExtractTokenRight('/', &strName);
+        lstItems.push_back(NxItem(strName, vecPaths[ui]));
+      }
+    }
+    else
+    {
+      // Open parent group
+      m_nxf.OpenGroupPath(PSZ(*pstrPath));
+
+      // Check opened group type
+      if( !bGroup && !String(m_nxf.CurrentGroupClass()).IsEqualsNoCase("NXdata") )
+      {
+        cerr << "To Iterate over SDS-Axis or SDS-signal, parent group type must be 'NXdata'" << endl;
+        return NULL;
+      }
+
+      NexusItemInfo  ItemInfo;
+      int  iStatus = m_nxf.GetFirstItem(&ItemInfo);
+      while( iStatus != NX_EOD )
+      {
+        if( bGroup && ItemInfo.IsGroup() && strTypeName.IsEquals(ItemInfo.ClassName()) )
+          // Store the item name and path
+          lstItems.push_back(NxItem(ItemInfo.ItemName(), (*pstrPath) + ItemInfo.ItemName()));
+
+        // Retreive all signal regardless dimensions
+        else if( bSignal && ItemInfo.IsDataSet() && m_nxf.HasAttribute("signal", ItemInfo.ItemName()) && -1 == iSignalDimension )
+          lstItems.push_back(NxItem(ItemInfo.ItemName(), (*pstrPath) + ItemInfo.ItemName()));
+
+        // Retreive signal of specified dimension size
+        else if( bSignal && ItemInfo.IsDataSet() && m_nxf.HasAttribute("signal", ItemInfo.ItemName()) )
+        {
+          NexusDataSetInfo info;
+          m_nxf.GetDataSetInfo(&info, ItemInfo.ItemName());
+          if( info.Rank() == iSignalDimension )
+            lstItems.push_back(NxItem(ItemInfo.ItemName(), (*pstrPath) + ItemInfo.ItemName()));
+        }
+
+        // Retreive axis datasets of given dimension
+        else if( bAxis && ItemInfo.IsDataSet() && m_nxf.HasAttribute("axis", ItemInfo.ItemName(), strAxisDimension) )
+          lstItems.push_back(NxItem(ItemInfo.ItemName(), (*pstrPath) + ItemInfo.ItemName()));
+
+        iStatus = m_nxf.GetNextItem(&ItemInfo);
+      }
+    }
+    m_nxf.CloseAllGroups();
+
+    // Add list in cache and return pointer to inserted object
+    return &(m_mapListCache.insert(ListCache::value_type(strPath, lstItems)).first->second);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::ReadAttribute
+//-----------------------------------------------------------------------------
+bool NexusEvaluator::ReadAttribute(const String &strAttr, DataBuf *pValue, NexusDataType *pNxType)
+{
+  NexusAttrInfo AttrInfo;
+  int iStatus = m_nxf.GetFirstAttribute(&AttrInfo);
+  // we look for the attribute strAttr.
+  while( iStatus != NX_EOD )
+  {
+    if( IsEqualsNoCase(strAttr, AttrInfo.AttrName()) )
+    {
+      pValue->MemBufRef()->SetLen(4096);
+      pValue->Empty();
+      int iBufLen = pValue->MemBufRef()->BufLen();
+      m_nxf.GetAttribute(AttrInfo.AttrName(), &iBufLen, pValue->Buf(), AttrInfo.DataType());
+      // Put real length
+      pValue->MemBufRef()->SetLen(iBufLen);
+
+      ostringstream oss;
+      switch (AttrInfo.DataType()) 
+      {
+        case NX_CHAR:
+          pValue->DataType() = DataBuf::CHAR;
+          break;
+        case NX_INT:
+          pValue->DataType() = DataBuf::INT;
+          break;
+        case NX_INT32:
+          pValue->DataType() = DataBuf::LONG;
+          break;
+        case NX_INT16:
+          pValue->DataType() = DataBuf::SHORT;
+          break;
+        case NX_INT8:
+          pValue->DataType() = DataBuf::BYTE;
+          break;
+        case NX_FLOAT32:
+          pValue->DataType() = DataBuf::FLOAT;
+          break;
+        case NX_FLOAT64:
+          pValue->DataType() = DataBuf::DOUBLE;
+          break;
+        default:
+          return false;
+      }
+      *pNxType = AttrInfo.DataType();
+      return true;
+    }
+    iStatus = m_nxf.GetNextAttribute(&AttrInfo);
+  }
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+// NexusEvaluator::CheckItem
+//-----------------------------------------------------------------------------
+bool NexusEvaluator::CheckItem(const String &_strPath)
+{
+  String strPath = _strPath, strDataSet, strAttribut;
+  if( strPath.StartWith("nxs:") )
+    strPath.erase(0, strlen("nxs:"));
+
+  // Attribute part ?
+  if( strPath.find_last_of('.') != string::npos )
+    strPath.ExtractTokenRight('.', &strAttribut);
+
+  if( strPath.EndWith('/') )
+  {
+    // It is a group path
+    if( !m_nxf.OpenGroupPath(PSZ(strPath), false) )
+      return false;
+    // Group attribute ?
+    if( !strAttribut.empty() && !m_nxf.HasAttribute(PSZ(strAttribut)) )
+      return false;
+    return true;
+  }
+
+  // Extract DataSet part
+
+  strPath.ExtractTokenRight('/', &strDataSet);
+
+  if( !m_nxf.OpenGroupPath(PSZ(strPath), false) )
+    return false;
+
+  // Try to opening dataset
+  if( !strDataSet.empty() && m_nxf.OpenDataSet(PSZ(strDataSet), false)  == false )
+     return false;
+
+  // Check attribute
+  if( !strAttribut.empty() && !m_nxf.HasAttribute(PSZ(strAttribut)) )
+    return false;
+
+  return true;
+}
diff --git a/contrib/applications/NXextract/src/nexusevaluator.h b/contrib/applications/NXextract/src/nexusevaluator.h
new file mode 100644
index 0000000..48f03d4
--- /dev/null
+++ b/contrib/applications/NXextract/src/nexusevaluator.h
@@ -0,0 +1,124 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// in this Class we evaluate a data by looking for its value in the Nexus File.
+//
+// Creation : 20/07/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __NEXUSEVALUATOR_H__
+#define __NEXUSEVALUATOR_H__
+
+using namespace gdshare; 
+
+// Forward declaration
+class DataBuf;
+
+// we use this map to stock the NexusDataSet that we have already look for.
+typedef map<String, NexusDataSet *> DataSetMap;
+//typedef pair<String, NexusDataSet *> NamedDataSetPair;
+// we use this map to stock the names of groups that we need in our iterations (
+// loop-over).
+
+typedef map<String, String> ListGroup;
+typedef pair<String,String> NxItem;  // (name, path) pair
+typedef list<NxItem> ItemList;
+typedef map<String, ItemList> ListCache;
+
+//-----------------------------------------------------------------------------
+// struct SSplittedRequest
+// Store a request components
+//-----------------------------------------------------------------------------
+struct SSplittedRequest
+{
+  // Request type
+  enum Type
+  {
+    DATASET_ARRAY_ELEMENT = 0,
+    DATASET,
+    DATASET_ATTRIBUTE,
+    GLOBAL_ATTRIBUTE,
+    SIZE_ATTRIBUTE,
+    RANK_ATTRIBUTE,
+    SCANDIM_ATTRIBUTE,
+    NAME_ATTRIBUTE
+  };
+
+  Type   eType;         // Request type
+  String strFullPath;   // Full request
+  String strGroupPath;  // Path to NeXus group
+  String strDataSet;    // DataSet name
+  String strAttr;       // Attribute name
+  String strLastPart;   // coordinate part
+  String strDataSetPath;// path to dataset
+
+  vector<String> vecArrayCoordinates; // 
+};
+typedef map<String, SSplittedRequest> MapRequests;
+//typedef pair<String, MapRequests::iterator> ItRequestNamedPair;
+//-----------------------------------------------------------------------------
+// Class NexusEvaluator
+//
+//-----------------------------------------------------------------------------
+class NexusEvaluator
+{
+private:
+  NexusFile           m_nxf;
+  DataSetMap          m_mapDataSetCache;
+  MapRequests         m_mapRequestCache;
+  ListCache           m_mapListCache;
+  ListGroup           m_listGroupe;
+  class ICounterVars *m_pCounterVars;
+
+  // Get the data from NeXus data set.
+  void GetData(const NexusDataSet &nxDataRes, int *piDim, DataBuf *pValue, bool bGetAllBuffer=false);
+  // Get the data from NeXus data set.
+  void GetDataEx(const NexusDataSet &nxDataRes, int *piDim, DataBuf *pValue, bool bGetAllBuffer=false);
+  // Get 2D data slices
+  void Get2DDataFromArray(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue);
+  // Get 1D data slices
+  void Get1DDataFromArray(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue);
+  // Get 0D data slices
+  void GetScalarDataFromArray(const NexusDataSet &nxDataSet, int *piDim, DataBuf *pValue);
+  // Retreive data set
+  bool GetDataSet(SSplittedRequest *pRequest, NexusDataSet **ppNxDataSet, bool bUseCache=true);
+  // Retreive data set information
+  bool GetDataSetInfo(SSplittedRequest *pRequest, NexusDataSet **ppNxDataSet);
+  // Retreive request in cache
+  SSplittedRequest *GetSplittedRequest(const String &strRequest);
+  
+  // Get "_size_" attribute
+  bool GetSizeAttribute(const NexusDataSet &nds, const String &strAttrSpec, DataBuf *pValue);
+  // Get coordinates
+  void GetCoordinates(const SSplittedRequest &Request, int *piDim, int iRank);
+  // get some usefull attributes (file_name,file_type..)
+  bool ReadAttribute(const String &strAttr, DataBuf *pValue, NexusDataType *pNxType);
+  // get the data to evaluate if bExist is true so we don't have to
+  // open the file else we open it.
+  bool OpenGroups(const String &strData);
+
+public:
+  NexusEvaluator(const String &strNeXusFile, ICounterVars *pCounterVars);
+  virtual ~NexusEvaluator(); 
+  // Get items list
+  ItemList *GetItemsList(String *strPath, const String &strName); 
+  // Evalute the a string and fill it in the end of the procedure by its value.
+  // return false if the string can't be evaluated.
+  virtual bool Evaluate(const String &strVar, DataBuf *pValue);
+
+  // Look for a item (group or dataset)
+  // return true if it exists, otherwise false
+  bool CheckItem(const String &_strPath);
+};
+
+#endif
diff --git a/contrib/applications/NXextract/src/nxfile.cpp b/contrib/applications/NXextract/src/nxfile.cpp
new file mode 100644
index 0000000..8961d21
--- /dev/null
+++ b/contrib/applications/NXextract/src/nxfile.cpp
@@ -0,0 +1,2246 @@
+//*****************************************************************************
+/// Synchrotron SOLEIL
+///
+/// NeXus C++ API over NAPI
+///
+/// Creation : 16/02/2005
+/// Author   : Stephane Poirier
+///
+/// This program is free software; you can redistribute it and/or modify it under
+/// the terms of the GNU General Public License as published by the Free Software
+/// Foundation; version 2 of the License.
+/// 
+/// This program is distributed in the hope that it will be useful, but WITHOUT 
+/// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+/// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+///
+//*****************************************************************************
+
+#ifndef NEXUSAPI
+  #ifdef WIN32
+    #include "napi.h"
+  #else // LINUX
+    #include <napi.h>
+  #endif
+#endif
+
+#ifdef WIN32
+  #pragma warning(disable:4786)
+#endif
+
+// Use enum instead of #define for NeXus DataTypes
+#undef NX_FLOAT32
+#undef NX_FLOAT64
+#undef NX_INT8   
+#undef NX_UINT8  
+#undef NX_INT16  
+#undef NX_UINT16 
+#undef NX_INT32  
+#undef NX_UINT32 
+#undef NX_INT64  
+#undef NX_UINT64 
+#undef NX_CHAR   
+#undef NX_BINARY
+
+// Use enum instead of #define for Nexus Status codes
+#undef NX_OK
+#undef NX_EOD
+
+#include "base.h"
+#include "file.h"
+#include <cstring>
+
+#include "nxfile.h"
+
+// STL headers
+#include <string>
+#include <list>
+#include <map>
+#include <vector>
+#include <stack>
+
+#include <sstream>
+
+using namespace soleil;
+
+// Error msgs
+const char CREATE_FILE_ERR[]        = "Cannot create file";
+const char OPENING_FILE_ERR[]       = "Cannot open file";
+const char OPENING_FILE_READ_ERR[]  = "Cannot open file for reading";
+const char OPENING_FILE_RW_ERR[]    = "Cannot open file for reading and writing";
+const char CREATE_DATA_ERR[]        = "Cannot create dataset '%s' (group '%s', file '%s')";
+const char BAD_GROUP_NAME_ERR[]     = "Null value passed as group name";
+const char OPEN_GROUP_ERR[]         = "Cannot open group '%s' (file '%s')";
+const char MAKE_GROUP_ERR[]         = "Cannot create group '%s' (file '%s')";
+const char OPEN_DATA_ERR[]          = "Cannot open dataset '%s' (group '%s', file '%s')";
+const char CLOSE_DATA_ERR[]         = "Cannot close dataset (group '%s', file '%s')";
+const char CLOSE_GROUP_ERR[]        = "Cannot close group '%s' in file '%s'";
+const char PUT_DATA_ERR[]           = "Cannot put data in dataset '%s' (group '%s', file '%s')";
+const char PUT_DATASUBSET_ERR[]     = "Cannot put data subset in dataset '%s' (group '%s', file '%s')";
+const char PUT_ATTR_ERR[]           = "Cannot write attribute '%s' (group '%s', file '%s')";
+const char GET_ATTR_ERR[]           = "Cannot read attribute '%s' (group '%s', file '%s')";
+const char GETINFO_ERR[]            = "Cannot read data set infos (dataset '%s', group '%s', file '%s')";
+const char GETDATA_ERR[]            = "Cannot read data set (dataset '%s', group '%s', file '%s')";
+const char FLUSH_ERR[]              = "Cannot flush data (file '%s')";
+const char GET_INIT_ENUM_ITEM[]     = "Cannot initialize group items enumeration (file '%s')";
+const char GET_RETREIVE_ITEM[]      = "Cannot retreive group items information (file '%s')";
+const char GET_INIT_ENUM_ATTR[]     = "Cannot initialize attributes enumeration (file '%s')";
+const char GET_RETREIVE_ATTR[]      = "Cannot retreive attributes information (file '%s')";
+const char LINK_ITEM_ERR[]          = "Cannot link item to current group (file '%s')";
+const char GET_GROUPINFO_ERR[]      = "Cannot read group infos (group '%s', file '%s')";
+const char GET_ATTRINFO_ERR[]       = "Cannot read attributes infos (group '%s', file '%s')";
+const char NO_SIGNAL_ATTR_ERR[]     = "Cannot find 'signal' attribute";
+
+// Reasons
+const char MISSING_FILE_NAME[]      = "Missing file name !";
+const char UNABLE_TO_OPEN_FILE[]    = "Unable to open '%s'";
+const char NO_HANDLE[]              = "Missing file handle !";
+const char OPERATION_FAILED[]       = "Operation failed !";
+const char NO_DATASET[]             = "No data set !";
+const char TYPES_MISMATCH[]         = "Type mismatch !";
+const char BAD_DATASET[]            = "Bad dataset";
+
+// Constantes
+const int MAX_DIM = 32;              // Max rank
+const int MAX_NAME_LENGTH = 256;      // For class, attributes, group names
+const char DATASET_CLASS[] = "SDS";  // Class name for NeXus data set
+const char ROOT_LEVEL[] = "root(NXroot)";    // Top level group of a NeXus file
+const string g_strNoDataSet = "(no data set)";
+
+//---------------------------------------------------------------------------
+// Free function that return a char * from a string objet
+//---------------------------------------------------------------------------
+inline char *PCSZToPSZ(const char *pcsz)
+{
+  return (char *)((void *)pcsz);
+}
+
+//=============================================================================
+// NeXus exceptions
+//
+//=============================================================================
+NexusException::NexusException(const char *pcszError, const char *pcszReason,
+                               const char *pcszMethod)
+{
+  m_pError = (void *)(new string(pcszError));
+  m_pReason = (void *)(new string(pcszReason));
+  m_pMethod = (void *)(new string(pcszMethod));
+}
+
+//---------------------------------------------------------------------------
+// NexusException::PrintMessage
+//---------------------------------------------------------------------------
+void NexusException::PrintMessage()
+{
+  cerr << "Nexus exception!" << endl
+       << "Desc  : " << *( string *)m_pError  << endl
+       << "Reason: " << *( string *)m_pReason << endl
+       << "Origin: " << *( string *)m_pMethod << endl;
+}
+
+//---------------------------------------------------------------------------
+// NexusException::GetMessage
+//---------------------------------------------------------------------------
+void NexusException::GetMsg(char *pBuf, int iLen)
+{
+  string strMsg;
+  strMsg  = "Nexus exception: " + *( string *)m_pError
+          + ". Reason: " + *( string *)m_pReason
+          + ". Origin: " + *( string *)m_pMethod + ".";
+  strncpy(pBuf, strMsg.c_str(), iLen - 1);
+}
+
+//---------------------------------------------------------------------------
+// NexusException::Error
+//---------------------------------------------------------------------------
+const char *NexusException::Error() const
+{
+  return (*( string *)m_pError).c_str();
+}
+
+//---------------------------------------------------------------------------
+// NexusException::Reason
+//---------------------------------------------------------------------------
+const char *NexusException::Reason() const
+{
+  return (*( string *)m_pReason).c_str();
+}
+
+//---------------------------------------------------------------------------
+// NexusException::Method
+//---------------------------------------------------------------------------
+const char *NexusException::Method() const
+{
+  return (*( string *)m_pMethod).c_str();
+}
+
+//=============================================================================
+// NeXus item identifier
+//
+// This class holds a nexus links
+//=============================================================================
+NexusItemID::NexusItemID()
+{
+  m_pLink = new NXlink;
+}
+
+NexusItemID::~NexusItemID()
+{
+  delete (NXlink *)m_pLink;
+}
+
+//=============================================================================
+// NeXus item info
+//
+//=============================================================================
+NexusItemInfo::NexusItemInfo()
+{
+  m_pszItem = new char[MAX_NAME_LENGTH];
+  m_pszClass = new char[MAX_NAME_LENGTH];
+}
+
+NexusItemInfo::~NexusItemInfo()
+{
+  delete [] m_pszItem;
+  delete [] m_pszClass;
+}
+
+bool NexusItemInfo::IsDataSet() const
+{
+  return !strncmp(m_pszClass, DATASET_CLASS, 3);
+}
+
+bool NexusItemInfo::IsGroup() const
+{
+  return !strncmp(m_pszClass, "NX", 2);
+}
+
+//=============================================================================
+// NeXus attribute info
+//
+//=============================================================================
+NexusAttrInfo::NexusAttrInfo()
+{
+  m_pszName = new char[MAX_NAME_LENGTH];
+}
+
+NexusAttrInfo::~NexusAttrInfo()
+{
+  delete [] m_pszName;
+}
+
+//=============================================================================
+// NeXus Data set info
+//
+//=============================================================================
+
+//---------------------------------------------------------------------------
+// NexusDataSetInfo::DataTypeSize
+//---------------------------------------------------------------------------
+int NexusDataSetInfo::DataTypeSize(NexusDataType eDataType)
+{
+  switch( eDataType )
+  {
+    case NX_INT16:
+    case NX_UINT16:
+      return sizeof(short);
+    case NX_INT32:
+    case NX_UINT32:
+      return sizeof(long);
+    case NX_INT64:
+    case NX_UINT64:
+      return sizeof(int64);
+    case NX_FLOAT32:
+      return sizeof(float);
+    case NX_FLOAT64:
+      return sizeof(double);
+    default:
+      return 1;
+  }
+}
+
+//---------------------------------------------------------------------------
+// Constructors
+//---------------------------------------------------------------------------
+NexusDataSetInfo::NexusDataSetInfo()
+{
+  m_eDataType = NX_NONE;
+  m_iRank = 0;
+  m_piDim = new int[MAX_DIM];
+}
+
+//---------------------------------------------------------------------------
+// Destructors
+//---------------------------------------------------------------------------
+NexusDataSetInfo::~NexusDataSetInfo()
+{
+  Clear();
+  delete [] m_piDim;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSetInfo::Clear
+//---------------------------------------------------------------------------
+void NexusDataSetInfo::Clear()
+{
+  m_eDataType = NX_NONE;
+  m_iRank = 0;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSetInfo::IsEmpty
+//---------------------------------------------------------------------------
+bool NexusDataSetInfo::IsEmpty() const
+{
+  if( NX_NONE == m_eDataType && 0 == m_iRank )
+    return true;
+  return false;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSetInfo::SetInfo
+//---------------------------------------------------------------------------
+void NexusDataSetInfo::SetInfo(NexusDataType eDataType, int iRank)
+{
+  m_eDataType = eDataType;
+  m_iRank = iRank;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSetInfo::Size
+//---------------------------------------------------------------------------
+int NexusDataSetInfo::Size() const
+{
+  int iSize = 1;
+  for( int i = 0; i < m_iRank; i++ )
+    iSize *= m_piDim[i];
+  return iSize;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::DatumSize
+//---------------------------------------------------------------------------
+unsigned int NexusDataSetInfo::DatumSize() const
+{
+  switch( m_eDataType )
+  {
+    case NX_INT16:
+    case NX_UINT16:
+      return sizeof(short);
+    case NX_INT32:
+    case NX_UINT32:
+      return sizeof(long);
+    case NX_INT64:
+    case NX_UINT64:
+      return sizeof(int64);
+    case NX_FLOAT32:
+      return sizeof(float);
+    case NX_FLOAT64:
+      return sizeof(double);
+    default: // CHAR, NX_INT8, NX_UINT8
+      return 1;
+  }
+}
+
+//=============================================================================
+// NeXus Data set
+//
+//=============================================================================
+
+//---------------------------------------------------------------------------
+// Constructors
+//---------------------------------------------------------------------------
+NexusDataSet::NexusDataSet()
+{
+  m_pData = NULL;
+  m_piStart = new int[MAX_DIM];
+}
+
+//---------------------------------------------------------------------------
+// Destructors
+//---------------------------------------------------------------------------
+NexusDataSet::~NexusDataSet()
+{
+  Clear();
+  delete [] m_piStart;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::FreeData
+//---------------------------------------------------------------------------
+void NexusDataSet::FreeData()
+{
+  if( m_pData )
+  {
+    switch( m_eDataType )
+    {
+      case NX_INT16:
+      case NX_UINT16:
+        delete [] (short *)m_pData;
+        break;
+      case NX_INT32:
+      case NX_UINT32:
+      case NX_FLOAT32:
+        delete [] (long *)m_pData;
+        break;
+      case NX_INT64:
+      case NX_UINT64:
+        delete [] (int64 *)m_pData;
+        break;
+      case NX_FLOAT64:
+        delete [] (double *)m_pData;
+        break;
+      default:  // CHAR, NX_INT8, NX_UINT8
+        delete [] (char *)m_pData;
+    }
+  }
+
+  m_pData = NULL;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::Clear
+//---------------------------------------------------------------------------
+void NexusDataSet::Clear()
+{
+  FreeData();
+  NexusDataSetInfo::Clear();
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::Size
+//---------------------------------------------------------------------------
+unsigned int NexusDataSet::Size() const
+{
+  unsigned int uiSize=1;
+  int iRank;
+  for( iRank = 0; iRank < m_iRank; iRank++ )
+    uiSize *= m_piDim[iRank];
+  return uiSize;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::MemSize
+//---------------------------------------------------------------------------
+unsigned int NexusDataSet::MemSize() const
+{
+  return Size() * DatumSize();
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::Alloc
+//---------------------------------------------------------------------------
+void NexusDataSet::Alloc()
+{
+  switch( m_eDataType )
+  {
+    case NX_INT16:
+    case NX_UINT16:
+      m_pData = new short[Size()];
+      break;
+    case NX_INT32:
+    case NX_UINT32:
+    case NX_FLOAT32:
+      m_pData = new long[Size()];
+      break;
+    case NX_INT64:
+    case NX_UINT64:
+      m_pData = new int64[Size()];
+      break;
+    case NX_FLOAT64:
+      m_pData = new double[Size()];
+      break;
+    default:  // CHAR, NX_INT8, NX_UINT8
+      m_pData = new char[Size()];
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::Alloc
+//---------------------------------------------------------------------------
+void NexusDataSet::SetDimension(int iDim, int iSize)
+{
+  if( iDim < MAX_DIM )
+    m_piDim[iDim] = iSize;
+}
+
+//---------------------------------------------------------------------------
+// NexusDataSet::SetData
+//---------------------------------------------------------------------------
+void NexusDataSet::SetData(const void *pData, NexusDataType eDataType, int iRank, int *piDimArray)
+{
+  // Clear data
+  Clear();
+
+  // Store properties
+  m_iRank = iRank;
+  m_eDataType = eDataType;
+  for( iRank = 0; iRank < m_iRank; iRank++ )
+    m_piDim[iRank] = piDimArray[iRank];
+
+  // Allocate memory for data block
+  Alloc();
+
+  memcpy(m_pData, pData, MemSize());
+}
+
+//=============================================================================
+// NeXus File Class internal implementation
+//
+// Do the job
+//=============================================================================
+class NexusFileImpl
+{
+private:
+  void             *m_hFile;
+  string            m_strFullPath;
+  string            m_strOpenDataSet;  // name of the currently opened data set
+  stack<string>     m_stkstrOpenGroup; // stack of opened groups names
+  bool              m_bNeedFlush;      // if true flushing data is needed before closing
+  
+  // Method called by CreateFile, OpenRead, OpenReadWrite
+  int PrivOpenFile(const char *pcszFullPath, int iAccessMode);
+
+  // For internal purpose
+  void SetNeedFlush(bool bNeed=true) { m_bNeedFlush = bNeed; }
+
+  // Check group name
+  // Look for forbidden char and replace them by '_'
+  String GetGroupName(const char *pcszName);
+
+public:
+  // Constructor
+  NexusFileImpl(const char *pcszFullPath=NULL);
+
+  // Destructor
+  ~NexusFileImpl();
+
+  // Creates file
+  void Create(const char *pcszFullPath, ENexusCreateMode eMode);
+
+  // Opens an existing file for read operations
+  void OpenRead(const char *pcszFullPath);
+
+  // Opens an existing file for read/write operations
+  void OpenReadWrite(const char *pcszFullPath);
+
+  // Closes currently opened file
+  void Close();
+
+  // Flushes all data to the file
+  void Flush();
+
+  // Adds a new group
+  void CreateGroup(const char *pcszName, const char *pcszClass, bool bOpen=true);
+
+  // Opens a existing group
+  bool OpenGroup(const char *pcszName, const char *pcszClass, bool bThrowException=true);
+
+  // CurrentGroup
+  string CurrentGroup();
+
+  // Closes current group
+  void CloseGroup();
+
+  // Closes all opened groups
+  void CloseAllGroups();
+
+  // Creates data set
+  void CreateDataSet(const char *pcszName, NexusDataType eDataType, 
+                     int iRank, int *piDim, int bOpen);
+
+  // Creates compressed data set
+  void CreateCompressedDataSet(const char *pcszName, NexusDataType eDataType, 
+                               int iRank, int *piDim, int *piChunkDim, int bOpen);
+
+  // Closes currenly open dataset
+  void CloseDataSet();
+
+  // Quickly creates simple data set and writes the data
+  void WriteData(const char *pcszName, void *pData, NexusDataType eDataType, int iRank,
+                 int *piDim, bool bCreate=true);
+
+  // Quickly creates simple data set and writes part of the data
+  void WriteDataSubSet(const char *pcszName, void *pData, NexusDataType eDataType, 
+                       int iRank, int *piStart, int *piDim, bool bCreate=true, bool bNoDim = false);
+
+  // Opens a already existing data set
+  bool OpenDataSet(const char *pcszName, bool bThrowException=true);
+
+  // Puts data in an existing data set
+  void PutData(void *pData, const char *pcszName, int bFlush);
+
+  // Puts data subset in an existing data set
+  void PutDataSubSet(void *pData, int *piStart, int *piSize, const char *pcszName);
+
+  // Put Data set attribut
+  void PutAttr(const char *pcszName, void *pValue, int iLen, int iDataType);
+
+  // Read data values from a data set in currently open group
+  void GetData(NexusDataSet *DataSet, const char *pcszDataSetName);
+
+  // Reads data values from a data set in currently open group
+  void GetDataSubSet(NexusDataSet *pDataSet, const char *pcszDataSetName);
+
+  // Gets info about a data set
+  void GetDataSetInfo(NexusDataSetInfo *pDataSetInfo, const char *pcszDataSetName);
+
+  // Read attribute
+  void GetAttribute(const char *pcszAttr, int *pBufLen, void *pData, int iDataType);
+  void GetAttribute(const char *pcszAttr, int *pBufLen, void *pData, int *piDataType);
+
+  // Get info about the first item (data set or group) in the current group
+  int GetFirstItem(NexusItemInfo *pItemInfo);
+  
+  // Get info about the next item (data set or group) in the current group
+  int GetNextItem(NexusItemInfo *pItemInfo);
+  
+  // Get info about the first attribute of the specified data set
+  int GetFirstAttribute(NexusAttrInfo *pAttrInfo, const char *pcszDataSet=NULL);
+
+  // Get info about the next attribute of the specified data set
+  int GetNextAttribute(NexusAttrInfo *pAttrInfo);
+
+  // Get a handle on the currently open data set in order to link it with a group
+  void GetDataSetLink(NexusItemID *pnxl);
+
+  // Get a handle on the currently open group set in order to link it with a group
+  void GetGroupLink(NexusItemID *pnxl);
+
+  // Link a item to the currently open group
+  void LinkToCurrentGroup(const NexusItemID &nxl);
+
+  // Get the number of items in the current group
+  int ItemCount();
+
+  // Get the number of items in the current group
+  int AttrCount();
+};
+
+//=============================================================================
+//
+// NeXus File Class
+//
+//=============================================================================
+
+//---------------------------------------------------------------------------
+// Constructor
+//---------------------------------------------------------------------------
+NexusFileImpl::NexusFileImpl(const char *pszFullPath)
+{
+  m_hFile = NULL;
+  if( NULL != pszFullPath )
+    m_strFullPath = pszFullPath;
+  m_strOpenDataSet = g_strNoDataSet;
+  m_stkstrOpenGroup.push(ROOT_LEVEL);
+  m_bNeedFlush = false;
+}
+
+//---------------------------------------------------------------------------
+// Destructor
+//---------------------------------------------------------------------------
+NexusFileImpl::~NexusFileImpl()
+{
+  Close();
+}
+
+//*****************************************************************************
+// Private methods
+//*****************************************************************************
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::PrivOpenFile
+//---------------------------------------------------------------------------
+int NexusFileImpl::PrivOpenFile(const char *pcszFullPath, int iAccessMode)
+{
+  // Close file, if open
+  Close();
+
+  if( NULL == pcszFullPath && m_strFullPath == g_strEmpty )
+    throw NexusException(OPENING_FILE_ERR, MISSING_FILE_NAME, "NexusFileImpl::PrivOpenFile");
+  else if( pcszFullPath && false == IsEqualsNoCase(m_strFullPath, String(pcszFullPath)) )
+    m_strFullPath = pcszFullPath;
+
+  LogVerbose("nex", "Opening file '%s' whith access mode %d", PSZ(m_strFullPath), iAccessMode);
+
+  return NXopen(PCSZToPSZ(m_strFullPath.c_str()), (NXaccess)iAccessMode, &m_hFile);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CheckGroupName
+//---------------------------------------------------------------------------
+String NexusFileImpl::GetGroupName(const char *pcszName)
+{
+  if( !pcszName )
+    throw NexusException(PSZ(StrFormat(BAD_GROUP_NAME_ERR)), OPERATION_FAILED, "NexusFileImpl::GetGroupName");
+
+  String strGroupName(pcszName);
+  strGroupName.Replace('/', '_');
+  strGroupName.Replace('\\', '_');
+  strGroupName.Replace(' ', '_');
+  strGroupName.Replace('*', '_');
+  strGroupName.Replace('"', '_');
+  strGroupName.Replace('\'', '_');
+  strGroupName.Replace(',', '_');
+  strGroupName.Replace(';', '_');
+  strGroupName.Replace(':', '_');
+  strGroupName.Replace('!', '_');
+  strGroupName.Replace('?', '_');
+
+  if( !String(pcszName).IsEquals(strGroupName) )
+    LogWarning("nex", "Changed group name from '%s' to '%s'", pcszName, PSZ(strGroupName));
+
+  return strGroupName;
+}
+
+//*****************************************************************************
+// Publics methods
+//*****************************************************************************
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::Close
+//---------------------------------------------------------------------------
+void NexusFileImpl::Close()
+{
+  if( NULL != m_hFile )
+  {
+    // Gracefully close opened groups
+    CloseAllGroups();
+    // Flushing data
+    Flush();
+
+    LogVerbose("nex", "Close file '%s'", PSZ(m_strFullPath));
+
+    // Then close the file
+    NXclose(&m_hFile);
+    m_hFile = NULL;
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::Flush
+//---------------------------------------------------------------------------
+void NexusFileImpl::Flush()
+{
+  if( NULL != m_hFile && m_bNeedFlush)
+  {
+    if( NX_OK != NXflush(&m_hFile) )
+    {
+      // No needs to retry since it will fail again then call Close()
+      m_bNeedFlush = false;
+      throw NexusException(PSZ(StrFormat(FLUSH_ERR, PSZ(m_strFullPath))),
+                           OPERATION_FAILED, "NexusFileImpl::Flush");
+    }
+  }
+
+  LogVerbose("nex", "Flush data");
+
+  // Flushing data closes the currently open data set
+  m_strOpenDataSet = g_strNoDataSet;
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::Create
+//---------------------------------------------------------------------------
+void NexusFileImpl::Create(const char *pcszFullPath, ENexusCreateMode eMode)
+{
+  int iMode = 0;
+  switch( eMode )
+  {
+    case NX_HDF4:
+      iMode = NXACC_CREATE4; break;
+    case NX_HDF5:
+    case NX_XML: // Not implemented yet
+      iMode = NXACC_CREATE5; break;
+  }
+  int iRc = PrivOpenFile(pcszFullPath, iMode);
+  if( iRc != NX_OK )
+    throw NexusException(CREATE_FILE_ERR, 
+                         PSZ(StrFormat(UNABLE_TO_OPEN_FILE, PSZ(m_strFullPath))),
+                         "NexusFileImpl::Create");
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::OpenRead
+//---------------------------------------------------------------------------
+void NexusFileImpl::OpenRead(const char *pcszFullPath)
+{
+  int iRc = PrivOpenFile(pcszFullPath, NXACC_READ);
+  if( iRc != NX_OK )
+    throw NexusException(OPENING_FILE_READ_ERR, 
+                         PSZ(StrFormat(UNABLE_TO_OPEN_FILE, PSZ(m_strFullPath))),
+                         "NexusFileImpl::OpenRead");
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::OpenReadWrite
+//---------------------------------------------------------------------------
+void NexusFileImpl::OpenReadWrite(const char *pcszFullPath)
+{
+  int iRc = PrivOpenFile(pcszFullPath, NXACC_RDWR);
+  if( iRc != NX_OK )
+    throw NexusException(OPENING_FILE_RW_ERR, 
+                         PSZ(StrFormat(UNABLE_TO_OPEN_FILE, PSZ(m_strFullPath))),
+                         "NexusFileImpl::OpenReadWrite");
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CreateGroup
+//---------------------------------------------------------------------------
+void NexusFileImpl::CreateGroup(const char *pcszName, const char *pcszClass, bool bOpen)
+{
+  CloseDataSet();
+
+  if( NULL == m_hFile )
+    throw NexusException(MAKE_GROUP_ERR, NO_HANDLE, "NexusFileImpl::CreateGroup");
+  
+  if( !pcszName )
+    throw NexusException(PSZ(StrFormat(MAKE_GROUP_ERR, "<noname>", PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::CreateGroup");
+
+  String strGroupName = GetGroupName(pcszName);
+  if( NXmakegroup(m_hFile, PCSZToPSZ(PSZ(strGroupName)), PCSZToPSZ(pcszClass)) != NX_OK )
+    throw NexusException(PSZ(StrFormat(MAKE_GROUP_ERR, pcszName, PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::CreateGroup");
+  
+  if( bOpen )
+    OpenGroup(PSZ(strGroupName), pcszClass);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::OpenGroup
+//---------------------------------------------------------------------------
+bool NexusFileImpl::OpenGroup(const char *pcszName, const char *pcszClass, bool bThrowException)
+{
+  if( NULL == m_hFile )
+    throw NexusException(PSZ(StrFormat(OPEN_GROUP_ERR, pcszName, PSZ(m_strFullPath))),
+                         NO_HANDLE, "NexusFileImpl::OpenGroup");
+
+
+  CString strGroup;
+  strGroup.Printf("%s(%s)", pcszName, pcszClass);
+  LogVerbose("nex", "Opening group '%s'", PSZ(strGroup));
+
+  // Trying to open group without filtering the requested name
+  String strGroupName = pcszName;
+  int iRc = NXopengroup(m_hFile, PCSZToPSZ(PSZ(strGroupName)), PCSZToPSZ(pcszClass));
+  if( iRc != NX_OK )
+  {
+    // Trying 
+    strGroupName = GetGroupName(pcszName);
+    strGroup.Printf("%s(%s)", PSZ(strGroupName), pcszClass);
+    iRc = NXopengroup(m_hFile, PCSZToPSZ(PSZ(strGroupName)), PCSZToPSZ(pcszClass));
+  }
+  if( iRc != NX_OK )
+  {
+    if( bThrowException )
+      throw NexusException(PSZ(StrFormat(OPEN_GROUP_ERR, PSZ(strGroupName), PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::OpenGroup");
+    else
+      return false;
+  }
+
+  // Empiler le nom du groupe
+  m_stkstrOpenGroup.push(strGroup);
+  return true;
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CurrentGroup
+//---------------------------------------------------------------------------
+string NexusFileImpl::CurrentGroup()
+{
+  return m_stkstrOpenGroup.top();
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CloseGroup
+//---------------------------------------------------------------------------
+void NexusFileImpl::CloseGroup()
+{
+  CloseDataSet();
+
+  if( m_stkstrOpenGroup.size() > 1 )
+  {
+    LogVerbose("nex", "Close group");
+
+    if( NXclosegroup(m_hFile) != NX_OK )
+      throw NexusException(PSZ(StrFormat(CLOSE_GROUP_ERR, PSZ(m_stkstrOpenGroup.top()),
+                                                       PSZ(m_strFullPath))),
+                           OPERATION_FAILED, "NexusFileImpl::CloseGroup");
+    m_stkstrOpenGroup.pop();
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CloseAllGroups
+//---------------------------------------------------------------------------
+void NexusFileImpl::CloseAllGroups()
+{
+  while( m_stkstrOpenGroup.size() > 1 )
+    CloseGroup();
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CloseDataSet
+//---------------------------------------------------------------------------
+bool NexusFileImpl::OpenDataSet(const char *pcszName, bool bThrowException)
+{
+  if( m_strOpenDataSet != pcszName )
+    CloseDataSet();
+
+  LogVerbose("nex", "Open data set '%s'", pcszName);
+
+  if( NXopendata(m_hFile, PCSZToPSZ(pcszName)) != NX_OK )
+  {
+    if( bThrowException )
+      throw NexusException(PSZ(StrFormat(OPEN_DATA_ERR, pcszName, 
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::OpenDataSet");
+    else
+      return false;
+  }
+  m_strOpenDataSet = pcszName;
+  return true;
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CloseDataSet
+//---------------------------------------------------------------------------
+void NexusFileImpl::CloseDataSet()
+{
+  if( m_strOpenDataSet != g_strNoDataSet )
+  {
+    LogVerbose("nex", "Close data set '%s'", PSZ(m_strOpenDataSet));
+
+    if( NXclosedata(m_hFile) != NX_OK )
+      throw NexusException(PSZ(StrFormat(CLOSE_DATA_ERR, PSZ(m_stkstrOpenGroup.top()),
+                                                      PSZ(m_strFullPath))),
+                           OPERATION_FAILED, "NexusFileImpl::CloseDataSet");
+
+    m_strOpenDataSet = g_strNoDataSet;
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CreateDataSet
+//---------------------------------------------------------------------------
+void NexusFileImpl::CreateCompressedDataSet(const char *pcszName, NexusDataType eDataType, 
+                                        int iRank, int *piDim, int *piChunkDim, int bOpen)
+{
+  if( m_strOpenDataSet != pcszName )
+    CloseDataSet();
+
+  int aiChunkSize[MAX_DIM];
+  if( piChunkDim )
+  {
+    for( int i = 0; i < iRank; i++ )
+      aiChunkSize[i] = piChunkDim[i];
+  }
+  else
+  {
+    for( int i = 0; i < iRank; i++ )
+      aiChunkSize[i] = piDim[i];
+  }
+
+  LogVerbose("nex", "create compressed data set '%s'", pcszName);
+
+  // Create dataset
+  if( NXcompmakedata(m_hFile, PCSZToPSZ(pcszName), (int)eDataType, iRank, 
+                     piDim, NX_COMP_LZW, aiChunkSize) != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(CREATE_DATA_ERR, pcszName,
+                                                     PSZ(m_stkstrOpenGroup.top()),
+                                                     PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::CreateCompressedDataSet");
+  }
+
+  if( bOpen )
+    OpenDataSet(pcszName);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::CreateDataSet
+//---------------------------------------------------------------------------
+void NexusFileImpl::CreateDataSet(const char *pcszName, NexusDataType eDataType, 
+                                  int iRank, int *piDim, int bOpen)
+{
+  if( m_strOpenDataSet != pcszName )
+    CloseDataSet();
+  
+  LogVerbose("nex", "Create data set '%s'", pcszName);
+
+  int iRc = 0;
+  if( piDim )
+    iRc = NXmakedata(m_hFile, PCSZToPSZ(pcszName), (int)eDataType, iRank, piDim);
+  else
+  {
+    int iSize = NX_UNLIMITED;
+    iRc = NXmakedata(m_hFile, PCSZToPSZ(pcszName), (int)eDataType, iRank, &iSize);
+  }
+  // Create dataset
+  if( iRc != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(CREATE_DATA_ERR, pcszName,
+                                                     PSZ(m_stkstrOpenGroup.top()),
+                                                     PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::CreateDataSet");
+  }
+
+  if( bOpen )
+    OpenDataSet(pcszName);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::PutData
+//---------------------------------------------------------------------------
+void NexusFileImpl::PutData(void *pData, const char *pcszName, int bFlush)
+{
+  if( NULL != pcszName && m_strOpenDataSet != pcszName )
+  {
+    // The DataSet 'pcszName' isn't open
+    CloseDataSet();
+    // Try to openit
+    OpenDataSet(pcszName);
+  }
+
+  if( NXputdata(m_hFile, pData) != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(PUT_DATA_ERR, PSZ(m_strOpenDataSet),
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::PutData");
+  }
+
+  if( bFlush )
+    Flush();
+// Not useful since flushing data is performed when calling NXclose()
+//  else
+//    SetNeedFlush();
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::PutDataSubSet
+//---------------------------------------------------------------------------
+void NexusFileImpl::PutDataSubSet(void *pData, int *piStart, int *piSize,
+                                  const char *pcszName)
+{
+  if( NULL != pcszName && m_strOpenDataSet != pcszName )
+  {
+    // The DataSet 'pcszName' isn't open
+    CloseDataSet();
+    // Try to openit
+    OpenDataSet(pcszName);
+  }
+
+  if( NXputslab(m_hFile, pData, piStart, piSize) != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(PUT_DATASUBSET_ERR, PSZ(m_strOpenDataSet),
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::PutDataSubSet");
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::WriteData
+//---------------------------------------------------------------------------
+void NexusFileImpl::WriteData(const char *pcszName, void *pData, 
+                              NexusDataType eDataType, int iRank, int *piDim, bool bCreate)
+{
+  if( m_strOpenDataSet != pcszName )
+    CloseDataSet();
+  
+  if( bCreate )
+  {
+    // Create dataset
+    CreateDataSet(pcszName, eDataType, iRank, piDim, true);
+  }
+  // Put data
+  PutData(pData, pcszName, false);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::WriteDataSubSet
+//---------------------------------------------------------------------------
+void NexusFileImpl::WriteDataSubSet(const char *pcszName, void *pData, NexusDataType eDataType, 
+                                    int iRank, int *piStart, int *piSize, bool bCreate, bool bNoDim)
+{
+  if( m_strOpenDataSet != pcszName )
+    CloseDataSet();
+  
+  if( bCreate )
+  {
+    // Create dataset
+    if( !bNoDim )
+      CreateDataSet(pcszName, eDataType, iRank, piSize, true);
+    else
+    {
+      // Create unlimited size dataset
+      int iSize = NX_UNLIMITED;
+      CreateDataSet(pcszName, eDataType, iRank, &iSize, true);
+    }
+  }
+  // Put data
+  PutDataSubSet(pData, piStart, piSize, pcszName);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::PutAttr
+//---------------------------------------------------------------------------
+void NexusFileImpl::PutAttr(const char *pcszName, void *pValue, int iLen, int iDataType)
+{
+  if( NXputattr(m_hFile, PCSZToPSZ(pcszName), pValue, iLen, iDataType) != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(PUT_DATA_ERR, pcszName,
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::PutAttr");
+  }
+
+  // Not useful since flushing data is performed when calling NXclose()
+  // SetNeedFlush();
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetDataSetInfo
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetDataSetInfo(NexusDataSetInfo *pDataSetInfo, 
+                                   const char *pcszDataSet)
+{
+  if( m_strOpenDataSet != pcszDataSet )
+  {
+    // The DataSet 'pcszName' isn't open
+    CloseDataSet();
+    // Try to open correct data set
+    OpenDataSet(pcszDataSet);
+    // Clear the NexusDataSetInfo object
+    pDataSetInfo->Clear();
+  }
+
+  if( pDataSetInfo->IsEmpty() )
+  {
+    // Read Data set info
+    int iRank, iDataType;
+    if( NX_OK != NXgetinfo(m_hFile, &iRank, pDataSetInfo->DimArray(), &iDataType) )
+    {
+      throw NexusException(PSZ(StrFormat(GETINFO_ERR, pcszDataSet,
+                                                   PSZ(m_stkstrOpenGroup.top()),
+                                                   PSZ(m_strFullPath))),
+                           OPERATION_FAILED, "NexusFileImpl::GetDataSetInfo");
+    }
+
+    pDataSetInfo->SetInfo((NexusDataType)iDataType, iRank);
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetData
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetData(NexusDataSet *pDataSet, const char *pcszDataSet)
+{
+  if( NULL != pcszDataSet )
+    // First, get info about the data set
+    GetDataSetInfo(pDataSet, pcszDataSet);
+
+  // Allocate dataset
+  pDataSet->Alloc();
+
+  // Read data
+  if( NX_OK != NXgetdata(m_hFile, pDataSet->Data()) )
+  {
+    throw NexusException(PSZ(StrFormat(GETDATA_ERR, pcszDataSet,
+                                                 PSZ(m_stkstrOpenGroup.top()),
+                                                 PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetData");
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetDataSubSet
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetDataSubSet(NexusDataSet *pDataSet, const char *pcszDataSet)
+{
+  // Allocate dataset
+  pDataSet->Alloc();
+
+  // Read data
+  if( NX_OK != NXgetslab(m_hFile, pDataSet->Data(), pDataSet->StartArray(),
+                                                     pDataSet->DimArray()) )
+  {
+    throw NexusException(PSZ(StrFormat(GETDATA_ERR, pcszDataSet,
+                                                 PSZ(m_stkstrOpenGroup.top()),
+                                                 PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetDataSubSet");
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetAttribute
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetAttribute(const char *pcszAttr, int *piBufLen, 
+                                 void *pData, int iDataType)
+{
+  int _iDataType = iDataType;
+
+  // Read attribute
+  if( NXgetattr(m_hFile, PCSZToPSZ(pcszAttr), pData, piBufLen, &_iDataType) != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(GET_ATTR_ERR, pcszAttr,
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetAttribute");
+  }
+
+  // Check type, except if NX_NONE is the passed type
+  if( NX_NONE != iDataType && _iDataType != iDataType )
+  {
+    throw NexusException(PSZ(StrFormat(GET_ATTR_ERR, pcszAttr,
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         TYPES_MISMATCH, "NexusFileImpl::GetAttribute");
+
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetAttribute
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetAttribute(const char *pcszAttr, int *piBufLen, 
+                                 void *pData, int *piDataType)
+{
+  // Read attribute
+  if( NXgetattr(m_hFile, PCSZToPSZ(pcszAttr), pData, piBufLen, piDataType) != NX_OK )
+  {
+    throw NexusException(PSZ(StrFormat(GET_ATTR_ERR, pcszAttr,
+                                                  PSZ(m_stkstrOpenGroup.top()),
+                                                  PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetAttribute");
+  }
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::ItemCount
+//---------------------------------------------------------------------------
+int NexusFileImpl::ItemCount()
+{
+  int iCount;
+  if( NXgetgroupinfo(m_hFile, &iCount, g_acScratchBuf, g_acScratchBuf) != NX_OK )
+    throw NexusException(PSZ(StrFormat(GET_GROUPINFO_ERR, PSZ(m_stkstrOpenGroup.top()),
+                                                       PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::ItemCount");
+  return iCount;
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::AttrCount
+//---------------------------------------------------------------------------
+int NexusFileImpl::AttrCount()
+{
+  int iCount;
+  if( NXgetattrinfo(m_hFile, &iCount) != NX_OK )
+    throw NexusException(PSZ(StrFormat(GET_ATTRINFO_ERR, PSZ(m_stkstrOpenGroup.top()),
+                                                       PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::AttrCount");
+  return iCount;
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetFirstItem
+//---------------------------------------------------------------------------
+int NexusFileImpl::GetFirstItem(NexusItemInfo *pItemInfo)
+{
+  int iStatus = NX_OK;
+
+  // Initiate enumeration
+  iStatus = NXinitgroupdir(m_hFile);
+  if( NX_ERROR == iStatus )
+  {
+    throw NexusException(PSZ(StrFormat(GET_INIT_ENUM_ITEM, PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetFirstItem");
+  }
+
+  // Get first item
+  return GetNextItem(pItemInfo);
+}
+  
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetNextItem
+//---------------------------------------------------------------------------
+int NexusFileImpl::GetNextItem(NexusItemInfo *pItemInfo)
+{
+  int iStatus = NXgetnextentry(m_hFile, pItemInfo->m_pszItem, pItemInfo->m_pszClass, 
+                           (int *)&(pItemInfo->m_eDataType));
+  if( NX_ERROR == iStatus )
+  {
+    throw NexusException(PSZ(StrFormat(GET_RETREIVE_ITEM, PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetNextItem");
+  }
+
+  return iStatus;
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetFirstAttribute
+//---------------------------------------------------------------------------
+int NexusFileImpl::GetFirstAttribute(NexusAttrInfo *pAttrInfo, const char *pcszDataSet)
+{
+  int iStatus = NX_OK;
+
+  if( pcszDataSet )
+    OpenDataSet(pcszDataSet);
+
+  // Initiate enumeration
+  iStatus = NXinitattrdir(m_hFile);
+  if( NX_ERROR == iStatus )
+  {
+    throw NexusException(PSZ(StrFormat(GET_INIT_ENUM_ATTR, PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetFirstAttribute");
+  }
+
+  // Get first attribute
+  return GetNextAttribute(pAttrInfo);
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetNextAttribute
+//---------------------------------------------------------------------------
+int NexusFileImpl::GetNextAttribute(NexusAttrInfo *pAttrInfo)
+{
+  int iStatus = NXgetnextattr(m_hFile, pAttrInfo->m_pszName, &pAttrInfo->m_iLen,
+                           (int *)&(pAttrInfo->m_eDataType));
+  if( NX_ERROR == iStatus )
+  {
+    throw NexusException(PSZ(StrFormat(GET_RETREIVE_ATTR, PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::GetNextAttribute");
+  }
+
+  return iStatus;
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetDataSetHandle
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetDataSetLink(NexusItemID *pnxl)
+{
+  NXgetdataID(m_hFile, (NXlink *)(pnxl->m_pLink));
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::GetGroupHandle
+//---------------------------------------------------------------------------
+void NexusFileImpl::GetGroupLink(NexusItemID *pnxl)
+{
+  NXgetgroupID(m_hFile, (NXlink *)(pnxl->m_pLink));
+}
+
+//---------------------------------------------------------------------------
+// NexusFileImpl::LinkToCurrentGroup
+//---------------------------------------------------------------------------
+void NexusFileImpl::LinkToCurrentGroup(const NexusItemID &nxl)
+{
+  if( NX_OK != NXmakelink(m_hFile, (NXlink *)(nxl.m_pLink)) )
+  {
+    throw NexusException(PSZ(StrFormat(LINK_ITEM_ERR, PSZ(m_strFullPath))),
+                         OPERATION_FAILED, "NexusFileImpl::LinkToCurrentGroup");
+  }
+}
+
+//=============================================================================
+//
+// NeXus File Class - wrapper class
+//
+//=============================================================================
+
+//---------------------------------------------------------------------------
+// Constructor
+//---------------------------------------------------------------------------
+NexusFile::NexusFile(const char *pcszFullPath)
+{
+  m_pImpl = new NexusFileImpl(pcszFullPath);
+  m_pUserPtr = NULL;
+}
+
+//---------------------------------------------------------------------------
+// Destructor
+//---------------------------------------------------------------------------
+NexusFile::~NexusFile()
+{
+  Close();
+  delete m_pImpl;
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::Close
+//---------------------------------------------------------------------------
+void NexusFile::Close()
+{
+  m_pImpl->Close();
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::Flush
+//---------------------------------------------------------------------------
+void NexusFile::Flush()
+{
+  m_pImpl->Flush();
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::Create
+//---------------------------------------------------------------------------
+void NexusFile::Create(const char *pcszFullPath, ENexusCreateMode eMode)
+{
+  m_pImpl->Create(pcszFullPath, eMode);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::OpenRead
+//---------------------------------------------------------------------------
+void NexusFile::OpenRead(const char *pcszFullPath)
+{
+  m_pImpl->OpenRead(pcszFullPath);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::OpenReadWrite
+//---------------------------------------------------------------------------
+void NexusFile::OpenReadWrite(const char *pcszFullPath)
+{
+  m_pImpl->OpenReadWrite(pcszFullPath);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CreateGroup
+//---------------------------------------------------------------------------
+void NexusFile::CreateGroup(const char *pcszName, const char *pcszClass, bool bOpen)
+{
+  m_pImpl->CreateGroup(pcszName, pcszClass, bOpen);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::OpenGroup
+//---------------------------------------------------------------------------
+bool NexusFile::OpenGroup(const char *pcszName, const char *pcszClass, bool bThrowException)
+{
+  return m_pImpl->OpenGroup(pcszName, pcszClass, bThrowException);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CloseGroup
+//---------------------------------------------------------------------------
+void NexusFile::CloseGroup()
+{
+  m_pImpl->CloseGroup();
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CloseAllGroups
+//---------------------------------------------------------------------------
+void NexusFile::CloseAllGroups()
+{
+  m_pImpl->CloseAllGroups();
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CloseDataSet
+//---------------------------------------------------------------------------
+bool NexusFile::OpenDataSet(const char *pcszName, bool bThrowException)
+{
+  return m_pImpl->OpenDataSet(pcszName, bThrowException);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CloseDataSet
+//---------------------------------------------------------------------------
+void NexusFile::CloseDataSet()
+{
+  m_pImpl->CloseDataSet();
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CreateCompressedDataSet
+//---------------------------------------------------------------------------
+void NexusFile::CreateCompressedDataSet(const char *pcszName, NexusDataType eDataType, 
+                                        int iRank, int *piDim, int *piChunkDim, int bOpen)
+{
+  m_pImpl->CreateCompressedDataSet(pcszName, eDataType, iRank, piDim, piChunkDim, bOpen);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::CreateDataSet
+//---------------------------------------------------------------------------
+void NexusFile::CreateDataSet(const char *pcszName, NexusDataType eDataType, 
+                              int iRank, int *piDim, int bOpen)
+{
+  m_pImpl->CreateDataSet(pcszName, eDataType, iRank, piDim, bOpen);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutData
+//---------------------------------------------------------------------------
+void NexusFile::PutData(void *pData, const char *pcszName, int bFlush)
+{
+  m_pImpl->PutData(pData, pcszName, bFlush);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutDataSubSet
+//---------------------------------------------------------------------------
+void NexusFile::PutDataSubSet(void *pData, int *piStart, int *piSize,
+                              const char *pcszName)
+{
+  m_pImpl->PutDataSubSet(pData, piStart, piSize, pcszName);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteData
+//---------------------------------------------------------------------------
+void NexusFile::WriteData(const char *pcszName, void *pData, 
+                          NexusDataType eDataType, int iRank, int *piDim,
+                          bool bCreate)
+{
+  m_pImpl->WriteData(pcszName, pData, eDataType, iRank, piDim, bCreate);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteDataSubSet
+//---------------------------------------------------------------------------
+void NexusFile::WriteDataSubSet(const char *pcszName, void *pData, NexusDataType eDataType, 
+                       int iRank, int *piStart, int *piSize, bool bCreate, bool bNoDim)
+{
+  m_pImpl->WriteDataSubSet(pcszName, pData, eDataType, iRank, piStart, piSize, bCreate, bNoDim);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteData | float version
+//---------------------------------------------------------------------------
+void NexusFile::WriteData(const char *pcszName, float fValue, bool bCreate)
+{
+  int iLen = 1;
+  m_pImpl->WriteData(pcszName, &fValue, NX_FLOAT32, 1, &iLen, bCreate);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteData | double version
+//---------------------------------------------------------------------------
+void NexusFile::WriteData(const char *pcszName, double dValue, bool bCreate)
+{
+  int iLen = 1;
+  m_pImpl->WriteData(pcszName, &dValue, NX_FLOAT64, 1, &iLen, bCreate);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteData | long version
+//---------------------------------------------------------------------------
+void NexusFile::WriteData(const char *pcszName, long lValue, bool bCreate)
+{
+  int iLen = 1;
+  m_pImpl->WriteData(pcszName, &lValue, NX_INT32, 1, &iLen, bCreate);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteData | string version
+//---------------------------------------------------------------------------
+void NexusFile::WriteData(const char *pcszName, const char *pcszValue, bool bCreate)
+{
+  int iLen = strlen(pcszValue);
+  m_pImpl->WriteData(pcszName, PCSZToPSZ(pcszValue), NX_CHAR, 1, &iLen, bCreate);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::WriteData | binary version
+//---------------------------------------------------------------------------
+void NexusFile::WriteData(const char *pcszName, void *pData, int _iLen, bool bCreate)
+{
+  int iLen = _iLen;
+  m_pImpl->WriteData(pcszName, pData, NX_BINARY, 1, &iLen, bCreate);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutAttr
+//---------------------------------------------------------------------------
+void NexusFile::PutAttr(const char *pcszName, void *pValue, int iLen, 
+                        NexusDataType eDataType)
+{
+  m_pImpl->PutAttr(pcszName, pValue, iLen, (int)eDataType);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutAttr | 'long' version
+//---------------------------------------------------------------------------
+void NexusFile::PutAttr(const char *pcszName, long lValue)
+{
+  m_pImpl->PutAttr(pcszName, &lValue, 1, NX_INT32);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutAttr | 'pcsz' version
+//---------------------------------------------------------------------------
+void NexusFile::PutAttr(const char *pcszName, const char *pcszValue)
+{
+  m_pImpl->PutAttr(pcszName, (void *)pcszValue, strlen(pcszValue), NX_CHAR);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutAttr | 'double' version
+//---------------------------------------------------------------------------
+void NexusFile::PutAttr(const char *pcszName, double dValue)
+{
+  m_pImpl->PutAttr(pcszName, &dValue, 1, NX_FLOAT64);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::PutAttr | 'float' version
+//---------------------------------------------------------------------------
+void NexusFile::PutAttr(const char *pcszName, float fValue)
+{
+  m_pImpl->PutAttr(pcszName, &fValue, 1, NX_FLOAT32);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetData
+//---------------------------------------------------------------------------
+void NexusFile::GetData(NexusDataSet *pDataSet, const char *pcszDataSet)
+{
+  m_pImpl->GetData(pDataSet, pcszDataSet);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetDataSubSet
+//---------------------------------------------------------------------------
+void NexusFile::GetDataSubSet(NexusDataSet *pDataSet, const char *pcszDataSet)
+{
+  m_pImpl->GetDataSubSet(pDataSet, pcszDataSet);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetDataSetInfo
+//---------------------------------------------------------------------------
+void NexusFile::GetDataSetInfo(NexusDataSetInfo *pDataSetInfo, const char *pcszDataSet)
+{
+  m_pImpl->GetDataSetInfo(pDataSetInfo, pcszDataSet);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetAttribute
+//---------------------------------------------------------------------------
+void NexusFile::GetAttribute(const char *pcszAttr, int *piBufLen, 
+                             void *pData, NexusDataType eDataType)
+{
+  m_pImpl->GetAttribute(pcszAttr, piBufLen, pData, (int)eDataType);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetAttribute 'long' version
+//---------------------------------------------------------------------------
+void NexusFile::GetAttribute(const char *pcszAttr, long *plValue)
+{
+  int iLen = 1;
+  m_pImpl->GetAttribute(pcszAttr, &iLen, plValue, NX_INT32);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetAttribute 'double' version
+//---------------------------------------------------------------------------
+void NexusFile::GetAttribute(const char *pcszAttr, double *pdValue)
+{
+  int iLen = 1;
+  m_pImpl->GetAttribute(pcszAttr, &iLen, pdValue, NX_FLOAT64);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetAttribute 'float' version
+//---------------------------------------------------------------------------
+void NexusFile::GetAttribute(const char *pcszAttr, float *pfValue)
+{
+  int iLen = 1;
+  m_pImpl->GetAttribute(pcszAttr, &iLen, pfValue, NX_FLOAT32);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetAttribute 'string' version
+//---------------------------------------------------------------------------
+void NexusFile::GetAttribute(const char *pcszAttr, string *pstrValue)
+{
+  char szBuf[512];
+  int iLen = 512;
+  m_pImpl->GetAttribute(pcszAttr, &iLen, szBuf, NX_CHAR);
+  (*pstrValue) = szBuf;
+}
+void NexusFile::GetAttribute(const char *pcszAttr, char *pszValue, int iBufLen)
+{
+  int iLen = iBufLen;
+  m_pImpl->GetAttribute(pcszAttr, &iLen, pszValue, NX_CHAR);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetFirstItem
+//---------------------------------------------------------------------------
+int NexusFile::GetFirstItem(NexusItemInfo *pItemInfo)
+{
+  return m_pImpl->GetFirstItem(pItemInfo);
+}
+  
+//---------------------------------------------------------------------------
+// NexusFile::GetNextItem
+//---------------------------------------------------------------------------
+int NexusFile::GetNextItem(NexusItemInfo *pItemInfo)
+{
+  return m_pImpl->GetNextItem(pItemInfo);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetFirstAttribute
+//---------------------------------------------------------------------------
+int NexusFile::GetFirstAttribute(NexusAttrInfo *pAttrInfo, const char *pcszDataSet)
+{
+  return m_pImpl->GetFirstAttribute(pAttrInfo, pcszDataSet);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetNextAttribute
+//---------------------------------------------------------------------------
+int NexusFile::GetNextAttribute(NexusAttrInfo *pAttrInfo)
+{
+  return m_pImpl->GetNextAttribute(pAttrInfo);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetDataSetLink
+//---------------------------------------------------------------------------
+void NexusFile::GetDataSetLink(NexusItemID *pnxl)
+{
+  m_pImpl->GetDataSetLink(pnxl);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::GetGroupHandle
+//---------------------------------------------------------------------------
+void NexusFile::GetGroupLink(NexusItemID *pnxl)
+{
+  m_pImpl->GetGroupLink(pnxl);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::LinkToCurrentGroup
+//---------------------------------------------------------------------------
+void NexusFile::LinkToCurrentGroup(const NexusItemID &nxl)
+{
+  m_pImpl->LinkToCurrentGroup(nxl);
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::ItemCount
+//---------------------------------------------------------------------------
+int NexusFile::ItemCount()
+{
+  return m_pImpl->ItemCount();
+}
+
+//---------------------------------------------------------------------------
+// NexusFile::AttrCount
+//---------------------------------------------------------------------------
+int NexusFile::AttrCount()
+{
+  return m_pImpl->AttrCount();
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::OpenGroupPath
+//-----------------------------------------------------------------------------
+bool NexusFile::OpenGroupPath(const char *pszPath, bool bThrowException)
+{
+  LogVerbose("nex", "Open group from path '%s'", pszPath);
+
+  String strPath = pszPath;
+  if( strPath.StartWith('/') )
+  {
+    // Sarting from root level => ensure that no group is already opened
+    CloseAllGroups();
+    strPath.erase(0, 1);
+  }
+
+  if( NULL == pszPath )
+    // No path => nothing to do
+    return false;
+
+  while( strPath.size() > 0 )
+  {
+    String strGroup;
+    String strClass;
+
+    // we extract the name and the class's name of the Item.
+    soleil::ExtractToken(&strPath, '/', &strGroup);
+    soleil::ExtractTokenRight(&strGroup, '<', '>', &strClass);
+    if( strClass.empty() )
+      // 2nd chance !
+      soleil::ExtractTokenRight(&strGroup, '(', ')', &strClass);
+    if( strClass.empty() )
+      // last chance !
+      soleil::ExtractTokenRight(&strGroup, '{', '}', &strClass);
+
+    if( strGroup.IsEquals("..") )
+    {
+      // Up one level
+      CloseGroup();
+    }
+
+    else if( strGroup.IsEquals(".") )
+    {
+      // do nothing
+    }
+
+    // Provide groupe name and class
+    else if( !strClass.empty() && !strGroup.empty() )
+    {
+      // Open the group
+      bool bOpened = OpenGroup( PSZ(strGroup), PSZ(strClass), bThrowException);
+      if( !bOpened )
+        return false;
+    }
+
+    // Provide only class name
+    else if( strGroup.empty() && !strClass.empty() )
+    {     
+      // Find first group of class {strClass}
+      NexusItemInfo ItemInfo;
+      int iRc = GetFirstItem(&ItemInfo);
+      // we start our research.
+      while( iRc != NX_EOD )
+      {
+        if( ItemInfo.IsGroup() && IsEquals(ItemInfo.ClassName(), strClass) )
+        {
+          strGroup = ItemInfo.ItemName();
+          break;
+        }
+        iRc = GetNextItem(&ItemInfo);
+      }
+      if( !strGroup.empty() )
+        // we open the group found.
+        OpenGroup(PSZ(strGroup), PSZ(strClass), bThrowException);
+      else
+        return false;
+    }
+
+    // Provide only group name
+    else if( strClass.empty() && !strGroup.empty() )
+    {
+      // Find first group of class {strClass}
+      NexusItemInfo ItemInfo;
+      int iRc = GetFirstItem(&ItemInfo);
+      // we start our research.
+      while( iRc != NX_EOD )
+      {
+        if( ItemInfo.IsGroup() && IsEquals(ItemInfo.ItemName(), strGroup) )
+        {
+          strClass = ItemInfo.ClassName();
+          break;
+        }
+        iRc = GetNextItem(&ItemInfo);
+      }
+      if( !strClass.empty() )
+        // we open the group found.
+        OpenGroup(PSZ(strGroup), PSZ(strClass), bThrowException);
+      else
+        return false;
+    }
+  }
+  
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::SearchGroup
+//-----------------------------------------------------------------------------
+int NexusFile::SearchGroup(const char *pszGroupName, const char *pszClassName,
+                vector<string> *pvecPaths, const char *pszStartPath)
+{
+  static bool bReEnter = false;
+  bool bFirstCall = !bReEnter;
+  bReEnter = true;
+
+  if( bFirstCall && pszStartPath )
+    OpenGroupPath(pszStartPath);
+
+  NexusItemInfo aItemInfo;
+  int iRc = GetFirstItem(&aItemInfo);
+  while( NX_OK == iRc )
+  {
+    if( aItemInfo.IsGroup() )
+    {
+      CString strPath = pszStartPath;
+      strPath += '/' + CString(aItemInfo.ItemName()) + '<' + CString(aItemInfo.ClassName()) + '>';
+      if( stricmp(pszClassName, aItemInfo.ClassName()) == 0 &&
+          (!pszGroupName || stricmp(pszGroupName, aItemInfo.ItemName()) == 0) )
+      {
+        pvecPaths->push_back(strPath);
+      }
+      
+      OpenGroup(aItemInfo.ItemName(), aItemInfo.ClassName());
+      SearchGroup(pszGroupName, pszClassName, pvecPaths, PSZ(strPath));
+      CloseGroup();
+    }
+
+    iRc = GetNextItem(&aItemInfo);
+  }
+
+  if( bFirstCall )
+  {
+    bReEnter = false;
+    if( pvecPaths->size() == 0 )
+      return NX_EOD;
+  }
+  return NX_OK;
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::SearchDataSetFromAttr
+//-----------------------------------------------------------------------------
+int NexusFile::SearchDataSetFromAttr(const char *pszAttrName, vector<string> *pvecDataSets,
+                                     const string &strAttrVal)
+{
+  soleil::CString strName(pszAttrName);
+  // browse through items into current group
+  NexusItemInfo aItemInfo;
+  int iRc = GetFirstItem(&aItemInfo);
+  while( NX_OK == iRc )
+  {
+    if( aItemInfo.IsDataSet() )
+    {
+      // Open data set and through its attributs 
+      NexusAttrInfo aAttrInfo;
+      int iRc = GetFirstAttribute(&aAttrInfo, aItemInfo.ItemName());
+      while( NX_OK == iRc )
+      {
+        if( strName.IsEqualsNoCase(aAttrInfo.AttrName()) )
+        {
+          if( !strAttrVal.empty() )
+          {
+            // Get attr value
+            string strValue = GetAttributeAsString(aAttrInfo);
+            if( strValue == strAttrVal )
+              // Ok add data set name
+              pvecDataSets->push_back(aItemInfo.ItemName());
+          }
+          else
+            // Ok add data set name
+            pvecDataSets->push_back(aItemInfo.ItemName());
+          break;
+        }
+        iRc = GetNextAttribute(&aAttrInfo);
+      }
+    }
+    iRc = GetNextItem(&aItemInfo);
+  }
+  if( pvecDataSets->size() )
+    return NX_OK;
+  return NX_EOD;
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::SearchFirstDataSetFromAttr
+//-----------------------------------------------------------------------------
+int NexusFile::SearchFirstDataSetFromAttr(const char *pszAttrName, string *pstrDataSet,
+                                          const string &strAttrVal)
+{
+  vector<string> vecstrDataSet;
+  int rc = SearchDataSetFromAttr(pszAttrName, &vecstrDataSet, strAttrVal);
+  if( NX_OK == rc )
+    *pstrDataSet = vecstrDataSet[0];
+  else
+    *pstrDataSet = "";
+  return rc;
+}
+//-----------------------------------------------------------------------------
+// NexusFile::SearchDataSetFromAttr
+//-----------------------------------------------------------------------------
+string NexusFile::GetAttributeAsString(const NexusAttrInfo &aAttrInfo)
+{
+  // Get attribute
+  int iBufLen = 1024;
+  char szBuf[1024];
+  int iDataType = aAttrInfo.DataType();
+  m_pImpl->GetAttribute(aAttrInfo.AttrName(), &iBufLen, szBuf, &iDataType);
+
+  ostringstream ossVal;
+  // Setting floating point precision
+  ossVal.precision(10);
+
+  switch( iDataType )
+  {
+    case NX_INT8:
+    {
+      int iVal = *((char *)szBuf);
+      ossVal << iVal;
+    }
+    break;
+    case NX_UINT8:
+    {
+      int iVal = *((unsigned char *)szBuf);
+      ossVal << iVal;
+    }
+    break;
+    case NX_INT16:
+      ossVal << *((short *)szBuf);
+    break;
+    case NX_UINT16:
+      ossVal << *((unsigned short *)szBuf);
+    break;
+    case NX_INT32:
+      ossVal << *((long *)szBuf);
+    break;
+    case NX_UINT32:
+      ossVal << *((unsigned long *)szBuf);
+    break;
+    case NX_FLOAT32:
+      ossVal << *((float *)szBuf);
+    break;
+    case NX_FLOAT64:
+      ossVal << *((double *)szBuf);
+    break;
+    case NX_CHAR:
+      ossVal.write(szBuf, iBufLen);
+    break;
+    default:
+      //## Error...
+      break;
+  }
+  return ossVal.str();
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::CurrentGroupName
+//-----------------------------------------------------------------------------
+string NexusFile::CurrentGroupName()
+{
+  string strGroup = m_pImpl->CurrentGroup();
+	return strGroup.substr(0, strGroup.find('(') - 1);
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::CurrentGroupClass
+//-----------------------------------------------------------------------------
+string NexusFile::CurrentGroupClass()
+{
+  string strGroup = m_pImpl->CurrentGroup();  
+	return strGroup.substr(strGroup.find('(') + 1, strGroup.find(')') - strGroup.find('(') - 1);
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::HasAttribute
+//-----------------------------------------------------------------------------
+bool NexusFile::HasAttribute(const char *pszAttrName, const char *pcszDataSet, const string &strAttrVal)
+{
+	NexusAttrInfo attrInfo;
+  int iStatus = GetFirstAttribute(&attrInfo, pcszDataSet);
+	while( iStatus != NX_EOD )
+	{
+		if( strAttrVal.empty() && stricmp(attrInfo.AttrName(), pszAttrName) == 0 )
+			return true;
+    else if( stricmp(attrInfo.AttrName(), pszAttrName) == 0 )
+    {
+      string strValue = GetAttributeAsString(attrInfo);
+      if( strValue == strAttrVal )
+			  return true;
+    }
+		iStatus = GetNextAttribute(&attrInfo);
+	}
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::BuildAxisDict
+//-----------------------------------------------------------------------------
+bool NexusFile::BuildAxisDict(map<string, string> *pdict, const char *pszGroupPath, const char *pcszDataSet)
+{
+  // Open group and dataset if needed
+  if( pszGroupPath )
+    OpenGroupPath(pszGroupPath);
+  if( pcszDataSet )
+    m_pImpl->OpenDataSet(pcszDataSet);
+
+  // Check 'signal' attribute
+  if( !HasAttribute("signal") )
+  {
+    throw NexusException(NO_SIGNAL_ATTR_ERR, NO_DATASET, "NexusFile::GetAxisList");
+  }
+
+  String strAxes;
+  // Check for 'axes' attribute
+  if( HasAttribute("axes") )
+  {
+    // The 'axes' attribute immediately give the axis list
+    GetAttribute("axes", &strAxes);
+  }
+
+  if( !strAxes.empty() && !(strAxes.StartWith("[") || strAxes.EndWith('?') || strAxes.EndWith(']')) )
+  {
+    // Retreive separator
+    unsigned int iSepPos =  strAxes.find_first_of(",:");
+    char cSep = ':';
+    if( iSepPos != string::npos )
+      cSep = strAxes[iSepPos];
+
+    int iDim=1;
+    CString strAxeName;
+    while( !strAxes.empty() )
+    {
+      ostringstream oss;
+      oss << "axis_" << iDim << "_1";
+      strAxes.ExtractTokenRight(cSep, &strAxeName);
+      (*pdict)[oss.str()] = strAxeName;
+    }
+  }
+  else
+  {
+    // Search for datasets with 'axis' attribute
+    NexusItemInfo aItemInfo;
+    int iRc = GetFirstItem(&aItemInfo);
+    while( NX_EOD != iRc )
+    {
+      if( aItemInfo.IsDataSet() )
+      {
+        OpenDataSet(aItemInfo.ItemName());
+        if( HasAttribute("axis") )
+        {
+          // We found a axis
+          // Get axis (dimension) and order (primary)
+          long lAxis, lPrimary=1;
+          GetAttribute("axis", &lAxis);
+          // Look for 'primary' attribute
+          if( HasAttribute("primary") )
+            GetAttribute("primary", &lPrimary);
+          // Fill dictionnary
+          ostringstream oss;
+          oss << "axis_" << lAxis << "_" << lPrimary;
+          (*pdict)[oss.str()] = aItemInfo.ItemName();
+        }
+        CloseDataSet();
+      }
+      iRc = GetNextItem(&aItemInfo);
+    }
+  }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::BuildScanAxisDict
+//-----------------------------------------------------------------------------
+bool NexusFile::BuildScanAxisDict(map<string, string> *pdict, const char *pszGroupPath, const char *pcszDataSet)
+{
+  // Open group and dataset if needed
+  if( pszGroupPath )
+    OpenGroupPath(pszGroupPath);
+  if( pcszDataSet )
+    m_pImpl->OpenDataSet(pcszDataSet);
+
+  // Check 'signal' attribute
+  if( !HasAttribute("signal") )
+  {
+    throw NexusException(NO_SIGNAL_ATTR_ERR, NO_DATASET, "NexusFile::GetAxisList");
+  }
+
+  String strAxes;
+  // Check for 'axes' attribute
+  if( HasAttribute("axes") )
+  {
+    // The 'axes' attribute immediately give the axis list
+    GetAttribute("axes", &strAxes);
+  }
+
+  // Search for datasets with 'axis' attribute
+  NexusItemInfo aItemInfo;
+  int iRc = GetFirstItem(&aItemInfo);
+  while( NX_EOD != iRc )
+  {
+    if( aItemInfo.IsDataSet() )
+    {
+      OpenDataSet(aItemInfo.ItemName());
+      if( HasAttribute("axis") )
+      {
+        // We found a axis
+        // Get axis (dimension) and order (primary)
+        long lAxis, lPrimary=1;
+        GetAttribute("axis", &lAxis);
+        // Look for 'primary' attribute
+        if( HasAttribute("primary") )
+          GetAttribute("primary", &lPrimary);
+
+        // Look for trajectory pointer
+        if( HasAttribute("trajectory") )
+        {
+          String strTrajectory;
+          GetAttribute("trajectory", &strTrajectory);
+
+          // Fill dictionnary with readed axis values (e.g. actuator at Soleil)
+          ostringstream oss1;
+          oss1 << "axis-readed_" << lAxis << "_" << lPrimary;
+          (*pdict)[oss1.str()] = aItemInfo.ItemName();
+
+          // Get trajectory dataset name
+          GetAttribute("trajectory", &strTrajectory);
+
+          // Fill dictionnary with setted values  (e.g. trajectory at Soleil)
+          ostringstream oss2;
+          oss2 << "axis-setted_" << lAxis << "_" << lPrimary;
+          (*pdict)[oss2.str()] = strTrajectory;
+        }
+        else
+        {
+          // Fill dictionnary
+          ostringstream oss;
+          oss << "axis_" << lAxis << "_" << lPrimary;
+          (*pdict)[oss.str()] = aItemInfo.ItemName();
+        }
+      }
+      CloseDataSet();
+    }
+    iRc = GetNextItem(&aItemInfo);
+  }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// NexusFile::GetScanDim
+//-----------------------------------------------------------------------------
+int NexusFile::GetScanDim(const char *pszGroupPath)
+{
+  // Open group and dataset if needed
+  if( pszGroupPath )
+    OpenGroupPath(pszGroupPath);
+
+  int iMaxAxis = -1;
+  // Search for datasets with 'axis' attribute
+  NexusItemInfo aItemInfo;
+  int iRc = GetFirstItem(&aItemInfo);
+  while( NX_EOD != iRc )
+  {
+    if( aItemInfo.IsDataSet() )
+    {
+      OpenDataSet(aItemInfo.ItemName());
+      if( HasAttribute("axis") )
+      {
+        // We found a axis
+        // Get axis (dimension) and order (primary)
+        long lAxis, lPrimary=1;
+        GetAttribute("axis", &lAxis);
+        if( lAxis > iMaxAxis )
+          iMaxAxis = (int) lAxis;
+      }
+      CloseDataSet();
+    }
+    iRc = GetNextItem(&aItemInfo);
+  }
+
+  if( 0 == iMaxAxis ) 
+    // Time scan
+    return 1;
+
+  if( -1 == iMaxAxis )
+    // No axis dataset found => not a scan
+    return 0;
+
+  return iMaxAxis;
+}
diff --git a/contrib/applications/NXextract/src/nxfile.h b/contrib/applications/NXextract/src/nxfile.h
new file mode 100644
index 0000000..65df3f3
--- /dev/null
+++ b/contrib/applications/NXextract/src/nxfile.h
@@ -0,0 +1,927 @@
+//*****************************************************************************
+/// Synchrotron SOLEIL
+///
+/// NeXus C++ API over NAPI
+///
+/// Creation : 16/02/2005
+/// Author   : Stephane Poirier
+///
+/// This program is free software; you can redistribute it and/or modify it under
+/// the terms of the GNU General Public License as published by the Free Software
+/// Foundation; version 2 of the License.
+/// 
+/// This program is distributed in the hope that it will be useful, but WITHOUT 
+/// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+/// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+///
+//*****************************************************************************
+
+#ifndef __NX_FILE_H__
+#define __NX_FILE_H__
+
+// standard library objets
+#ifndef __IOSTREAM_INCLUDED__
+  #include <iostream>
+  #define __IOSTREAM_INCLUDED__
+#endif
+
+#ifndef __VECTOR_INCLUDED__
+  #include <vector>
+  #define __VECTOR_INCLUDED__
+#endif
+
+using namespace std;
+
+
+#if defined(WIN32) && defined(NEXUSCPP_DLL)
+#  if defined (NEXUSCPP_BUILD)
+#   define NEXUSCPP_DECL __declspec(dllexport)
+#  else
+#   define NEXUSCPP_DECL __declspec(dllimport)
+#  endif
+#else
+#   define NEXUSCPP_DECL
+#endif
+
+// Forward declaration
+class NexusFileImpl;
+
+/// NeXus data types (see napi.h)
+enum NexusDataType
+{
+  NX_NONE      = 0,  /// Value not defined in the NeXus API
+  NX_CHAR      = 4,
+  NX_FLOAT32   = 5,
+  NX_FLOAT64   = 6,
+  NX_INT8      = 20,
+  NX_UINT8     = 21,
+  NX_INT16     = 22,
+  NX_UINT16    = 23,
+  NX_INT32     = 24,
+  NX_UINT32    = 25,
+  NX_INT64     = 26,
+  NX_UINT64    = 27,
+  NX_BINARY    = 21,
+  /// Logical data types (not defined in NeXus API) readed in NeXus meta-DTD files
+  ISO8601      = 100, /// (NX_CHAR)
+  NX_INT       = 102, /// generic integer type
+  NX_FLOAT     = 103  /// generic real type
+};
+
+/// NeXus return codes
+enum NexusRC
+{
+  NX_OK = 1,
+  NX_EOD = -1,
+  NX_ITEM_NOT_FOUND = -2 /// Value not defined in the NeXus API
+};
+
+/// Create access types
+enum ENexusCreateMode
+{
+  NX_HDF4 = 0,
+  NX_HDF5,     // This is the default
+  NX_XML       // Not implemented yet
+};
+
+//=============================================================================
+/// NeXus exceptions
+///
+/// This class is designed to hold nexus exceptions
+//=============================================================================
+class NEXUSCPP_DECL NexusException
+{
+private:
+  void *m_pError;   // Anonymous pointer to error text
+  void *m_pReason;  // Anonymous pointer to reason
+  void *m_pMethod;  // Anonymous pointer to method name
+
+public:
+  NexusException(const char *pcszError, const char *pcszReason, const char *pcszMethod);
+  
+  /// Prints error message on console
+  void PrintMessage();
+
+  /// Copies error message in a pre-allocated string buffer
+  ///
+  /// @param pBuf Buffer (allocated by caller) to copy hte message in
+  /// @param iLen Buffer length
+  ///
+  void GetMsg(char *pBuf, int iLen);
+
+  /// Accessors
+  const char *Error() const;
+  const char *Reason() const;
+  const char *Method() const;
+};
+
+//=============================================================================
+/// NeXus item identifier
+///
+/// This class holds a nexus item ids
+//=============================================================================
+class NEXUSCPP_DECL NexusItemID
+{
+friend class NexusFileImpl;
+
+private:
+  void *m_pLink;  // Anonymous pointer to Nexus link object
+  
+public:
+  NexusItemID();
+  ~NexusItemID();
+};
+
+//=============================================================================
+/// NeXus Data set info
+///
+/// This class allow manipulation of NeXus Data sets and subsets
+//=============================================================================
+class NEXUSCPP_DECL NexusDataSetInfo
+{
+protected:
+  NexusDataType  m_eDataType;      // data type
+  int            m_iRank;          // Data set rank
+  int           *m_piDim;          // size of each dimensions
+
+public:
+  
+  /// Returns size according to a data type
+  static int DataTypeSize(NexusDataType eDataType);
+
+  /// Constructor
+  NexusDataSetInfo();
+
+  /// Destructor
+  ~NexusDataSetInfo();
+
+  /// Sets datas
+  ///
+  /// @param eDataType Data type
+  /// @param iRank Data rank
+  ///
+  void SetInfo(NexusDataType eDataType, int iRank);
+
+  /// Clears instance
+  void Clear();
+
+  //-----------------------------------------------------------------
+  /// @name Accessors
+  //@{
+
+  /// Returns the data type
+  NexusDataType DataType() const { return m_eDataType; }
+
+  /// Returns the data set rank
+  int Rank() const { return m_iRank; }
+
+  /// Returns size array of dimensions
+  /// 
+  int *DimArray() const { return m_piDim; }
+
+  /// Returns total size
+  ///
+  int Size() const;
+
+  /// Returns 'true' if no data set info is stored
+  ///
+  bool IsEmpty() const;
+
+  /// Returns datum size
+  ///
+  unsigned int DatumSize() const;
+
+  /// Returns buffer size
+  unsigned int BufferSize() const { return Size() * DatumSize(); }
+
+  //@} Accessors
+};
+
+//=============================================================================
+/// NeXus Data set
+///
+/// This class allow manipulation of NeXus Data sets and subsets
+//=============================================================================
+class NEXUSCPP_DECL NexusDataSet : public NexusDataSetInfo
+{
+private:
+  void        *m_pData;    // Data set
+  int         *m_piStart;  // indices of starting values in each dimensions
+
+public:
+  /// Constructors
+  NexusDataSet();
+  NexusDataSet(NexusDataType eDataType, void *pData, int iRank, int *piDim, int *piStart=NULL);
+
+  /// Destructor
+  ~NexusDataSet();
+
+  /// Free data block
+  ///
+  void FreeData();
+
+  /// Clears data set
+  void Clear();
+
+  /// Allocate the data set, according to the NexusDataSetInfo part
+  ///
+  void Alloc();
+
+  //-----------------------------------------------------------------
+  /// @name Accessors
+  //@{
+
+  /// Returns a pointer to the data set
+  void *Data() const { return m_pData; }
+
+  /// Returns size of the data block (i.e. Size() * sizeof(<datatype>) )
+  unsigned int MemSize() const;
+
+  /// Returns the number of items
+  unsigned int Size() const;
+
+  /// Sets datas
+  /// 
+  /// @param pParam data pointer we take ownership
+  ///
+  void SetData(void *pData) { m_pData = pData; }
+
+  /// Sets datas
+  ///
+  /// @param pData      Pointer to data to copy
+  /// @param eDataType  Data type
+  /// @param iRank      Number of dimension
+  /// @param piDimArray Dimensions sizes
+  ///
+  void SetData(const void *pData, NexusDataType eDataType, int iRank, int *piDimArray);
+
+  /// Sets one dimension size
+  ///
+  /// iDim  Dimension in range [0, 32[
+  /// iSize Dimension size
+  ///
+  void SetDimension(int iDim, int iSize);
+
+  /// Returns array of indices of starting values in Ith dimension
+  /// 
+  int *StartArray() const { return m_piStart; }
+
+  //@} Accessors
+
+  //=============================================================================
+  /// Basic iterator to browse over NeXusDataSet values
+  //=============================================================================
+  template <class T> class Iterator
+  {
+  private:
+    const NexusDataSet &m_DataSet;
+    char *m_pDataItem;
+
+  public:
+    /// Constructor
+    Iterator(const NexusDataSet &DataSet) : m_DataSet(DataSet)
+    {
+      m_pDataItem = (char *)DataSet.Data();
+    }
+
+    /// Return current value
+    T Value() const
+    {
+      switch( m_DataSet.DataType() )
+      {
+        case NX_FLOAT32:
+          return T(*((float *)m_pDataItem));
+        case NX_FLOAT64:
+          return T(*((double *)m_pDataItem));
+        case NX_INT8:
+          return T(*((char *)m_pDataItem));
+        case NX_INT16:
+          return T(*((short *)m_pDataItem));
+        case NX_INT32:
+          return T(*((long *)m_pDataItem));
+        case NX_UINT8:
+          return T(*((unsigned char *)m_pDataItem));
+        case NX_UINT16:
+          return T(*((unsigned short *)m_pDataItem));
+        case NX_UINT32:
+          return T(*((unsigned long *)m_pDataItem));
+      }
+      return T(0);
+    }
+
+    /// Dereferencing operator
+    T operator *() { return Value(); }
+  
+    /// Post-incrementation operator
+    Iterator operator++(int) 
+    { 
+      m_pDataItem += m_DataSet.DatumSize(); 
+      return *this;
+    }
+
+    /// Pre-incrementation operator
+    Iterator operator++() 
+    { 
+      m_pDataItem += m_DataSet.DatumSize(); 
+      return *this;
+    }
+
+    /// Is end of buffer reached ?
+    bool End() const 
+    { 
+      return m_pDataItem == (char *)m_DataSet.Data() + m_DataSet.MemSize(); 
+    }
+  };
+};
+
+//=============================================================================
+/// NeXus item info
+///
+/// This class is used to store info about founded groups while
+/// browsing a group level
+//=============================================================================
+class NEXUSCPP_DECL NexusItemInfo
+{
+friend class NexusFileImpl;
+
+private:
+  char          *m_pszItem;       // Name of NeXus data item (group or set)
+  char          *m_pszClass;      // Class of NeXus group
+  NexusDataType  m_eDataType;     // data type (NX_NONE for groups)
+
+public:
+  /// Constructor
+  NexusItemInfo();
+
+  /// Destructor
+  ~NexusItemInfo();
+
+  //-----------------------------------------------------------------
+  /// Accessors
+  //@{
+  
+  /// Returns name of NeXus data item (group or set)
+  const char *ItemName() const { return m_pszItem; }
+
+  /// Returns class name of NeXus group
+  const char *ClassName() const { return m_pszClass; }
+
+  /// Returns the data type
+  NexusDataType DataType() const { return m_eDataType; }
+
+  /// Returns 'true' id the item is a data set
+  bool IsDataSet() const;
+
+  /// Returns 'true' id the item is a group
+  bool IsGroup() const;
+
+  //@} Accessors
+};
+
+//=============================================================================
+/// NeXus Attribute info
+///
+/// This class is used to store info about founded attributes while browsing
+/// a group level
+//=============================================================================
+class NEXUSCPP_DECL NexusAttrInfo
+{
+friend class NexusFileImpl;
+
+private:
+  char          *m_pszName;   // Attribute name
+  int            m_iLen;      // Attribute length
+  NexusDataType  m_eDataType;     // Type of attribute data
+
+public:
+  /// Constructor
+  NexusAttrInfo();
+
+  /// Destructor
+  ~NexusAttrInfo();
+
+  //-----------------------------------------------------------------
+  /// Accessors
+  //@{
+  
+  /// Returns name of NeXus attribute
+  const char *AttrName() const { return m_pszName; }
+
+  /// Returns len of attribute
+  int Len() const { return m_iLen; }
+
+  /// Returns type attribute data
+  NexusDataType DataType() const { return m_eDataType; }
+
+  //@} Accessors
+};
+
+//=============================================================================
+/// NeXus File Class
+///
+/// This class allow manipulation of NeXus File with no need to known about
+/// nexus file handle
+/// @note This is wrapper class, the real job is make by a internal objet
+//=============================================================================
+class NEXUSCPP_DECL NexusFile
+{
+private:
+  NexusFileImpl *m_pImpl;   /// Pointer to implementation
+  void          *m_pUserPtr; /// a free data pointer
+
+public:
+  /// @name Constructors and destructor
+  //@{
+
+  /// Constructor
+  ///
+  /// @param pcszFullPath path + complete filename
+  NexusFile(const char *pcszFullPath=NULL);
+
+  /// Destructor
+  ///
+  /// Perform all operations needed such as closing open groups
+  ~NexusFile();
+
+  //@}
+
+  //-----------------------------------------------------------------
+  /// @name File manipulation methods
+  //@{
+
+  /// Creating file
+  ///
+  /// Create Nexus file based on HDF4 library
+  ///
+  /// @param pcszFullPath path + complete filename
+  /// @param eMode creating mode can be NX_HDF4, NX_HDF5 or NX_XML
+  ///
+  void Create(const char *pcszFullPath, ENexusCreateMode eMode = NX_HDF5);
+
+  /// Opens an existing file for read operations
+  ///
+  /// @param pcszFullPath path + complete filename
+  /// 
+  void OpenRead(const char *pcszFullPath);
+
+  /// Opens an existing file for read/write operations
+  ///
+  /// @param pcszFullPath path + complete filename
+  /// 
+  void OpenReadWrite(const char *pcszFullPath);
+
+  /// Closes currently opened file
+  /// Frees all allocated objects (groups & data sets)
+  ///
+  void Close();
+
+  /// Flush
+  /// Flushes all data to the NeXus file
+  ///
+  void Flush();
+
+  //@}
+
+  //-----------------------------------------------------------------
+  /// @name groups manipulations
+  //@{
+
+  /// Adds a new group
+  ///
+  /// The new group is added under the currently opened group
+  /// If no group is already open add the group at the top-level
+  /// (hope this is a NXentry group)
+  ///
+  /// @param pcszName  Group name
+  /// @param pcszClass NeXus class
+  /// @param bOpen    If 'true' automatically open the group
+  ///
+  void CreateGroup(const char *pcszName, const char *pcszClass, bool bOpen=true);
+
+  /// Opens a existing group
+  ///
+  /// @param pcszName  Group name
+  /// @param pcszClass NeXus class
+  /// @param bThrowException if true this method may throw a exception
+  /// @return 
+  ///
+  bool OpenGroup(const char *pcszName, const char *pcszClass, bool bThrowException=true);
+
+  /// Closes current group
+  ///
+  void CloseGroup();
+
+  /// Closes all opened groups
+  ///
+  void CloseAllGroups();
+
+  //@} groups manipulations
+
+  //-----------------------------------------------------------------
+  /// @name data sets manipulations
+  //@{
+
+  /// Creates data set
+  ///
+  /// @param pcszName Data set name
+  /// @param eDataType Data type
+  /// @param iRank Data set rank
+  /// @param piDim Pointer to array of dimensions
+  ///
+  void CreateDataSet(const char *pcszName, NexusDataType eDataType, 
+                     int iRank, int *piDim, int bOpen=true);
+
+  /// Creates compressed data set
+  ///
+  /// @param pcszName Data set name
+  /// @param eDataType Data type (see napi.h)
+  /// @param iRank Data set rank
+  /// @param piDim Pointer to array of dimensions
+  /// @param piChunkDim Pointer to array of chunk dimensions
+  ///
+  void CreateCompressedDataSet(const char *pcszName, NexusDataType eDataType, 
+                               int iRank, int *piDim, int *piChunkDim = NULL, int bOpen=true);
+
+  /// Closes currenly open dataset
+  ///
+  void CloseDataSet();
+
+  /// Quickly creates simple data set and writes the data
+  ///
+  /// @param pcszName Data set name
+  /// @param pData pointer to value
+  /// @param piDim Pointer to array of dimensions sizes
+  /// @param eDataType NeXus Data type (see napi.h)
+  /// @param iRank Dimensions count
+  /// @param bCreate true for creating the dataset before write data otherwise
+  ///        we suppose the dataset already created and opened
+  ///
+  void WriteData(const char *pcszName, void *pData, NexusDataType eDataType, 
+                 int iRank, int *piDim, bool bCreate=true);
+
+  void WriteDataSubSet(const char *pcszName, void *pData, NexusDataType eDataType, 
+                       int iRank, int *piStart, int *piDim, bool bCreate=true, bool bNoDim = false);
+
+  /// 'float' version of #WriteData
+  void WriteData(const char *pcszName, float fValue, bool bCreate=true);
+
+  /// 'double' version of #WriteData
+  void WriteData(const char *pcszName, double dValue, bool bCreate=true);
+
+  /// 'long' version of #WriteData
+  void WriteData(const char *pcszName, long lValue, bool bCreate=true);
+
+  /// 'string' version of #WriteData
+  void WriteData(const char *pcszName, const char *pcszValue, bool bCreate=true);
+
+  /// 'binary' version of #WriteData
+  void WriteData(const char *pcszName, void *pData, int _iLen, bool bCreate=true);
+
+  /// Opens a already existing data set
+  ///
+  /// @param pcszName Data set name
+  bool OpenDataSet(const char *pcszName, bool bThrowException=true);
+
+  /// Puts data in the currently open data set
+  ///
+  /// @param pData Pointer to the data bloc
+  /// @param pcszName Data set name
+  ///
+  /// @note Use pcszName to specify another data set
+  ///
+  void PutData(void *pData, const char *pcszName=NULL, int bFlush=false);
+
+  /// Puts data subset in the currently open data set
+  ///
+  /// @param pData Pointer to the data bloc
+  /// @param piStart Indices of starting values in each dimension
+  /// @param piSize Length of subset in each dimension
+  /// @param pcszName Data set name
+  ///
+  /// @note Use pcszName to specify another data set
+  ///
+  void PutDataSubSet(void *pData, int *piStart, int *piSize, const char *pcszName=NULL);
+
+  //-----------------------------------------------------------------
+  /// @name Data set reading
+  //@{
+  
+  /// Reads data values from a data set in currently open group
+  ///
+  /// @param pDataSet a pointer to a NexusDataSet instanciate by caller
+  /// @param pcszDataSet Data set name
+  /// @note if the data set name isn't provided, supposes that pDataSet isn't empty
+  ///
+  void GetData(NexusDataSet *pDataSet, const char *pcszDataSet=NULL);
+
+  /// Reads data values from a data set in currently open group
+  ///
+  /// @param pDataSet a pointer to a NexusDataSet instanciate by caller
+  /// @param pcszDataSet Data set name
+  /// @note if the data set name isn't provided, supposes that pDataSet isn't empty
+  ///
+  void GetDataSubSet(NexusDataSet *pDataSet, const char *pcszDataSet=NULL);
+
+  /// Gets info about a data set
+  ///
+  /// @param pDataSetInfo a pointer to a NexusDataSetInfo instanciate by caller
+  /// @param pcszDataSet Data set name
+  ///
+  void GetDataSetInfo(NexusDataSetInfo *pDataSetInfo, const char *pcszDataSet);
+
+  //@} data sets manipulations
+
+  //-----------------------------------------------------------------
+  /// @name Getting attributes
+  //@{
+
+  /// Gets a attribute
+  ///
+  /// @param pcszAttr Attribute name
+  /// @param piBufLen Pointer to BufLen
+  /// @param pData Pointer to attribute value buffer
+  /// @param eDataType Attribute data value type
+  ///
+  /// @note The caller is responsible for allocating enough memory
+  ///       for the attribute values
+  void GetAttribute(const char *pcszAttr, int *piBufLen, void *pData, 
+                    NexusDataType eDataType);
+  
+  /// Gets a 'long' attribute. Call 
+  ///
+  /// @param pcszAttr Attribute name
+  /// @param plValue Pointer to attribute value buffer
+  ///
+  /// @note The caller is responsible for allocating enough memory
+  ///       for the attribute values
+  void GetAttribute(const char *pcszAttr, long *plValue);
+  
+  /// Gets a 'double' attribute
+  ///
+  /// @param pcszAttr Attribute name
+  /// @param pdValue Pointer to attribute value buffer
+  ///
+  /// @note The caller is responsible for allocating enough memory
+  ///       for the attribute values
+  void GetAttribute(const char *pcszAttr, double *pdValue);
+
+  /// Gets a 'float' attribute
+  ///
+  /// @param pcszAttr Attribute name
+  /// @param pfValue Pointer to attribute value buffer
+  ///
+  /// @note The caller is responsible for allocating enough memory
+  ///       for the attribute values
+  void GetAttribute(const char *pcszAttr, float *pfValue);
+
+  /// Gets a 'string' attribute
+  ///
+  /// @param pcszAttr Attribute name
+  /// @param pstrValue Pointer to attribute value
+  ///
+  void GetAttribute(const char *pcszAttr, string *pstrValue);
+
+  //@} Getting attributes
+
+  //-----------------------------------------------------------------
+  /// @name Putting attributes
+  /// Writes an attribute of the currently open data set. 
+  /// If no data set is open, a global attribute is generated. 
+  /// The attribute has both a name and a value.
+  /// @param pcszName Data set name
+  /// @param pValue pointer to value
+  /// @param iLen Value buffer length
+  /// @param eDataType NeXus Data type (see napi.h)
+  //@{
+
+  /// Generic method for putting attribute
+  void PutAttr(const char *pcszName, void *pValue, int iLen, NexusDataType eDataType);
+
+  /// Puts a attribute of type 'long'
+  void PutAttr(const char *pcszName, long lValue);
+
+  /// Puts a attribute of type 'string'
+  void PutAttr(const char *pcszName, const char *pcszValue);
+
+  /// Puts a attribute of type 'double'
+  void PutAttr(const char *pcszName, double dValue);
+
+  /// Puts a attribute of type 'float'
+  void PutAttr(const char *pcszName, float fValue);
+
+  //@} // Putting attributes
+
+  //-----------------------------------------------------------------
+  /// @name Browsing methods
+  //@{
+ 
+  /// Get the number of items in the current group
+  int ItemCount();
+
+  /// Get the number of attributes in the current data set
+  int AttrCount();
+
+  /// Get info about the first item (data set or group) in the current group
+  ///
+  /// @param pItemInfo Pointer to NexusItemInfo used to store info
+  ///
+  /// @return NX_OK if data set found
+  ///         NX_EOD if not
+  ///
+  int GetFirstItem(NexusItemInfo *pItemInfo);
+  
+  /// Get info about the next item (data set or group) in the current group
+  ///
+  /// @param pItemInfo Pointer to NexusItemInfo used to store info
+  ///
+  /// @return NX_OK if data set found
+  ///         NX_EOD if not
+  ///
+  int GetNextItem(NexusItemInfo *pItemInfo);
+  
+  /// Get info about the first attribute of the specified data set
+  ///
+  /// @param pAttrInfo Pointer to a NexusAttrInfo object
+  /// @param pcszDataSet Name of the data set to search in
+  /// @return NX_OK if group found,
+  ///         NX_EOD if not
+  ///
+  /// @note if pcszDataSet is NULL searching will be performed in currently open
+  /// data set or in global attribute list if no data set is open
+  /// @note You must call GetFirstAttribute in order to initialize the search process
+  /// then call GetNextAttribute for retrieving information about the remaining
+  /// attributes
+  ///
+  int GetFirstAttribute(NexusAttrInfo *pAttrInfo, const char *pcszDataSet=NULL);
+
+  /// Get info about the next attribute of the specified data set
+  ///
+  /// @param pAttrInfo Pointer to a NexusAttrInfo object
+  /// @return NX_OK if group found
+  ///         NX_EOD if not
+  ///
+  /// @note You must call GetFirstAttribute in order to initialize the search process
+  /// then call GetNextAttribute for retrieving information about the remaining
+  /// attributes
+  ///
+  int GetNextAttribute(NexusAttrInfo *pAttrInfo);
+
+  //@} // Browsing methods
+
+  //-----------------------------------------------------------------
+  /// @name Item linking methods
+  //@{
+ 
+  /// Get a handle on the currently open data set in order to link it with a group
+  /// 
+  /// @return a pointer to the handle, or NULL if no data set is open or no file is open
+  ///
+  void GetDataSetLink(NexusItemID *pnxl);
+
+  /// Get a handle on the currently open group set in order to link it with a group
+  /// 
+  /// @return a pointer to the handle, or NULL if no file is open
+  ///
+  void GetGroupLink(NexusItemID *pnxl);
+
+  /// Link a item to the currently open group
+  ///
+  /// @param pItemHandle Handle of the item to link
+  ///
+  void LinkToCurrentGroup(const NexusItemID &nxl);
+
+  //@} // Item linking methods
+
+  //-----------------------------------------------------------------
+  /// @name User pointer accessors
+  //@{
+
+  /// Get user pointer
+  void *UserPtr() const { return m_pUserPtr; } 
+
+  /// Set user pointer
+  void SetUserPtr(void *p) { m_pUserPtr = p; }
+
+  //@} // User pointer accessors
+
+  //-----------------------------------------------------------------
+  /// @name high level methods
+  //@{
+
+  /// Opens a existing group from a given path
+  ///
+  /// @param pszPath   path to group in the form : /<NXroot>/{Group name}<{group class}>/...
+  ///                  if no group name is specified then open the first group for the given class
+  ///                  example : /<NXroot>/scan_1<NXentry>/<NXdata>
+  /// @param bThrowException if true this method may throw a exception
+  /// @return true if group has been succefully open
+  ///
+  bool OpenGroupPath(const char *pszPath, bool bThrowException=true);
+
+  /// Search for all occurences of a group (name and class) starting at a given level on the hierarchy
+  ///
+  /// @param pszGroupName name of searched group
+  /// @param pszClassName class of searched group
+  /// @param pvecPaths output vector of found groups
+  /// @param pszStartPath path for starting research
+  /// @return NX_OK if at least one group was found
+  ///         NX_EOD if not
+  ///
+  int SearchGroup(const char *pszGroupName, const char *pszClassName,
+                  vector<string> *pvecPaths, const char *pszStartPath=NULL);
+
+  /// Search for all occurences of a data set (name) with a given attribute
+  ///
+  /// @param pszAttrName name of looked attribute 
+  /// @param pvecPaths output vector of found data sets
+  /// @param strAttrVal optionnal attribute value to match
+  /// @return NX_OK if at least one data set was found
+  ///         NX_EOD if not
+  ///
+  int SearchDataSetFromAttr(const char *pszAttrName, vector<string> *pvecDataSets, const string &strAttrVal="");
+
+  /// Search for first occurence of a data set (name) with a given attribute
+  ///
+  /// @param pszAttrName name of looked attribute 
+  /// @param pstrDataSet name of founded data set
+  /// @param strAttrVal optionnal attribute value to match
+  /// @return NX_OK if at least one data set was found
+  ///         NX_EOD if not
+  ///
+  int SearchFirstDataSetFromAttr(const char *pszAttrName, string *pstrDataSet, const string &strAttrVal="");
+
+  /// Gets a attribute as a string regardless of its type
+  ///
+  /// @param pcszAttr Attribute name
+  /// @param pszDataSetName Name of the data set containing the attributge
+  /// @param pszGroupPath Path to the group containing the data set
+  /// @return A STL string containing the value
+  ///
+  string GetAttributeAsString(const NexusAttrInfo &aAttrInfo);
+
+  /// Check if dataset has attribute
+  ///
+  /// @param pszAttrName Name of looked attribute
+  /// @param pcszDataSet (optionnal) Data set to open, if not specified look in currently opened dataset
+  /// @param strAttrVal optionnal attribute value to match
+  /// @return 'true' if sds has attribute, otherwise 'false'
+  ///
+  bool HasAttribute(const char *pszAttrName, const char *pcszDataSet=NULL, const string &strAttrVal="");
+
+  /// Build a dictionnary that contains axis datasets for each dimension belong to a given dataset
+  /// Entries in the dictionnary are in the form :
+  /// 'axis_<axis>_<primary>' = '<dataset name>
+  ///
+  /// @param vecvecAxis Vector of axis vectors that will contains the axis datasets name
+  /// @param pszGroup Group Path
+  /// @param pszDataSet DataSet name
+  ///
+  /// @return 'true' if at least one axis has been found
+  ///
+  bool BuildAxisDict(map<string, string> *pmapAxis, const char *pszGroupPath=NULL, const char *pcszDataSet=NULL);
+
+  /// Build a dictionnary that contains axis values (readed and setted) datasets for each dimension belong to a given dataset
+  /// Entries in the dictionnary are in the form :
+  /// 'axis-readed_<axis>_<primary>' = '<dataset name>
+  /// 'axis-setted_<axis>_<primary>' = '<dataset name>
+  ///
+  /// @param vecvecAxis Vector of axis vectors that will contains the axis datasets name
+  /// @param pszGroup Group Path
+  /// @param pszDataSet DataSet name
+  ///
+  /// @return 'true' if at least one axis has been found
+  ///
+  bool BuildScanAxisDict(map<string, string> *pmapAxis, const char *pszGroupPath=NULL, const char *pcszDataSet=NULL);
+
+  /// Get scam dimension
+  ///
+  /// Reads NXdata group and look for variables datasets (with attribute axis) and return the 
+  /// biggest axis attribute value (note that in time scan case axis may be seeted to 0)
+  ///
+  /// @param pszGroup Group Path
+  ///
+  /// @return scan dimension (time scans are 1D scans), or 0 if no axis datasets was found
+  ///
+  int GetScanDim(const char *pszDataGroupPath);
+
+  /// Current Group Name
+  ///
+  string CurrentGroupName();
+
+  /// Current Group Class
+  ///
+  string CurrentGroupClass();
+
+  //@}
+
+  //-----------------------------------------------------------------
+  /// @name Deprecated methods
+  //@{
+
+  void GetAttribute(const char *pcszAttr, char *pszValue, int iBufLen);
+
+  //@}
+
+};
+
+#endif
diff --git a/contrib/applications/NXextract/src/templateparsor.cpp b/contrib/applications/NXextract/src/templateparsor.cpp
new file mode 100644
index 0000000..4e18783
--- /dev/null
+++ b/contrib/applications/NXextract/src/templateparsor.cpp
@@ -0,0 +1,1026 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 20/07/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "file.h"
+#include "membuf.h"
+#include "nxfile.h"
+#include "variant.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>  
+#include <vector>
+#include <cstring>
+#include <cstdlib>
+
+#include "nexusevaluator.h"
+#include "extractor.h"
+#include "templateparsor.h"
+
+using namespace gdshare;
+
+typedef struct _LineToken
+{
+  pcsz pszToken1;                // Token
+  TemplateToken::Type TokenType; // Token type
+  bool bRemoveToken;
+} SLineToken;
+
+const int g_iTokenCount = 13;
+SLineToken g_LineToken[g_iTokenCount] = 
+{ 
+  {"@(", TemplateToken::LOOP, true},
+  {"@)", TemplateToken::END_LOOP, true},
+  {"?(", TemplateToken::IF, true},
+  {"?)", TemplateToken::END_IF, true},
+  {"\"", TemplateToken::PRINT, false},
+  {">", TemplateToken::OUTPUT, true},
+  {"b>", TemplateToken::BINARY_OUTPUT, true},
+  {"%", TemplateToken::SET, true},
+  {"(", TemplateToken::BLOCK_START, true},
+  {")", TemplateToken::BLOCK_END, true},
+  {"...", TemplateToken::PADDING, true},
+  {"'", TemplateToken::BINARY, false},
+  {"+", TemplateToken::INCLUDE, true}
+};
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::TemplateFileParsor
+//-----------------------------------------------------------------------------
+TemplateFileParsor::TemplateFileParsor(VecToken *pvecToken)
+                    :m_vecToken(*pvecToken), m_pVarEval(NULL)
+{
+  m_bHeaderParsed = false;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::SuppressComments
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::SuppressComments(String *pstrLine)
+{
+  // Extract payload charge
+  int iSearchPos = 0;
+  while( true )
+  {
+    int iCom = pstrLine->find("//", iSearchPos);
+    if( (uint)iCom != string::npos )
+    {
+      if( ((*pstrLine)[iCom - 1] == ' ' || (*pstrLine)[iCom - 1] == '\t') )
+      {
+        pstrLine->erase(iCom, pstrLine->size()-iCom);
+          break;
+      }
+      iSearchPos = iCom + 1;
+    }
+    else
+      break;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseSet
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ParseSet(String *pstrLine, int iLine)
+{
+  TokenSet *pToken = new TokenSet;
+  pToken->m_TokenType = TemplateToken::SET;
+
+  // Looking for the commentaries to eliminate them.
+  SuppressComments(pstrLine);
+
+  // Parsing variable name
+  String strVarName;
+  pstrLine->ExtractToken('=' , &strVarName);
+
+  pToken->m_strParam1 = strVarName;
+  pToken->m_strParam1.Trim();
+  (*pstrLine).Trim();
+  pToken->m_bEvalArgument = true;
+  if( pstrLine->Match("'*'") || pstrLine->Match("\"*\"") )
+  {
+    pToken->m_iTemplateLine = iLine;
+    (*pstrLine).RemoveEnclosure("'\"", "'\"");
+    pToken->m_bEvalArgument = false;
+    pToken->m_strParam2 = *pstrLine; // value
+  }
+  else if( pstrLine->Match("[*]*") )
+  {
+    // This is a list
+    pToken->m_TokenType = TemplateToken::SET_LIST;
+    pstrLine->ExtractToken('[', ']', &pToken->m_strParam2);
+    pToken->m_strParam3 = *pstrLine;
+  }
+  else
+  {
+    // Standard argument
+    pToken->m_iTemplateLine = iLine;
+    pToken->m_strParam2 = *pstrLine; // value
+  }
+  m_vecToken.push_back(TemplateTokenPtr(pToken));
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseOutput
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ParseOutput(String *pstrLine, int iLine, bool bBinary)
+{
+  TemplateTokenPtr ptrToken(new TemplateToken);
+  ptrToken->m_TokenType = TemplateToken::OUTPUT;
+
+  // we look for the commentaries to eliminate them.
+  SuppressComments(pstrLine);
+
+  // Store parameters
+  ptrToken->m_strParam1 = *pstrLine;
+  ptrToken->m_strParam1.Trim();
+  ptrToken->m_iTemplateLine = iLine;
+  ptrToken->m_iParam1 = bBinary ? 1 : 0;
+
+  m_vecToken.push_back(ptrToken);
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseLoop
+//-----------------------------------------------------------------------------
+int TemplateFileParsor::ParseLoop(String *pstrLine, int iLine)
+{
+  TokenLoop *pToken = new TokenLoop;
+
+  pToken->m_iTemplateLine = iLine;
+  
+  // we look for the commentaries to eliminate them.
+  SuppressComments(pstrLine);
+
+  // Extract the name of iteration variable
+  pstrLine->ExtractToken('=', &pToken->m_strParam1);
+  // Next parameter
+  int rc = pstrLine->ExtractToken(',', &pToken->m_strParam2);
+  if( pstrLine->find(',') != string::npos )
+    // Loop step
+    pstrLine->ExtractTokenRight(',', &pToken->m_strParam4);
+
+  // Suppress white spaces
+  pToken->m_strParam1.Trim();
+  pToken->m_strParam2.Trim();
+
+  if( 2 == rc ) // token not found
+  {
+    pToken->m_TokenType = TemplateToken::LOOP_OVER;
+    if( pToken->m_strParam1.empty() )
+    {
+      cerr << "Error: Missed variable name at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+      exit(1);
+    }
+
+    if( pToken->m_strParam2.empty() )
+    {
+      cerr << "Error: Missed NeXus path at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+      exit(1);
+    }
+    if( pToken->m_strParam2.Match("[*]") )
+      pToken->m_strParam2 = pToken->m_strParam2.substr(1, pToken->m_strParam2.size()-2 );
+    else
+    {
+      cerr << "Error: Bad loop syntax at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+      exit(1);
+    }
+  }
+  else
+  {
+    pToken->m_TokenType = TemplateToken::LOOP;
+    // End value 
+    pToken->m_strParam3 = *pstrLine;
+    pToken->m_strParam3.Trim();
+    if( pToken->m_strParam1.empty() )
+    {
+      cerr << "Error: Missed counter name at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+      exit(1);
+    }
+
+    if( pToken->m_strParam2.empty() )
+    {
+      cerr << "Error: Missed initial value for counter at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+      exit(1);
+    }
+
+    if( pToken->m_strParam3.empty() )
+    {
+      cerr << "Error: Missed final value for counter at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+      exit(1);
+    }
+
+    // Parse expressions
+    pToken->ptrExprBegin = ParseExpression(pToken->m_strParam2);
+    pToken->ptrExprEnd = ParseExpression(pToken->m_strParam3);
+    if( !pToken->m_strParam4.empty() )
+      pToken->ptrExprStep = ParseExpression(pToken->m_strParam4);
+  }
+
+  m_vecToken.push_back(pToken);
+  return m_vecToken.size()-1;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseIfCond
+//-----------------------------------------------------------------------------
+int TemplateFileParsor::ParseIfCond(String *pstrLine, int iLine)
+{
+  TemplateTokenPtr ptrToken(new TemplateToken);
+  ptrToken->m_iTemplateLine = iLine;
+  
+  // Extract payload charge
+  SuppressComments(pstrLine);
+  pstrLine->Trim();
+
+  String strCond, strParam2;
+  uint uiPos = string::npos;
+  if( string::npos == uiPos )
+  {
+    uiPos = pstrLine->rfind("!=");
+    if( uiPos != string::npos )
+    {
+      ptrToken->m_TokenType = TemplateToken::IF_NOT_EQ;
+      ptrToken->m_strParam1 = pstrLine->substr(0, uiPos);
+      strParam2 = pstrLine->substr(uiPos + 2);
+    }
+  }
+  if( string::npos == uiPos )
+  {
+    uiPos = pstrLine->rfind("=");
+    if( uiPos != string::npos )
+    {
+      ptrToken->m_TokenType = TemplateToken::IF_EQ;
+      ptrToken->m_strParam1 = pstrLine->substr(0, uiPos);
+      strParam2 = pstrLine->substr(uiPos + 1);
+    }
+  }
+  if( string::npos == uiPos )
+  {
+    uiPos = pstrLine->rfind(">");
+    if( uiPos != string::npos )
+    {
+      ptrToken->m_TokenType = TemplateToken::IF_SUP;
+      ptrToken->m_strParam1 = pstrLine->substr(0, uiPos);
+      strParam2 = pstrLine->substr(uiPos + 1);
+    }
+  }
+  if( string::npos == uiPos )
+  {
+    uiPos = pstrLine->rfind("<");
+    if( uiPos != string::npos )
+    {
+      ptrToken->m_TokenType = TemplateToken::IF_INF;
+      ptrToken->m_strParam1 = pstrLine->substr(0, uiPos);
+      strParam2 = pstrLine->substr(uiPos + 1);
+    }
+  }
+
+  ptrToken->m_strParam1.Trim();
+  strParam2.Trim();
+
+  // Remove quotes or double quotes if any
+  strParam2.ExtractToken('\'', '\'', &ptrToken->m_strParam2);
+  if( ptrToken->m_strParam2.empty() )
+    strParam2.ExtractToken('"', '"', &ptrToken->m_strParam2);
+  if( ptrToken->m_strParam2.empty() )
+    // No quotes
+    ptrToken->m_strParam2 = strParam2;
+
+  m_vecToken.push_back(ptrToken);
+  return m_vecToken.size()-1;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseIfExists
+//-----------------------------------------------------------------------------
+int TemplateFileParsor::ParseIfExists(String *pstrLine, int iLine)
+{
+  TemplateTokenPtr ptrToken(new TemplateToken);
+  ptrToken->m_TokenType = TemplateToken::IF_EXISTS;
+  ptrToken->m_iTemplateLine = iLine;
+
+  // Extract payload charge
+  SuppressComments(pstrLine);
+
+  // we parse the name of the NeXus Object.
+  pstrLine->Trim();
+  if( pstrLine->StartWith("nxs:") )
+    ptrToken->m_strData = *pstrLine;
+  else // Variable
+    ptrToken->m_strParam1 = *pstrLine;
+  m_vecToken.push_back(ptrToken);
+  return m_vecToken.size()-1;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseIf
+//-----------------------------------------------------------------------------
+int TemplateFileParsor::ParseIf(String *pstrLine, int iLine)
+{
+  // Search kind of 'if' statement
+  pcsz pszLine = PSZ(*pstrLine);
+  if( strstr(pszLine, "=") || strstr(pszLine, "!=") || strstr(pszLine, ">") || strstr(pszLine, "<") )
+    return ParseIfCond(pstrLine, iLine);
+
+  return ParseIfExists(pstrLine, iLine);
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseBlockStart
+//-----------------------------------------------------------------------------
+int TemplateFileParsor::ParseBlockStart(String *pstrLine)
+{
+  // Extract payload charge
+  SuppressComments(pstrLine);
+  pstrLine->Trim();
+
+  TemplateTokenPtr ptrToken(new TemplateToken);
+  ptrToken->m_TokenType = TemplateToken::BLOCK_START;
+
+  // Get block name
+  pstrLine->ExtractToken(' ', &ptrToken->m_strParam1); 
+  // Get max block length
+  ptrToken->m_strParam2 = *pstrLine;
+
+  m_vecToken.push_back(ptrToken);
+  return m_vecToken.size()-1;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParsePadding
+//-----------------------------------------------------------------------------
+int TemplateFileParsor::ParsePadding(String *pstrLine, int iLine)
+{
+  // Extract payload charge
+  SuppressComments(pstrLine);
+  pstrLine->Trim();
+
+  TemplateTokenPtr ptrToken(new TemplateToken);
+  ptrToken->m_TokenType = TemplateToken::PADDING;
+
+  // Get Padding pattern
+  ptrToken->m_strParam1 = *pstrLine;
+  if( pstrLine->empty() )
+    // default padding pattern : 80 blanks characters and a LF
+    ptrToken->m_strParam1 = "                                                                                \n";
+  else
+  {
+    int iRc = pstrLine->ExtractToken('"', '"', &ptrToken->m_strParam1);
+    if( iRc != String::SEP_FOUND )
+    {
+      cerr << "Error: bad syntax at line " << iLine << " in file " << m_strCurrentTemplateFile << "; quotes missing." << endl;
+      exit(1);
+    }
+  }
+
+  m_vecToken.push_back(ptrToken);
+  return m_vecToken.size()-1;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::BuildDataFragments
+//-----------------------------------------------------------------------------
+bool TemplateFileParsor::BuildDataFragments(TemplateToken *pToken, const String &strData)
+{
+  String strToFragment = strData;
+  bool bVarDetected = false;
+
+  while( strToFragment.size() > 0 )
+  {
+    // Search for a variable
+    uint uiFirstPos = strToFragment.find("$(");
+    if( String::npos != uiFirstPos )
+    {
+      // Search for matching ')'. Take care of nested variables
+      uint uiMatchPos = strToFragment.find_first_of(')', uiFirstPos + 2);
+
+      if( String::npos != uiMatchPos )
+      {
+        // New fragment
+        if( uiFirstPos > 0 )
+        {
+          DataFragment fragText(DataFragment::TEXT, strToFragment.substr(0, uiFirstPos));
+          pToken->lstDataFragments.push_back(fragText);
+        }
+
+        // Delete up to '$(' characters
+        strToFragment.erase(0, uiFirstPos + 2);
+
+        // Extract variable content
+        DataFragment fragVar(DataFragment::VARIABLE, strToFragment.substr(0, uiMatchPos - uiFirstPos - 2));
+        pToken->lstDataFragments.push_back(fragVar);
+
+        // Delete up to matching end parenthesis
+        strToFragment.erase(0, uiMatchPos - uiFirstPos - 1);
+
+        bVarDetected = true;
+      }
+      else
+      {
+        // Missing close bracket
+        // Copying up to the end of template string
+        DataFragment fragText(DataFragment::TEXT, strToFragment);
+        pToken->lstDataFragments.push_back(fragText);
+        strToFragment.erase();
+      }
+    }
+    else
+    {
+      // Copying up to the end of template string
+      DataFragment fragText(DataFragment::TEXT, strToFragment);
+      pToken->lstDataFragments.push_back(fragText);
+      strToFragment.erase();
+    }
+  }
+  return bVarDetected;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::GetTypeFromFormat
+//-----------------------------------------------------------------------------
+DataBuf::Type TemplateFileParsor::GetTypeFromFormat(char cType, char cMod)
+{
+  switch( cType )
+  {
+    case 's':
+      return DataBuf::CHAR;
+    case 'd':
+      if( cMod == 'l')
+        return DataBuf::LONG;
+      else if( cMod == 'h')
+        return DataBuf::SHORT;
+      return DataBuf::INT;
+    case 'e':
+    case 'E':
+    case 'f':
+    case 'g':
+    case 'G':
+      return DataBuf::DOUBLE;
+    case '?':
+      return DataBuf::UNKNOWN;
+    default:
+      return DataBuf::UNKNOWN;
+  };
+
+  return DataBuf::UNKNOWN;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParsePrintData
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ParsePrintData(String *pstrLine, int iLine)
+{
+  pstrLine->Trim();
+  String strToPrint;
+  int iRc = pstrLine->ExtractToken('"', '"', &strToPrint);
+
+  CTemplateProcessor VarProc(CTemplateProcessor::EMPTY_STRING);
+  if( m_pVarEval )
+    VarProc.AddEvaluator(m_pVarEval);
+  CEnvVariableEvaluator EnvVar;
+  VarProc.AddEvaluator(&EnvVar);
+
+  // Variable substitution in quoted strings !!
+  VarProc.Process(&strToPrint);
+
+  uint uiPos = 0;
+  // looking for new line characters.
+  for( uiPos = strToPrint.find("\\n"); uiPos != String::npos; uiPos = strToPrint.find("\\n"))
+    strToPrint.replace(uiPos, 2, "\n");
+
+  // looking for carriage return characters.
+  for( uiPos = strToPrint.find("\\r"); uiPos != String::npos; uiPos = strToPrint.find("\\r"))
+    strToPrint.replace(uiPos, 2, "\r");
+
+  // looking for tab characters.
+  for( uiPos = strToPrint.find("\\t"); uiPos != String::npos; uiPos = strToPrint.find("\\t"))
+    strToPrint.replace(uiPos, 2, "\t");
+
+  if( 1 == iRc )
+  {
+    while( !strToPrint.empty() )
+    {
+      String strTxt, strTmp;
+      // Search for next format directive
+      bool bParse = true;
+      while( bParse )
+      {
+        iRc = strToPrint.ExtractToken('%', &strTmp);
+        // Skip directive indicator if it's a '%%' pair
+        if( strToPrint.StartWith('%') )
+        {
+          strTmp += '%';
+          strToPrint.erase(0, 1);
+        }
+        else
+          bParse = false;
+        strTxt += strTmp;
+      }
+
+      if( !strTxt.empty() )
+      {
+        // Text to print before format directive
+        TemplateTokenPtr ptrToken(new TemplateToken);
+        ptrToken->m_iTemplateLine = iLine;
+        ptrToken->m_TokenType = TemplateToken::PRINT_TEXT;
+        ptrToken->m_strData = strTxt;
+        ptrToken->m_Format.Set("%s");
+        m_vecToken.push_back(ptrToken);
+      }
+
+      if( 1 == iRc )
+      {
+        // A format directive was found
+        SuppressComments(pstrLine);
+        String strArgument;
+        int iRc2 = pstrLine->ExtractToken(',', &strArgument);
+        if( 0 == iRc2 )
+        {
+          cerr << "Error: Argument missing at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+          exit(1);
+        }
+        // Remove blanks
+        strArgument.Trim();
+
+        // Check argument type
+        if( strArgument.Match("[nxs:*<*>]*") )
+        {
+          // This is a array type argument
+          // Erase '[' and ']' enclosers
+          strArgument.erase(0, 1); // '['
+          uint uiMatchingPos = strArgument.find(']');
+          strArgument.erase(uiMatchingPos, 1); // ']'
+
+          // Insert a loop/end-loop couple
+          TemplateTokenPtr ptrLoopToken(new TemplateToken);
+          ptrLoopToken->m_iTemplateLine = iLine;
+          ptrLoopToken->m_TokenType = TemplateToken::LOOP_OVER;
+          ptrLoopToken->m_strParam1 = "loopvar";
+
+          // Extract loop part of the argument
+          String strLastPart;
+          int iLastPart = strArgument.rfind('>');
+          strLastPart = strArgument.substr(iLastPart+1);
+          ptrLoopToken->m_strParam2 = strArgument.substr(0, iLastPart+1);
+          ptrLoopToken->m_iEndBlockPos = m_vecToken.size() + 1;
+          // Add 'loop' Token
+          m_vecToken.push_back(ptrLoopToken);
+
+          // Replace loop element with variable access
+          String strTmp;
+          strArgument.ExtractTokenRight('<', '>', &strTmp);
+          strArgument += "$(loopvar_name)" + strLastPart;
+        }
+        else if( strArgument.Match("*[$(*)]*") )
+        {
+          uint uiMatchingPos = strArgument.find("[$(");
+          uint uiLastPos = strArgument.find("]", uiMatchingPos);
+          String strBeforePattern = strArgument.substr(0, uiMatchingPos);
+          String strAfterPattern = strArgument.substr(uiLastPos + 1);
+          String strMatchedPattern = strArgument.substr(uiMatchingPos + 1, uiLastPos - uiMatchingPos - 1);
+
+          // Insert a loop/end-loop couple
+          TemplateTokenPtr ptrLoopToken(new TemplateToken);
+          ptrLoopToken->m_iTemplateLine = iLine;
+          ptrLoopToken->m_TokenType = TemplateToken::LOOP_OVER;
+          ptrLoopToken->m_strParam1 = "loopvar";
+
+          ptrLoopToken->m_strParam2 = strMatchedPattern;
+          ptrLoopToken->m_iEndBlockPos = m_vecToken.size() + 1;
+          // Add 'loop' Token
+          m_vecToken.push_back(ptrLoopToken);
+          // Rebuild argument for next token (inside loop)
+          strArgument = strBeforePattern + "$(loopvar_name)" + strAfterPattern;
+        }
+
+        TemplateTokenPtr ptrToken(new TemplateToken);
+        ptrToken->m_iTemplateLine = iLine;
+        ptrToken->m_TokenType = TemplateToken::PRINT_DATA;
+
+        if( false == BuildDataFragments(ptrToken.ObjectPtr(), strArgument) )
+          // If no variable are presents in the argument string then fill strData member
+          ptrToken->m_strData = strArgument;
+        
+        // Extend format string up to next format directive
+        int iPos = strToPrint.find('%');
+        // Parse format
+        ptrToken->m_Format.Set('%' + strToPrint.substr(0, iPos));
+        // Search for format type in first 10 characters
+        DataBuf::Type eType = GetTypeFromFormat(ptrToken->m_Format.Type(), ptrToken->m_Format.Modifier());
+        if( DataBuf::NO_TYPE == eType )
+        {
+          cerr << "Error: Bad type specification at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+          exit(1);
+        }
+        ptrToken->m_eOutputType = eType;
+        ptrToken->m_strPrintFmt = ptrToken->m_Format.Get();
+
+        m_vecToken.push_back(ptrToken);
+        strToPrint.erase(0, iPos);
+      }
+    }
+  }
+  else
+  {
+    cerr << "Error: Missed '\"' at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+    exit(1);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseBinary
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ParseBinary(String *pstrLine, int iLine)
+{
+  if( pstrLine->StartWith("binary", true) )
+    pstrLine->erase(0, strlen("binary"));
+  pstrLine->Trim();
+
+  String strBinaryFormat;
+  int iRc = pstrLine->ExtractToken('\'', '\'', &strBinaryFormat);
+  pstrLine->Trim();
+
+  if( iRc != EXTRACT_TOKEN_FOUND )
+  {
+    cerr << "Error: Syntax error at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+    exit(1);
+  }
+
+  TemplateTokenPtr ptrToken(new TemplateToken);
+  ptrToken->m_iTemplateLine = iLine;
+  ptrToken->m_TokenType = TemplateToken::BINARY;
+
+  if( false == BuildDataFragments(ptrToken.ObjectPtr(), *pstrLine) )
+    // If no variable are presents in the argument string then fill strData member
+    ptrToken->m_strData = *pstrLine;
+
+  if( strBinaryFormat == "c" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::CHAR;
+    ptrToken->m_uiTypeSize = 1;
+  }
+  else if( strBinaryFormat == "i1" || strBinaryFormat == "bt" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::BYTE;
+    ptrToken->m_uiTypeSize = 1;
+  }
+  else if( strBinaryFormat == "i2" || strBinaryFormat == "si")
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::SHORT;
+    ptrToken->m_uiTypeSize = sizeof(short);
+  }
+  else if( strBinaryFormat == "ui2" || strBinaryFormat == "usi")
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::USHORT;
+    ptrToken->m_uiTypeSize = sizeof(unsigned short);
+  }
+  else if( strBinaryFormat == "i4" || strBinaryFormat == "li" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::LONG;
+    ptrToken->m_uiTypeSize = sizeof(long);
+  }
+  else if( strBinaryFormat == "ui4" || strBinaryFormat == "uli" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::LONG;
+    ptrToken->m_uiTypeSize = sizeof(unsigned long);
+  }
+  else if( strBinaryFormat == "f4" || strBinaryFormat == "f" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::FLOAT;
+    ptrToken->m_uiTypeSize = sizeof(float);
+  }
+  else if( strBinaryFormat == "f8" || strBinaryFormat == "lf" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::DOUBLE;
+    ptrToken->m_uiTypeSize = sizeof(double);
+  }
+  else if( strBinaryFormat == "b" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::RAW;
+    ptrToken->m_uiTypeSize = 0;
+  }
+  else if( strBinaryFormat == "jpeg" )
+  {
+#ifdef __JPEG_SUPPORT__
+    ptrToken->m_eBinaryDataType = TemplateToken::JPEG_IMAGE;
+    ptrToken->m_uiTypeSize = 0;
+#else
+    cerr << "Error: jpeg output not supported in this version (line: " << iLine << " in file " << m_strCurrentTemplateFile << ")." << endl;
+    exit(1);
+#endif
+  }
+  else if( strBinaryFormat == "bmp" )
+  {
+    ptrToken->m_eBinaryDataType = TemplateToken::BMP_IMAGE;
+    ptrToken->m_uiTypeSize = 0;
+  }
+  else
+  {
+    cerr << "Error: unknown binary format '" << strBinaryFormat << "' at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+    exit(1);
+  }
+  m_vecToken.push_back(ptrToken);
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::Parse
+//-----------------------------------------------------------------------------
+bool TemplateFileParsor::IsLoopToken(const TemplateToken &aToken)
+{
+  if( TemplateToken::LOOP_OVER == aToken.m_TokenType ||
+      TemplateToken::LOOP == aToken.m_TokenType )
+    return true;
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::Parse
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::Parse(const string &strTemplateName, IVariableEvaluator *pVarEval)
+{
+  m_pVarEval = pVarEval;
+  m_fnMainTemplate.Set(strTemplateName);
+  m_strCurrentTemplateFile = strTemplateName;
+  Parse(strTemplateName);
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::Parse
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::Parse(const string &strTemplateName)
+{
+  m_strCurrentTemplateFile = strTemplateName;
+  if( !FileExists(PSZ(m_strCurrentTemplateFile)) )
+  {
+    // Try with name relative to main template
+    m_strCurrentTemplateFile = FileName(m_fnMainTemplate.Path() + m_strCurrentTemplateFile).FullName();
+    if( !FileExists(PSZ(m_strCurrentTemplateFile)) )
+    {
+      cerr << "File " << strTemplateName << "don't exists" << endl;
+      exit(1);
+    }
+  }
+
+  // Build tokens tree
+  ifstream fs(PSZ(m_strCurrentTemplateFile));
+
+  int iLine = 0;
+  // Tokenize
+  Tokenize(fs, iLine);
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ReadHeader
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ReadHeader(const string &strTemplateName, String *pstrParams)
+{
+  // Build template lines list
+  ifstream fs(PSZ(strTemplateName));
+  int iLine = 0;
+  
+  while( !fs.eof() )
+  {
+    iLine++;
+    fs.getline(g_acScratchBuf, g_iScratchLen);
+    String strLine = g_acScratchBuf;
+    strLine.Trim();
+
+    if( !strLine.StartWith("#") )
+      // End of header reached
+      return;
+
+    // Header parsing
+    // Search for lines begining with "# @param..."
+    strLine.erase(0, 1);
+    strLine.Trim();
+    if( strLine.StartWith("@param") )
+    {
+      strLine.erase(0, strlen("@param"));
+      strLine.Trim();
+
+      // Get name
+      String strName;
+      strLine.ExtractToken(' ', &strName);
+      strName.Trim();
+      strLine.Trim();
+      
+      // Pass type;
+      String strTmp;
+      strLine.ExtractToken(' ', &strTmp);
+      strLine.Trim();
+
+      // Pass description
+      strLine.ExtractToken('\'', '\'', &strTmp);
+      strLine.Trim();
+      *pstrParams += strName + string("=") + strLine + string(",");
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseEndBlock
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ParseEndBlock(TemplateToken::Type eExpectedType, 
+                                        TemplateToken::Type eTokenType,
+                                        int iLine)
+{
+  if( eExpectedType != eTokenType )
+  {
+    cerr << "Error : end block mismatching at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+    exit(1);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParsePreprocessorInclude
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::ParsePreprocessorInclude(String *pstrLine)
+{
+  if( pstrLine->StartWith("include", true) )
+    pstrLine->erase(0, strlen("include"));
+  if( pstrLine->StartWith("+", true) )
+    pstrLine->erase(0, strlen("+"));
+  pstrLine->Trim();
+
+  String strFileName;
+  pstrLine->ExtractToken('\'', '\'', &strFileName);
+  Parse(strFileName);
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::GetLineToken
+//-----------------------------------------------------------------------------
+TemplateToken::Type TemplateFileParsor::GetLineToken(String &strLine)
+{
+  for( int i = 0; i < g_iTokenCount; i++ )
+  {
+    if( strLine.StartWith(g_LineToken[i].pszToken1) )
+    {
+      if( g_LineToken[i].bRemoveToken )
+        strLine.erase(0, strlen(g_LineToken[i].pszToken1) );
+      return g_LineToken[i].TokenType;
+    }
+  }
+  return TemplateToken::NO_TYPE;
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::Tokenize
+//-----------------------------------------------------------------------------
+void TemplateFileParsor::Tokenize(ifstream &fs, int &iLine, TemplateToken::Type eEndBlockToken)
+{
+  while( !fs.eof() )
+  {
+    iLine++;
+    fs.getline(g_acScratchBuf, g_iScratchLen);
+    String strLine = g_acScratchBuf;
+    Trim(&strLine);
+    // Merge splitted lines (with '\')
+    while( EndWith(strLine, '\\') )
+    {
+      iLine++;
+      strLine.erase(strLine.size()-1);
+      fs.getline(g_acScratchBuf, g_iScratchLen);
+      String strPartLine = g_acScratchBuf;
+      Trim(&strPartLine);
+      strLine += strPartLine;
+    }
+
+    // Replace tabs with spaces
+    strLine.Replace('\t', ' ');
+
+    if( strLine.size() == 0 || strLine.StartWith("//") || strLine.StartWith("#") )
+      // Empty line
+      continue;
+
+    int iTokenType = (int)GetLineToken(strLine);
+    switch( iTokenType )
+    {
+      case TemplateToken::PRINT:
+        ParsePrintData(&strLine, iLine);
+        break;
+      case TemplateToken::LOOP:
+      {
+        int iPos = ParseLoop(&strLine, iLine);
+        Tokenize(fs, iLine, TemplateToken::END_LOOP);
+        // Store end block position in token vector
+        m_vecToken[iPos]->m_iEndBlockPos = m_vecToken.size() - 1;
+        break;
+      }
+      case TemplateToken::IF:
+      {
+        int iPos = ParseIf(&strLine, iLine);
+        Tokenize(fs, iLine, TemplateToken::END_IF);
+        // Store end block position in token vector
+        m_vecToken[iPos]->m_iEndBlockPos = m_vecToken.size() - 1;
+        break;
+      }
+      case TemplateToken::BLOCK_START:
+        {
+          int iPos = ParseBlockStart(&strLine);
+          Tokenize(fs, iLine, TemplateToken::BLOCK_END);
+          // Store end block position in token vector
+          m_vecToken[iPos]->m_iEndBlockPos = m_vecToken.size() - 1;
+          break;
+        }
+      case TemplateToken::END_LOOP:
+        ParseEndBlock(eEndBlockToken, TemplateToken::END_LOOP, iLine);
+        return;
+      case TemplateToken::END_IF:
+        ParseEndBlock(eEndBlockToken, TemplateToken::END_IF, iLine);
+        return;
+      case TemplateToken::BLOCK_END:
+        ParseEndBlock(eEndBlockToken, TemplateToken::BLOCK_END, iLine);
+        return;
+      case TemplateToken::SET:
+        ParseSet(&strLine, iLine);
+        break;
+      case TemplateToken::OUTPUT:
+        ParseOutput(&strLine, iLine, false);
+        break;
+      case TemplateToken::BINARY_OUTPUT:
+        ParseOutput(&strLine, iLine, true);
+        break;
+      case TemplateToken::BINARY:
+        ParseBinary(&strLine, iLine);
+        break;
+      case TemplateToken::PADDING:
+        ParsePadding(&strLine, iLine);
+        break;
+      case TemplateToken::INCLUDE:
+        ParsePreprocessorInclude(&strLine);
+        break;
+      default:
+        cerr << "Error: Bad syntax at line " << iLine << " in file " << m_strCurrentTemplateFile << "." << endl;
+        exit(1);
+    }
+  }
+
+  if( eEndBlockToken != TemplateToken::NO_TYPE )
+  {
+    // End of file reached while parsing a 'loop' or 'if' block
+    cerr << "Error : Unexpected end of template file (" << m_strCurrentTemplateFile << ")." << endl;
+    exit(1);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// TemplateFileParsor::ParseExpression
+//-----------------------------------------------------------------------------
+ExpressionPtr TemplateFileParsor::ParseExpression(const String &_strExpr)
+{
+  // Very basic math expression parsor:
+  // - can only parse expression like 'a + b - c * d / e' without parenthesis
+  // - spaces characters must enclose operators
+  ExpressionPtr ptrExpression = new Expression();
+
+  String strExpr = _strExpr;
+  Expression::Operation opPrevious = Expression::CharToOp('N');
+  uint uiStartSearch = 0;
+  while( !strExpr.empty() )
+  {
+    int iOpPos = strExpr.find_first_of("+-/*", uiStartSearch);
+
+    if( string::npos != iOpPos )
+    {
+      String strMatching = strExpr.substr(iOpPos-1,3);
+      // Operator must be enclosed by spaces characters
+      if( strMatching.Match(" * ") )
+      { 
+        char cOp = strExpr[iOpPos];
+        String strToken;
+        // Extract first operand
+        strExpr.ExtractToken(cOp, &strToken);
+        strToken.Trim();
+        ptrExpression->AddFragment(new Expression::Fragment(new Expression::Constant(strToken), opPrevious));
+        opPrevious = Expression::CharToOp(cOp);
+      }
+      else
+      { // Look forward
+        uiStartSearch = iOpPos + 1;
+      }
+    }
+    else
+    {
+      strExpr.Trim();
+      ptrExpression->AddFragment(new Expression::Fragment(new Expression::Constant(strExpr), opPrevious));
+      break;
+    }
+  }
+  return ptrExpression;
+}
diff --git a/contrib/applications/NXextract/src/templateparsor.h b/contrib/applications/NXextract/src/templateparsor.h
new file mode 100644
index 0000000..087a0af
--- /dev/null
+++ b/contrib/applications/NXextract/src/templateparsor.h
@@ -0,0 +1,96 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+//
+// Creation : 20/07/2005
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __TEMPLATEFILEPARSOR_H__
+#define __TEMPLATEFILEPARSOR_H__
+
+
+//-----------------------------------------------------------------------------
+// Referencable String
+//
+//-----------------------------------------------------------------------------
+class RefString:public String, MReferencable {};
+
+//-----------------------------------------------------------------------------
+// class TemplateLine
+//
+//-----------------------------------------------------------------------------
+class TemplateLine
+{
+public:
+  int iLine;
+  RefString refFileName;
+  String strLine;
+};
+
+//-----------------------------------------------------------------------------
+// Class TemplateFileParsor
+//
+//-----------------------------------------------------------------------------
+class TemplateFileParsor
+{
+private:
+  VecToken           &m_vecToken;       // Tokenized template file
+  bool                m_bSilentMode;    // If true disable warnings
+  IVariableEvaluator *m_pVarEval;       // Variable evaluator
+  bool                m_bHeaderParsed;  // 'true' if header was parsed
+  FileName            m_fnMainTemplate; // Main template file
+  String              m_strCurrentTemplateFile;
+
+  void SuppressComments(String *pstrLine);
+  bool IsLoopToken(const TemplateToken &aToken);
+
+  // Get type id according to specified print format spec
+  DataBuf::Type GetTypeFromFormat(char cType, char cMod);
+
+  // Parsing
+  TemplateToken::Type GetLineToken(String &strLine);
+  void Tokenize(ifstream &fs, int &iLine, TemplateToken::Type eBlockType=TemplateToken::NO_TYPE);
+  bool BuildDataFragments(TemplateToken *pToken, const String &strData);
+  void ParsePrintData(String *pstrLine, int iLine);
+  void ParseBinary(String *pstrLine, int iLine);
+  void ParseOutput(String *pstrLine, int iLine, bool bBinary);
+  void ParseSet(String *pstrLine, int iLine);
+  int  ParseLoop(String *pstrLine, int iLine);
+  int  ParseIf(String *pstrLine, int iLine);
+  int  ParseIfExists(String *pstrLine, int iLine);
+  int  ParseIfCond(String *pstrLine, int iLine);
+  int  ParseBlockStart(String *pstrLine);
+  int  ParsePadding(String *pstrLine, int iLine);
+  void ParseEndBlock(TemplateToken::Type eExpectedType, 
+                     TemplateToken::Type eTokenType,
+                     int iLine);
+  void ParsePreprocessorInclude(String *pstrLine);
+
+public:
+  // @param pstrVar Variable to evaluate
+  // @return true if evaluation is done, or false
+  TemplateFileParsor(VecToken *pvecToken);
+
+  // Set silent mode
+  void SetSilent(bool bSilent=true) { m_bSilentMode = bSilent; }
+
+  // Parsing and script executing
+  void Parse(const string &strTemplateName, IVariableEvaluator *pVarEval);
+  void Parse(const string &strTemplateName);
+  void ReadHeader(const string &strTemplateName, String *pstrParams);
+
+
+  static ExpressionPtr ParseExpression(const String &strExpr);
+};
+
+#endif
diff --git a/contrib/applications/NXextract/src/variant.cpp b/contrib/applications/NXextract/src/variant.cpp
new file mode 100755
index 0000000..4a05e83
--- /dev/null
+++ b/contrib/applications/NXextract/src/variant.cpp
@@ -0,0 +1,526 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// Creation : 26/11/2009
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#include "base.h"
+#include "date.h"
+#include "membuf.h"
+#include "variant.h"
+
+using namespace soleil;
+//------------------------------------------------------------------------
+// Variant::Variant
+//------------------------------------------------------------------------
+Variant::Variant()
+{
+  m_eType = NONE;
+}
+Variant::Variant(const Variant &v)
+{
+  m_mbValue = v.m_mbValue;
+  m_eType = v.m_eType;
+}
+Variant::Variant(const char *pcsz)
+{
+  m_mbValue << pcsz;
+  m_eType = Variant::STRING;
+}
+Variant::Variant(char c)
+{
+  m_mbValue << c;
+  m_eType = Variant::CHAR;
+}
+Variant::Variant(uint8 uc)
+{
+  m_mbValue << uc;
+  m_eType = Variant::UINT8;
+}
+Variant::Variant(short s)
+{
+  m_mbValue << s;
+  m_eType = Variant::INT16;
+}
+Variant::Variant(ushort us)
+{
+  m_mbValue << us;
+  m_eType = Variant::UINT16;
+}
+Variant::Variant(int i)
+{
+  switch( sizeof(int) )
+  {
+  case 4:
+    m_mbValue << (long)i;
+    m_eType = Variant::INT32;
+    break;
+  case 8:
+    m_mbValue << (int64)i;
+    m_eType = Variant::INT64;
+    break;
+  }
+}
+Variant::Variant(uint i)
+{
+  switch( sizeof(uint) )
+  {
+  case 4:
+    m_mbValue << (ulong)i;
+    m_eType = Variant::UINT32;
+    break;
+  case 8:
+    m_mbValue << (int64)i;
+    m_eType = Variant::INT64;
+    break;
+  }
+}
+Variant::Variant(long l)
+{
+  m_mbValue << l;
+  m_eType = Variant::INT32;
+}
+Variant::Variant(ulong ul)
+{
+  m_mbValue << ul;
+  m_eType = Variant::UINT32;
+}
+Variant::Variant(int64 i64)
+{
+  m_mbValue << i64;
+  m_eType = Variant::INT64;
+}
+Variant::Variant(float f)
+{
+  m_mbValue << f;
+  m_eType = Variant::FLOAT32;
+}
+Variant::Variant(double d)
+{
+  m_mbValue << d;
+  m_eType = Variant::FLOAT64;
+}
+Variant::Variant(const string &str)
+{
+  m_mbValue << str;
+  m_eType = Variant::STRING;
+}
+Variant::Variant(const Date &dt)
+{
+  m_mbValue << dt.RawValue();
+  m_eType = Variant::DATE;
+}
+
+//------------------------------------------------------------------------
+// Variant::operator=
+//------------------------------------------------------------------------
+Variant &Variant::operator=(const Variant &v)
+{
+  m_mbValue = v.m_mbValue;
+  m_eType = v.m_eType;
+  return *this;
+}
+Variant &Variant::operator=(const char *pcsz)
+{
+  m_mbValue.Empty();
+  m_mbValue << pcsz;
+  m_eType = Variant::STRING;
+  return *this;
+}
+Variant &Variant::operator=(char c)
+{
+  m_mbValue.Empty();
+  m_mbValue << c;
+  m_eType = Variant::CHAR;
+  return *this;
+}
+Variant &Variant::operator=(uint8 uc)
+{
+  m_mbValue.Empty();
+  m_mbValue << uc;
+  m_eType = Variant::UINT8;
+  return *this;
+}
+Variant &Variant::operator=(short s)
+{
+  m_mbValue.Empty();
+  m_mbValue << s;
+  m_eType = Variant::INT16;
+  return *this;
+}
+Variant &Variant::operator=(ushort us)
+{
+  m_mbValue.Empty();
+  m_mbValue << us;
+  m_eType = Variant::UINT16;
+  return *this;
+}
+Variant &Variant::operator=(int i)
+{
+  m_mbValue.Empty();
+  switch( sizeof(int) )
+  {
+  case 4:
+    m_mbValue << (long)i;
+    m_eType = Variant::INT32;
+    break;
+  case 8:
+    m_mbValue << (int64)i;
+    m_eType = Variant::INT64;
+    break;
+  }
+  return *this;
+}
+Variant &Variant::operator=(uint i)
+{
+  m_mbValue.Empty();
+  switch( sizeof(uint) )
+  {
+  case 4:
+    m_mbValue << (ulong)i;
+    m_eType = Variant::UINT32;
+    break;
+  case 8:
+    m_mbValue << (int64)i;
+    m_eType = Variant::INT64;
+    break;
+  }
+  return *this;
+}
+Variant &Variant::operator=(long l)
+{
+  m_mbValue.Empty();
+  m_mbValue << l;
+  m_eType = Variant::INT32;
+  return *this;
+}
+Variant &Variant::operator=(ulong ul)
+{
+  m_mbValue.Empty();
+  m_mbValue << ul;
+  m_eType = Variant::UINT32;
+  return *this;
+}
+Variant &Variant::operator=(int64 i64)
+{
+  m_mbValue.Empty();
+  m_mbValue << i64;
+  m_eType = Variant::INT64;
+  return *this;
+}
+Variant &Variant::operator=(float f)
+{
+  m_mbValue.Empty();
+  m_mbValue << f;
+  m_eType = Variant::FLOAT32;
+  return *this;
+}
+Variant &Variant::operator=(double d)
+{
+  m_mbValue.Empty();
+  m_mbValue << d;
+  m_eType = Variant::FLOAT64;
+  return *this;
+}
+Variant &Variant::operator=(const string &str)
+{
+  m_mbValue.Empty();
+  m_mbValue << str;
+  m_eType = Variant::STRING;
+  return *this;
+}
+Variant &Variant::operator=(const Date &dt)
+{
+  m_mbValue.Empty();
+  m_mbValue << dt.RawValue();
+  m_eType = Variant::DATE;
+  return *this;
+}
+
+//------------------------------------------------------------------------
+// Variant::operator char()
+//------------------------------------------------------------------------
+Variant::operator char() const
+{
+  if( CHAR == m_eType )
+    return *(char *)(m_mbValue.Buf());
+  else
+    throw BadCast("Cannot convert value to 'char'", "Bad cast", "Variant::operator char");
+}
+
+//------------------------------------------------------------------------
+// Variant::operator uchar()
+//------------------------------------------------------------------------
+Variant::operator uchar() const
+{
+  if( UINT8 == m_eType )
+    return *(uchar *)(m_mbValue.Buf());
+  else
+    throw BadCast("Cannot convert value to 'unsigned char'", "Bad cast", "Variant::operator char");
+}
+
+//------------------------------------------------------------------------
+// Variant::operator short()
+//------------------------------------------------------------------------
+Variant::operator short() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return short(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return short(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+    case UINT16:
+      return *(short *)(m_mbValue.Buf());
+    default:
+      throw BadCast("Cannot convert value to 'short'", "Bad cast", "Variant::operator short");
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator ushort()
+//------------------------------------------------------------------------
+Variant::operator ushort() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return ushort(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return ushort(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+    case UINT16:
+      return *(ushort *)(m_mbValue.Buf());
+    default:
+      throw BadCast("Cannot convert value to 'unsigned short'", "Bad cast", "Variant::operator short");
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator int()
+//------------------------------------------------------------------------
+Variant::operator int() const
+{
+  switch( sizeof(int) )
+  {
+    case 4:
+      switch( m_eType )
+      {
+        case CHAR:
+          return int(*(char *)(m_mbValue.Buf()));
+        case UINT8:
+          return int(*(uint8 *)(m_mbValue.Buf()));
+        case INT16:
+          return int(*(short *)(m_mbValue.Buf()));
+        case UINT16:
+          return int(*(ushort *)(m_mbValue.Buf()));
+        case INT32:
+        case UINT32:
+          return *(int *)(m_mbValue.Buf());
+        default:
+          throw BadCast("Cannot convert value to 'int'", "Bad cast", "Variant::operator int");
+      }
+    case 8:
+      switch( m_eType )
+      {
+        case CHAR:
+          return int(*(char *)(m_mbValue.Buf()));
+        case UINT8:
+          return int(*(uint8 *)(m_mbValue.Buf()));
+        case INT16:
+          return int(*(short *)(m_mbValue.Buf()));
+        case UINT16:
+          return int(*(ushort *)(m_mbValue.Buf()));
+        case INT32:
+          return int(*(long *)(m_mbValue.Buf()));
+        case UINT32:
+          return int(*(ulong *)(m_mbValue.Buf()));
+        case INT64:
+          return *(int *)(m_mbValue.Buf());
+        default:
+          throw BadCast("Cannot convert value to 'int'", "Bad cast", "Variant::operator int");
+      }
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator int64()
+//------------------------------------------------------------------------
+Variant::operator int64() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return int64(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return int64(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+      return int64(*(short *)(m_mbValue.Buf()));
+    case UINT16:
+      return int64(*(ushort *)(m_mbValue.Buf()));
+    case INT32:
+      return int64(*(long *)(m_mbValue.Buf()));
+    case UINT32:
+      return int64(*(ulong *)(m_mbValue.Buf()));
+    case INT64:
+      return *(int64 *)(m_mbValue.Buf());
+    case DATE:
+      return *(int64 *)(m_mbValue.Buf());
+    default:
+      throw BadCast("Cannot convert value to 'int64'", "Bad cast", "Variant::operator int64");
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator long()
+//------------------------------------------------------------------------
+Variant::operator long() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return long(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return long(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+      return long(*(short *)(m_mbValue.Buf()));
+    case UINT16:
+      return long(*(ushort *)(m_mbValue.Buf()));
+    case INT32:
+    case UINT32:
+      return *(long *)(m_mbValue.Buf());
+    default:
+      throw BadCast("Cannot convert value to 'long'", "Bad cast", "Variant::operator long");
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator ulong()
+//------------------------------------------------------------------------
+Variant::operator ulong() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return ulong(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return ulong(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+      return ulong(*(short *)(m_mbValue.Buf()));
+    case UINT16:
+      return ulong(*(ushort *)(m_mbValue.Buf()));
+    case INT32:
+    case UINT32:
+      return *(ulong *)(m_mbValue.Buf());
+    default:
+      throw BadCast("Cannot convert value to 'long'", "Bad cast", "Variant::operator long");
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator float()
+//------------------------------------------------------------------------
+Variant::operator float() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return float(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return float(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+      return float(*(short *)(m_mbValue.Buf()));
+    case UINT16:
+      return float(*(ushort *)(m_mbValue.Buf()));
+    case INT32:
+      return float(*(long *)(m_mbValue.Buf()));
+    case UINT32:
+      return float(*(ulong *)(m_mbValue.Buf()));
+    case INT64:
+      return float(*(int64 *)(m_mbValue.Buf()));
+    case FLOAT32:
+      return *(float *)(m_mbValue.Buf());
+    case FLOAT64:
+      return double(*(float *)(m_mbValue.Buf()));
+    default:
+      throw BadCast("Cannot convert value to 'float'", "Bad cast", "Variant::operator float");
+  }
+}
+
+//------------------------------------------------------------------------
+// Variant::operator double()
+//------------------------------------------------------------------------
+Variant::operator double() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return double(*(char *)(m_mbValue.Buf()));
+    case UINT8:
+      return double(*(uint8 *)(m_mbValue.Buf()));
+    case INT16:
+      return double(*(short *)(m_mbValue.Buf()));
+    case UINT16:
+      return double(*(ushort *)(m_mbValue.Buf()));
+    case INT32:
+      return double(*(long *)(m_mbValue.Buf()));
+    case UINT32:
+      return double(*(ulong *)(m_mbValue.Buf()));
+    case INT64:
+      return double(*(int64 *)(m_mbValue.Buf()));
+    case FLOAT32:
+      return double(*(float *)(m_mbValue.Buf()));
+    case FLOAT64:
+      return *(double *)(m_mbValue.Buf());
+    default:
+      throw BadCast("Cannot convert value to 'long'", "Bad cast", "Variant::operator long");
+  }
+}
+//------------------------------------------------------------------------
+// Variant::operator String()
+//------------------------------------------------------------------------
+Variant::operator String() const
+{
+  switch( m_eType )
+  {
+    case CHAR:
+      return StrFormat("%c", *(char *)m_mbValue.Buf());
+    case UINT8:
+      return StrFormat("%ud", uint(*(char *)(m_mbValue.Buf())));
+    case INT16:
+      return StrFormat("%hd", *(short *)(m_mbValue.Buf()));
+    case UINT16:
+      return StrFormat("%uhd", *(ushort *)(m_mbValue.Buf()));
+    case INT32:
+      return StrFormat("%ld", *(long *)(m_mbValue.Buf()));
+    case UINT32:
+      return StrFormat("%uld", *(ulong *)(m_mbValue.Buf()));
+    case INT64:
+      return StrFormat("%uld", *(int64 *)(m_mbValue.Buf()));
+    case FLOAT32:
+      return StrFormat("%g", *(float *)(m_mbValue.Buf()));
+    case FLOAT64:
+      return StrFormat("%g", *(double *)(m_mbValue.Buf()));
+    case STRING:
+      return StrFormat("%s", m_mbValue.Buf());
+    case DATE:
+      {
+        Date dt;
+        dt.SetRawValue(*(int64 *)(m_mbValue.Buf()));
+        return StrFormat("%s", PSZ(dt.ToISO8601()));
+      }
+    default:
+      throw BadCast("Cannot convert value to 'long'", "Bad cast", "Variant::operator long");
+  }
+}
diff --git a/contrib/applications/NXextract/src/variant.h b/contrib/applications/NXextract/src/variant.h
new file mode 100755
index 0000000..c184b13
--- /dev/null
+++ b/contrib/applications/NXextract/src/variant.h
@@ -0,0 +1,143 @@
+//*****************************************************************************
+// Synchrotron SOLEIL
+//
+// 'Variant' class
+//
+// Creation : 26/11/2009
+// Author   : Stephane Poirier
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; version 2 of the License.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+//
+//*****************************************************************************
+
+#ifndef __VARIANT_H__
+#define __VARIANT_H__
+
+#ifndef __BASE_H__
+  #include "base.h"
+#endif
+
+namespace gdshare
+{
+//=============================================================================
+/// Handling various types in a single class
+//=============================================================================
+class Variant
+{
+public:
+  /// Value type
+  enum EType
+  {
+    NONE = 0, CHAR, UINT8, INT16, INT32, INT64, UINT16, UINT32, FLOAT32, FLOAT64, STRING, DATE
+  };
+
+  /// Bad cast Exception
+  class BadCast: public Exception
+  {
+  protected:
+    const char *ErrorTitle() { return "Bad cast: "; }
+  public:
+    BadCast(const char *pcszError=NULL, const char *pcszReason=NULL, const char *pcszMethod=NULL):
+    Exception(pcszError, pcszReason, pcszMethod) { }
+  };
+
+private:
+  MemBuf m_mbValue;
+  EType  m_eType;
+
+public:
+  EType Type() const { return m_eType; }
+
+  Variant();
+  Variant(const Variant &v);
+  Variant(char c);
+  Variant(uchar uc);
+  Variant(short s);
+  Variant(ushort us);
+  Variant(long l);
+  Variant(ulong ul);
+  Variant(int i);
+  Variant(uint ui);
+  Variant(int64 i64);
+  Variant(float f);
+  Variant(double d);
+  Variant(const string &str);
+  Variant(const char *pcsz);
+  Variant(const Date &dt);
+
+  Variant &operator=(char c);
+  Variant &operator=(uchar uc);
+  Variant &operator=(short s);
+  Variant &operator=(ushort us);
+  Variant &operator=(long l);
+  Variant &operator=(ulong l);
+  Variant &operator=(int i);
+  Variant &operator=(uint ui);
+  Variant &operator=(int64 i64);
+  Variant &operator=(float f);
+  Variant &operator=(double d);
+  Variant &operator=(const char *pcsz);
+  Variant &operator=(const string &str);
+  Variant &operator=(const Date &dt);
+  Variant &operator=(const Variant &v);
+
+  //@{ Comparison operator: YET to be implmented
+  Variant &operator==(char c) const;
+  Variant &operator==(uchar uc) const;
+  Variant &operator==(short s) const;
+  Variant &operator==(ushort us) const;
+  Variant &operator==(long l) const;
+  Variant &operator==(ulong l) const;
+  Variant &operator==(int i) const;
+  Variant &operator==(uint ui) const;
+  Variant &operator==(int64 i64) const;
+  Variant &operator==(float f) const;
+  Variant &operator==(double d) const;
+  Variant &operator==(const char *pcsz) const;
+  Variant &operator==(const string &str) const;
+  Variant &operator==(const Date &dt) const;
+  Variant &operator==(const Variant &v) const;
+
+  //@{ Implicite conversions
+  operator char() const;
+  operator uchar() const;
+  operator short() const;
+  operator ushort() const;
+  operator int() const;
+  operator int64() const;
+  operator long() const;
+  operator ulong() const;
+  operator float() const;
+  operator double() const;
+  operator String() const;
+  operator Date() const;
+  //@}
+
+  //@{ Explicite conversions: YET to be implmented
+  char   ToChar() const;
+  uint8  ToUInt8() const;
+  short  ToShort() const;
+  ushort ToUShort() const;
+  long   ToLong() const;
+  ulong  ToULong() const;
+  int    ToInt() const;
+  int64  ToInt64() const;
+  float  ToFloat() const;
+  double ToDouble() const;
+  String ToString() const;
+  Date   ToDate() const;
+  //@}
+};
+
+/// Reference pointer to variant
+typedef RefPtr<Variant> VariantPtr;
+
+} // namespace soleil
+
+#endif
\ No newline at end of file
diff --git a/contrib/applications/NXformat_dfn/NXconvert.py b/contrib/applications/NXformat_dfn/NXconvert.py
new file mode 100755
index 0000000..5292e44
--- /dev/null
+++ b/contrib/applications/NXformat_dfn/NXconvert.py
@@ -0,0 +1,191 @@
+#!env python
+
+"""
+Form to convert NeXus XML definition files into formatted HTML
+R. Osborn 2002/4/6
+"""
+
+import cgitb; cgitb.enable()
+import cgi, os, re
+from StringIO import *
+from urllib import *
+from xml.dom.minidom import *
+
+rootURL = "http://127.0.0.1/nexus/"
+XMLdir = rootURL+"xml"
+homeLink = '<a href="'+rootURL+'">NeXus Home Page</a>'
+glossaryLink = '<a href="'+rootURL+'NeXus_contents.html#Glossary">NeXus Glossary</a>'
+instrumentLink = '<a href="'+rootURL+'NeXus_instruments.html">NeXus Instruments</a>'
+metaLink = '<a href="'+rootURL+'NeXus_metaformat.html">NeXus Meta-DTD Format</a>'
+reComment = re.compile(r"\<\!--([\s\S]*)--\>")
+
+def FormatStartTag(node):
+    "Write element name and attributes as a start tag"
+    buffer = StringIO()
+    try:
+        node.tagName.index("NX")
+        class_ = "group"
+    except ValueError:
+        class_ = "data"
+    buffer.write('<span class="%s"><b>' % class_)
+    buffer.write(cgi.escape('<'))
+    try:
+        node.tagName.index("NX")
+        buffer.write('<a href="/cgi-bin/NXconvert.py?file='+node.tagName+'.xml">')
+        buffer.write(node.tagName)
+        buffer.write('</a>')
+    except ValueError:
+        buffer.write(node.tagName)
+    if node.hasAttributes(): 
+        buffer.write('</b></span>')
+        buffer.write(FormatAttributes(node))
+        buffer.write('<span class="%s"><b>' % class_)
+    buffer.write(cgi.escape('>'))
+    buffer.write('</b></span>\n')
+    return buffer.getvalue()
+
+def FormatEndTag(node):
+    "Write element name as an end tag"
+    buffer = StringIO()
+    try:
+        node.tagName.index("NX")
+        class_ = "group"
+    except ValueError:
+        class_ = "data"
+    buffer.write('<span class="%s"><b>' % class_)
+    buffer.write(cgi.escape('</'+node.tagName+'>'))
+    buffer.write('</b></span>\n')
+    return buffer.getvalue()
+
+def FormatAttributes(node):
+    "Write element attributes"
+    buffer = StringIO()
+    buffer.write('<span class="attribute">')
+    keys = node.attributes.keys()
+    for key in keys:
+        buffer.write(' '+key+'="<span class="attributevalue">')
+        buffer.write(node.attributes[key].value)
+        buffer.write('</span>"')
+    buffer.write('</span>')
+    return buffer.getvalue()
+
+def FormatXMLTag():
+    "Write XML definition tag"
+    buffer = StringIO()
+    buffer.write('<span class="comment">')
+    buffer.write(cgi.escape('<?xml version="1.0" ?>'))
+    buffer.write('</span>\n')
+    return buffer.getvalue()
+
+def HTMLelement(node, indent="", 
+                addindent="        "):
+    "Write HTML formatting for each type of node"
+    buffer = StringIO()
+    if node.nodeType == node.DOCUMENT_NODE:
+        for childNode in node.childNodes:
+            buffer.write(HTMLelement(childNode,indent,addindent))
+    elif node.nodeType == node.ELEMENT_NODE:
+        buffer.write('<br \>'+indent+FormatStartTag(node))
+        for childNode in node.childNodes:
+            buffer.write(HTMLelement(childNode,indent+addindent,addindent))
+        if len(node.childNodes)>1: buffer.write('<br>'+indent)
+        buffer.write(FormatEndTag(node))
+    elif node.nodeType == node.TEXT_NODE:
+        text = node.data.strip()
+        if len(text)>0:
+            buffer.write('<font color="#990099">')
+            buffer.write(text)
+            buffer.write('</font>\n')
+    return buffer.getvalue()
+
+def HTMLhead(title):
+    "Return string for head of HTML page"
+    buffer = StringIO()
+    buffer.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\n')
+    buffer.write('"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n')
+    buffer.write('<html xmlns="http://www.w3.org/1999/xhtml">\n')
+    buffer.write('<head>\n')
+    buffer.write('<title>'+title+'</title>\n')
+    buffer.write('<style type="text/css">\n')
+    buffer.write('/* <![CDATA[ */\n')
+    buffer.write('.xmltag {color: #999999}\n')
+    buffer.write('.comment {color: #000066}\n')
+    buffer.write('.group {color: #FF0000}\n')
+    buffer.write('.data {color: #000099}\n')
+    buffer.write('.datavalue {color: #FF00FF}\n')
+    buffer.write('.attribute {color: #660033}\n')
+    buffer.write('.attributevalue {color: #339900}\n')
+    buffer.write('/* ]]> */\n')
+    buffer.write('</style>\n')
+    buffer.write('</head>\n')
+    buffer.write('<body>\n')
+    buffer.write('<p align="center">')
+    buffer.write('<a href="../nexus/"><img align=top src="../nexus/nexus.gif" border=0 width=597 height=90></a>\n')
+    buffer.write('</p>\n')
+    buffer.write('<h1>'+title+'</h1>\n')
+    buffer.write('<hr \>\n')
+    buffer.write(FormatXMLTag())
+    return buffer.getvalue()
+        
+def HTMLcomments(text):
+    "Return string for foot of HTML page"
+    buffer = StringIO()
+    commentSearch = reComment.search(text)
+    if commentSearch:
+        comment = cgi.escape(commentSearch.group())
+        buffer.write('<span class="comment">')
+        buffer.write('<br>'+comment.replace('\n','<br \>'))
+        buffer.write('</span>\n')
+        return buffer.getvalue()
+    else:
+        pass
+
+def HTMLfile(file_name):
+    "Return string for foot of HTML page"
+    buffer = StringIO()
+    buffer.write('<hr \>\n')
+    buffer.write('<p class="center">\n')
+    buffer.write('[<a href="http://www.neutron.anl.gov/nexus/xml/'+file_name+'">')
+    buffer.write('Download '+file_name+'</a>]\n')
+    buffer.write('</p>\n')
+    return buffer.getvalue()
+
+def HTMLfoot(links):
+    "Return string for foot of HTML page"
+    buffer = StringIO()
+    buffer.write('<hr \>\n')
+    buffer.write('<p align="center">\n')
+    buffer.write('['+' | '.join(links)+']\n')
+    buffer.write('</p>\n')
+    buffer.write('</body>\n')
+    buffer.write('</html>\n')
+    return buffer.getvalue()
+
+def ConvertToHTML(text):
+    "Convert XML text into formatted HTML"
+    doc = parseString(text)
+    return HTMLelement(doc)
+
+def main():
+    "Output XML file as formatted HTML"
+    try:
+        form = cgi.FieldStorage()
+        print 'Content-type: text/html'
+        print
+        if form.has_key("file"):
+            file_name = form["file"].value
+            file = urlopen(os.path.join(XMLdir,file_name))
+            text = file.read()
+            file.close()
+            print HTMLhead(file_name)
+            print HTMLcomments(text)
+            doc = parseString(text)
+            doc.normalize()
+            print HTMLelement(doc)
+            print HTMLfile(file_name)
+            print HTMLfoot([homeLink,glossaryLink,instrumentLink,metaLink])
+    except:
+        cgi.print_exception()
+
+main()
+
diff --git a/contrib/applications/NXformat_dfn/NXformat_dfn.py b/contrib/applications/NXformat_dfn/NXformat_dfn.py
new file mode 100755
index 0000000..e678810
--- /dev/null
+++ b/contrib/applications/NXformat_dfn/NXformat_dfn.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python
+
+import format_docbook
+import format_xml
+import StringIO
+from xml.dom.minidom import parse
+
+def copy_dictionary(orig):
+    copy={}
+    for key in orig.keys():
+        copy[key]=orig[key]
+    return copy
+
+def get_path(file):
+    """Determine the directory name that a file exists in (if specified)"""
+
+    # default value for end
+    end=0
+    
+    # try linux path separator
+    try:
+        end=file.rindex("/")
+    except ValueError:
+        pass # let it drop on the floor
+    if(end): return file[:end]+"/"
+
+    # try windows path separator
+    try:
+        end=file.rindex("\\")
+    except ValueError:
+        pass # let it drop on the floor
+    if(end): return file[:end]+"\\"
+
+    # the path must not have been specified
+    return ""
+
+def get_root_name(file):
+    """Determine the root of the filename assuming that it either ends
+    with '.xml' or is already a root"""
+
+    # determine the path and strip it off
+    begin=get_path(file).__len__()
+
+    # determine where the result ends
+    ext=".xml"
+    end=file.__len__()
+    try:
+        end=file.rindex(ext)
+    except ValueError:
+        pass # let it drop on the floor
+
+    # return the result
+    return file[begin:end]
+
+def print_usage(command,level=0):
+    print "USAGE:",command,"[options] <definition file>"
+    print "      where <definition file> is the name of file to format"
+    if(level<1): # done after simple usage statement
+        return
+    print ""
+    print "This will format the file using the \"XML\" formatter unless specified."
+
+    print ""
+    print "GENERAL:"
+    print " -d|--debug  Increase debug level."
+    print " --docbook   Use the docbook formatter."
+    print " --format    Specify the formatter to use. The options are \"xml\""
+    print "             and \"docbook\". \"xml\" is the default."
+    print " -h|--help   Print this help information."
+    print " -o          Name of output file. If not specified uses STDOUT."
+    print " --root      Specify the name of the definition."
+    print " --xml       Use the xml formatter."
+
+    print ""
+    print "For XML formatter: (default extension is \"%s\")" \
+          % format_xml.get_def_ext()
+    print format_xml.get_command_line_doc()
+
+    print ""
+    print "For DOCBOOK formatter: (default extension is \"%s\")" \
+          % format_docbook.get_def_ext()
+    print format_docbook.get_command_line_doc()
+
+def process_file(infile, outfile, options, DEBUG=1, append=False):
+    # parse the xml file
+    if DEBUG: print "Processing \"%s\"" % infile
+    try:
+        doc=parse(infile)
+    except Exception, error:
+        print "ERROR:",error.__str__()
+        raise error
+    if DEBUG: print "          ... done"
+
+    # determine the path
+    path=get_path(infile)
+
+    # determine the input name
+    try:
+        root_name=options.pop("--root")
+    except KeyError:
+        root_name=get_root_name(infile)
+
+    # determine the proper formatter
+    try:
+        format_option=options.pop("--format")
+    except KeyError:
+        format_option="xml"
+    format_option=format_option.upper()
+
+    # if output file name not supplied create the default one
+    if not outfile:
+        ext=""
+        if(format_option=="XML"):
+            ext=format_xml.get_def_ext()
+        elif(format_option=="DOCBOOK"):
+            ext=format_docbook.get_def_ext()
+        outfile="%s%s.%s" % (path,root_name,ext)
+
+    # open the output file or create the buffer to write to
+    if DEBUG: print "Writing result to \"%s\"" % outfile
+    if DEBUG<=0:
+        if(append):
+            buffer=open(outfile,"a")
+        else:
+            buffer=open(outfile,"w")
+    else:
+        buffer=StringIO.StringIO()
+
+    # if appending then add a newline to the end of the file
+    if(append): buffer.write("\n")
+
+    # get the appropriate formatter
+    if DEBUG: print "Creating %s formatter" % format_option
+    if format_option=="XML":
+        formatter=format_xml.format_xml(root_name,options)
+    elif format_option=="DOCBOOK":
+        formatter=format_docbook.format_docbook(root_name,options)
+    else:
+        raise KeyError("no formatter named \"%s\"" % format_option)
+    if DEBUG: print "          ... done"
+
+    # format the DOM directly to the file buffer
+    if DEBUG: print "Formatting information"
+    formatter.format(doc,buffer)
+    if DEBUG: print "          ... done"
+
+    # if we are actually writting to STDOUT then print there now
+    if DEBUG:
+        string=buffer.getvalue()
+        if(string):
+            print string,
+        else:
+            print "EMPTY RESULT"
+
+def main(infile, outfile, options, DEBUG=1):
+    # deal with processing a single file
+    if not infile.__class__==[].__class__:
+        process_file(infile,outfile,options,DEBUG)
+        return
+
+    # confirm that we are working without an output file name
+    append=False
+    first=True
+    if outfile:
+        append=True
+    else:
+        outfile=""
+
+    # deal with no output file specified
+    for file in infile:
+        options_copy=copy_dictionary(options)
+        if first:
+            process_file(file,outfile,options_copy,DEBUG)
+            first=False
+        else:
+            process_file(file,outfile,options_copy,DEBUG,append)
+            
+
+if __name__ == "__main__":
+    # sys module only needed for command line operation
+    import sys
+
+    # remove the program name from the command line arguments
+    progname=sys.argv[0]
+    sys.argv.remove(progname)
+
+    # confirm that there are enough arguments to even bother
+    if sys.argv.__len__()<1:
+        print_usage(progname)
+        sys.exit(-1)
+
+    # parse the command line options
+    options={}
+    debug=0
+    infile=[]
+    outfile=""
+    while sys.argv.__len__()>0:
+        key=sys.argv[0]
+        sys.argv=sys.argv[1:]
+        if key.startswith("-"):
+            if key=="--help" or key=="-h": # print help
+                print_usage(progname,100)
+                sys.exit(0)
+            elif key=="--debug" or key=="-d": # increase debug level
+                debug=debug+1
+            elif key=="--docbook": # use the docbook formatter
+                options["--format"]="docbook"
+            elif key=="--xml": # use the xml formatter
+                options["--format"]="xml"
+            else:
+                # get key and value
+                try:
+                    index=key.index("=")
+                    value=key[index+1:]
+                    key=key[:index]
+                except ValueError:
+                    value=sys.argv[0]
+                    sys.argv=sys.argv[1:]
+                # check for special keys
+                if key=="-o": # output file selected
+                    outfile=value
+                else: # everything else goes into the options slop bucket
+                    options[key]=value
+        else:
+            infile.append(key)
+
+    if infile.__len__()==1:
+        infile=infile[0]
+
+    # pass the command line options to main
+    try:
+        main(infile,outfile,options,debug)
+    except Exception:
+        sys.exit(-1)
diff --git a/contrib/applications/NXformat_dfn/NXprettyprint.py b/contrib/applications/NXformat_dfn/NXprettyprint.py
new file mode 100755
index 0000000..b2c9781
--- /dev/null
+++ b/contrib/applications/NXformat_dfn/NXprettyprint.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+
+"""
+Form to convert NeXus XML definition files into a formatted HTML table
+R. Osborn 2004/02/12
+"""
+
+import sys, os, re, cgi
+from urllib import *
+from xml.dom.minidom import *
+import HTML
+
+rootURL = "http://www.nexus.anl.gov/"
+XMLurl = "http://www.nexus.anl.gov/classes/xml"
+XMLdir = "/Users/osborn/Sites/nexus/classes/xml"
+HTMLdir = "/Users/osborn/Sites/nexus/classes"
+reComment = re.compile(r"\<\!--([\s\S]*?)--\>", re.DOTALL)
+reValue = re.compile(r"([\s\S]*)[\?\*\+]")
+reShort = re.compile(r"([\s\S]*){([\s\S]*)}", re.DOTALL)
+reLong = re.compile(r"([\s\S]*){([\s\S]*)}.*{([\s\S]*)}", re.DOTALL)
+reAttribute = re.compile(r"([\s\S]*){([\s\S]*)}", re.DOTALL)
+
+def XMLhead(NXclass):
+    "Return string for head of HTML page"
+    file = open("NXheader.txt","r")
+    header = file.read()
+    file.close()
+    title = NXclass+" Class"
+    output = HTML.headblock(title, header, stylesheet="%s/nexus.css" % rootURL)
+    return "%s\n%s" % (output, str(HTML.Header(title)))
+        
+def XMLcomments(text):
+    "Return description of XML file contained in the initial comments"
+    comment = cgi.escape(reComment.search(text).groups()[0])
+    return str(HTML.Para(comment.replace('\n', '<br \>', 5)))
+
+def XMLtags(doc):
+    "Start table"
+    table = HTML.Table(["15%", "15%", "50%", "20%"], width="90%",
+                       cellspacing="0")
+    row = HTML.Row()
+    row.Add(HTML.HeaderCell("Name"))
+    row.Add(HTML.HeaderCell("Type"))
+    row.Add(HTML.HeaderCell("Description"))
+    row.Add(HTML.HeaderCell("Attributes"))
+    table.Add(row)
+    for node in doc.childNodes[1].childNodes:
+        if node.nodeType == node.ELEMENT_NODE:
+            table.Add(XMLtag(node))
+    return str(table)
+
+def XMLtag(node):
+    "Write HTML formatting for each type of node"
+    row = HTML.Row()
+    try:
+        node.tagName.index("NX")
+        row.Add(HTML.Cell(" "))
+        url = node.tagName + ".html"
+        row.Add(HTML.Cell(HTML.anchor(url, node.tagName)))
+    except ValueError:
+        row.Add(HTML.Cell(node.tagName))
+        NXtype = "NX_CHAR"
+        if node.hasAttributes():
+            if "type" in node.attributes.keys():
+                NXtype = node.attributes["type"].value
+        row.Add(HTML.Cell(NXtype))
+    if len(node.childNodes) > 0:
+        cell = HTML.Cell()
+        longSearch = reLong.search(node.childNodes[0].data)
+        shortSearch = reShort.search(node.childNodes[0].data)
+        valueSearch = reValue.search(node.childNodes[0].data)
+        if longSearch:
+            value, shortDescription, longDescription = longSearch.groups()
+            value = value.strip()
+            if value:
+                cell.Add(cgi.escape(value))
+                if shortDescription: 
+                    cell.Add(HTML.br())
+            cell.Add(cgi.escape(shortDescription.strip()))
+            if shortDescription.strip() and longDescription.strip(): 
+                cell.Add(HTML.br())
+            cell.Add(HTML.Span(cgi.escape(longDescription.strip()), 
+                               class_="small"))
+        elif shortSearch:
+            value, shortDescription = shortSearch.groups()
+            value = value.strip()
+            if value:
+                cell.Add(cgi.escape(value))
+                if shortDescription: 
+                    cell.Add(HTML.br())
+            cell.Add(cgi.escape(shortDescription.strip()))
+        elif valueSearch:
+            value, = valueSearch.groups()
+            cell.Add(value.strip())
+        row.Add(cell)
+    else:
+        row.Add(HTML.Cell(" "))
+    cell = HTML.Cell()
+    try:
+        node.tagName.index("NX")
+        cell.Add(" ")
+    except ValueError:
+        text = ""
+        for key in node.attributes.keys():
+            value = node.attributes[key].value
+            attributeSearch = reAttribute.search(value)
+            if key <> "type":
+                if text: text += HTML.br()
+                text += key
+                if attributeSearch:
+                    value, shortDescription = attributeSearch.groups()
+                    if value:
+                        text += '="%s"' % value
+                    text += "%s\n%s" % \
+                    (HTML.br(), 
+                     HTML.Span(cgi.escape(shortDescription), class_="small"))
+                else:
+                    text +='="%s"' % node.attributes[key].value
+        if text:        
+    	    cell.Add(text)
+    	else:
+    	    cell.Add(" ")
+    row.Add(cell)
+    return row
+    
+def XMLfile(fileName):
+    "Return link to the original XML file"
+    url = os.path.join(XMLurl, fileName)
+    return str(HTML.Para("%s%s%s" 
+                         % ("[", HTML.anchor(url, "Download "+fileName), "]"),
+                         class_="center"))
+
+def XMLfoot():
+    "Return string for foot of HTML page"
+    file = open("NXfooter.txt","r")
+    footer = file.read()
+    file.close()
+    return HTML.foot(footer=footer)
+
+def main():
+    "Output XML file as formatted HTML"
+    NXclass = sys.argv[1]
+    fileName = sys.argv[1] + ".xml"
+    file = open(os.path.join(XMLdir, fileName))
+    text = file.read()
+    file.close()
+    file = open(os.path.join(HTMLdir, NXclass+".html"), "w")
+    file.write(XMLhead(NXclass))
+    file.write(XMLcomments(text))
+    doc = parseString(text)
+    doc.normalize()
+    file.write(XMLtags(doc))
+    file.write(XMLfile(fileName))
+    file.write(XMLfoot())
+    file.close()
+
+if __name__ == "__main__":
+    main()
+
diff --git a/contrib/applications/NXformat_dfn/format_docbook.py b/contrib/applications/NXformat_dfn/format_docbook.py
new file mode 100644
index 0000000..6c38dfe
--- /dev/null
+++ b/contrib/applications/NXformat_dfn/format_docbook.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+from format_xml import *
+
+def get_def_ext():
+    return "docbook"
+
+class format_docbook(format_xml):
+    """Formatting object that goes through a DOM tree and puts it out
+    as a space formatted XML document surrounded by docbook tagsfor
+    easier reading in a simple text editor."""
+
+    def format_head(self):
+        """Put a header on the resulting document"""
+        result="<example id=\"%s.xml\"><title>" % self.main_name
+        result=result+"<filename>%s.xml</filename></title>\n" % self.main_name
+        result=result+"<programlisting role=\"XML\">\n"
+        result=result+"<![CDATA["
+        return result
+
+    def format_foot(self):
+        """Put a footer on the resulting document"""
+        return "]]>\n"+"</programlisting>\n"+"</example>\n"
diff --git a/contrib/applications/NXformat_dfn/format_xml.py b/contrib/applications/NXformat_dfn/format_xml.py
new file mode 100644
index 0000000..a267159
--- /dev/null
+++ b/contrib/applications/NXformat_dfn/format_xml.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+
+# default value for options
+default_width=80
+default_indent=2
+
+def trim(string):
+    """Trim leading and trailing whitespace off of the supplied string"""
+
+    # exit early if supplied an empty string
+    if not string: return ""
+
+    # default value for trimming
+    begin=0
+    end=string.__len__()-1 # index of last char is one less
+                           # than string size
+
+    # determine amount of leading whitespace
+    while string[begin].isspace() and begin<end:
+        begin=begin+1
+    # determine amount of trailing whitespace
+    while string[end].isspace() and end>begin:
+        end=end-1
+    # return shortened result
+    if begin+1>=end:
+        return ""
+    else:
+        return string[begin:end+1]
+
+def remove_extra_spaces(string):
+    """Condense all whitespace into ' '"""
+    # first remove leading and trailing space
+    temp_string=trim(string)
+
+    # set up for loop
+    is_space=False
+    result=""
+
+    # go through entire string, condensing all spaces into " "
+    for letter in temp_string:
+        if letter.isspace(): # look for a space
+            if not is_space: # turn multiple spaces into one
+                is_space=True
+                result=result+" "
+        else: # just copy the result
+            is_space=False
+            result=result+letter
+
+    # remove the shortened result
+    return result
+
+def wrap_text(string,width,continue_additional_indent=""):
+    """This will perform \"word wrapping\" of text based on
+    spaces. The default indentation level is determined from the
+    number of spaces at the start of the string"""
+
+    # confirm that there is something to wrap
+    if string.__len__()<=width:
+        return string
+    
+    # determine the current indentation level
+    indent=""
+    for char in string:
+        if char.isspace():
+            indent=indent+char
+        else:
+            break
+
+    # add the continuation indentation
+    indent=indent+continue_additional_indent
+
+    # generate an array of strings of the correct with for formatting
+    result=string
+    str_array=[]
+    while result.__len__()>width:
+        line=result[0:width]
+        while not line[-1].isspace():
+            line=line[0:-1]
+        str_array.append(line+"\n")
+        result=indent+trim(result[line.__len__():])
+    str_array.append(result+"\n")
+            
+    # convert the string array into a single string
+    result=""
+    for str in str_array:
+        result=result+str
+
+    # return the wrapped string
+    return result
+
+def get_def_ext():
+    return "xml"
+
+def get_command_line_doc():
+    result = " --width     Specify the width the the document for wrapping. This does not \n"+ \
+             "             apply to open or close tags. The default is %d.\n" %default_width + \
+             " --indent    Specify the number of spaces for each indentation level. The \n" + \
+             "             default is %d." % default_indent
+    return result
+
+class format_xml(object):
+    """Formatting object that goes through a DOM tree and puts it out
+    as a space formatted XML document for easier reading in a simple
+    text editor."""
+    def __init__(self,main_name,options={},indent=2):
+        # variable for tracking indent level
+        self.__cur_indent=0
+
+        # option for how wide text can go before wrapping
+        try:
+            self.__width=int(options.pop("--width"))
+        except KeyError:
+            self.__width=default_width
+
+        # option for how many spaces to use for each indentation level
+        try:
+            self.__indent=int(options.pop("--indent"))
+        except KeyError:
+            self.__indent=default_indent
+
+        # name of definition being formatted
+        self.main_name=main_name
+
+    def __setattr__(self,name,value):
+        """This does not allow the user to set the value of the
+        attributes. This is an immutable object"""
+        if name=="width":
+            raise AttributeError("Cannot set value of immutable \"width\"")
+        if name=="indent":
+            raise AttributeError("Cannot set value of immutable \"indent\"")
+        if name=="cur_indent":
+            raise AttributeError("Cannot set value of immutable \"cur_indent\"")
+        self.__dict__[name]=value
+
+    # allow access to the attribute values
+    def __getattr__(self,name):
+        if name=="width":
+            return int(self.__width)
+        if name=="indent":
+            return int(self.__indent)
+        if name=="cur_indent":
+            return int(self.__cur_indent)
+        return self.__dict__[name]
+
+    def format_head(self):
+        """Put a header on the resulting document"""
+        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+
+    def format_foot(self):
+        """Put a footer on the resulting document"""
+        return ""
+
+    def format_data(self,data):
+        """Format the data for the output file"""
+        # determine the indentation
+        indent=self.__cur_indent*" "
+
+        # create the idiot version
+        result="%s%s\n" % (indent,data)
+
+        return wrap_text(result,self.__width)
+#
+#        # return the idiot version if it works
+#        if(result.__len__()<=self.__width):
+#            return result
+#
+#        # generate an array of strings of the correct with for formatting
+#        str_array=[]
+#        while result.__len__()>self.__width:
+#            line=result[0:self.__width]
+#            while not line[-1].isspace():
+#                line=line[0:-1]
+#            str_array.append(line+"\n")
+#            result=indent+trim(result[line.__len__():])
+#        str_array.append(result+"\n")
+#
+#        # convert the string array into a single string
+#        result=""
+#        for str in str_array:
+#            result=result+str
+#
+#        return result
+
+    def format_attributes(self,node):
+        """Format the node attributes for the output file"""
+        # return empty string if nothing found
+        if not node.hasAttributes():
+            return ""
+
+        # put together a string of the formatted attributes
+        string=""
+        for key in node.attributes.keys():
+            value=node.attributes[key].value
+            string=string+(" %s=\"%s\"" % (key,value))
+
+        return string
+
+    def format_node(self,file,tag,node):
+        """Format a node for the output file"""
+        # format the attributes
+        attr_string=self.format_attributes(node)
+        # create the open tag
+        file.write(wrap_text("%s<%s%s>\n" % ((" "*self.__cur_indent),tag,attr_string),self.__width,(" "*(self.__indent+2))))
+        # increase the indent level
+        self.__cur_indent=self.__cur_indent+self.__indent
+        # recurse down into the tree
+        for child in node.childNodes:
+            try:
+                child_tag=child.tagName
+                self.format_node(file,child_tag,child)
+            except AttributeError:
+                data=remove_extra_spaces(child.data)
+                if(data.__len__()):
+                    file.write(self.format_data(data))
+        # decrease the indent level
+        self.__cur_indent=self.__cur_indent-self.__indent
+        # create the close tag
+        file.write("%s</%s>\n" % ((" "*self.__cur_indent),tag))
+
+    def format_comment_section(self,file,node):
+        # get the data, if there is a problem, just return
+        full_comment=""
+        try:
+            full_comment=trim(node.data)
+        except AttributeError:
+            return
+        if not full_comment: return
+
+        # divide the data into lines
+        lines=full_comment.splitlines()
+
+        # compress the lines into header and overview
+        header=""
+        overview=""
+        is_header=True
+        for line in lines:
+            if is_header:
+                header=header+line+"\n"
+                if line.startswith("$Id"):
+                    is_header=False
+            else:
+                overview=overview+line+" "
+
+        # remove leading and trailing whitespace
+        header=trim(header)
+        overview=wrap_text(trim(overview),self.__width)
+
+        # format the result into the file
+        file.write("<!--\n%s\n\n%s-->\n" % (header,overview))
+
+    def format(self,doc,file): # take from NXconvert.HTMLelement
+        """The public method for formating a DOM"""
+        # put in the header
+        file.write(self.format_head())
+        # format the body
+        for childNode in doc.childNodes:
+            try:
+                tag=childNode.tagName
+                self.format_node(file,tag,childNode)
+            except AttributeError:
+                self.format_comment_section(file,childNode)
+        # put in the footer
+        file.write(self.format_foot())
diff --git a/contrib/applications/nxplot/NXplot/.classpath b/contrib/applications/nxplot/NXplot/.classpath
new file mode 100755
index 0000000..ad32c83
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/NXplot/.project b/contrib/applications/nxplot/NXplot/.project
new file mode 100755
index 0000000..b0e18cc
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>NXplot</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/NXplot/.settings/org.eclipse.jdt.core.prefs b/contrib/applications/nxplot/NXplot/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 0000000..a67c808
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Wed Oct 21 11:46:43 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/contrib/applications/nxplot/NXplot/META-INF/MANIFEST.MF b/contrib/applications/nxplot/NXplot/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..2c1ecb1
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: NXplot
+Bundle-SymbolicName: NXplot; singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Vendor: NeXus International Advisory Comittee
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.ui,
+ mountaingumsys;bundle-version="0.1.0",
+ mountaingumuibase;bundle-version="1.0.0",
+ mountaingumnexus;bundle-version="1.0.0",
+ org.eclipse.nebula.compositetable;bundle-version="1.0.0",
+ jnexus;bundle-version="4.2.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/contrib/applications/nxplot/NXplot/build.properties b/contrib/applications/nxplot/NXplot/build.properties
new file mode 100755
index 0000000..8923d23
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+               META-INF/,\
+               .,\
+               icons/,\
+               splash.bmp
diff --git a/contrib/applications/nxplot/NXplot/icons/alt_window_16.gif b/contrib/applications/nxplot/NXplot/icons/alt_window_16.gif
new file mode 100755
index 0000000..05626b1
Binary files /dev/null and b/contrib/applications/nxplot/NXplot/icons/alt_window_16.gif differ
diff --git a/contrib/applications/nxplot/NXplot/icons/alt_window_32.gif b/contrib/applications/nxplot/NXplot/icons/alt_window_32.gif
new file mode 100755
index 0000000..b432f88
Binary files /dev/null and b/contrib/applications/nxplot/NXplot/icons/alt_window_32.gif differ
diff --git a/contrib/applications/nxplot/NXplot/icons/nexusw.png b/contrib/applications/nxplot/NXplot/icons/nexusw.png
new file mode 100644
index 0000000..abd1b3c
Binary files /dev/null and b/contrib/applications/nxplot/NXplot/icons/nexusw.png differ
diff --git a/contrib/applications/nxplot/NXplot/icons/nexusw32.png b/contrib/applications/nxplot/NXplot/icons/nexusw32.png
new file mode 100644
index 0000000..ee54e06
Binary files /dev/null and b/contrib/applications/nxplot/NXplot/icons/nexusw32.png differ
diff --git a/contrib/applications/nxplot/NXplot/nxplot.product b/contrib/applications/nxplot/NXplot/nxplot.product
new file mode 100644
index 0000000..4fc3042
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/nxplot.product
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="NXplot" uid="NXPlot.ID" id="NXplot.product" application="NXplot.application" version="1.0" useFeatures="false" includeLaunchers="true">
+
+   <aboutInfo>
+      <image path="/NXplot/icons/nexusw.png"/>
+      <text>
+         NXplot
+
+An extendable utility for plotting any NeXus file.
+
+NeXus International Advisory Committee (2009 - ????)
+
+Problems to be reported to: nexus-developers at nexusformat.org
+      </text>
+   </aboutInfo>
+
+   <configIni use="default">
+   </configIni>
+
+   <launcherArgs>
+      <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts</vmArgsMac>
+   </launcherArgs>
+
+   <windowImages i32="/NXplot/icons/nexusw32.png" i128="/NXplot/icons/nexusw.png"/>
+
+   <launcher name="nxplot">
+      <solaris/>
+      <win useIco="false">
+         <bmp/>
+      </win>
+   </launcher>
+
+   <vm>
+   </vm>
+
+   <plugins>
+      <plugin id="NXplot"/>
+      <plugin id="com.ibm.icu"/>
+      <plugin id="jnexus"/>
+      <plugin id="mountaingumnexus"/>
+      <plugin id="mountaingumsys"/>
+      <plugin id="mountaingumuibase"/>
+      <plugin id="org.eclipse.core.commands"/>
+      <plugin id="org.eclipse.core.contenttype"/>
+      <plugin id="org.eclipse.core.databinding"/>
+      <plugin id="org.eclipse.core.databinding.observable"/>
+      <plugin id="org.eclipse.core.databinding.property"/>
+      <plugin id="org.eclipse.core.expressions"/>
+      <plugin id="org.eclipse.core.jobs"/>
+      <plugin id="org.eclipse.core.runtime"/>
+      <plugin id="org.eclipse.core.runtime.compatibility.registry" fragment="true"/>
+      <plugin id="org.eclipse.equinox.app"/>
+      <plugin id="org.eclipse.equinox.common"/>
+      <plugin id="org.eclipse.equinox.preferences"/>
+      <plugin id="org.eclipse.equinox.registry"/>
+      <plugin id="org.eclipse.help"/>
+      <plugin id="org.eclipse.jface"/>
+      <plugin id="org.eclipse.jface.databinding"/>
+      <plugin id="org.eclipse.nebula.compositetable"/>
+      <plugin id="org.eclipse.osgi"/>
+      <plugin id="org.eclipse.swt"/>
+      <plugin id="org.eclipse.swt.carbon.macosx" fragment="true"/>
+      <plugin id="org.eclipse.swt.cocoa.macosx" fragment="true"/>
+      <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.ppc" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.s390" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.s390x" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.solaris.sparc" fragment="true"/>
+      <plugin id="org.eclipse.swt.gtk.solaris.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.motif.aix.ppc" fragment="true"/>
+      <plugin id="org.eclipse.swt.motif.hpux.PA_RISC" fragment="true"/>
+      <plugin id="org.eclipse.swt.motif.hpux.ia64_32" fragment="true"/>
+      <plugin id="org.eclipse.swt.motif.linux.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.motif.solaris.sparc" fragment="true"/>
+      <plugin id="org.eclipse.swt.photon.qnx.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86" fragment="true"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.swt.wpf.win32.x86" fragment="true"/>
+      <plugin id="org.eclipse.ui"/>
+      <plugin id="org.eclipse.ui.carbon" fragment="true"/>
+      <plugin id="org.eclipse.ui.cocoa" fragment="true"/>
+      <plugin id="org.eclipse.ui.workbench"/>
+      <plugin id="sgtgraphics"/>
+   </plugins>
+
+
+</product>
diff --git a/contrib/applications/nxplot/NXplot/plugin.xml b/contrib/applications/nxplot/NXplot/plugin.xml
new file mode 100755
index 0000000..a031d43
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/plugin.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+   <extension
+         id="application"
+         point="org.eclipse.core.runtime.applications">
+      <application>
+         <run
+               class="org.nexusformat.nxplot.NXplot">
+         </run>
+      </application>
+   </extension>
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            name="Perspective"
+            class="org.nexusformat.nxplot.Perspective"
+            id="NXplot.perspective">
+      </perspective>
+   </extension>
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            name="View"
+            class="org.nexusformat.nxplot.View"
+            id="NXplot.view">
+      </view>
+   </extension>
+   <extension
+         id="product"
+         point="org.eclipse.core.runtime.products">
+      <product
+            application="NXplot.application"
+            name="NXplot">
+         <property
+               name="appName"
+               value="NXplot">
+         </property>
+         <property
+               name="aboutImage"
+               value="icons/nexusw.png">
+         </property>
+         <property
+               name="aboutText"
+               value="NXplot&#x0A;&#x0A;An extendable utility for plotting any NeXus file.&#x0A;&#x0A;NeXus International Advisory Committee (2009 - ????)&#x0A;&#x0A;Problems to be reported to: nexus-developers at nexusformat.org">
+         </property>
+         <property
+               name="windowImages"
+               value="icons/nexusw32.png,icons/nexusw.png">
+         </property>
+      </product>
+   </extension>
+
+</plugin>
diff --git a/contrib/applications/nxplot/NXplot/splash.bmp b/contrib/applications/nxplot/NXplot/splash.bmp
new file mode 100755
index 0000000..6d9e8ae
Binary files /dev/null and b/contrib/applications/nxplot/NXplot/splash.bmp differ
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ActionDelegateProxy.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ActionDelegateProxy.java
new file mode 100755
index 0000000..26f1525
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ActionDelegateProxy.java
@@ -0,0 +1,35 @@
+/**
+ * The NeXus actions are IWorkbenchWindowActionDelegates. These 
+ * have to mogrified to actions to be included in a menu of NXplot.
+ * This is the point of this class. This should probably go into
+ * some util package in the long run.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package org.nexusformat.nxplot;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.PlatformUI;
+
+public class ActionDelegateProxy extends Action {
+	private IWorkbenchWindowActionDelegate deli;
+	private String title;
+	
+	ActionDelegateProxy(String title, IWorkbenchWindowActionDelegate deli){
+		super(title);
+		this.deli = deli;
+		this.title = title;
+	}
+
+	public String getId() {
+		return "actiondelgateproxy." + title;
+	}
+
+	public void run() {
+		deli.init(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+		deli.run(this);
+	}
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationActionBarAdvisor.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationActionBarAdvisor.java
new file mode 100755
index 0000000..c1e6592
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationActionBarAdvisor.java
@@ -0,0 +1,79 @@
+/**
+ * This class defines the menu bar for the NXplot application
+ * 
+ * copyright:GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package org.nexusformat.nxplot;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+
+import ch.psi.num.mountaingum.nexus.actions.*;
+/**
+ * An action bar advisor is responsible for creating, adding, and disposing of
+ * the actions added to a workbench window. Each window will be populated with
+ * new actions.
+ */
+public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
+
+	// Actions - important to allocate these only in makeActions, and then use
+	// them
+	// in the fill methods. This ensures that the actions aren't recreated
+	// when fillActionBars is called with FILL_PROXY.
+	private IWorkbenchAction exitAction, about;
+	private IAction open, save, png, print;
+	
+	public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
+		super(configurer);
+	}
+
+	protected void makeActions(final IWorkbenchWindow window) {
+		// Creates the actions and registers them.
+		// Registering is needed to ensure that key bindings work.
+		// The corresponding commands key bindings are defined in the plugin.xml
+		// file.
+		// Registering also provides automatic disposal of the actions when
+		// the window is closed.
+
+		exitAction = ActionFactory.QUIT.create(window);
+		register(exitAction);
+		
+		about = ActionFactory.ABOUT.create(window);
+		
+		open = new ActionDelegateProxy("Open" ,new OpenNexus());
+		register(open);
+		save = new ActionDelegateProxy("Save" ,new SaveNexus());
+		register(save);
+		png = new ActionDelegateProxy("Export PNG" ,new PNGNexusGraph());
+		register(save);
+		print = new ActionDelegateProxy("Print" ,new PrintNexusGraph());
+		register(save);
+
+	}
+
+	protected void fillMenuBar(IMenuManager menuBar) {
+		MenuManager fileMenu = new MenuManager("&File",
+				IWorkbenchActionConstants.M_FILE);
+		menuBar.add(fileMenu);
+		fileMenu.add(open);
+		fileMenu.add(save);
+		fileMenu.add(png);
+		fileMenu.add(print);
+		fileMenu.add(exitAction);
+		
+		MenuManager helpMenu = new MenuManager("&Help",
+				IWorkbenchActionConstants.HELP_END);
+		menuBar.add(helpMenu);
+		helpMenu.add(about);
+		
+	}
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationWorkbenchAdvisor.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationWorkbenchAdvisor.java
new file mode 100755
index 0000000..b454d55
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationWorkbenchAdvisor.java
@@ -0,0 +1,20 @@
+package org.nexusformat.nxplot;
+
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
+
+	private static final String PERSPECTIVE_ID = "NXplot.perspective";
+
+	public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
+			IWorkbenchWindowConfigurer configurer) {
+		return new ApplicationWorkbenchWindowAdvisor(configurer);
+	}
+
+	public String getInitialWindowPerspectiveId() {
+		return PERSPECTIVE_ID;
+	}
+
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationWorkbenchWindowAdvisor.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationWorkbenchWindowAdvisor.java
new file mode 100755
index 0000000..fbf8a68
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/ApplicationWorkbenchWindowAdvisor.java
@@ -0,0 +1,26 @@
+package org.nexusformat.nxplot;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+
+	public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
+		super(configurer);
+	}
+
+	public ActionBarAdvisor createActionBarAdvisor(
+			IActionBarConfigurer configurer) {
+		return new ApplicationActionBarAdvisor(configurer);
+	}
+
+	public void preWindowOpen() {
+		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
+		configurer.setInitialSize(new Point(640, 480));
+		configurer.setShowCoolBar(false);
+		configurer.setShowStatusLine(false);
+	}
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/BlankSysAdapter.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/BlankSysAdapter.java
new file mode 100755
index 0000000..8dfa984
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/BlankSysAdapter.java
@@ -0,0 +1,40 @@
+/**
+ * This is a dummy system adapter to make NXplot tick
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package org.nexusformat.nxplot;
+
+import ch.psi.num.mountaingum.sys.IDisconnectListener;
+import ch.psi.num.mountaingum.sys.ISystemAdapter;
+import ch.psi.num.mountaingum.sys.TerminalInterface;
+import ch.psi.num.mountaingum.tree.TreeNode;
+
+public class BlankSysAdapter implements ISystemAdapter {
+
+	public void addDisconnectListener(IDisconnectListener l) {
+	}
+
+	public boolean canAsync() {
+		return false;
+	}
+
+	public void closeTerminalInterface(TerminalInterface ti) {
+	}
+
+	public void configureTree(TreeNode root) {
+	}
+
+	public void interrupt() {
+	}
+
+	public TerminalInterface makeTerminalInterface() {
+		return null;
+	}
+
+	public void removeDisconnectListener(IDisconnectListener l) {
+	}
+
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/NXplot.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/NXplot.java
new file mode 100755
index 0000000..de03a44
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/NXplot.java
@@ -0,0 +1,55 @@
+/** 
+ * Eclipse-rcp main class for NXplot
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package org.nexusformat.nxplot;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+
+import ch.psi.num.mountaingum.sys.SysRegistry;
+
+/**
+ * This class controls all aspects of the application's execution
+ */
+public class NXplot implements IApplication {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
+	 */
+	public Object start(IApplicationContext context) {
+		SysRegistry.setSystemAdapter(new BlankSysAdapter());
+		Display display = PlatformUI.createDisplay();
+		try {
+			int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
+			if (returnCode == PlatformUI.RETURN_RESTART) {
+				return IApplication.EXIT_RESTART;
+			}
+			return IApplication.EXIT_OK;
+		} finally {
+			display.dispose();
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.equinox.app.IApplication#stop()
+	 */
+	public void stop() {
+		final IWorkbench workbench = PlatformUI.getWorkbench();
+		if (workbench == null)
+			return;
+		final Display display = workbench.getDisplay();
+		display.syncExec(new Runnable() {
+			public void run() {
+				if (!display.isDisposed())
+					workbench.close();
+			}
+		});
+	}
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/Perspective.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/Perspective.java
new file mode 100755
index 0000000..f0631bb
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/Perspective.java
@@ -0,0 +1,31 @@
+/**
+ * The NeXus Perspective to load
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package org.nexusformat.nxplot;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+import ch.psi.num.mountaingum.nexus.Perspective.NameView;
+import ch.psi.num.mountaingum.nexus.Perspective.NexusTree;
+import ch.psi.num.mountaingum.ui.EditorView.TreeEditorView;
+
+public class Perspective implements IPerspectiveFactory {
+
+	public void createInitialLayout(IPageLayout layout) {
+		String editorArea = layout.getEditorArea();
+		layout.setEditorAreaVisible(false);
+		layout.setFixed(true);
+		
+		layout.addStandaloneView(NameView.ID,  false, IPageLayout.TOP, 0.05f, editorArea);
+		layout.addStandaloneView(NexusTree.ID,  false, IPageLayout.LEFT, 0.33f, editorArea);
+		layout.addStandaloneView(TreeEditorView.ID +":1", false, 
+				IPageLayout.RIGHT, 0.66f, editorArea);
+		
+	}
+
+}
diff --git a/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/View.java b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/View.java
new file mode 100755
index 0000000..89f6c99
--- /dev/null
+++ b/contrib/applications/nxplot/NXplot/src/org/nexusformat/nxplot/View.java
@@ -0,0 +1,73 @@
+package org.nexusformat.nxplot;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+public class View extends ViewPart {
+	public static final String ID = "NXplot.view";
+
+	private TableViewer viewer;
+
+	/**
+	 * The content provider class is responsible for providing objects to the
+	 * view. It can wrap existing objects in adapters or simply return objects
+	 * as-is. These objects may be sensitive to the current input of the view,
+	 * or ignore it and always show the same content (like Task List, for
+	 * example).
+	 */
+	class ViewContentProvider implements IStructuredContentProvider {
+		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
+		}
+
+		public void dispose() {
+		}
+
+		public Object[] getElements(Object parent) {
+			return new String[] { "One", "Two", "Three" };
+		}
+	}
+
+	class ViewLabelProvider extends LabelProvider implements
+			ITableLabelProvider {
+		public String getColumnText(Object obj, int index) {
+			return getText(obj);
+		}
+
+		public Image getColumnImage(Object obj, int index) {
+			return getImage(obj);
+		}
+
+		public Image getImage(Object obj) {
+			return PlatformUI.getWorkbench().getSharedImages().getImage(
+					ISharedImages.IMG_OBJ_ELEMENT);
+		}
+	}
+
+	/**
+	 * This is a callback that will allow us to create the viewer and initialize
+	 * it.
+	 */
+	public void createPartControl(Composite parent) {
+		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
+				| SWT.V_SCROLL);
+		viewer.setContentProvider(new ViewContentProvider());
+		viewer.setLabelProvider(new ViewLabelProvider());
+		viewer.setInput(getViewSite());
+	}
+
+	/**
+	 * Passing the focus request to the viewer's control.
+	 */
+	public void setFocus() {
+		viewer.getControl().setFocus();
+	}
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/README.build b/contrib/applications/nxplot/README.build
new file mode 100644
index 0000000..c1e768f
--- /dev/null
+++ b/contrib/applications/nxplot/README.build
@@ -0,0 +1,61 @@
+
+  Building NXplot
+
+  Prerequisites
+
+  At a minimum you need the eclipse IDE with the plugin development 
+  kit installed. Eclipse version 3.5 is required. This can be 
+  downloaded from www.eclipse.org. Choose the classic option. 
+
+  If you just want to have a look, a copy of eclipse is all you need. 
+  However, if you wish to create stand alone copies of NXplot, you 
+  need a platform kit. A platform kit is the set of basic eclipse 
+  plugins you need to build an eclipse-RCP application. In order to 
+  arrive at a suitable platform kit for NXplot you need to merge 
+  plugins from three different sources:
+  - The eclipse-RCP platform kit. To be downloaded from the eclipse 
+    site 
+  - The diff-kit belonging to your platform kit. This kit contains 
+    system specific shared libraries and such for the various platforms 
+    eclipse runs on.
+  - A selection of eclipse-IDE plugins which you copy from your 
+    eclipse-IDE installation. Of course: same version as the eclipse-RCP
+    platform.
+  Again at least version 3.5 is required. Older then that: you are in 
+  trouble on the Macintosh. A full list of platform plugins is provided 
+  in a separate text file. Please note that version strings may vary 
+  over time.
+
+  The easy way to get a suitable kit is to ask someone who already 
+  develops for NXplot to send you a tarball. 
+
+
+  Setting up Eclipse
+
+  1) Fire up eclipse and select a workspace
+  2) Add and activate the eclipse-RCP platform you installed in
+     Window/Preference/Plugin Development/Target Platform. Omit this step 
+     if you did not setup a platform.
+  3) Import all the plugins in this directory to your workspace:
+     File/Import/Existing projects into workspace
+     Unckeck the copy sources option, otherwise all files will be copied 
+     and svn will be thrown off. 
+  4) Find and double click the nxplot.product file in the NXplot 
+     plugin
+  5) In its dependencies tab, use Add required plugins
+  6) Do the same in Run/Run configurations. If you have no run 
+     configuration for NXplot, try to run it from the nxplot.product 
+     Overview tab
+  7) Setting up eclipse run configurations and dependencies can be painful!
+
+
+
+ Running NXplot
+
+ The key to everything is the nxplot.nxproduct/Overview tab. It has 
+ buttons to start NXplot in normal and debug mode and to export 
+ NXplot as a standalone application. 
+
+ jnexus requires shared libraries. There is yet another readme in the 
+ jnexus root directory how to set this up for different platforms. 
+  
\ No newline at end of file
diff --git a/contrib/applications/nxplot/jnexus/.classpath b/contrib/applications/nxplot/jnexus/.classpath
new file mode 100755
index 0000000..ad32c83
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/jnexus/.project b/contrib/applications/nxplot/jnexus/.project
new file mode 100755
index 0000000..759a85a
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>jnexus</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/jnexus/.settings/org.eclipse.jdt.core.prefs b/contrib/applications/nxplot/jnexus/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 0000000..a67c808
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Wed Oct 21 11:46:43 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/contrib/applications/nxplot/jnexus/Linuxi386.lib b/contrib/applications/nxplot/jnexus/Linuxi386.lib
new file mode 100644
index 0000000..764d195
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/Linuxi386.lib
@@ -0,0 +1,8 @@
+z
+mxml
+jpeg
+hdf5
+df
+mfhdf
+NeXus
+jnexus
diff --git a/contrib/applications/nxplot/jnexus/META-INF/MANIFEST.MF b/contrib/applications/nxplot/jnexus/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..7046931
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Jnexus Plug-in
+Bundle-SymbolicName: jnexus
+Bundle-Version: 4.2.0
+Bundle-Vendor: The NeXus Group
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: ncsa.hdf.hdflib,
+ org.nexusformat
+Eclipse-LazyStart: true
+Bundle-Activator: NexusActivator
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.3.100"
diff --git a/contrib/applications/nxplot/jnexus/build.properties b/contrib/applications/nxplot/jnexus/build.properties
new file mode 100755
index 0000000..588a95d
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/build.properties
@@ -0,0 +1,34 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               libNeXus.so,\
+               libjnexus.so,\
+               hd421m.dll,\
+               hdf5dll.dll,\
+               hm421m.dll,\
+               iconv.dll,\
+               jnexus.dll,\
+               libNeXus-0.dll,\
+               libjnexus-0.dll,\
+               libxml2.dll,\
+               szlibdll.dll,\
+               zlib1.dll,\
+               libjpeg.so.62,\
+               libmfhdf.so.4,\
+               libmxml.so.1,\
+               libhdf5-1.6.5.so.0,\
+               libdf.so.4,\
+               libz.so.1,\
+               libdf.so,\
+               libhdf5.so,\
+               libjpeg.so,\
+               libmfhdf.so,\
+               libmxml.so,\
+               libz.so,\
+               Linuxi386.lib,\
+               windoofx86.lib,\
+               build.properties,\
+               sharedlib.readme,\
+               libjnexus.jnilib,\
+               macosx.lib
diff --git a/contrib/applications/nxplot/jnexus/hd421m.dll b/contrib/applications/nxplot/jnexus/hd421m.dll
new file mode 100755
index 0000000..28d236a
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/hd421m.dll differ
diff --git a/contrib/applications/nxplot/jnexus/hdf5dll.dll b/contrib/applications/nxplot/jnexus/hdf5dll.dll
new file mode 100755
index 0000000..9045f3b
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/hdf5dll.dll differ
diff --git a/contrib/applications/nxplot/jnexus/hm421m.dll b/contrib/applications/nxplot/jnexus/hm421m.dll
new file mode 100755
index 0000000..b052206
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/hm421m.dll differ
diff --git a/contrib/applications/nxplot/jnexus/iconv.dll b/contrib/applications/nxplot/jnexus/iconv.dll
new file mode 100755
index 0000000..b448e7d
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/iconv.dll differ
diff --git a/contrib/applications/nxplot/jnexus/jnexus.dll b/contrib/applications/nxplot/jnexus/jnexus.dll
new file mode 100755
index 0000000..2b8465c
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/jnexus.dll differ
diff --git a/contrib/applications/nxplot/jnexus/libNeXus-0.dll b/contrib/applications/nxplot/jnexus/libNeXus-0.dll
new file mode 100755
index 0000000..4f6a4e9
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libNeXus-0.dll differ
diff --git a/contrib/applications/nxplot/jnexus/libNeXus.so b/contrib/applications/nxplot/jnexus/libNeXus.so
new file mode 100755
index 0000000..3620524
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libNeXus.so differ
diff --git a/contrib/applications/nxplot/jnexus/libNeXus.so.0 b/contrib/applications/nxplot/jnexus/libNeXus.so.0
new file mode 100755
index 0000000..3620524
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libNeXus.so.0 differ
diff --git a/contrib/applications/nxplot/jnexus/libdf.so.4 b/contrib/applications/nxplot/jnexus/libdf.so.4
new file mode 100644
index 0000000..74f4fe1
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libdf.so.4 differ
diff --git a/contrib/applications/nxplot/jnexus/libhdf5-1.6.5.so.0 b/contrib/applications/nxplot/jnexus/libhdf5-1.6.5.so.0
new file mode 100644
index 0000000..4b3ef6a
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libhdf5-1.6.5.so.0 differ
diff --git a/contrib/applications/nxplot/jnexus/libhdf5.so b/contrib/applications/nxplot/jnexus/libhdf5.so
new file mode 100755
index 0000000..4b3ef6a
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libhdf5.so differ
diff --git a/contrib/applications/nxplot/jnexus/libjnexus-0.dll b/contrib/applications/nxplot/jnexus/libjnexus-0.dll
new file mode 100755
index 0000000..d5ccb39
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libjnexus-0.dll differ
diff --git a/contrib/applications/nxplot/jnexus/libjnexus.jnilib b/contrib/applications/nxplot/jnexus/libjnexus.jnilib
new file mode 100644
index 0000000..97e5e7c
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libjnexus.jnilib differ
diff --git a/contrib/applications/nxplot/jnexus/libjnexus.so b/contrib/applications/nxplot/jnexus/libjnexus.so
new file mode 100755
index 0000000..b332925
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libjnexus.so differ
diff --git a/contrib/applications/nxplot/jnexus/libjpeg.so b/contrib/applications/nxplot/jnexus/libjpeg.so
new file mode 100755
index 0000000..b95fa57
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libjpeg.so differ
diff --git a/contrib/applications/nxplot/jnexus/libjpeg.so.62 b/contrib/applications/nxplot/jnexus/libjpeg.so.62
new file mode 100644
index 0000000..b95fa57
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libjpeg.so.62 differ
diff --git a/contrib/applications/nxplot/jnexus/libmfhdf.so b/contrib/applications/nxplot/jnexus/libmfhdf.so
new file mode 100755
index 0000000..0226558
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libmfhdf.so differ
diff --git a/contrib/applications/nxplot/jnexus/libmfhdf.so.4 b/contrib/applications/nxplot/jnexus/libmfhdf.so.4
new file mode 100644
index 0000000..0226558
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libmfhdf.so.4 differ
diff --git a/contrib/applications/nxplot/jnexus/libmxml.so b/contrib/applications/nxplot/jnexus/libmxml.so
new file mode 100755
index 0000000..a55fe73
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libmxml.so differ
diff --git a/contrib/applications/nxplot/jnexus/libmxml.so.1 b/contrib/applications/nxplot/jnexus/libmxml.so.1
new file mode 100644
index 0000000..a55fe73
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libmxml.so.1 differ
diff --git a/contrib/applications/nxplot/jnexus/libxml2.dll b/contrib/applications/nxplot/jnexus/libxml2.dll
new file mode 100755
index 0000000..cecdc43
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libxml2.dll differ
diff --git a/contrib/applications/nxplot/jnexus/libz.so.1 b/contrib/applications/nxplot/jnexus/libz.so.1
new file mode 100644
index 0000000..1711f99
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/libz.so.1 differ
diff --git a/contrib/applications/nxplot/jnexus/macosx.lib b/contrib/applications/nxplot/jnexus/macosx.lib
new file mode 100644
index 0000000..fdf6b1e
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/macosx.lib
@@ -0,0 +1 @@
+jnexus
diff --git a/contrib/applications/nxplot/jnexus/sharedlib.readme b/contrib/applications/nxplot/jnexus/sharedlib.readme
new file mode 100644
index 0000000..c3de732
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/sharedlib.readme
@@ -0,0 +1,38 @@
+
+   Shared Library Instructions
+   
+   Both NXplot and GTSE use jnexus and jnexus in turn requires the shared libraries
+   for NeXus and HDF. This is a pain in the ass. Contrary to the eclipse documentation
+   (2009) loading shared libraries from some directory in the jnexus hierarchy does 
+   not work. The only thing what does work is to load a named shared library from 
+   the root directory of the plugin. However, shared libraries the loaded library 
+   dependent upon are not automatically found. Thus the only way is to load the 
+   shared libraries and their dependents from Java code in the right order. To this 
+   purpose an activator class was defined which implements the following algorithm:
+   - A system specific filename is constructed from Java properties. The name of this 
+     file is printed. For further reference I call this file the library file.
+   - The library file is supposed to hold the names of the libraries to load in 
+     the right order, a library per line.
+   - The Activator reads this file, line by line, prints the name of the library Java 
+     thinks it should have and loads the library.
+     
+   Thus exchanging the libraries or adding libraries for an unsupported architecture 
+   requires the following steps:
+   1) copy the jnexus libraries and its dependents into this directory.
+   2) Run NXplot in order to find out about the library filename
+   3) Write a new library file with the required libraries
+   4) Try it out, I am sure there will be errors
+   Java tries to be clever and builds library names from the strings provided. 
+   These names may not be the ones expected, for instance under unix it tries to find 
+   for jnexus libjnexus.so but not the libjnexus.so.12 or so which usually is present. 
+   Thus some shared library renaming may be in order too. 
+   
+   If NXplot does not print onto the console, please start it with:
+   
+     nxplot -debug -console -consolelog
+     
+   NXplot also works if the shared libraries are somewhere in the system shared 
+   library path.
+     
+   Mark.Koennecke at psi.ch
+         
\ No newline at end of file
diff --git a/contrib/applications/nxplot/jnexus/src/NexusActivator.java b/contrib/applications/nxplot/jnexus/src/NexusActivator.java
new file mode 100644
index 0000000..58154c7
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/NexusActivator.java
@@ -0,0 +1,51 @@
+/**
+ * This is the activator class for the jnexus plugin. Its purpose is to 
+ * load all the shared libraries required for jnexus, depending on the OS.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2000
+ */
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+
+public class NexusActivator extends Plugin {
+
+	public void start(BundleContext context) throws Exception {
+		String line, os, libfile;
+		super.start(context);
+		
+		os = System.getProperty("os.name");
+		if(os.indexOf("Windows") >= 0){
+			libfile = "windoof" + System.getProperty("os.arch") + ".lib";
+		} else if(os.indexOf("Mac OS X") >= 0){
+			libfile = "macosx.lib";
+		} else {
+			libfile = os + System.getProperty("os.arch") + ".lib";
+			libfile = libfile.replace(" ", "_");	
+		}
+		System.out.println("Trying to load libraries from " + libfile);
+		URL ulli = Platform.getBundle("jnexus").getEntry(libfile);
+		if(ulli == null){
+			System.out.println(libfile + " library information file not found");
+			return;
+		}
+		BufferedReader in = new BufferedReader(new InputStreamReader(ulli.openStream()));
+		while((line = in.readLine()) != null){
+			System.out.println(System.mapLibraryName(line));
+			try{
+				System.loadLibrary(line);
+			}catch(Exception e){
+				System.out.println("Failed to load library: " + line);
+			}
+		}
+		in.close();
+	}
+
+}
diff --git a/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFArray.java b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFArray.java
new file mode 100755
index 0000000..25f92fd
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFArray.java
@@ -0,0 +1,850 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  This is a class for handling multidimensional arrays for
+ *  HDF.
+ *  <p>
+ *  The purpose is to allow the storage and retrieval of
+ *  arbitrary array types containing scientific data.
+ *  <p>
+ *  The methods support the conversion of an array to and
+ *  from Java to a one-dimensional array of bytes suitable
+ *  for I/O by the C library.
+ *  <p>
+ *  This class heavily uses the <a href="./ncsa.hdf.hdflib.HDFNativeData.html">HDFNativeData</a>
+ *  class to convert between Java and C representations.
+ */
+
+public class HDFArray {
+
+private Object _theArray = null;
+private ArrayDescriptor _desc = null;
+private byte [] _barray = null;
+
+public HDFArray(Object anArray) throws HDFException {
+
+	if (anArray == null) {
+		HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: array is null?: ");
+ex.printStackTrace();
+	}
+	Class tc = anArray.getClass();
+        if (tc.isArray() == false) {
+                /* exception: not an array */
+		HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: not an array?: ");
+ex.printStackTrace();
+		throw(ex);
+        }
+	_theArray = anArray;
+	_desc = new ArrayDescriptor( _theArray );
+
+	/* extra error checking -- probably not needed */
+	if (_desc == null ) {
+		HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: internal error: array description failed?: ");
+		throw(ex);
+	}
+}
+
+/**
+ *  allocate a one-dimensional array of bytes sufficient to store
+ *  the array.
+ *  @exception HDFException .
+ */
+
+public byte[] emptyBytes()
+throws HDFException
+{
+	byte[] b = null;
+	if (_desc.dims == 1 && _desc.NT == 'B') {
+		b = (byte [])_theArray;
+	} else {
+		b = new byte[_desc.totalSize];
+	}
+	if (b == null) {
+                System.out.println("Error:  HDFArray can't allocate bytes for array");
+ HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: emptyBytes: allocation failed");
+                        throw(ex);
+	}
+	return (b);
+	//return (new byte[_desc.totalSize]);
+}
+
+/**
+ *  Given a Java array of numbers, convert it to a one-dimensional
+ *  array of bytes in correct native order.
+ *
+ *  @exception ncsa.hdf.hdflib.HDFException 
+ *             thrown for errors: 
+ *		object is not array:  HDFJavaException
+ */
+public byte[] byteify() throws HDFException{
+
+	if (_barray != null) return _barray;
+	if (_theArray == null) {
+                /* exception: not an array */
+		 HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: byteify not an array?: ");
+		throw(ex);
+        }
+
+	if (_desc.dims == 1) {
+		/* special case */
+		if (_desc.NT == 'B') {
+			/* really special case! */
+			_barray = (byte [])_theArray;
+			return _barray;
+		} else {
+			try {
+			_barray = new byte[_desc.totalSize];
+
+			byte [] therow;
+			if (_desc.NT == 'I') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.intToByte(0,_desc.dimlen[1],(int [])_theArray);
+			} else if (_desc.NT == 'S') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.shortToByte(0,_desc.dimlen[1],(short [])_theArray);
+			} else if (_desc.NT == 'F') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.floatToByte(0,_desc.dimlen[1],(float [])_theArray);
+			} else if (_desc.NT == 'J') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.longToByte(0,_desc.dimlen[1],(long [])_theArray);
+			} else if (_desc.NT == 'D') {
+				therow = ncsa.hdf.hdflib.HDFNativeData.doubleToByte(0,_desc.dimlen[1],(double [])_theArray);
+			} else if (_desc.NT == 'L') {
+				if (_desc.className.equals("java.lang.Byte")) {
+					therow = ByteObjToByte((Byte[])_theArray);
+				} else if (_desc.className.equals("java.lang.Integer")) {
+					therow = IntegerToByte((Integer[])_theArray);
+				} else if (_desc.className.equals("java.lang.Short")) {
+					therow = ShortToByte((Short[])_theArray);
+				} else if (_desc.className.equals("java.lang.Float")) {
+					therow = FloatObjToByte((Float[])_theArray);
+				} else if (_desc.className.equals("java.lang.Double")) {
+					therow = DoubleObjToByte((Double[])_theArray);
+				} else if (_desc.className.equals("java.lang.Long")) {
+					therow = LongObjToByte((Long[])_theArray);
+				} else {
+					 HDFJavaException ex =
+						new HDFJavaException("HDFArray: unknown type of Object?");
+					 throw(ex);
+				}
+			} else {
+				HDFJavaException ex =
+					new HDFJavaException("HDFArray: unknown type of Object?");
+				throw(ex);
+			}
+			System.arraycopy(therow,0,_barray,0,(_desc.dimlen[1] * _desc.NTsize));
+			return _barray;
+			} catch (OutOfMemoryError err) {
+				 HDFException ex =
+				(HDFException)new HDFJavaException("HDFArray: byteify array too big?");
+				ex.printStackTrace();
+				throw(ex);
+			}
+		}
+	}
+
+	try {
+		_barray = new byte[_desc.totalSize];
+        } catch (OutOfMemoryError err) {
+	 HDFException ex =
+		(HDFException)new HDFJavaException("HDFArray: byteify array too big?");
+		ex.printStackTrace();
+                        throw(ex);
+	}
+
+
+	Object oo = _theArray;
+	int n = 0;  /* the current byte */
+	int index = 0;
+	int i;
+	while ( n < _desc.totalSize ) {
+		oo = _desc.objs[0];
+		index = n / _desc.bytetoindex[0];
+                index %= _desc.dimlen[0];
+		for (i = 0 ; i < (_desc.dims); i++) {
+			index = n / _desc.bytetoindex[i];
+			index %= _desc.dimlen[i];
+
+			if (index == _desc.currentindex[i]) {
+				/* then use cached copy */
+				oo = _desc.objs[i];
+			} else {
+				/* check range of index */		
+				if (index > (_desc.dimlen[i] - 1)) {
+					System.out.println("out of bounds?");
+					return null;
+				}
+				oo = java.lang.reflect.Array.get((Object) oo,index);
+				_desc.currentindex[i] = index;
+				_desc.objs[i] = oo;
+			}
+		}
+
+		/* byte-ify */
+		byte arow[];
+		try {
+		if (_desc.NT == 'J') {
+			arow = ncsa.hdf.hdflib.HDFNativeData.longToByte(0,_desc.dimlen[_desc.dims],(long [])_desc.objs[_desc.dims - 1]);
+			arow = ncsa.hdf.hdflib.HDFNativeData.longToByte(0,_desc.dimlen[_desc.dims],(long [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'I') {
+			arow = ncsa.hdf.hdflib.HDFNativeData.intToByte(0,_desc.dimlen[_desc.dims],(int [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'S') {
+			arow = ncsa.hdf.hdflib.HDFNativeData.shortToByte(0,_desc.dimlen[_desc.dims],(short [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'B') {
+			arow = (byte [])_desc.objs[_desc.dims - 1];
+		} else if (_desc.NT == 'F') {
+			/* 32 bit float */
+			arow = ncsa.hdf.hdflib.HDFNativeData.floatToByte(0,_desc.dimlen[_desc.dims],(float [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'D') {
+			/* 64 bit float */
+			arow = ncsa.hdf.hdflib.HDFNativeData.doubleToByte(0,_desc.dimlen[_desc.dims],(double [])_desc.objs[_desc.dims - 1]);
+		} else if (_desc.NT == 'L') {
+			if (_desc.className.equals("java.lang.Byte")) {
+				arow = ByteObjToByte((Byte[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Integer")) {
+				arow = IntegerToByte((Integer[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Short")) {
+				arow = ShortToByte((Short[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Float")) {
+				arow = FloatObjToByte((Float[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Double")) {
+				arow = DoubleObjToByte((Double[])_desc.objs[_desc.dims - 1]);
+			} else if (_desc.className.equals("java.lang.Long")) {
+				arow = LongObjToByte((Long[])_desc.objs[_desc.dims - 1]);
+			} else {
+				HDFJavaException ex =
+				new HDFJavaException("HDFArray: byteify Object type not implemented?");
+				throw(ex);
+			}
+		} else {
+			HDFJavaException ex =
+			new HDFJavaException("HDFArray: byteify Object type not implemented?");
+			throw(ex);
+		}
+		System.arraycopy(arow,0,_barray,n,(_desc.dimlen[_desc.dims] * _desc.NTsize));
+		n += _desc.bytetoindex[_desc.dims - 1];
+		} catch (OutOfMemoryError err) {
+		 HDFException ex =
+			(HDFException)new HDFJavaException("HDFArray: byteify array too big?");
+			ex.printStackTrace();
+			throw(ex);
+		}
+	}
+/* assert:  the whole array is completed--currentindex should == len - 1 */
+
+	/* error checks */
+
+	if (n < _desc.totalSize) {
+		throw new java.lang.InternalError(
+		new String("HDFArray:::byteify: Panic didn't complete all input data: n=  "+n+" size = "+_desc.totalSize));
+	}
+	for (i = 0;i < _desc.dims; i++) {
+		if (_desc.currentindex[i] != _desc.dimlen[i] - 1) {
+			throw new java.lang.InternalError(
+			new String("Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i] - 1)+" ?)"));
+		}
+	}
+	return _barray;
+}
+
+/**
+ *  Given a one-dimensional array of numbers, convert it to a java
+ *  array of the shape and size passed to the constructor.
+ *
+ *  @exception ncsa.hdf.hdflib.HDFException 
+ *             thrown for errors: 
+ *		object not an array:  HDFJavaException 
+ */
+public Object arrayify(byte[] bytes) throws HDFException {
+
+	if (_theArray == null) {
+                /* exception: not an array */
+		 HDFException ex = 
+		(HDFException)new HDFJavaException("arrayify: not an array?: "); 
+		throw(ex); 
+	} 
+
+	if (java.lang.reflect.Array.getLength((Object) bytes) != _desc.totalSize) { 
+		/* exception: array not right size */ 
+		 HDFException ex = 
+		(HDFException)new HDFJavaException("arrayify: array is wrong size?: "); 
+	} 
+	_barray = bytes; /* hope that the bytes are correct.... */ 
+	if (_desc.dims == 1) {
+		/* special case */
+		/* 2 data copies here! */
+		try {
+		if (_desc.NT == 'I') {
+			int [] x = (int [])ncsa.hdf.hdflib.HDFNativeData.byteToInt(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'S') {
+			short [] x = ncsa.hdf.hdflib.HDFNativeData.byteToShort(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'F') {
+			float x[] = ncsa.hdf.hdflib.HDFNativeData.byteToFloat(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'J') {
+			long x[] = ncsa.hdf.hdflib.HDFNativeData.byteToLong(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'D') {
+			double x[] = ncsa.hdf.hdflib.HDFNativeData.byteToDouble(_barray);
+			System.arraycopy(x,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'B') {
+			System.arraycopy(_barray,0,_theArray,0,_desc.dimlen[1]);
+			return _theArray;
+		} else if (_desc.NT == 'L') {
+			if (_desc.className.equals("java.lang.Byte")) {
+				Byte I[] = ByteToByteObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Integer")) {
+				Integer I[] = ByteToInteger(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Short")) {
+				Short I[] = ByteToShort(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Float")) {
+				Float I[] = ByteToFloatObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Double")) {
+				Double I[] = ByteToDoubleObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else if (_desc.className.equals("java.lang.Long")) {
+				Long I[] = ByteToLongObj(_barray);
+				System.arraycopy(I,0,_theArray,0,_desc.dimlen[1]);
+				return _theArray;
+			} else {
+			HDFJavaException ex =
+			new HDFJavaException("arrayify:  Object type not implemented yet...");
+			throw(ex); 
+			}
+		} else {
+			HDFJavaException ex =
+			new HDFJavaException("arrayify:  Object type not implemented yet...");
+			throw(ex); 
+		}
+		} catch (OutOfMemoryError err) {
+		 HDFException ex =
+			(HDFException)new HDFJavaException("HDFArray: arrayify array too big?");
+			ex.printStackTrace();
+			throw(ex);
+		}
+	}
+	/* Assert dims >= 2 */
+
+	Object oo = _theArray;
+	int n = 0;  /* the current byte */
+	int index = 0;
+	int i;
+	while ( n < _desc.totalSize ) {
+		oo = _desc.objs[0];
+		index = n / _desc.bytetoindex[0];
+		index %= _desc.dimlen[0];
+		for (i = 0 ; i < (_desc.dims); i++) {
+			index = n / _desc.bytetoindex[i];
+			index %= _desc.dimlen[i];
+
+			if (index == _desc.currentindex[i]) {
+				/* then use cached copy */
+				oo = _desc.objs[i];
+			} else {
+				/* check range of index */		
+				if (index > (_desc.dimlen[i] - 1)) {
+					System.out.println("out of bounds?");
+					return null;
+				}
+				oo = java.lang.reflect.Array.get((Object) oo,index);
+				_desc.currentindex[i] = index;
+				_desc.objs[i] = oo;
+			}
+		}
+
+		/* array-ify */
+		try {
+		if (_desc.NT == 'J') {
+			long [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToLong(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'I') {
+			int [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToInt(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'S') {
+			short [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToShort(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'B') {
+			System.arraycopy( _barray, n, _desc.objs[_desc.dims - 1], 0, _desc.dimlen[_desc.dims]);
+			n += _desc.bytetoindex[_desc.dims - 1];
+		} else if (_desc.NT == 'F') {
+			float arow[] = ncsa.hdf.hdflib.HDFNativeData.byteToFloat(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'D') {
+			double [] arow = ncsa.hdf.hdflib.HDFNativeData.byteToDouble(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), (Object)arow);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+		} else if (_desc.NT == 'L') {
+			if (_desc.className.equals("java.lang.Byte")) {
+				Byte I[] = ByteToByteObj(n,_desc.dimlen[_desc.dims],_barray);
+		java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+			(_desc.currentindex[_desc.dims - 1]), 
+			(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Integer")) {
+				Integer I[] = ByteToInteger(n,_desc.dimlen[_desc.dims],_barray);
+		java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+			(_desc.currentindex[_desc.dims - 1]), 
+			(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Short")) {
+				Short I[] = ByteToShort(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Float")) {
+				Float I[] = ByteToFloatObj(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Double")) {
+				Double I[] = ByteToDoubleObj(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else if (_desc.className.equals("java.lang.Long")) {
+				Long I[] = ByteToLongObj(n,_desc.dimlen[_desc.dims],_barray);
+			java.lang.reflect.Array.set(_desc.objs[_desc.dims - 2] ,
+				(_desc.currentindex[_desc.dims - 1]), 
+				(Object)I);
+
+			n += _desc.bytetoindex[_desc.dims - 1];
+			_desc.currentindex[_desc.dims - 1]++;
+			} else {
+			HDFJavaException ex =
+			new HDFJavaException("HDFArray: unsupported Object type: "+_desc.NT);
+			throw(ex);
+			}
+		} else {
+			HDFJavaException ex =
+			new HDFJavaException("HDFArray: unsupported Object type: "+_desc.NT);
+			throw(ex);
+		}
+		} catch (OutOfMemoryError err) {
+		 HDFException ex =
+			(HDFException)new HDFJavaException("HDFArray: arrayify array too big?");
+			ex.printStackTrace();
+			throw(ex);
+		}
+
+	}
+
+/* assert:  the whole array is completed--currentindex should == len - 1 */
+
+	/* error checks */
+
+	if (n < _desc.totalSize) {
+		throw new java.lang.InternalError(
+	       new String("HDFArray::arrayify Panic didn't complete all input data: n=  "+n+" size = "+_desc.totalSize));
+	}
+	for (i = 0;i <= _desc.dims-2; i++) {
+		if (_desc.currentindex[i] != _desc.dimlen[i] - 1) {
+		throw new java.lang.InternalError(
+			new String("HDFArray::arrayify Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i] - 1)+"?"));
+		}
+	}
+	if (_desc.NT != 'B') {
+	if (_desc.currentindex[_desc.dims - 1] != _desc.dimlen[_desc.dims - 1]) {
+		throw new java.lang.InternalError(
+		new String("HDFArray::arrayify Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i])+"?"));
+	}
+	} else {
+	if (_desc.currentindex[_desc.dims - 1] != (_desc.dimlen[_desc.dims - 1] - 1)) {
+		throw new java.lang.InternalError(
+		new String("HDFArray::arrayify Panic didn't complete all data: currentindex["+i+"] = "+_desc.currentindex[i]+" (should be "+(_desc.dimlen[i] - 1)+"?"));
+	}
+	}
+
+	return _theArray;
+}
+
+private byte[] IntegerToByte( Integer in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	int[] out = new int[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].intValue();
+	}
+	return  HDFNativeData.intToByte(0,nelems,out);
+}
+
+private Integer[] ByteToInteger( byte[] bin ) {
+	int in[] = (int [])HDFNativeData.byteToInt(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Integer[] out = new Integer[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Integer(in[i]);
+	}
+	return  out;
+}
+private Integer[] ByteToInteger( int start, int len, byte[] bin ) {
+	int in[] = (int [])HDFNativeData.byteToInt(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Integer[] out = new Integer[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Integer(in[i]);
+	}
+	return  out;
+}
+
+
+private byte[] ShortToByte( Short in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	short[] out = new short[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].shortValue();
+	}
+	return  HDFNativeData.shortToByte(0,nelems,out);
+}
+
+private Short[] ByteToShort( byte[] bin ) {
+	short in[] = (short [])HDFNativeData.byteToShort(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Short[] out = new Short[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Short(in[i]);
+	}
+	return  out;
+}
+
+private Short[] ByteToShort( int start, int len, byte[] bin ) {
+	short in[] = (short [])HDFNativeData.byteToShort(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Short[] out = new Short[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Short(in[i]);
+	}
+	return  out;
+}
+
+private byte[] ByteObjToByte( Byte in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	byte[] out = new byte[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].byteValue();
+	}
+	return out;
+}
+
+private Byte[] ByteToByteObj( byte[] bin ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)bin);
+	Byte[] out = new Byte[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Byte(bin[i]);
+	}
+	return  out;
+}
+
+private Byte[] ByteToByteObj( int start, int len, byte[] bin ) {
+	Byte[] out = new Byte[len];
+
+	for (int i = 0; i < len; i++) {
+		out[i] = new Byte(bin[i]);
+	}
+	return  out;
+}
+
+private byte[] FloatObjToByte( Float in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	float[] out = new float[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].floatValue();
+	}
+	return  HDFNativeData.floatToByte(0,nelems,out);
+}
+
+private Float[] ByteToFloatObj( byte[] bin ) {
+	float in[] = (float [])HDFNativeData.byteToFloat(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Float[] out = new Float[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Float(in[i]);
+	}
+	return  out;
+}
+
+private Float[] ByteToFloatObj( int start, int len, byte[] bin ) {
+	float in[] = (float [])HDFNativeData.byteToFloat(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Float[] out = new Float[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Float(in[i]);
+	}
+	return  out;
+}
+
+private byte[] DoubleObjToByte( Double in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	double[] out = new double[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].doubleValue();
+	}
+	return  HDFNativeData.doubleToByte(0,nelems,out);
+}
+
+private Double[] ByteToDoubleObj( byte[] bin ) {
+	double in[] = (double [])HDFNativeData.byteToDouble(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Double[] out = new Double[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Double(in[i]);
+	}
+	return  out;
+}
+
+private Double[] ByteToDoubleObj( int start, int len, byte[] bin ) {
+	double in[] = (double [])HDFNativeData.byteToDouble(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Double[] out = new Double[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Double(in[i]);
+	}
+	return  out;
+}
+
+private byte[] LongObjToByte( Long in[] ) {
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	long[] out = new long[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = in[i].longValue();
+	}
+	return  HDFNativeData.longToByte(0,nelems,out);
+}
+
+private Long[] ByteToLongObj( byte[] bin ) {
+	long in[] = (long [])HDFNativeData.byteToLong(bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Long[] out = new Long[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Long(in[i]);
+	}
+	return  out;
+}
+
+private Long[] ByteToLongObj( int start, int len, byte[] bin ) {
+	long in[] = (long [])HDFNativeData.byteToLong(start,len,bin);
+	int nelems = java.lang.reflect.Array.getLength((Object)in);
+	Long[] out = new Long[nelems];
+
+	for (int i = 0; i < nelems; i++) {
+		out[i] = new Long(in[i]);
+	}
+	return  out;
+}
+
+}
+
+
+/**
+  * This class is used by HDFArray to discover the shape and type of an
+  * arbitrary array.
+  */
+
+class ArrayDescriptor {
+
+	static String theType = "";
+	static Class theClass = null;
+        static int [] dimlen = null;
+        static int [] dimstart = null;
+        static int [] currentindex = null;
+        static int [] bytetoindex = null;
+	static int totalSize = 0;
+        static Object [] objs = null;
+	static char NT = ' ';  /*  must be B,S,I,L,F,D, else error */
+        static int NTsize = 0;
+	static int dims = 0;
+	static String className;
+
+	public ArrayDescriptor ( Object anArray ) throws HDFException {
+
+		Class tc = anArray.getClass();
+		if (tc.isArray() == false) {
+			/* exception: not an array */
+			 HDFException ex =
+		(HDFException)new HDFJavaException("ArrayDescriptor: not an array?: ");
+			throw(ex);
+		}
+
+		theClass = tc;
+
+		/* parse the type descriptor to discover the
+			shape of the array */
+		String ss = tc.toString();
+		theType = ss;
+		int n = 6;
+		dims = 0;
+		char c = ' ';
+		while (n < ss.length()) {
+			c = ss.charAt(n);
+			n++;
+			if (c == '[') {
+				dims++;
+			}
+		}
+
+		String css = ss.substring(ss.lastIndexOf('[')+1);
+		Class compC = tc.getComponentType();
+		String cs = compC.toString();
+		NT = c;
+		if (NT == 'B') {
+			NTsize = 1;
+		} else if (NT == 'S') {
+			NTsize = 2;
+		} else if ((NT == 'I') || (NT == 'F')) {
+			NTsize = 4;
+		} else if ((NT == 'J') || (NT == 'D')){
+			NTsize = 8;
+		} else if (css.startsWith("Ljava.lang.Byte")) {
+			NT='L';
+			className = "java.lang.Byte";
+			NTsize = 1;
+		} else if (css.startsWith("Ljava.lang.Short")) {
+			NT='L';
+			className = "java.lang.Short";
+			NTsize = 2;
+		} else if (css.startsWith("Ljava.lang.Integer")) {
+			NT='L';
+			className = "java.lang.Integer";
+			NTsize = 4;
+		} else if (css.startsWith("Ljava.lang.Float")) {
+			NT='L';
+			className = "java.lang.Float";
+			NTsize = 4;
+		} else if (css.startsWith("Ljava.lang.Double")) {
+			NT='L';
+			className = "java.lang.Double";
+			NTsize = 8;
+		} else if (css.startsWith("Ljava.lang.Long")) {
+			NT='L';
+			className = "java.lang.Long";
+			NTsize = 8;
+		} else if (css.startsWith("Ljava.lang.String")) {
+throw new HDFJavaException(new String("ArrayDesciptor: Error:  String array not supported yet"));
+		} else {
+			/* exception:  not a numeric type */
+throw new HDFJavaException(new String("Error:  array is not numeric? (type is "+css+")"));
+		}
+
+		/* fill in the table */
+		dimlen = new int [dims+1];
+		dimstart = new int [dims+1];
+		currentindex = new int [dims+1];
+		bytetoindex = new int [dims+1];
+		objs = new Object [dims+1];
+
+		Object o = anArray;
+		objs[0] = o;
+		dimlen[0]= 1;
+		dimstart[0] = 0;
+		currentindex[0] = 0;
+		int i;
+		for ( i = 1; i <= dims; i++) {
+			dimlen[i]= java.lang.reflect.Array.getLength((Object) o);
+			o = java.lang.reflect.Array.get((Object) o,0);
+			objs [i] = o;
+			dimstart[i] = 0;
+			currentindex[i] = 0;
+		}
+
+		int j;
+		int dd;
+		bytetoindex[dims] = NTsize;
+		for ( i = dims; i >= 0; i--) {
+			dd = NTsize;
+			for (j = i; j < dims; j++) {
+				dd *= dimlen[j + 1];
+			}
+			bytetoindex[i] = dd;
+		}
+
+		totalSize = bytetoindex[0];
+	}
+
+	public void dumpInfo()
+	{
+		System.out.println("Type: "+theType);
+		System.out.println("Class: "+theClass);
+		System.out.println("NT: "+NT+" NTsize: "+NTsize);
+		System.out.println("Array has "+dims+" dimensions ("+totalSize+" bytes)");
+		int i;
+		for (i = 0; i <= dims; i++) {
+			Class tc = objs[i].getClass();
+			String ss = tc.toString();
+			System.out.println(i+":  start "+dimstart[i]+": len "+dimlen[i]+" current "+currentindex[i]+" bytetoindex "+bytetoindex[i]+" object "+objs[i]+" otype "+ss);
+		}
+	}
+}
diff --git a/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFConstants.java b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFConstants.java
new file mode 100755
index 0000000..5209fb6
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFConstants.java
@@ -0,0 +1,312 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  This interface defines the values of constants defined
+ *  by the HDF 4.1 API.
+ * <p>
+ *  For details of the HDF libraries, see the HDF Documentation at:
+ *     <a href="http://hdf.ncsa.uiuc.edu">http://hdf.ncsa.uiuc.edu</a>
+ */
+public class HDFConstants
+{
+    /** FAIL */
+    public static final int FAIL = -1;
+
+    // file access code definitions
+    public static final int     DFACC_READ = 1;
+    public static final int     DFACC_WRITE= 2;
+    public static final int     DFACC_RDWR = 3;
+    public static final int     DFACC_CREATE=4;
+    public static final int     DFACC_RDONLY=DFACC_READ;
+    public static final int     DFACC_DEFAULT=000;
+    public static final int     DFACC_SERIAL=001;
+    public static final int     DFACC_PARALLEL=011;
+
+    // annotation type in HDF
+    public static final int     AN_DATA_LABEL  = 0;
+    public static final int     AN_DATA_DESC   = AN_DATA_LABEL + 1;
+    public static final int     AN_FILE_LABEL  = AN_DATA_LABEL + 2;
+    public static final int     AN_FILE_DESC   = AN_DATA_LABEL + 3;
+
+    // HDF Tag Definations
+
+    // HDF WILDCARD
+    public static final int     DFTAG_WILDCARD = 0;
+    public static final int     DFREF_WILDCARD = 0;
+
+    // File identifier
+    public static final int     DFTAG_FID = 100;
+
+    // File Description
+    public static final int     DFTAG_FD  = 101;
+
+    // Data Identifier Label
+    public static final int     DFTAG_DIL = 104;
+
+    // Data Identifier Annotation
+    public static final int     DFTAG_DIA = 105;
+
+    // 8-bits Raster image
+    public static final int     DFTAG_RI8  = 202;
+    public static final int     DFTAG_CI8  = 203;
+    public static final int     DFTAG_II8  = 204;
+
+    // 24-bits Raster image
+    public static final int     DFTAG_RI  = 302;
+    public static final int     DFTAG_CI  = 303;
+    public static final int     DFTAG_RIG = 306;
+
+    // SDS
+    public static final int     DFTAG_SD  = 702;
+    public static final int     DFTAG_SDG  = 700;
+    public static final int     DFTAG_NDG  = 720;
+    
+    // Vgroup or Vdata
+    public static final int     DFTAG_VH  = 1962;
+    public static final int     DFTAG_VS  = 1963;
+    public static final int     DFTAG_VG  = 1965;
+
+    /** pixel interlacing scheme */
+    public static final int MFGR_INTERLACE_PIXEL = 0;
+
+    /** line interlacing scheme */
+    public static final int MFGR_INTERLACE_LINE = MFGR_INTERLACE_PIXEL +1;
+
+    /** component interlacing scheme */ 
+    public static final int MFGR_INTERLACE_COMPONENT = MFGR_INTERLACE_PIXEL +2;
+
+    /** interlacing supported by the vset.*/
+    public static final int FULL_INTERLACE = 0;
+    public static final int NO_INTERLACE   = 1;
+
+    /** unsigned char */
+    public static final int DFNT_UCHAR8 = 3;
+    public static final int DFNT_UCHAR  = 3;
+
+    /** char */
+    public static final int DFNT_CHAR8  = 4;
+    public static final int DFNT_CHAR   = 4;
+
+    /** No supported by HDF */
+    public static final int DFNT_CHAR16 = 42;
+    public static final int DFNT_UCHAR16= 43;
+
+
+    /** float */
+    public static final int  DFNT_FLOAT32   =  5;
+    public static final int  DFNT_FLOAT     =  5 ;
+
+    //** double */
+    public static final int  DFNT_FLOAT64   =  6;
+    public static final int  DFNT_FLOAT128  =  7 ; 
+    public static final int  DFNT_DOUBLE    =  6  ;
+
+    /** 8-bit integer */
+    public static final int  DFNT_INT8      =  20;
+
+    /** unsigned 8-bit interger */
+    public static final int  DFNT_UINT8    =  21;
+
+    /** short */
+    public static final int  DFNT_INT16    =  22;
+
+    /** unsigned interger */
+    public static final int  DFNT_UINT16   =  23;
+
+    /** interger */
+    public static final int  DFNT_INT32    =  24;
+
+    /** unsigned interger */
+    public static final int  DFNT_UINT32   =  25;
+
+    /** No supported */
+    public static final int  DFNT_INT64    =  26;
+    public static final int  DFNT_UINT64   =  27;
+    public static final int  DFNT_INT128   =  28;
+    public static final int  DFNT_UINT128  =  30;
+    public static final int  DFNT_LITEND =  0x00004000;
+
+    public static final int DF_FORWARD  = 1;
+    public static final int  DFS_MAXLEN = 255;
+
+    public static final int COMP_NONE     =  0;
+    public static final int COMP_JPEG     =  2;
+    public static final int COMP_RLE      =  11;
+    public static final int COMP_IMCOMP   =  12;
+    public static final int COMP_CODE_NONE     =  0;
+    public static final int COMP_CODE_RLE     =  1;
+    public static final int COMP_CODE_NBIT     =  2;
+    public static final int COMP_CODE_SKPHUFF  =  3; 
+    public static final int COMP_CODE_DEFLATE  =  4;
+    public static final int COMP_CODE_INVALID  =  5;
+    public static final int COMP_MODEL_STDIO  =  0;
+
+    // Interlace schemes
+    public static final int DFIL_PIXEL  = 0;  /* Pixel Interlacing */
+    public static final int DFIL_LINE   = 1;  /* Scan Line Interlacing */
+    public static final int DFIL_PLANE  = 2;  /* Scan Plane Interlacing */
+
+    public static final int SD_FILL  = 0;  
+    public static final int SD_NOFILL  = 0x100;
+    public static final int SD_DIMVAL_BW_COMP  = 1;  
+    public static final int SD_DIMVAL_BW_INCOMP  = 0;
+
+    public static final int HDF_NONE  = 0x0;
+    public static final int HDF_CHUNK  = 0x1;
+    public static final int HDF_COMP  = 0x3;
+    public static final int HDF_NBIT  = 0x5;
+    public static final int MAX_VAR_DIMS =32;
+
+    //the names of the Vgroups created by the GR interface
+    public static final String GR_NAME = "RIG0.0";
+    public static final String RI_NAME = "RI0.0";
+    public static final String RIGATTRNAME = "RIATTR0.0N";
+    public static final String RIGATTRCLASS = "RIATTR0.0C";
+
+    // names of classes of the Vdatas/Vgroups created by the SD interface 
+    public static final String  HDF_ATTRIBUTE = "Attr0.0";
+    public static final String  HDF_VARIABLE = "Var0.0";
+    public static final String  HDF_DIMENSION = "Dim0.0";
+    public static final String  HDF_UDIMENSION = "UDim0.0";
+    public static final String  DIM_VALS = "DimVal0.0";
+    public static final String  DIM_VALS01 = "DimVal0.1";
+    public static final String  HDF_CHK_TBL = "_HDF_CHK_TBL_";
+    public static final String  HDF_CDF = "CDF0.0";
+
+    // names of data object types
+    public static final String ANNOTATION = "HDF_ANNOTATION";
+    public static final String RI8 = "HDF_RI8";
+    public static final String RI24 = "HDF_RI24";
+    public static final String GR = "HDF_GR";
+    public static final String SDS = "HDF_SDS";
+    public static final String VDATA = "HDF_VDATA";
+    public static final String VGROUP = "HDF_GROUP";
+
+    // data types represented by Strings
+    public static final String UCHAR8   = "UCHAR8";
+    public static final String CHAR8    = "CHAR8";
+    public static final String UCHAR16  = "UCHAR16";
+    public static final String CHAR16   = "CHAR16";
+    public static final String FLOAT32  = "FLOAT32";
+    public static final String FLOAT64  = "FLOAT64";
+    public static final String FLOAT128 = "FLOAT128";
+    public static final String INT8     = "INT8";
+    public static final String UINT8    = "UINT8";
+    public static final String INT16    = "INT16";
+    public static final String UINT16   = "UINT16";
+    public static final String INT32    = "INT32";
+    public static final String UINT32   = "UINT32";
+    public static final String INT64    = "INT64";
+    public static final String UINT64   = "UINT64";
+    public static final String INT128   = "INT128";
+    public static final String UINT128  = "UINT128";
+
+
+    /**
+     *  convert number type to string type
+     *  params type  the number representing the data type
+     *  return the string representing the data type
+     */
+    public static String getType(int type)
+    {
+        if   (type == HDFConstants.DFNT_UCHAR8) return HDFConstants.UCHAR8;
+        else if (type == HDFConstants.DFNT_CHAR8) return HDFConstants.CHAR8;
+        else if (type == HDFConstants.DFNT_UCHAR16) return HDFConstants.UCHAR16;
+        else if (type == HDFConstants.DFNT_CHAR16) return HDFConstants.CHAR16;
+        else if (type == HDFConstants.DFNT_FLOAT32) return HDFConstants.FLOAT32;
+        else if (type == HDFConstants.DFNT_FLOAT64) return HDFConstants.FLOAT64;
+        else if (type == HDFConstants.DFNT_FLOAT128) return HDFConstants.FLOAT128;
+        else if (type == HDFConstants.DFNT_INT8) return HDFConstants.INT8;
+        else if (type == HDFConstants. DFNT_UINT8) return HDFConstants.UINT8;
+        else if (type == HDFConstants.DFNT_INT16) return HDFConstants.INT16;
+        else if (type == HDFConstants.DFNT_UINT16) return HDFConstants.UINT16;
+        else if (type == HDFConstants.DFNT_INT32) return HDFConstants.INT32;
+        else if (type == HDFConstants.DFNT_UINT32) return HDFConstants.UINT32;
+        else if (type == HDFConstants.DFNT_INT64) return HDFConstants.INT64;
+        else if (type == HDFConstants.DFNT_UINT64) return HDFConstants.UINT64;
+        else if (type == HDFConstants.DFNT_INT128) return HDFConstants.INT128;
+        else if (type == HDFConstants.DFNT_UINT128) return HDFConstants.UINT128;
+        else return "Undefined Data Type";
+    }
+
+    /**
+     *  convert string type to number type
+     *  params type  the string representing the data type
+     *  return the integer representing the data type
+     */
+    public static int getType(String type)
+    {
+        if   (type.equalsIgnoreCase(HDFConstants.UCHAR8)) return HDFConstants.DFNT_UCHAR8;
+        else if (type.equalsIgnoreCase(HDFConstants.CHAR8)) return HDFConstants.DFNT_CHAR8;
+        else if (type.equalsIgnoreCase(HDFConstants.UCHAR16)) return HDFConstants.DFNT_UCHAR16;
+        else if (type.equalsIgnoreCase(HDFConstants.CHAR16)) return HDFConstants.DFNT_CHAR16;
+        else if (type.equalsIgnoreCase(HDFConstants.FLOAT32)) return HDFConstants.DFNT_FLOAT32;
+        else if (type.equalsIgnoreCase(HDFConstants.FLOAT64)) return HDFConstants.DFNT_FLOAT64;
+        else if (type.equalsIgnoreCase(HDFConstants.FLOAT128)) return HDFConstants.DFNT_FLOAT128;
+        else if (type.equalsIgnoreCase(HDFConstants.INT8)) return HDFConstants.DFNT_INT8;
+        else if (type.equalsIgnoreCase(HDFConstants. UINT8)) return HDFConstants.DFNT_UINT8;
+        else if (type.equalsIgnoreCase(HDFConstants.INT16)) return HDFConstants.DFNT_INT16;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT16)) return HDFConstants.DFNT_UINT16;
+        else if (type.equalsIgnoreCase(HDFConstants.INT32)) return HDFConstants.DFNT_INT32;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT32)) return HDFConstants.DFNT_UINT32;
+        else if (type.equalsIgnoreCase(HDFConstants.INT64)) return HDFConstants.DFNT_INT64;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT64)) return HDFConstants.DFNT_UINT64;
+        else if (type.equalsIgnoreCase(HDFConstants.INT128)) return HDFConstants.DFNT_INT128;
+        else if (type.equalsIgnoreCase(HDFConstants.UINT128)) return HDFConstants.DFNT_UINT128;
+        else return -1;
+    }
+
+    /**
+     *  gets the size of the data type in bytes,
+     *  e.g size of DFNT_FLOAT32 = 4
+     *
+     *  the size of the data type
+     */
+    public static int getTypeSize(int type)
+    {
+        int size = 0;
+
+        switch(type)
+        {
+            case HDFConstants.DFNT_UCHAR16:
+            case HDFConstants.DFNT_CHAR16:
+            case HDFConstants.DFNT_INT16:
+            case HDFConstants.DFNT_UINT16:
+                size = 2;
+                break;
+            case HDFConstants.DFNT_FLOAT32:
+            case HDFConstants.DFNT_INT32:
+            case HDFConstants.DFNT_UINT32:
+                size = 4;
+                break;
+            case HDFConstants.DFNT_FLOAT64:
+            case HDFConstants.DFNT_INT64:
+            case HDFConstants.DFNT_UINT64:
+                size = 8;
+                break;
+            case HDFConstants.DFNT_FLOAT128:
+            case HDFConstants.DFNT_INT128:
+            case HDFConstants.DFNT_UINT128:
+                size = 16;
+                break;
+            default:
+                size = 1;
+                break;
+        }
+
+        return size;
+    }
+
+}
diff --git a/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFException.java b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFException.java
new file mode 100755
index 0000000..45904cd
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFException.java
@@ -0,0 +1,61 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  The class HDFException returns errors from the HDF
+ *  library.
+ *  <p>
+ *  Two sub-classes of HDFException are defined:
+ *  <p>
+ *  <ol>
+ *  <li>
+ *   HDFLibraryException -- errors raised the HDF library code
+ *  <li>
+ *   HDFJavaException -- errors raised the HDF Java wrapper code
+ *  </ol>
+ *  <p>
+ *  These exceptions will be sub-classed to represent specific
+ *  error conditions, as needed.
+ *  <p>
+ *  The only specific exception currently defined is 
+ *  HDFNotImplementedException, indicating a function that is part
+ *  of the HDF API, but which cannot or will not be implemented
+ *  for Java.
+ */
+public class HDFException extends Exception {
+
+	
+	static public final String OutOfMemoryMessage="ERROR: HDF Library: Out of memory";
+	static public final String HDFExceptionMessage="ERROR: HDF Library Error"; 
+	static public final String HDFMessage="ERROR: Unknown HDF Error"; 
+
+	int HDFerror;
+	String msg;
+
+	public HDFException() {
+		HDFerror = 0;
+	}
+
+	public HDFException(String s) {
+		msg = s;
+	}
+
+	public HDFException(int err) {
+		HDFerror = err;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
diff --git a/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFJavaException.java b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFJavaException.java
new file mode 100755
index 0000000..1afafec
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFJavaException.java
@@ -0,0 +1,37 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  The class HDFJavaException returns errors from the Java
+ *  wrapper of theHDF library.
+ *  <p>
+ *  These errors include Java configuration errors, security
+ *  violations, and resource exhaustion.
+ */
+public class HDFJavaException extends HDFException {
+
+	String msg;
+
+	public HDFJavaException() {
+		HDFerror = 0;
+	}
+
+	public HDFJavaException(String s) {
+		msg = "HDFLibraryException: "+s;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
diff --git a/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFNativeData.java b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFNativeData.java
new file mode 100755
index 0000000..1f0b11b
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFNativeData.java
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+public class HDFNativeData
+{
+    public HDFNativeData() {}
+    public static native int[] byteToInt( byte[] data );
+    public static native float[] byteToFloat( byte[] data );
+    public static native short[] byteToShort( byte[] data );
+    public static native long[] byteToLong( byte[] data );
+    public static native double[] byteToDouble( byte[] data );
+
+    public static native int[] byteToInt( int start, int len, byte[] data );
+    public static int byteToInt( byte[] data, int start)
+    {
+        int []ival = new int[1];
+        ival = byteToInt(start,1,data);
+        return(ival[0]);
+    }
+
+    public static native short[] byteToShort( int start, int len, byte[] data );
+    public static short byteToShort( byte[] data, int start)
+    {
+        short []sval = new short[1];
+        sval = byteToShort(start,1,data);
+        return(sval[0]);
+    }
+
+    public static native float[] byteToFloat( int start, int len, byte[] data );
+    public static float byteToFloat( byte[] data, int start)
+    {
+        float []fval = new float[1];
+        fval = byteToFloat(start,1,data);
+        return(fval[0]);
+    }
+
+    public static native long[] byteToLong( int start, int len, byte[] data );
+    public static long byteToLong( byte[] data, int start)
+    {
+        long []lval = new long[1];
+        lval = byteToLong(start,1,data);
+        return(lval[0]);
+    }
+
+    public static native double[] byteToDouble( int start, int len, byte[] data );
+    public static double byteToDouble( byte[] data, int start)
+    {
+        double []dval = new double[1];
+        dval = byteToDouble(start,1,data);
+        return(dval[0]);
+    }
+
+    public static native byte[] intToByte( int start, int len, int[] data);
+    public static native byte[] shortToByte( int start, int len, short[] data);
+    public static native byte[] floatToByte( int start, int len, float[] data);
+    public static native byte[] longToByte( int start, int len, long[] data);
+    public static native byte[] doubleToByte( int start, int len, double[] data);
+
+    public static native byte[] byteToByte( byte data);
+    static byte[] byteToByte( Byte data){return byteToByte(data.byteValue());}
+    public static native byte[] intToByte( int data);
+    static byte[] intToByte( Integer data){return intToByte(data.intValue());}
+    public static native byte[] shortToByte(short data);
+    static byte[] shortToByte( Short data){return shortToByte(data.shortValue());}
+    public static native byte[] floatToByte( float data);
+    static byte[] floatToByte( Float data){return floatToByte(data.floatValue());};
+    public static native byte[] longToByte( long data);
+    static byte[] longToByte(Long data){ return longToByte(data.longValue());}
+    public static native byte[] doubleToByte( double data);
+    static byte[] doubleToByte( Double data){return doubleToByte(data.doubleValue());}
+
+    public Object byteToNumber( byte[] barray, Object obj)
+        throws HDFException
+    {
+        Class theClass = obj.getClass();
+        String type = theClass.getName();
+        Object retobj = null;
+
+        if (type.equals("java.lang.Integer")) {
+            int[] i = ncsa.hdf.hdflib.HDFNativeData.byteToInt(0,1,barray);
+            retobj = new Integer(i[0]);
+        } else  if (type.equals("java.lang.Byte")) {
+            retobj = new Byte(barray[0]);
+        } else  if (type.equals("java.lang.Short")) {
+            short[] f = ncsa.hdf.hdflib.HDFNativeData.byteToShort(0,1,barray);
+            retobj = new Short(f[0]) ;
+        } else  if (type.equals("java.lang.Float")) {
+            float[] f = ncsa.hdf.hdflib.HDFNativeData.byteToFloat(0,1,barray);
+            retobj = new Float(f[0]) ;
+        } else  if (type.equals("java.lang.Long")) {
+            long[] f = ncsa.hdf.hdflib.HDFNativeData.byteToLong(0,1,barray);
+            retobj = new Long(f[0]) ;
+        } else  if (type.equals("java.lang.Double")) {
+            double[] f = ncsa.hdf.hdflib.HDFNativeData.byteToDouble(0,1,barray);
+            retobj = new Double(f[0] );
+        } else {
+            /* exception: unsupprted type */
+            HDFException ex =
+            (HDFException)new HDFJavaException("byteToNumber: setfield bad type: "+obj+" "+type);
+            throw(ex);
+        }
+        return(retobj);
+    }
+
+    /**
+     *  Allocate a 1D array large enough to hold a multidimensional
+     *  array of 'datasize' elements of 'dataType' numbers.
+     *  This is called from ncsa.hdf.hdfobject.HDFGR and
+     *  ncsa.hdf.hdfobject.HDFSDS, and hdf.ncsa.io.ASCII2HDF
+     *
+     *  @param dataType  the type of the iamge data
+     *  @param datasize  the size of the image data array
+     *  @returns         an array of 'datasize' numbers of 'dataType
+     *
+     *  @see ncsa.hdf.hdfobject.HDFGR 
+     *  @see ncsa.hdf.hdfobject.HDFSDS
+     */
+public static Object defineDataObject(int dataType, int datasize)
+    {
+        Object data = null;
+
+        if ((dataType & HDFConstants.DFNT_LITEND) != 0) {
+          dataType -= HDFConstants.DFNT_LITEND;
+        }
+
+        switch(dataType)
+        {
+            case HDFConstants.DFNT_INT16:
+            case HDFConstants.DFNT_UINT16:
+                data = new short[datasize];
+                break;
+            case HDFConstants.DFNT_INT32:
+            case HDFConstants.DFNT_UINT32:
+                data = new int[datasize];
+                break;
+            case HDFConstants.DFNT_INT64:
+            case HDFConstants.DFNT_UINT64:
+                data = new long[datasize];
+                break;
+            case HDFConstants.DFNT_FLOAT32:
+                data = new float[datasize];
+                break;
+            case HDFConstants.DFNT_FLOAT64:
+                data = new double[datasize];
+                break;
+            default:
+            case HDFConstants.DFNT_CHAR:
+            case HDFConstants.DFNT_UCHAR8:
+            case HDFConstants.DFNT_UINT8:
+            case HDFConstants.DFNT_INT8:
+                data = new byte[datasize];
+                break;
+            
+        }
+        return data;
+    }
+}
diff --git a/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFNotImplementedException.java b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFNotImplementedException.java
new file mode 100755
index 0000000..73cf322
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/ncsa/hdf/hdflib/HDFNotImplementedException.java
@@ -0,0 +1,41 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * hdf/COPYING file.                                                        *
+ *                                                                          *
+ ****************************************************************************/
+
+package ncsa.hdf.hdflib;
+
+/**
+ *  <p>
+ *  HDFNotImplementedException indicates a function that is part
+ *  of the HDF API, but which cannot or will not be implemented
+ *  for Java.
+ *  <p>
+ *  For instance, C routines which take Unix FILE objects
+ *  as parameters are not appropriate for the Java interface
+ *  and will not be implemented.  These routines will raise
+ *  an HDFNotImplementedException.
+ */
+
+public class HDFNotImplementedException  extends HDFJavaException {
+
+	String msg;
+
+	public HDFNotImplementedException() {
+		HDFerror = 0;
+	}
+
+	public HDFNotImplementedException(String s) {
+		msg = "HDFJavaException: HDF function not implmented (yet): "+s;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
diff --git a/contrib/applications/nxplot/jnexus/src/org/nexusformat/AttributeEntry.java b/contrib/applications/nxplot/jnexus/src/org/nexusformat/AttributeEntry.java
new file mode 100755
index 0000000..e4bb0d6
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/org/nexusformat/AttributeEntry.java
@@ -0,0 +1,19 @@
+/**
+  * This is a little helper class which holds additional information about
+  * a dataset or global attribute.
+  *
+  * @author Mark Koennecke, October 2000
+  *
+  * @see NeXusFileInterface.
+  *
+  * copyright: see acompanying COPYRIGHT file.
+  */
+package org.nexusformat;
+
+public class AttributeEntry {
+    /**
+      * length is the length of the attribute.
+      * type is the number type of the attribute.
+      */
+  public int length, type;
+}
diff --git a/contrib/applications/nxplot/jnexus/src/org/nexusformat/NXlink.java b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NXlink.java
new file mode 100755
index 0000000..3dd12d7
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NXlink.java
@@ -0,0 +1,24 @@
+/**
+  * NXlink is a replacement for the structure holding the data necessary
+  * for doing a link in the NeXus-API. Consequently it is primitive.
+  *
+  * Mark Koennecke, October 2000
+  * 
+  * updated for Napi-2.0 with HDF-5
+  * Mark Koennecke, August 2001
+  *
+  * updated for NAPI-3.0 with XML
+  * Mark Koennecke, October 2004
+  *
+  * copyright: see accompanying COPYRIGHT file 
+  */
+package org.nexusformat;
+
+public class NXlink {
+    public int tag, ref, linkType;
+    public String targetPath;
+   
+    public NXlink(){
+       targetPath = new String("");
+    }
+}
diff --git a/contrib/applications/nxplot/jnexus/src/org/nexusformat/NeXusFileInterface.java b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NeXusFileInterface.java
new file mode 100755
index 0000000..0bb3553
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NeXusFileInterface.java
@@ -0,0 +1,346 @@
+/**
+  *
+  * The NeXus-API for Java. NeXus is an attempt to define a common data 
+  * format for org and x-ray diffraction. NeXus is built on top of the
+  * Hierarchical Data Format from NCSA. There exist already API's to
+  * NeXus files for F77, F90, C and C++. This is the interface definition
+  * for a Java API to NeXus files.
+  *
+  * Some changes to the API have been necessary however, due to the 
+  * different calling standards between C and Java. 
+  *
+  *
+  * @author Mark Koennecke, October 2000
+  *
+  * updated for NAPI-2.0, including HDF-5 support
+  * @author Mark Koennecke, August 2001
+  *
+  * updated for NXopengrouppath, NXopensourcepath, XML
+  * @author Mark Koennecke, December 2004
+  *
+  * copyright: see accompanying COPYRIGHT file
+  */
+package org.nexusformat;
+
+import java.util.Hashtable;
+
+public interface NeXusFileInterface {
+
+    // general functions
+    /**
+      * flush writes all previously unsaved data to disk. All directory
+      * searches are invalidated. Any open SDS is closed.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public void flush() throws NexusException;
+    /**
+      * finalize closes the file. It is supposed to be called by the
+      * garbage collector when the object is collected. As this happens
+      * at discretion of the garbage collector it is safer to call finalize
+      * yourself, when a NeXus file needs to be closed. Multiple calls to
+      * finalize do no harm.
+      * @exception Throwable because it is required by the definition of
+      * finalize. 
+      */
+    public void finalize() throws Throwable;
+    /**
+     * close the NeXus file. To make javalint and diamond happy
+     * @throws NexusException
+     */
+    public void close() throws NexusException;
+    // group functions
+    /** 
+      * makegroup creates a new group below the current group within
+      * the NeXus file hierarchy.
+      * @param name The name of the group to create.
+      * @param nxclass The classname of the group.
+      * @exception NexusException if an error occurs during this operation.
+      */ 
+    public void makegroup(String name, String nxclass) throws 
+                            NexusException;
+    /**
+      * opengroup opens the group name with class nxclass. 
+      * The group must exist, otherwise an exception is thrown. opengroup is
+      * similar to a cd name in a filesystem.
+      * @param name the name of the group to open.
+      * @param nxclass the classname of the group to open. 
+      * @exception NexusException when something goes wrong.
+      */   
+    public void opengroup(String name, String nxclass) throws 
+                             NexusException;
+    /**
+      * openpath opens groups and datsets accroding to the path string
+      * given. The path syntax follows unix conventions. Both absolute
+      * and relative paths are possible. All objects of the path must
+      * exist.
+      * @param path The path string
+      * @exception NexusException when something goes wrong.
+      */   
+    public void openpath(String path) throws 
+                           NexusException;
+    /**
+      * opengrouppath opens groups and datsets accroding to the path string
+      * given. The path syntax follows unix conventions. Both absolute
+      * and relative paths are possible. All objects of the path must
+      * exist. This function stops int the last group.
+      * @param path The path string
+      * @exception NexusException when something goes wrong.
+      */   
+    public void opengrouppath(String path) throws 
+                           NexusException;
+    /**
+      * closegroup closes access to the current group and steps down one
+      * step in group hierarchy.
+      * @exception NexusException when an HDF error occurs during this
+      * operation.
+      */ 
+    public void closegroup() throws 
+                             NexusException;
+
+    // data set handling
+    /**
+      * makedata creates a new dataset with the specified characteristics 
+      * in the current group.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. The first dimension can be -1 which
+      * means it is an unlimited dimension.
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void makedata(String name, int type, int rank, int dim[]) 
+	throws NexusException;
+    /**
+      * compmakedata creates a new dataset with the specified characteristics 
+      * in the current group. This data set will be compressed.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. The first dimension can be -1 which
+      * means it is an unlimited dimension.
+      * @param compression_type determines the compression type. 
+      * @param iChunk With HDF-5, slabs can be written to compressed data 
+      * sets. The size of these slabs is specified through the chunk array.
+      * This must have the rank values for the size of the chunk to
+      * be written in each dimension. 
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void compmakedata(String name, int type, int rank, int dim[],
+                             int compression_type, int iChunk[]) throws
+	                   NexusException; 
+    /**
+      * opendata opens an existing dataset for access. For instance for 
+      * reading or writing.
+      * @param name The name of the dataset to open.
+      * @exception NexusException when the dataset does not exist or 
+      * something else is wrong.
+      */
+    public void opendata(String name)throws 
+                           NexusException;
+    /**
+      * closedata closes an opened dataset. Then no further access is 
+      * possible without a call to opendata.
+      * @exception NexusException when an HDF error occurrs.
+      */
+    public void closedata() throws
+                           NexusException;
+    /**
+      * causes the currently open dataset to be compressed on file.
+      * This must be called after makedata and before writing to the
+      * dataset.
+      * @param compression_type determines the type of compression 
+      * to use.
+      * @exception NexusException when no dataset is open or an HDF error 
+      * occurs.
+      */ 
+    public void compress(int compression_type) throws 
+                           NexusException;
+
+    // data set reading
+    /**
+      * getdata reads the data from an previously openend dataset into
+      * array.
+      * @param array An n-dimensional array of the appropriate number
+      * type for the dataset. Make sure to have the right type and size
+      * here.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getdata(Object arrary)throws 
+                          NexusException;
+    /**
+      * getslab reads a subset of a large dataset into array.
+      * @param start An array of dimension rank which contains the start 
+      * position in the dataset from where to start reading.
+      * @param size An array of dimension rank which contains the size
+      * in each dimension of the data subset to read.
+      * @param array An array for holding the returned data values.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getslab(int start[], int size[],Object array)throws
+                          NexusException;
+    /**
+      * getattr retrieves the data associated with the attribute 
+      * name. 
+      * @param name The name of the attribute.
+      * @param data an array with sufficient space for holding the attribute 
+      * data.
+      * @param args An integer array holding the number of data elements
+      * in data as args[0], and the type as args[1]. Both values will be
+      * updated while reading.
+      * @exception NexusException when either an HDF error occurs or 
+      * the attribute could not be found.
+      */
+    public void getattr(String name,Object data, int args[])throws
+                          NexusException;
+
+    // data set writing
+    /**
+      * putdata writes the data from array into a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @exception NexusException when an HDF error occurs.
+      */
+    public void putdata(Object array) throws 
+	                  NexusException;
+    /**
+      * putslab writes a subset of a larger dataset to a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @param start An integer array of dimension rank which holds the
+      * startcoordinates of the data subset in the larger dataset.
+      * @param size An integer array of dimension rank whidh holds the
+      * size in each dimension of the data subset to write.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public void putslab(Object array, int start[], int size[]) throws
+                          NexusException;
+    /**
+      * putattr adds a named attribute to a previously opened dataset or
+      * a global attribute if no dataset is open.
+      * @param name The name of the attribute.
+      * @param array The data of the attribute.
+      * @param iType The number type of the attribute.
+      * @exception NexusException if an HDF error occurs.
+      */  
+    public void putattr(String name, Object array, int iType) throws
+                          NexusException;
+
+    // inquiry
+    /**
+      * getinfo retrieves information about a previously opened dataset.
+      * @param iDim An array which will be filled with the size of
+      * the dataset in each dimension.
+      * @param args An integer array which will hold more information about
+      * the dataset after return. The fields: args[0] is the rank, args[1] is
+      * the number type.
+      * @exception NexusException when  an HDF error occurs.
+      */ 
+    public void getinfo(int iDim[], int args[]) throws 
+                          NexusException;
+    /**
+     * setnumberformat sets the number format for printing number when
+     * using the XML-NeXus format. For HDF4 and HDF5 this is ignored.
+     * If a dataset is open, the format for the dataset is set, if none 
+     * is open the default setting for the number type is changed.
+     * The format must be a ANSII-C language format string.
+     * @param type The NeXus type to set the format for. 
+     * @param format The new format to use.
+     */
+    public void setnumberformat(int type, String format) 
+	throws NexusException;
+    /**
+      * groupdir will retrieve the content of the currently open vGroup.
+      * groupdir is similar to an ls in unix. 
+      * @return A Hashtable  which will hold the names of the items in 
+      * the group as keys and the NeXus classname for vGroups or the 
+      * string 'SDS' for datasets as values. 
+      * @exception NexusException if an HDF error occurs
+      */
+    public Hashtable groupdir()throws
+                          NexusException;
+    /**
+      * attrdir returns the attributes of the currently open dataset or
+      * the file global attributes if no dataset is open.
+      * @return A Hashtable which will hold the names of the attributes
+      * as keys. For each key there is an AttributeEntry class as value.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public Hashtable attrdir()throws
+                          NexusException;
+    
+    // linking 
+    /**
+      * getgroupID gets the data necessary for linking the current vGroup
+      * somewhere else.
+      * @return A NXlink object holding the link data.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public NXlink getgroupID() throws
+                          NexusException;
+    /**
+      * getdataID gets the data necessary for linking the current dataset
+      * somewhere else.
+      * @return A NXlink object holding the link data.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public NXlink getdataID()throws
+                          NexusException;
+    /**
+      * makelink links the object described by target into the current
+      * vGroup.
+      * @param target The Object to link into the current group.
+      * @exception NexusException if an error occurs.
+      */
+    public void   makelink(NXlink target)throws
+                          NexusException;     
+    /**
+      * makenamedlink links the object described by target into the current
+      * vGroup. The object will have a new name in the group into which it is 
+      * linked
+      * @param target The Object to link into the current group.
+      * @param name The name of this object in the current group
+      * @exception NexusException if an error occurs.
+      */
+    public void   makenamedlink(String name, NXlink target)throws
+                          NexusException;     
+    /**
+      * opensourcepath opens the group from which the current item was linked
+      * Returns an error if the current item is not linked.
+      * @exception NexusException if an error occurs.
+      */
+    public void   opensourcepath()throws
+                          NexusException;     
+    /**
+     * inquirefile inquires which file we are currently in. This is
+     * a support function for external linking
+     * @return The current file
+     * @throws NexusException when things are wrong
+     */
+    public String inquirefile() throws NexusException;
+    /** 
+     * linkexternal links group name, nxclass to the URL nxurl
+     * @param name The name of the vgroup to link to
+     * @apram nxcall The class name of the linked vgroup
+     * @param nxurl The URL to the linked external file
+     * @throws NexusException if things are wrong
+     */
+    public void linkexternal(String name, String nxclass, String nxurl) throws NexusException;
+    /**
+     * nxisexternalgroup test the group name, nxclass if it is linked externally.
+     * @param name of the group to test
+     * @param  nxclass class of the group to test
+     * @return null when the group is not linked, else a string giving the URL of the
+     * linked file.
+     * @throws NexusException if things are wrong
+     */
+    public String isexternalgroup(String name, String nxclass) throws NexusException;
+}
+  
diff --git a/contrib/applications/nxplot/jnexus/src/org/nexusformat/NexusException.java b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NexusException.java
new file mode 100755
index 0000000..ce6fec8
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NexusException.java
@@ -0,0 +1,39 @@
+/**
+  * NexusException is thrown whenever an error occurs in the NeXus Java API
+  *
+  * Mark Koennecke, October 2000
+  *
+  * copyright: see accompanying COPYRIGHT file.  
+  */ 
+package org.nexusformat;
+
+public class NexusException extends Exception {
+
+	
+	static public final String OutOfMemoryMessage= 
+                        "ERROR: NeXus-API: Out of memory";
+	static public final String NexusExceptionMessage= 
+                        "ERROR: NeXus-API Error"; 
+	static public final String NeXusMessage=
+                        "ERROR: Unknown NeXus-API Error"; 
+
+	int HDFerror;
+	String msg;
+
+	public NexusException() {
+		HDFerror = 0;
+	}
+
+	public NexusException(String s) {
+		msg = s;
+	}
+
+	public NexusException(int err) {
+		HDFerror = err;
+	}
+
+	public String getMessage() {
+		return msg;
+	}
+}
+
diff --git a/contrib/applications/nxplot/jnexus/src/org/nexusformat/NexusFile.java b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NexusFile.java
new file mode 100755
index 0000000..70e9d89
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/src/org/nexusformat/NexusFile.java
@@ -0,0 +1,780 @@
+/**
+  *
+  * The NeXus-API for Java. NeXus is an attempt to define a common data 
+  * format for org and x-ray diffraction. NeXus is built on top of the
+  * Hierarchical Data Format from NCSA. There exist already API's to
+  * NeXus files for F77, F90, C and C++. This is an implementation of
+  * a Java NeXus API using native methods.
+  *
+  * Some changes to the API have been necessary however, due to the 
+  * different calling standards between C and Java. 
+  *
+  *
+  * @author Mark Koennecke, October 2000
+  *
+  * Updated: Mark Koennecke, April 2006
+  *
+  * copyright: see accompanying COPYRIGHT file
+  */
+package org.nexusformat;
+
+import java.util.Hashtable;
+import java.io.File;
+import ncsa.hdf.hdflib.HDFArray;
+import ncsa.hdf.hdflib.HDFException;
+import ncsa.hdf.hdflib.HDFConstants;
+
+public class  NexusFile implements NeXusFileInterface {
+
+    // constants 
+    /**
+      * possible access codes, @see #NexusFile.
+      */
+    public final static int NXACC_READ = 1;
+    public final static int NXACC_RDWR = 2;
+    public final static int NXACC_CREATE = 3;
+    public final static int NXACC_CREATE4 = 4;
+    public final static int NXACC_CREATE5 = 5;
+    public final static int NXACC_CREATEXML = 6;
+    public final static int NXACC_NOSTRIP = 128;
+    
+    /**
+      * constant denoting an unlimited dimension.
+      */
+    public final static int NX_UNLIMITED = -1;
+
+    /**
+      * constants for number types. @see #makedata, @see #putattr 
+      * and others.
+      */
+    public final static int NX_FLOAT32 = 5; 
+    public final static int NX_FLOAT64 = 6; 
+    public final static int NX_INT8 = 20; 
+    public final static int NX_BINARY = 20;
+    public final static int NX_UINT8 = 21; 
+    public final static int NX_BOOLEAN = 21; 
+    public final static int NX_INT16 = 22; 
+    public final static int NX_UINT16 = 23; 
+    public final static int NX_INT32 = 24; 
+    public final static int NX_UINT32 = 25; 
+    public final static int NX_INT64 = 26; 
+    public final static int NX_UINT64 = 27; 
+    public final static int NX_CHAR   = 4;
+
+    /**
+      * constants for compression schemes @see #compress
+      */
+    public final static int NX_COMP_NONE = 100;
+    public final static int NX_COMP_LZW =  200;
+    public final static int NX_COMP_RLE =  300;
+    public final static int NX_COMP_HUF =  400;
+
+    /**
+      * Maximum name length, must be VGNAMELENMAX in hlimits.h
+      */
+    protected final static int MAXNAMELEN = 64;
+
+    /*
+       This code takes care of loading the static library required for
+       this class to work properly. The algorithm first looks for a 
+       property org.nexusformat.JNEXUSLIB and loads that file if available,
+       else it tries to locate the library in the system shared library 
+       path.
+    */
+     static
+     {
+        String filename = null;   
+        filename = System.getProperty("org.nexusformat.JNEXUSLIB",null);
+        if ((filename != null) && (filename.length() > 0))
+        {
+            File hdfdll = new File(filename);
+            if (hdfdll.exists() && hdfdll.canRead() && hdfdll.isFile()) 
+	    {
+                System.load(filename);
+             } else {
+                 throw (new UnsatisfiedLinkError("Invalid JNEXUS library"));
+             }
+         }
+         else {
+            System.loadLibrary("jnexus");
+         }
+      }
+
+    /**
+      * This is the handle to the NeXus file handle.
+      */
+    protected int handle;
+
+    // Construction
+    // native methods for this section
+    protected native int  init(String filename, int access);
+    protected native void close(int handle);
+    protected native int  nxflush(int handle);
+
+    /**
+      * constructs a new NexusFile Object.
+      * @param filename The name of the NeXus file to access.
+      * @param access. The access mode for the file. Can only be one
+      * of the predefined NeXus access code NXACC.... These are:
+      * <dl>
+      * <dt>NXACC_CREATE
+      * <DD>or creating a new file.
+      * <DT>NXACC_RDWR
+      * <DD>For opening an existing file for modification or appending 
+      * data.
+      * <DT>NXACC_READ
+      * <DD>For opening a file for reading.
+      * </dl>
+      * <DT>NXACC_NOSTRIP
+      * <DD>To keep leading and trailing whitespace on strings
+      * </dl>
+      * @exception NexusException when the file could not be found or
+      * an HDF error occurred.
+      */
+    public NexusFile(String filename, int access) throws NexusException 
+    {
+         handle = init(filename,access);
+         if(handle < 0){
+	    throw new NexusException("Failed to open " + filename);
+	 }
+    }
+    /**
+      * flushes all pending data to disk. Closes any open SDS's.
+      */
+    public void flush() throws NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	 handle = nxflush(handle);
+    }
+    /**
+     * close the NeXus file. To make javalint and diamond happy
+     * @throws NexusException
+     */
+    public void close() throws NexusException{
+        if(handle  >= 0)
+        {
+           close(handle);
+           handle = -1;
+        }
+    }
+    
+    /**
+      * removes all NeXus file data structures and closes the file. This 
+      * function should automatically be called by the Java garbage 
+      * collector whenever the NexusFile object falls into disuse. However
+      * the time when this is done is left to the garbage collector. My
+      * personal experience is that finalize might never be called. I
+      * suggest, to call finalize yourself when you are done with the 
+      * NeXus file. finalize makes sure that multiple invocations will not
+      * do any harm.
+      */   
+    public void finalize() throws Throwable 
+    {
+    	close();
+    }
+
+
+    // group functions
+    //native methods for this section
+    protected native void nxmakegroup(int handle, String name, String nxclass);
+    protected native void nxopengroup(int handle, String name, String nxclass);
+    protected native void nxopenpath(int handle, String path);
+    protected native void nxopengrouppath(int handle, String path);
+    protected native void nxclosegroup(int handle);
+
+    /** 
+      * makegroup creates a new group below the current group within
+      * the NeXus file hierarchy.
+      * @param name The name of the group to create.
+      * @param nxclass The classname of the group.
+      * @exception NexusException if an error occurs during this operation.
+      */ 
+    public void makegroup(String name, String nxclass) throws 
+                            NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxmakegroup(handle, name, nxclass);
+    }
+    /**
+      * opengroup opens the group name with class nxclass. 
+      * The group must exist, otherwise an exception is thrown. opengroup is
+      * similar to a cd name in a filesystem.
+      * @param name the name of the group to open.
+      * @param nxclass the classname of the group to open. 
+      * @exception NexusException when something goes wrong.
+      */   
+    public void opengroup(String name, String nxclass) throws 
+                             NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxopengroup(handle, name, nxclass);
+    }
+    /**
+      * openpath opens groups and datsets accroding to the path string
+      * given. The path syntax follows unix conventions. Both absolute
+      * and relative paths are possible. All objects of the path must
+      * exist.
+      * @param path The path string
+      * @exception NexusException when something goes wrong.
+      */   
+    public void openpath(String path) throws 
+                         NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxopenpath(handle,path);
+    }
+    /**
+      * opengrouppath opens groups and datsets accroding to the path string
+      * given. The path syntax follows unix conventions. Both absolute
+      * and relative paths are possible. All objects of the path must
+      * exist. This opens only until the last group.
+      * @param path The path string
+      * @exception NexusException when something goes wrong.
+      */   
+    public void opengrouppath(String path) throws 
+                         NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxopengrouppath(handle,path);
+    }
+
+    /**
+      * closegroup closes access to the current group and steps down one
+      * step in group hierarchy.
+      * @exception NexusException when an HDF error occurs during this
+      * operation. 
+      */
+    public void closegroup() throws 
+                             NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxclosegroup(handle);
+    }
+
+    // data set handling
+    // native methods for this section
+    protected native void nxmakedata(int handle, String name, int type,
+                                  int rank, int dim[]);
+    protected native void nxmakecompdata(int handle, String name, int type,
+                                  int rank, int dim[], int iCompress, 
+                                  int iChunk[]);
+    protected native void nxopendata(int handle, String name);
+    protected native void nxclosedata(int handle);
+    protected native void nxcompress(int handle, int compression_type);
+    /**
+      * compmakedata creates a new dataset with the specified characteristics 
+      * in the current group. This data set will be compressed.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. The first dimension can be -1 which
+      * means it is an unlimited dimension.
+      * @param compression_type determines the compression type. 
+      * @param iChunk With HDF-5, slabs can be written to compressed data 
+      * sets. The size of these slabs is specified through the chunk array.
+      * This must have the rank values for the size of the chunk to
+      * be written in each dimension. 
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void compmakedata(String name, int type, int rank, int dim[],
+                             int compression_type, int iChunk[]) throws
+			     NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(type);
+        switch(compression_type) {
+	case NexusFile.NX_COMP_NONE:
+	case NexusFile.NX_COMP_LZW:
+	    break;
+	default:
+	    throw new NexusException("Invalid compression code requested");
+
+	}
+	nxmakecompdata(handle,name,type,rank,dim,compression_type, iChunk);
+    }
+
+    /**
+      * makedata creates a new dataset with the specified characteristics 
+      * in the current group.
+      * @param name The name of the dataset.
+      * @param type The number type of the dataset. Usually a constant from
+      * a selection of values.
+      * @param rank The rank or number of dimensions of the dataset.
+      * @param dim An array containing the length of each dimension. dim must
+      * have at least rank entries. The first dimension can be -1 which
+      * means it is an unlimited dimension.
+      * @exception NexusException when the dataset could not be created.
+      */ 
+    public void makedata(String name, int type, int rank, int dim[]) throws
+	                   NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(type);
+	nxmakedata(handle,name,type,rank,dim);
+    }
+    /**
+      * opendata opens an existing dataset for access. For instance for 
+      * reading or writing.
+      * @param name The name of the dataset to open.
+      * @exception NexusException when the dataset does not exist or 
+      * something else is wrong.
+      */
+    public void  opendata(String name)throws 
+                           NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxopendata(handle,name);
+    }
+    /**
+      * closedata closes an opened dataset. Then no further access is 
+      * possible without a call to opendata.
+      * @exception NexusException when an HDF error occurrs.
+      */
+    public void closedata() throws
+                           NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxclosedata(handle);
+    }
+    /**
+      * causes the currently open dataset to be compressed on file.
+      * This must be called after makedata and before writing to the
+      * dataset.
+      * @param compression_type determines the type of compression 
+      * to use.
+      * @exception NexusException when no dataset is open or an HDF error 
+      * occurs.
+      */ 
+    public void compress(int compression_type) throws 
+                           NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        switch(compression_type) {
+	case NexusFile.NX_COMP_NONE:
+	case NexusFile.NX_COMP_LZW:
+	case NexusFile.NX_COMP_RLE:
+	case NexusFile.NX_COMP_HUF:
+	    break;
+	default:
+	    throw new NexusException("Invalid compression code requested");
+
+	}
+	nxcompress(handle,compression_type);
+    }
+
+    // data set reading
+    // native methods in this section
+    protected native void nxgetdata(int handle, byte bdata[]);
+    protected native void nxgetslab(int handle, int Start[], int size[],
+                                    byte bdata[]);
+    protected native void nxgetattr(int handle, String name, byte bdata[],
+                                    int args[]);
+    /**
+      * getdata reads the data from an previously openend dataset into
+      * array.
+      * @param array An n-dimensional array of the appropriate number
+      * type for the dataset. Make sure to have the right type and size
+      * here.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getdata(Object array)throws 
+                          NexusException
+    {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetdata(handle,bdata);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+    /**
+      * getslab reads a subset of a large dataset into array.
+      * @param start An array of dimension rank which contains the start 
+      * position in the dataset from where to start reading.
+      * @param size An array of dimension rank which contains the size 
+      * of the dataset subset in each dimension to read.
+      * @param array An array for holding the returned data values.
+      * @exception NexusException when either an HDF error occurs or 
+      * no dataset is open or array is not of the right type to hold
+      * the data.
+      */
+    public void getslab(int start[], int size[],Object array)throws
+                          NexusException
+    {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetslab(handle,start,size,bdata);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+    /**
+      * getattr retrieves the data associated with the attribute 
+      * name. 
+      * @param name The name of the attribute.
+      * @param array an array with sufficient space for holding the attribute 
+      * data.
+      * @param args An integer array of dimension rank which holds the
+      * length of the array as first value and the type as the last
+      * value. Both values will be updated during reading.
+      * @exception NexusException when either an HDF error occurs or 
+      * the attribute could not be found.
+      */
+    public void getattr(String name,Object array, int args[])throws
+                          NexusException
+    {
+        byte bdata[];
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        checkType(args[1]);
+        try{
+	    HDFArray ha = new HDFArray(array);
+            bdata = ha.emptyBytes();
+            nxgetattr(handle, name, bdata,args);
+            array = ha.arrayify(bdata);
+	 }catch(HDFException he) {
+           throw new NexusException(he.getMessage());
+	 }
+    }
+
+    // data set writing
+    // native methods for this section
+    protected native void nxputdata(int handle, byte array[]); 
+    protected native void nxputslab(int handle, byte array[], 
+                                    int start[],int size[]); 
+    protected native void nxputattr(int handle, String name,
+                                    byte array[], int type); 
+
+    /**
+      * putdata writes the data from array into a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @exception NexusException when an HDF error occurs.
+      */
+    public void putdata(Object array) throws 
+	                  NexusException
+    {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       try{
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       }catch(HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputdata(handle,data);
+       data = null;
+    }
+    /**
+      * putslab writes a subset of a larger dataset to a previously opened
+      * dataset.
+      * @param array The data to write.
+      * @param start An integer array of dimension rank which holds the
+      * startcoordinates of the data subset in the larger dataset.
+      * @param size An integer array of dimension rank which holds the
+      * size in each dimension of the data subset to write.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public void putslab(Object array, int start[], int size[]) throws
+                          NexusException
+    {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       try{
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       }catch(HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputslab(handle,data,start,size);
+       data = null;
+    }
+    /**
+      * putattr adds a named attribute to a previously opened dataset or
+      * a global attribute if no dataset is open.
+      * @param name The name of the attribute.
+      * @param array The data of the attribute.
+      * @param iType The number type of the attribute.
+      * @exception NexusException if an HDF error occurs.
+      */  
+    public void putattr(String name, Object array, int iType) throws
+                          NexusException
+    {
+       byte data[];
+
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       checkType(iType);
+       try{
+           HDFArray ha =  new HDFArray(array);
+           data = ha.byteify();
+           ha = null;
+       }catch(HDFException he) {
+	   throw new NexusException(he.getMessage());
+       }
+       nxputattr(handle,name,data,iType);
+       data = null;
+    }
+
+    // inquiry
+    //native methods for this section
+    protected native void nxgetinfo(int handle, int iDim[], int args[]);
+    protected native void nxsetnumberformat(int handle, int type, 
+					    String format);
+    protected native int nextentry(int handle, String names[]);
+    protected native int nextattr(int handle, String names[], int args[]);
+    /**
+     * setnumberformat sets the number format for printing number when
+     * using the XML-NeXus format. For HDF4 and HDF5 this is ignored.
+     * If a dataset is open, the format for the dataset is set, if none 
+     * is open the default setting for the number type is changed.
+     * The format must be a ANSII-C language format string.
+     * @param type The NeXus type to set the format for. 
+     * @param format The new format to use.
+     */
+    public void setnumberformat(int type, String format) 
+	throws NexusException{
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       nxsetnumberformat(handle,type,format);
+    }
+    /**
+      * getinfo retrieves information about a previously opened dataset.
+      * @param iDim An array which will be filled with the size of
+      * the dataset in each dimension.
+      * @param args An integer array which will hold more information about
+      * the dataset after return. The fields: args[0] is the rank, args[1] is
+      * the number type.
+      * @exception NexusException when  an HDF error occurs.
+      */ 
+    public void getinfo(int iDim[], int args[]) throws 
+                          NexusException
+    {
+       if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+       nxgetinfo(handle,iDim,args);
+    }
+    /**
+      * groupdir will retrieve the content of the currently open vGroup.
+      * groupdir is similar to an ls in unix. 
+      * @return A Hashtable  which will hold the names of the items in 
+      * the group as keys and the NeXus classname for vGroups or the 
+      * string 'SDS' for datasets as values. 
+      * @exception NexusException if an HDF error occurs
+      */
+    public Hashtable groupdir()throws
+                          NexusException
+    {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        Hashtable h = new Hashtable();
+        String names[] = new String[2];
+        int i;
+        while(nextentry(handle,names) != -1)
+	{
+           h.put(names[0],names[1]);
+        }
+        return h;
+    }
+    /**
+      * attrdir returns the attributes of the currently open dataset or
+      * the file global attributes if no dataset is open.
+      * @return A Hashtable which will hold the names of the attributes
+      * as keys. For each key there is an AttributeEntry class as value.
+      * @exception NexusException when an HDF error occurs.
+      */ 
+    public Hashtable attrdir()throws
+                          NexusException
+    {
+        int args[] = new int[2];
+        AttributeEntry at;
+        String names[] = new String[1];
+
+        Hashtable h = new Hashtable();
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+        while(nextattr(handle,names,args) != -1)
+	{
+          at = new AttributeEntry();
+          at.length = args[0];
+          at.type   = args[1];
+          h.put(names[0], at);
+        } 
+        return h;
+    }
+    
+    // linking 
+    // native methods for this section
+    protected native void nxgetgroupid(int handle, NXlink link);
+    protected native void nxgetdataid(int handle, NXlink link);
+    protected native void nxmakelink(int handle, NXlink target); 
+    protected native void nxmakenamedlink(int handle, String name, NXlink target); 
+    protected native void nxopensourcepath(int handle); 
+    /**
+      * getgroupID gets the data necessary for linking the current vGroup
+      * somewhere else.
+      * @return A NXlink class holding the link data.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public NXlink getgroupID() throws
+                          NexusException
+    {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      NXlink l = new NXlink();
+      nxgetgroupid(handle,l);
+      return l;
+    }
+    /**
+      * getdataID gets the data necessary for linking the current dataset
+      * somewhere else.
+      * @return A NXlink class holding the link data.
+      * @exception NexusException if an HDF error occurs.
+      */
+    public NXlink getdataID()throws
+                          NexusException
+    {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      NXlink l = new NXlink();
+      nxgetdataid(handle,l);
+      return l;
+    }
+    /**
+      * makelink links the object described by target into the current
+      * vGroup.
+      * @param target The Object to link into the current group.
+      * @exception NexusException if an error occurs.
+      */
+    public void   makelink(NXlink target)throws
+                          NexusException
+    {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      nxmakelink(handle,target);
+    }
+    /**
+      * makenamedlink links the object described by target into the current
+      * vGroup. The object will have a new name in the group into which it is 
+      * linked
+      * @param target The Object to link into the current group.
+      * @param name The name of this object in the current group
+      * @exception NexusException if an error occurs.
+      */
+    public void   makenamedlink(String name, NXlink target)throws
+	NexusException {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      nxmakenamedlink(handle,name, target);
+    }     
+
+    /**
+      * opensourcepath opens the group from which the current item was linked
+      * Returns an error if the current item is not linked.
+      * @exception NexusException if an error occurs.
+      */
+    public void   opensourcepath()throws
+                          NexusException
+    {
+      if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+      nxopensourcepath(handle);
+    }
+	
+
+    /**
+      * checkType verifies if a parameter is a valid NeXus type code. 
+      * If not an exception is thrown.
+      * @param type The type value to check.
+      * @exception NexusException if the the type is no known type value
+      */
+    private void checkType(int type) throws NexusException
+    {
+	switch(type) {
+	case NexusFile.NX_INT8:
+	case NexusFile.NX_UINT8:
+        case NexusFile.NX_CHAR:
+	case NexusFile.NX_INT16:
+	case NexusFile.NX_UINT16:
+	case NexusFile.NX_INT32:
+	case NexusFile.NX_UINT32:
+	case NexusFile.NX_FLOAT32:
+	case NexusFile.NX_FLOAT64:
+	    break;
+        default:
+	    throw new NexusException("Illegal number type requested");
+        }
+    } 
+
+    // external file interface
+    // native methods for this section
+    protected native void nxinquirefile(int handle, String names[]);
+    protected native void nxlinkexternal(int handle, String name, String nxclass, String nxurl);
+    protected native int nxisexternalgroup(int handle, String name, String nxclass, String nxurl[]); 
+    /**
+     * inquirefile inquires which file we are currently in. This is
+     * a support function for external linking
+     * @return The current file
+     * @throws NexusException when things are wrong
+     */
+    public String inquirefile() throws NexusException {
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	String names[] = new String[1];
+	nxinquirefile(handle,names);
+	return names[0];
+    }
+    /** 
+     * linkexternal links group name, nxclass to the URL nxurl
+     * @param name The name of the vgroup to link to
+     * @apram nxcall The class name of the linked vgroup
+     * @param nxurl The URL to the linked external file
+     * @throws NexusException if things are wrong
+     */
+    public void linkexternal(String name, String nxclass, String nxurl) throws NexusException{
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	nxlinkexternal(handle,name,nxclass,nxurl);
+    }
+    /**
+     * nxisexternalgroup test the group name, nxclass if it is linked externally.
+     * @param name of the group to test
+     * @param  nxclass class of the group to test
+     * @return null when the group is not linked, else a string giving the URL of the
+     * linked file.
+     * @throws NexusException if things are wrong
+     */
+    public String isexternalgroup(String name, String nxclass) throws NexusException{
+        if(handle < 0) throw new NexusException("NAPI-ERROR: File not open");
+	String nxurl[] = new String[1];
+
+	int status = nxisexternalgroup(handle,name,nxclass,nxurl);
+	if(status == 1){
+	    return nxurl[0];
+	} else {
+	    return null;
+	}
+    }
+
+    /**
+      * debugstop is a debugging helper function which goes into an 
+      * endless loop in the dynamic link library. Then a unix debugger
+      * may attach to the running java process using the pid, interrupt,
+      * set the loop variable to leave the loop, set a new breakpoint and
+      * continue debugging. This works with ladebug on DU40D. This is an
+      * developer support routine and should NEVER be called in normal
+      * code. 
+      */
+    public native void debugstop();
+}
+  
+
+
+
+
+
+
+
+
diff --git a/contrib/applications/nxplot/jnexus/szlibdll.dll b/contrib/applications/nxplot/jnexus/szlibdll.dll
new file mode 100755
index 0000000..01baf71
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/szlibdll.dll differ
diff --git a/contrib/applications/nxplot/jnexus/windoofx86.lib b/contrib/applications/nxplot/jnexus/windoofx86.lib
new file mode 100755
index 0000000..52fa8f3
--- /dev/null
+++ b/contrib/applications/nxplot/jnexus/windoofx86.lib
@@ -0,0 +1,9 @@
+zlib1
+szlibdll
+iconv
+libxml2
+hdf5dll
+hd421m
+hm421m
+libNeXus-0
+libjnexus-0
diff --git a/contrib/applications/nxplot/jnexus/zlib1.dll b/contrib/applications/nxplot/jnexus/zlib1.dll
new file mode 100755
index 0000000..7912482
Binary files /dev/null and b/contrib/applications/nxplot/jnexus/zlib1.dll differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/.classpath b/contrib/applications/nxplot/mountaingumnexus/.classpath
new file mode 100755
index 0000000..9fa5ee5
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry exported="true" kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src">
+		<attributes>
+			<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="mountaingumnexus/native"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/mountaingumnexus/.project b/contrib/applications/nxplot/mountaingumnexus/.project
new file mode 100755
index 0000000..3a40948
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mountaingumnexus</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/mountaingumnexus/.settings/org.eclipse.jdt.core.prefs b/contrib/applications/nxplot/mountaingumnexus/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 0000000..a67c808
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Wed Oct 21 11:46:43 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/contrib/applications/nxplot/mountaingumnexus/META-INF/MANIFEST.MF b/contrib/applications/nxplot/mountaingumnexus/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..d5cf1b2
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Mountaingumnexus Plug-in
+Bundle-SymbolicName: mountaingumnexus;singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Vendor: Mark Koennecke
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: mountaingumsys;bundle-version="0.1.0",
+ org.eclipse.core.runtime;bundle-version="3.3.100",
+ org.eclipse.ui;bundle-version="3.3.1",
+ jnexus;bundle-version="4.2.0",
+ mountaingumuibase;bundle-version="1.0.0"
+Export-Package: ch.psi.num.mountaingum.nexus.Perspective,
+ ch.psi.num.mountaingum.nexus.actions,
+ ch.psi.num.mountaingum.nexus.loader
diff --git a/contrib/applications/nxplot/mountaingumnexus/build.properties b/contrib/applications/nxplot/mountaingumnexus/build.properties
new file mode 100755
index 0000000..1f0bd9d
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               icons/nexusw.png,\
+               icons/nexusw32.png
diff --git a/contrib/applications/nxplot/mountaingumnexus/icons/nexusw.png b/contrib/applications/nxplot/mountaingumnexus/icons/nexusw.png
new file mode 100755
index 0000000..abd1b3c
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/icons/nexusw.png differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/icons/nexusw32.png b/contrib/applications/nxplot/mountaingumnexus/icons/nexusw32.png
new file mode 100644
index 0000000..37f9e50
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/icons/nexusw32.png differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/plugin.xml b/contrib/applications/nxplot/mountaingumnexus/plugin.xml
new file mode 100755
index 0000000..f0840e1
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/plugin.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+   <extension-point id="ch.psi.num.mountaingum.nexus.loader.NexusMapper" name="NexusMapper" schema="schema/ch.psi.num.mountaingum.nexus.loader.nexusMapper.exsd"/>
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            class="ch.psi.num.mountaingum.nexus.Perspective.NexusPerspective"
+            icon="icons/nexusw32.png"
+            id="mountaingum.NexusPerspective"
+            name="Nexus">
+      </perspective>
+   </extension>
+   <extension
+         point="org.eclipse.ui.actionSets">
+      <actionSet
+            id="mountaingumnexus.ActionSet"
+            label="&NeXus"
+            visible="false">
+         <menu
+               id="mountaingumnexus.Nexus"
+               label="NeXus"
+               path="additions">
+            <groupMarker
+                  name="mountaingumnexus.nexusgroup">
+            </groupMarker>
+         </menu>
+         <action
+               class="ch.psi.num.mountaingum.nexus.actions.PrintNexusGraph"
+               id="mountaingumnexus.Print"
+               label="Print"
+               menubarPath="mountaingumnexus.Nexus/mountaingumnexus.nexusgroup"
+               style="push">
+         </action>
+         <action
+               class="ch.psi.num.mountaingum.nexus.actions.PNGNexusGraph"
+               id="mountaingumnexus.Hard"
+               label="Make PNG"
+               menubarPath="mountaingumnexus.Nexus/mountaingumnexus.nexusgroup"
+               style="push">
+         </action>
+         <action
+               class="ch.psi.num.mountaingum.nexus.actions.SaveNexus"
+               id="mountaingumnexus.Save"
+               label="Save"
+               menubarPath="mountaingumnexus.Nexus/mountaingumnexus.nexusgroup"
+               style="push">
+         </action>
+         <action
+               class="ch.psi.num.mountaingum.nexus.actions.OpenNexus"
+               id="mountaingumnexus.LoadFile"
+               label="Open"
+               menubarPath="mountaingumnexus.Nexus/mountaingumnexus.nexusgroup"
+               style="push">
+         </action>
+         <action
+               class="ch.psi.num.mountaingum.nexus.actions.SinqFileAction"
+               id="mountaingumnexus.LoadSinqFile"
+               label="Load SINQ File"
+               menubarPath="mountaingumnexus.Nexus/mountaingumnexus.nexusgroup"
+               style="push">
+         </action>
+       </actionSet>
+   </extension>
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            class="ch.psi.num.mountaingum.nexus.Perspective.NexusTree"
+            id="mountaingumnexus.NexusTree"
+            name="NexusTree">
+      </view>
+      <view
+            class="ch.psi.num.mountaingum.nexus.Perspective.NameView"
+            id="mountaingumnexus.NameView"
+            name="NameView">
+      </view>
+   </extension>
+   <extension
+         point="ch.psi.num.mountaingum.nexus.loader.NexusMapper">
+         <NexusMapper
+          className="ch.psi.num.mountaingum.nexus.loader.NexusMapperDemo"
+          id="mountaingumnexus.demo"
+          name="mountaingumnexus.demo"
+           />
+         <NexusMapper
+          className="ch.psi.num.mountaingum.nexus.loader.PruneEmptyGroup"
+          id="mountaingumnexus.prune"
+          name="mountaingumnexus.prune"
+           />
+   </extension>
+
+</plugin>
diff --git a/contrib/applications/nxplot/mountaingumnexus/schema/NexusMapper.ID.exsd b/contrib/applications/nxplot/mountaingumnexus/schema/NexusMapper.ID.exsd
new file mode 100755
index 0000000..e4616b8
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/schema/NexusMapper.ID.exsd
@@ -0,0 +1,85 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="mountaingumnexus" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="mountaingumnexus" id="NexusMapper.ID" name="NexusMapper"/>
+      </appinfo>
+      <documentation>
+         This extension point alllows to influence how a NeXus file hierarchy is 
+translated into a hierarchy for use with GTSE. 
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+
+</schema>
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NameView.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NameView.java
new file mode 100755
index 0000000..5124fb6
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NameView.java
@@ -0,0 +1,36 @@
+/**
+ * This is a tiny little view which will be used to display the 
+ * filename of the loaded file.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.Perspective;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.part.ViewPart;
+
+public class NameView extends ViewPart {
+	public final static String ID = "mountaingumnexus.NameView";
+	
+	private Label l;
+	
+	public NameView() {
+	}
+
+	public void createPartControl(Composite parent) {
+		l = new Label(parent, SWT.CENTER);
+		l.setText("Unknown");
+		l.setBackground(l.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+	}
+
+	public void setName(String val){
+		l.setText(val);
+	}
+	public void setFocus() {
+		// Nothing to do
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NexusPerspective.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NexusPerspective.java
new file mode 100755
index 0000000..72cf2bb
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NexusPerspective.java
@@ -0,0 +1,29 @@
+/**
+ * This is the perspective for looking at NeXus files.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.Perspective;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+import ch.psi.num.mountaingum.ui.EditorView.TreeEditorView;
+
+public class NexusPerspective implements IPerspectiveFactory {
+	public static final String ID = "mountaingum.NexusPerspective";
+	public void createInitialLayout(IPageLayout layout) {
+		String editorArea = layout.getEditorArea();
+		layout.setEditorAreaVisible(false);
+		layout.setFixed(true);
+		
+		layout.addStandaloneView(NameView.ID,  false, IPageLayout.TOP, 0.05f, editorArea);
+		layout.addStandaloneView(NexusTree.ID,  false, IPageLayout.LEFT, 0.33f, editorArea);
+		layout.addStandaloneView(TreeEditorView.ID +":1", false, 
+				IPageLayout.RIGHT, 0.66f, editorArea);
+		layout.addActionSet("mountaingumnexus.ActionSet");
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NexusTree.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NexusTree.java
new file mode 100755
index 0000000..9db38bc
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/Perspective/NexusTree.java
@@ -0,0 +1,74 @@
+/**
+ * This is derived class of BaseTreeView which locates
+ * a TreeEditorView instead of a EditroView. All in an ongoing 
+ * effort not do display interrupt buttons in the NeXus perspective
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.Perspective;
+
+import java.util.Comparator;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.widgets.Composite;
+
+import ch.psi.num.mountaingum.nexus.labelprovider.IconTreeLabelProvider;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.ui.EditorView.EditorView;
+import ch.psi.num.mountaingum.ui.EditorView.TreeEditorView;
+import ch.psi.num.mountaingum.ui.TreeViewer.BaseTreeView;
+import ch.psi.num.mountaingum.ui.eclipse.RCPUtil;
+
+public class NexusTree extends BaseTreeView {
+	public static final String ID = "mountaingumnexus.NexusTree";
+
+	protected EditorView getEditorView() {
+		if(eva == null){
+			eva = (EditorView)RCPUtil.findView(TreeEditorView.ID,"1");
+		}
+		return eva;
+	}
+	
+	public TreeNode getTree(){
+		return root;
+	}
+
+	public void createPartControl(Composite parent) {
+		super.createPartControl(parent);
+		treeViewer.setLabelProvider(new IconTreeLabelProvider());
+		ViewerComparator comparator = new ViewerComparator(new Comparator<Object>() {
+			public int compare(Object o1, Object o2) {
+				TreeNode node1;
+				TreeNode node2;
+				if (o1 instanceof TreeNode) {
+					node1 = (TreeNode) o1;
+				} else return -1;
+				if (o2 instanceof TreeNode) {
+					node2 = (TreeNode) o2;
+				} else return 1;
+				
+				String type1 = node1.getProperty("type");
+				String type2 = node2.getProperty("type");
+				String name1 = node1.getProperty("name");
+				String name2 = node2.getProperty("name");				
+				if (type1 == null && type2 == null) return 0;
+				if (type1 == null) return 1;
+				if (type2 == null) return -1;
+				if (type1.equals(type2)) 
+					return name1.compareTo(name2);
+				if (type1.startsWith("graph")) return -1;
+				if (type2.startsWith("graph")) return 1;
+				return name1.compareTo(name2);
+			}
+		}) {
+			public int compare(Viewer viewer, Object e1, Object e2) {
+				return getComparator().compare(e1, e2);
+			}
+		};
+		treeViewer.setComparator(comparator);
+	}
+	
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/OpenNexus.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/OpenNexus.java
new file mode 100755
index 0000000..50f4d93
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/OpenNexus.java
@@ -0,0 +1,77 @@
+/**
+ * This is the action for loading a NeXus file from the 
+ * file system.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import ch.psi.num.mountaingum.nexus.loader.NexusLoader;
+import ch.psi.num.mountaingum.nexus.loader.sinqascii.ASCIILoader;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+
+public class OpenNexus implements IWorkbenchWindowActionDelegate {
+	private IWorkbenchWindow win;
+	private static String dirpref = "opendir"; 
+	
+	public void init(IWorkbenchWindow window) {
+		win = window;
+	}
+
+	public void run(IAction action) {
+		NexusLoader loadi = new NexusLoader();
+		FileDialog fd = new FileDialog(win.getShell(),SWT.OPEN);
+		TreeNode root = null;
+		
+		fd.setFilterExtensions(new String[]  {"*.hdf","*.dat", "*.*"});
+		fd.setFilterNames(new String[] {"HDF-files","ASCII-Scan-files", "All Files"});
+		IEclipsePreferences pref = new InstanceScope().getNode("mountaingumnexus");
+		String path = pref.get(dirpref, null);
+		if(path != null){
+			fd.setFileName(path);
+		}
+		String filename = fd.open();
+		if(filename != null){
+			try{
+				if(filename.endsWith(".dat")){
+					ASCIILoader al = new ASCIILoader();
+					root = al.loadASCIIFile(filename);
+				} else {
+					root = loadi.loadNexusIntoTree(filename);
+				}
+				loadi.viewNode(root);
+				pref.put(dirpref, filename);
+				try{
+					pref.flush();
+				}catch(Exception edith){
+					edith.printStackTrace();
+				}
+			}catch(Exception eva){
+				eva.printStackTrace();
+			}
+		}
+	}
+
+	public void selectionChanged(IAction action, ISelection selection) {
+		// Nothing to do
+	}
+	public void dispose() {
+		// Nothing to do
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/PNGNexusGraph.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/PNGNexusGraph.java
new file mode 100644
index 0000000..17f7db8
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/PNGNexusGraph.java
@@ -0,0 +1,74 @@
+/**
+ * This is an action for printing a NeXus graph into a PNG file
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import ch.psi.num.mountaingum.nexus.Perspective.NexusTree;
+import ch.psi.num.mountaingum.sys.SysRegistry;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+import ch.psi.num.mountaingum.ui.EditorView.TreeEditorView;
+import ch.psi.num.mountaingum.ui.GraphicsView.GraphicsView;
+import ch.psi.num.mountaingum.ui.eclipse.NodeViewer;
+import ch.psi.num.mountaingum.ui.eclipse.RCPUtil;
+
+public class PNGNexusGraph implements IWorkbenchWindowActionDelegate {
+	private IWorkbenchWindow win;
+
+	public void init(IWorkbenchWindow window) {
+		win = window;
+	}
+
+
+
+	public void run(IAction action) {
+		TreeEditorView gv = (TreeEditorView)RCPUtil.findView("mountaingumui.TreeEditorView","1");
+		if(gv == null){
+			SysRegistry.getLogger().error("No NexusTree found in PNGNexusGraph");
+			return;
+		}
+		NodeViewer nv = gv.getPlot();
+		if(nv == null){
+			UIRegistry.getAdapter().displayError("No graph to print selected");
+			return;
+		}
+		
+		FileDialog fd = new FileDialog(win.getShell(),SWT.OPEN);
+		fd.setText("Open");
+		String[] ext  = {"*.png"};
+		fd.setFilterExtensions(ext);
+		String file = fd.open();
+		if(file != null){
+			BufferedImage bi = nv.makeImage(1280, 1024);
+			try{
+				ImageIO.write(bi, "png", new File(file));
+			}catch(IOException eva){
+				SysRegistry.getLogger().exception(eva);
+			}finally {
+				bi.flush();
+			}
+		}
+	}
+
+	public void selectionChanged(IAction action, ISelection selection) {
+	}
+	public void dispose() {
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/PrintNexusGraph.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/PrintNexusGraph.java
new file mode 100644
index 0000000..ee5fdd1
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/PrintNexusGraph.java
@@ -0,0 +1,60 @@
+/**
+ * This is an action for printing a NeXus graph as displayed 
+ * in the neXus viewer
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.printing.PrintDialog;
+import org.eclipse.swt.printing.Printer;
+import org.eclipse.swt.printing.PrinterData;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import ch.psi.num.mountaingum.sys.SysRegistry;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+import ch.psi.num.mountaingum.ui.EditorView.TreeEditorView;
+import ch.psi.num.mountaingum.ui.GraphicsView.GraphicsView;
+import ch.psi.num.mountaingum.ui.eclipse.NodeViewer;
+import ch.psi.num.mountaingum.ui.eclipse.RCPUtil;
+
+public class PrintNexusGraph implements IWorkbenchWindowActionDelegate {
+	private IWorkbenchWindow win;
+
+	public void init(IWorkbenchWindow window) {
+		win = window;
+	}
+
+	public void run(IAction action) {
+		TreeEditorView gv = (TreeEditorView)RCPUtil.findView("mountaingumui.TreeEditorView","1");
+		if(gv == null){
+			SysRegistry.getLogger().error("No GraphicsView found in PrintAction");
+			return;
+		}
+		NodeViewer nv = gv.getPlot();
+		if(nv == null){
+			UIRegistry.getAdapter().displayError("No graph to print selected");
+			return;
+		}
+		
+		PrintDialog dia = new PrintDialog(win.getShell(),SWT.NONE);
+		PrinterData pd = dia.open();
+		if(pd != null){
+			Printer p = new Printer(pd);
+			nv.print(p);
+			p.dispose();
+		}
+	}
+
+	public void selectionChanged(IAction action, ISelection selection) {
+	}
+	public void dispose() {
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SaveNexus.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SaveNexus.java
new file mode 100755
index 0000000..d9be0d7
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SaveNexus.java
@@ -0,0 +1,46 @@
+/**
+ * This is a plain old save of the modified NeXus file when 
+ * possible.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+import java.io.IOException;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import ch.psi.num.mountaingum.nexus.loader.NexusLoader;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+
+public class SaveNexus implements IWorkbenchWindowActionDelegate {
+
+	public void dispose() {
+		// Nothing to do
+	}
+
+	public void init(IWorkbenchWindow window) {
+		// Nothing to do
+	}
+
+	public void run(IAction action) {
+		NexusLoader nl = new NexusLoader();
+		TreeNode root = nl.getTree();
+		try{
+			nl.saveTree(root, root.getProperty("filename"));
+		}catch(IOException eva){
+			UIRegistry.getAdapter().displayError(eva.getMessage());
+		}
+	}
+
+	public void selectionChanged(IAction action, ISelection selection) {
+		// Nothing to do
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFile.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFile.java
new file mode 100755
index 0000000..f6319be
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFile.java
@@ -0,0 +1,83 @@
+/**
+ * This is a tiny utility class for finding the filename of a SINQ data 
+ * file. It first tries to locate the file in the local data area and 
+ * if this fails, at sinqdata. May be this gets extended to download the file 
+ * via http in a later stage. As this may be used elsewhere, this goes into 
+ * a little utility class.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+import java.io.File;
+import java.text.NumberFormat;
+
+public class SinqFile {
+	public static String getSinqFile(String instrument, int year, int numor, String extension){
+		StringBuffer  file, path;
+		String yy, numString, hundred;
+		File f;
+		
+		/**
+		 * build bits and pieces
+		 */
+		NumberFormat nf = NumberFormat.getInstance();
+		nf.setGroupingUsed(false);
+		nf.setMinimumIntegerDigits(4);
+		yy = nf.format(year);
+		nf.setMinimumIntegerDigits(6);
+		numString = nf.format(numor);
+		nf.setMinimumIntegerDigits(3);
+		hundred = nf.format(numor/1000);
+		
+		
+		/**
+		 * build file name
+		 */
+		file = new StringBuffer(instrument.toLowerCase());
+		file.append(yy);
+		file.append('n');
+		file.append(numString);
+		file.append(extension);
+		//System.out.println(file.toString());
+		
+		/**
+		 * test local
+		 */
+		path = new StringBuffer("/home/");
+		path.append(instrument);
+		path.append("/data/");
+		path.append(yy);
+		path.append('/');
+		path.append(hundred);
+		path.append('/');
+		path.append(file.toString());
+		//System.out.println(path.toString());
+		
+		f = new File(path.toString());
+		if(f.canRead()){
+			return path.toString();
+		}
+
+		/**
+		 * test sinqdata
+		 */
+		path = new StringBuffer("/afs/psi.ch/project/sinqdata/");
+		path.append(yy);
+		path.append('/');
+		path.append(instrument);
+		path.append('/');
+		path.append(hundred);
+		path.append('/');
+		path.append(file.toString());
+		//System.out.println(path.toString());
+		
+		f = new File(path.toString());
+		if(f.canRead()){
+			return path.toString();
+		}
+		return null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFileAction.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFileAction.java
new file mode 100755
index 0000000..52968ba
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFileAction.java
@@ -0,0 +1,62 @@
+/**
+ * This is the action driving the dialog to load a SINQ data file
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+import java.io.IOException;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import ch.psi.num.mountaingum.nexus.loader.NexusLoader;
+import ch.psi.num.mountaingum.nexus.loader.sinqascii.ASCIILoader;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+
+public class SinqFileAction implements IWorkbenchWindowActionDelegate {
+
+	private IWorkbenchWindow win;
+	
+	public void run(IAction action) {
+		TreeNode root;
+		
+		SinqFileDialog sfd = new SinqFileDialog(win.getShell());
+		int status = sfd.open();
+		if(status == Window.OK){
+			String filename = sfd.getFilename();
+			if(filename == null){
+				UIRegistry.getAdapter().displayError("This file does not exist");
+			} else {
+				NexusLoader nl = new NexusLoader();
+				try{
+					if(filename.endsWith(".dat")){
+						ASCIILoader al = new ASCIILoader();
+						root = al.loadASCIIFile(filename);
+					} else {
+						root = nl.loadNexusIntoTree(filename);
+					}
+					nl.viewNode(root);
+				}catch(IOException eva){
+					UIRegistry.getAdapter().displayError(eva.getMessage());
+				}
+			}
+		}
+	}
+	public void init(IWorkbenchWindow window) {
+		win = window;
+	}
+
+	public void selectionChanged(IAction action, ISelection selection) {
+		// Nothing to do
+	}
+	public void dispose() {
+		// Nothing to do
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFileDialog.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFileDialog.java
new file mode 100755
index 0000000..7d3904d
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/actions/SinqFileDialog.java
@@ -0,0 +1,156 @@
+/**
+ * This is the dialog for loading SINQ files.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.actions;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import ch.psi.num.mountaingum.sys.SysRegistry;
+
+public class SinqFileDialog extends Dialog {
+	private String filename;
+	private Combo instrument;
+	private Combo year;
+	private Text numor;
+	private HashSet killSet;
+	
+	private static String savedInst = "savedInst";
+	private static String savedYear = "savedYear";
+	private static String savedNumor = "savedNumor";
+	
+	protected SinqFileDialog(Shell parentShell) {
+		super(parentShell);
+		killSet = new HashSet();
+		killSet.add("local");
+		killSet.add("test");
+		killSet.add("sansli");
+		killSet.add("tasp");
+	}
+
+	protected Control createDialogArea(Composite parent) {
+		Composite root = (Composite)super.createDialogArea(parent);
+		root.setLayout(new GridLayout());
+		
+		Group instGroup = new Group(root,SWT.NONE);
+		instGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		instGroup.setText("Select Instrument");
+		instGroup.setLayout(new GridLayout());
+		instrument = new Combo(instGroup,SWT.SINGLE);
+		instrument.setLayoutData(new GridData(GridData.FILL_BOTH));
+		URL ulli = Platform.getBundle("MountainGumApplication").getEntry("sics.config");
+		Properties config  = new Properties();
+		try{
+			config.load(ulli.openStream());
+		}catch(IOException e){
+			SysRegistry.getLogger().error("Failed to load SICS properties");
+			return root;
+		}
+		String prop = config.getProperty("instrumentlist");
+		if(prop == null){
+			SysRegistry.getLogger().error("Failed to load SICS Properties");
+			return root;
+		}
+		StringTokenizer st = new StringTokenizer(prop.trim(),",",false);
+		String inst;
+		while(st.hasMoreTokens()){
+			inst = st.nextToken();
+			if(inst.indexOf("sim") < 0 && !killSet.contains(inst)){
+				if(inst.indexOf("rita") >= 0){
+					instrument.add("rita2");
+				} else {
+					instrument.add(inst);
+				}
+			}
+		}
+		instrument.select(0);
+		
+		Group yearGroup  = new Group(root,SWT.NONE);
+		yearGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		yearGroup.setText("Select Year");
+		yearGroup.setLayout(new GridLayout());
+		year = new Combo(yearGroup, SWT.SINGLE);
+		year.setLayoutData(new GridData(GridData.FILL_BOTH));
+		Calendar cal = Calendar.getInstance();
+		int yy = cal.get(Calendar.YEAR);
+		for(int y = yy; y > 1996; y--){
+			year.add(Integer.toString(y));
+		}
+		year.select(0);
+		
+		Group numGroup  = new Group(root,SWT.NONE);
+		numGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		numGroup.setText("Data File Number");
+		numGroup.setLayout(new GridLayout());
+		numor = new Text(numGroup, SWT.SINGLE);
+		numor.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		numor.setEditable(true);
+		numor.setText("0");
+		
+		IEclipsePreferences pref = new InstanceScope().getNode("mountaingumnexus");
+		String val = pref.get(savedInst, null);
+		if(val != null){
+			instrument.setText(val);
+		}
+		val = pref.get("savedYear", null);
+		if(val != null){
+			year.setText(val);
+		}
+		val = pref.get("savedNumor", null);
+		if(val != null){
+			numor.setText(val);
+		}
+		
+		
+		return root;
+	}
+
+	public String getFilename() {
+		return filename;
+	}
+
+	protected void okPressed() {
+		filename = SinqFile.getSinqFile(instrument.getText(),
+				Integer.parseInt(year.getText()), 
+				Integer.parseInt(numor.getText()), ".hdf");
+
+		if(filename == null){
+			filename = SinqFile.getSinqFile(instrument.getText(),
+					Integer.parseInt(year.getText()), 
+					Integer.parseInt(numor.getText()), ".dat");
+		}
+		IEclipsePreferences pref = new InstanceScope().getNode("mountaingumnexus");
+		pref.put(savedInst, instrument.getText());
+		pref.put(savedYear, year.getText());
+		pref.put(savedNumor, numor.getText());
+		try{
+			pref.flush();
+		}catch(Exception e){}
+		
+		super.okPressed();
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/IconTreeLabelProvider.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/IconTreeLabelProvider.java
new file mode 100644
index 0000000..d429f9b
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/IconTreeLabelProvider.java
@@ -0,0 +1,59 @@
+package ch.psi.num.mountaingum.nexus.labelprovider;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.ui.TreeViewer.TreeLabelProvider;
+
+public class IconTreeLabelProvider extends TreeLabelProvider {
+
+	Map<String, Image> classToIcon = new HashMap<String, Image>();
+
+	Image defaultIcon;
+
+	public IconTreeLabelProvider() {
+		super();
+		URL iconUrl = getClass().getResource("icons/unknown.gif");
+		ImageDescriptor iconDes = ImageDescriptor.createFromURL(iconUrl);
+		this.defaultIcon = iconDes.createImage(true);
+	}
+
+	@Override
+	public Image getColumnImage(Object element, int columnIndex) {
+		
+		if (columnIndex != 0) return null;
+		
+		if (element instanceof TreeNode) {
+			TreeNode node = (TreeNode) element;
+			String type = node.getProperty("type");
+			if (type != null) {
+				if (classToIcon.containsKey(type))
+					return classToIcon.get(type);
+				else {
+					URL iconUrl = getClass().getResource("icons/" + type + ".gif");
+					ImageDescriptor iconDes = ImageDescriptor.createFromURL(iconUrl);
+					Image icon = iconDes.createImage(false);
+					if (icon == null) {
+//						System.out.println("dishing out default icon for " + type);
+						icon = defaultIcon;
+					}
+					classToIcon.put(type, icon);
+					return icon;
+				}
+			} else {
+//				System.out.println("IconTreeLabelProvider.getColumnImage() type null");
+			}
+		}
+
+//		System.out.println("dishing out default icon for " + element);
+
+		Image columnImage = super.getColumnImage(element, columnIndex);
+		return columnImage;
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/CHAR.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/CHAR.gif
new file mode 100755
index 0000000..3154a64
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/CHAR.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/CHAR_array.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/CHAR_array.gif
new file mode 100755
index 0000000..d47c8f8
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/CHAR_array.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DOUBLE.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DOUBLE.gif
new file mode 100755
index 0000000..2ab8b20
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DOUBLE.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DOUBLE_array.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DOUBLE_array.gif
new file mode 100755
index 0000000..5318a49
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DOUBLE_array.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DfnTree.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DfnTree.gif
new file mode 100755
index 0000000..969ee11
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/DfnTree.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/FLOAT.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/FLOAT.gif
new file mode 100755
index 0000000..65ff452
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/FLOAT.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/FLOAT_array.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/FLOAT_array.gif
new file mode 100755
index 0000000..471b4ed
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/FLOAT_array.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/INT.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/INT.gif
new file mode 100755
index 0000000..c2a5520
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/INT.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/INT_array.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/INT_array.gif
new file mode 100755
index 0000000..4703b48
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/INT_array.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/ISO8601.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/ISO8601.gif
new file mode 100755
index 0000000..d054382
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/ISO8601.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXaperture.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXaperture.gif
new file mode 100755
index 0000000..b03ef99
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXaperture.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXattenuator.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXattenuator.gif
new file mode 100755
index 0000000..a88b650
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXattenuator.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXchopper.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXchopper.gif
new file mode 100755
index 0000000..4bd6b1e
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXchopper.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXcollimator.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXcollimator.gif
new file mode 100755
index 0000000..d644444
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXcollimator.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXcrystal.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXcrystal.gif
new file mode 100755
index 0000000..cc6130c
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXcrystal.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXdata.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXdata.gif
new file mode 100755
index 0000000..05e7a3b
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXdata.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXdetector.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXdetector.gif
new file mode 100755
index 0000000..1b6f8b2
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXdetector.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXentry.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXentry.gif
new file mode 100755
index 0000000..7ce9477
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXentry.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXfilter.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXfilter.gif
new file mode 100755
index 0000000..3ac7969
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXfilter.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXinstrument.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXinstrument.gif
new file mode 100755
index 0000000..cf1bf81
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXinstrument.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXlog.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXlog.gif
new file mode 100755
index 0000000..8c9e3ac
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXlog.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXmonitor.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXmonitor.gif
new file mode 100755
index 0000000..0f59fe7
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXmonitor.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXmonochromator.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXmonochromator.gif
new file mode 100755
index 0000000..e4cef85
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXmonochromator.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXnote.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXnote.gif
new file mode 100755
index 0000000..6aa9bd2
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXnote.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXroot.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXroot.gif
new file mode 100755
index 0000000..5721420
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXroot.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXsample.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXsample.gif
new file mode 100755
index 0000000..e0ac6e2
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXsample.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXslit.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXslit.gif
new file mode 100755
index 0000000..72e2270
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXslit.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXsource.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXsource.gif
new file mode 100755
index 0000000..5b25331
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXsource.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXuser.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXuser.gif
new file mode 100755
index 0000000..10a7797
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/NXuser.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/UINT.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/UINT.gif
new file mode 100755
index 0000000..7c2a957
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/UINT.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/UINT_array.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/UINT_array.gif
new file mode 100755
index 0000000..65a581e
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/UINT_array.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/graphdata.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/graphdata.gif
new file mode 100755
index 0000000..05e7a3b
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/graphdata.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/graphset.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/graphset.gif
new file mode 100755
index 0000000..e0b531c
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/graphset.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrCol.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrCol.gif
new file mode 100755
index 0000000..b9d546d
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrCol.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrLay.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrLay.gif
new file mode 100755
index 0000000..a770668
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrLay.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrRow.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrRow.gif
new file mode 100755
index 0000000..7189ad1
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/incrRow.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transCL.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transCL.gif
new file mode 100755
index 0000000..52cdba8
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transCL.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transRC.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transRC.gif
new file mode 100755
index 0000000..4b46221
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transRC.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transRL.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transRL.gif
new file mode 100755
index 0000000..07c7b40
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/transRL.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/unknown.gif b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/unknown.gif
new file mode 100755
index 0000000..e0b531c
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/labelprovider/icons/unknown.gif differ
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/FlatNexusFile.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/FlatNexusFile.java
new file mode 100755
index 0000000..bc7e0ac
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/FlatNexusFile.java
@@ -0,0 +1,106 @@
+/**
+ * This is a derived class of NexusFile which uses the protected 
+ * native getdata function and HDFnative methods to get plain 
+ * 1D array data of various data types. this is what I need for 
+ * GTSE.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import ncsa.hdf.hdflib.HDFNativeData;
+
+import org.nexusformat.NexusException;
+import org.nexusformat.NexusFile;
+
+public class FlatNexusFile extends NexusFile {
+
+	public FlatNexusFile(String arg0, int arg1) throws NexusException {
+		super(arg0, arg1);
+	}
+
+	protected int getTotalLength(){
+		int dim[], info[], length = 1;
+		dim = new int[32];
+		info = new int[2];
+		
+		try{
+			getinfo(dim,info);
+		}catch(NexusException ne){
+			return 0;
+		}
+		
+		for(int i = 0; i < info[0]; i++){
+			length *= dim[i];
+		}
+		
+		return length;
+	}
+	public int[] getintdata(){
+		int length = getTotalLength();
+		byte bdata[] = new byte[length*4];
+		nxgetdata(handle,bdata);
+		return HDFNativeData.byteToInt(bdata);
+	}
+	public short[] getshortdata(){
+		int length = getTotalLength();
+		byte bdata[] = new byte[length*2];
+		nxgetdata(handle,bdata);
+		return HDFNativeData.byteToShort(bdata);
+	}
+	public long[] getlongdata(){
+		int length = getTotalLength();
+		byte bdata[] = new byte[length*8];
+		nxgetdata(handle,bdata);
+		return HDFNativeData.byteToLong(bdata);
+	}
+	public float[] getfloatdata(){
+		int length = getTotalLength();
+		byte bdata[] = new byte[length*4];
+		nxgetdata(handle,bdata);
+		return HDFNativeData.byteToFloat(bdata);
+	}
+	public double[] getdoubledata(){
+		int length = getTotalLength();
+		byte bdata[] = new byte[length*8];
+		nxgetdata(handle,bdata);
+		return HDFNativeData.byteToDouble(bdata);
+	}
+	public String gettextdata(){
+		int length = getTotalLength();
+		byte bdata[] = new byte[length];
+		nxgetdata(handle,bdata);
+		return  new String(bdata);
+	}
+
+	public byte[] getrawslab(int start[], int size[], int type){
+		int i, length = 1;
+		for(i = 0; i < size.length; i++){
+			length *= size[i]; 
+		}
+		switch(type){
+			case NexusFile.NX_CHAR:
+			case NexusFile.NX_INT8:
+			case NexusFile.NX_UINT8:
+				break;
+			case NexusFile.NX_INT16:
+			case NexusFile.NX_UINT16:
+				length *= 2;
+				break;
+			case NexusFile.NX_INT32:
+			case NexusFile.NX_UINT32:
+			case NexusFile.NX_FLOAT32:
+				length *= 4;
+				break;
+			case NexusFile.NX_INT64:	
+			case NexusFile.NX_UINT64:
+			case NexusFile.NX_FLOAT64:
+				length *= 8;
+		}
+		byte result[] = new byte[length];
+		nxgetslab(handle,start,size,result);
+		return result;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NeXusMapper.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NeXusMapper.java
new file mode 100755
index 0000000..e80d72d
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NeXusMapper.java
@@ -0,0 +1,28 @@
+/**
+ * This is a the interface to be implemented by any NeXus data file 
+ * mapper. The mappers task is to edit the raw hierarchy as created 
+ * by the NexusLoader in order to adapt it to different needs. 
+ * 
+ * 
+ * copyright GPL
+ * 
+ * Mark Koennecke, July 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import ch.psi.num.mountaingum.tree.TreeNode;
+
+public interface NeXusMapper {
+
+	/**
+	 * This method allows the mapper to modify the tree at will.
+	 * Usually the mapper may want to check if it can be sensibly applied and just 
+	 * return otherwise.
+	 * 
+	 * @param root the populated tree
+	 * @param nf a handle to the file if needed
+	 * @param nl The NexusLoader for support functions
+	 */
+	public void transform(TreeNode root, FlatNexusFile nf, NexusLoader nl);
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusLoader.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusLoader.java
new file mode 100755
index 0000000..da2d21e
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusLoader.java
@@ -0,0 +1,971 @@
+/**
+ * This is the main driver class for loading  NeXus file data into 
+ * a tree. I first build a list of all paths to consider, then 
+ * iterate through this list. The idea is that the mapper may choose 
+ * to step through the tree at its own pleasure in order to find axis 
+ * data or whatever. 
+ *
+ * This also supports saving of NeXus trees.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.nexusformat.AttributeEntry;
+import org.nexusformat.NexusException;
+import org.nexusformat.NexusFile;
+
+import ch.psi.num.mountaingum.func.FuncUtil;
+import ch.psi.num.mountaingum.func.IFunc;
+import ch.psi.num.mountaingum.nexus.Perspective.NameView;
+import ch.psi.num.mountaingum.nexus.Perspective.NexusTree;
+import ch.psi.num.mountaingum.sys.SysRegistry;
+import ch.psi.num.mountaingum.tree.ChildStream;
+import ch.psi.num.mountaingum.tree.CommandNode;
+import ch.psi.num.mountaingum.tree.DoubleValue;
+import ch.psi.num.mountaingum.tree.GraphicsNode;
+import ch.psi.num.mountaingum.tree.IntValue;
+import ch.psi.num.mountaingum.tree.InternalParameter;
+import ch.psi.num.mountaingum.tree.LongValue;
+import ch.psi.num.mountaingum.tree.NodeValue;
+import ch.psi.num.mountaingum.tree.ParameterNode;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.tree.TreeUtil;
+import ch.psi.num.mountaingum.ui.EditorView.EditorView;
+import ch.psi.num.mountaingum.ui.EditorView.TreeEditorView;
+import ch.psi.num.mountaingum.ui.eclipse.RCPUtil;
+
+public class NexusLoader {
+
+	private HashSet<String> checkedPaths = new HashSet<String>();
+	private TreeNode root;
+	private FlatNexusFile nf;
+	
+	public static final Charset nexusCharset = Charset.forName("UTF-8");
+
+	public NexusLoader() {
+	}
+
+	public TreeNode loadNexusIntoTree(String filename) throws IOException {
+		root = null;
+
+		nf = null;
+		boolean canWrite = false;
+
+		File f = new File(filename);
+		if (!f.canRead()) {
+			throw new IOException("File not readable");
+		}
+		canWrite = f.canWrite();
+
+		try {
+			if (canWrite) {
+				nf = new FlatNexusFile(filename, NexusFile.NXACC_RDWR);
+			} else {
+				nf = new FlatNexusFile(filename, NexusFile.NXACC_READ);
+			}
+		} catch (NexusException ne) {
+			throw new IOException(ne.getMessage());
+		}
+
+		buildTree(filename);
+
+		setPrivilege(root, canWrite);
+
+		try {
+			nf.close();
+		} catch (NexusException ne) {
+			throw new IOException(ne.getMessage());
+		}
+
+		return root;
+	}
+
+	private void recurseFile(TreeNode parent, String path) throws NexusException {
+		String name, type, newPath;
+		StringBuffer stb;
+
+		Hashtable dir = nf.groupdir();
+		Enumeration d = dir.keys();
+		while (d.hasMoreElements()) {
+			name = (String) d.nextElement();
+			type = (String) dir.get(name);
+			if (type.equalsIgnoreCase("CDF0.0")) {
+				continue;
+			}
+			stb = new StringBuffer();
+			stb.append(path);
+			stb.append('/');
+			stb.append(name);
+			newPath = stb.toString();
+			TreeNode nextLevel = makeNode(parent, type, newPath);
+			if (!type.equalsIgnoreCase("SDS") && nextLevel != null) {
+				nf.opengroup(name, type);
+				recurseFile(nextLevel, newPath);
+				nf.closegroup();
+			}
+		}
+	}
+
+	private class PrivFunc implements IFunc {
+		private boolean canWrite;
+
+		PrivFunc(boolean canWrite) {
+			this.canWrite = canWrite;
+		}
+
+		public Object apply(Object o) {
+			if (o instanceof ParameterNode) {
+				ParameterNode pn = (ParameterNode) o;
+				pn.setReadOnly(!canWrite);
+			}
+			return null;
+		}
+	}
+
+	private void setPrivilege(TreeNode root, boolean canWrite) {
+		FuncUtil.map(root.getTreeStream(), new PrivFunc(canWrite));
+	}
+
+	private void buildTree(String filename) throws IOException {
+
+		root = new TreeNode(null, "");
+		root.setProperty("filename", filename);
+		locateGraphics();
+		checkedPaths.clear();
+		
+		try {
+			recurseFile(root, "");
+		} catch (NexusException e) {
+			throw new IOException(e);
+		}
+
+		engageMappers();
+	}
+
+	private void engageMappers() {
+
+		NeXusMapper mapper;
+		IConfigurationElement[] decl = Platform.getExtensionRegistry().getConfigurationElementsFor(
+				"ch.psi.num.mountaingum.nexus.loader.NexusMapper");
+		for (int i = 0; i < decl.length; i++) {
+			IConfigurationElement e = decl[i];
+			try {
+				mapper = (NeXusMapper) e.createExecutableExtension("className");
+				mapper.transform(root, nf, this);
+			} catch (Exception eva) {
+				eva.printStackTrace();
+			}
+		}
+	}
+
+	public TreeNode getTree() {
+		NexusTree btv = (NexusTree) RCPUtil.findView(NexusTree.ID);
+		if (btv == null) {
+			// This means that the Nexus perspective has not yet been opened
+			return null;
+		}
+		return btv.getTree();
+	}
+
+	private class SaveNXPar implements IFunc {
+		private FlatNexusFile nf;
+
+		SaveNXPar(FlatNexusFile nf) {
+			this.nf = nf;
+		}
+
+		public Object apply(Object o) {
+			NexusParameter nxpar;
+			String path;
+			int dim[], info[], i;
+
+			if (o instanceof NexusParameter) {
+				nxpar = (NexusParameter) o;
+				if (nxpar.getProperty("mogrified") != null) {
+					path = nxpar.getProperty("nxpath");
+					try {
+						nf.openpath(path);
+						dim = new int[32];
+						info = new int[2];
+						nf.getinfo(dim, info);
+						switch (info[1]) {
+						case NexusFile.NX_CHAR:
+						case NexusFile.NX_INT8:
+						case NexusFile.NX_UINT8:
+							String data = nxpar.getValue().toString();
+							nf.putdata(data.getBytes());
+							break;
+						case NexusFile.NX_INT16:
+						case NexusFile.NX_UINT16:
+							IntValue iv = (IntValue) nxpar.getValue();
+							short sdata[] = new short[iv.getLength()];
+							int idata[] = iv.getData();
+							for (i = 0; i < sdata.length; i++) {
+								sdata[i] = (short) idata[i];
+							}
+							nf.putdata(sdata);
+							sdata = null;
+							idata = null;
+							break;
+						case NexusFile.NX_INT32:
+						case NexusFile.NX_UINT32:
+							IntValue iiv = (IntValue) nxpar.getValue();
+							nf.putdata(iiv.getData());
+							break;
+						case NexusFile.NX_INT64:
+						case NexusFile.NX_UINT64:
+							LongValue lv = (LongValue) nxpar.getValue();
+							nf.putdata(lv.getData());
+							break;
+						case NexusFile.NX_FLOAT32:
+							DoubleValue dv = (DoubleValue) nxpar.getValue();
+							double ddata[] = dv.getData();
+							float fdata[] = new float[ddata.length];
+							for (i = 0; i < ddata.length; i++) {
+								fdata[i] = (float) ddata[i];
+							}
+							nf.putdata(fdata);
+							fdata = null;
+							ddata = null;
+							break;
+						case NexusFile.NX_FLOAT64:
+							DoubleValue ddv = (DoubleValue) nxpar.getValue();
+							nf.putdata(ddv.getData());
+							break;
+						}
+					} catch (NexusException ne) {
+						SysRegistry.getLogger().error("Failed to write " + path);
+					}
+				}
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * the main mapping function, entry to all the work
+	 */
+	public TreeNode makeNode(TreeNode parent, String nxclass, String nxpath) {
+
+		if (alreadySeen(nxpath)) {
+			return null;
+		}
+
+		TreeNode node;
+
+		if (nxclass.equalsIgnoreCase("SDS")) {
+			node = makeParameterNode(parent, nxpath, nxclass);
+			addPath(nxpath);
+		} else {
+			node = makeGroupNode(parent, nxpath, nxclass);
+		}
+
+		return node;
+	}
+
+	protected void addPath(String nxpath) {
+		checkedPaths.add(nxpath);
+		//System.out.println("Added " + nxpath);
+		
+		// TODO
+		try {
+			nf.openpath(nxpath);
+			/**
+			 * This section is a workaround for a problem with attribute reading
+			 * through the Java-API. This can be removed once nxinitattrdir()
+			 * has been included and is used by nf.attrdir()
+			 */
+			String pathel[] = nxpath.substring(1).split("/");
+			String name = pathel[pathel.length - 1];
+			nf.closedata();
+			nf.opendata(name);
+			String link = getAttr("target");
+			if (link != null) {
+				checkedPaths.add(link);
+				//System.out.println("Added target" + link);
+			}
+		} catch (NexusException ne) {
+		}
+	}
+
+	/*
+	 * This creates all the group hierarchy components till nxpath.
+	 */
+	protected TreeNode makeGroupNode(TreeNode parent, String nxpath, String type) {
+		String pathElement[] = nxpath.substring(1).split("/");
+		String name = pathElement[pathElement.length - 1];
+		TreeNode current;
+
+		current = new TreeNode(parent, name);
+		if (type == null) {
+			System.out.println("could not get type for " + nxpath + " you may guess this shouldn't happen");
+			type = "NXwidget";
+		}
+		current.setProperty("type", type);
+		parent.insertNode(TreeNode.APPEND, current);
+
+		return current;
+	}
+
+	/**
+	 * make any parameter node
+	 * 
+	 * @param root
+	 * @param nf
+	 * @param parent
+	 * @param nxpath
+	 * @param nxclass
+	 * @return
+	 */
+	protected TreeNode makeParameterNode(TreeNode parent, String nxpath, String nxclass) {
+		int dim[], info[], totalLength = 1;
+		TreeNode node = null;
+
+		dim = new int[32];
+		info = new int[2];
+		String pathel[] = nxpath.substring(1).split("/");
+		String name = pathel[pathel.length - 1];
+
+		try {
+
+			nf.opendata(name);
+
+			nf.getinfo(dim, info);
+			totalLength = calcTotalLength(dim,info);
+
+			Hashtable attr = nf.attrdir();
+			if (attr.get("axis") != null) {
+				// ignore: will be picked up when building graph data
+			} else if (attr.get("signal") != null || totalLength > 100) {
+				// System.out.println("Making graphnode for " + nxpath);
+				node = makeGraphNode(parent, nxpath);
+			} else {
+				node = makeSimpleParNode(parent, nxpath, dim, info);
+			}
+		} catch (NexusException ne) {
+			ne.printStackTrace();
+		}
+		return node;
+	}
+
+	/**
+	 * make a simple parameter node
+	 * 
+	 * @param root
+	 * @param nf
+	 * @param nxpath
+	 * @param dim
+	 * @param info
+	 */
+	protected TreeNode makeSimpleParNode(TreeNode parent, String nxpath, int[] dim, int[] info) {
+		String name, pathel[];
+		NexusParameter par;
+
+		pathel = nxpath.substring(1).split("/");
+		name = pathel[pathel.length - 1];
+
+		par = new NexusParameter(parent, name);
+		parent.insertNode(TreeNode.APPEND, par);
+		par.setProperty("nxpath", nxpath);
+
+		if(calcTotalLength(dim,info) < 1000){
+			NodeValue v = makeValue(nf,dim, info);
+			par.updateValue(v);
+		} else {
+			// use deferred loading
+			par.setProperty("visible", "false");
+		}
+		return par;
+	}
+
+	/**
+	 * convert the current SDS to a GTSE NodeValue
+	 * 
+	 * @param nf
+	 * @param dim
+	 * @param info
+	 * @return
+	 */
+	public static NodeValue makeValue(FlatNexusFile nf, int[] dim, int[] info) {
+		NodeValue v;
+		IntValue iv;
+		DoubleValue dv;
+		LongValue lv;
+		int i;
+
+		switch (info[1]) {
+		case NexusFile.NX_CHAR:
+		case NexusFile.NX_INT8:
+		case NexusFile.NX_UINT8:
+			v = new NodeValue();
+			v.setFromString(nf.gettextdata());
+			return v;
+		case NexusFile.NX_INT16:
+		case NexusFile.NX_UINT16:
+			short sdata[] = nf.getshortdata();
+			iv = new IntValue(info[0], dim);
+			for (i = 0; i < sdata.length; i++) {
+				iv.append(sdata[i]);
+			}
+			return iv;
+		case NexusFile.NX_INT32:
+		case NexusFile.NX_UINT32:
+			int idata[] = nf.getintdata();
+			iv = new IntValue(info[0], dim);
+			iv.setData(idata);
+			return iv;
+		case NexusFile.NX_INT64:
+		case NexusFile.NX_UINT64:
+			long ldata[] = nf.getlongdata();
+			lv = new LongValue(info[0], dim);
+			lv.setData(ldata);
+			return lv;
+		case NexusFile.NX_FLOAT32:
+			float fdata[] = nf.getfloatdata();
+			dv = new DoubleValue(info[0], dim);
+			for (i = 0; i < fdata.length; i++) {
+				dv.append(fdata[i]);
+			}
+			return dv;
+		case NexusFile.NX_FLOAT64:
+			double ddata[] = nf.getdoubledata();
+			dv = new DoubleValue(info[0], dim);
+			dv.setData(ddata);
+			return dv;
+		}
+		return null;
+	}
+
+	/**
+	 * make a graphics node
+	 * 
+	 * @param root
+	 * @param nf
+	 * @param parent
+	 * @param nxpath
+	 * @return
+	 */
+	public TreeNode makeGraphNode(TreeNode parent, String nxpath) {
+		TreeNode graphics, mygraph = null;
+		InternalParameter tmp;
+		int dim[], info[], helpdim[], i;
+		IntValue iv;
+
+		// ensure graphics node
+		graphics = locateGraphics();
+
+		// get data info
+		dim = new int[32];
+		info = new int[2];
+		try {
+			nf.getinfo(dim, info);
+		} catch (NexusException ne) {
+			return null;
+		}
+
+		// create graph data node and the rank and dim nodes
+		String pathel[] = nxpath.substring(1).split("/");
+		mygraph = new GraphicsNode(graphics, pathel[pathel.length - 2]);
+		mygraph.setProperty("type", "graphdata");
+		testNameAndInsert(graphics, mygraph);
+
+		tmp = new InternalParameter(mygraph, "rank");
+		mygraph.insertNode(TreeNode.APPEND, tmp);
+		helpdim = new int[1];
+		helpdim[0] = 1;
+		iv = new IntValue(1, helpdim);
+		iv.append(info[0]);
+		tmp.updateValue(iv);
+
+		tmp = new InternalParameter(mygraph, "dim");
+		mygraph.insertNode(TreeNode.APPEND, tmp);
+		helpdim[0] = info[0];
+		iv = new IntValue(1, helpdim);
+		for (i = 0; i < info[0]; i++) {
+			iv.append(dim[i]);
+		}
+		tmp.updateValue(iv);
+
+		// add our data
+		if (info[0] == 3) {
+			makeFrameSeriesViewer(mygraph, nxpath, info, dim);
+			return mygraph;
+		} else {
+			tmp = new NexusParameter(mygraph, "counts");
+			mygraph.insertNode(TreeNode.APPEND, tmp);
+			tmp.setProperty("type", "data");
+			tmp.setProperty("nxpath", nxpath);
+			if(calcTotalLength(dim,info) < 1000){
+				tmp.updateValue(makeValue(nf,dim, info));
+			} else {
+				// use deferred loading
+				tmp.setProperty("visible", "false");
+			}
+		}
+
+		try {
+			nf.closedata();
+		} catch (NexusException ne) {
+		}
+
+		findAxis(nxpath, mygraph);
+
+		checkAndDefaultAxis(mygraph, info[0], dim);
+
+		return mygraph;
+	}
+
+
+	public TreeNode locateGraphics() {
+		TreeNode graphics = TreeUtil.findChild(root, "graphics");
+		if (graphics == null) {
+			graphics = new TreeNode(root, "graphics");
+			root.insertNode(TreeNode.APPEND, graphics);
+			graphics.setProperty("type", "graphset");
+		}
+		return graphics;
+	}
+
+	/**
+	 * this test if the name for mygraph is already a child of graphics If so a
+	 * new name is invented.
+	 * 
+	 * @param graphics
+	 *            The node to insert mygraph to
+	 * @param mygraph
+	 *            The node to insert.
+	 */
+	protected void testNameAndInsert(TreeNode graphics, TreeNode mygraph) {
+		int i = 1, idx;
+		StringBuffer name;
+		String oldName;
+
+		while (TreeUtil.findChild(graphics, mygraph.getName()) != null) {
+			oldName = mygraph.getName();
+			if ((idx = oldName.indexOf('_')) > 0) {
+				oldName = oldName.substring(0, idx);
+			}
+			name = new StringBuffer(oldName);
+			name.append('_');
+			name.append(Integer.toString(i));
+			mygraph.setProperty("name", name.toString());
+			i++;
+		}
+		graphics.insertNode(TreeNode.APPEND, mygraph);
+	}
+
+	protected void makeFrameSeriesViewer(TreeNode mygraph, String nxpath, int info[], int dim[]) {
+		int helpdim[] = new int[1], i, idim;
+		IntValue iv;
+		InternalParameter work;
+		String axis;
+		TreeNode node;
+
+		mygraph.setProperty("viewer", "mountaingumui.frameseries");
+
+		work = (InternalParameter) TreeUtil.findChild(mygraph, "dim");
+		work.setValue(Integer.toString(dim[1]) + " " + Integer.toString(dim[2]));
+
+		work = (InternalParameter) TreeUtil.findChild(mygraph, "rank");
+		work.setValue("2");
+
+		work = new InternalParameter(mygraph, "currentFrame");
+		helpdim[0] = dim[0];
+		iv = new IntValue(1, helpdim);
+		iv.append(dim[0] - 1);
+		work.updateValue(iv);
+		mygraph.insertNode(TreeNode.APPEND, work);
+
+		work = new InternalParameter(mygraph, "counts");
+		helpdim[0] = dim[1] * dim[2];
+		iv = new IntValue(1, helpdim);
+		work.updateValue(iv);
+		work.setProperty("type", "data");
+		mygraph.insertNode(TreeNode.APPEND, work);
+		String countpath = TreeUtil.pathForNode(work);
+
+		InternalParameter cur = new InternalParameter(mygraph, "currentData");
+		iv = new IntValue(1, helpdim);
+		cur.updateValue(iv);
+		mygraph.insertNode(TreeNode.APPEND, cur);
+
+		CommandNode oldframe = new OldFrameCommand(mygraph, "getoldframe");
+		oldframe.setProperty("countpath", countpath);
+		oldframe.setProperty("nxpath", nxpath);
+		oldframe.setProperty("type", "command");
+		mygraph.insertNode(TreeNode.APPEND, oldframe);
+		InternalParameter num = (InternalParameter) TreeUtil.findChild(oldframe, "framenumber");
+		num.setValue(Integer.toString(dim[0] - 1));
+		oldframe.start();
+
+		cur.updateValue(work.getValue());
+
+		try {
+			nf.closedata();
+		} catch (NexusException ne) {
+		}
+
+		findAxis(nxpath, mygraph);
+
+		/**
+		 * Axis numbers in the NeXus file refer to a 3D array. This has to be
+		 * fixed up here.
+		 */
+		for (i = 0; i < mygraph.countChildren(); i++) {
+			node = mygraph.getChild(i);
+			if (node instanceof InternalParameter) {
+				work = (InternalParameter) node;
+			} else {
+				continue;
+			}
+			axis = work.getProperty("type");
+			if (axis != null && axis.equalsIgnoreCase("axis")) {
+				axis = work.getProperty("dim");
+				idim = Integer.parseInt(axis);
+				idim--;
+				work.setProperty("dim", Integer.toString(idim));
+			}
+		}
+
+		checkAndDefaultAxis(mygraph, info[0], dim);
+	}
+
+	/**
+	 * check if each axis has been found; if not add a suitable default axis.
+	 * 
+	 * @param mygraph
+	 *            The graphics node to check
+	 * @param rank
+	 *            the rank of the data
+	 * @param dim
+	 *            The dimensions of the data
+	 */
+	protected void checkAndDefaultAxis(TreeNode mygraph, int rank, int[] dim) {
+		int i;
+		
+		for (i = 0; i < rank; i++) {
+			ParameterNode ax = (ParameterNode)locateAxis(mygraph, i);
+			if (ax == null) {
+				addDefaultAxis(mygraph, i, dim[i]);
+			} else {
+				if(ax.getValue().getLength() != dim[i]){
+					/*
+					System.out.println("Dimension mismatch on axis " + ax.getName() + 
+							", is " + ax.getValue().getLength() +", should " + dim[i]);
+							*/
+					mygraph.deleteChild(ax);
+					addDefaultAxis(mygraph, i, dim[i]);
+				}
+			}
+		}
+	}
+
+	public void addDefaultAxis(TreeNode mygraph, int dim, int size) {
+		String name = "axis" + dim;
+		InternalParameter ax = new InternalParameter(mygraph, name);
+		ax.setProperty("type", "axis");
+		ax.setProperty("dim", Integer.toString(dim));
+		int tmp[] = new int[1];
+		tmp[0] = size;
+		DoubleValue dv = new DoubleValue(1, tmp);
+		for (int i = 0; i < size; i++) {
+			dv.append(i);
+		}
+		ax.updateValue(dv);
+		mygraph.insertNode(TreeNode.APPEND, ax);
+	}
+
+	/**
+	 * try to find a suitable axis for dimension i
+	 * 
+	 * @param mygraph
+	 *            The node to search
+	 * @param i
+	 *            The dim to check
+	 * @return A suitable TreeNode or null
+	 */
+	protected TreeNode locateAxis(TreeNode mygraph, int i) {
+		ChildStream cs = new ChildStream(mygraph);
+		TreeNode ax;
+		String dim;
+
+		while ((ax = (TreeNode) cs.next()) != null) {
+			dim = ax.getProperty("dim");
+			if (dim != null) {
+				if (Integer.parseInt(dim) == i) {
+					return ax;
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Try to locate axis nodes
+	 * 
+	 * @param nf
+	 * @param nxpath
+	 * @param mygraph
+	 */
+	protected void findAxis(String nxpath, TreeNode mygraph) {
+		String name, type, axAttr;
+		try {
+			Hashtable dir = nf.groupdir();
+			Enumeration it = dir.keys();
+			while (it.hasMoreElements()) {
+				name = (String) it.nextElement();
+				type = (String) dir.get(name);
+				if (type.equalsIgnoreCase("SDS")) {
+					nf.opendata(name);
+					axAttr = getAttr("axis");
+					if (axAttr != null) {
+						makeAxis(name, axAttr, mygraph);
+					}
+					nf.closedata();
+				}
+			}
+		} catch (NexusException ne) {
+
+		}
+	}
+
+	/**
+	 * create an axis node
+	 * 
+	 * @param nf
+	 * @param name
+	 * @param axAttr
+	 * @param mygraph
+	 * @throws NexusException
+	 */
+	protected void makeAxis(String name, String axAttr, TreeNode mygraph) throws NexusException {
+		InternalParameter ax = new InternalParameter(mygraph, name);
+		mygraph.insertNode(TreeNode.APPEND, ax);
+		ax.setProperty("type", "axis");
+		int axno = Integer.parseInt(axAttr);
+		ax.setProperty("dim", Integer.toString(axno - 1));
+		int dim[] = new int[32];
+		int info[] = new int[2];
+		nf.getinfo(dim, info);
+		ax.updateValue(makeValue(nf,dim, info));
+	}
+
+	/**
+	 * test if this node has already been seen.
+	 * 
+	 * @param nf
+	 * @param nxpath
+	 * @return
+	 */
+	protected boolean alreadySeen(String nxpath) {
+		if (checkedPaths.contains(nxpath)) {
+			return true;
+		}
+		String link = getAttr("target");
+		if (link != null) {
+			if (checkedPaths.contains(link)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * helper function to get an attribute
+	 * 
+	 * @param nf
+	 * @param name
+	 * @return
+	 */
+	public String getAttr(String name) {
+		try {
+			Hashtable h = nf.attrdir();
+			AttributeEntry e = (AttributeEntry) h.get(name);
+			if (e == null) {
+				return null;
+			}
+			Serializable value = getAttrInSuitableJavaType(name, e.type, e.length);
+			return value.toString();
+		} catch (NexusException ne) {
+			return null;
+		}
+	}
+
+	private Serializable getAttrInSuitableJavaType(String name, int type, int length) throws NexusException {
+		/*
+		 * add on 1 extra byte for the null in the attribute string hdfdump
+		 * shows that we simply put the attribute using the code:
+		 * file.putattr(name, (String)value.getBytes(), NexusFile.NX_CHAR); but
+		 * the attribute length does not account the byte for the null
+		 */
+
+		if (type == NexusFile.NX_CHAR) {
+			length += 1;
+		}
+
+		int args[] = new int[] { length, type };
+
+		Serializable data = createObjectFromTypeAndLength(type, length);
+
+		nf.getattr(name, data, args);
+
+		// string
+		if (type == NexusFile.NX_CHAR) {
+			// remove the 1 extra bytes added on for the null in the attribute
+			length -= 1;
+			// remove training zero, if any
+			while (length > 0 && ((Number) Array.get(data, length - 1)).intValue() == 0)
+				length -= 1;
+			if (length == 0)
+				return "";
+			data = Arrays.copyOf((byte[]) data, length);
+			return new String((byte[]) data, nexusCharset);
+		}
+
+		return (Serializable) Array.get(data, 0);
+	}
+
+	private Object getDataInSuitableJavaType(int[] infoDims, int[] infoArgs) throws NexusException {
+		int rank = infoArgs[0];
+		int[] dimensions = new int[rank];
+		for (int i = 0; i < rank; i++) {
+			dimensions[i] = infoDims[i];
+		}
+		int type = infoArgs[1];
+		int totalLength = calcTotalLength(dimensions,infoArgs);
+
+		Serializable data = null;
+		if (totalLength > 0) {
+			data = createObjectFromTypeAndLength(type, totalLength);
+			if (data == null) {
+				throw new NexusException("Nexus type " + Integer.toString(type) + " is not supported");
+			}
+			nf.getdata(data);
+		}
+		return data;
+	}
+
+	private Serializable createObjectFromTypeAndLength(int type, int length) {
+		Serializable data = null;
+		switch (type) {
+		case NexusFile.NX_CHAR:
+		case NexusFile.NX_INT8:
+		case NexusFile.NX_UINT8:
+			data = new byte[length];
+			break;
+		case NexusFile.NX_INT16:
+		case NexusFile.NX_UINT16:
+			data = new short[length];
+			break;
+		case NexusFile.NX_INT32:
+		case NexusFile.NX_UINT32:
+			data = new int[length];
+			break;
+		case NexusFile.NX_INT64:
+		case NexusFile.NX_UINT64:
+			data = new long[length];
+			break;
+		case NexusFile.NX_FLOAT32:
+			data = new float[length];
+			break;
+		case NexusFile.NX_FLOAT64:
+			data = new double[length];
+			break;
+		}
+		return data;
+	}
+
+	/**
+	 * @param dimensions
+	 * @return the size of a buffer needed to hold the data in an SDS block
+	 */
+	static public int calcTotalLength(int[] dimensions, int[] info) {
+		int totalLength = 1;
+		for (int i = 0; i < info[0]; i++) {
+			totalLength *= dimensions[i];
+		}
+		return totalLength;
+	}
+
+	/**
+	 * reset ourselves...
+	 */
+	public void reset() {
+		checkedPaths.clear();
+	}
+
+	public void saveTree(TreeNode root, String filename) throws IOException {
+
+		String oldfile = root.getProperty("filename");
+		if (!oldfile.equals(filename)) {
+			/**
+			 * To fix this I need to copy the old file on the new file and then
+			 * apply the changes. For this I would need the apache commons-io
+			 * library, or include it into the source or whatever. As of now
+			 * (08/2009) I cannot yet bring myself to add the additional
+			 * dependency.
+			 */
+			throw new IOException("Filename mismatch");
+		}
+
+		try {
+			FlatNexusFile nf = new FlatNexusFile(filename, NexusFile.NXACC_RDWR);
+			FuncUtil.map(root.getTreeStream(), new SaveNXPar(nf));
+			nf.close();
+		} catch (NexusException ne) {
+			throw new IOException(ne.getMessage());
+		}
+	}
+
+	public void viewNode(TreeNode root) {
+		if (root == null) {
+			return;
+		}
+
+		NexusTree btv = (NexusTree) RCPUtil.findView(NexusTree.ID);
+		if (btv == null) {
+			// This means that the Nexus perspective has not yet been opened
+			return;
+		}
+
+		btv.setTree(root);
+		EditorView ed = (EditorView) RCPUtil.findView(TreeEditorView.ID, "1");
+		if (ed != null) {
+			ed.disconnect();
+		}
+
+		NameView nv = (NameView) RCPUtil.findView(NameView.ID);
+		if (nv != null) {
+			nv.setName(root.getProperty("filename"));
+		}
+	}
+
+	public void removeUnwanted(TreeNode root, String[] toRemove) {
+		int i;
+		TreeNode n;
+		
+		for(i = 0; i < toRemove.length; i++){
+			n = TreeUtil.searchNode(root, toRemove[i]);
+			if(n != null){
+				n.getParent().deleteChild(n);
+			}else {
+				System.out.println("Failed to remove: " + toRemove[i]);
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusMapperDemo.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusMapperDemo.java
new file mode 100755
index 0000000..12b8522
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusMapperDemo.java
@@ -0,0 +1,16 @@
+/**
+ * This is a demonstration mapper Is useless 
+ *   copyright: GPL
+ *   
+ *   Tobias Richter, October 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import ch.psi.num.mountaingum.tree.TreeNode;
+
+public class NexusMapperDemo implements NeXusMapper {
+	public void transform(TreeNode root, FlatNexusFile nf, NexusLoader nl) {
+		if (false)
+		root.insertNode(TreeNode.APPEND, new TreeNode(root, "DemoMapperNode"));
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusParameter.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusParameter.java
new file mode 100755
index 0000000..80f6ae6
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/NexusParameter.java
@@ -0,0 +1,71 @@
+/**
+ * This is a very simple derived class of InternalParameter which makes a 
+ * property by setting the property mogified if it has been changed. 
+ * The intent is that, when saving files, this property will be examined and 
+ * only those fields changed on file which have this property. The other 
+ * operation implemented by this class is deferred loading, i.e. data is 
+ * only read from file when it is actually required for the calculation of a 
+ * plot.
+ * 
+ *  copyright: GPL
+ *  
+ *  Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import org.nexusformat.NexusException;
+
+import ch.psi.num.mountaingum.tree.NodeValue;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.tree.TreeUtil;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+
+
+public class NexusParameter extends ch.psi.num.mountaingum.tree.InternalParameter {
+	private boolean loaded;
+	
+	public NexusParameter(TreeNode p, String name) {
+		super(p, name);
+		loaded = false;
+	}
+
+	public void setValue(String val) {
+		super.setValue(val);
+		setProperty("mogrified", "true");
+		loaded = true;
+	}
+	public NodeValue getValue() {
+		if(!loaded){
+			loadData();
+		}
+		return v;
+	}
+
+	private void loadData() {
+		int dim[], info[];
+		TreeNode root = TreeUtil.findRoot(this);
+		
+		String filename = root.getProperty("filename");
+		String nxpath = getProperty("nxpath");
+
+		//System.out.println("Doing deferred load of " + nxpath);
+		
+		try{
+			FlatNexusFile nf = new FlatNexusFile(filename,FlatNexusFile.NXACC_READ);
+			nf.openpath(nxpath);
+			dim = new int[32];
+			info = new int[2];
+			nf.getinfo(dim,info);
+			NodeValue v = NexusLoader.makeValue(nf, dim, info);
+			updateValue(v);
+			nf.close();
+		}catch(NexusException ne){
+			UIRegistry.getAdapter().displayError("Exception " + ne.getMessage() + " while loading " + nxpath);
+		}
+	}
+
+	public void updateValue(NodeValue v) {
+		loaded = true;
+		super.updateValue(v);
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/OldFrameCommand.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/OldFrameCommand.java
new file mode 100755
index 0000000..92b0995
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/OldFrameCommand.java
@@ -0,0 +1,127 @@
+/**
+ * This is a node which can load old frames from a NeXus data file.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import ncsa.hdf.hdflib.HDFNativeData;
+
+import org.nexusformat.NexusException;
+import org.nexusformat.NexusFile;
+
+import ch.psi.num.mountaingum.tree.CommandNode;
+import ch.psi.num.mountaingum.tree.IntValue;
+import ch.psi.num.mountaingum.tree.InternalParameter;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.tree.TreeUtil;
+import ch.psi.num.mountaingum.ui.UIRegistry;
+import ch.psi.num.mountaingum.util.Array2DUtil;
+
+public class OldFrameCommand extends CommandNode {
+
+	public OldFrameCommand(TreeNode parent, String name) {
+		super(parent, name);
+		InternalParameter no = new InternalParameter(this,"framenumber");
+		int helpdim[] = new int[1];
+		helpdim[0] = 1;
+		IntValue iv = new IntValue(1,helpdim);
+		iv.append(0);
+		no.updateValue(iv);
+		insertNode(TreeNode.APPEND,no);
+	}
+
+	public void start() {
+		int start[], size[];
+		int dim[], info[];
+		TreeNode root = TreeUtil.findRoot(this);
+		
+		String filename = root.getProperty("filename");
+		String nxpath = getProperty("nxpath");
+		int frameNo = getFrameNo();
+		start = new int[3];
+		size = new int[3];
+		
+		InternalParameter dn = (InternalParameter) TreeUtil.searchNode(root, getProperty("countpath"));
+		
+		if(getProperty("buenzel") != null){
+			loadThorough(filename, frameNo, dn);
+			return;
+		}
+		try{
+			FlatNexusFile nx = new FlatNexusFile(filename, NexusFile.NXACC_READ);
+			nx.openpath(nxpath);
+			dim = new int[32];
+			info = new int[2];
+			nx.getinfo(dim,info);
+			start[0] = Math.max(0,frameNo-1);
+			if(start[0] >= dim[0]){
+				start[0] = dim[0] -1;
+			}
+			start[1] = 0;
+			start[2] = 0;
+			size[0] = 1;
+			size[1] = dim[1];
+			size[2] = dim[2];
+			byte raw[] = nx.getrawslab(start, size, info[1]);
+			if(info[1] != NexusFile.NX_INT32 && info[1] != NexusFile.NX_UINT32){
+				/**
+				 * TODO: fix this to handle all types of data?
+				 */
+				throw new NexusException("Unsupported data conversion");
+			}
+			int data[] = HDFNativeData.byteToInt(raw);
+			if(getProperty("swap") != null){
+				int targetdata[] = new int[data.length];
+				Array2DUtil au = new Array2DUtil();
+				au.rotate90(data, targetdata, dim[2], dim[1]);
+				data = targetdata;
+			}
+			IntValue iv = (IntValue) dn.getValue();
+			iv.setData(data);
+			dn.notifyUpdate();
+			raw = null;
+			data = null;
+			nx.close();
+		}catch(Exception noemi){
+			UIRegistry.getAdapter().displayError(noemi.getMessage());
+		}
+	}
+
+	private void loadThorough(String filename, int frameNo, InternalParameter dn) {
+		int data[], rawdata[][][], dim[], info[], i, j;
+		
+		try{
+			FlatNexusFile nx = new FlatNexusFile(filename, NexusFile.NXACC_READ);
+			nx.openpath(getProperty("nxpath"));
+			dim = new int[32];
+			info = new int[2];
+			nx.getinfo(dim,info);
+			rawdata = new int[dim[0]][dim[1]][dim[2]];
+			data = new int[dim[1]*dim[2]];
+			nx.getdata(rawdata);
+			for(j = 0; j < dim[2]; j++ ){
+				for(i = 0; i < dim[1]; i++){
+					data[i + j*dim[1]] = rawdata[frameNo][j][i];
+				}
+			}
+			nx.close();
+			IntValue iv = (IntValue)dn.getValue();
+			iv.setData(data);
+			dn.notifyUpdate();
+			rawdata = null;
+			data = null;
+		}catch(Exception eva){
+			UIRegistry.getAdapter().displayError(eva.getMessage());
+		}
+	}
+
+	private int getFrameNo() {
+		InternalParameter no = (InternalParameter) TreeUtil.findChild(this, "framenumber");
+		IntValue iv = (IntValue) no.getValue();
+		return iv.getValue(0);
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/PruneEmptyGroup.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/PruneEmptyGroup.java
new file mode 100644
index 0000000..3ef598a
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/PruneEmptyGroup.java
@@ -0,0 +1,33 @@
+/**
+ * This is a NeXusMapper which removes empty groups
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, October 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader;
+
+import ch.psi.num.mountaingum.func.FuncUtil;
+import ch.psi.num.mountaingum.func.IFunc;
+import ch.psi.num.mountaingum.func.IStream;
+import ch.psi.num.mountaingum.tree.ParameterNode;
+import ch.psi.num.mountaingum.tree.TreeNode;
+
+public class PruneEmptyGroup implements NeXusMapper {
+
+	private class TestFunc implements IFunc {
+		public Object apply(Object o) {
+			TreeNode n = (TreeNode)o;
+			if( ! (o instanceof ParameterNode) && n.countChildren() < 1){
+				n.getParent().deleteChild(n);
+			}
+			return null;
+		}
+		
+	}
+	public void transform(TreeNode root, FlatNexusFile nf, NexusLoader nl) {
+		IStream s = root.getTreeStream();
+		FuncUtil.map(s, new TestFunc());
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/sinqascii/ASCIILoader.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/sinqascii/ASCIILoader.java
new file mode 100755
index 0000000..a10207b
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/sinqascii/ASCIILoader.java
@@ -0,0 +1,142 @@
+/**
+ * This class is responsible for loading a SINQ ASCII file into a
+ * GTSE NeXus viewer tree for viewing.
+ * 
+ *  copyright: GPL
+ *  
+ *  Mark Koennecke, September 2009
+ */
+package ch.psi.num.mountaingum.nexus.loader.sinqascii;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import ch.psi.num.mountaingum.sys.SysRegistry;
+import ch.psi.num.mountaingum.tree.DoubleValue;
+import ch.psi.num.mountaingum.tree.GraphicsNode;
+import ch.psi.num.mountaingum.tree.IntValue;
+import ch.psi.num.mountaingum.tree.InternalParameter;
+import ch.psi.num.mountaingum.tree.TreeNode;
+
+public class ASCIILoader {
+	private HashSet exclude;
+
+	public ASCIILoader(){
+		exclude = new HashSet();
+		exclude.add("ScanVariables");
+	}
+	public TreeNode loadASCIIFile(String filename){
+		TreeNode root = null, par;
+		GraphicsNode graph;
+		InternalParameter tmp;
+		ASCIIReader ar;
+		int i;
+		String parname, parvalue;
+		
+		try{
+			File f = new File(filename);
+			FileInputStream fin = new FileInputStream(f);
+			ar = new ASCIIReader(fin);
+			ar.read();
+			fin.close();
+		}catch(IOException eva){
+			SysRegistry.getLogger().error(eva.getMessage());
+			return null;
+		}
+		
+		root = new TreeNode(null,"");
+		par = new TreeNode(root,"parameter");
+		root.insertNode(TreeNode.APPEND, par);
+		graph = new GraphicsNode(root,"scan");
+		root.insertNode(TreeNode.APPEND, graph);
+
+		/**
+		 * exclude arrays of scan vars
+		 */
+		String scanvars = (String)ar.getValue("names");
+		String scanp[] = scanvars.split(",");
+		for(i = 0; i < scanp.length; i++){
+			exclude.add(scanp[i]);
+		}
+		
+		
+		/**
+		 * add parameters
+		 */
+		Enumeration e = ar.getKeys();
+		while(e.hasMoreElements()){
+			parname = (String)e.nextElement();
+			if(! exclude.contains(parname)){
+				parvalue = (String)ar.getValue(parname);
+				tmp = new InternalParameter(par,parname);
+				par.insertNode(TreeNode.APPEND, tmp);
+				tmp.setValue(parvalue);
+			}
+		}
+		
+		makeGraph(graph, ar);
+		root.setProperty("filename", filename);
+		
+		return root;
+	}
+	private void makeGraph(GraphicsNode graph, ASCIIReader ar) {
+		int helpdim[], i, j;
+		InternalParameter tmp;
+		IntValue iv;
+		DoubleValue dv;
+		float counts[], par[];
+		
+		graph.setProperty("type", "graphset");
+		counts = (float[])ar.getValue("Counts");
+		
+		helpdim = new int[1];
+		tmp = new InternalParameter(graph,"rank");
+		graph.insertNode(TreeNode.APPEND, tmp);
+		helpdim = new int[1];
+		helpdim[0] = 1;
+		iv = new IntValue(1,helpdim);
+		iv.append(1);
+		tmp.updateValue(iv);
+
+		
+		tmp = new InternalParameter(graph,"dim");
+		graph.insertNode(TreeNode.APPEND, tmp);
+		helpdim[0] = 1;
+		iv = new IntValue(1,helpdim);
+		iv.append(counts.length);
+		tmp.updateValue(iv);
+
+		
+		tmp = new InternalParameter(graph,"counts");
+		tmp.setProperty("type", "data");
+		graph.insertNode(TreeNode.APPEND, tmp);
+		helpdim[0] = counts.length;
+		iv = new IntValue(1,helpdim);
+		for(i = 0; i < counts.length; i++){
+			iv.append(counts[i]);
+		}
+		tmp.updateValue(iv);
+
+		String scanvars = (String)ar.getValue("ScanVariables");
+		String scanp[] = scanvars.split(",");
+		for(i = 0; i < scanp.length; i++){
+			par = (float[])ar.getValue(scanp[i].trim());
+			if(par != null && par.length > 1 && Math.abs(par[1] - par[0]) > 0.0001) {
+				tmp = new InternalParameter(graph,scanp[i]);
+				graph.insertNode(TreeNode.APPEND, tmp);
+				helpdim[0] = par.length;
+				dv = new DoubleValue(1,helpdim);
+				for(j = 0; j < par.length; j++){
+					dv.append(par[j]);
+				}
+				tmp.updateValue(dv);
+				tmp.setProperty("type", "axis");
+				tmp.setProperty("dim", "0");
+				return;
+			}
+		}
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/sinqascii/ASCIIReader.java b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/sinqascii/ASCIIReader.java
new file mode 100755
index 0000000..e8bffae
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumnexus/src/ch/psi/num/mountaingum/nexus/loader/sinqascii/ASCIIReader.java
@@ -0,0 +1,266 @@
+   /**
+     *                  A S C I I R e a d e r
+     *
+     * A class for reading SinQ ASCII data files. Data is entered in a 
+     * dictionary on reading. From this dictionary data can be retrieved
+     * using its keyword. There are a few system special dictionary entries:
+     * NP is the number of points, Preset the preset and Mode the scan mode.
+     * ScanVariables has as value a comma separated list of scan variables.
+     * names is a comma separated list of all the variables recorded at each
+     * scan point.
+     *
+     * Mark Koennecke, August 1998
+     * 
+     * Added getKeys() method
+     * 
+     * Mark Koennecke, September 2009
+     */
+package ch.psi.num.mountaingum.nexus.loader.sinqascii;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.StringTokenizer;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+     public class ASCIIReader {
+
+       /**
+         * Variables 
+       */
+         protected BufferedReader bin;
+         protected Hashtable datadict;
+         private final static int debug = 0;
+    
+       /** 
+         * A Constructor
+       */
+       public ASCIIReader(InputStream in)
+       {
+         bin = new BufferedReader(new InputStreamReader(in));
+         datadict = new Hashtable();
+       }
+
+       /**
+         * The Read method coordinates the work. It calls readHeader and
+         * readData
+       */
+       public void read() throws IOException
+       {
+           readHeader();
+           readData();
+       }
+
+       /**
+         * readHader reads lines until it finds a string with ** DATA **.
+         * If the line contains a = sign, the line is split there and
+         * the two components added to the datadict as key value pair.
+       */
+       protected void readHeader() throws IOException
+       {
+          String line;
+          StringTokenizer st;
+          int iIndex;
+          String key,value;
+
+          line = bin.readLine();
+          while(line.indexOf("*** DATA ***") < 0)
+          {
+              /* older TOPSI files do not have the = in all cases */
+              line = fixTopsi(line);
+              iIndex = line.indexOf('=');
+              if(iIndex > 0)
+              {
+                 key = line.substring(0,iIndex);
+                 key = key.trim();
+                 value = line.substring(iIndex+1,line.length());
+                 value = value.trim();
+                 if(debug > 0)
+                 {
+                     System.out.println("Entering: " +
+                       key + ", " +
+                       value );
+                 }
+                 datadict.put(key,value);
+             }
+             line = bin.readLine();
+          }
+       }
+       /**
+         *
+       */
+       private String fixTopsi(String line)
+       {
+           int iIndex;
+           String result;
+
+           if(line.indexOf("Stardate:") > 0)
+           {
+             iIndex = line.indexOf(':');
+             result = line.substring(0,iIndex) + "=" +
+                      line.substring(iIndex+1, line.length()) ;
+             return result;                
+           }
+           return line;
+       }
+
+       /**
+         * readData reads the data header info, then the data and stores
+         * them in the dictionary as Vectors.
+       */
+       protected void readData() throws IOException
+       {
+          int iIndex, i, i2;
+          int iNP = 0, nData, iCount;
+          String line, temp, snames;
+          String names[];
+          float data[][], f2[];
+          Float f;
+
+          /* get scan variables */
+          line = bin.readLine();
+          iIndex = line.indexOf("WARNING");
+          if(iIndex >=0 )
+	  {
+            line = bin.readLine();
+          }
+          iIndex = line.indexOf(':');
+          datadict.put("ScanVariables",
+               line.substring(iIndex+1,line.length()));
+
+          /* get np, mode & preset */
+          line = bin.readLine();
+          StringTokenizer st = new StringTokenizer(line,",",false);
+          if(st.countTokens() < 3)
+          {
+              throw new IOException("Invalid data file format");
+          }
+          temp = st.nextToken();
+          iIndex = temp.indexOf(' ');
+          Integer ig = new Integer(0);
+          try {
+              ig = new Integer(temp.substring(0,iIndex));
+              iNP = ig.intValue();
+          } catch(Exception egolf) {
+            throw new IOException("Invalid data file format"); 
+          }
+          if(debug > 0)
+          {
+              System.out.println("Found NP as: " + iNP);
+          }
+          datadict.put("NP",ig.toString());
+          temp = st.nextToken();
+          iIndex = temp.indexOf(':');
+          datadict.put("ScanMode",
+                      temp.substring(iIndex+1,temp.length()));
+          temp = st.nextToken();
+          iIndex = temp.indexOf(' ');
+          datadict.put("Preset",
+             temp.substring(iIndex+1,temp.length()));
+
+          /* get data item names */
+          line = bin.readLine();
+          st = new StringTokenizer(line," ",false);          
+          nData = st.countTokens();
+          names = new String[nData-1]; /* do not get NP */
+          st.nextToken(); /* skip NP */
+          for(i = 0; i < nData-1; i++)
+          {
+              names[i] = st.nextToken();
+          }
+          data = new float[nData][iNP];
+
+          /* after having set up, read the actual data */
+          if(debug > 0)
+          {
+             System.out.println("Starting to read Scan data");
+          }
+          for(i = 0; i < iNP; i++)
+          {
+             line = bin.readLine();
+             /* handle it gracefully, if the user aborted the scan */
+             if(line.equals("END-OF-DATA"))
+             {
+                 iNP = i-1;
+                 datadict.remove("NP");
+                 ig = new Integer(iNP);
+                 datadict.put("NP",ig.toString());
+                 break;            
+             }
+             st = new StringTokenizer(line," ",false);
+             /* skip NP as first column */
+             st.nextToken();
+             for(i2 = 0; i2 < nData -1; i2++)
+             {
+               temp = st.nextToken();
+               try {
+                   f = new Float(temp);
+                   data[i2][i] = f.floatValue();
+                   if(debug > 3)
+                   {
+                       System.out.println("assigning: " + f.floatValue() +
+                                 "to " + i2 + "," +i);
+                   }
+                }catch(Exception rudolf) {
+                  if(debug > 0) 
+                  {
+                      System.out.println("Failure to convert number from "
+                                         +temp);
+                      System.out.println(rudolf.getMessage());
+                  }
+                  data[i2][i] = (float)0.0;
+                }
+             }
+          }
+          if(debug > 0)
+          {
+              System.out.println("Read all scan points");
+          }
+
+          /* done reading, stow away */
+          snames = new String();
+          for(i = 0; i < nData-1; i++)
+          {
+              snames = snames.concat(names[i]);
+              snames = snames.concat(",");
+              f2 = new float[iNP];
+              for(i2 = 0; i2 < iNP; i2++)
+              {
+                 f2[i2] = data[i][i2];
+              }
+              datadict.put(names[i],f2);
+          }
+          /* remove last komma in snames */
+          iIndex = snames.lastIndexOf(',');
+          snames = snames.substring(0,iIndex);
+         
+          datadict.put("names",snames);
+       }
+
+     /**
+       * getValue gets the object requested as key from the dictionary.
+     */
+      public Object getValue(String key)
+      {
+          return datadict.get(key);
+      } 
+
+      public Enumeration getKeys(){
+    	  return datadict.keys();
+      }
+      /**
+        * a finalizer
+      */
+       protected void finalize() throws Throwable
+       {
+           if(bin != null)
+           {
+               bin.close();
+               bin = null;
+           }
+           datadict = null;
+       }
+     } /* end of class definition */
diff --git a/contrib/applications/nxplot/mountaingumsys/.classpath b/contrib/applications/nxplot/mountaingumsys/.classpath
new file mode 100755
index 0000000..1fa3e68
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/mountaingumsys/.project b/contrib/applications/nxplot/mountaingumsys/.project
new file mode 100755
index 0000000..fd13e05
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mountaingumsys</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/mountaingumsys/META-INF/MANIFEST.MF b/contrib/applications/nxplot/mountaingumsys/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..9b6bc71
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Mountaingumsys Plug-in
+Bundle-SymbolicName: mountaingumsys;singleton:=true
+Bundle-Version: 0.1
+Bundle-Vendor: Mark.Koennecke at psi.ch
+Bundle-Localization: plugin
+Export-Package: ch.psi.num.mountaingum.batch,
+ ch.psi.num.mountaingum.func,
+ ch.psi.num.mountaingum.sys,
+ ch.psi.num.mountaingum.tree,
+ ch.psi.num.mountaingum.ui,
+ ch.psi.num.mountaingum.util
diff --git a/contrib/applications/nxplot/mountaingumsys/build.properties b/contrib/applications/nxplot/mountaingumsys/build.properties
new file mode 100755
index 0000000..e9863e2
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
diff --git a/contrib/applications/nxplot/mountaingumsys/plugin.xml b/contrib/applications/nxplot/mountaingumsys/plugin.xml
new file mode 100755
index 0000000..9483051
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/plugin.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+   <extension-point id="ch.psi.num.mountaingum.tree.DataFilter" name="Node Data Filter" schema="schema/ch.num.psi.mountaingum.tree.DataFilter.exsd"/>
+
+</plugin>
diff --git a/contrib/applications/nxplot/mountaingumsys/schema/ch.num.psi.mountaingum.tree.DataFilter.exsd b/contrib/applications/nxplot/mountaingumsys/schema/ch.num.psi.mountaingum.tree.DataFilter.exsd
new file mode 100755
index 0000000..2b52c23
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/schema/ch.num.psi.mountaingum.tree.DataFilter.exsd
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="mountaingumsys">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="mountaingumsys" id="ch.psi.num.mountaingum.tree.DataFilter" name="Node Data Filter"/>
+      </appInfo>
+      <documentation>
+         A filter for node data
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <complexType>
+         <sequence>
+            <element ref="DataFilter"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appInfo>
+                  <meta.attribute translatable="true"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="DataFilter">
+      <complexType>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="className" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         See interface ch.psi.num.mountaingum.tree.DataFilter
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="implementation"/>
+      </appInfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchAdapter.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchAdapter.java
new file mode 100755
index 0000000..a381be8
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchAdapter.java
@@ -0,0 +1,186 @@
+/**
+ * This is an abstract class for interfacing with the batch system. The general idea
+ * is that Parameter- or CommandNodes are cloned into a batch queue which can be 
+ * edited, both the sequence and the nodes. Implementations are then responsible
+ * for serializing, deserializing and running such queues against the underlying
+ * system
+ * 
+ * Classes implementing this interface are also responsible for holding the current 
+ * Queue of edited or active batch nodes.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.batch;
+
+import java.util.List;
+import java.util.Vector;
+
+import ch.psi.num.mountaingum.func.FuncUtil;
+import ch.psi.num.mountaingum.func.IFunc;
+import ch.psi.num.mountaingum.func.IteratorStream;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.util.ListSequence;
+import ch.psi.num.mountaingum.util.Sequence;
+
+public abstract class BatchAdapter {
+	protected Sequence buffer;
+	protected Vector batchListeners;
+	
+	public BatchAdapter(){
+		batchListeners = new Vector();
+		buffer = new ListSequence();
+	}
+	/**
+	 * Clone a tree node in a suitable way that it can be used in the 
+	 * batch editor. 
+	 * @param source The node to clone
+	 * @return A TreeNode implementing the BatchNode interface
+	 */
+	abstract public TreeNode cloneBatchNode(TreeNode source);
+	/**
+	 * get the sequence we are currently editing.
+	 * @return An editing Sequence
+	 */
+	public Sequence getSequence(){
+		return buffer;
+	}
+	/**
+	 * Get a list of urls for available batch files held in the underlying 
+	 * system. 
+	 * @return A List holding url strings. 
+	 */
+	abstract public List getAvailableBatchBuffers();
+	
+	/**
+	 * Load a batch sequence from somewhere into the editing sequence
+	 * @param url A system specific identifier for the buffer to laod.
+	 */
+	abstract public void load(String url);
+	/**
+	 * save the current sequence to a file 
+	 * @param url The identifier for the file to save the sequence too
+	 */
+	abstract public void save(String url);
+	/**
+	 * Start executing the current Sequence
+	 */
+	abstract public void start(String url);
+	/**
+	 * Interrupt processing of the current sequence. 
+	 */
+	abstract public void Interrupt();
+	/**
+	 * loadRaw loads a batch file for script style editing
+	 * @param url The URL of the batch file to load
+	 * @return the content of the batch file or an error message
+	 */
+	abstract public String loadRaw(String url);
+	/**
+	 * save a raw script edited file to the DAQ system
+	 * @param url The URL of the file to save
+	 * @param txt The content of the file
+	 */
+	abstract public void saveRaw(String url, String txt);
+	/**
+	 * execute a batch file
+	 * @param url The name of the batch file
+	 * @param data The batch data
+	 * @param l A BatchScriptListener which is informed about the progress of the 
+	 * 	script.
+	 */
+	abstract public void exeScript(String url, String data, BatchScriptListener l);
+	/**
+	 * add a BatchListener
+	 * @param l The BatchListener to add
+	 */
+	public void addBatchListener(BatchListener l){
+		batchListeners.add(l);
+	}
+	/**
+	 * remove a BatchListener
+	 * @param l The BatchListener to remove.
+	 */
+	public void removeBatchListener(BatchListener l){
+		batchListeners.remove(l);
+	}
+	/**
+	 * Utility function for appending a node to the sequence. 
+	 * @param n The node to append
+	 */
+	public void append(TreeNode n){
+		buffer.insert(buffer.length(), n);
+		sequenceChanged();
+		nodeEnqueued(n);
+	}
+	private class NewIndex implements IFunc {
+		private int id;
+
+		NewIndex(int id){
+			this.id = id;
+		}
+		public Object apply(Object o) {
+			BatchListener l = (BatchListener)o;
+			l.startingEntry(id);
+			return null;
+		}
+	}
+	private class NewLog implements IFunc {
+		private String  log;
+
+		NewLog(String txt){
+			this.log = txt;
+		}
+		public Object apply(Object o) {
+			BatchListener l = (BatchListener)o;
+			l.logMessage(log);
+			return null;
+		}
+	}
+	private class SeqChange implements IFunc {
+		private Sequence s;
+
+		SeqChange(Sequence s){
+			this.s = s;
+		}
+		public Object apply(Object o) {
+			BatchListener l = (BatchListener)o;
+			l.sequenceChanged(s);
+			return null;
+		}
+	}
+	private class NodeEnqueue implements IFunc {
+		private BatchNode n;
+
+		NodeEnqueue(BatchNode n){
+			this.n = n;
+		}
+		public Object apply(Object o) {
+			BatchListener l = (BatchListener)o;
+			l.nodeEnqueued(n);
+			return null;
+		}
+	}
+	/**
+	 * send a notification to all BatchListeners that we are now executing a 
+	 * new entry.
+	 * @param id The entry which starts executing.
+	 */
+	protected void newIndex (int id){
+		FuncUtil.map(new IteratorStream(batchListeners), new NewIndex(id));
+	}
+	/**
+	 * send a new log message to all BatchListeners.
+	 * @param txt The message to send.
+	 */
+	protected void newLogData(String txt){
+		FuncUtil.map(new IteratorStream(batchListeners), new NewLog(txt));
+	}
+	public void sequenceChanged(){
+		FuncUtil.map(new IteratorStream(batchListeners), new SeqChange(buffer));
+	}
+	protected void nodeEnqueued(TreeNode n){
+		FuncUtil.map(new IteratorStream(batchListeners), new NodeEnqueue((BatchNode)n));
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchListener.java
new file mode 100755
index 0000000..0db10d1
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchListener.java
@@ -0,0 +1,36 @@
+/**
+ * This is a listener interface for all things coming from the execution of 
+ * a batch sequence.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.batch;
+
+import ch.psi.num.mountaingum.util.Sequence;
+
+public interface BatchListener {
+	/**
+	 * This is the information that the entry with the index id
+	 * has started executing.
+	 * @param id The index of the queue entry executing 
+	 */
+	public void startingEntry(int id);
+	/**
+	 * A log message has arrived.
+	 * @param txt The text being logged.
+	 */
+	public void logMessage(String txt);
+	/**
+	 * This shall be  called whenever the sequence has changed. The client ought to 
+	 * react to this with a redraw. 
+	 * @param s The sequence changed.
+	 */
+	public void sequenceChanged(Sequence s);
+	/**
+	 * This is called whenever a node has been queued to the batch queue.
+	 * @param n The node which has been enqueued.
+	 */
+	public void nodeEnqueued(BatchNode n);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchNode.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchNode.java
new file mode 100755
index 0000000..b3160a4
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchNode.java
@@ -0,0 +1,31 @@
+/**
+ * This is the interface to be implemented by tree nodes in the batch queue. I 
+ * separated this into an interface in order to allow batch tree nodes to 
+ * inherit from real nodes as they might and will share the command formatting
+ * code in the SICS implementation.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.batch;
+
+public interface BatchNode {
+	/**
+	 * Is this node capable to handle textual edits of command strings?
+	 * If yes, parse() must do sensible things.
+	 * @return true or false
+	 */
+	public boolean canEdit();
+	/**
+	 * getDescription returns a textual description of the batch node entry
+	 * @return  A string for displaying info about this entry.
+	 */
+	public String getDescription();
+	/**
+	 * After text editing, parse the resulting string into the 
+	 * node. 
+	 * @param txt The text to parse. 
+	 */
+	public void parse(String txt)throws BatchParseException;
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchParseException.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchParseException.java
new file mode 100755
index 0000000..8cdeaf2
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchParseException.java
@@ -0,0 +1,15 @@
+/**
+ * An exception top be thrown when parsing a node from edited data fails. Currently 
+ * this jusst identifies the type. More things may be added later on.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.batch;
+
+public class BatchParseException extends Exception {
+	public BatchParseException(String txt){
+		super(txt);
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchReceiver.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchReceiver.java
new file mode 100755
index 0000000..ba501c2
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchReceiver.java
@@ -0,0 +1,29 @@
+/**
+ * This is a little class with default implementations for the BatchListener interface.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.batch;
+
+import ch.psi.num.mountaingum.util.Sequence;
+
+public class BatchReceiver implements BatchListener {
+
+	public void logMessage(String txt) {
+		// Nothing to do
+	}
+
+	public void nodeEnqueued(BatchNode n) {
+		// Nothing to do
+	}
+
+	public void sequenceChanged(Sequence s) {
+		// Nothing to do
+	}
+
+	public void startingEntry(int id) {
+		// Nothing to do
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchScriptListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchScriptListener.java
new file mode 100755
index 0000000..4e66d5c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/batch/BatchScriptListener.java
@@ -0,0 +1,27 @@
+/**
+ * This is a listener for events from processing scripted batch 
+ * files.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, September 2009
+ */
+package ch.psi.num.mountaingum.batch;
+
+public interface BatchScriptListener {
+	/**
+	 * some log data
+	 * @param txt The log data;
+	 */
+	public void log(String txt);
+	/**
+	 * change the text range which is currently executing
+	 * @param start of the range
+	 * @param end of the range
+	 */
+	public void range(int start, int end);
+	/**
+	 * inidication that the script terminated
+	 */
+	public void terminated();
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/ArrayStream.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/ArrayStream.java
new file mode 100755
index 0000000..6d3e9af
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/ArrayStream.java
@@ -0,0 +1,28 @@
+/**
+ * This is an aray of objects based stream
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.func;
+
+public class ArrayStream implements IStream {
+
+	private Object obj[];
+	private int count;
+	public ArrayStream(Object o[]){
+		obj = o;
+		count = 0;
+	}
+	public Object next() {
+		Object o;
+		if(count < obj.length ){
+			o = obj[count];
+			count++;
+			return o;
+		}
+		return null;
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/EnumerationStream.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/EnumerationStream.java
new file mode 100755
index 0000000..346ef92
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/EnumerationStream.java
@@ -0,0 +1,24 @@
+/**
+ * This is a stream to iterate over a Java Enumeration
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, December 2007
+ */
+package ch.psi.num.mountaingum.func;
+import java.util.Enumeration;
+
+public class EnumerationStream implements IStream {
+	private Enumeration eno;
+	
+	public EnumerationStream(Enumeration eno){
+		this.eno = eno;
+	}
+	public Object next() {
+		if(eno.hasMoreElements()){
+			return eno.nextElement();
+		} else {
+			return null;
+		}
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/FuncUtil.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/FuncUtil.java
new file mode 100755
index 0000000..c642571
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/FuncUtil.java
@@ -0,0 +1,26 @@
+/**
+ * a utility class which implements various functional strategies
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.func;
+import java.util.LinkedList;
+import java.util.List;
+
+public class FuncUtil {
+
+	public static List map(IStream in, IFunc func){
+		Object arg, out;
+		List l = new LinkedList();
+		
+		while((arg = in.next()) != null){
+			out = func.apply(arg);
+			if(out != null){
+				l.add(out);
+			}
+		}
+		return l;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IFunc.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IFunc.java
new file mode 100755
index 0000000..7345485
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IFunc.java
@@ -0,0 +1,17 @@
+/**
+ * Interface for a function acting upon an object
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.func;
+
+public interface IFunc {
+	/**
+	 * apply the function to 
+	 * @param o The argument object
+	 * @return null or a result object
+	 */
+	public Object apply(Object o);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IStream.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IStream.java
new file mode 100755
index 0000000..53e5534
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IStream.java
@@ -0,0 +1,16 @@
+/**
+ * This is an interface for streams of objects.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.func;
+
+public interface IStream {
+	/**
+	 * return next object or null when exhausted
+	 * @return an object or null when exhausted.
+	 */
+	public Object next();
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IteratorStream.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IteratorStream.java
new file mode 100755
index 0000000..e119c20
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/func/IteratorStream.java
@@ -0,0 +1,26 @@
+/**
+ * This packages any of the standard Java collection iterators into a
+ * stream interface
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.func;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class IteratorStream implements IStream {
+
+	protected Iterator it;
+	
+	public IteratorStream(Collection c){
+		it = c.iterator();
+	}
+	public Object next() {
+		if(it.hasNext()){
+			return it.next();
+		}
+		return null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/DefaultLogger.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/DefaultLogger.java
new file mode 100755
index 0000000..c7f4baa
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/DefaultLogger.java
@@ -0,0 +1,36 @@
+/**
+ * This is a default logger which does: NOTHING!
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+public class DefaultLogger implements LoggerInterface {
+
+	public void debug(String txt) {
+	}
+
+	public void error(String txt) {
+	}
+
+	public void info(String txt) {
+	}
+
+	public void received(String txt) {
+	}
+
+	public void sent(String txt) {
+	}
+
+	public void trace(String txt) {
+	}
+
+	public void warn(String txt) {
+	}
+
+	public void exception(Exception eva) {
+	}
+}
+
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/IDisconnectListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/IDisconnectListener.java
new file mode 100755
index 0000000..578fb3c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/IDisconnectListener.java
@@ -0,0 +1,12 @@
+/**
+ * listeneing for disconnects?
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+public interface IDisconnectListener {
+	public void disconnect();
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/ISystemAdapter.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/ISystemAdapter.java
new file mode 100755
index 0000000..d3cd286
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/ISystemAdapter.java
@@ -0,0 +1,47 @@
+/**
+ * This is the interface any adapter to an underlying system has to implement
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.sys;
+import ch.psi.num.mountaingum.tree.TreeNode;
+
+public interface ISystemAdapter {
+	/*
+	 * can do asynchronous processing
+	 */
+	public boolean canAsync();
+	/**
+	 * configure the tree according to the demands of the underlying system.
+	 * Please note that this may also be called to reconfigure parts of the 
+	 * tree after the underlying system modifies the tree.
+	 * @param root The root of the tree. Children have to be added to this
+	 */
+	public void configureTree(TreeNode root);
+	/**
+	 * interrupt the current operation
+	 */
+	public void interrupt();
+	/**
+	 * create a suitable TerminalInterface implementation.
+	 * @return A TerminalInterface
+	 */
+	public TerminalInterface makeTerminalInterface();
+	/**
+	 * return a terminal interface to the factory for destruction.
+	 * @param ti The TerminalInterface to destroy.
+	 */
+	public void closeTerminalInterface(TerminalInterface ti);
+	/**
+	 * add a listener for disconnects to the control system
+	 * @param l The listener to add
+	 */
+	public void addDisconnectListener(IDisconnectListener l);
+	/**
+	 * remove a listener for disconnects to the control system
+	 * @param l The listener to remove
+	 */
+	public void removeDisconnectListener(IDisconnectListener l);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/LoggerInterface.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/LoggerInterface.java
new file mode 100755
index 0000000..9a3eefd
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/LoggerInterface.java
@@ -0,0 +1,21 @@
+/**
+ * This is an interface describing a logger. Clients can implement 
+ * different implementations in order to realize different logging 
+ * strategies.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+public interface LoggerInterface {
+	public void trace(String txt);
+	public void debug(String txt);
+	public void info(String txt);
+	public void warn(String txt);
+	public void error(String txt);
+	public void sent(String txt);
+	public void received(String txt);
+	public void exception(Exception eva);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/NullTerminal.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/NullTerminal.java
new file mode 100755
index 0000000..7080d47
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/NullTerminal.java
@@ -0,0 +1,41 @@
+/**
+ * This is the default implementation of a terminal interface
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, December 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NullTerminal implements TerminalInterface {
+
+	public NullTerminal(){
+		l = null;
+	}
+	protected TerminalListener l;
+	public TerminalListener getTerminalListener() {
+		return l;
+	}
+
+	public void interrupt() {
+		reply("ERROR: Not connected, interrupt annihilated");
+	}
+
+	public void sendCommand(String command) {
+		reply("ERROR: not connected, command " + command + " annihilated");
+	}
+
+	public void setTerminalListener(TerminalListener l) {
+		this.l = l;
+	}
+	private void reply(String txt){
+		if(l != null){
+			List ll = new ArrayList();
+			ll.add(txt);
+			l.handleOutput(ll);
+		}
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/QueueListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/QueueListener.java
new file mode 100755
index 0000000..ad51717
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/QueueListener.java
@@ -0,0 +1,14 @@
+/**
+ * This is the interface anyone has to implement who wishes to be informed of 
+ * a batch queues progress.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+public interface QueueListener {
+	public void nodeExecuting(int idx);
+	public void batchError(String descr);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/StdoutLogger.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/StdoutLogger.java
new file mode 100755
index 0000000..3499cd0
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/StdoutLogger.java
@@ -0,0 +1,95 @@
+/**
+ * This is another logger which outputs to stdout.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+public class StdoutLogger implements LoggerInterface {
+
+	public final static int IO    = 0;
+	public final static int TRACE = 1;
+	public final static int INFO  = 2;
+	public final static int DEBUG = 3;
+	public final static int WARN  = 4;
+	public final static int ERROR = 5;
+	public final static int OFF   = 6;
+	
+	protected int logLevel;
+	
+	public void debug(String txt) {
+		log(DEBUG,txt);
+	}
+
+	public void error(String txt) {
+		log(ERROR,txt);
+	}
+
+	public void info(String txt) {
+		log(INFO,txt);
+	}
+
+	public void received(String txt) {
+		log(IO,txt);
+	}
+
+	public void sent(String txt) {
+		log(IO,txt);
+	}
+
+	public void trace(String txt) {
+		log(TRACE,txt);
+	}
+
+	public void warn(String txt) {
+		log(WARN,txt);
+	}
+	protected  void log(int level, String txt){
+		if(level >= logLevel){
+			System.out.println(txt);
+		}
+	}
+
+	protected String levelToString(int level) {
+		switch(level){
+		case IO:
+			return "IO";
+		case TRACE:
+			return "TRACE";
+		case INFO:
+			return "INFO";
+		case DEBUG:
+			return "DEBUG";
+		case WARN:
+			return "WARNING";
+		case ERROR:
+			return "ERROR";
+		}
+		return "BADLEVEL";
+	}
+	public int getLogLevel() {
+		return logLevel;
+	}
+
+	public void setLogLevel(int logLevel) {
+		this.logLevel = logLevel;
+	}
+
+	public void exception(Exception eva) {
+		if(logLevel > ERROR){
+			return;
+		}
+		/*
+		 * This keeps popping up as excessive 
+		 * object allocations in hprof-files. So we stop
+		 * it with the code above. 
+		 */
+		log(ERROR,"Exception " + eva.getMessage());
+		StackTraceElement stack[] = eva.getStackTrace();
+		for(int i = 0; i < stack.length; i++){
+			log(ERROR,stack[i].toString());
+		}
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/SysRegistry.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/SysRegistry.java
new file mode 100755
index 0000000..d505755
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/SysRegistry.java
@@ -0,0 +1,53 @@
+/**
+ * This is the central access point for all system services.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ * 
+ * added TerminalInterface support
+ * 
+ * Mark Koennecke, December 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+import ch.psi.num.mountaingum.batch.BatchAdapter;
+
+public class SysRegistry {
+	/**
+	 * logging stuff
+	 */
+	private static LoggerInterface logger = null;
+
+	/**
+	 * an adapter which can do tree creation
+	 */
+	private static ISystemAdapter sys = null;
+	
+	/**
+	 * and adpater for managing batch processing
+	 */
+	private static BatchAdapter batch = null;
+	
+	static public LoggerInterface getLogger(){
+		if(logger == null){
+			logger = new DefaultLogger();
+		}
+		return logger;
+	}
+	static synchronized public void setLogger(LoggerInterface li){
+		logger = li;
+	}
+	public static BatchAdapter getBatchAdapter() {
+		return batch;
+	}
+	public static void setBatchAdapter(BatchAdapter batch) {
+		SysRegistry.batch = batch;
+	}
+	public static ISystemAdapter getSystemAdapter() {
+		return sys;
+	}
+	public static void setSystemAdapter(ISystemAdapter sys) {
+		SysRegistry.sys = sys;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/TerminalInterface.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/TerminalInterface.java
new file mode 100755
index 0000000..283f060
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/TerminalInterface.java
@@ -0,0 +1,30 @@
+/**
+ * This is an interface to an underlying text based command system
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, December 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+public interface TerminalInterface {
+	/**
+	 * send a command to the CLI system
+	 * @param command The command to send
+	 */
+	public void sendCommand(String command);
+	/**
+	 * interrupt what is going on in the CLI
+	 */
+	public void interrupt();
+	/**
+	 * set a listener for output from the CLI
+	 * @param l The listener to set.
+	 */
+	public void setTerminalListener(TerminalListener l);
+	/**
+	 * get the current terminal listener
+	 * @return The current TerminalListener
+	 */
+	public TerminalListener getTerminalListener();
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/TerminalListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/TerminalListener.java
new file mode 100755
index 0000000..48fdc5d
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/sys/TerminalListener.java
@@ -0,0 +1,19 @@
+/**
+ * This is an interface for an object to listen for output from 
+ * a command line application.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, December 2007
+ */
+package ch.psi.num.mountaingum.sys;
+
+import java.util.List;
+
+public interface TerminalListener {
+	/**
+	 * handle output from the CLI
+	 * @param lines is a list of lines. 
+	 */
+	public void handleOutput(List lines);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/test/TestInt.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/test/TestInt.java
new file mode 100755
index 0000000..2b3e867
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/test/TestInt.java
@@ -0,0 +1,23 @@
+/**
+ * Testing the IntValue class.....
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.test;
+import ch.psi.num.mountaingum.tree.IntValue;
+public class TestInt {
+	public static void main(String argv[]){
+		int dim[] = new int[1];
+		dim[0] = 3;
+		IntValue iv = new IntValue(1,dim);
+		iv.setFromString("1 2 3");
+		int d[] = iv.getData();
+		d[0] = 5;
+		d[1] = 6;
+		d[2] = 7;
+		iv.setData(d);
+		System.out.println(iv.toString());
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ChildStream.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ChildStream.java
new file mode 100755
index 0000000..e645e80
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ChildStream.java
@@ -0,0 +1,31 @@
+/**
+ * A stream of child nodes of the parent node given in the constructor.
+ * This stream does not recurse
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+import ch.psi.num.mountaingum.func.IStream;
+
+public class ChildStream implements IStream {
+
+	private TreeNode parent;
+	private int current;
+	private int count;
+	public ChildStream(TreeNode parent){
+		current = 0;
+		this.parent = parent;
+		count = parent.countChildren();
+	}
+	public Object next() {
+		Object o = null;
+		if(current < count){
+			o = parent.getChild(current);
+			current++;
+		}
+		return o;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/CommandNode.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/CommandNode.java
new file mode 100755
index 0000000..4b25242
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/CommandNode.java
@@ -0,0 +1,23 @@
+/**
+ * This is a node representing a command. 
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+import ch.psi.num.mountaingum.batch.BatchAdapter;
+import ch.psi.num.mountaingum.sys.SysRegistry;
+
+public abstract class CommandNode extends ExecutableNode {
+	public CommandNode(TreeNode parent, String name){
+		super(parent,name);
+	}
+	abstract public void start();
+	public void enqueue(){
+		BatchAdapter ba = SysRegistry.getBatchAdapter();
+		TreeNode tn = ba.cloneBatchNode(this);
+		ba.append(tn);
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/DataFilter.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/DataFilter.java
new file mode 100755
index 0000000..92bdba4
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/DataFilter.java
@@ -0,0 +1,12 @@
+/**
+ * This is an interface for all data filters. A data filter transforms 
+ * the data read into something else.
+ * 
+ * Mark Koennecke, May 2008
+ */
+package ch.psi.num.mountaingum.tree;
+
+
+public interface DataFilter {
+	public void process(TreeNode n) throws Exception;
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/DoubleValue.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/DoubleValue.java
new file mode 100755
index 0000000..9ac5c0a
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/DoubleValue.java
@@ -0,0 +1,82 @@
+/**
+ * This is a node representing double data. We do some lazy evaluation 
+ * here: i.e. data gets converted from text to array or from array to text
+ * only when requested. Please note that client code is responsible for 
+ * adapting dimensions for the case of variable length arrays.  
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+import ch.psi.num.mountaingum.util.DynamicDoubleArray;
+
+public class DoubleValue extends NodeValue {
+	protected DynamicDoubleArray data;
+	protected boolean arrayDirty;
+	protected boolean textDirty;
+	
+	public DoubleValue(int rank, int dim[]){
+		this.type = FLOAT;
+		this.rank = rank;
+		this.dim = dim;
+		textData = new String("0");
+		data = new DynamicDoubleArray();
+		textDirty = false;
+	}
+
+	public void setFromString(String data){
+		super.setFromString(data);
+		arrayDirty = true;
+		textDirty = false;
+	}
+	public String toString(){
+		if(textDirty){
+			textData = data.toString();
+			textDirty = false;
+		}
+		return textData;
+	}
+	public void setDim(int dim[]){
+		super.setDim(dim);
+		arrayDirty = true;
+		textDirty = true;
+	}
+	public int getLength(){
+		return data.getLength();
+	}
+	public double[] getData(){
+		if(arrayDirty){
+			data.setFromText(textData.trim());
+			arrayDirty = false;
+		}
+		return data.getData();
+	}
+	public double getValue(int idx){
+		if(arrayDirty){
+			data.setFromText(textData.trim());
+			arrayDirty = false;
+		}
+		return data.getValue(idx);
+	}
+	public void setData(double data[]){
+		this.data.reset();
+		this.data.append(data);
+		textDirty = true;
+	}
+	public void append(double d){
+		data.append(d);
+		textDirty = true;
+	}
+	public void append(int i){
+		data.append((double)i);
+		textDirty = true;
+	}
+	public double[] getRawData(){
+		return data.getRawArray();
+	}
+	public void reset() {
+		super.reset();
+		data.reset();
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ExecutableNode.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ExecutableNode.java
new file mode 100755
index 0000000..8cf9452
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ExecutableNode.java
@@ -0,0 +1,178 @@
+/**
+ * This is a base class for all node which are executable.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+import java.util.LinkedList;
+import ch.psi.num.mountaingum.func.*;
+
+public abstract class ExecutableNode extends TreeNode {
+	public final static int OK    = 0;
+	public final static int RUN   = 1;
+	public final static int ERROR = 2;
+	
+	protected LinkedList logListeners, updateListeners;
+	protected boolean readOnly;
+	protected StringBuffer logBuffer;
+	protected int state;
+	
+	public ExecutableNode(TreeNode mama, String name){
+		super(mama,name);
+		logListeners = new LinkedList();
+		updateListeners = new LinkedList();
+		readOnly = false;
+		logBuffer = new StringBuffer();
+		state = OK;
+	}
+	/**
+	 * add a log listener
+	 * @param l The listener to add
+	 */
+	public void addLogListener(LogListener l){
+		logListeners.add(l);
+	}
+	/**
+	 * remove a LogListener
+	 * @param l The LogListener to remove
+	 */
+	public void removeLogListener(LogListener  l){
+		if(logListeners.contains(l)){
+			logListeners.remove(l);
+		}
+	}
+	private class StartNotify implements IFunc {
+		private TreeNode me;
+		StartNotify(TreeNode m){
+			me = m;
+		}
+		public Object apply(Object o){
+			LogListener ll = (LogListener)o;
+			ll.deviceStarted(me);
+			return null;
+		}
+	}
+	protected void startDevice(){
+		logBuffer = null;
+		logBuffer = new StringBuffer();
+		FuncUtil.map(new IteratorStream(logListeners), new StartNotify(this));
+		state = RUN;
+	}
+	private class LogNotify implements IFunc{
+		private TreeNode me;
+		private String message;
+		private boolean success;
+		LogNotify(TreeNode n, String mes, boolean s){
+			me = n;
+			message = mes;
+			success = s;
+		}
+		public Object apply(Object o){
+			LogListener ll = (LogListener)o;
+			ll.addLogData(me, message, success);
+			return null;
+		}
+	}
+	protected void log(String message, boolean success){
+		FuncUtil.map(new IteratorStream(logListeners),
+				new LogNotify(this, message, success));
+		logBuffer.append(message);
+		logBuffer.append('\n');
+		if(!success){
+			state = ERROR;
+		}
+	}
+	private class StopNotify implements IFunc {
+		private TreeNode me;
+		boolean success;
+		StopNotify(TreeNode n, boolean success){
+			me = n;
+			this.success = success;
+		}
+		public Object apply(Object o){
+			LogListener ll = (LogListener)o;
+			ll.deviceFinished(me, success);
+			return null;
+		}
+	}
+	protected void finish(boolean success){
+		if(!success){
+			state = ERROR;
+		}
+		if(state != ERROR){
+			state = OK;
+		}
+		FuncUtil.map(new IteratorStream(logListeners),
+				new StopNotify(this,success));
+	}
+	private class CommandNotify implements IFunc {
+		private TreeNode me;
+		private String com;
+		CommandNotify(TreeNode n, String command){
+			me = n;
+			com = command;
+		}
+		public Object apply(Object o){
+			LogListener ll = (LogListener)o;
+			ll.commandSent(me, com);
+			return null;
+		}
+	}
+	protected void commandNotify(String command){
+		/*
+		FuncUtil.map(new IteratorStream(logListeners), 
+					new CommandNotify(this,command));
+					*/
+		int i;
+		LogListener ll;
+		for(i = 0; i < logListeners.size(); i++){
+			ll = (LogListener)logListeners.get(i);
+			ll.commandSent(this,command);
+		}
+	}
+	public boolean isReadOnly() {
+		return readOnly;
+	}
+
+	public void setReadOnly(boolean readOnly) {
+		this.readOnly = readOnly;
+		notifyState();
+	}
+	class StateNotify implements IFunc {
+		private TreeNode me;
+		StateNotify(TreeNode m){
+			me = m;
+		}
+		public Object apply(Object o){
+			UpdateListener ll = (UpdateListener)o;
+			ll.nodeStatusChanged(me);
+			return null;
+		}
+	}
+	public void addUpdateListener(UpdateListener l) {
+		updateListeners.add(l);
+	}
+
+	public void removeUpdateListener(UpdateListener  l) {
+		updateListeners.remove(l);
+	}
+
+	protected void notifyState() {
+		FuncUtil.map(new IteratorStream(updateListeners), new StateNotify(this));
+	}
+	public String getLogBuffer(){
+		return logBuffer.toString();
+	}
+	public int getState(){
+		return state;
+	}
+	public void dispose() {
+		super.dispose();
+		logListeners = null;
+		updateListeners = null;
+		logBuffer = null;
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/GraphicsNode.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/GraphicsNode.java
new file mode 100755
index 0000000..05f798f
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/GraphicsNode.java
@@ -0,0 +1,14 @@
+package ch.psi.num.mountaingum.tree;
+
+public class GraphicsNode extends TreeNode {
+	public GraphicsNode(TreeNode p, String name){
+		super(p,name);
+		p.setProperty("viewer","default");
+	}
+	public void setDisplayKey(String editor){
+		p.setProperty("viewer", editor);
+	}
+	public String getDisplayKey(){
+		return p.getProperty("viewer");
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/IntValue.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/IntValue.java
new file mode 100755
index 0000000..63ebfb3
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/IntValue.java
@@ -0,0 +1,87 @@
+/**
+ * This is a node representing integer data. We do some lazy evaluation 
+ * here: i.e. data gets converted from text to array or from array to text
+ * only when requested. Please note that client code is responsible for 
+ * adapting dimensions for the case of variable length arrays.  
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+import ch.psi.num.mountaingum.util.DynamicIntArray;
+
+public class IntValue extends NodeValue {
+	protected DynamicIntArray data;
+	protected boolean arrayDirty;
+	protected boolean textDirty;
+	
+	public IntValue(int rank, int dim[]){
+		this.type = INT;
+		this.rank = rank;
+		this.dim = dim;
+		textData = new String("0");
+		data = new DynamicIntArray();
+		textDirty = false;
+	}
+
+	public void setFromString(String data){
+		super.setFromString(data);
+		arrayDirty = true;
+		textDirty = false;
+	}
+	public String toString(){
+		if(textDirty){
+			textData = data.toString();
+			textDirty = false;
+		}
+		return textData;
+	}
+	public void setDim(int dim[]){
+		super.setDim(dim);
+		arrayDirty = true;
+		textDirty = true;
+	}
+	public int getLength(){
+		return data.getLength();
+	}
+	public int[] getData(){
+		if(arrayDirty){
+			data.setFromText(textData.trim());
+			arrayDirty = false;
+		}
+		return data.getData();
+	}
+	public int getValue(int idx){
+		if(arrayDirty){
+			data.setFromText(textData.trim());
+			arrayDirty = false;
+		}
+		return data.getValue(idx);
+	}
+	public void setData(int data[]){
+		this.data.reset();
+		this.data.append(data);
+		textDirty = true;
+	}
+	public void append(int i){
+		data.append(i);
+		textDirty = true;
+	}
+	public void append(double d){
+		data.append((int)Math.abs(d));
+		textDirty = true;
+	}
+	public void append(long i){
+		data.append((int)i);
+		textDirty = true;
+	}
+	
+	public void reset() {
+		super.reset();
+		data.reset();
+	}
+	public int[] getRawData(){
+		return data.getRawArray();
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/InternalParameter.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/InternalParameter.java
new file mode 100755
index 0000000..e71fd39
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/InternalParameter.java
@@ -0,0 +1,25 @@
+package ch.psi.num.mountaingum.tree;
+
+public class InternalParameter extends ParameterNode {
+
+	public InternalParameter(TreeNode p, String name){
+		super(p,name);
+	}
+	public void setValue(String val) {
+		v.setFromString(val);
+		notifyUpdate();
+	}
+	public void updateValue(NodeValue v) {
+		this.v = v;
+		notifyUpdate();
+	}
+	public void enqueueValue(String v) {
+		// Nothing to do....
+	}
+	public void queryValue() {
+		/*
+		 * As this is an internal parameter, we cannot ask 
+		 * any underlying system to do something for us. 
+		 */
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/LogListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/LogListener.java
new file mode 100755
index 0000000..d86818d
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/LogListener.java
@@ -0,0 +1,39 @@
+/**
+ * An interface for receiving logging data on active nodes.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+public interface LogListener {
+	/**
+	 * called when the node started processing
+	 * It shall clear any old log buffers. When required
+	 * @param node The node which started
+	 */
+	public void deviceStarted(TreeNode node);
+	/**
+	 * add runtime log information
+	 * @param node The node from which this data is coming
+	 * @param txt The actual logging data
+	 * @param success A flag which determines if the node is in error
+	 * or is still OK
+	 */
+	public void addLogData(TreeNode node, String txt, boolean success);
+	/**
+	 * called to notfy termination of a device
+	 * @param node The node from which the message originated
+	 * @param success A flag determining if the operation was a 
+	 * success or not.
+	 */
+	public void deviceFinished(TreeNode node, boolean success);
+	/**
+	 * Notification of a command being sent to the underlying system.
+	 * Makes only sense in systems which work with commands.
+	 * @param tn The TreeNode sending the command
+	 * @param command The command sent
+	 */
+	public void commandSent(TreeNode tn, String command);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/LongValue.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/LongValue.java
new file mode 100755
index 0000000..454a5eb
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/LongValue.java
@@ -0,0 +1,81 @@
+/**
+ * This is value class for long ints.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, February 2008
+ */
+package ch.psi.num.mountaingum.tree;
+
+import ch.psi.num.mountaingum.util.DynamicLongArray;
+
+public class LongValue extends NodeValue {
+	protected DynamicLongArray data;
+	protected boolean arrayDirty;
+	protected boolean textDirty;
+	
+	public LongValue(int rank, int dim[]){
+		this.type = INT;
+		this.rank = rank;
+		this.dim = dim;
+		textData = new String("0");
+		data = new DynamicLongArray();
+		textDirty = false;
+	}
+
+	public void setFromString(String data){
+		super.setFromString(data);
+		arrayDirty = true;
+		textDirty = false;
+	}
+	public String toString(){
+		if(textDirty){
+			textData = data.toString();
+			textDirty = false;
+		}
+		return textData;
+	}
+	public void setDim(int dim[]){
+		super.setDim(dim);
+		arrayDirty = true;
+		textDirty = true;
+	}
+	public int getLength(){
+		return data.getLength();
+	}
+	public long[] getData(){
+		if(arrayDirty){
+			data.setFromText(textData.trim());
+			arrayDirty = false;
+		}
+		return data.getData();
+	}
+	public long getValue(int idx){
+		return data.getValue(idx);
+	}
+	public void setData(long data[]){
+		this.data.reset();
+		this.data.append(data);
+		textDirty = true;
+	}
+	public void append(long i){
+		data.append(i);
+		textDirty = true;
+	}
+	public void append(double d){
+		data.append((long)Math.abs(d));
+		textDirty = true;
+	}
+	public void append(int i){
+		data.append((long)i);
+		textDirty = true;
+	}
+	public long[] getRawData(){
+		return data.getRawArray();
+	}
+	
+	public void reset() {
+		super.reset();
+		data.reset();
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeListListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeListListener.java
new file mode 100755
index 0000000..e88cef5
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeListListener.java
@@ -0,0 +1,13 @@
+/**
+ * This defines a listener for the case when a node list has been changed.
+ * See TreeNodeList.java for more details.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+public interface NodeListListener {
+	public void nodeListChanged(TreeNodeList l);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeSearchFunc.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeSearchFunc.java
new file mode 100755
index 0000000..b337f4c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeSearchFunc.java
@@ -0,0 +1,25 @@
+/**
+ * This is a function used when searhing for child nodes
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+import ch.psi.num.mountaingum.func.IFunc;
+
+public class NodeSearchFunc implements IFunc {
+	private String name;
+	
+	public NodeSearchFunc(String name){
+		this.name = name;
+	}
+	public Object apply(Object o) {
+		TreeNode n = (TreeNode)o;
+		if(name.equalsIgnoreCase(n.getName())){
+			return n;
+		}
+		return null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeValue.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeValue.java
new file mode 100755
index 0000000..600ed17
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/NodeValue.java
@@ -0,0 +1,92 @@
+/**
+ * This is the class representing the value of a parameter node 
+ * in MountainGum. Incidentally it is also the node for text data.
+ * Further subclasses support integer and float data.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+public class NodeValue {
+	/**
+	 * type codes
+	 */
+	public final static int TEXT  = 0;
+	public final static int INT   = 1;
+	public final static int FLOAT = 2;
+	public final static int LONG  = 3;
+	
+	protected int type;
+	protected int rank;
+	protected int dim[];
+	protected String textData;
+	
+	public NodeValue(){
+		type = TEXT;
+		rank = 1;
+		dim = new int[1];
+		dim[0] = 0;
+	}
+	public NodeValue(int type, int rank, int dim[]){
+		this.type = type;
+		this.rank = rank;
+		this.dim = dim;
+		textData = new String("Undefined");
+	}
+
+	public String toString(){
+		return textData;
+	}
+	
+	public void setFromString(String data){
+		textData = data;
+	}
+
+	public int getType() {
+		return type;
+	}
+
+	public int getRank() {
+		return rank;
+	}
+
+	public int[] getDim() {
+		return dim;
+	}
+
+	public void setDim(int[] dim) {
+		this.dim = dim;
+	}
+	protected  boolean testWhiteSpace(String text){
+		int i;
+		
+		for(i = 0; i < text.length(); i++){
+			if(!Character.isWhitespace(text.charAt(i))){
+				return false;
+			}
+		}
+		return true;
+	}
+	public int getLength(){
+		return 1;
+	}
+	public void reset(){
+		textData = "Undefined";
+	}
+	/**
+	 * These appends make most sense for numbers, not for strings, what this 
+	 * really is. 
+	 * @param i
+	 */
+	public void append(int i){
+		textData = Integer.toString(i);
+	}
+	public void append(double i){
+		textData = Double.toString(i);
+	}
+	public void append(long i){
+		textData = Long.toString(i);
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ParameterNode.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ParameterNode.java
new file mode 100755
index 0000000..c2a462c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/ParameterNode.java
@@ -0,0 +1,67 @@
+/**
+ * This is a node representing a parameter.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+import ch.psi.num.mountaingum.batch.BatchAdapter;
+import ch.psi.num.mountaingum.func.FuncUtil;
+import ch.psi.num.mountaingum.func.IFunc;
+import ch.psi.num.mountaingum.func.IteratorStream;
+import ch.psi.num.mountaingum.sys.SysRegistry;
+
+public abstract class ParameterNode extends ExecutableNode {
+	protected NodeValue v;
+	protected boolean initialized;
+	
+	public boolean isInitialized() {
+		return initialized;
+	}
+	public ParameterNode(TreeNode p, String name){
+		super(p,name);
+		v = new NodeValue();
+		readOnly = false;
+		initialized = false;
+	}
+	abstract public void setValue(String val);
+	public void enqueueValue(String val){
+		BatchAdapter ba = SysRegistry.getBatchAdapter();
+		ParameterNode pn = (ParameterNode)ba.cloneBatchNode(this);
+		pn.getValue().setFromString(val);
+		ba.append(pn);
+	}
+	abstract public void queryValue();
+	public void updateValue(String v){
+		this.v.setFromString(v);
+		initialized = true;
+	}
+	
+	public NodeValue getValue(){
+		return v;
+	}
+	private class UpdateNotify implements IFunc {
+		private TreeNode me;
+		UpdateNotify(TreeNode m){
+			me = m;
+		}
+		public Object apply(Object o){
+			UpdateListener ll = (UpdateListener)o;
+			ll.nodeUpdated(me);
+			return null;
+		}
+	}
+	public void notifyUpdate(){
+		initialized = true;
+		FuncUtil.map(new IteratorStream(updateListeners), new UpdateNotify(this));
+	}
+	public void configure(int type, int rank, int dim[]){
+		v = TreeUtil.makeNodeValue(type, rank, dim);
+	}
+	public void dispose() {
+		super.dispose();
+		v = null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/PropertySearchFunc.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/PropertySearchFunc.java
new file mode 100755
index 0000000..8c2c0ba
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/PropertySearchFunc.java
@@ -0,0 +1,32 @@
+/**
+ * This is a node processor which searches for a given property 
+ * with a given value.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, November 2008
+ */
+package ch.psi.num.mountaingum.tree;
+
+import ch.psi.num.mountaingum.func.IFunc;
+
+public class PropertySearchFunc implements IFunc {
+	private String key, value;
+	
+	public PropertySearchFunc(String k, String v){
+		key = k;
+		value = v;
+	}
+	
+	public Object apply(Object o) {
+		TreeNode n = (TreeNode)o;
+		String myValue = n.getProperty(key);
+		if(myValue != null){
+			if(myValue.compareToIgnoreCase(value) == 0){
+				return o;
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeListener.java
new file mode 100755
index 0000000..420a65a
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeListener.java
@@ -0,0 +1,12 @@
+/**
+ * a lsitener for changes to the tree structure
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+public interface TreeListener {
+	public void treeStructureChanged(TreeNode parent);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeNode.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeNode.java
new file mode 100755
index 0000000..ffc227e
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeNode.java
@@ -0,0 +1,298 @@
+/**
+ * The representation of a basic node in the tree
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+import java.util.Properties;
+import java.util.LinkedList;
+import ch.psi.num.mountaingum.func.*;
+
+public class TreeNode {
+	public final static int APPEND = -10;
+	public final static int PREPEND = -1;
+	
+	protected TreeNode parent;
+	protected TreeNode babies;
+	protected TreeNode previous, next;
+	protected boolean hidden;
+	
+	protected Properties p;
+	
+	LinkedList treeListeners;
+	
+	public TreeNode(TreeNode mama, String name){
+		this.parent = mama;
+		babies = null;
+		previous = next = null;
+		p = new Properties();
+		p.setProperty("name", name);
+		treeListeners = new LinkedList();
+		hidden = false;
+	}
+	/**
+	 * node insertion
+	 * @param where to insert
+	 * @param child node to insert
+	 */
+	public void insertNode(int where, TreeNode child){
+		TreeNode current = babies;
+        int count = 0;
+		
+		if(babies == null){
+			babies = child;
+			child.previous = null;
+			child.next = null;
+			return;
+		}
+		
+		
+		child.setParent(this);
+		switch(where){
+		case PREPEND:
+			child.next = babies;
+			babies.previous = child;
+			babies = child;
+			break;
+		case APPEND:
+			while(current.next != null){
+				current = current.next;
+			}
+			child.next = null;
+			child.previous = current;
+			current.next = child;
+			break;
+		default:
+			while(current.next != null && count < where){
+				current = current.next;
+				count++;			
+			}
+			child.next = current.next;
+			child.previous = current;
+			current.next = child;
+			break;
+		}
+	}
+	/**
+	 * count children
+	 * @return number of children
+	 */
+	public int countChildren(){
+		TreeNode current = babies;
+		int count = 0;
+		while(current != null){
+			count++;
+			current = current.next;
+		}
+		return count;
+	}
+	/**
+	 * return child at idx
+	 * @param idx index of child
+	 * @return null when found, TreeNod else
+	 */
+	public TreeNode getChild(int idx){
+		int count = 0;
+		TreeNode current = babies;
+		while(current != null && count < idx){
+			current = current.next;
+			count++;
+		}
+		return current;
+	}
+	/*
+	 * remove all children of this node
+	 */
+	public void deleteChildren(){
+		babies = null;
+	}
+	public void deleteChild(TreeNode tn){
+		if(tn == null){
+			return;
+		}
+		
+		if(tn == babies){
+			babies = tn.next;
+			tn.next.previous = null;
+			return;
+		}
+		
+		TreeNode prev = tn.previous;
+		TreeNode next = tn.next;
+		if(prev != null){
+			prev.next = next;
+		}
+		if(next != null){
+			next.previous = prev;
+		}
+		tn = null;
+	}
+	/**
+	 * get the parent of this node
+	 * @return A parent, can be null when root node
+	 */
+	public TreeNode getParent() {
+		return parent;
+	}
+	/**
+	 * set parent of node
+	 * @param parent new parent
+	 */
+	public void setParent(TreeNode parent) {
+		this.parent = parent;
+	}
+	/**
+	 * set a node property
+	 * @param key name of property
+	 * @param value value of property
+	 */
+	public void setProperty(String key, String value){
+		p.setProperty(key, value);
+	}
+	public void removeProperty(String key){
+		p.remove(key);
+	}
+	/**
+	 * get a property
+	 * @param key The key of the property to find
+	 * @return a value or null
+	 */
+	public String getProperty(String key){
+		return p.getProperty(key);
+	}
+	/**
+	 * get the node name 
+	 * @return The name of the node
+	 */
+	public String getName(){
+		return p.getProperty("name");
+	}
+	/**
+	 * add a TreeListener 
+	 * @param l The listener to add
+	 */
+	public void addTreeListener(TreeListener l){
+		treeListeners.add(l);
+	}
+	/**
+	 * remove a TreeListener
+	 * @param l The TreeListener to remove
+	 */
+	public void removeTreeListener(TreeListener l){
+		treeListeners.remove(l);
+	}
+	private class TreeNotify implements IFunc {
+		TreeNode me;
+		
+		public TreeNotify(TreeNode n){
+			me = n;
+		}
+		public Object apply(Object o){
+			TreeListener l = (TreeListener)o;
+			l.treeStructureChanged(me);
+			return null;
+		}
+	};
+	public void notifyTreeListeners(){
+		FuncUtil.map(new ArrayStream(treeListeners.toArray()), new TreeNotify(this));
+	}
+	private class TreeStream implements IStream {
+		private TreeNode parent, current;
+		private boolean start;
+		public TreeStream(TreeNode parent){
+			this.parent = parent;
+			current = parent;
+			start = true;
+		}
+		public Object next(){
+			TreeNode n = current;
+			
+			if(current == parent && start == true){
+				start = false;
+				current = babies;
+				return n;
+			}
+			if(current == null){
+				return null;
+			}
+			/*
+			 * if there are babies go into them
+			 */
+			if(current.babies != null){
+				current = current.babies;
+				return n;
+			}
+			/**
+			 * if no more babies, go to next node
+			 */
+			if(current.next != null){
+				current = current.next;
+			} else {
+				/* move up:
+				 * there are two conditions here: if current becomes the 
+				 * parent again we are finished.If there is no sibling one 
+				 * up we have to go up further until we find siblings
+				 */
+				do{
+					current = current.parent;
+				}while(current != null && current.next == null);
+				if(current == null || current == parent){
+					current = null;
+				} else {
+					current = current.next;
+				}
+			}
+			return n;
+		}
+	}
+	/**
+	 * get a stream to process all child nodes, recursively
+	 * @return A suitable stream for operating on all sub nodes. 
+	 */
+	public IStream getTreeStream(){
+		return new TreeStream(this);
+	}
+	private class CopyProp implements IFunc{
+		private TreeNode target;
+		CopyProp(TreeNode target){
+			this.target = target;
+		}
+		public Object apply(Object o) {
+			String name = (String)o;
+			String val = p.getProperty(name);
+			target.setProperty(name, val);
+			return null;
+		}
+	}
+	public void copyProperties(TreeNode target){
+		FuncUtil.map(new EnumerationStream(p.propertyNames()), new CopyProp(target));
+	}
+	public boolean isHidden() {
+		return hidden;
+	}
+	public void setHidden(boolean hidden) {
+		this.hidden = hidden;
+	}
+	public String toString() {
+		return getProperty("name");
+	}
+	public void dispose(){
+		TreeNode son, tmp;
+		
+		parent = null;
+		treeListeners = null;
+		p = null;
+		
+		son = babies;
+		while(son != null){
+			son.dispose();
+			tmp = son.next;
+			son.previous = null;
+			son.next = null;
+			son = tmp;
+		}
+		babies = null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeNodeList.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeNodeList.java
new file mode 100755
index 0000000..950fcad
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeNodeList.java
@@ -0,0 +1,84 @@
+/**
+ * This is an abstract class which maintains a  list of nodes which fulfill 
+ * some condition which derived classes define through their implementation of
+ * the abstract method test(). This class registers to the whole subtree 
+ * to be searched as a TreeChangeListener. When the tree changes the list 
+ * of nodes is updated and all NodeListListeners are updated. This class 
+ * was invented to maintain the list of all drivables, but it can be put to 
+ * other uses as well.
+ * 
+ *  copyrigth: GPL
+ *   
+ *  Mark Koennecke, August 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+import java.util.LinkedList;
+
+import ch.psi.num.mountaingum.func.FuncUtil;
+import ch.psi.num.mountaingum.func.IFunc;
+import ch.psi.num.mountaingum.func.IStream;
+import ch.psi.num.mountaingum.func.IteratorStream;
+
+public abstract class TreeNodeList implements TreeListener {
+	protected String searchPath;
+	protected LinkedList nodeList;
+	protected LinkedList listListeners;
+	
+	public TreeNodeList(String sp){
+		searchPath = sp;
+		nodeList = new LinkedList();
+		listListeners = new LinkedList();
+		TreeNode root = TreeRegistry.getInstance().getRoot();
+		root.addTreeListener(this);
+		treeStructureChanged(root);
+	}
+
+	protected abstract boolean test(TreeNode n);
+	
+	private class TestNode implements IFunc {
+
+		public Object apply(Object o) {
+			TreeNode n = (TreeNode)o;
+			if(test(n)){
+				nodeList.add(n);
+			}
+			n.removeTreeListener(TreeNodeList.this);
+			n.addTreeListener(TreeNodeList.this);
+			return null;
+		}
+		
+	}
+	public void treeStructureChanged(TreeNode parent) {
+		TreeNode root = TreeUtil.nodeForPath(searchPath);
+		if(root != null){
+			nodeList.clear();
+			FuncUtil.map(root.getTreeStream(), new TestNode());
+			notifyListeners();
+		}
+	}
+	public void addNodeListListener(NodeListListener l){
+		listListeners.add(l);
+	}
+	public void removeNodeListListener(NodeListListener l){
+		listListeners.remove(l);
+	}
+	public IStream getNodeStream(){
+		return new IteratorStream(nodeList);
+	}
+	private class InvokeListener implements IFunc {
+
+		public Object apply(Object o) {
+			NodeListListener l = (NodeListListener)o;
+			l.nodeListChanged(TreeNodeList.this);
+			return null;
+		}
+	}
+	private void notifyListeners() {
+		FuncUtil.map(new IteratorStream(listListeners), new InvokeListener());
+	}
+
+	public String getSearchPath() {
+		return searchPath;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeRegistry.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeRegistry.java
new file mode 100755
index 0000000..ca83c67
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeRegistry.java
@@ -0,0 +1,50 @@
+/**
+ * This is a central registry for Tree related things and editors and 
+ * displays to use with TreeNodes. This is a singleton.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+import java.util.HashMap;
+
+
+public class TreeRegistry {
+	private static TreeRegistry instance;
+	private TreeNode root;
+	private HashMap pathRegistry;
+	private HashMap nodeListRegistry;
+	
+	private TreeRegistry(){
+		root = new TreeNode(null,"");
+		root.insertNode(TreeNode.APPEND, new TreeNode(root,"Not_connected"));
+		pathRegistry = new HashMap();
+		nodeListRegistry = new HashMap();
+	}
+	
+	public static TreeRegistry getInstance(){
+		if(instance == null){
+			instance = new TreeRegistry();
+		}
+		return instance;
+	}
+	public TreeNode getRoot(){
+		return root;
+	}
+	public void registerEditorPath(String editor, String path){
+		pathRegistry.put(editor, path);
+	}
+	public String getEditorPath(String editor){
+		return (String)pathRegistry.get(editor);
+	}
+	public void registerNodeList(String key, TreeNodeList l){
+		nodeListRegistry.put(key, l);
+	}
+	public void removeNodeList(String key){
+		nodeListRegistry.remove(key);
+	}
+	public TreeNodeList getNodeList(String key){
+		return (TreeNodeList)nodeListRegistry.get(key);
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeUtil.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeUtil.java
new file mode 100755
index 0000000..d7cd618
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/TreeUtil.java
@@ -0,0 +1,258 @@
+/**
+ *   This is a class with various utility functions for helping out with trees.
+ * 
+ *   copyright: GPL
+ *   
+ *   Mark Koennecke, June 2007
+ *   
+ *   Added nodeForProperty, Mark Koennecke, November 2008
+ */
+package ch.psi.num.mountaingum.tree;
+import java.util.StringTokenizer;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Collections;
+import java.util.Iterator;
+import ch.psi.num.mountaingum.func.*;
+import ch.psi.num.mountaingum.sys.SysRegistry;
+
+public class TreeUtil {
+	public static NodeValue makeNodeValue(int type, int rank, int dim[]){
+		NodeValue v;
+		switch(type) {
+		case NodeValue.INT:
+			v = new IntValue(rank,dim);
+			break;
+		case NodeValue.LONG:
+			v = new LongValue(rank,dim);
+			break;
+		case NodeValue.FLOAT:
+			v = new DoubleValue(rank,dim);
+			break;
+		default:
+			v = new NodeValue(NodeValue.TEXT,rank,dim);
+			break;
+		}
+		return v;
+	}
+	public static TreeNode nodeForPath(String path){
+		return searchNode(TreeRegistry.getInstance().getRoot(),path);
+	}
+	public static TreeNode searchNode(TreeNode parent, String path){
+		TreeNode current = null;
+		String name;
+		List l;
+		
+		StringTokenizer st = new StringTokenizer(path,"/",false);
+		current = parent;
+		while(st.hasMoreElements()){
+			name = st.nextToken();
+			NodeSearchFunc f = new NodeSearchFunc(name);
+			l = FuncUtil.map(new ChildStream(current), f);
+			if(l.isEmpty()){
+				return null;
+			} else {
+				current = (TreeNode)l.get(0);
+			}
+		}
+		return current;
+	}
+	public static String pathForNode(TreeNode n){
+		String name;
+		StringBuffer path = new StringBuffer();
+		
+		if(n.getParent() == null){
+			return "/";
+		}
+		
+		LinkedList l = new LinkedList();
+		while(n != null){
+			l.add(n.getName());
+			n = n.getParent();
+		}
+		Collections.reverse(l);
+		Iterator it = l.iterator();
+		while(it.hasNext()){
+			name = (String)it.next();
+			if(name.length() > 0){
+				path.append("/");
+				path.append(name);
+			}
+		}
+		return path.toString();
+	}
+	public static TreeNode findChild(TreeNode parent, String name){
+		ChildStream cs = new ChildStream(parent);
+		TreeNode tn;
+		String testName;
+		
+		while((tn = (TreeNode)cs.next()) != null){
+			testName = tn.getName();
+			if(testName.equalsIgnoreCase(name)){
+				return tn;
+			}
+		}
+		return null;
+	}
+	public static double[] getNodeValueAsDouble(ParameterNode p){
+		NodeValue v = p.getValue();
+		int i;
+		switch(v.getType()){
+		case NodeValue.TEXT:
+			return null;
+		case NodeValue.INT:
+			IntValue iv = (IntValue)v;
+			int idata[] = iv.getData();
+			double d[] = new double[idata.length];
+			for(i = 0; i <  idata.length; i++){
+				d[i] = (double)idata[i];
+			}
+			return d;
+		case NodeValue.LONG:
+			LongValue lv = (LongValue)v;
+			long ldata[] = lv.getData();
+			double dl[] = new double[ldata.length];
+			for(i = 0; i < ldata.length; i++){
+				dl[i] = (double)ldata[i];
+			}
+			return dl;
+		case NodeValue.FLOAT:
+			DoubleValue fv = (DoubleValue)v;
+			return fv.getData();
+		default:
+			SysRegistry.getLogger().debug("getNodeValueAsDouble called with bad type code");
+			return null;
+		}
+	}
+	public static double getNodeValue(ParameterNode pn, int idx){
+		NodeValue v = pn.getValue();
+		switch(v.getType()){
+		case NodeValue.INT:
+			IntValue iv = (IntValue)v;
+			if(iv.getLength()-1 <= idx){
+				return (double)iv.getValue(idx);
+			} else {
+				return -9999.99;
+			}
+		case NodeValue.LONG:
+			LongValue lv = (LongValue)v;
+			if(lv.getLength()-1 <= idx){
+				return (double)lv.getValue(idx);
+			} else {
+				return -9999.99;
+			}
+		case NodeValue.FLOAT:
+			DoubleValue fv = (DoubleValue)v;
+			if(fv.getLength()-1 <= idx){
+				return fv.getValue(idx);
+			} else {
+				return -9999.99;
+			}
+		}
+		return  -9999.99;
+	}
+	public static void copyNodeValue(ParameterNode source, ParameterNode target) {
+		NodeValue nvs = source.getValue();
+		NodeValue nvt = target.getValue();
+		if(nvs.getType() != nvt.getType()){
+			SysRegistry.getLogger().debug("Type mismatch while trying to copy node values");
+			return;
+		}
+		switch(nvs.getType()){
+		case NodeValue.FLOAT:
+			DoubleValue ds = (DoubleValue)nvs;
+			DoubleValue dt = (DoubleValue)nvt;
+			dt.setData(ds.getData());
+			break;
+		case NodeValue.INT:
+			IntValue ids = (IntValue)nvs;
+			IntValue idt = (IntValue)nvt;
+			idt.setData(ids.getData());
+			break;
+		case NodeValue.LONG:
+			LongValue lds = (LongValue)nvs;
+			LongValue ldt = (LongValue)nvt;
+			ldt.setData(lds.getData());
+			break;
+		case NodeValue.TEXT:
+			nvt.setFromString(nvs.toString());
+			break;
+		}
+		target.notifyUpdate();
+	}
+	public static void copyNodeValueToDouble(ParameterNode node, double[] data) {
+		NodeValue v = node.getValue();
+		int i;
+		switch(v.getType()){
+		case NodeValue.TEXT:
+			break;
+		case NodeValue.INT:
+			IntValue iv = (IntValue)v;
+			int idata[] = iv.getRawData();
+			for(i = 0; i <  Math.min(idata.length, data.length); i++){
+				data[i] = (double)idata[i];
+			}
+			break;
+		case NodeValue.LONG:
+			LongValue lv = (LongValue)v;
+			long ldata[] = lv.getRawData();
+			for(i = 0; i < Math.min(ldata.length, data.length); i++){
+				data[i] = (double)ldata[i];
+			}
+			break;
+		case NodeValue.FLOAT:
+			DoubleValue fv = (DoubleValue)v;
+			double ddata[] = fv.getRawData();
+			System.arraycopy(ddata, 0, data, 0, data.length);
+			break;
+		default:
+			SysRegistry.getLogger().debug("copyNodeValueToDouble called with bad type code");
+			break;
+		}
+	}
+	public static TreeNode nodeForProperty(TreeNode parent, String key, String value){
+		PropertySearchFunc prs = new PropertySearchFunc(key,value);
+		List l = FuncUtil.map(parent.getTreeStream(), prs);
+		if(l.isEmpty()){
+			return null;
+		} else {
+			return (TreeNode)l.get(0);
+		}
+	}
+	/*
+	 * make a copy of the hierarchy under and including source consisting of 
+	 * InternalParameter Nodes. 
+	 * @param source The node to copy
+	 * @result A copy of the subtree including source
+	 */
+	public static TreeNode privateDeepCopy(TreeNode source){
+		InternalParameter result = null;
+		TreeNode child, myChild;
+		ParameterNode p;
+		
+		result = new InternalParameter(null, source.getName());
+		if(source instanceof ParameterNode){
+			p = (ParameterNode) source;
+			result.setValue(p.getValue().toString());
+		}
+		source.copyProperties(result);
+		ChildStream children = new ChildStream(source);
+		while((child = (TreeNode)children.next()) != null){
+			myChild = privateDeepCopy(child);
+			result.insertNode(TreeNode.APPEND, myChild);
+		}
+		return result;
+	}
+	/**
+	 * locate the root of the hierarchy. 
+	 * @param in The node to start the search from
+	 * @return The root node
+	 */
+	public static TreeNode findRoot(TreeNode in){
+		TreeNode cur = in;
+		while(cur.getParent() != null){
+			cur = cur.getParent();
+		}
+		return cur;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/UpdateListener.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/UpdateListener.java
new file mode 100755
index 0000000..a18167a
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/tree/UpdateListener.java
@@ -0,0 +1,22 @@
+/**
+ * An interface for receiving updates about the node status.
+ * 
+ *  copyright: GPL
+ *  
+ *  Mark Koennecke, June 2007
+ */
+package ch.psi.num.mountaingum.tree;
+
+public interface UpdateListener {
+	/**
+	 * called when the node has new data
+	 * @param n The TreeNode which had been updated.
+	 */
+	public void nodeUpdated(TreeNode n);
+	/**
+	 * called when the node status changed: i.e. from readonly to editable 
+	 * etc. This may happen after a privilege change
+	 * @param node The TreeNode whose state changed.
+	 */
+	public void nodeStatusChanged(TreeNode node);
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/DataRange.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/DataRange.java
new file mode 100755
index 0000000..7a4a0dd
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/DataRange.java
@@ -0,0 +1,35 @@
+/**
+ * This is just a little class for holding the range of a data set.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2007
+ */
+package ch.psi.num.mountaingum.ui;
+
+public class DataRange {
+	public double min, max;
+	
+	public DataRange(){
+		min = Double.MAX_VALUE;
+		max =  Double.MIN_VALUE;
+	}
+	public void calculate(double d[]){
+		min = Double.MAX_VALUE;
+		max = -min;
+		for(int i = 0; i < d.length; i++){
+			if(d[i] < min){
+				min = d[i];
+			}
+			if(d[i] > max){
+				max = d[i];
+			}
+		}
+	}
+	public boolean isValid(){
+		if(min == Double.MAX_VALUE || max == Double.MIN_VALUE){
+			return false;
+		} 
+		return true;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/Graph.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/Graph.java
new file mode 100755
index 0000000..242ec9c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/Graph.java
@@ -0,0 +1,123 @@
+/**
+ * This abstract class implements some of the plumbing required to update 
+ * a graph when either the axis or the data associated with it changes. This 
+ * together with GrapData and GraphAxis. Derived classes are supposed to 
+ * implement makePlot() and changeData()
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2007
+ */
+package ch.psi.num.mountaingum.ui;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import ch.psi.num.mountaingum.func.FuncUtil;
+import ch.psi.num.mountaingum.func.IFunc;
+import ch.psi.num.mountaingum.func.IteratorStream;
+
+public abstract class Graph {
+	protected GraphAxis  xAxis;
+	protected GraphAxis  yAxis;
+	protected HashMap data;
+	
+	public Graph(){
+		data = new HashMap();
+		xAxis = null;
+		yAxis = null;
+	}
+	/**
+	 * makePlot is supposed to redraw the entire plot, axis, data 
+	 * and all from scratch. It is called after major changes, such as 
+	 * changes to axis or styles have been detected.
+	 */
+	public abstract void makePlot();
+	/**
+	 * changeData is called when only the plotted data is changed but 
+	 * nothing else. This ought to replace only the data, but it may call
+	 * makePlot when the underlying graphics system does not support the
+	 * exchange of the plot data only.
+	 */
+	public abstract void changeData(GraphData g);
+	public GraphAxis getXAxis() {
+		return xAxis;
+	}
+	public void setXAxis(GraphAxis axis) {
+		xAxis = axis;
+		xAxis.setGraph(this);
+	}
+	public GraphAxis getYAxis() {
+		return yAxis;
+	}
+	public void setYAxis(GraphAxis axis) {
+		yAxis = axis;
+		yAxis.setGraph(this);
+	}
+	public void addData(GraphData gd){
+		gd.setGraph(this);
+		data.put(gd.getName(), gd);
+	}
+	public GraphData getData(String name){
+		return (GraphData)data.get(name);
+	}
+	public void clearAll(){
+		data.clear();
+	}
+	public DataRange getMaxDataRange(){
+		DataRange res = new DataRange();
+		DataRange cur;
+		GraphData gd = null;
+		
+		IteratorStream it = new IteratorStream(data.values());
+		while((gd = (GraphData)it.next()) != null){
+			cur = gd.getDataRange();
+			if(cur.max > res.max){
+				res.max = cur.max;
+			}
+			if(cur.min < res.min){
+				res.min = cur.min;
+			}
+		}
+		return res;
+	}
+	private class DataUpdate implements IFunc {
+
+		public Object apply(Object o) {
+			GraphData gd = (GraphData)o;
+			if(gd != null){
+				gd.getNode().queryValue();
+			}
+			return null;
+		}
+		
+	}
+	public boolean isValid() {
+		if(xAxis == null || data.isEmpty()){
+			return false;
+		}
+		DataRange dr = xAxis.getDataRange();
+		return dr.isValid();
+	}
+	public void refresh(){
+		if(xAxis != null){
+			xAxis.getNode().getValue();
+		}
+		if(yAxis != null){
+			yAxis.getNode().getValue();
+		}
+		FuncUtil.map(new IteratorStream(data.values()), new DataUpdate());
+	}
+	public void dispose() {
+		Iterator it = data.values().iterator();
+		while(it.hasNext()){
+			GraphData dg = (GraphData)it.next();
+			try{
+				dg.finalize();
+			}catch(Throwable t){}
+		}
+		data = null;
+		xAxis = null;
+		yAxis = null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/GraphAxis.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/GraphAxis.java
new file mode 100755
index 0000000..6230d42
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/GraphAxis.java
@@ -0,0 +1,56 @@
+/**
+ * This holds data for an Axis. It watches over log axis and makes the 
+ * plot redraw ehen the data on the watcehd node changes.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2007
+ */
+package ch.psi.num.mountaingum.ui;
+
+import ch.psi.num.mountaingum.tree.ParameterNode;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.tree.TreeUtil;
+
+public class GraphAxis extends GraphData {
+
+	protected boolean log;
+	public GraphAxis(String name, ParameterNode p) {
+		super(name, p);
+		log = false;
+	}
+	public boolean isLog() {
+		return log;
+	}
+	public void setLog(boolean log) {
+		this.log = log;
+		if(graph != null){
+			graph.makePlot();
+		}
+	}
+	public void nodeUpdated(TreeNode n){
+		//System.out.println(name + " updated ");
+		if(graph != null){
+			graph.makePlot();
+		}
+	}
+	public String getAxisName(){
+		ParameterNode pn = (ParameterNode)TreeUtil.findChild(node,"name");
+		if(pn != null){
+			return pn.getValue().toString();
+		} else {
+			return node.getName();
+		}
+	}
+	public int findIndex(double value){
+		int i;
+		//TODO: fix up for descending axis
+		getData();
+		for(i = 1; i < data.length; i++){
+			if(data[i] > value){
+				return i - 1;
+			}
+		}
+		return data.length-1;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/GraphData.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/GraphData.java
new file mode 100755
index 0000000..d4a79b5
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/GraphData.java
@@ -0,0 +1,159 @@
+/**
+ * This class manages the data associated with a graphical component: i.e,
+ * axis data or the data to be plotted. 
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, August 2007
+ * 
+ * Copying arrays all the time introduced reference leaks. Thus this 
+ * was rewritten to maintain a local copy of the node data for the 
+ * graphics and copy data from the node on each request. A local 
+ * copy of the data is required as the plot logic may require to 
+ * modify data. And if you do not allocate memory, it cannot 
+ * leak!
+ * 
+ * Mark Koennecke, June 2008
+ */
+package ch.psi.num.mountaingum.ui;
+
+
+import ch.psi.num.mountaingum.sys.SysRegistry;
+import ch.psi.num.mountaingum.tree.ParameterNode;
+import ch.psi.num.mountaingum.tree.TreeNode;
+import ch.psi.num.mountaingum.tree.TreeUtil;
+import ch.psi.num.mountaingum.tree.UpdateListener;
+
+public class GraphData implements UpdateListener {
+	protected Graph graph;
+	protected String name;
+	protected ParameterNode node;
+	protected Object style;
+	protected double data[];
+	
+	public GraphData(String name, ParameterNode p){
+		this.name = name;
+		style = null;
+		node = p;
+		graph = null;
+		node.addUpdateListener(this);
+		data = null;
+	}
+
+	public void nodeStatusChanged(TreeNode node) {
+		// nothing to do here
+	}
+
+	public void nodeUpdated(TreeNode n) {
+		if(graph != null){
+			SysRegistry.getLogger().debug("GraphData received new data");
+			//System.out.println("GraphData received new data");
+			graph.changeData(this);
+		}
+	}
+	public double[] getData(){
+		if(data == null || node.getValue().getLength() != data.length){
+			data = new double[node.getValue().getLength()];
+		}
+		TreeUtil.copyNodeValueToDouble(node, data);
+		return data;
+	}
+	public double getDataValue(int idx){
+		if(data == null){
+			getData();
+		}
+		return data[idx];
+	}
+	/**
+	 * when plotting logarithmically, values below or equal to zero
+	 * fuck up. This fixes this. 
+	 * @return A spick and spank data set ready for log plotting.
+	 */
+	public double[] getDataLogWashed(){
+		getData();
+		for(int i = 0; i < data.length; i++){
+			if(data[i] <= .0){
+				data[i] = .1;
+			}
+		}
+		return data;
+	}
+	public Graph getGraph() {
+		return graph;
+	}
+
+	public DataRange getDataRange(){
+		DataRange dr = new DataRange();
+		double d[] = getData();
+		if(d != null){
+			dr.calculate(d);
+		}
+		d = null;
+		return dr;
+	}
+	public int getDataLength(){
+		return node.getValue().getLength();
+	}
+	public void setGraph(Graph graph) {
+		this.graph = graph;
+	}
+
+	public Object getStyle() {
+		return style;
+	}
+
+	public void setStyle(Object style) {
+		this.style = style;
+		if(graph != null){
+			graph.makePlot();
+		}
+	}
+
+	public String getName() {
+		return name;
+	}
+	
+	public String getAxisName(){
+		ParameterNode pn = (ParameterNode)TreeUtil.findChild(node,"name");
+		if(pn != null){
+			return pn.getValue().toString();
+		} else {
+			return name;
+		}
+	}
+
+	public int findIndex(double val){
+		int res = 0;
+		if(data == null){
+			return 0;
+		}
+		while(data[res] < val  && res < data.length -1){
+			res++;
+		}
+		return res;
+	}
+	public ParameterNode getNode() {
+		return node;
+	}
+	public String getTitle(){
+		ParameterNode  pn = (ParameterNode)TreeUtil.findChild(node.getParent(), "title");
+		if(pn != null){
+			return pn.getValue().toString();
+		} else {
+			return node.getParent().getName();
+		}
+	}
+	public double getValue(int pos[]){
+		if(data == null){
+			getData();
+		}
+		return data[pos[0]];
+	}
+	public void finalize() throws Throwable {
+		data = null;
+		graph = null;
+		node = null;
+		//System.out.println("Killing GraphData.." );
+		super.finalize();
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/UIAdapter.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/UIAdapter.java
new file mode 100755
index 0000000..58c2256
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/UIAdapter.java
@@ -0,0 +1,22 @@
+/**
+ * This is the adapter to the UI lower level code may use. Currently 
+ * there is not much except displaying an error. This is the default 
+ * implementation. Applications may choose to override this and set an
+ * improved instance at the UIRegistry.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.ui;
+
+import ch.psi.num.mountaingum.sys.SysRegistry;
+
+public class UIAdapter {
+	public void displayError(String txt){
+		SysRegistry.getLogger().error(txt);
+	}
+	public void runInUIThread(Runnable r){
+		SysRegistry.getLogger().error("Running in UI Thread not implemented");
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/UIRegistry.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/UIRegistry.java
new file mode 100755
index 0000000..44fe3be
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/ui/UIRegistry.java
@@ -0,0 +1,22 @@
+/**
+ * A static class to access and adpater to the UI. To be used by lower level code.
+ * 
+ *  copyright: GPL
+ *  
+ *  Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.ui;
+
+public class UIRegistry {
+	private static UIAdapter adapter = null;
+	
+	public static void setAdapter(UIAdapter a){
+		adapter = a;
+	}
+	public static UIAdapter getAdapter(){
+		if(adapter == null){
+			adapter = new UIAdapter();
+		}
+		return adapter;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Array2DUtil.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Array2DUtil.java
new file mode 100755
index 0000000..f374551
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Array2DUtil.java
@@ -0,0 +1,223 @@
+/**
+ * This is a utility class for defining some array manipulation methods. This will be 
+ * used to rotate, mirror or otherwise manipulate 2D arrays in order to create an image 
+ * which satisfies the instrument scientists. Please note that I usally work with 1D 
+ * arrays which in reality are 2D arrays. 
+ * 
+ * copyright: see file COPYRIGHT
+ * 
+ * Mark Koennecke, March 2007
+ */
+package ch.psi.num.mountaingum.util;
+
+public class Array2DUtil {
+	/*
+	 * rotate the array by 90 degree which is synonymous with swapping 
+	 * the dimensions.
+	 * @param src The source array with dims oriXdim, oriYDim
+	 * @param target The target array where the data will be oriYDim, oriXdim
+	 * @param oriXdim the xsize of src
+	 * @param oriYdim the ysize of src.
+	 */
+	public void rotate90(double src[], double target[], int oriXdim, int oriYdim)
+		throws Exception {
+		int indSrc, indTarget, x, y;
+		
+		if(src.length != target.length){
+			throw new Exception("Data size mismatch");
+		}
+		
+		//System.out.println("Dimensions, x, y: " + oriXdim + ", " + oriYdim);
+		for(y = 0; y < oriYdim; y++){
+			for(x = 0; x < oriXdim; x++){
+				indSrc = calcIndex(x,y,oriXdim, oriYdim);
+				indTarget = calcIndex(y,x,oriYdim, oriXdim);
+				//System.out.println("Mapping " + indSrc + " to " + indTarget);
+				target[indTarget] = src[indSrc];
+			}
+		}
+	}
+	/*
+	 * mirorY the dimensions. Puts y0 on top ymax to 0
+	 * @param src The source array with dims oriXdim, oriYDim
+	 * @param target The target array where the data will be mirrored
+	 * @param oriXdim the xsize of src
+	 * @param oriYdim the ysize of src.
+	 */
+	public void mirrorY(double src[], double target[], int oriXdim, int oriYdim)
+		throws Exception {
+		int indSrc, indTarget, x, y;
+		
+		if(src.length != target.length){
+			throw new Exception("Data size mismatch");
+		}
+		
+		for(y = 0; y < oriYdim; y++){
+			for(x = 0; x < oriXdim; x++){
+				indSrc = calcIndex(x,y,oriXdim, oriYdim);
+				indTarget = calcIndex(x,oriYdim - y,oriXdim, oriYdim);
+				target[indTarget] = src[indSrc];
+			}
+		}
+	}
+	/*
+	 * mirorX the dimensions. Puts x0 to xmax and vice versa 
+	 * @param src The source array with dims oriXdim, oriYDim
+	 * @param target The target array where the data will be mirrored
+	 * @param oriXdim the xsize of src
+	 * @param oriYdim the ysize of src.
+	 */
+	public void mirrorX(double src[], double target[], int oriXdim, int oriYdim)
+		throws Exception {
+		int indSrc, indTarget, x, y;
+		
+		if(src.length != target.length){
+			throw new Exception("Data size mismatch");
+		}
+		
+		for(y = 0; y < oriYdim; y++){
+			for(x = 0; x < oriXdim; x++){
+				indSrc = calcIndex(x,y,oriXdim, oriYdim);
+				indTarget = calcIndex(oriXdim - x -1,y,oriXdim, oriYdim);
+				target[indTarget] = src[indSrc];
+			}
+		}
+	}
+	/*
+	 * rotate the array by 90 degree which is synonymous with swapping 
+	 * the dimensions.
+	 * @param src The source array with dims oriXdim, oriYDim
+	 * @param target The target array where the data will be oriYDim, oriXdim
+	 * @param oriXdim the xsize of src
+	 * @param oriYdim the ysize of src.
+	 */
+	public void rotate90(int src[], int target[], int oriXdim, int oriYdim)
+		throws Exception {
+		int indSrc, indTarget, x, y;
+		
+		if(src.length != target.length){
+			throw new Exception("Data size mismatch");
+		}
+		
+		//System.out.println("Dimensions, x, y: " + oriXdim + ", " + oriYdim);
+		for(y = 0; y < oriYdim; y++){
+			for(x = 0; x < oriXdim; x++){
+				indSrc = calcIndex(x,y,oriXdim, oriYdim);
+				indTarget = calcIndex(y,x,oriYdim, oriXdim);
+				//System.out.println("Mapping " + indSrc + " to " + indTarget);
+				target[indTarget] = src[indSrc];
+			}
+		}
+	}
+	/*
+	 * mirorY the dimensions. Puts y0 on top ymax to 0
+	 * @param src The source array with dims oriXdim, oriYDim
+	 * @param target The target array where the data will be mirrored
+	 * @param oriXdim the xsize of src
+	 * @param oriYdim the ysize of src.
+	 */
+	public void mirrorY(int src[], int target[], int oriXdim, int oriYdim)
+		throws Exception {
+		int indSrc, indTarget, x, y;
+		
+		if(src.length != target.length){
+			throw new Exception("Data size mismatch");
+		}
+		
+		for(y = 0; y < oriYdim; y++){
+			for(x = 0; x < oriXdim; x++){
+				indSrc = calcIndex(x,y,oriXdim, oriYdim);
+				indTarget = calcIndex(x,oriYdim - y,oriXdim, oriYdim);
+				target[indTarget] = src[indSrc];
+			}
+		}
+	}
+	/*
+	 * mirorX the dimensions. Puts x0 to xmax and vice versa 
+	 * @param src The source array with dims oriXdim, oriYDim
+	 * @param target The target array where the data will be mirrored
+	 * @param oriXdim the xsize of src
+	 * @param oriYdim the ysize of src.
+	 */
+	public void mirrorX(int src[], int target[], int oriXdim, int oriYdim)
+		throws Exception {
+		int indSrc, indTarget, x, y;
+		
+		if(src.length != target.length){
+			throw new Exception("Data size mismatch");
+		}
+		
+		for(y = 0; y < oriYdim; y++){
+			for(x = 0; x < oriXdim; x++){
+				indSrc = calcIndex(x,y,oriXdim, oriYdim);
+				indTarget = calcIndex(oriXdim - x -1,y,oriXdim, oriYdim);
+				target[indTarget] = src[indSrc];
+			}
+		}
+	}
+	/**
+	 * make a projection on the x axis
+	 * @param srcData The data to project from
+	 * @param xdim x dimension
+	 * @param ydim y dimension
+	 * @param xstart x index to start projection
+	 * @param xend y index to end projection
+	 * @param ystart y index to starting summing
+	 * @param yend y index of end of summing
+	 */
+	public double[] projectX(double srcData[], double projData[],
+			int xdim, int ydim, int xstart, int xend, 
+			int ystart, int yend){
+		int i, j, k, idx;
+		
+		int length = xend - xstart;
+		for(i = xstart, k = 0; i < xend; i++, k++){
+			projData[k] = .0;
+			for(j = ystart; j < yend; j++){
+				idx = calcIndex(i,j,xdim,ydim);
+				projData[k] += srcData[idx];
+			}
+		}
+		return projData;
+	}
+	/**
+	 * make a projection on the Y axis
+	 * @param srcData The data to project from
+	 * @param xdim x dimension
+	 * @param ydim y dimension
+	 * @param xstart x index to start summing
+	 * @param xend y index to end summing
+	 * @param ystart y index to starting projecting
+	 * @param yend y index to end projecting
+	 */
+	public double[] projectY(double srcData[], double projData[],
+			int xdim, int ydim, int xstart, int xend, 
+			int ystart, int yend){
+		int i, j, k, idx;
+		
+		int length = yend - ystart;
+		for(i = ystart, k = 0; i < yend; i++, k++){
+			projData[k] = .0;
+			for(j = xstart; j < xend; j++){
+				idx = calcIndex(j,i,xdim,ydim);
+				projData[k] += srcData[idx];
+			}
+		}
+		return projData;
+	}
+	
+	/**
+	 * calculate the index of a data item in the array
+	 * @param x The x coordinate
+	 * @param y  The y coordinate
+	 * @param xdim The x size
+	 * @param ydim The y size
+	 * @return An index into the array.
+	 */
+	private int calcIndex(int x, int y, int xdim, int ydim){
+		int address = 0;
+		
+		address = y * xdim + x;
+		return address;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/ArrayTools.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/ArrayTools.java
new file mode 100755
index 0000000..a0522fa
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/ArrayTools.java
@@ -0,0 +1,409 @@
+/*
+ * ArrayTools.java
+ * Copyright (c) 2004, KTH NADA.
+ *
+ * This file is part of SweSum^2 (see http://swesum.nada.kth.se/),
+ * and is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, see
+ * http://opensource.org/licenses/gpl-license.php
+ *
+ * Martin Hassel, 2004-feb-01
+ * http://www.nada.kth.se/~xmartin/
+ *
+ */
+
+//package moj.util;
+package ch.psi.num.mountaingum.util;
+
+/**
+ * A small utility class that contains methods for converting between strings 
+ * and arrays, as well as increasing and decreasing the size of arrays.
+ * 
+ * @author Martin Hassel
+ * @version 2004-Oct-18
+ */
+
+public final class ArrayTools {
+	
+	//// String to Array methods ////
+	
+	/**
+	 * Converts a string of numbers to a byte array. Observe that a byte
+	 * ranges from -127 to 127
+	 *
+	 * @param str String of numbers to convert
+	 * @param fieldSeparator String that separates each number
+	 * @return an array of bytes
+	 */
+	public static byte[] splitBytes(String str, String fieldSeparator){
+		String[] fields = str.split(fieldSeparator);
+		byte[] tmp = new byte[fields.length];
+		for(int i = 0; i < tmp.length; i++)
+			tmp[i] = Byte.parseByte(fields[i]);
+		return tmp;
+	}
+	
+	/**
+	 * Converts a string of numbers to a short array
+	 *
+	 * @param str String of numbers to convert
+	 * @param fieldSeparator String that separates each number
+	 * @return an array of shorts
+	 */
+	public static short[] splitShorts(String str, String fieldSeparator){
+		String[] fields = str.split(fieldSeparator);
+		short[] tmp = new short[fields.length];
+		for(int i = 0; i < tmp.length; i++)
+			tmp[i] = Short.parseShort(fields[i]);
+		return tmp;
+	}
+	
+	/**
+	 * Converts a string of numbers to an integer array
+	 *
+	 * @param str String of numbers to convert
+	 * @param fieldSeparator String that separates each number 
+	 * @return an array of integers
+	 */
+	public static int[] splitInts(String str, String fieldSeparator){
+		String[] fields = str.split(fieldSeparator);
+		int[] tmp = new int[fields.length];
+		for(int i = 0; i < tmp.length; i++)
+			tmp[i] = Integer.parseInt(fields[i]);
+		return tmp;
+	}
+	
+	/**
+	 * Converts a string of numbers to a long array
+	 *
+	 * @param str String of numbers to convert
+	 * @param fieldSeparator String that separates each number
+	 * @return an array of shorts
+	 */
+	public static long[] splitLongs(String str, String fieldSeparator){
+		String[] fields = str.split(fieldSeparator);
+		long[] tmp = new long[fields.length];
+		for(int i = 0; i < tmp.length; i++)
+			tmp[i] = Long.parseLong(fields[i]);
+		return tmp;
+	}
+	
+	/**
+	 * Convert a string of reals to a float array.
+	 *
+	 * @param str String of numbers to convert
+	 * @param fieldSeparator String that separates each number
+	 * @return an array of floats
+	 */
+	public static float[] splitFloats(String str, String fieldSeparator){
+		String[] fields = str.split(fieldSeparator);
+		float[] tmp = new float[fields.length];
+		for(int i = 0; i < tmp.length; i++)
+			tmp[i] = Float.parseFloat(fields[i]);
+		return tmp;
+	}
+	
+	/**
+	 * Convert a string of reals to a double array.
+	 *
+	 * @param str String of numbers to convert
+	 * @param fieldSeparator String that separates each number
+	 * @return an array of doubles
+	 */
+	public static double[] splitDoubles(String str, String fieldSeparator){
+		String[] fields = str.split(fieldSeparator);
+		double[] tmp = new double[fields.length];
+		for(int i = 0; i < tmp.length; i++)
+			tmp[i] = Double.parseDouble(fields[i]);
+		return tmp;
+	}
+	
+	//// Re-sizing methods ////
+	
+	/**
+	 * Resizes an array of bytes. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static byte[] setSize(byte[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		byte[] v = new byte[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of chars. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static char[] resize(char[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		char[] v = new char[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of shors. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static short[] resize(short[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		short[] v = new short[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of ints. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static int[] resize(int[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		int[] v = new int[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of longs. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static long[] resize(long[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		long[] v = new long[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of floats. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static float[] resize(float[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		float[] v = new float[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of doubles. If the new size
+	 * is smaller only newSize elements will be copied.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static double[] resize(double[] a, int newSize) {
+		if(newSize < 0)
+			throw new IllegalArgumentException("Negative array size");
+		double[] v = new double[newSize];
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	/**
+	 * Resizes an array of Objects. If the new size
+	 * is smaller overflowing elements will be discarded.
+	 *
+	 * @param a the original array
+	 * @param newSize the size of the new array
+	 * @return a new array with the original elements in a copied to it
+	 */
+	public static Object[] resize(Object[] a, int newSize) {
+		if(newSize < 0) throw new IllegalArgumentException("Negative array size");
+		Class arrayClass = a.getClass().getComponentType();
+		Object[] v = (Object[]) java.lang.reflect.Array.newInstance(arrayClass, newSize);
+		System.arraycopy(a,0,v,0,newSize > a.length ? a.length : newSize);
+		return v;
+	}
+	
+	//// Array to String methods ////
+	
+	/**
+	 * Converts a array of numbers into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(byte[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	
+	/**
+	 * Converts a array of numbers into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(short[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	
+	/**
+	 * Converts a array of numbers into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(int[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	
+	/**
+	 * Converts a array of numbers into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(long[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	
+	/**
+	 * Converts a array of reals into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(float[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	
+	/**
+	 * Converts a array of reals into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(double[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	
+	/**
+	 * Converts an array of Objects into a String.
+	 *
+	 * @param array the array to convert
+	 * @param fieldSeparator string that separates each element
+	 * @return a String representation of the array
+	 */
+	public static String join(Object[] array, String fieldSeparator) {
+		StringBuffer sb = new StringBuffer();
+		for(int i = 0; i < array.length; i++)
+			sb.append(array[i]+fieldSeparator);
+		sb.setLength(sb.length() > 0 ? sb.length()-1 : 0);
+		return sb.toString();
+	}
+	/**
+	 * prints statistics on an array
+	 * @param d The array to analyze
+	 */
+	public static void printStats(int d[]){
+		int min = Integer.MAX_VALUE;
+		long max = -min;
+		int maxIndex = 0;
+		int i;
+		long sum = 0;
+		
+		for(i = 0; i < d.length; i++){
+			sum += d[i];
+			if(d[i] < min){
+				min = d[i];
+			}
+			if(d[i] > max){
+				max = d[i];
+				maxIndex = i;
+			}
+		}
+		System.out.println("Min, max, maxIndex, avg = " + min +", " +
+				max +", " + maxIndex + ", " + (double)sum/d.length);
+	}
+	/**
+	 * prints statistics on an array
+	 * @param d The array to analyze
+	 */
+	public static void printStats(double d[]){
+		double min = Integer.MAX_VALUE;
+		double max = -min;
+		int maxIndex = 0;
+		int i;
+		long sum = 0;
+		
+		for(i = 0; i < d.length; i++){
+			sum += d[i];
+			if(d[i] < min){
+				min = d[i];
+			}
+			if(d[i] > max){
+				max = d[i];
+				maxIndex = i;
+			}
+		}
+		System.out.println("Min, max, maxIndex, avg = " + min +", " +
+				max +", " + maxIndex + ", " + (double)sum/d.length);
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicDoubleArray.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicDoubleArray.java
new file mode 100755
index 0000000..f34f56d
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicDoubleArray.java
@@ -0,0 +1,81 @@
+/**
+ * A dynamic array of doubles. As Java does not have such an animal and using the 
+ * object based standard collection classes from Java would lead to the creation
+ * of many small objects. Which is inefficient.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.util;
+
+public class DynamicDoubleArray {
+	protected double data[];
+	protected int capacity, length;
+
+	public DynamicDoubleArray(){
+		capacity = 8;
+		length = 0;
+		data = new double[capacity];
+	}
+	public void reset(){
+		length = 0;
+	}
+	public void append(double i){
+		data[length] = i;
+		length++;
+		if(length >= capacity - 2){
+			capacity = capacity*2;
+			data = ArrayTools.resize(data, capacity);
+		}
+	}
+	public void append(double d[]){
+		if(d.length + length >= capacity - 1){
+			capacity = d.length + length*2;
+			data = ArrayTools.resize(data, capacity);
+		}
+		System.arraycopy(d, 0, data, length, d.length);
+		length += d.length;
+	}
+	public int getLength(){
+		return length;
+	}
+	public String toText(){
+		StringBuffer stb = new StringBuffer();
+		for(int i = 0; i < length; i++) {
+			stb.append(data[i]);
+			stb.append(' ');
+		}
+		return stb.toString();
+	}
+	public String toString(){
+		return toText();
+	}
+	public void setFromText(String txt){
+		data = ArrayTools.splitDoubles(txt, "\\p{Space}+");
+		length = data.length;
+		capacity = length;
+	}
+	public double[] getData(){
+		double r[];
+		r = new double[length];
+		System.arraycopy(data,0 , r, 0, length);
+		return r;
+	}
+	public double getValue(int idx){
+		return data[idx];
+	}
+	/**
+	 * access the raw array: take extra care! The array is certainly longer 
+	 * the length but onbly length values are defined.
+	 * Changes to the array which would affect length are not properly hounoured
+	 * @return a dangerous pointer to the raw data array. 
+	 */
+	public double[] getRawArray(){
+		return data;
+	}
+	protected void finalize() throws Throwable {
+		super.finalize();
+		data = null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicIntArray.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicIntArray.java
new file mode 100755
index 0000000..96ba282
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicIntArray.java
@@ -0,0 +1,86 @@
+/**
+ * A dynamic array of ints. As Java does not have such an animal and using the 
+ * object based standard collection classes from Java would lead to the creation
+ * of many small objects. Which is inefficient.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, July 2007
+ */
+package ch.psi.num.mountaingum.util;
+
+public class DynamicIntArray {
+	protected int data[];
+	protected int capacity, length;
+
+	public DynamicIntArray(){
+		capacity = 128;
+		length = 0;
+		data = new int[128];
+	}
+	public void reset(){
+		length = 0;
+	}
+	public void append(int i){
+		data[length] = i;
+		length++;
+		if(length >= capacity - 1){
+			capacity = capacity*2;
+			int[] duta = ArrayTools.resize(data, capacity);
+			data = null;
+			data = duta;
+		}
+	}
+	public void append(int d[]){
+		int duta[];
+		if(d.length + length >= capacity - 1){
+			capacity = d.length + length*2;
+			duta = ArrayTools.resize(data, capacity);
+			data = null;
+			data = duta;
+		}
+		System.arraycopy(d, 0, data, length, d.length);
+		length += d.length;
+	}
+	public int getLength(){
+		return length;
+	}
+	public String toText(){
+		StringBuffer stb = new StringBuffer();
+		for(int i = 0; i < length; i++) {
+			stb.append(data[i]);
+			stb.append(' ');
+		}
+		return stb.toString();
+	}
+	public void setFromText(String txt){
+		data = ArrayTools.splitInts(txt, "\\p{Space}+");
+		length = data.length;
+		capacity = length;
+	}
+	public String toString(){
+		return toText();
+	}
+	public int[] getData(){
+		int r[];
+		r = new int[length];
+		System.arraycopy(data,0 , r, 0, length);
+		return r;
+	}
+	public int getValue(int idx){
+		return data[idx];
+	}
+	/**
+	 * access the raw array: take extra care! The array is certainly longer 
+	 * then length but only length values are defined.
+	 * Changes to the array which would affect length are not properly honoured
+	 * @return a dangerous pointer to the raw data array. 
+	 */
+	public int[] getRawArray(){
+		return data;
+	}
+	protected void finalize() throws Throwable {
+		super.finalize();
+		data = null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicLongArray.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicLongArray.java
new file mode 100755
index 0000000..3da8b87
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/DynamicLongArray.java
@@ -0,0 +1,79 @@
+/**
+ * This is a dynamic array for long values. Needed to store time stamps
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, February 2008
+ */
+package ch.psi.num.mountaingum.util;
+
+public class DynamicLongArray {
+	protected long data[];
+	protected int capacity, length;
+
+	public DynamicLongArray(){
+		capacity = 128;
+		length = 0;
+		data = new long[128];
+	}
+	public void reset(){
+		length = 0;
+	}
+	public void append(long i){
+		data[length] = i;
+		length++;
+		if(length >= capacity - 1){
+			capacity = capacity*2;
+			data = ArrayTools.resize(data, capacity);
+		}
+	}
+	public void append(long d[]){
+		if(d.length + length >= capacity - 1){
+			capacity = d.length + length*2;
+			data = ArrayTools.resize(data, capacity);
+		}
+		System.arraycopy(d, 0, data, length, d.length);
+		length += d.length;
+	}
+	public int getLength(){
+		return length;
+	}
+	public String toText(){
+		StringBuffer stb = new StringBuffer();
+		for(int i = 0; i < length; i++) {
+			stb.append(data[i]);
+			stb.append(' ');
+		}
+		return stb.toString();
+	}
+	public void setFromText(String txt){
+		data = ArrayTools.splitLongs(txt, "\\p{Space}+");
+		length = data.length;
+		capacity = length;
+	}
+	public String toString(){
+		return toText();
+	}
+	public long[] getData(){
+		long r[];
+		r = new long[length];
+		System.arraycopy(data,0 , r, 0, length);
+		return r;
+	}
+	public long getValue(int idx){
+		return data[idx];
+	}
+	/**
+	 * access the raw array: take extra care! The array is certainly longer 
+	 * then length but only length values are defined.
+	 * Changes to the array which would affect length are not properly honoured
+	 * @return a dangerous pointer to the raw data array. 
+	 */
+	public long[] getRawArray(){
+		return data;
+	}
+	protected void finalize() throws Throwable {
+		super.finalize();
+		data = null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Fmt.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Fmt.java
new file mode 100755
index 0000000..e3c9b89
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Fmt.java
@@ -0,0 +1,610 @@
+// Fmt - some simple single-arg sprintf-like routines
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef at acme.com>.  All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+package ch.psi.num.mountaingum.util;
+
+// package Acme;
+
+/// Some simple single-arg sprintf-like routines.
+// <P>
+// It is apparently impossible to declare a Java method that accepts
+// variable numbers of any type of argument.  You can declare it to take
+// Objects, but numeric variables and constants are not in fact Objects.
+// <P>
+// However, using the built-in string concatenation, it's almost as
+// convenient to make a series of single-argument formatting routines.
+// <P>
+// Fmt can format the following types:
+// <BLOCKQUOTE><CODE>
+// byte short int long float double char String Object
+// </CODE></BLOCKQUOTE>
+// For each type there is a set of overloaded methods, each returning
+// a formatted String.  There's the plain formatting version:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x )
+// </PRE></BLOCKQUOTE>
+// There's a version specifying a minimum field width:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x, minWidth )
+// </PRE></BLOCKQUOTE>
+// And there's a version that takes flags:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x, minWidth, flags )
+// </PRE></BLOCKQUOTE>
+// Currently available flags are:
+// <BLOCKQUOTE><PRE>
+// Fmt.ZF - zero-fill
+// Fmt.LJ - left justify
+// Fmt.HX - hexadecimal
+// Fmt.OC - octal
+// </PRE></BLOCKQUOTE>
+// The HX and OC flags imply unsigned output.
+// <P>
+// For doubles and floats, there's a significant-figures parameter before
+// the flags:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( d )
+// Fmt.fmt( d, minWidth )
+// Fmt.fmt( d, minWidth, sigFigs )
+// Fmt.fmt( d, minWidth, sigFigs, flags )
+// </PRE></BLOCKQUOTE>
+// <P>
+// <A HREF="/resources/classes/Acme/Fmt.java">Fetch the software.</A><BR>
+// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
+// <HR>
+// Similar classes:
+// <UL>
+// <LI> Andrew Scherpbier's <A HREF="http://www.sdsu.edu/doc/java-SDSU/sdsu.FormatString.html">FormatString</A>
+// Tries to allow variable numbers of arguments by
+// supplying overloaded routines with different combinations of parameters,
+// but doesn't actually supply that many.  The floating point conversion
+// is described as "very incomplete".
+// <LI> Core Java's <A HREF="http://www.apl.jhu.edu/~hall/java/CoreJava-Format.html">Format</A>.
+// The design seems a little weird.  They want you to create an instance,
+// passing the format string to the constructor, and then call an instance
+// method with your data to do the actual formatting.  The extra steps are
+// pointless; better to just use static methods.
+// </UL>
+
+public class Fmt
+    {
+
+    // Flags.
+    /// Zero-fill.
+    public static final int ZF = 1;
+    /// Left justify.
+    public static final int LJ = 2;
+    /// Hexadecimal.
+    public static final int HX = 4;
+    /// Octal.
+    public static final int OC = 8;
+    // Was a number - internal use.
+    private static final int WN = 16;
+
+    // byte
+    public static String fmt( byte b )
+	{
+	return fmt( b, 0, 0 );
+	}
+    public static String fmt( byte b, int minWidth )
+	{
+	return fmt( b, minWidth, 0 );
+	}
+    public static String fmt( byte b, int minWidth, int flags )
+	{
+	boolean hexadecimal = ( ( flags & HX ) != 0 );
+	boolean octal = ( ( flags & OC ) != 0 );
+	if ( hexadecimal )
+	    return fmt( Integer.toString( b & 0xff, 16 ), minWidth, flags|WN );
+	else if ( octal )
+	    return fmt( Integer.toString( b & 0xff, 8 ), minWidth, flags|WN );
+	else
+	    return fmt( Integer.toString( b & 0xff ), minWidth, flags|WN );
+	}
+
+    // short
+    public static String fmt( short s )
+	{
+	return fmt( s, 0, 0 );
+	}
+    public static String fmt( short s, int minWidth )
+	{
+	return fmt( s, minWidth, 0 );
+	}
+    public static String fmt( short s, int minWidth, int flags )
+	{
+	boolean hexadecimal = ( ( flags & HX ) != 0 );
+	boolean octal = ( ( flags & OC ) != 0 );
+	if ( hexadecimal )
+	    return fmt(
+		Integer.toString( s & 0xffff, 16 ), minWidth, flags|WN );
+	else if ( octal )
+	    return fmt(
+		Integer.toString( s & 0xffff, 8 ), minWidth, flags|WN );
+	else
+	    return fmt( Integer.toString( s ), minWidth, flags|WN );
+	}
+
+    // int
+    public static String fmt( int i )
+	{
+	return fmt( i, 0, 0 );
+	}
+    public static String fmt( int i, int minWidth )
+	{
+	return fmt( i, minWidth, 0 );
+	}
+    public static String fmt( int i, int minWidth, int flags )
+	{
+	boolean hexadecimal = ( ( flags & HX ) != 0 );
+	boolean octal = ( ( flags & OC ) != 0 );
+	if ( hexadecimal )
+	    return fmt(
+		Long.toString( i & 0xffffffffL, 16 ), minWidth, flags|WN );
+	else if ( octal )
+	    return fmt(
+		Long.toString( i & 0xffffffffL, 8 ), minWidth, flags|WN );
+	else
+	    return fmt( Integer.toString( i ), minWidth, flags|WN );
+	}
+
+    // long
+    public static String fmt( long l )
+	{
+	return fmt( l, 0, 0 );
+	}
+    public static String fmt( long l, int minWidth )
+	{
+	return fmt( l, minWidth, 0 );
+	}
+    public static String fmt( long l, int minWidth, int flags )
+	{
+	boolean hexadecimal = ( ( flags & HX ) != 0 );
+	boolean octal = ( ( flags & OC ) != 0 );
+	if ( hexadecimal )
+	    {
+	    if ( ( l & 0xf000000000000000L ) != 0 )
+		return fmt(
+		    Long.toString( l >>> 60, 16 ) +
+		    fmt( l & 0x0fffffffffffffffL, 15, HX|ZF ),
+		    minWidth, flags|WN );
+	    else
+		return fmt( Long.toString( l, 16 ), minWidth, flags|WN );
+	    }
+	else if ( octal )
+	    {
+	    if ( ( l & 0x8000000000000000L ) != 0 )
+		return fmt(
+		    Long.toString( l >>> 63, 8 ) +
+		    fmt( l & 0x7fffffffffffffffL, 21, OC|ZF ),
+		    minWidth, flags|WN );
+	    else
+		return fmt( Long.toString( l, 8 ), minWidth, flags|WN );
+	    }
+	else
+	    return fmt( Long.toString( l ), minWidth, flags|WN );
+	}
+
+    // float
+    public static String fmt( float f )
+	{
+	return fmt( f, 0, 0, 0 );
+	}
+    public static String fmt( float f, int minWidth )
+	{
+	return fmt( f, minWidth, 0, 0 );
+	}
+    public static String fmt( float f, int minWidth, int sigFigs )
+	{
+	return fmt( f, minWidth, sigFigs, 0 );
+	}
+    public static String fmt( float f, int minWidth, int sigFigs, int flags )
+	{
+	if ( sigFigs != 0 )
+	    return fmt(
+		sigFigFix( Float.toString( f ), sigFigs ), minWidth,
+		flags|WN );
+	else
+	    return fmt( Float.toString( f ), minWidth, flags|WN );
+	}
+
+    // double
+    public static String fmt( double d )
+	{
+	return fmt( d, 0, 0, 0 );
+	}
+    public static String fmt( double d, int minWidth )
+	{
+	return fmt( d, minWidth, 0, 0 );
+	}
+    public static String fmt( double d, int minWidth, int sigFigs )
+	{
+	return fmt( d, minWidth, sigFigs, 0 );
+	}
+    public static String fmt( double d, int minWidth, int sigFigs, int flags )
+	{
+	if ( sigFigs != 0 )
+	    return fmt(
+		sigFigFix( doubleToString( d ), sigFigs ), minWidth,
+		flags|WN );
+	else
+	    return fmt( doubleToString( d ), minWidth, flags|WN );
+	}
+
+    // char
+    public static String fmt( char c )
+	{
+	return fmt( c, 0, 0 );
+	}
+    public static String fmt( char c, int minWidth )
+	{
+	return fmt( c, minWidth, 0 );
+	}
+    public static String fmt( char c, int minWidth, int flags )
+	{
+	// return fmt( Character.toString( c ), minWidth, flags );
+	// Character currently lacks a static toString method.  Workaround
+	// is to make a temporary instance and use the instance toString.
+	return fmt( new Character( c ).toString(), minWidth, flags );
+	}
+
+    // Object
+    public static String fmt( Object o )
+	{
+	return fmt( o, 0, 0 );
+	}
+    public static String fmt( Object o, int minWidth )
+	{
+	return fmt( o, minWidth, 0 );
+	}
+    public static String fmt( Object o, int minWidth, int flags )
+	{
+	return fmt( o.toString(), minWidth, flags );
+	}
+
+    // String
+    public static String fmt( String s )
+	{
+	return fmt( s, 0, 0 );
+	}
+    public static String fmt( String s, int minWidth )
+	{
+	return fmt( s, minWidth, 0 );
+	}
+    public static String fmt( String s, int minWidth, int flags )
+	{
+	int len = s.length();
+	boolean zeroFill = ( ( flags & ZF ) != 0 );
+	boolean leftJustify = ( ( flags & LJ ) != 0 );
+	boolean hexadecimal = ( ( flags & HX ) != 0 );
+	boolean octal = ( ( flags & OC ) != 0 );
+	boolean wasNumber = ( ( flags & WN ) != 0 );
+	if ( ( hexadecimal || octal || zeroFill ) && ! wasNumber )
+	    throw new InternalError( "Acme.Fmt: number flag on a non-number" );
+	if ( zeroFill && leftJustify )
+	    throw new InternalError( "Acme.Fmt: zero-fill left-justify is silly" );
+	if ( hexadecimal && octal )
+	    throw new InternalError( "Acme.Fmt: can't do both hex and octal" );
+	if ( len >= minWidth )
+	    return s;
+	int fillWidth = minWidth - len;
+	StringBuffer fill = new StringBuffer( fillWidth );
+	for ( int i = 0; i < fillWidth; ++i )
+	    if ( zeroFill )
+		fill.append( '0' );
+	    else
+		fill.append( ' ' );
+	if ( leftJustify )
+	    return s + fill;
+	else if ( zeroFill && s.startsWith( "-" ) )
+	    return "-" + fill + s.substring( 1 );
+	else
+	    return fill + s;
+	}
+
+
+    // Internal routines.
+
+    private static String sigFigFix( String s, int sigFigs )
+	{
+	// First dissect the floating-point number string into sign,
+	// integer part, fraction part, and exponent.
+	String sign;
+	String unsigned;
+	if ( s.startsWith( "-" ) || s.startsWith( "+" ) )
+	    {
+	    sign = s.substring( 0, 1 );
+	    unsigned = s.substring( 1 );
+	    }
+	else
+	    {
+	    sign = "";
+	    unsigned = s;
+	    }
+	String mantissa;
+	String exponent;
+	int eInd = unsigned.indexOf( 'e' );
+	if ( eInd == -1 )
+	    {
+	    mantissa = unsigned;
+	    exponent = "";
+	    }
+	else
+	    {
+	    mantissa = unsigned.substring( 0, eInd );
+	    exponent = unsigned.substring( eInd );
+	    }
+	StringBuffer number, fraction;
+	int dotInd = mantissa.indexOf( '.' );
+	if ( dotInd == -1 )
+	    {
+	    number = new StringBuffer( mantissa );
+	    fraction = new StringBuffer( "" );
+	    }
+	else
+	    {
+	    number = new StringBuffer( mantissa.substring( 0, dotInd ) );
+	    fraction = new StringBuffer( mantissa.substring( dotInd + 1 ) );
+	    }
+
+	int numFigs = number.length();
+	int fracFigs = fraction.length();
+	if ( ( numFigs == 0 || number.equals( "0" ) ) && fracFigs > 0 )
+	    {
+	    // Don't count leading zeros in the fraction.
+	    numFigs = 0;
+	    for ( int i = 0; i < fraction.length(); ++i )
+		{
+		if ( fraction.charAt( i ) != '0' )
+		    break;
+		--fracFigs;
+		}
+	    }
+	int mantFigs = numFigs + fracFigs;
+	if ( sigFigs > mantFigs )
+	    {
+	    // We want more figures; just append zeros to the fraction.
+	    for ( int i = mantFigs; i < sigFigs; ++i )
+		fraction.append( '0' );
+	    }
+	else if ( sigFigs < mantFigs && sigFigs >= numFigs )
+	    {
+	    // Want fewer figures in the fraction; chop.
+	    fraction.setLength(
+		fraction.length() - ( fracFigs - ( sigFigs - numFigs ) ) );
+	    // Round?
+	    }
+	else if ( sigFigs < numFigs )
+	    {
+	    // Want fewer figures in the number; turn them to zeros.
+	    fraction.setLength( 0 );	// should already be zero, but make sure
+	    for ( int i = sigFigs; i < numFigs; ++i )
+		number.setCharAt( i, '0' );
+	    // Round?
+	    }
+	// Else sigFigs == mantFigs, which is fine.
+
+	if ( fraction.length() == 0 )
+	    return sign + number + exponent;
+	else
+	    return sign + number + "." + fraction + exponent;
+	}
+
+
+    /// Improved version of Double.toString(), returns more decimal places.
+    // <P>
+    // The JDK 1.0.2 version of Double.toString() returns only six decimal
+    // places on some systems.  In JDK 1.1 full precision is returned on
+    // all platforms.
+    // @deprecated
+    // @see java.lang.Double#toString
+    public static String doubleToString( double d )
+	{
+	// Handle special numbers first, to avoid complications.
+	if ( Double.isNaN( d ) )
+	    return "NaN";
+	if ( d == Double.NEGATIVE_INFINITY )
+	    return "-Inf";
+	if ( d == Double.POSITIVE_INFINITY )
+	    return "Inf";
+
+	// Grab the sign, and then make the number positive for simplicity.
+	boolean negative = false;
+	if ( d < 0.0D )
+	    {
+	    negative = true;
+	    d = -d;
+	    }
+
+	// Get the native version of the unsigned value, as a template.
+	String unsStr = Double.toString( d );
+
+	// Dissect out the exponent.
+	String mantStr, expStr;
+	int exp;
+	int eInd = unsStr.indexOf( 'e' );
+	if ( eInd == -1 )
+	    {
+	    mantStr = unsStr;
+	    expStr = "";
+	    exp = 0;
+	    }
+	else
+	    {
+	    mantStr = unsStr.substring( 0, eInd );
+	    expStr = unsStr.substring( eInd + 1 );
+	    if ( expStr.startsWith( "+" ) )
+		exp = Integer.parseInt( expStr.substring( 1 ) );
+	    else
+		exp = Integer.parseInt( expStr );
+	    }
+
+	// Dissect out the number part.
+	String numStr;
+	int dotInd = mantStr.indexOf( '.' );
+	if ( dotInd == -1 )
+	    numStr = mantStr;
+	else
+	    numStr = mantStr.substring( 0, dotInd );
+	long num;
+	if ( numStr.length() == 0 )
+	    num = 0;
+	else
+	    num = Integer.parseInt( numStr );
+
+	// Build the new mantissa.
+	StringBuffer newMantBuf = new StringBuffer( numStr + "." );
+	double p = Math.pow( 10, exp );
+	double frac = d - num * p;
+	String digits = "0123456789";
+	int nDigits = 16 - numStr.length();	// about 16 digits in a double
+	for ( int i = 0; i < nDigits; ++i )
+	    {
+	    p /= 10.0D;
+	    int dig = (int) ( frac / p );
+	    if ( dig < 0 ) dig = 0;
+	    if ( dig > 9 ) dig = 9;
+	    newMantBuf.append( digits.charAt( dig ) );
+	    frac -= dig * p;
+	    }
+
+	if ( (int) ( frac / p + 0.5D ) == 1 )
+	    {
+	    // Round up.
+	    boolean roundMore = true;
+	    for ( int i = newMantBuf.length() - 1; i >= 0; --i )
+		{
+		int dig = digits.indexOf( newMantBuf.charAt( i ) );
+		if ( dig == -1 )
+		    continue;
+		++dig;
+		if ( dig == 10 )
+		    {
+		    newMantBuf.setCharAt( i, '0' );
+		    continue;
+		    }
+		newMantBuf.setCharAt( i, digits.charAt( dig ) );
+		roundMore = false;
+		break;
+		}
+	    if ( roundMore )
+		{
+		// If this happens, we need to prepend a 1.  But I haven't
+		// found a test case yet, so I'm leaving it out for now.
+		// But if you get this message, please let me know!
+		newMantBuf.append( "ROUNDMORE" );
+		}
+	    }
+
+	// Chop any trailing zeros.
+	int len = newMantBuf.length();
+	while ( newMantBuf.charAt( len - 1 ) == '0' )
+	    newMantBuf.setLength( --len );
+	// And chop a trailing dot, if any.
+	if ( newMantBuf.charAt( len - 1 ) == '.' )
+	    newMantBuf.setLength( --len );
+
+	// Done.
+	return ( negative ? "-" : "" ) +
+	       newMantBuf +
+	       ( expStr.length() != 0 ? ( "e" + expStr ) : "" );
+	}
+
+
+/******************************************************************************
+    /// Test program.
+    public static void main( String[] args )
+	{
+	System.out.println( "Starting tests." );
+	show( Fmt.fmt( "Hello there." ) );
+	show( Fmt.fmt( 123 ) );
+	show( Fmt.fmt( 123, 10 ) );
+	show( Fmt.fmt( 123, 10, Fmt.ZF ) );
+	show( Fmt.fmt( 123, 10, Fmt.LJ ) );
+	show( Fmt.fmt( -123 ) );
+	show( Fmt.fmt( -123, 10 ) );
+	show( Fmt.fmt( -123, 10, Fmt.ZF ) );
+	show( Fmt.fmt( -123, 10, Fmt.LJ ) );
+	show( Fmt.fmt( (byte) 0xbe, 22, Fmt.OC ) );
+	show( Fmt.fmt( (short) 0xbabe, 22, Fmt.OC ) );
+	show( Fmt.fmt( 0xcafebabe, 22, Fmt.OC ) );
+	show( Fmt.fmt( 0xdeadbeefcafebabeL, 22, Fmt.OC ) );
+	show( Fmt.fmt( 0x8000000000000000L, 22, Fmt.OC ) );
+	show( Fmt.fmt( (byte) 0xbe, 16, Fmt.HX ) );
+	show( Fmt.fmt( (short) 0xbabe, 16, Fmt.HX ) );
+	show( Fmt.fmt( 0xcafebabe, 16, Fmt.HX ) );
+	show( Fmt.fmt( 0xdeadbeefcafebabeL, 16, Fmt.HX ) );
+	show( Fmt.fmt( 0x8000000000000000L, 16, Fmt.HX ) );
+	show( Fmt.fmt( 'c' ) );
+	show( Fmt.fmt( new java.util.Date() ) );
+	show( Fmt.fmt( 123.456F ) );
+	show( Fmt.fmt( 123456000000000000.0F ) );
+	show( Fmt.fmt( 123.456F, 0, 8 ) );
+	show( Fmt.fmt( 123.456F, 0, 7 ) );
+	show( Fmt.fmt( 123.456F, 0, 6 ) );
+	show( Fmt.fmt( 123.456F, 0, 5 ) );
+	show( Fmt.fmt( 123.456F, 0, 4 ) );
+	show( Fmt.fmt( 123.456F, 0, 3 ) );
+	show( Fmt.fmt( 123.456F, 0, 2 ) );
+	show( Fmt.fmt( 123.456F, 0, 1 ) );
+	show( Fmt.fmt( 123456000000000000.0F, 0, 4 ) );
+	show( Fmt.fmt( -123.456F, 0, 4 ) );
+	show( Fmt.fmt( -123456000000000000.0F, 0, 4 ) );
+	show( Fmt.fmt( 123.0F ) );
+	show( Fmt.fmt( 123.0D ) );
+	show( Fmt.fmt( 1.234567890123456789F ) );
+	show( Fmt.fmt( 1.234567890123456789D ) );
+	show( Fmt.fmt( 1234567890123456789F ) );
+	show( Fmt.fmt( 1234567890123456789D ) );
+	show( Fmt.fmt( 0.000000000000000000001234567890123456789F ) );
+	show( Fmt.fmt( 0.000000000000000000001234567890123456789D ) );
+	show( Fmt.fmt( 12300.0F ) );
+	show( Fmt.fmt( 12300.0D ) );
+	show( Fmt.fmt( 123000.0F ) );
+	show( Fmt.fmt( 123000.0D ) );
+	show( Fmt.fmt( 1230000.0F ) );
+	show( Fmt.fmt( 1230000.0D ) );
+	show( Fmt.fmt( 12300000.0F ) );
+	show( Fmt.fmt( 12300000.0D ) );
+	show( Fmt.fmt( Float.NaN ) );
+	show( Fmt.fmt( Float.POSITIVE_INFINITY ) );
+	show( Fmt.fmt( Float.NEGATIVE_INFINITY ) );
+	show( Fmt.fmt( Double.NaN ) );
+	show( Fmt.fmt( Double.POSITIVE_INFINITY ) );
+	show( Fmt.fmt( Double.NEGATIVE_INFINITY ) );
+	show( Fmt.fmt( 1.0F / 8.0F ) );
+	show( Fmt.fmt( 1.0D / 8.0D ) );
+	System.out.println( "Done with tests." );
+	}
+
+    private static void show( String str )
+	{
+	System.out.println( "#" + str + "#" );
+	}
+******************************************************************************/
+
+    }
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/ListSequence.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/ListSequence.java
new file mode 100755
index 0000000..a480024
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/ListSequence.java
@@ -0,0 +1,48 @@
+/**
+ * This is linked list implementation of the Sequence interface. This is inefficient
+ * for text editing but as Maountaingum batch queues are not expected to hold more 
+ * then a hundred entries, this is OK.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.util;
+
+import java.util.LinkedList;
+
+public class ListSequence implements Sequence {
+
+	private LinkedList l;
+	public ListSequence(){
+		l = new LinkedList();
+	}
+	public void delete(int pos) {
+		l.remove(pos);
+	}
+	public void delete(int start, int end) {
+		for(int i = start; i < end; i++){
+			l.remove(start);
+		}
+	}
+	public boolean empty() {
+		return l.isEmpty();
+	}
+	public void insert(int position, Object o) {
+		l.add(position,o);
+	}
+
+	public void insert(int position, Sequence s) {
+		for(int i = 0; i < s.length(); i++){
+			l.add(position+i,s.itemAt(i));
+		}
+	}
+
+	public Object itemAt(int pos) {
+		return l.get(pos);
+	}
+
+	public int length() {
+		return l.size();
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Sequence.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Sequence.java
new file mode 100755
index 0000000..1644937
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/Sequence.java
@@ -0,0 +1,56 @@
+/**
+ * This is an interface for managing a sequence of edit items, like in 
+ * a text editor. It is inspired by the paper:
+ * 
+ * Charles Crowley: Data Structures for Text Sequences
+ * 
+ * I have a gut feeling that I need this interface though the implementation for 
+ * Mountaingum will be based on a primitive linked list.
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.util;
+
+public interface Sequence {
+	/**
+	 * is the sequence empty?
+	 * @return true or flase
+	 */
+	public boolean empty();
+	/**
+	 * insert o at position
+	 * @param position The position where to insert the item
+	 * @param o The item to insert
+	 */
+	public void insert(int position, Object o);
+	/**
+	 * insert a sequence 
+	 * @param position the position where to start inserting the sequence
+	 * @param s The sequence to insert
+	 */
+	public void insert(int position, Sequence s);
+	/**
+	 * delete the item at pos
+	 * @param pos The index of the item to delete.
+	 */
+	public void delete(int pos);
+	/**
+	 * delete several items
+	 * @param start
+	 * @param end
+	 */
+	public void delete(int start, int end);
+	/**
+	 * return the item at pos
+	 * @param pos The index into the sequence
+	 * @return The element at pos or null.
+	 */
+	public Object itemAt(int pos);
+	/**
+	 * return the length of the sequence
+	 * @return The length
+	 */
+	public int length();
+}
diff --git a/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/SequenceStream.java b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/SequenceStream.java
new file mode 100755
index 0000000..607df7c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumsys/src/ch/psi/num/mountaingum/util/SequenceStream.java
@@ -0,0 +1,29 @@
+/**
+ * This is a stream wrapper for a sequence
+ * 
+ * copyright: GPL
+ * 
+ * Mark Koennecke, January 2008
+ */
+package ch.psi.num.mountaingum.util;
+
+import ch.psi.num.mountaingum.func.IStream;
+
+public class SequenceStream implements IStream {
+	private int count, length;
+	private Sequence s;
+	
+	public SequenceStream(Sequence s){
+		this.s = s;
+		count = 0;
+		length = s.length();
+	}
+	public Object next() {
+		if(count < length){
+			Object o = s.itemAt(count);
+			count++;
+			return o;
+		}
+		return null;
+	}
+}
diff --git a/contrib/applications/nxplot/mountaingumuibase/.project b/contrib/applications/nxplot/mountaingumuibase/.project
new file mode 100755
index 0000000..f65924c
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumuibase/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mountaingumuibase</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/mountaingumuibase/.settings/org.eclipse.jdt.core.prefs b/contrib/applications/nxplot/mountaingumuibase/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 0000000..a67c808
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumuibase/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Wed Oct 21 11:46:43 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/contrib/applications/nxplot/mountaingumuibase/META-INF/MANIFEST.MF b/contrib/applications/nxplot/mountaingumuibase/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..e8ab1e7
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumuibase/META-INF/MANIFEST.MF
@@ -0,0 +1,71 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Mountaingumuibase
+Bundle-SymbolicName: mountaingumuibase;singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Vendor: Mark Koennecke, PSI
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: mountaingumsys;bundle-version="0.1.0",
+ org.eclipse.nebula.compositetable;bundle-version="1.0.0",
+ sgtgraphics;bundle-version="3.1.0",
+ org.eclipse.swt;bundle-version="3.3.2",
+ org.eclipse.ui;bundle-version="3.3.1",
+ org.eclipse.core.runtime;bundle-version="3.3.100"
+Export-Package: ch.psi.num.mountaingum.ui.EditorView;
+  uses:="org.eclipse.swt.events,
+   ch.psi.num.mountaingum.sys,
+   org.eclipse.swt.custom,
+   ch.psi.num.mountaingum.ui.eclipse,
+   org.eclipse.ui.part,
+   ch.psi.num.mountaingum.tree,
+   org.eclipse.swt.widgets",
+ ch.psi.num.mountaingum.ui.GraphicsView;
+  uses:="ch.psi.num.mountaingum.func,
+   ch.psi.num.mountaingum.util,
+   org.eclipse.swt.printing,
+   org.eclipse.swt.events,
+   org.eclipse.ui,
+   org.eclipse.ui.part,
+   ch.psi.num.mountaingum.tree,
+   gov.noaa.pmel.sgt.swing,
+   ch.psi.num.mountaingum.ui,
+   gov.noaa.pmel.util,
+   org.eclipse.jface.action,
+   gov.noaa.pmel.sgt,
+   gov.noaa.pmel.sgt.dm,
+   ch.psi.num.mountaingum.ui.eclipse,
+   org.eclipse.jface.viewers,
+   org.eclipse.swt.widgets",
+ ch.psi.num.mountaingum.ui.GraphicsView.maps,
+ ch.psi.num.mountaingum.ui.QuickView;
+  uses:="org.eclipse.jface.action,
+   org.eclipse.swt.events,
+   org.eclipse.ui.actions,
+   org.eclipse.ui.part,
+   ch.psi.num.mountaingum.tree,
+   org.eclipse.swt.widgets",
+ ch.psi.num.mountaingum.ui.TreeViewer;
+  uses:="org.eclipse.jface.resource,
+   org.eclipse.swt.nebula.widgets.compositetable,
+   org.eclipse.swt.events,
+   org.eclipse.swt.custom,
+   ch.psi.num.mountaingum.tree,
+   org.eclipse.ui.part,
+   ch.psi.num.mountaingum.ui.EditorView,
+   org.eclipse.jface.viewers,
+   ch.psi.num.mountaingum.ui.eclipse,
+   org.eclipse.swt.graphics,
+   org.eclipse.swt.widgets",
+ ch.psi.num.mountaingum.ui.eclipse;
+  uses:="org.eclipse.jface.action,
+   gov.noaa.pmel.sgt,
+   org.eclipse.swt.printing,
+   org.eclipse.ui,
+   ch.psi.num.mountaingum.tree,
+   org.eclipse.swt.widgets",
+ ch.psi.num.mountaingum.ui.util;
+  uses:="org.eclipse.swt.graphics,
+   ch.psi.num.mountaingum.tree,
+   org.eclipse.swt.widgets,
+   org.eclipse.jface.dialogs",
+ ch.psi.num.mountaingum.ui.util.eclipse;uses:="org.eclipse.jface.action,org.eclipse.ui"
diff --git a/contrib/applications/nxplot/mountaingumuibase/build.properties b/contrib/applications/nxplot/mountaingumuibase/build.properties
new file mode 100755
index 0000000..e9863e2
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumuibase/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
diff --git a/contrib/applications/nxplot/mountaingumuibase/icons/lock-icon.png b/contrib/applications/nxplot/mountaingumuibase/icons/lock-icon.png
new file mode 100755
index 0000000..472627c
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumuibase/icons/lock-icon.png differ
diff --git a/contrib/applications/nxplot/mountaingumuibase/icons/lock25.gif b/contrib/applications/nxplot/mountaingumuibase/icons/lock25.gif
new file mode 100755
index 0000000..64d360c
Binary files /dev/null and b/contrib/applications/nxplot/mountaingumuibase/icons/lock25.gif differ
diff --git a/contrib/applications/nxplot/mountaingumuibase/plugin.xml b/contrib/applications/nxplot/mountaingumuibase/plugin.xml
new file mode 100755
index 0000000..16aab72
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumuibase/plugin.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+   <extension-point id="ch.psi.num.mountaingum.ui.eclipse.NodeEditor" name="NodeEditor" schema="schema/mountaingumuibase.NodeEditor.exsd"/>
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            class="ch.psi.num.mountaingum.ui.Switcher.SwitchView"
+            id="mountaingum.SwitchView"
+            name="SwitchView"/>
+      <stickyView
+            closeable="false"
+            moveable="false"
+            location="LEFT"
+            id="mountaingum.SwitchView"/>
+      <view
+            allowMultiple="true"
+            class="ch.psi.num.mountaingum.ui.EditorView.EditorView"
+            id="mountaingumui.EditorView"
+            name="Editor View"/>
+      <view
+            class="ch.psi.num.mountaingum.ui.QuickView.QuickView"
+            id="mountaingumui.QuickView"
+            name="QuickView"/>
+      <stickyView
+            closeable="false"
+            id="mountaingumui.QuickView"
+            location="LEFT"
+            moveable="true"/>
+      <view
+            class="ch.psi.num.mountaingum.ui.TreeViewer.BaseTreeView"
+            id="mountaingumui.BaseTreeView"
+            name="BaseTreeView">
+      </view>
+      <view
+            allowMultiple="true"
+            class="ch.psi.num.mountaingum.ui.EditorView.TreeEditorView"
+            id="mountaingumui.TreeEditorView"
+            name="TreeEditorView">
+      </view>
+   </extension>
+   <extension
+         point="ch.psi.num.mountaingum.ui.eclipse.NodeEditor">
+      <editor
+            className="ch.psi.num.mountaingum.ui.CommandView.DefaultCommandEditor"
+            id="mountaingumui.command"
+            name="Command  View Editor"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.GraphicsView.Graph1DSGT"
+            id="mountaingumui.graph1d"
+            name="Graph 1D"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.GraphicsView.Graph2DSGT"
+            id="mountaingumui.graph2d"
+            name="Graph 2D"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.GraphicsView.FrameSeries"
+            id="mountaingumui.frameseries"
+            name="Frame Series"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.DefaultParameterEditor"
+            id="mountaingumui.parametereditor"
+            name="Parameter Editor"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.DefaultCommandEditor"
+            id="mountaingumui.commandeditor"
+            name="Default Command Editor"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.SingleParEditor"
+            id="mountaingumui.SingleParEditor"
+            name="SingleParEditor"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.ScanEditor"
+            id="mountaingumui.ScanEditor"
+            name="Scan Editor"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.GraphicsView.CommandGraph1D"
+            id="mountaingumui.CommandGraph1D"
+            name="CommandGraph1D"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.GraphicsView.TimeSeriesSGT"
+            id="mountaingumui.TimeSeries"
+            name="Time Series SGT"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.TextEdit"
+            id="mountaingumui.TextEdit"
+            name="Text Editor"/>
+      <editor
+            className="ch.psi.num.mountaingum.GraphicsView.LogLog1DSGT"
+            id="mountaingumui.LogLog1D"
+            name="LogLog Viewer"/>
+      <editor
+            className="ch.psi.num.mountaingum.ui.GraphicsView.Graph2DProj"
+            id="mountaingumui.Graph2DProj"
+            name="Graphics 2D Projection"/>
+     <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.table.TableEditor"
+            id="mountaingumui.TableEditor"
+            name="TableEditor"/>
+     <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.table.DataTableEditor"
+            id="mountaingumui.DataTableEditor"
+            name="DataTableEditor"/>
+     <editor
+            className="ch.psi.num.mountaingum.ui.TreeViewer.CalcEditor"
+            id="mountaingumui.CalcEditor"
+            name="CalcEditor"/>
+   </extension>
+   <extension
+         point="org.eclipse.ui.actionSets">
+      <actionSet
+            id="mountaingumui.GraphActions"
+            label="Graphics Actions"
+            visible="false">
+         <action
+               class="ch.psi.num.mountaingum.ui.GraphicsView.HardcopyAction"
+               id="ch.psi.num.mountaingum.ui.GraphicsView.HardcopyAction"
+               label="Save to png"
+               menubarPath="mountaingum/additions"
+               style="push"
+               tooltip="Save the current graphics to png"/>
+         <action
+               class="ch.psi.num.mountaingum.ui.GraphicsView.PrintAction"
+               id="ch.psi.num.mountaingum.ui.GraphicsView.PrintAction"
+               label="Print"
+               menubarPath="mountaingum/additions"
+               style="push"/>
+      </actionSet>
+   </extension>
+</plugin>
diff --git a/contrib/applications/nxplot/mountaingumuibase/schema/mountaingumuibase.NodeEditor.exsd b/contrib/applications/nxplot/mountaingumuibase/schema/mountaingumuibase.NodeEditor.exsd
new file mode 100755
index 0000000..d9ef58b
--- /dev/null
+++ b/contrib/applications/nxplot/mountaingumuibase/schema/mountaingumuibase.NodeEditor.exsd
@@ -0,0 +1,117 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="mountaingumui">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="mountaingumui" id="mountaingumui.NodeEditor" name="NodeEditor"/>
+      </appInfo>
+      <documentation>
+         NodeEditor is a extension point which allows to contribute specialized viewers or 
+editors for TreeNodes.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <complexType>
+         <sequence>
+            <element ref="editor"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appInfo>
+                  <meta.attribute translatable="true"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="editor">
+      <complexType>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="className" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         December 2007
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="implementation"/>
+      </appInfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/contrib/applications/nxplot/nxplot-platform.lis b/contrib/applications/nxplot/nxplot-platform.lis
new file mode 100644
index 0000000..678ab41
--- /dev/null
+++ b/contrib/applications/nxplot/nxplot-platform.lis
@@ -0,0 +1,180 @@
+com.ibm.icu_4.0.1.v20090822.jar
+com.ibm.icu.source_4.0.1.v20090822.jar
+javax.servlet_2.5.0.v200806031605.jar
+org.eclipse.ant.core_3.2.100.v20090817_r351.jar
+org.eclipse.compare.core_3.5.0.I20090430-0408.jar
+org.eclipse.compare.win32_1.0.0.I20090430-0408.jar
+org.eclipse.compare.win32.source_1.0.0.I20090430-0408.jar
+org.eclipse.core.commands_3.5.0.I20090525-2000.jar
+org.eclipse.core.commands.source_3.5.0.I20090525-2000.jar
+org.eclipse.core.contenttype_3.4.1.R35x_v20090826-0451.jar
+org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar
+org.eclipse.core.databinding_1.2.0.M20090819-0800.jar
+org.eclipse.core.databinding.beans_1.2.0.I20090525-2000.jar
+org.eclipse.core.databinding.beans.source_1.2.0.I20090525-2000.jar
+org.eclipse.core.databinding.observable_1.2.0.M20090902-0800.jar
+org.eclipse.core.databinding.observable.source_1.2.0.M20090902-0800.jar
+org.eclipse.core.databinding.property_1.2.0.M20090819-0800.jar
+org.eclipse.core.databinding.property.source_1.2.0.M20090819-0800.jar
+org.eclipse.core.databinding.source_1.2.0.M20090819-0800.jar
+org.eclipse.core.expressions_3.4.100.v20090429-1800.jar
+org.eclipse.core.expressions.source_3.4.100.v20090429-1800.jar
+org.eclipse.core.filebuffers_3.5.0.v20090526-2000.jar
+org.eclipse.core.filesystem_1.2.0.v20090507.jar
+org.eclipse.core.filesystem.hpux.ia64_32_1.0.0.v20080604-1400.jar
+org.eclipse.core.filesystem.hpux.PA_RISC_1.0.0.v20080604-1400.jar
+org.eclipse.core.filesystem.linux.ppc_1.0.100.v20080604-1400.jar
+org.eclipse.core.filesystem.linux.x86_1.2.0.v20080604-1400.jar
+org.eclipse.core.filesystem.linux.x86_64_1.0.100.v20080604-1400.jar
+org.eclipse.core.filesystem.macosx_1.1.0.v20090112.jar
+org.eclipse.core.filesystem.qnx.x86_1.0.0.v20080604-1400.jar
+org.eclipse.core.filesystem.solaris.sparc_1.0.100.v20080604-1400.jar
+org.eclipse.core.filesystem.win32.x86_1.1.0.v20080604-1400.jar
+org.eclipse.core.filesystem.win32.x86_64_1.1.0.v20090316-0910.jar
+org.eclipse.core.jobs_3.4.100.v20090429-1800.jar
+org.eclipse.core.jobs.source_3.4.100.v20090429-1800.jar
+org.eclipse.core.net_1.2.1.r35x_20090812-1200.jar
+org.eclipse.core.net.linux.x86_1.1.0.I20081021.jar
+org.eclipse.core.net.win32.x86_1.0.0.I20080909.jar
+org.eclipse.core.net.win32.x86_64_1.0.0.I20090306-1030.jar
+org.eclipse.core.resources_3.5.1.R35x_v20090826-0451.jar
+org.eclipse.core.resources.compatibility_3.4.0.v20090505.jar
+org.eclipse.core.resources.win32.x86_3.5.0.v20081020.jar
+org.eclipse.core.runtime_3.5.0.v20090525.jar
+org.eclipse.core.runtime.compatibility.auth_3.2.100.v20090413.jar
+org.eclipse.core.runtime.compatibility.auth.source_3.2.100.v20090413.jar
+org.eclipse.core.runtime.compatibility.registry_3.2.200.v20090429-1800
+org.eclipse.core.runtime.source_3.5.0.v20090525.jar
+org.eclipse.core.variables_3.2.200.v20090521.jar
+org.eclipse.ecf_3.0.0.v20090831-1906.jar
+org.eclipse.ecf.filetransfer_3.0.0.v20090831-1906.jar
+org.eclipse.ecf.identity_3.0.0.v20090831-1906.jar
+org.eclipse.ecf.provider.filetransfer_3.0.1.v20090831-1906.jar
+org.eclipse.ecf.provider.filetransfer.ssl_1.0.0.v20090831-1906.jar
+org.eclipse.ecf.ssl_1.0.0.v20090831-1906.jar
+org.eclipse.equinox.app_1.2.0.v20090520-1800.jar
+org.eclipse.equinox.app.source_1.2.0.v20090520-1800.jar
+org.eclipse.equinox.common_3.5.1.R35x_v20090807-1100.jar
+org.eclipse.equinox.common.source_3.5.1.R35x_v20090807-1100.jar
+org.eclipse.equinox.concurrent_1.0.0.v20090520-1800.jar
+org.eclipse.equinox.ds_1.1.1.R35x_v20090806.jar
+org.eclipse.equinox.ds.source_1.1.1.R35x_v20090806.jar
+org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
+org.eclipse.equinox.launcher.carbon.macosx_1.0.200.v20090520-1835
+org.eclipse.equinox.launcher.cocoa.macosx_1.0.1.R35x_v20090707
+org.eclipse.equinox.launcher.cocoa.macosx.x86_64_1.0.1.R35x_v20090707
+org.eclipse.equinox.launcher.gtk.linux.ppc_1.0.200.v20090519
+org.eclipse.equinox.launcher.gtk.linux.s390_1.0.100.v20090426-1530
+org.eclipse.equinox.launcher.gtk.linux.s390x_1.0.100.v20090426-1530
+org.eclipse.equinox.launcher.gtk.linux.x86_1.0.200.v20090520
+org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.200.v20090519
+org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.201.R35x_v20090720
+org.eclipse.equinox.launcher.gtk.solaris.x86_1.0.201.R35x_v20090720
+org.eclipse.equinox.launcher.motif.aix.ppc_1.0.200.v20090519
+org.eclipse.equinox.launcher.motif.hpux.ia64_32_1.0.100.v20090519
+org.eclipse.equinox.launcher.motif.hpux.PA_RISC_1.0.100.v20090306-1900
+org.eclipse.equinox.launcher.motif.linux.x86_1.0.200.v20090520
+org.eclipse.equinox.launcher.motif.solaris.sparc_1.0.300.HEAD
+org.eclipse.equinox.launcher.source_1.0.201.R35x_v20090715.jar
+org.eclipse.equinox.launcher.win32.win32.x86_1.0.200.v20090519
+org.eclipse.equinox.launcher.win32.win32.x86_64_1.0.200.v20090519
+org.eclipse.equinox.launcher.wpf.win32.x86_1.0.200.v20090519
+org.eclipse.equinox.p2.artifact.repository_1.0.101.R35x_v20090721.jar
+org.eclipse.equinox.p2.core_1.0.101.R35x_v20090819.jar
+org.eclipse.equinox.p2.engine_1.0.101.R35x_v20090825.jar
+org.eclipse.equinox.p2.jarprocessor_1.0.100.v20090520-1905.jar
+org.eclipse.equinox.p2.metadata_1.0.100.v20090525.jar
+org.eclipse.equinox.p2.metadata.repository_1.0.101.R35x_v20090812.jar
+org.eclipse.equinox.p2.repository_1.0.1.v20090901-1041.jar
+org.eclipse.equinox.preferences_3.2.300.v20090520-1800.jar
+org.eclipse.equinox.preferences.source_3.2.300.v20090520-1800.jar
+org.eclipse.equinox.registry_3.4.100.v20090520-1800.jar
+org.eclipse.equinox.registry.source_3.4.100.v20090520-1800.jar
+org.eclipse.equinox.security_1.0.100.v20090520-1800.jar
+org.eclipse.equinox.security.macosx_1.100.0.v20090520-1800.jar
+org.eclipse.equinox.security.macosx.source_1.100.0.v20090520-1800.jar
+org.eclipse.equinox.security.win32.x86_1.0.100.v20090520-1800.jar
+org.eclipse.equinox.security.win32.x86.source_1.0.100.v20090520-1800.jar
+org.eclipse.equinox.simpleconfigurator_1.0.101.R35x_v20090807-1100.jar
+org.eclipse.equinox.simpleconfigurator.source_1.0.101.R35x_v20090807-1100.jar
+org.eclipse.equinox.util_1.0.100.v20090520-1800.jar
+org.eclipse.equinox.util.source_1.0.100.v20090520-1800.jar
+org.eclipse.help_3.4.1.v20090805_35x.jar
+org.eclipse.help.source_3.4.1.v20090805_35x.jar
+org.eclipse.jdt.launching.macosx_3.2.0.v20090527.jar
+org.eclipse.jdt.launching.macosx.source_3.2.0.v20090527.jar
+org.eclipse.jdt.launching.ui.macosx_1.0.0.v20090527.jar
+org.eclipse.jdt.launching.ui.macosx.source_1.0.0.v20090527.jar
+org.eclipse.jface_3.5.1.M20090826-0800.jar
+org.eclipse.jface.databinding_1.3.1.M20090826-0800.jar
+org.eclipse.jface.databinding.source_1.3.1.M20090826-0800.jar
+org.eclipse.jface.source_3.5.1.M20090826-0800.jar
+org.eclipse.jface.text_3.5.1.r351_v20090708-0800.jar
+org.eclipse.osgi_3.5.1.R35x_v20090827.jar
+org.eclipse.osgi.services_3.2.0.v20090520-1800.jar
+org.eclipse.osgi.services.source_3.2.0.v20090520-1800.jar
+org.eclipse.osgi.source_3.5.1.R35x_v20090827.jar
+org.eclipse.rcp_3.5.0.v200909170800.jar
+org.eclipse.rcp.source_3.5.0.v200909170800.jar
+org.eclipse.swt_3.5.1.v3555a.jar
+org.eclipse.swt.carbon.macosx_3.5.1.v3555a.jar
+org.eclipse.swt.carbon.macosx.source_3.5.1.v3555a.jar
+org.eclipse.swt.cocoa.macosx_3.5.1.v3555a.jar
+org.eclipse.swt.cocoa.macosx.source_3.5.1.v3555a.jar
+org.eclipse.swt.cocoa.macosx.x86_64_3.5.1.v3555a.jar
+org.eclipse.swt.cocoa.macosx.x86_64.source_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.linux.ppc_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.linux.ppc.source_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.linux.s390_3.5.0.v3550b.jar
+org.eclipse.swt.gtk.linux.s390.source_3.5.0.v3550b.jar
+org.eclipse.swt.gtk.linux.s390x_3.5.0.v3550b.jar
+org.eclipse.swt.gtk.linux.s390x.source_3.5.0.v3550b.jar
+org.eclipse.swt.gtk.linux.x86_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.linux.x86_64_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.linux.x86_64.source_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.linux.x86.source_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.solaris.sparc_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.solaris.sparc.source_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.solaris.x86_3.5.1.v3555a.jar
+org.eclipse.swt.gtk.solaris.x86.source_3.5.1.v3555a.jar
+org.eclipse.swt.motif.aix.ppc_3.5.1.v3555a.jar
+org.eclipse.swt.motif.aix.ppc.source_3.5.1.v3555a.jar
+org.eclipse.swt.motif.hpux.ia64_32_3.5.1.v3555a.jar
+org.eclipse.swt.motif.hpux.ia64_32.source_3.5.1.v3555a.jar
+org.eclipse.swt.motif.hpux.PA_RISC_3.5.0.HEAD.jar
+org.eclipse.swt.motif.hpux.PA_RISC.source_3.5.0.HEAD.jar
+org.eclipse.swt.motif.linux.x86_3.5.1.v3555a.jar
+org.eclipse.swt.motif.linux.x86.source_3.5.1.v3555a.jar
+org.eclipse.swt.motif.solaris.sparc_3.5.1.v3555a.jar
+org.eclipse.swt.motif.solaris.sparc.source_3.5.1.v3555a.jar
+org.eclipse.swt.photon.qnx.x86_3.5.1.v3555a.jar
+org.eclipse.swt.photon.qnx.x86.source_3.5.1.v3555a.jar
+org.eclipse.swt.win32.win32.x86_3.5.1.v3555a.jar
+org.eclipse.swt.win32.win32.x86_64_3.5.1.v3555a.jar
+org.eclipse.swt.win32.win32.x86_64.source_3.5.1.v3555a.jar
+org.eclipse.swt.win32.win32.x86.source_3.5.1.v3555a.jar
+org.eclipse.swt.wpf.win32.x86_3.5.1.v3555a.jar
+org.eclipse.swt.wpf.win32.x86.source_3.5.1.v3555a.jar
+org.eclipse.text_3.5.0.v20090513-2000.jar
+org.eclipse.ui_3.5.1.M20090902-1000.jar
+org.eclipse.ui.carbon_4.0.0.I20090525-2000.jar
+org.eclipse.ui.carbon.source_4.0.0.I20090525-2000.jar
+org.eclipse.ui.cocoa_1.0.0.I20090525-2000.jar
+org.eclipse.ui.cocoa.source_1.0.0.I20090525-2000.jar
+org.eclipse.ui.console_3.4.0.v20090513.jar
+org.eclipse.ui.editors_3.5.0.v20090527-2000.jar
+org.eclipse.ui.forms_3.4.1.v20090714_35x.jar
+org.eclipse.ui.ide_3.5.1.M20090826-0800.jar
+org.eclipse.ui.source_3.5.1.M20090902-1000.jar
+org.eclipse.ui.views_3.4.1.M20090826-0800.jar
+org.eclipse.ui.win32_3.2.100.v20090429-1800.jar
+org.eclipse.ui.win32.source_3.2.100.v20090429-1800.jar
+org.eclipse.ui.workbench_3.5.1.M20090826-0800a.jar
+org.eclipse.ui.workbench.source_3.5.1.M20090826-0800a.jar
+org.eclipse.ui.workbench.texteditor_3.5.0.v20090603.jar
+org.eclipse.update.configurator_3.3.0.v20090312.jar
+org.eclipse.update.configurator.source_3.3.0.v20090312.jar
+org.eclipse.update.core.linux_3.2.100.v20081008.jar
+org.eclipse.update.core.linux.source_3.2.100.v20081008.jar
+org.eclipse.update.core.win32_3.2.100.v20080107.jar
+org.eclipse.update.core.win32.source_3.2.100.v20080107.jar
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/.classpath b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/.classpath
new file mode 100755
index 0000000..e48a290
--- /dev/null
+++ b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry exported="true" kind="lib" path="" sourcepath="src.zip"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/.project b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/.project
new file mode 100755
index 0000000..82b03fd
--- /dev/null
+++ b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.nebula.compositetable</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/META-INF/MANIFEST.MF b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..099b1e2
--- /dev/null
+++ b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/META-INF/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Compositetable Plug-in
+Bundle-SymbolicName: org.eclipse.nebula.compositetable
+Bundle-Version: 1.0.0
+Bundle-ClassPath: .
+Bundle-Vendor: The Nebula Project, from outer space
+Bundle-Localization: plugin
+Export-Package: org.eclipse.swt.nebula.widgets.compositetable,
+ org.eclipse.swt.nebula.widgets.compositetable.day,
+ org.eclipse.swt.nebula.widgets.compositetable.day.internal,
+ org.eclipse.swt.nebula.widgets.compositetable.internal,
+ org.eclipse.swt.nebula.widgets.compositetable.month,
+ org.eclipse.swt.nebula.widgets.compositetable.month.internal,
+ org.eclipse.swt.nebula.widgets.compositetable.timeeditor
+Require-Bundle: org.eclipse.swt
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/build.properties b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/build.properties
new file mode 100755
index 0000000..876835f
--- /dev/null
+++ b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/build.properties
@@ -0,0 +1,4 @@
+source.. = .
+output.. = .
+bin.includes = META-INF/,\
+               org/
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbsoluteLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbsoluteLayout.class
new file mode 100755
index 0000000..f20bf7f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbsoluteLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractGridRowLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractGridRowLayout.class
new file mode 100755
index 0000000..88269fe
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractGridRowLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$1.class
new file mode 100755
index 0000000..1533fcb
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$2.class
new file mode 100755
index 0000000..3c7d15e
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$3.class
new file mode 100755
index 0000000..afe70f8
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$4.class
new file mode 100755
index 0000000..90d8c6a
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader.class
new file mode 100755
index 0000000..06bfceb
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractNativeHeader.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSelectableRow.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSelectableRow.class
new file mode 100755
index 0000000..a829a07
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSelectableRow.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader$1.class
new file mode 100755
index 0000000..7ec76f0
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader$2.class
new file mode 100755
index 0000000..23d71ce
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader.class
new file mode 100755
index 0000000..262c968
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/AbstractSortableHeader.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ColumnControlListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ColumnControlListener.class
new file mode 100755
index 0000000..ff1b813
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ColumnControlListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTable$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTable$1.class
new file mode 100755
index 0000000..3e3d25d
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTable$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTable.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTable.class
new file mode 100755
index 0000000..2813f20
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTable.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTableLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTableLayout.class
new file mode 100755
index 0000000..0d4de34
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/CompositeTableLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/DeleteAdapter.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/DeleteAdapter.class
new file mode 100755
index 0000000..3bb1e5f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/DeleteAdapter.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$1.class
new file mode 100755
index 0000000..1fddaf9
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$2.class
new file mode 100755
index 0000000..59a42c0
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$3.class
new file mode 100755
index 0000000..c5aa8a6
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$4.class
new file mode 100755
index 0000000..adbaf99
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$5.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$5.class
new file mode 100755
index 0000000..ba53d93
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$5.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$6.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$6.class
new file mode 100755
index 0000000..6bb349c
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder$6.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder.class
new file mode 100755
index 0000000..a0e9fd4
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/EmptyTablePlaceholder.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/GridRowLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/GridRowLayout.class
new file mode 100755
index 0000000..0fc82af
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/GridRowLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$1.class
new file mode 100755
index 0000000..8844d5b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$2.class
new file mode 100755
index 0000000..fb701d6
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$HeaderControlListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$HeaderControlListener.class
new file mode 100755
index 0000000..d9c90e6
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout$HeaderControlListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout.class
new file mode 100755
index 0000000..4203c44
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/HeaderLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IDeleteHandler.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IDeleteHandler.class
new file mode 100755
index 0000000..3502b5d
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IDeleteHandler.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IInsertHandler.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IInsertHandler.class
new file mode 100755
index 0000000..36996d1
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IInsertHandler.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IRowContentProvider.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IRowContentProvider.class
new file mode 100755
index 0000000..800ea96
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IRowContentProvider.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IRowFocusListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IRowFocusListener.class
new file mode 100755
index 0000000..df18634
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/IRowFocusListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$1.class
new file mode 100755
index 0000000..26659e2
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$10.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$10.class
new file mode 100755
index 0000000..883b8e3
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$10.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$11.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$11.class
new file mode 100755
index 0000000..50df153
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$11.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$12.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$12.class
new file mode 100755
index 0000000..c849b0a
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$12.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$2.class
new file mode 100755
index 0000000..2583b9a
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$3.class
new file mode 100755
index 0000000..9a9f5bc
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$4.class
new file mode 100755
index 0000000..920752b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$5.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$5.class
new file mode 100755
index 0000000..552ee7b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$5.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$6.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$6.class
new file mode 100755
index 0000000..c2a2043
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$6.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$7.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$7.class
new file mode 100755
index 0000000..78a2191
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$7.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$8.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$8.class
new file mode 100755
index 0000000..fb5a502
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$8.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$9.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$9.class
new file mode 100755
index 0000000..995f5ab
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable$9.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable.class
new file mode 100755
index 0000000..f8bc7eb
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/InternalCompositeTable.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout$1.class
new file mode 100755
index 0000000..3a52d51
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout$GridColumnControlListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout$GridColumnControlListener.class
new file mode 100755
index 0000000..1c2329b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout$GridColumnControlListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout.class
new file mode 100755
index 0000000..6ecfa84
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ResizableGridRowLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/RowConstructionListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/RowConstructionListener.class
new file mode 100755
index 0000000..3b19edc
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/RowConstructionListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/RowFocusAdapter.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/RowFocusAdapter.class
new file mode 100755
index 0000000..d257eb5
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/RowFocusAdapter.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ScrollEvent.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ScrollEvent.class
new file mode 100755
index 0000000..98618da
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ScrollEvent.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ScrollListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ScrollListener.class
new file mode 100755
index 0000000..5622fae
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/ScrollListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$1.class
new file mode 100755
index 0000000..da9c7de
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$2.class
new file mode 100755
index 0000000..4efb475
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$3.class
new file mode 100755
index 0000000..44aecbd
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow.class
new file mode 100755
index 0000000..1c8d579
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/TableRow.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableItemEvent.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableItemEvent.class
new file mode 100755
index 0000000..69451ea
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableItemEvent.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableItemEventHandler.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableItemEventHandler.class
new file mode 100755
index 0000000..fcbc396
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableItemEventHandler.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableSelectionChangeListener.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableSelectionChangeListener.class
new file mode 100755
index 0000000..03043a2
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/CalendarableSelectionChangeListener.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$1.class
new file mode 100755
index 0000000..d1771ac
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$10.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$10.class
new file mode 100755
index 0000000..d40cdf8
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$10.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$11.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$11.class
new file mode 100755
index 0000000..2f7bab3
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$11.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$12.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$12.class
new file mode 100755
index 0000000..e61cf03
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$12.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$13.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$13.class
new file mode 100755
index 0000000..85b4b8c
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$13.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$2.class
new file mode 100755
index 0000000..1f7d2ec
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$3.class
new file mode 100755
index 0000000..c942c65
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$4.class
new file mode 100755
index 0000000..70a2558
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$5.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$5.class
new file mode 100755
index 0000000..7f19c4f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$5.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$6.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$6.class
new file mode 100755
index 0000000..a50f633
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$6.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$7.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$7.class
new file mode 100755
index 0000000..a2584e8
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$7.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$8.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$8.class
new file mode 100755
index 0000000..3c0a6ea
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$8.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$9.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$9.class
new file mode 100755
index 0000000..952995c
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor$9.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor.class
new file mode 100755
index 0000000..cd70314
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditor.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditorSelection.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditorSelection.class
new file mode 100755
index 0000000..c7b3aa5
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/DayEditorSelection.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/ICalendarableItemControl.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/ICalendarableItemControl.class
new file mode 100755
index 0000000..30e1309
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/ICalendarableItemControl.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/NewEvent.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/NewEvent.class
new file mode 100755
index 0000000..5f27776
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/NewEvent.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/SelectionChangeEvent.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/SelectionChangeEvent.class
new file mode 100755
index 0000000..a92943b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/SelectionChangeEvent.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl$1.class
new file mode 100755
index 0000000..859363a
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl$2.class
new file mode 100755
index 0000000..8874b48
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl.class
new file mode 100755
index 0000000..721fcc2
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/DayEditorCalendarableItemControl.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/EventLayoutComputer$EventLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/EventLayoutComputer$EventLayout.class
new file mode 100755
index 0000000..77b4676
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/EventLayoutComputer$EventLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/EventLayoutComputer.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/EventLayoutComputer.class
new file mode 100755
index 0000000..7999c77
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/EventLayoutComputer.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlice$TimeSliceAcrossTimeLayout.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlice$TimeSliceAcrossTimeLayout.class
new file mode 100755
index 0000000..c5111ec
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlice$TimeSliceAcrossTimeLayout.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlice.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlice.class
new file mode 100755
index 0000000..8b5d4cf
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlice.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$1.class
new file mode 100755
index 0000000..f3f7d14
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$2.class
new file mode 100755
index 0000000..c836b68
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$3.class
new file mode 100755
index 0000000..97056e6
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$4.class
new file mode 100755
index 0000000..be044fe
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$5.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$5.class
new file mode 100755
index 0000000..7f0b0fa
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$5.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$6.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$6.class
new file mode 100755
index 0000000..46890c7
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot$6.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot.class
new file mode 100755
index 0000000..0a81a97
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/TimeSlot.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/clock.png b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/clock.png
new file mode 100755
index 0000000..d43f6ca
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/clock.png differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/clock.svg b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/clock.svg
new file mode 100755
index 0000000..2ca33c5
--- /dev/null
+++ b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/day/internal/clock.svg
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.43"
+   sodipodi:docbase="C:\Documents and Settings\dorme"
+   sodipodi:docname="clock.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Send"
+       style="overflow:visible;">
+      <path
+         id="path2364"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+         transform="scale(0.2) rotate(180)" />
+    </marker>
+    <linearGradient
+       id="linearGradient2452">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop2454" />
+      <stop
+         style="stop-color:#7373ee;stop-opacity:1;"
+         offset="1"
+         id="stop2456" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Mend"
+       style="overflow:visible;">
+      <path
+         id="path2370"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+         transform="scale(0.4) rotate(180)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lend"
+       style="overflow:visible;">
+      <path
+         id="path2376"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+         transform="scale(0.8) rotate(180)" />
+    </marker>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2458"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2485"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2519"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2521"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2555"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2557"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2593"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2614"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2648"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2452"
+       id="linearGradient2666"
+       gradientUnits="userSpaceOnUse"
+       x1="131.28571"
+       y1="372.36218"
+       x2="560.85712"
+       y2="667.36218" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="409.08296"
+     inkscape:cy="647.0534"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="1383"
+     inkscape:window-height="1276"
+     inkscape:window-x="50"
+     inkscape:window-y="58" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="g2460"
+       transform="translate(3.571429,-4.285714)">
+      <path
+         transform="translate(7.78572,-203.5715)"
+         d="M 612.14285 513.79077 A 257.85715 257.14285 0 1 1  96.428558,513.79077 A 257.85715 257.14285 0 1 1  612.14285 513.79077 z"
+         sodipodi:ry="257.14285"
+         sodipodi:rx="257.85715"
+         sodipodi:cy="513.79077"
+         sodipodi:cx="354.28571"
+         id="path1307"
+         style="fill:url(#linearGradient2666);fill-opacity:1;stroke:#030084;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         id="path2182"
+         d="M 362.07143,70.21925 L 362.07143,148.79068"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         id="path2184"
+         d="M 362.07143,462.36211 L 362.07143,540.93354"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         id="path2192"
+         d="M 597.42859,310.21924 L 518.85716,310.21924"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         id="path2194"
+         d="M 205.28573,310.21924 L 126.7143,310.21924"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path2204"
+         d="M 362.14286,313.79068 L 436.42857,153.0764"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path2386"
+         d="M 362.84711,313.15934 L 362.13282,411.73077"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    </g>
+    <g
+       id="g2657"
+       inkscape:export-filename="C:\Documents and Settings\dorme\clock.png"
+       inkscape:export-xdpi="9.6499996"
+       inkscape:export-ydpi="9.6499996">
+      <path
+         transform="matrix(0.224029,4.215227e-2,0,0.27196,357.7523,565.618)"
+         d="M 612.14285 513.79077 A 257.85715 257.14285 0 1 1  96.428558,513.79077 A 257.85715 257.14285 0 1 1  612.14285 513.79077 z"
+         sodipodi:ry="257.14285"
+         sodipodi:rx="257.85715"
+         sodipodi:cy="513.79077"
+         sodipodi:cx="354.28571"
+         id="path2634"
+         style="fill:url(#linearGradient2648);fill-opacity:1;stroke:#010070;stroke-width:22.98158073;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:type="arc" />
+      <path
+         id="path2636"
+         d="M 437.12272,655.01196 L 437.12272,676.38022"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:3.24150491;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         id="path2638"
+         d="M 437.12272,761.659 L 437.12272,783.02726"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:3.24150491;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         id="path2640"
+         d="M 489.84966,730.20312 L 472.24735,726.89114"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:3.24150491;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         id="path2642"
+         d="M 401.9981,713.6734 L 384.39578,710.36144"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#030084;stroke-width:3.24150491;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path2644"
+         d="M 437.13872,721.25657 L 468.10597,686.27961"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path2646"
+         d="M 437.29649,721.11456 L 437.13647,754.72911"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/DuckType$Wrapper.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/DuckType$Wrapper.class
new file mode 100755
index 0000000..5fd779f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/DuckType$Wrapper.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/DuckType.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/DuckType.class
new file mode 100755
index 0000000..535e05b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/DuckType.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ISelectableRegionControl.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ISelectableRegionControl.class
new file mode 100755
index 0000000..d0518ff
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ISelectableRegionControl.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ReflectedMethod.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ReflectedMethod.class
new file mode 100755
index 0000000..7f702ca
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ReflectedMethod.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ReflectedProperty.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ReflectedProperty.class
new file mode 100755
index 0000000..280ac10
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/ReflectedProperty.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/RelaxedDuckType.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/RelaxedDuckType.class
new file mode 100755
index 0000000..968027a
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/internal/RelaxedDuckType.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$1.class
new file mode 100755
index 0000000..b3f4b4f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$2.class
new file mode 100755
index 0000000..eebbf55
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$3.class
new file mode 100755
index 0000000..be53aa9
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar.class
new file mode 100755
index 0000000..ec32b9f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendar.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendarSelectedDay.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendarSelectedDay.class
new file mode 100755
index 0000000..92fe904
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/MonthCalendarSelectedDay.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$1.class
new file mode 100755
index 0000000..c772998
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$2.class
new file mode 100755
index 0000000..545a44b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$3.class
new file mode 100755
index 0000000..16db9cc
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$4.class
new file mode 100755
index 0000000..3a4743f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day.class
new file mode 100755
index 0000000..33aa655
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Day.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$1.class
new file mode 100755
index 0000000..8e7fe9b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$2.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$2.class
new file mode 100755
index 0000000..3e988d2
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$2.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$3.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$3.class
new file mode 100755
index 0000000..95371c8
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$3.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$4.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$4.class
new file mode 100755
index 0000000..d62613f
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl$4.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl.class
new file mode 100755
index 0000000..c8fd27b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/MonthCalendarableItemControl.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Week.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Week.class
new file mode 100755
index 0000000..85da55b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/Week.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/WeekHeader.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/WeekHeader.class
new file mode 100755
index 0000000..89cbb91
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/month/internal/WeekHeader.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/AbstractEventEditor.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/AbstractEventEditor.class
new file mode 100755
index 0000000..b921f4b
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/AbstractEventEditor.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableItem$1.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableItem$1.class
new file mode 100755
index 0000000..8e8c9f2
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableItem$1.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableItem.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableItem.class
new file mode 100755
index 0000000..8d34ae3
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableItem.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableModel.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableModel.class
new file mode 100755
index 0000000..2231bc4
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/CalendarableModel.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/EventContentProvider.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/EventContentProvider.class
new file mode 100755
index 0000000..25c5ec4
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/EventContentProvider.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/EventCountProvider.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/EventCountProvider.class
new file mode 100755
index 0000000..9b70044
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/EventCountProvider.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/IEventEditor.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/IEventEditor.class
new file mode 100755
index 0000000..e9b652e
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/IEventEditor.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/ModelObject.class b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/ModelObject.class
new file mode 100755
index 0000000..e9f9f9a
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/org/eclipse/swt/nebula/widgets/compositetable/timeeditor/ModelObject.class differ
diff --git a/contrib/applications/nxplot/org.eclipse.nebula.compositetable/src.zip b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/src.zip
new file mode 100755
index 0000000..0cbb560
Binary files /dev/null and b/contrib/applications/nxplot/org.eclipse.nebula.compositetable/src.zip differ
diff --git a/contrib/applications/nxplot/sgtgraphics/.classpath b/contrib/applications/nxplot/sgtgraphics/.classpath
new file mode 100755
index 0000000..1fa3e68
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/sgtgraphics/.project b/contrib/applications/nxplot/sgtgraphics/.project
new file mode 100755
index 0000000..ae3e7a3
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>sgtgraphics</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/sgtgraphics/META-INF/MANIFEST.MF b/contrib/applications/nxplot/sgtgraphics/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..e1899be
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Sgtgraphics Plug-in
+Bundle-SymbolicName: sgtgraphics
+Bundle-Version: 3.1.0
+Bundle-Localization: plugin
+Export-Package: gov.noaa.pmel.sgt,
+ gov.noaa.pmel.sgt.dm,
+ gov.noaa.pmel.sgt.swing,
+ gov.noaa.pmel.util
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/META-INF/MANIFEST.MF b/contrib/applications/nxplot/sgtgraphics/bin/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..9bdb983
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/META-INF/MANIFEST.MF
@@ -0,0 +1,62 @@
+Manifest-Version: 1.0
+Main-Class: gov.noaa.pmel.sgt.beans.PanelModelEditor
+
+Name: gov/noaa/pmel/sgt/beans/Page.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/sgt/beans/PageBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/sgt/beans/DataModel.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/sgt/beans/DataModelBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/sgt/beans/PanelModel.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/sgt/beans/PanelModelBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/sgt/beans/PanelModelCustomizer.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JSlider2.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JDateTimeGetter.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JSlider2DateBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JSlider2BeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JSlider2Date.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JStretchPanel.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JSlider2Double.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/beans/DateTimeEditor.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/beans/GeoDateEditor.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/beans/SliderHandle.class
+Java-Bean: False
+
+Name: gov/noaa/pmel/swing/JSlider2DoubleBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JStretchPanelBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JDateTimeGetterBeanInfo.class
+Design-Time-Only: True
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/eps/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/eps/package.html
new file mode 100755
index 0000000..874d085
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/eps/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Provides EPIC netCDF file support.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/io/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/io/package.html
new file mode 100755
index 0000000..2b665a2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/io/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Provides for input and output through data streams, serialization and the file system.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/PaneIcon16.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/PaneIcon16.gif
new file mode 100755
index 0000000..5ebb6e2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/PaneIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/PaneIcon32.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/PaneIcon32.gif
new file mode 100755
index 0000000..33b6e99
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/PaneIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/README.txt b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/README.txt
new file mode 100755
index 0000000..f7c64b6
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/README.txt
@@ -0,0 +1,7 @@
+This directory contains the scientific graphics toolkit (sgt).
+The sgt is jdk1.2 compatible.
+
+Thanks to:
+
+Laurent Beigbeder for development of LogAxis and LogTransform. (2003-02-26)
+
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt
new file mode 100755
index 0000000..091b58c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt
@@ -0,0 +1,158 @@
+              Notes for Scientific Graphics Toolkit (sgt)
+                           version 2.0
+                        February 12, 2001
+
+$Id: RELEASE-NOTES-2.0.txt,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+
+The major incompatability is the package name changes.  The root package
+gov.noaa.noaaserver has been changed to gov.noaa.pmel.  This was done
+to reflect the organization of origin rather than the project
+responsible for the toolkits inception.  The
+gov.noaa.noaaserver.sgt.datamodel package was renamed to the shorted
+gov.noaa.pmel.sgt.dm, since all the packages were renamed anyway.
+
+Packages gov.noaa.pmel.sgt.contour, gov.noaa.pmel.sgt.swing, and
+gov.noaa.pmel.sgt.swing.prop added.  These packages were added to
+support contouring, swing, and attribute editing with swing dialogs.
+The swing components replace and extend the awt classes which have
+been deprecated.  The current development plan for sgt includes
+removing the deprecated classes from sgt.
+
+Package gov.noaa.pmel.sgt.demo older awt classes moved to
+gov.noaa.pmel.sgt.demo.awt.  These classes were moved out of demo to
+prelude the dropping of support for awt.
+
+Packages gov.noaa.pmel.sgt.awt and gov.noaa.pmel.sgt.util have been
+deprecated.  These packages contain classes based on awt whose
+functionality has been superceeded by classes in
+gov.noaa.pmel.sgt.swing and gov.noaa.pmel.sgt.swing.prop.
+
+NOTE: 
+
+Package gov.noaa.pmel.sgt  (formerly gov.noaa.noaaserver.sgt)
+
+New Interfaces:
+    AbstractPane
+    ContourLevelAccess
+    IndexedColor
+    LabelDrawer
+    Moveable
+    TransformAccess
+    TransformColor
+
+New Classes:
+    CLIndexedColorMap
+    CLTransformColorMap
+    ContourLineAttribute
+    DefaultContourLineAttribute
+    IndexedColorMap
+    JPane
+    LabelDrawer1
+    LabelDrawer2
+    LayerStack
+    PlotMark
+    PointCollectionKey
+    TransformColorMap
+
+New Exception:
+    DataNotFoundException
+
+Classes moved to gov.noaa.pmel.util:
+    GeoDate
+    Point2D
+    Range
+    Range2D
+    Rectangle2D
+    TimePoint
+    TimeRange
+    IllegalTimeValueException
+
+Package gov.noaa.pmel.sgt.dm  (formerly gov.noaa.noaaserver.sgt.datamodel)
+
+New Classes:
+    PointCollection
+
+
+Package gov.noaa.pmel.sgt.awt  (formerly gov.noaa.noaaserver.sgt.awt)
+    Entire package deprecated support of awt will be removed after
+    version 2.0. See gov.noaa.pmel.sgt.swing for replacement classes.
+
+Package gov.noaa.pmel.sgt.contour
+    Contour and ContourLine support contouring in sgt.  These classes
+    used by GridCartesianRenderer.  The classes were designed so that
+    the ContourLine would be accessible by the user application.
+    Labeling is handled such that labels can be added or removed after
+    the contour line has been generated.
+
+Package gov.noaa.pmel.sgt.demo  (formerly gov.noaa.noaaserver.sgt.demo)
+
+New Classes: (These classes all use swing)
+    JGridDemo
+    JLayoutDemo
+    JPointDemo
+    JProfileDemo
+    JRealTimeDemo
+    JTimeSeriesDemo
+    PseudoRealTimeData
+    TAOMap
+
+Classes moved to gov.noaa.pmel.sgt.demo.awt
+    GridDemo
+    LayoutDemo
+    PointDemo
+    ProfileDemo
+    TimeSeriesDemo
+
+
+Package gov.noaa.pmel.sgt.util  (formerly gov.noaa.noaaserver.sgt.util)
+    Package deprecated.  Support for awt will be removed after version
+    2.0.  See gov.noaa.pmel.sgt.swing.prop for replacement utility
+    classes.
+
+    JClassTree moved to gov.noaa.pmel.sgt.swing and Units moved to
+    gov.noaa.pmel.util 
+
+Utility classes in package gov.noaa.pmel.util
+
+New classes:
+    Domain
+    Point2D.Float
+    SoTDomain
+    SoTPoint
+    SoTRange
+    SoTRange.Double
+    SoTRange.GeoDate
+    SoTValue
+    SoTValue.Double
+    SoTValue.GeoDate
+
+The SoT classes were introduced to make creating Time/Space neutral
+applications easier.  The SoT classes are used by the Transform and
+Axis classes.
+
+JDK 1.1.8 compatability.  
+
+The following classes will not compile using a jdk 1.1.8 compiler.
+
+   JPane   (imports java.awt.print.*, java.awt.Graphics2D)
+   LabelDrawer2  (depends on Java2D)
+   JGraphicLayout (extends JPane)
+   JPlotLayout (extends JPane)
+   JLineProfileLayout (extends JPane, deprecated)
+
+   All the demonstration applications in gov.noaa.pmel.sgt.demo use
+   JPane.
+
+   The following ..swing.prop classes refrence JPane
+   GridAttributeDialog
+   LogoDialog
+   PointAttributeDialog
+   SGLabelDialog
+   SpaceAxisDialog
+   TimeAxisDialog
+
+While these classes won't compile using jdk1.1.8, if compiled with a
+Java 2 compiler they will run under jdk1.1.8 if you don't print.  The
+swing classes haven't been tested under the jdk1.1.8 swing
+implementation. 
+
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt
new file mode 100755
index 0000000..69d6e21
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt
@@ -0,0 +1,68 @@
+	    Scientific Graphics Toolkit (sgt) Version 2.1  
+			    Release Notes
+
+$Id: RELEASE-NOTES-2.1.txt,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+
+Introduction:
+-------------
+
+This document describes the changes in the Scientific Graphics Toolkit
+from version 2.0 to 2.1. 
+
+Bug reports, comments, and suggestions can be sent to
+dwd at pmel.noaa.gov or sgt at epic.noaa.gov.
+
+New Features:
+-------------
+
+Two major new features have been added to SGT since its last
+release. Both features require Java2D, which is available in JDK
+version 1.2 and newer.
+
+Vectors. The datatype SGTVector has been implemented and the
+    VectorAttribute, VectorKey, VectorCartesianRenderer, and
+    VectorAttributeDialog classes have been added to support vector
+    drawing.  The VectorAttribute class enables users to customize
+    vector head attributes (e.g. scale, min and max head size), color,
+    line attributes (width, cap and miter style), and optionally
+    placing a plot mark at the vector origin.  See the javadoc for
+    more information.
+
+    JPlotLayout has been expanded to include support for the
+    SGTVector datatype.
+
+Stroke lines.  Stroke lines, where the width, dash properties, cap and
+    miter styles, are all selectable have been added.  Line and
+    contour plotting now make use of the new stroke lines.
+
+Line key title.  To better support dynamic changes in data a SGLabel
+    can be specified to describe a data object in a LineKey,
+    PointCollectionKey, and VectorKey.  This feature was added so that
+    the key could be automatically updated when the data changed.
+
+GridAttributeDialog, LineAttributeDialog, PointAttributeDialog, and
+    VectorAttributeDialog now allow multiple JPanes to be registered.
+    This enables the dialog to notifiy both the main graphic JPane and
+    a JPane that contains a key that attribute changes have occured.
+
+Bug Fixes and Improvements:
+---------------------------
+
+A bug that required a Graphics object to be available before
+setBatch(false) could be called has been fixed. This feature uses the
+new init() method that is available in Pane and JPane.  The init()
+method is called with the Pane or JPane first becomes visible,
+initializing those features that require a Graphics object reference. 
+
+Several bugs have been fixed in JPlotLayout, relating to LineKey
+placement, and using the new init() method.
+
+Known Issues This Release:
+--------------------------
+
+GridAttributeDialog is still not complete.  It presently only works
+with an IndexedColorMap.
+
+Java2D is required for the new Stroke lines and Vector graphics to
+work.
+
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt
new file mode 100755
index 0000000..c797baf
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt
@@ -0,0 +1,509 @@
+	    Scientific Graphics Toolkit (sgt) Version 3.0
+                      SGT Beans Initial Release
+			    Release Notes
+
+$Id: RELEASE-NOTES-3.0.txt,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+
+Introduction:
+-------------
+
+This document describes the changes in the Scientific Graphics Toolkit
+from version 2.1 to 3.0 and introduces the first release of SGT Beans.
+
+Bug reports, comments, and suggestions can be sent to
+Donald.W.Denbo at noaa.gov, sgt at epic.noaa.gov or preferrably reported 
+using the Mantis system at http://heron.pmel.noaa.gov:8082/mantis. 
+
+New Features:
+-------------
+
+The biggest new feature is the initial delivery of SGT Beans. The
+three main beans Page, PanelModel, and DataModel can be used to
+produce graphics more easily. These beans also enable a user to more
+easily change the layout of existing graphics. [I will be making a
+tutorial available in about 2 months.] 
+
+New classes have been added to support graphical annotation.  And a
+new GeoDateArray class has been added to improve performance.
+
+Bug Fixes:
+----------
+
+To many to list.  The major fixes include using repaint() internally
+to make the drawing more robust. Problems with placing multiple JPanes
+in a single JFrame have been addressed and printing has been updated
+to work after the above bug fixes :-).  
+
+Known Existing Problems:
+------------------------
+
+SGT Beans require jdk 1.4.  This requirement is because I use
+XMLEncoder to serialize SGT Beans.
+
+The JRealTimeDemo demonstrates a problem that occurs when SGT is
+forced to redraw too rapidly.  On Solaris, the JPanel goes blank until
+the repainting is done.
+
+Printing SGT Beans with titled borders cause the graphic to be shifted
+down but not rescaled.  The result is the border overplot on the
+graphic.
+
+The Page SGT Bean doesn't account for the extra space a pixel
+rendering requires, causing the pixels to overlap the axes.
+
+Future Features:
+---------------
+
+Presently SGT Beans don't use a LayoutManager to position Panels on
+the Page.  I will be developing the interface and visual customization
+classes necessary to support SpringLayout. Eventually :-(.
+
+Deprecated Classes:
+------------------
+
+The following classes are now deprecated and will be removed at some
+future sgt release.
+
+gov.noaa.pmel.sgt.Pane -- use gov.noaa.pmel.sgt.JPane
+gov.noaa.pmel.sgt.swing.JLineProfileLayout -- use gov.noaa.pmel.sgt.swing.JPlotLayout
+
+in gov.noaa.pmel.util:
+
+SoTRange.GeoDate -- use SoTRange.Time
+SoTValue.GeoDate -- use SoTValue.Time
+TimePoint -- use SoTPoint
+TimeRange -- use SoTRange
+
+New Packages:
+-------------
+
+gov.noaa.pmel.sgt.beans
+
+New Classes:
+------------
+For details see the JavaDoc.
+
+gov.noaa.pmel.sgt
+	AnnotationCartesianRenderer
+	AttributeChangeEvent
+	DataKey
+	LayerControl
+	NegativeLogException
+
+gov.noaa.pmel.sgt.demo
+	JLogLogDemo
+	BeanDemo
+
+gov.noaa.pmel.sgt.dm
+	Annotation
+	Annote
+	SGT3DVector
+
+gov.noaa.pmel.sgt.swing.prop
+	ColorDialog
+	ColorEntryPanel
+	RulerDialog
+
+gov.noaa.pmel.swing
+	FocusableSwatch
+	MRJUtil
+	Swatch
+	SwatchGroup
+	ThreeDotsButton
+	ThreeDotsIcon
+
+gov.noaa.pmel.util
+	EPICSystem
+	GeoDateArray
+	SimpleFileFilter
+
+New Methods and Constructors:
+-----------------------------
+For details see the JavaDoc.
+
+gov.noaa.pmel.sgt
+	AbstractPane 
+	  new fields
+            DEFAULT_SCALE
+	    TO_FIT
+	    SHRINK_TO_FIT
+	  new methods
+	    Object[] getObjectsAt(int x,int y),
+	    Object[] getObjectsAt(Point pt)
+	    Point getZoomStart()
+	    void setMouseEventsEnabled(boolean en)
+	    boolean isMouseEventsEnabled()
+	    void setPageScaleMode(int mode)
+	    int getPageScaleMode()
+
+	Attribute
+	  new methods
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	Axis	    
+          new methods
+	    void setLineColor(Color color)
+	    Color getLineColor()
+
+	AxisTransform
+	  new constructors
+	    AxisTransform(double p1, double p2, long t1, long t2)
+	  new methods
+	    double getTransP(long t)
+	    long getLongTimeTransU(double p)
+
+	CLIndexedColorMap
+	  new methods
+	    Color getColorByIndex(int indx)
+
+	CartesianGraph
+	  new methods
+	    void setClip(long tmin, long tmax, double min, double max)
+	    double getXUtoD2(double u)
+	    double getYUtoD2(double u)
+	    double getXUtoP(long t)
+	    double getYUtoP(long t)
+	    int getXUtoD(long t)
+	    int getYUtoD(long t)
+	    double getXUtoD2(GeoDate t)
+	    double getYUtoD2(GeoDate t)
+	    double getXUtoD2(long t)
+	    double getYUtoD2(long t)
+	    int getXUtoD(SoTValue val)
+	    int getYUtoD(SoTValue val)
+	    double getXUtoD2(SoTValue val)
+	    double getYUtoD2(SoTValue val)
+	    double getXUtoP(SoTValue val)
+	    double getYUtoP(SoTValue val)
+	    SoTValue getXPtoSoT(double p)
+	    SoTValue getYPtoSoT(double p)
+	    long getXPtoLongTime(double p)
+	    long getYPtoLongTime(double p)
+	    SoTPoint getPtoU(Point2D.Double loc)
+	    SGTData getDataAt(Point pt)
+
+	CartesianRenderer
+	  new methdos
+	    SGTData getDataAt(int x, int y)
+	    SGTData getDataAt(Point pt)
+
+	ColorKey
+	  Fixed vertical orientation.
+	  new constructor
+	    ColorKey(Point2D.Double pt, Dimension2D size, int valign, int halign)
+	  new methods
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+	    void setColumns(int col)
+	    void setLineLengthP(double len)
+
+	ColorMap
+	  new methods
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	Graph
+	  new methods
+	    SGTData getDataAt(Point pt)
+
+	GridAttribute
+	  new methods
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	GridCartesianRenderer
+	  new methdos
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	IndexedColor
+	  new methods
+	    Color getColorByIndex(int index)
+
+	IndexedColorMap
+	  new methods
+	    Color getColorByIndex(int index)
+
+	JPane
+	  new methods
+	    String getVersion()
+	    Point getZoomStart()
+	    Object[] getObjectsAt(int x, int y)
+	    Object[] getObjectsAt(Point pt)
+	    void setMouseEventsEnabled(boolean enable)
+	    boolean isMouseEventsEnabled()
+	    void setPageScaleMode(int mode)
+	    int getPageScaleMode()
+
+	Layer
+	  new methods
+	    double getXPtoD2(double xp)
+	    double getYPtoD2(double yp)
+	    LayerChild findChild(String id)
+	    Iterator childIterator()
+	    LayerChild[] getChildren()
+	    Object[] getObjectsAt(int x, int y, boolean check)
+
+	LayerContainer - unimplemented
+
+	LayerStack - unimplemented
+
+	LineAttribute
+	  new methods
+	    boolean  equals(Object obj)
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	LineCartesianRenderer
+	  new methods
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	LineKey
+	  new methods
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+
+	LinearTransform
+	  new methods
+	    double getTransP(long t)
+	    long  getLongTimeTransU(double p)
+
+	LogAxis - new implementation
+
+	LogTransform - new implementation
+
+	Pane
+	  mew methods
+	    String getVersion()
+	    Point getZoomStart()
+	    Object[] getObjectsAt(int x, int y)
+	    Object[] getObjectsAt(point pt)
+	    void setMouseEventsEnabled(boolean enable)
+	    boolean isMouseEventsEnabled()
+	    void setPageScaleMode(int mode)
+	    int getPageScaleMode()
+
+	PaneProxy
+	  new methods
+	    String getVersion()
+	    Object[] getObjectsAt(int x, int y)
+	    void setMouseEventsEnabled(boolean enable)
+	    boolean isMouseEventsEnabled()
+
+	PointAttribute
+	  new methods
+	    boolean equals(Object obj)
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	PointCartesianRenderer
+	  new methods
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	PointCollectionKey
+	  new methods
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+
+	Ruler
+	  new methods
+	    int getLabelInterval()
+	    void setLabelInterval(int interval)
+	    int getSignificantDigits()
+	    void setSignificantDigist(int sig)
+	    String getLabelFormat()
+	    void setLabelFormat(String format)
+	    Color getLabelColor()
+	    void setLabelColor(Color color)
+	    Color getLineColor()
+	    void setLineColor(Color color)
+
+	SGLabel
+	  new methods
+	    boolean equals(Object obj)
+
+	VectorAttribute
+	  new methods
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	VectorCartesianRenderer
+	  new methods
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	VectorKey
+	  new methods
+	    void setLineLengthP(double len)
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+
+gov.noaa.pmel.sgt.beans
+	all new package
+
+gov.noaa.pmel.sgt.contour
+
+gov.noaa.pmel.sgt.demo
+
+gov.noaa.pmel.sgt.dm
+	SGTGrid
+	  new methods
+	    GeoDateArray getGeoDateArray()
+	    GeoDateArray getGeoDateArrayEdges()
+
+	SGTLine
+	  new methods
+	    GeoDateArray getGeoDateArray()
+
+	SGTPoint
+	  new methods
+	    long getLongTime()
+
+	SGTTuple
+
+	SGTVector
+
+	SimpleGrid
+	  new methods
+	    GeoDateArray getGeoDateArray()
+	    GeoDateArray getGeoDateArrayEdges()
+	    void setTimeEdges(GeoDateArray tarray)
+	    void setTimeArray(GeoDateArray tarray)
+
+	SimpleLine
+	  new constructor
+	    SimpleLine(GeoDateArray tloc, double[] yloc, String title)
+	    SimpleLine(double[] xloc, GeoDateArray tloc, String title)
+	  new methods
+	    GeoDateArray getGeoDateArray()
+	    void setTimeArray(GeodDateArray tarray)
+
+	SimplePoint
+	  new constructor
+	    SimplePoint(SoTPoint loc, String title)
+	  new methods
+	    long getLongTime()
+	    void setTime(GeoDate date)
+	    void setTime(long t)
+
+	SimpleTuple
+	  new methods
+	    void setXArray(GeoDateArray tArray)
+	    void setYArray(GeoDateArray tArray)
+	    GeoDateArray getGeoDateArray()
+
+gov.noaa.pmel.sgt.swing
+	Draggable
+	  new method
+	    void setLocation(Point loc, boolean fireEvent)
+
+	JGraphicLayout
+	  new methods
+	    Attribute findAttribute(String id)
+	    void setAllClip(long tmin, long tmax, double min, double max)
+
+	JPlotLayout
+	  new methods
+	    SoTDomain getGraphDomain()
+
+	UserIcon
+	  new methods
+	    SoTPoint getLocationU()
+	    void setLocationUNoVeto(SoTPoint loc)
+	    void setLocationU(SoTPoint loc)
+
+	ValueIcon
+	  new methods
+	    SoTPoint getLocationU()
+	    void setLocationUNoVeto(SoTPoint loc)
+	    void setLocationU(SoTPoint loc)
+
+	ValueIconFormat
+	  new methods
+	    void setTimeFormat(String tfrmt)
+	    String format(SoTPoint pt)
+
+gov.noaa.pmel.sgt.swing.prop
+
+gov.noaa.pmel.swing
+	SelectTimeDialog
+	  new method
+	    void setRange(long min, long max)
+
+gov.noaa.pmel.util
+	Domain
+	  new constructors
+	    Domain(Range2D xRange, Range2D yrange, boolean xRev, boolean yRev)
+	    Domain(TimeRange tRange, Range2D yRange, boolean xRev, boolean yRev)
+	    Domain(Range2D xRange, TimeRange tRange, boolean xRev, boolean yRev)
+	  new methods
+	    void setYReversed(boolean rev)
+	    boolean isYReversed()
+	    void setXReversed(boolean rev)
+	    boolean isXReversed()
+
+	Point2D
+	  new methods
+	    boolean equals(Object obj)
+	    Point2D copy()
+
+	Rectangle2D
+	  new subclass
+  	    Rectangle2D.Float
+	  new methods
+	    void setWidth(double w)
+	    double getWidth()
+	    void setHeight(double h)
+	    double getHeight()
+	    void setX(double x)
+	    double getX()
+	    void setY(double y)
+	    double getY()
+	    Rectangle2D copy()
+
+	SoTDomain
+	  new constructor
+	    SoTDomain(SoTRange xRange, SoTRange yRange, boolean xRev, boolean yRev)
+	  new methods
+	    SoTPoint getCenter()
+	    void setXReversed(boolean rev)
+	    boolean isXReversed()
+	    void setYReversed(boolean rev)
+	    boolean isYReversed()
+
+	SoTPoint
+	  new constructors
+	    SoTPoint(double x, long y)
+	    SoTPoint(long x, double y)
+	  new methods
+	    void setX(SoTValue x)
+	    void setY(SoTValue y)
+	    void add(SoTPoint point)
+	    SoTPoint copy()
+
+	SoTRange
+	  new subclass
+	    SoTRange.Time
+
+	SoTValue
+	  new sublcass
+	    SoTValue.Time
+	  new methods
+	    void add(SoTValue val)
+	    long getLongTime()
+	    GeoDate getGeoDate()
+
+	TimeRange
+	  new constructor
+	    TimeRange(long start, long end, long delta)
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/DataModelIcon16.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/DataModelIcon16.gif
new file mode 100755
index 0000000..65a026f
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/DataModelIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/DataModelIcon32.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/DataModelIcon32.gif
new file mode 100755
index 0000000..5df5338
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/DataModelIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PageIcon16.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PageIcon16.gif
new file mode 100755
index 0000000..292709e
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PageIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PageIcon32.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PageIcon32.gif
new file mode 100755
index 0000000..31ec4eb
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PageIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif
new file mode 100755
index 0000000..5fe6cc0
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif
new file mode 100755
index 0000000..6dfe217
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignBottom24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignBottom24.gif
new file mode 100755
index 0000000..62e921d
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignBottom24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignCenter24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignCenter24.gif
new file mode 100755
index 0000000..f19d8ed
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignCenter24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignJustifyHorizontal24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignJustifyHorizontal24.gif
new file mode 100755
index 0000000..32a1070
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignJustifyHorizontal24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignJustifyVertical24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignJustifyVertical24.gif
new file mode 100755
index 0000000..f5d4a00
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignJustifyVertical24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif
new file mode 100755
index 0000000..4db364c
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignRight24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignRight24.gif
new file mode 100755
index 0000000..9c82ad4
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignRight24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignTop24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignTop24.gif
new file mode 100755
index 0000000..8fd07a2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/AlignTop24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/DataModelSimple.png b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/DataModelSimple.png
new file mode 100755
index 0000000..dae8b72
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/DataModelSimple.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Edit24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Edit24.gif
new file mode 100755
index 0000000..a5af7d7
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Edit24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/New24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/New24.gif
new file mode 100755
index 0000000..1cc488d
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/New24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewDataGroup24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewDataGroup24.gif
new file mode 100755
index 0000000..db272f7
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewDataGroup24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewLabel24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewLabel24.gif
new file mode 100755
index 0000000..60589ed
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewLabel24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewLegend24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewLegend24.gif
new file mode 100755
index 0000000..57bfaf8
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/NewLegend24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Open24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Open24.gif
new file mode 100755
index 0000000..2086bc2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Open24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/PanelModelSimple.png b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/PanelModelSimple.png
new file mode 100755
index 0000000..b2cc5dd
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/PanelModelSimple.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Preferences24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Preferences24.gif
new file mode 100755
index 0000000..2e727b2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Preferences24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Remove24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Remove24.gif
new file mode 100755
index 0000000..fa40604
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Remove24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/RunTimeSimple.png b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/RunTimeSimple.png
new file mode 100755
index 0000000..d90a4eb
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/RunTimeSimple.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Save24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Save24.gif
new file mode 100755
index 0000000..bfa98a8
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/Save24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/SaveAs24.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/SaveAs24.gif
new file mode 100755
index 0000000..97eb6fa
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/images/SaveAs24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/package.html
new file mode 100755
index 0000000..6b00eda
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/beans/package.html
@@ -0,0 +1,20 @@
+<HTML>
+<BODY>
+Classes and interfaces that make up SGT Beans. The classes
+<code>Page</code>, <code>DataModel</code>, and <code>PanelModel</code>
+are the core bean classes. Classes that extend
+<code>PropertyPanel</code> or <code>DragBox</code> are used with both
+<code>PanelModelCustomizer</code> (called from IDE's) and
+<code>PanelModelEditor</code> (designed to be called from users
+code).
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/contour/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/contour/package.html
new file mode 100755
index 0000000..3be8be1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/contour/package.html
@@ -0,0 +1,14 @@
+<HTML>
+<BODY>
+Contour and polygon fill support.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml
new file mode 100755
index 0000000..e36330c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml
@@ -0,0 +1,695 @@
+<?xml version="1.0" encoding="UTF-8"?> 
+<java version="1.4.1_01" class="java.beans.XMLDecoder"> 
+ <object class="gov.noaa.pmel.sgt.beans.PanelModel"> 
+  <void property="printScaleMode"> 
+   <int>0</int> 
+  </void> 
+  <void property="pageSize"> 
+   <object class="java.awt.Dimension"> 
+    <int>501</int> 
+    <int>400</int> 
+   </object> 
+  </void> 
+  <void property="panelList"> 
+   <void method="put"> 
+    <string>UpperRight</string> 
+    <object class="gov.noaa.pmel.sgt.beans.PanelHolder"> 
+     <void property="border"> 
+      <object class="javax.swing.border.BevelBorder"> 
+       <int>0</int> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>255</int> 
+       </object> 
+      </object> 
+     </void> 
+     <void property="bounds"> 
+      <object class="java.awt.Rectangle"> 
+       <int>300</int> 
+       <int>0</int> 
+       <int>200</int> 
+       <int>293</int> 
+      </object> 
+     </void> 
+     <void property="dataGroups"> 
+      <void method="put"> 
+       <string>Random</string> 
+       <object class="gov.noaa.pmel.sgt.beans.DataGroup"> 
+        <void property="XAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="width"> 
+           <double>2.097222328186035</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.5</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="VAlign"> 
+           <int>0</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>394</int> 
+            <int>278</int> 
+            <int>34</int> 
+            <int>10</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>12</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>411</int> 
+            <int>276</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Random</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double0" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double0"/> 
+          </void> 
+          <void id="SoTValue$Double1" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double1"/> 
+          </void> 
+          <void id="SoTValue$Double2" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double2"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="YAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>3.125</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.5</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>308</int> 
+            <int>128</int> 
+            <int>10</int> 
+            <int>34</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>12</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>316</int> 
+            <int>145</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+          <void property="orientation"> 
+           <int>1</int> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Random</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double3" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double3"/> 
+          </void> 
+          <void id="SoTValue$Double4" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double4"/> 
+          </void> 
+          <void id="SoTValue$Double5" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double5"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="ZRangeU"> 
+         <void id="SoTValue$Double6" property="delta"/> 
+         <void property="delta"> 
+          <object idref="SoTValue$Double6"/> 
+         </void> 
+         <void id="SoTValue$Double7" property="end"/> 
+         <void property="end"> 
+          <object idref="SoTValue$Double7"/> 
+         </void> 
+         <void id="SoTValue$Double8" property="start"/> 
+         <void property="start"> 
+          <object idref="SoTValue$Double8"/> 
+         </void> 
+        </void> 
+        <void property="id"> 
+         <string>Random</string> 
+        </void> 
+        <void id="Margin0" property="margin"> 
+         <void property="right"> 
+          <float>0.18055555</float> 
+         </void> 
+         <void property="top"> 
+          <float>0.44444445</float> 
+         </void> 
+        </void> 
+        <void property="margin"> 
+         <object idref="Margin0"/> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+     <void property="id"> 
+      <string>UpperRight</string> 
+     </void> 
+     <void property="labels"> 
+      <void method="put"> 
+       <string>Label0</string> 
+       <object class="gov.noaa.pmel.sgt.beans.Label"> 
+        <void property="boundsP"> 
+         <object class="gov.noaa.pmel.util.Rectangle2D$Double"> 
+          <void property="height"> 
+           <double>0.25</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.75</double> 
+          </void> 
+          <void property="x"> 
+           <double>1.0138888359069824</double> 
+          </void> 
+          <void property="y"> 
+           <double>3.75</double> 
+          </void> 
+         </object> 
+        </void> 
+        <void property="id"> 
+         <string>Label0</string> 
+        </void> 
+        <void property="text"> 
+         <string>Bean Demo</string> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+    </object> 
+   </void> 
+   <void method="put"> 
+    <string>UpperLeft</string> 
+    <object class="gov.noaa.pmel.sgt.beans.PanelHolder"> 
+     <void property="border"> 
+      <object class="javax.swing.border.BevelBorder"> 
+       <int>0</int> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>255</int> 
+       </object> 
+      </object> 
+     </void> 
+     <void property="bounds"> 
+      <object class="java.awt.Rectangle"> 
+       <int>0</int> 
+       <int>0</int> 
+       <int>300</int> 
+       <int>293</int> 
+      </object> 
+     </void> 
+     <void property="dataGroups"> 
+      <void method="put"> 
+       <string>Grid</string> 
+       <object class="gov.noaa.pmel.sgt.beans.DataGroup"> 
+        <void property="XAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="width"> 
+           <double>2.375</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.5</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="VAlign"> 
+           <int>0</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>102</int> 
+            <int>279</int> 
+            <int>38</int> 
+            <int>11</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>13</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>121</int> 
+            <int>277</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Grid</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double9" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double9"/> 
+          </void> 
+          <void id="SoTValue$Double10" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double10"/> 
+          </void> 
+          <void id="SoTValue$Double11" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double11"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="YAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>3.277777671813965</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.5</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>7</int> 
+            <int>121</int> 
+            <int>11</int> 
+            <int>38</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>13</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>16</int> 
+            <int>140</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+          <void property="orientation"> 
+           <int>1</int> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Grid</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double12" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double12"/> 
+          </void> 
+          <void id="SoTValue$Double13" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double13"/> 
+          </void> 
+          <void id="SoTValue$Double14" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double14"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="ZRangeU"> 
+         <void id="SoTValue$Double15" property="delta"/> 
+         <void property="delta"> 
+          <object idref="SoTValue$Double15"/> 
+         </void> 
+         <void id="SoTValue$Double16" property="end"/> 
+         <void property="end"> 
+          <object idref="SoTValue$Double16"/> 
+         </void> 
+         <void id="SoTValue$Double17" property="start"/> 
+         <void property="start"> 
+          <object idref="SoTValue$Double17"/> 
+         </void> 
+        </void> 
+        <void property="id"> 
+         <string>Grid</string> 
+        </void> 
+        <void id="Margin1" property="margin"> 
+         <void property="right"> 
+          <float>1.2916666</float> 
+         </void> 
+         <void property="top"> 
+          <float>0.29166666</float> 
+         </void> 
+        </void> 
+        <void property="margin"> 
+         <object idref="Margin1"/> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+     <void property="id"> 
+      <string>UpperLeft</string> 
+     </void> 
+     <void property="legends"> 
+      <void method="put"> 
+       <string>ColorKey</string> 
+       <object class="gov.noaa.pmel.sgt.beans.Legend"> 
+        <void property="boundsP"> 
+         <object class="gov.noaa.pmel.util.Rectangle2D$Double"> 
+          <void property="height"> 
+           <double>3.2916667461395264</double> 
+          </void> 
+          <void property="width"> 
+           <double>1.125</double> 
+          </void> 
+          <void property="x"> 
+           <double>2.930555582046509</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.4861111044883728</double> 
+          </void> 
+         </object> 
+        </void> 
+        <void property="id"> 
+         <string>ColorKey</string> 
+        </void> 
+        <void property="scaleSignificantDigits"> 
+         <int>1</int> 
+        </void> 
+        <void property="type"> 
+         <int>1</int> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+    </object> 
+   </void> 
+   <void method="put"> 
+    <string>Bottom</string> 
+    <object class="gov.noaa.pmel.sgt.beans.PanelHolder"> 
+     <void property="border"> 
+      <object class="javax.swing.border.BevelBorder"> 
+       <int>0</int> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>255</int> 
+       </object> 
+      </object> 
+     </void> 
+     <void property="bounds"> 
+      <object class="java.awt.Rectangle"> 
+       <int>0</int> 
+       <int>293</int> 
+       <int>500</int> 
+       <int>107</int> 
+      </object> 
+     </void> 
+     <void property="dataGroups"> 
+      <void method="put"> 
+       <string>TimeSeries</string> 
+       <object class="gov.noaa.pmel.sgt.beans.DataGroup"> 
+        <void property="XAxisHolder"> 
+         <void property="axisType"> 
+          <int>3</int> 
+         </void> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="width"> 
+           <double>6.291666507720947</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.5</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>TimeSeries</string> 
+         </void> 
+         <void property="userRange"> 
+          <object class="gov.noaa.pmel.util.SoTRange$Time"> 
+           <void id="SoTValue$Time0" property="delta"> 
+            <void property="value"> 
+             <long>172800000</long> 
+            </void> 
+           </void> 
+           <void property="delta"> 
+            <object idref="SoTValue$Time0"/> 
+           </void> 
+           <void id="SoTValue$Time1" property="end"> 
+            <void property="value"> 
+             <long>978307200000</long> 
+            </void> 
+           </void> 
+           <void property="end"> 
+            <object idref="SoTValue$Time1"/> 
+           </void> 
+           <void id="SoTValue$Time2" property="start"> 
+            <void property="value"> 
+             <long>946684800000</long> 
+            </void> 
+           </void> 
+           <void property="start"> 
+            <object idref="SoTValue$Time2"/> 
+           </void> 
+          </object> 
+         </void> 
+        </void> 
+        <void property="YAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.875</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.5</double> 
+          </void> 
+         </void> 
+         <void property="labelInterval"> 
+          <int>4</int> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>15</int> 
+            <int>317</int> 
+            <int>10</int> 
+            <int>34</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>12</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>23</int> 
+            <int>334</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+          <void property="orientation"> 
+           <int>1</int> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>TimeSeries</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double18" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double18"/> 
+          </void> 
+          <void id="SoTValue$Double19" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double19"/> 
+          </void> 
+          <void id="SoTValue$Double20" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double20"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="ZRangeU"> 
+         <void id="SoTValue$Double21" property="delta"/> 
+         <void property="delta"> 
+          <object idref="SoTValue$Double21"/> 
+         </void> 
+         <void id="SoTValue$Double22" property="end"/> 
+         <void property="end"> 
+          <object idref="SoTValue$Double22"/> 
+         </void> 
+         <void id="SoTValue$Double23" property="start"/> 
+         <void property="start"> 
+          <object idref="SoTValue$Double23"/> 
+         </void> 
+        </void> 
+        <void property="id"> 
+         <string>TimeSeries</string> 
+        </void> 
+        <void id="Margin2" property="margin"> 
+         <void property="right"> 
+          <float>0.15277778</float> 
+         </void> 
+         <void property="top"> 
+          <float>0.11111111</float> 
+         </void> 
+        </void> 
+        <void property="margin"> 
+         <object idref="Margin2"/> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+     <void property="id"> 
+      <string>Bottom</string> 
+     </void> 
+    </object> 
+   </void> 
+  </void> 
+ </object> 
+</java> 
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TAO.dat b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TAO.dat
new file mode 100755
index 0000000..e7a9736
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TAO.dat
@@ -0,0 +1,59 @@
+0;-95;0N 95W
+2;-95;2N 95W
+4;-95;4N 95W
+5;-95;5N 95W
+8;-95;8N 95W
+-2;-95;2S 95W
+-5;-95;5S 95W
+-8;-95;8S 95W
+10;-95;10N 95W
+12;-95;12N 95W
+0;-110;0N 110W
+2;-110;2N 110W
+5;-110;5N 110W
+8;-110;8N 110W
+-2;-110;2S 110W
+-5;-110;5S 110W
+-8;-110;8S 110W
+0;-125;0N 125W
+2;-125;2N 125W
+5;-125;5N 125W
+8;-125;8N 125W
+-2;-125;2S 125W
+-5;-125;5S 125W
+-8;-125;8S 125W
+0;-140;0N 140W
+2;-140;2N 140W
+5;-140;5N 140W
+7;-140;7N 140W
+9;-140;9N 140W
+-2;-140;2S 140W
+-5;-140;5S 140W
+0;-155;0N 155W
+2;-155;2N 155W
+5;-155;5N 155W
+8;-155;8N 155W
+-2;-155;2S 155W
+-5;-155;5S 155W
+-8;-155;8S 155W
+0;-170;0N 170W
+2;-170;2N 170W
+5;-170;5N 170W
+8;-170;8N 170W
+-2;-170;2S 170W
+-5;-170;5S 170W
+-8;-170;8S 170W
+0;-180;0N 180W
+2;-180;2N 180W
+5;-180;5N 180W
+8;-180;8N 180W
+-2;-180;2S 180W
+-5;-180;5S 180W
+-8;-180;8S 180W
+0;165;0N 165E
+2;165;2N 165E
+5;165;5N 165E
+8;165;8N 165E
+-2;165;2S 165E
+-5;165;5S 165E
+-8;165;8S 165E
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TRITON.dat b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TRITON.dat
new file mode 100755
index 0000000..63e856e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/TRITON.dat
@@ -0,0 +1,13 @@
+0;156;0N 156E
+2;156;2N 156E
+5;156;5N 156E
+8;156;8N 156E
+-2;156;2S 156E
+-5;156;5S 156E
+0;147;0N 147E
+2;147;2N 147E
+5;147;5N 147E
+0;137;0N 137E
+2;137;2N 137E
+5;137;5N 137E
+7;137;7N 137E
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/coarserezcoast.bin b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/coarserezcoast.bin
new file mode 100755
index 0000000..0af3323
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/coarserezcoast.bin differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/finerezcoast.bin b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/finerezcoast.bin
new file mode 100755
index 0000000..c9491a5
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/finerezcoast.bin differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/ncBrowse48.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/ncBrowse48.gif
new file mode 100755
index 0000000..35b8d68
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/ncBrowse48.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/ncBrowse96.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/ncBrowse96.gif
new file mode 100755
index 0000000..a476dcd
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/ncBrowse96.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/package.html
new file mode 100755
index 0000000..eeec276
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/package.html
@@ -0,0 +1,17 @@
+<HTML>
+<BODY>
+<code>JApplets</code> and applications that demonstrate the use of
+</code>sgt</code>.  Some of these examples use the
+<code>gov.noaa.pmel.sgt.swing</code> and
+<code>gov.noaa.pmel.sgt.swing.prop</code> classes.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/query.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/query.gif
new file mode 100755
index 0000000..3f98ed1
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/demo/query.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/dm/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/dm/package.html
new file mode 100755
index 0000000..660d1e4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/dm/package.html
@@ -0,0 +1,14 @@
+<HTML>
+<BODY>
+Classes and interfaces that define the sgt datamodel.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/overview.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/overview.html
new file mode 100755
index 0000000..54fde6d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/overview.html
@@ -0,0 +1,46 @@
+<HTML>
+<BODY>
+<P>The Scientific Graphics Toolkit (<b>SGT</b>) is designed
+to allow a graphics client developer a great deal of flexibility and
+freedom. <CODE>sgt</CODE> is a package that greatly aids a developer
+in creating graphics applets. <CODE>sgt</CODE> is not a general
+purpose graphics package, but provides the tools to enable scientific
+graphics to be easily incorporated into applications or 
+<code>Applets</code>.</P>
+
+<P>SGT has three main components, the {@link gov.noaa.pmel.sgt.JPane JPane}, 
+on which all graphics are drawn. The 
+{@link gov.noaa.pmel.sgt.Layer Layer}, of which several can be
+associated with a single <CODE>JPane</CODE>, that insulates the
+developer from device coordinates.  And the 
+{@link gov.noaa.pmel.sgt.Graph Graph}, of
+which a single instance can be associated with a <CODE>Layer</CODE>,
+that transforms form user coordinates (e.g. cm/sec, time, etc) to the
+layer coordinate system (physical coordinates).
+
+<P>Examples demonstrating the use of SGT are available in the {@link
+gov.noaa.pmel.sgt.demo demo} package.  These examples show how to
+create SGT applications from scratch and how to use the {@link
+gov.noaa.pmel.sgt.swing.JPlotLayout JPlotLayout} utility class.  A <A
+href="http://www.epic.noaa.gov/talks/dwd/noaatech2002/SGT_Tutorial_files/v3_document.htm">tutorial
+</A> on using SGT to develop interactive graphics is now available.
+
+<P>The gov.noaa.pmel.sgt.awt and gov.noaa.pmel.sgt.util packages have
+been deprecated.  The functionality in gov.noaa.pmel.sgt.swing and
+gov.noaa.pmel.sgt.swing.prop completely replaces the deprecated
+classes. 
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+
+ at see gov.noaa.pmel.sgt.JPane
+ at see gov.noaa.pmel.sgt.Layer 
+ at see gov.noaa.pmel.sgt.Graph
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/package.html
new file mode 100755
index 0000000..dbd23de
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/package.html
@@ -0,0 +1,43 @@
+<HTML>
+<BODY>
+Core classes for the Scientific Graphics Toolkit.
+
+<P>The Java Scientific Graphics Toolkit (<CODE>sgt</CODE>) is designed
+to allow a graphics client developer a great deal of flexibility and
+freedom. <CODE>sgt</CODE> is a package that greatly aids a developer
+in creating graphics applets. <CODE>sgt</CODE> is not a general
+purpose graphics package, but provides the tools to enable scientific
+graphics to be easily incorporated into applications or
+<code>Applets</code>.</P>
+
+<P>SGT has three main components, the <CODE>JPane</CODE>, on which all
+graphics are drawn. The <CODE>Layer</CODE>, of which several can be
+associated with a single <CODE>JPane</CODE>, that insulates the
+developer from device coordinates.  And the <CODE>Graph</CODE>, of
+which a single instance can be associated with a <CODE>Layer</CODE>,
+that transforms form user coordinates (e.g. cm/sec, time, etc) to the
+layer coordinate system (physical coordinates).
+
+<P>Examples demonstrating the use of SGT are available in the {@link
+gov.noaa.pmel.sgt.demo demo} package.  These examples show how to
+create SGT applications from scratch and how to use the {@link
+gov.noaa.pmel.sgt.swing.JPlotLayout JPlotLayout} utility class.  A <A
+href="http://www.epic.noaa.gov/talks/dwd/noaatech2002/SGT_Tutorial_files/v3_document.htm">tutorial
+</A> on using SGT to develop interactive graphics is now available.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+
+ at see gov.noaa.pmel.sgt.Pane
+ at see gov.noaa.pmel.sgt.JPane
+ at see gov.noaa.pmel.sgt.Layer 
+ at see gov.noaa.pmel.sgt.Graph
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plot/Notes.txt b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plot/Notes.txt
new file mode 100755
index 0000000..032994c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plot/Notes.txt
@@ -0,0 +1,51 @@
+			   JPlotPane Notes
+
+			      11/30/2000
+
+* Create JPlotPane
+  1) create and initealizes managers. (Print, DnD, Layer, ...)
+  2) other initialization efforts.
+  3) clear pane?
+
+* addData(SGTData, PlotLayerHints) to JPlotPane
+  1) create PlotLayer (data, hints)
+     - create Graph
+     - create Renderer and bind data
+  2) invoke PlotLayerManager
+      as newLayer(PlotLayer) or reLayout() <-  is this needed?
+
+      - if newLayer
+	+ get X-Y types (space/time, units)
+	+ using hints match with existing LayerStack
+	+ if needed create new LayerStack & add to JPlotPane
+	  else find stack to add layer to...
+	+ create new transform if needed or bind to existing transform
+	+ create new axes if needed
+
+      - if modified Layer
+	+ check for X-Y axes owner
+	+ check for transforms
+	+ update Key
+	  (once a PlotLayer is assigned to a LayerStack it
+	   stays there unless explictly moved)
+
+* hints (should hints include values?)
+  1) Keys  (location- on layer, new layer, table, popup; position)
+  2) Transforms (scale/offset, share, new)
+  3) Axes (share, new, location)
+  4) PlotLayer ...
+
+* modes
+  1) Zoom
+  2) Object Select
+  3) Data Select
+  4) Layer DnD (LayerStack is DnD client/server?)
+  5) Default (none? Zoom?)
+
+
+* LayerManager
+  1) LayerManager should have its rules about what can be overlayed!
+     For example, raster grid should not be over a contour grid! 
+  2) LayerManager should be able to re-order the Layers in a
+     LayerStack?
+ 
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plot/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plot/package.html
new file mode 100755
index 0000000..5068b35
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plot/package.html
@@ -0,0 +1,23 @@
+<HTML>
+<BODY>
+Classes for the automatic layout of multiple <code>Layer</code>s.
+
+<P>The classes in this package are designed to work together to create
+an automated system for plot layout.  Eventually, I hope to include
+managers for printing, Drag-and-Drop, and plot layout.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+
+ at see gov.noaa.pmel.sgt.JPane
+ at see gov.noaa.pmel.sgt.Layer 
+ at see gov.noaa.pmel.sgt.Graph
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plotmarkcodes.gif b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plotmarkcodes.gif
new file mode 100755
index 0000000..6b2fbce
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/plotmarkcodes.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/package.html
new file mode 100755
index 0000000..ec2d722
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/package.html
@@ -0,0 +1,14 @@
+<HTML>
+<BODY>
+Components that use the package <code>javax.swing</code>.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/plotmarkcodes.png b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/plotmarkcodes.png
new file mode 100755
index 0000000..16d181a
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/plotmarkcodes.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/prop/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/prop/package.html
new file mode 100755
index 0000000..4147f9e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/prop/package.html
@@ -0,0 +1,22 @@
+<HTML>
+<BODY>
+Property dialogs for <code>sgt</code> components using 
+<code>javax.swing</code>.  Dialogs that edit the properties of
+attributes and other <code>sgt</code> objects do not, in general, work
+on a copy of the object.  Because the references to attributes are
+one-way if a copy were created the editing would not affect most of
+the references. If you want these dialogs to work on copies instead of
+the actual object, the creation of the copy and updating of the
+original, if the changes are applied, will need to be done in the
+users application.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/sgt_logo.png b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/sgt_logo.png
new file mode 100755
index 0000000..0d2f5cd
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/sgt/swing/sgt_logo.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/space/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/space/package.html
new file mode 100755
index 0000000..37f92e2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/space/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Collaborative support classes for JavaSpaces and Jini.
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/swing/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/swing/package.html
new file mode 100755
index 0000000..f34bc46
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/swing/package.html
@@ -0,0 +1,10 @@
+<HTML>
+<BODY>
+Classes and beans developed from the <code>javax.swing</code> package.
+
+<P>This package contains both gui classes that begin with a "J")
+and non-visual support classes. </P>
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/text/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/text/package.html
new file mode 100755
index 0000000..3cc4782
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/text/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Provides classes and interfaces for handling text, dates, numbers, and messages.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/util/package.html b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/util/package.html
new file mode 100755
index 0000000..1b39912
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/bin/gov/noaa/pmel/util/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Contains date and time facilities and miscellaneous utility classes.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/build.properties b/contrib/applications/nxplot/sgtgraphics/build.properties
new file mode 100755
index 0000000..34d2e4d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/contrib/applications/nxplot/sgtgraphics/src/META-INF/MANIFEST.MF b/contrib/applications/nxplot/sgtgraphics/src/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..9bdb983
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/META-INF/MANIFEST.MF
@@ -0,0 +1,62 @@
+Manifest-Version: 1.0
+Main-Class: gov.noaa.pmel.sgt.beans.PanelModelEditor
+
+Name: gov/noaa/pmel/sgt/beans/Page.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/sgt/beans/PageBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/sgt/beans/DataModel.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/sgt/beans/DataModelBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/sgt/beans/PanelModel.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/sgt/beans/PanelModelBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/sgt/beans/PanelModelCustomizer.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JSlider2.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JDateTimeGetter.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JSlider2DateBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JSlider2BeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JSlider2Date.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JStretchPanel.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/JSlider2Double.class
+Java-Bean: True
+
+Name: gov/noaa/pmel/swing/beans/DateTimeEditor.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/beans/GeoDateEditor.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/beans/SliderHandle.class
+Java-Bean: False
+
+Name: gov/noaa/pmel/swing/JSlider2DoubleBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JStretchPanelBeanInfo.class
+Design-Time-Only: True
+
+Name: gov/noaa/pmel/swing/JDateTimeGetterBeanInfo.class
+Design-Time-Only: True
diff --git a/contrib/applications/nxplot/sgtgraphics/src/doc_stylesheet.css b/contrib/applications/nxplot/sgtgraphics/src/doc_stylesheet.css
new file mode 100755
index 0000000..fc49295
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/doc_stylesheet.css
@@ -0,0 +1,30 @@
+/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults  */
+
+/* Page background color */
+body { background-color: #FFFFFF }
+/* code { color: #FF0000 } */
+
+/* Table colors */
+#TableHeadingColor     { background: #CCCCFF } /* Dark mauve */
+#TableSubHeadingColor  { background: #EEEEFF } /* Light mauve */
+#TableRowColor         { background: #FFFFFF } /* White */
+
+/* Font used in left-hand frame lists */
+#FrameTitleFont   { font-size: normal; font-family: normal }
+#FrameHeadingFont { font-size: normal; font-family: normal }
+#FrameItemFont    { font-size: normal; font-family: normal }
+
+/* Example of smaller, sans-serif font in frames */
+/* #FrameItemFont  { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */
+
+/* Navigation bar fonts and colors */
+#NavBarCell1    { background-color:#EEEEFF;}/* Light mauve */
+#NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */
+#NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;}
+#NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
+
+#NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+#NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/eps/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/eps/package.html
new file mode 100755
index 0000000..874d085
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/eps/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Provides EPIC netCDF file support.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/io/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/io/package.html
new file mode 100755
index 0000000..2b665a2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/io/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Provides for input and output through data streams, serialization and the file system.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AbstractPane.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AbstractPane.java
new file mode 100755
index 0000000..8311e4d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AbstractPane.java
@@ -0,0 +1,377 @@
+/*
+ * $Id: AbstractPane.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.beans.PropertyChangeListener;
+
+/**
+ * Defines the basic sgt Pane functionality. <code>Pane</code> and
+ * <code>JPane</code> implement the <code>AbstractPane</code>
+ * interface.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ * @see Pane
+ * @see JPane
+ */
+public interface AbstractPane {
+  /**
+   * Align to top of printer page.
+   */
+  public static final int TOP = 0;
+  /**
+   * Align to middle of printer page.
+   */
+  public static final int MIDDLE = 1;
+  /**
+   * Align to bottom of printer page.
+   */
+  public static final int BOTTOM = 2;
+  /**
+   * Align to left of printer page.
+   */
+  public static final int LEFT = 0;
+  /**
+   * Align to center of printer page.
+   */
+  public static final int CENTER = 1;
+  /**
+   * Align to right of printer page.
+   */
+  public static final int RIGHT = 2;
+  /**
+   * Align to location specified on printer page.
+   */
+  public static final int SPECIFIED_LOCATION = -1;
+  /**
+   * Fit onto printer page.  Magnify or shrink to fit onto printer page.
+   * @since 3.0
+   */
+  public static final int TO_FIT = 0;
+  /**
+   * Default scale for printing.  A value of 1.0 physical units = 72 pts.
+   * @since 3.0
+   */
+  public static final int DEFAULT_SCALE = 1;
+  /**
+   * Shrink to fit onto printer page.  Will not magnify if graphic will already fit.
+   * @since 3.0
+   */
+  public static final int SHRINK_TO_FIT = 2;
+  /**
+   * The <code>AbstractPane</code> and all of the attached Classes
+   * will be drawn. Drawing will occur in an offscreen image and then
+   * copied to the screen. A new offscreen image is created on the
+   * first call to draw() or if the size of the pane has been
+   * changed. The offscreen image will be used as a "double" buffer
+   * when the screen requires redrawing.
+   * <p>
+   * Each <code>Layer</code> that has been added will be drawn in the
+   * order added, except if that order has been change using the
+   * <code>moveLayerUp()</code> or <code>moveLayerDown()</code> methods.
+   *
+   * @see java.awt.Graphics
+   * @see Layer
+   */
+  public void draw();
+  /**
+   * The <code>AbstractPane</code> and all of the attached Classes
+   * will be drawn. Drawing will occur using the supplied
+   * <code>Graphics</code> object.
+   *
+   * @param g User supplied <code>Graphics</code> object
+   *
+   * @see java.awt.Graphics
+   */
+  public void draw(Graphics g);
+  /**
+   * The <code>AbstractPane</code> and all of the attached Classes
+   * will be drawn. Drawing will occur using the supplied
+   * <code>Graphics</code> object. And clipping will be done to the
+   * width and height.
+   *
+   * @param g User supplied <code>Graphics</code> object
+   * @param width clipping width
+   * @param height clipping height
+   *
+   * @see java.awt.Graphics
+   */
+  public void draw(Graphics g, int width, int height);
+  /**
+   * This method is called when the <code>AbstractPane</code> first becomes
+   * visible.  The types of operations that should be implemented here include
+   * those that require a valid <code>Graphics</code> object.
+   */
+   public void init();
+  /**
+   * Test if the current <code>Graphics</code> object is a printer.
+   *
+   * @return true if a printer
+   */
+  public boolean isPrinter();
+  /**
+   * Return an array of objects whose bounds include x,y.
+   *
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(int x, int y);
+  /**
+   * Return an array of objects whose bounds are at point pt.
+   *
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(Point pt);
+  /**
+   * Get the printer page size.
+   *
+   * @return page size
+   */
+  public java.awt.Dimension getPageSize();
+  /**
+   * Get the <code>Pane</code> identifier.
+   *
+   * @return <code>String</code> containing the <code>Pane</code> identifier.
+   */
+  public String getId();
+  /**
+   * Set the <code>Pane</code> identifier
+   */
+  public void setId(String id);
+  /**
+   * Set printing scale mode.  Allowable choices are <code>TO_FIT</code>,
+   * <code>SHRINK_TO_FIT</code> and
+   * <code>DEFAULT_SCALE</code>. Default = DEFAULT_SCALE.
+   * @param mode print page scaling
+   * @since 3.0
+   * @see AbstractPane#DEFAULT_SCALE
+   * @see AbstractPane#TO_FIT
+   * @see AbstractPane#SHRINK_TO_FIT
+   */
+  public void setPageScaleMode(int mode);
+  /**
+   * Set alignment for printing.
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   * @see AbstractPane#TOP
+   * @see AbstractPane#MIDDLE
+   * @see AbstractPane#BOTTOM
+   * @see AbstractPane#LEFT
+   * @see AbstractPane#CENTER
+   * @see AbstractPane#RIGHT
+   * @see AbstractPane#SPECIFIED_LOCATION
+   */
+  public void setPageAlign(int vert, int horz);
+  /**
+   * Set vertical alignment for printing. Allowed choices include <code>TOP</code>,
+   * <code>MIDDLE</code>, and  <code>BOTTOM</code> for vert and
+   * <code>LEFT</code>, <code>CENTER</code>, and <code>RIGHT</code>
+   * for horz.  Either can be <code>SPECIFIED_LOCATION</code>.
+   *
+   * @param vert vertical alignment
+   * @see AbstractPane#TOP
+   * @see AbstractPane#MIDDLE
+   * @see AbstractPane#BOTTOM
+   * @see AbstractPane#SPECIFIED_LOCATION
+   */
+  public void setPageVAlign(int vert);
+  /**
+   * Set horizontal alignment for printing. Allowed choices include <code>TOP</code>,
+   * <code>MIDDLE</code>, and  <code>BOTTOM</code>.
+   *
+   * @param horz horizontal alignment
+   * @see AbstractPane#LEFT
+   * @see AbstractPane#CENTER
+   * @see AbstractPane#RIGHT
+   * @see AbstractPane#SPECIFIED_LOCATION
+   */
+  public void setPageHAlign(int horz);
+  /**
+   * Get printing scale mode.
+   * @return AUTO_SCALE, TO_FIT, or SHRINK_TO_FIT
+   * @since 3.0
+   * @see AbstractPane#DEFAULT_SCALE
+   * @see AbstractPane#TO_FIT
+   * @see AbstractPane#SHRINK_TO_FIT
+   */
+  public int getPageScaleMode();
+  /**
+   * Get vertical alignment for printing. Allowed choices include
+   * <code>LEFT</code>, <code>CENTER</code>, and <code>RIGHT</code>.
+   *
+   * @return vertical alignment
+   * @see AbstractPane#TOP
+   * @see AbstractPane#MIDDLE
+   * @see AbstractPane#BOTTOM
+   * @see AbstractPane#SPECIFIED_LOCATION
+   */
+  public int getPageVAlign();
+  /**
+   * Get horizontal alignment for printing.
+   *
+   * @return horizontal alignment
+   * @see AbstractPane#LEFT
+   * @see AbstractPane#CENTER
+   * @see AbstractPane#RIGHT
+   * @see AbstractPane#SPECIFIED_LOCATION
+   */
+  public int getPageHAlign();
+  /**
+   * Set the printer page origin. Valid for HAlign = <code>SPECIFIED_LOCATION</code> or
+   * VAlign = <code>SPECIFIED_LOCATION</code>.
+   */
+  public void setPageOrigin(java.awt.Point p);
+  /**
+   * Get the printer page origin. Valid for HAlign = <code>SPECIFIED_LOCATION</code> or
+   * VAlign = <code>SPECIFIED_LOCATION</code>.
+   */
+  public java.awt.Point getPageOrigin();
+  /**
+   * Get the first <code>Layer</code> associated with the <code>Pane</code>
+   *
+   * @return the first <code>Layer</code> object
+   */
+  public Layer getFirstLayer();
+  /**
+   * Get the <code>Layer</code> associated with the
+   * <code>Pane</code> indicated by the id.
+   *
+   * @param id identifier.
+   * @exception LayerNotFoundException The <code>Layer</code> indicated by the id was not found.
+   */
+  public Layer getLayer(String id) throws LayerNotFoundException;
+  /**
+   * Get the <code>Layer</code> associated with the
+   * <code>Pane</code> indicated by the data id.
+   *
+   * @param id data identifier
+   * @exception LayerNotFoundException The <code>Layer</code> indicated by the id was not found.
+   *
+   * @see gov.noaa.pmel.sgt.dm.SGTData
+   */
+  public Layer getLayerFromDataId(String id) throws  LayerNotFoundException;
+  /*
+   * methods to get mouse input results
+   */
+  /**
+   * Return the last object selected.  Returns only objects
+   * that are part of <code>Layer</code>s currently connected to the
+   * pane.  <code>AbstractPane</code> tests
+   * each layer after a MOUSE_DOWN event for an object whose bounding box
+   * contains the mouse.  The pane object then passes the event on to the next
+   * level.
+   */
+  public Object getSelectedObject();
+  /**
+   * Primarily used internally by sgt.  This can also be used to mark
+   * an object as selected for use in an event handler.
+   */
+  public void setSelectedObject(Object obj);
+  /**
+   * Return the device coordinates of the zoom action. The coordinates are
+   * in device units and may require transformation to the physical units or
+   * user units.
+   *
+   * @return zoom rectangle
+   */
+  public java.awt.Rectangle getZoomBounds();
+  /**
+   * Return the device coordinates of the start of the zoom action. The <code>Point</code>
+   * is in device coordinates and may require transformation to physical units
+   * or user units.  Zoom start may be useful to indicate which graph to zoom.
+   *
+   * @return zoom start
+   * @since 3.0
+   */
+  public Point getZoomStart();
+  /**
+   * Get the current selected object at a point.  Used internally by
+   * sgt.
+   */
+  public Object getObjectAt(int x, int y);
+  /**
+   * Get the bounding rectangle in pixels (device units).
+   *
+   * @return Rectangle object containing the bounding box for the pane.
+   **/
+  public java.awt.Rectangle getBounds();
+  /**
+   * Get the <code>Component</code> associated with
+   * the pane.
+   */
+  public java.awt.Component getComponent();
+  /*
+   * methods to handle ChangeEvent and PropertyChangeEvent's
+   */
+  /**
+   * Turn on/off batching of updates to the pane.  While
+   * batching is <code>true</code> property change events will
+   * <b>not</b> cause pane to redraw.  When batching is
+   * turned back on if the pane has been modified it
+   * will then redraw.
+   */
+  public void setBatch(boolean batch, String msg);
+  /**
+   * Turn on/off batching of updates to the pane.  While
+   * batching is <code>true</code> property change events will
+   * <b>not</b> cause pane to redraw.  When batching is
+   * turned back on if the pane has been modified it
+   * will then redraw.
+   */
+  public void setBatch(boolean batch);
+  /**
+   * Is batching turned on?
+   */
+  public boolean isBatch();
+  /**
+   * Notify the pane that something has changed and a redraw
+   * is required.  Used internally by sgt.
+   */
+  public void setModified(boolean mod, String mess);
+  /**
+   * Has the plot been modified?
+   */
+  public boolean isModified();
+  /**
+   * Enable/disable the handling of <code>MouseEvent</code>s by
+   * SGT.  Disabling mouse events will turn off object selection,
+   * moveable, selectable, draggable, and zooming.
+   *
+   * @since 3.0
+   */
+  public void setMouseEventsEnabled(boolean enable);
+  /**
+   * Are <code>MouseEvent</code>s enabled for processing by SGT?
+   *
+   * @since 3.0
+   */
+  public boolean isMouseEventsEnabled();
+  /*
+   * Pane PropertyChange methods
+   */
+  /**
+   * Add a PropertyChangeListener to the list. Properties for
+   * <code>Pane</code> and <code>JPane</code> include
+   * "objectSelected" and "zoomRectangle".
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l);
+  /**
+   * Remove the PropertyChangeListener from the list.
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l);
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AnnotationCartesianRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AnnotationCartesianRenderer.java
new file mode 100755
index 0000000..fc8ac7a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AnnotationCartesianRenderer.java
@@ -0,0 +1,467 @@
+/*
+ * $Id: AnnotationCartesianRenderer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import java.awt.*;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+//import java.awt.geom.*;
+
+import java.beans.PropertyChangeEvent;
+import java.util.Iterator;
+
+import gov.noaa.pmel.sgt.dm.Annotation;
+import gov.noaa.pmel.sgt.dm.Annote;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTPoint;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.util.SoTPoint;
+//import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.Point2D;
+
+/**
+ * Renders <code>Annote</code> and <code>Annotation</code> objects. 
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+public class AnnotationCartesianRenderer extends CartesianRenderer {
+  /**
+   * @link aggregation
+   * @undirected
+   * @label annotation
+   * @supplierCardinality 1 
+   */
+  private Annotation data_ = null;
+
+  public AnnotationCartesianRenderer(CartesianGraph cg,
+                                     Annotation annotation,
+                                     Attribute attr) {
+    cg_ = cg;
+    data_ = annotation;
+  }
+
+  public Attribute getAttribute() {
+    return null;
+  }
+
+  public CartesianGraph getCartesianGraph() {
+    return cg_;
+  }
+
+  public SGTData getDataAt(Point pt) {
+    SGTData data = null;
+    Annote note = null;
+    Iterator iter;
+//    System.out.println("point: " + pt);
+    Rectangle bnds;
+
+    if(data_.hasLine()) {
+      iter = data_.getLineIterator();
+      while(iter.hasNext()) {
+        note = (Annote)iter.next();
+        bnds = note.getBounds(cg_);
+//        System.out.println("Line.Bounds: " + bnds);
+        if(note.getBounds(cg_).contains(pt)) {
+          return note;
+        }
+      }
+    }
+    if(data_.hasPoint()) {
+      iter = data_.getPointIterator();
+      while(iter.hasNext()) {
+        note = (Annote)iter.next();
+        bnds = note.getBounds(cg_);
+//        System.out.println("Point.Bounds: " + bnds);
+        if(bnds.contains(pt)) {
+          return note;
+        }
+      }
+    }
+    if(data_.hasText()) {
+      iter = data_.getTextIterator();
+      while(iter.hasNext()) {
+        note = (Annote)iter.next();
+        bnds = note.getBounds(cg_);
+//        System.out.println("Text.Bounds: " + bnds);
+        if(bnds.contains(pt)) {
+          return note;
+        }
+      }
+    }
+    if(data_.hasOval()) {
+      iter = data_.getOvalIterator();
+      while(iter.hasNext()) {
+        note = (Annote)iter.next();
+        bnds = note.getBounds(cg_);
+//        System.out.println("Oval.Bounds: " + bnds);
+        if(bnds.contains(pt)) {
+          return note;
+        }
+      }
+    }
+    if(data_.hasRect()) {
+      iter = data_.getRectIterator();
+      while(iter.hasNext()) {
+        note = (Annote)iter.next();
+        bnds = note.getBounds(cg_);
+//        System.out.println("Rect.Bounds: " + bnds);
+        if(bnds.contains(pt)) {
+          return note;
+        }
+      }
+    }
+    return data;
+  }
+/**
+ * Render Annotation using java.awt.Graphic2D primatives.
+ */
+  public void draw(Graphics g) {
+    if(cg_.clipping_) {
+//      System.out.println("clipping: on");
+      int xmin, xmax, ymin, ymax;
+      int x, y, width, height;
+      if(cg_.xTransform_.isSpace()) {
+        xmin = cg_.getXUtoD(cg_.xClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.xClipRange_.end);
+      } else {
+        xmin = cg_.getXUtoD(cg_.tClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.tClipRange_.end);
+      }
+      if(cg_.yTransform_.isSpace()) {
+        ymin = cg_.getYUtoD(cg_.yClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.yClipRange_.end);
+      } else {
+        ymin = cg_.getYUtoD(cg_.tClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.tClipRange_.end);
+      }
+      if(xmin < xmax) {
+        x = xmin;
+        width = xmax - xmin;
+      } else {
+        x=xmax;
+        width = xmin - xmax;
+      }
+      if(ymin < ymax) {
+        y = ymin;
+        height = ymax - ymin;
+      } else {
+        y = ymax;
+        height = ymin - ymax;
+      }
+      g.setClip(x, y, width, height);
+    }
+    Graphics2D g2 = (Graphics2D)g;
+    Iterator iter;
+    if(data_.hasLine()) {
+      SGTLine line;
+      LineAttribute attr;
+      Annote.Line pLine;
+      iter = data_.getLineIterator();
+      while(iter.hasNext()) {
+        pLine = (Annote.Line)iter.next();
+        line = pLine.getLine();
+        attr = pLine.getAttribute();
+        //
+        renderLine(g2, line, attr);
+      }
+    }
+    if(data_.hasPoint()) {
+      SGTPoint point;
+      PointAttribute attr;
+      Annote.Point pPoint;
+      iter = data_.getPointIterator();
+      while(iter.hasNext()) {
+        pPoint = (Annote.Point)iter.next();
+        point = pPoint.getPoint();
+        attr = pPoint.getAttribute();
+        //
+        renderPoint(g2, point, attr);
+      }
+    }
+    if(data_.hasText()) {
+      SGLabel text;
+      SoTPoint location;
+      Annote.Text pText;
+      iter = data_.getTextIterator();
+      while(iter.hasNext()) {
+        pText = (Annote.Text)iter.next();
+        text = pText.getText();
+        location = pText.getLocation();
+        //
+        renderText(g2, location, text);
+      }
+    }
+    if(data_.hasOval()) {
+      SoTPoint pt1;
+      SoTPoint pt2;
+      LineAttribute attr;
+      Color color;
+      Annote.Oval pOval;
+      iter = data_.getOvalIterator();
+      while(iter.hasNext()) {
+        pOval = (Annote.Oval)iter.next();
+        pt1 = pOval.getUpperLeft();
+        pt2 = pOval.getLowerRight();
+        attr = pOval.getLineAttribute();
+        color = pOval.getFillColor();
+        //
+        renderOval(g2, pt1, pt2, attr, color);
+      }
+    }
+    if(data_.hasRect()) {
+      SoTPoint pt1;
+      SoTPoint pt2;
+      LineAttribute attr;
+      Color color;
+      Annote.Rect pRect;
+      iter = data_.getRectIterator();
+      while(iter.hasNext()) {
+        pRect = (Annote.Rect)iter.next();
+        pt1 = pRect.getUpperLeft();
+        pt2 = pRect.getLowerRight();
+        attr = pRect.getLineAttribute();
+        color = pRect.getFillColor();
+        //
+        renderRect(g2, pt1, pt2, attr, color);
+      }
+    }
+    /**@todo: implement this gov.noaa.pmel.sgt.CartesianRenderer abstract method*/
+    //
+    // reset clip
+    //
+    Rectangle rect = cg_.getLayer().getPane().getBounds();
+    g.setClip(rect);
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    modified("AnnotationCartesianRenderer: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  /**
+   * Render oval using Graphics2D
+   */
+  private void renderOval(Graphics2D g2, SoTPoint pt1, SoTPoint pt2,
+                          LineAttribute attr, Color color) {
+    Stroke stroke = getStrokeFromLineAttribute(attr);
+    //
+    float xPt1 = (float)cg_.getXUtoD2(pt1.getX());
+    float yPt1 = (float)cg_.getYUtoD2(pt1.getY());
+    float xPt2 = (float)cg_.getXUtoD2(pt2.getX());
+    float yPt2 = (float)cg_.getYUtoD2(pt2.getY());
+    float width = xPt2 - xPt1;
+    float height = yPt2 - yPt1;
+//
+    Shape oval = new Ellipse2D.Float(xPt1, yPt1, width, height);
+    Paint savedPaint = g2.getPaint();
+    Stroke savedStroke = g2.getStroke();
+    Color savedColor = g2.getColor();
+    //
+    if(color != null) {
+      g2.setPaint(color);
+      g2.fill(oval);
+    }
+    if(stroke != null) {
+      g2.setStroke(stroke);
+      g2.setColor(attr.getColor());
+      g2.draw(oval);
+    }
+    g2.setPaint(savedPaint);
+    g2.setStroke(savedStroke);
+    g2.setColor(savedColor);
+  }
+  /**
+   * Render rect using Graphics2D
+   */
+  private void renderRect(Graphics2D g2, SoTPoint pt1, SoTPoint pt2,
+                          LineAttribute attr, Color color) {
+    Stroke stroke = getStrokeFromLineAttribute(attr);
+    //
+    float xPt1 = (float)cg_.getXUtoD2(pt1.getX());
+    float yPt1 = (float)cg_.getYUtoD2(pt1.getY());
+    float xPt2 = (float)cg_.getXUtoD2(pt2.getX());
+    float yPt2 = (float)cg_.getYUtoD2(pt2.getY());
+    float width = xPt2 - xPt1;
+    float height = yPt2 - yPt1;
+//
+    Shape rect = new Rectangle2D.Float(xPt1, yPt1, width, height);
+    Paint savedPaint = g2.getPaint();
+    Stroke savedStroke = g2.getStroke();
+    Color savedColor = g2.getColor();
+    //
+    if(color != null) {
+      g2.setPaint(color);
+      g2.fill(rect);
+    }
+    if(stroke != null) {
+      g2.setStroke(stroke);
+      g2.setColor(attr.getColor());
+      g2.draw(rect);
+    }
+    g2.setPaint(savedPaint);
+    g2.setStroke(savedStroke);
+    g2.setColor(savedColor);
+  }
+/**
+ * Render line using Graphics2D
+ */
+  private void renderLine(Graphics2D g2, SGTLine line, LineAttribute attr) {
+    LineCartesianRenderer lcr = new LineCartesianRenderer(cg_, line, attr);
+    lcr.draw(g2);
+  /*
+    Stroke savedStroke = g2.getStroke();
+    Color savedColor = g2.getColor();
+    //
+    Stroke stroke = getStrokeFromLineAttribute(attr);
+    // build line
+    float[] xd;
+    float[] yd;
+    if(line.isXTime()) {
+      long[] xu = line.getGeoDateArray().getTime();
+      xd = new float[xu.length];
+      for(int i=0; i < xu.length; i++) {
+        xd[i] = (float)cg_.getXUtoD2(xu[i]);
+      }
+    } else {
+      double[] xu = line.getXArray();
+      xd = new float[xu.length];
+      for(int i=0; i < xu.length; i++) {
+        xd[i] = (float)cg_.getXUtoD2(xu[i]);
+      }
+    }
+    if(line.isYTime()) {
+      long[] yu = line.getGeoDateArray().getTime();
+      yd = new float[yu.length];
+      for(int i=0; i < yu.length; i++) {
+        yd[i] = (float)cg_.getYUtoD2(yu[i]);
+      }
+    } else {
+      double[] yu = line.getYArray();
+      yd = new float[yu.length];
+      for(int i=0; i < yu.length; i++) {
+        yd[i] = (float)cg_.getYUtoD2(yu[i]);
+      }
+    }
+    GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, xd.length);
+//
+    int start = 0;
+    for(int i=0; i < xd.length; i++) {
+      if(!(Float.isNaN(xd[i]) || Float.isNaN(yd[i]))) {
+        path.moveTo(xd[i], yd[i]);
+        start = i+1;
+        break;
+      }
+    }
+    boolean move = false;
+    for(int i=start; i < xd.length; i++) {
+      if(Float.isNaN(xd[i]) || Float.isNaN(yd[i])) {
+        move = true;
+        continue;
+      }
+      if(move) {
+        path.moveTo(xd[i], yd[i]);
+        move = false;
+      } else {
+        path.lineTo(xd[i], yd[i]);
+      }
+    }
+    if(stroke != null) g2.setStroke(stroke);
+    g2.setColor(attr.getColor());
+    g2.draw(path);
+    g2.setColor(savedColor);
+    g2.setStroke(savedStroke); */
+  }
+/**
+ * Render point using Graphics2D
+ */
+  private void renderPoint(Graphics2D g, SGTPoint point, PointAttribute attr) {
+    PointCartesianRenderer pcr = new PointCartesianRenderer(cg_, point, attr);
+    pcr.draw(g);
+  }
+/**
+ * Render label using Graphics2D
+ */
+  private void renderText(Graphics2D g, SoTPoint loc, SGLabel text) {
+    double xp;
+    double yp;
+    if(loc.getX().isTime()) {
+      xp = cg_.getXUtoP(loc.getX().getLongTime());
+    } else {
+      xp = cg_.getXUtoP(((Number)loc.getX().getObjectValue()).doubleValue());
+    }
+    if(loc.getY().isTime()) {
+      yp = cg_.getYUtoP(loc.getY().getLongTime());
+    } else {
+      yp = cg_.getYUtoP(((Number)loc.getY().getObjectValue()).doubleValue());
+    }
+    text.setLocationP(new Point2D.Double(xp, yp));
+    text.setLayer(cg_.getLayer());
+    try {
+      text.draw(g);
+    } catch (LayerNotFoundException ex) {
+      ex.printStackTrace();
+    }
+  }
+
+
+  private Stroke getStrokeFromLineAttribute(LineAttribute attr) {
+    BasicStroke stroke = null;
+    if(attr == null) return stroke;
+    switch(attr.getStyle()) {
+//      case LineAttribute.MARK:
+//        drawMark(g, xout, yout, lsize, attr);
+//        break;
+//      case LineAttribute.HIGHLIGHT:
+//        stroke_.drawHighlight(g, xout, yout, lsize, attr);
+//        break;
+      case LineAttribute.HEAVY:
+        stroke = new BasicStroke(attr.getWidth());
+        break;
+      case LineAttribute.DASHED:
+        float[] dashes = {4.0f, 4.0f};
+        stroke = new BasicStroke(1.0f,
+                                 BasicStroke.CAP_SQUARE,
+                                 BasicStroke.JOIN_MITER,
+                                 10.0f,
+                                 dashes,
+                                 0.0f);
+        break;
+      case LineAttribute.STROKE:
+        float[] arr = attr.getDashArray();
+        if(arr == null || (arr.length <= 1)) {
+          stroke = new BasicStroke(attr.getWidth(),
+                                   attr.getCapStyle(),
+                                   attr.getMiterStyle(),
+                                   attr.getMiterLimit());
+        } else {
+          stroke = new BasicStroke(attr.getWidth(),
+                                   attr.getCapStyle(),
+                                   attr.getMiterStyle(),
+                                   attr.getMiterLimit(),
+                                   attr.getDashArray(),
+                                   attr.getDashPhase());
+        }
+        break;
+//      case LineAttribute.MARK_LINE:
+//        drawMark(g, xout, yout, lsize, attr);
+      default:
+//      case LineAttribute.SOLID:
+//        g.drawPolyline(xout, yout, lsize);
+      }
+    return stroke;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Attribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Attribute.java
new file mode 100755
index 0000000..c69d05a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Attribute.java
@@ -0,0 +1,77 @@
+/*
+ * $Id: Attribute.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import java.beans.PropertyChangeListener;
+
+/**
+ * Defines an interface for classes that provide rendering
+ * information for <code>sgt.dm</code> classes.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public interface Attribute extends java.io.Serializable {
+
+  /**
+   * Return a printable representation of the object.
+   *
+   * @return Description
+   */
+  public String toString();
+  /**
+   * Add listener for changes to attribute properties. The properties
+   * that can be listened for depend on the implementing class.
+   *
+   * @since 2.0
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener);
+  /**
+   * Remove change listener.
+   *
+   * @since 2.0
+   */
+  public void removePropertyChangeListener(PropertyChangeListener listener);
+  /**
+   * Set attribute id.
+   *
+   * @since 3.0
+   */
+  public void setId(String id);
+  /**
+   * Get attribute id.
+   *
+   * @since 3.0
+   */
+  public String getId();
+  /**
+   * Batch the changes to the attribute.
+   *
+   * @since 3.0
+   */
+  public void setBatch(boolean batch);
+  /**
+   * Batch the changes to the attribute and set local flag.
+   * Determines whether <code>AttributeChangeEvent</code> will be set local.
+   *
+   * @since 3.0
+   */
+  public void setBatch(boolean batch, boolean local);
+  /**
+   * Is the attribute in batch mode?
+   *
+   * @since 3.0
+   */
+  public boolean isBatch();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AttributeChangeEvent.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AttributeChangeEvent.java
new file mode 100755
index 0000000..ab94a2f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AttributeChangeEvent.java
@@ -0,0 +1,44 @@
+/*
+ * $Id: AttributeChangeEvent.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import java.beans.PropertyChangeEvent;
+
+/**
+ * A class for wrapping local and remote property change events for attributes.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+public class AttributeChangeEvent extends PropertyChangeEvent {
+  private boolean local_ = true;
+
+  public AttributeChangeEvent(Object source,
+                              String propertyName,
+                              Object oldValue,
+                              Object newValue) {
+    this(source, propertyName, oldValue, newValue, true);
+  }
+
+  public AttributeChangeEvent(Object source,
+                              String propertyName,
+                              Object oldValue,
+                              Object newValue,
+                              boolean local) {
+    super(source, propertyName, oldValue, newValue);
+    local_ = local;
+  }
+
+  public boolean isLocal() {
+    return local_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Axis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Axis.java
new file mode 100755
index 0000000..64e75e5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Axis.java
@@ -0,0 +1,734 @@
+/*
+ * $Id: Axis.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Font;
+import java.awt.Color;
+
+/**
+ * Abstract base class for Cartesian axes.  Cartesian axes are
+ * designed to be used with
+ * the <code>CartesianGraph</code> class. Axes and <code>AxisTransform</code>s
+ * can be registed with an <code>Axis</code>.  This allows changes in both
+ * the physical range and user range to be immediatedly updated
+ * for the registered <code>AxisTransform</code>s and axes.
+ * <p>
+ * Cartesian axes can have their user coordinates be double values or time (as
+ * <code>GeoDate</code> objects).  These have been separated into
+ * two child objects.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see SpaceAxis
+ * @see TimeAxis
+**/
+public abstract class Axis implements Selectable {
+  private String ident_;
+  /** @directed
+   * @label graph
+   */
+  protected CartesianGraph graph_;
+  protected Vector registeredAxes_;
+  protected Vector registeredTransforms_;
+  protected Color lineColor_;
+  protected int numSmallTics_;
+  protected double largeTicHeight_;
+  protected double smallTicHeight_;
+  protected double thickTicWidth_;
+  protected int ticPosition_;
+  protected int labelPosition_;
+  protected int labelInterval_;
+  protected Font labelFont_;
+  protected Color labelColor_;
+  protected double labelHeight_;
+  protected int sigDigits_;
+  protected String labelFormat_;
+
+  /**
+   * @link aggregation
+   * @label title
+   */
+  protected SGLabel title_;
+  protected Range2D pRange_;
+  protected boolean space_;
+  protected int orientation_;
+  protected boolean selected_;
+  protected boolean selectable_;
+  protected boolean visible_;
+  /**
+   * Place the label and/or tic on the positive side of the axis.
+   * The right side of <code>VERTICAL</code> axes and the top of
+   * <code>HORIZONTAL</code> axes.
+   */
+  public static final int POSITIVE_SIDE = 0;
+  /**
+   * Place the label and/or tic on the negative side of the axis.
+   * The left side of <code>VERTICAL</code> axes and the bottom of
+   * <code>HORIZONTAL</code> axes.
+   */
+  public static final int NEGATIVE_SIDE = 1;
+  /**
+   * Do not draw a label and/or tic.
+   */
+  public static final int NO_LABEL = 2;
+  /**
+   * Draw the tics on both sides of the axes.
+   */
+  public static final int BOTH_SIDES = 2;
+  /**
+   * Draw a horizontal axis.
+   */
+  public static final int HORIZONTAL = 0;
+  /**
+   * Draw a vertical axis.
+   */
+  public static final int VERTICAL = 1;
+  public static final int AUTO = 3;
+  protected abstract void updateRegisteredTransforms();
+  protected abstract void updateRegisteredAxes();
+  //
+  protected void drawXTic(Graphics g,double xp,double yp,double ticHeight) {
+    int x0, y0, y1;
+    double yp0, yp1;
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      yp0 = yp + ticHeight;
+    } else {
+      yp0 = yp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      yp1 = yp - ticHeight;
+    } else {
+      yp1 = yp;
+    }
+    x0 = graph_.getLayer().getXPtoD(xp);
+    y0 = graph_.getLayer().getYPtoD(yp0);
+    y1 = graph_.getLayer().getYPtoD(yp1);
+    g.drawLine(x0, y0, x0, y1);
+  }
+  //
+  protected void drawThickXTic(Graphics g,double xp,double yp,double ticHeight) {
+    int x0, x1, y0, y1, xc;
+    int ticW, ticH;
+    double yp0, yp1;
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      yp0 = yp + ticHeight;
+    } else {
+      yp0 = yp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      yp1 = yp - ticHeight;
+    } else {
+      yp1 = yp;
+    }
+    xc = graph_.getLayer().getXPtoD(xp);
+    x0 = graph_.getLayer().getXPtoD(xp - thickTicWidth_/2.0);
+    x1 = graph_.getLayer().getXPtoD(xp + thickTicWidth_/2.0);
+    y0 = graph_.getLayer().getYPtoD(yp0);
+    y1 = graph_.getLayer().getYPtoD(yp1);
+    if((x1-x0) < 3) {
+      x0 = xc - 1;
+      x1 = xc + 1;
+    }
+    ticW = x1 - x0;
+    ticH = y1 - y0;
+    g.fillRect(x0, y0, ticW, ticH);
+    /*    g.drawLine(x0-1, y0, x0-1, y1);
+          g.drawLine(x0, y0, x0, y1);
+          g.drawLine(x0+1, y0, x0+1, y1); */
+  }
+  //
+  protected void drawYTic(Graphics g,double xp,double yp,double ticHeight) {
+    int x0, x1, y0;
+    double xp0, xp1;
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      xp0 = xp + ticHeight;
+    } else {
+      xp0 = xp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      xp1 = xp - ticHeight;
+    } else {
+      xp1 = xp;
+    }
+    y0 = graph_.getLayer().getYPtoD(yp);
+    x0 = graph_.getLayer().getXPtoD(xp0);
+    x1 = graph_.getLayer().getXPtoD(xp1);
+    g.drawLine(x0, y0, x1, y0);
+  }
+  //
+  protected void drawThickYTic(Graphics g,double xp,double yp,double ticHeight) {
+    int x0, x1, y0;
+    double xp0, xp1;
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      xp0 = xp + ticHeight;
+    } else {
+      xp0 = xp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      xp1 = xp - ticHeight;
+    } else {
+      xp1 = xp;
+    }
+    y0 = graph_.getLayer().getYPtoD(yp);
+    x0 = graph_.getLayer().getXPtoD(xp0);
+    x1 = graph_.getLayer().getXPtoD(xp1);
+    g.drawLine(x0, y0-1, x1, y0-1);
+    g.drawLine(x0, y0, x1, y0);
+    g.drawLine(x0, y0+1, x1, y0+1);
+  }
+  /**
+   * Default constructor for Axis.
+   */
+  public Axis() {
+    this("");
+  }
+  /**
+   * Constructor for Axis. Sets the axis identifier and initializes
+   *  the defaults. Default values are:
+   *
+   *  <PRE>
+   *    numberSmallTics = 0
+   *    largeTicHeightP = 0.1
+   *    smallTicHeightP = 0.05
+   *     thickTicWidth_ = 0.025
+   *        ticPosition = NEGATIVE_SIDE
+   *      labelPosition = NEGATIVE_SIDE
+   *      labelInterval = 2
+   *          labelFont = Font("Helvetica", Font.ITALIC, 10);
+   *         labelColor = Color.black;
+   *       labelHeightP = 0.15
+   *  significantDigits = 2;
+   *        labelFormat = ""
+   *              title = null
+   *        orientation = HORIZONTAL
+   *         selectable = true
+   *            visible = true
+   *  </PRE>
+   *
+   * @param id axis identifier
+   */
+  public Axis(String id) {
+    ident_ = id;
+    registeredAxes_ = new Vector();
+    registeredTransforms_ = new Vector();
+    //
+    // set defaults
+    //
+    lineColor_ = Color.black;
+    numSmallTics_ = 0;
+    largeTicHeight_ = 0.1;
+    smallTicHeight_ = 0.05;
+    thickTicWidth_ = 0.025;
+    ticPosition_ = NEGATIVE_SIDE;
+    labelPosition_ = NEGATIVE_SIDE;
+    labelInterval_ = 2;
+    labelHeight_ = 0.15;
+    sigDigits_ = 2;
+    labelFormat_ = "";
+    title_ = null;
+    orientation_ = HORIZONTAL;
+    labelFont_ = new Font("Helvetica", Font.ITALIC, 10);
+    labelColor_ = Color.black;
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+  }
+  /**
+   * Create a copy of the axis.
+   *
+   * @return the copy
+   */
+  public abstract Axis copy();
+  //
+  abstract void draw(Graphics g);
+  void setGraph(CartesianGraph g) {
+    graph_ = g;
+  }
+  /**
+   * Get the <code>Graph</code> associated with the axis.
+   *
+   * @return Graph object.
+   */
+  public CartesianGraph getGraph() {
+    return graph_;
+  }
+  /**
+   * Get the parent pane.
+   * @return AbstractPane
+   * @since 2.0
+   */
+  public AbstractPane getPane() {
+    return graph_.getPane();
+  }
+  /**
+   * Used internally by sgt.
+   * @since 2.0
+   */
+  public void modified(String mess) {
+    //    if(Debug.EVENT) System.out.println("Axis: modified()");
+    if(graph_ != null)
+      graph_.modified(mess);
+  }
+  /**
+   * Register an axis.  Registered axes will be notified of changes
+   * to the user coordinate range.
+   *
+   * @param axis An Axis object.
+   */
+  public void register(Axis axis) {
+    registeredAxes_.addElement(axis);
+  }
+  /**
+   * Register an <code>AxisTransform</code>. Registered
+   * <code>AxisTransform</code>s will be
+   * notified of changes to the user coordinate range and physical
+   * coordinate range.
+   *
+   * @param trns A AxisTransform object.
+   */
+  public void register(AxisTransform trns) {
+    registeredTransforms_.addElement(trns);
+  }
+  /**
+   * Unregister an axis.  Axis will no longer be notified of
+   * changes in the user range.
+   *
+   * @param axis An Axis object.
+   */
+  public void clear(Axis axis) {
+    if(!registeredAxes_.isEmpty()) {
+      registeredAxes_.removeElement(axis);
+    }
+  }
+  /**
+   * Unregister an <code>AxisTransform</code>.  The <code>AxisTransform</code>
+   * will no longer be
+   * notified of changes to the user or physical coordinate range.
+   *
+   * @param trns A AxisTransform ojbect.
+   */
+  public void clear(AxisTransform trns) {
+    if(!registeredTransforms_.isEmpty()) {
+      registeredTransforms_.removeElement(trns);
+    }
+  }
+  /**
+   * Unregister all axes.  No axes will be notified of changes in the
+   * user range.
+   */
+  public void clearAllRegisteredAxes() {
+    registeredAxes_.removeAllElements();
+  }
+  /**
+   * Unregister all <code>AxisTransform</code>s.  No
+   * <code>AxisTransform</code>s will be
+   * notified of changes in the user of physical range.
+   */
+  public void clearAllRegisteredTransforms() {
+    registeredTransforms_.removeAllElements();
+  }
+  /**
+   * Get the number of currently registered transforms.
+   *
+   * @return number of registered transforms
+   */
+  public int getNumberRegisteredTransforms() {
+    return registeredTransforms_.size();
+  }
+  /**
+   * Get the number of currently registered axes.
+   *
+   * @return number of registered axes
+   */
+  public int getNumberRegisteredAxes() {
+    return registeredAxes_.size();
+  }
+  /**
+   * Set the large tic height in physical units.
+   *
+   * @param lthgt large tic height.
+   */
+  public void setLargeTicHeightP(double lthgt) {
+    if(largeTicHeight_ != lthgt) {
+      largeTicHeight_ = lthgt;
+      modified("Axis: setLargeTicHeightP()");
+    }
+  }
+  /**
+   * Get the large tic height.
+   *
+   * @return large tic height in physcial units.
+   */
+  public double getLargeTicHeightP() {
+    return largeTicHeight_;
+  }
+  /**
+   * Set the number of small tics between large tics.
+   *
+   * @param nstic number of small tics.
+   */
+  public void setNumberSmallTics(int nstic) {
+    if(numSmallTics_ != nstic) {
+      numSmallTics_ = nstic;
+      modified("Axis: setNumerSmallTics()");
+    }
+  }
+  /**
+   * Get the number of small tics between large tics.
+   *
+   * @return number of small tics.
+   */
+  public int getNumberSmallTics() {
+    return numSmallTics_;
+  }
+  /**
+   * Set the small tic height in physical units.
+   *
+   * @param sthgt small tic height.
+   */
+  public void setSmallTicHeightP(double sthgt) {
+    if(smallTicHeight_ != sthgt) {
+      smallTicHeight_ = sthgt;
+      modified("Axis: setSmallTicHeightP()");
+    }
+  }
+  /**
+   * Get the small tic height.
+   *
+   * @return small tic height in physical units.
+   */
+  public double getSmallTicHeightP() {
+    return smallTicHeight_;
+  }
+  /**
+   * Set the thick tic width in physical units.
+   * Minimum thickness is 3 pixels.
+   *
+   * @param wid thick tic width.
+   */
+  public void setThickTicWidthP(double wid) {
+    if(thickTicWidth_ != wid) {
+      thickTicWidth_ = wid;
+      modified("Axis: setThickTicWidthP()");
+    }
+  }
+  /**
+   * Get the thick tic width.
+   *
+   * @return thick tic width in physical units.
+   */
+  public double getThickTicWidthP() {
+    return thickTicWidth_;
+  }
+  /**
+   * Set the tic position. Tic position can be <code>POSITIVE_SIDE</code>,
+   * <code>NEGATIVE_SIDE</code>, or <code>BOTH_SIDES</code>.
+   *
+   * @param tpos tic position
+   */
+  public void setTicPosition(int tpos) {
+    if(ticPosition_ != tpos) {
+      ticPosition_ = tpos;
+      modified("Axis: setTicPosition()");
+    }
+  }
+  /**
+   * Get the tic position.
+   *
+   * @return tic position
+   */
+  public int getTicPosition() {
+    return ticPosition_;
+  }
+  /**
+   * Set the label position. Label position can be <code>POSITIVE_SIDE</code>,
+   * <code>NEGATIVE_SIDE</code>, and <code>NO_LABEL</code>.
+   *
+   * @param labp label position.
+   */
+  public void setLabelPosition(int labp) {
+    if(labelPosition_ != labp) {
+      labelPosition_ = labp;
+      modified("Axis: setLabelPosition()");
+    }
+  }
+  /**
+   * Get the label position.
+   *
+   * @return label position
+   */
+  public int getLabelPosition() {
+    return labelPosition_;
+  }
+  /**
+   * Set the label font.
+   *
+   * @param fnt label font
+   */
+  public void setLabelFont(Font fnt) {
+    if(labelFont_ == null || !labelFont_.equals(fnt)) {
+      labelFont_ = fnt;
+      modified("Axis: setLabelFont()");
+    }
+  }
+  /**
+   * Get the label font.
+   *
+   * @return label font
+   */
+  public Font getLabelFont() {
+    return labelFont_;
+  }
+  /**
+   * Set the line and tick color.
+   * @param color line and tick color
+   * @since 3.0
+   */
+  public void setLineColor(Color color) {
+    if(lineColor_ == null || !lineColor_.equals(color)) {
+      lineColor_ = color;
+      modified("Axis: setLineColor()");
+    }
+  }
+  /**
+   * Get the line color.
+   * @since 3.0
+   * @return color
+   */
+  public Color getLineColor() {
+    return lineColor_;
+  }
+  /**
+   * Set the label color.
+   * @param color label color
+   * @since 2.0
+   */
+  public void setLabelColor(Color color) {
+    if(labelColor_ == null || !labelColor_.equals(color)) {
+      labelColor_ = color;
+      modified("Axis: setLabelColor()");
+    }
+  }
+  /**
+   * Get the label color.
+   * @since 2.0
+   * @return color
+   */
+  public Color getLabelColor() {
+    return labelColor_;
+  }
+  /**
+   * Set the label height in physical units.
+   *
+   * @param lhgt label height.
+   */
+  public void setLabelHeightP(double lhgt) {
+    if(labelHeight_ != lhgt) {
+      labelHeight_ = lhgt;
+      modified("Axis: setLabelHeightP()");
+    }
+  }
+  /**
+   * Get the label height.
+   *
+   * @return label height
+   */
+  public double getLabelHeightP() {
+    return labelHeight_;
+  }
+  /**
+   * Set the axis title.
+   *
+   * @param title axis title
+   */
+  public void setTitle(SGLabel title) {
+    if(title_ == null || !title_.equals(title)) {
+      title_ = title;
+      title_.setMoveable(false);
+      modified("Axis: setTitle()");
+    }
+  }
+  /**
+   * Get the axis title.
+   *
+   * @return axis title
+   */
+  public SGLabel getTitle() {
+    return title_;
+  }
+  /**
+   * Set the physical range.  This method updates any registered <code>Transform</code>s.
+   * If no <code>Transform</CODE>s are registered, the <code>setRangeP</code> method has no effect.
+   *
+   * @param pr physcial range
+   */
+  public void setRangeP(Range2D pr) {
+    if(pRange_ == null || !pRange_.equals(pr)) {
+      pRange_ = pr;
+      updateRegisteredTransforms();
+      modified("Axis: setRangeP()");
+    }
+  }
+  /**
+   * Get the physical range.  Obtains the physical range from the
+   * associated <code>CartesianGraph</code> object and attached <code>Transform</code>.
+   *
+   * @return physical range
+   */
+  public Range2D getRangeP() {
+    if(orientation_ == HORIZONTAL) {
+      return graph_.xTransform_.getRangeP();
+    } else {
+      return graph_.yTransform_.getRangeP();
+    }
+  }
+  /**
+   * Set the axis identifier.
+   *
+   * @param id identifier
+   **/
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get the axis identifier.
+   *
+   * @return identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set axis orientation.  Allowed orientations are
+   * <code>HORIZONATAL</code> and <code>VERTICAL</code>.
+   *
+   * @param or orientation
+   */
+  public void setOrientation(int or) {
+    if(orientation_ != or) {
+      orientation_ = or;
+      modified("Axis: setOrientation()");
+    }
+  }
+  /**
+   * Get axis orientation
+   *
+   * @return axis orientation
+   */
+  public int getOrientation() {
+    return orientation_;
+  }
+  /**
+   * Tests if axis is space.
+   *
+   * @return true if space
+   */
+  public boolean isSpace() {
+    return space_;
+  }
+  /**
+   * Tests if axis is time.
+   *
+   * @return true if time
+   */
+  public boolean isTime() {
+    return !space_;
+  }
+  /**
+   * Get the bounding box for the axis in device units.
+   *
+   * @return bounding box
+   */
+  public abstract Rectangle getBounds();
+  /**
+   * Get a <code>String</code> representation of the <code>Axis</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  /**
+   * Determines if the axis has been selected.
+   * @return true, if selected
+   * @since 2.0
+   */
+  public boolean isSelected() {
+    return selected_;
+  }
+  /**
+   * Set the selectable state.
+   * @since 2.0
+   */
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  /**
+   * Determines if the axis is selectable.
+   * @since 2.0
+   */
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  /**
+   * Determines if the axis is visible.
+   * @since 2.0
+   */
+  public boolean isVisible() {
+    return visible_;
+  }
+  /**
+   * Set the visibility state.
+   * @since 2.0
+   */
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("Axis: setVisible()");
+    }
+  }
+  /**
+   * Set the axis location.
+   * @since 2.0
+   */
+  public abstract void setLocationU(SoTPoint pt);
+  /**
+   * Get current axis location.
+   * @since 2.0
+   */
+  public abstract SoTPoint getSoTLocationU();
+  /**
+   * Set user range.
+   * @since 2.0
+   */
+  public abstract void setRangeU(SoTRange range);
+  /**
+   * Get user range.
+   * @since 2.0
+   */
+  public abstract SoTRange getSoTRangeU();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AxisNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AxisNotFoundException.java
new file mode 100755
index 0000000..08a3c8e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AxisNotFoundException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: AxisNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Axis was not found during operation.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class AxisNotFoundException extends SGException {
+  public AxisNotFoundException() {
+    super();
+}
+  public AxisNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AxisTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AxisTransform.java
new file mode 100755
index 0000000..feadc17
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/AxisTransform.java
@@ -0,0 +1,382 @@
+/*
+ * $Id: AxisTransform.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+ package  gov.noaa.pmel.sgt;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTRange;
+
+/**
+ * Abstract base class for cartesian axis transforms. Adds additional
+ * functionality to <code>Transform</code> necessary for use with
+ * axes.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public abstract class AxisTransform implements Transform {
+  protected PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  // serialVersion ref 1.9.2.2
+  private static final long serialVersionUID = -1577305732337537031L;
+  protected double p1_;
+  protected double p2_;
+  protected double u1_;
+  protected double u2_;
+  protected long t1_;
+  protected long t2_;
+  protected boolean space_;
+  protected String ident_;
+  /**
+   * Default constructor. Creates a transform with arguments
+   * <code>AxisTransform(0.0, 1.0, 0.0, 1.0)</code>.
+   **/
+  public AxisTransform() {
+    this(0.0, 1.0, 0.0, 1.0);
+  }
+  /**
+   * <code>AxisTransform</code> space constructor.
+   * This constructor is used to define
+   * transforms that use double values.
+   *
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @param u1 minimum value, user coordinates
+   * @param u2 maximum value, user coordinates
+   * @see LinearTransform
+   **/
+  public AxisTransform(double p1,double p2,double u1,double u2) {
+    this.p1_ = p1;
+    this.p2_ = p2;
+    this.u1_ = u1;
+    this.u2_ = u2;
+    space_ = true;
+    computeTransform();
+    ident_ = "space transform";
+  }
+  /**
+   * <code>AxisTransform</code> space constructor.
+   * This constructor is used to define
+   * transforms that use <Range2D> values.
+   *
+   * @param pr physical coordinate range
+   * @param ur user coordinate range
+   * @see Range2D
+   * @see LinearTransform
+   **/
+  public AxisTransform(Range2D pr,Range2D ur) {
+    this(pr.start, pr.end, ur.start, ur.end);
+  }
+  /**
+   * <code>AxisTransform</code> time constructor.
+   * This constructor is used to define
+   * transforms that use <code>GeoDate</code> values.
+   *
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @param t1 minimum time
+   * @param t2 maximum time
+   * @see GeoDate
+   * @see LinearTransform
+   **/
+  public AxisTransform(double p1,double p2,GeoDate t1,GeoDate t2) {
+    p1_ = p1;
+    p2_ = p2;
+    t1_ = t1.getTime();
+    t2_ = t2.getTime();
+    space_ = false;
+    computeTransform();
+    ident_ = "time transform";
+  }
+  /**
+   * <code>AxisTransform</code> time constructor.
+   * This constructor is used to define
+   * transforms that use <code>long</code> values to represent
+   * number of milliseconds since 1970-01-01.
+   *
+   * @since 3.0
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @param t1 minimum time
+   * @param t2 maximum time
+   * @see LinearTransform
+   **/
+  public AxisTransform(double p1, double p2, long t1, long t2) {
+    p1_ = p1;
+    p2_ = p2;
+    t1_ = t1;
+    t2_ = t2;
+    space_ = false;
+    computeTransform();
+    ident_ = "time transform";
+  }
+  /**
+   * <code>AxisTransform</code> time constructor.
+   * This constructor is used to define
+   * transforms that use <TimeRange> values.
+   *
+   * @param pr physical coordinates range
+   * @param tr time range
+   * @see Range2D
+   * @see TimeRange
+   * @see GeoDate
+   * @see LinearTransform
+   **/
+  public AxisTransform(Range2D pr, TimeRange tr) {
+    this(pr.start, pr.end, tr.start, tr.end);
+  }
+  /**
+   * <code>AxisTransform</code> SoT constructor.  This constructor
+   * uses the <code>SoTRange</code> class enabling the construction of
+   * a Time or Space transform.
+   *
+   * @since 2.0
+   */
+  public AxisTransform(Range2D pr, SoTRange str) {
+    if(str.isTime()) {
+      t1_ = str.getStart().getLongTime();
+      t2_ = str.getEnd().getLongTime();
+      space_ = false;
+    } else {
+      u1_ = ((SoTRange.Double)str).start;
+      u2_ = ((SoTRange.Double)str).end;
+      space_ = true;
+    }
+    setRangeP(pr);
+    computeTransform();
+  }
+  /**
+   * Set physical coordinate range.
+   * <BR><B>Property Change:</B> <code>rangeP</code>.
+   *
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @see LinearTransform
+   **/
+  public void setRangeP(double p1,double p2) {
+    if(p1_ != p1 || p2_ != p2) {
+      Range2D tempOld = new Range2D(p1_, p2_);
+      this.p1_ = p1;
+      this.p2_ = p2;
+      computeTransform();
+      changes_.firePropertyChange("rangeP",
+          tempOld,
+          new Range2D(p1_, p2_));
+    }
+  }
+  /**
+   * Set transform identifier.
+   *
+   * @param id transform identifier
+   **/
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get transform identifier.
+   *
+   * @return identifier
+   **/
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set physical coordinate range.
+   *
+   * @param prange physcial coordinate range
+   * @see Range2D
+   * @see LinearTransform
+   **/
+  public void setRangeP(Range2D prange) {
+    setRangeP(prange.start, prange.end);
+  }
+  /**
+   * Get the physical coordinate range.
+   *
+   * @return physcial coordinate range
+   * @see Range2D
+   **/
+  public Range2D getRangeP() {
+    return new Range2D(p1_, p2_);
+  }
+  /**
+   * Set the user coordinate range for space values.
+   * <BR><B>Property Change:</B> <code>rangeU</code>.
+   *
+   * @param u1 minimum value, user coordinates
+   * @param u2 maximum value, user coordinates
+   * @see LinearTransform
+   **/
+  public void setRangeU(double u1,double u2) {
+    if(u1_ != u1 || u2_ != u2) {
+      Range2D tempOld = new Range2D(u1_, u2_);
+      this.u1_ = u1;
+      this.u2_ = u2;
+      space_ = true;
+      computeTransform();
+      changes_.firePropertyChange("rangeU",
+          tempOld,
+          new Range2D(u1_, u2_));
+    }
+  }
+  /**
+   * Set the user coordinate range for <code>Range2D</code> values.
+   *
+   * @param urange user coordinate range
+   * @see Range2D
+   * @see LinearTransform
+   **/
+  public void setRangeU(Range2D urange) {
+    setRangeU(urange.start, urange.end);
+  }
+  /**
+   * Get the user coordinate range for double values.
+   *
+   * @return user range
+   * @see Range2D
+   **/
+  public Range2D getRangeU() {
+    return new Range2D(u1_, u2_);
+  }
+  /**
+   * Set the user coordinate range for <code>GeoDate</code> values.
+   * <BR><B>Property Change:</B> <code>rangeU</code>.
+   *
+   * @param t1 minimum time
+   * @param t2 maximum time
+   * @see GeoDate
+   * @see LinearTransform
+   **/
+  public void setRangeU(GeoDate gt1, GeoDate gt2) {
+    setRangeU(gt1.getTime(), gt2.getTime());
+  }
+  /**
+   *
+   * @since 3.0
+   */
+  public void setRangeU(long t1, long t2) {
+    if(!(t1_ == t1) || !(t2_ == t2)) {
+      SoTRange tempOld = new SoTRange.Time(t1_, t2_);
+      t1_ = t1;
+      t2_ = t2;
+      space_ = false;
+      computeTransform();
+      changes_.firePropertyChange("rangeU",
+          tempOld,
+          new SoTRange.Time(t1_, t2_));
+    }
+  }
+  /**
+   * Set the user coordinate range for <code>TimeRange</code> value.
+   *
+   * @param trange time range
+   * @see TimeRange
+   * @see LinearTransform
+   **/
+  public void setRangeU(TimeRange trange) {
+    setRangeU(trange.start, trange.end);
+  }
+  /**
+   * Get the user coordinate range for <code>GeoDate</code> values.
+   *
+   * @return time range
+   * @see TimeRange
+   **/
+  public TimeRange getTimeRangeU() {
+    return new TimeRange(new GeoDate(t1_), new GeoDate(t2_));
+  }
+  /**
+   * Set the user range with a <code>SoTRange</code> object.
+   * @since 2.0
+   */
+  public void setRangeU(SoTRange str) {
+    if(str.isTime()) {
+      setRangeU(str.getStart().getLongTime(),
+                str.getEnd().getLongTime());
+    } else {
+      setRangeU(((SoTRange.Double)str).start,
+                ((SoTRange.Double)str).end);
+    }
+  }
+  /**
+   * Get the user range as a <code>SoTRange</code> object.
+   * @since 2.0
+   */
+  public SoTRange getSoTRangeU() {
+    if(space_) {
+      return new SoTRange.Double(u1_, u2_);
+    } else {
+      return new SoTRange.Time(t1_, t2_);
+    }
+  }
+  /**
+   * Test if transform has user double values.
+   *
+   * @return true if user coordinates are double values
+   **/
+  public boolean isSpace() {
+    return space_;
+  }
+  /**
+   * Test if transform has user <code>GeoDate</code> values.
+   *
+   * @return true if user coordinates are <code>GeoDate</code> values.
+   * @see GeoDate
+   **/
+  public boolean isTime() {
+    return !space_;
+  }
+  abstract double getTransP(GeoDate t);
+  /**
+   * @since 3.0
+   */
+  abstract double getTransP(long t);
+  abstract GeoDate getTimeTransU(double p);
+  /**
+   * @since 3.0
+   */
+  abstract long getLongTimeTransU(double p);
+  abstract void computeTransform();
+  abstract AxisTransform copy();
+
+  /**
+   * Get physical value as a function of <code>SoTValue</code>.
+   * @since 2.0
+   */
+  public abstract double getTransP(SoTValue value);
+  /**
+   * Get user transform value as a <code>SoTValue</code>
+   * @since 2.0
+   */
+  public abstract SoTValue getSoTTransU(double value);
+  /**
+   * Add listener to changes in <code>LinearTransform</code>
+   * properties.
+   * @since 2.0
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    changes_.addPropertyChangeListener(listener);
+  }
+  /**
+   * Remove listener from list.
+   * @since 2.0
+   */
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CLIndexedColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CLIndexedColorMap.java
new file mode 100755
index 0000000..25d3301
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CLIndexedColorMap.java
@@ -0,0 +1,209 @@
+/*
+ * $Id: CLIndexedColorMap.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * <code>CLIndexedColorMap</code> provides a mapping from a value to a
+ * <code>Color</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public class CLIndexedColorMap extends ColorMap
+  implements Cloneable, PropertyChangeListener,
+             IndexedColor, ContourLevelsAccess {
+  protected Color[] colors_;
+
+  /**
+   * @label cl
+   * @link aggregation 
+   */
+  protected ContourLevels cl_ = null;
+  /**
+   * Initialize the color map with int arrays of red, green, and blue.
+   * The arrays must be the same length. Sets up <code>ColorMap</code>
+   * for <code>INDEXED</code> access.
+   *
+   * @param red Array of the red component 0 - 255.
+   * @param green Array of the green component 0 - 255.
+   * @param blue Array of the blue component 0 - 255.
+   *
+   * @see java.awt.Color
+   */
+  public CLIndexedColorMap(int[] red,int[] green,int[] blue) {
+    int indx;
+    colors_ = new Color[red.length];
+    for (indx=0; indx < red.length; indx++) {
+      colors_[indx] = new Color(red[indx], green[indx], blue[indx]);
+    }
+  }
+  /**
+   * Initialize the color map with float arrays of red, green, and blue.
+   * The arrays must be the same length. Sets up <code>ColorMap</code>
+   * for <code>INDEXED</code> access.
+   *
+   * @param red Array of the red component 0.0 - 1.0.
+   * @param green Array of the green component 0.0 - 1.0.
+   * @param blue Array of the blue component 0.0 - 1.0.
+   *
+   * @see java.awt.Color
+   */
+  public CLIndexedColorMap(float[] red,float[] green,float[] blue) {
+    int indx;
+    colors_ = new Color[red.length];
+    for (indx=0; indx < red.length; indx++) {
+      colors_[indx] = new Color(red[indx], green[indx], blue[indx]);
+    }
+  }
+  /**
+   * Initialize the color map with an array of <code>Color</code>
+   * objects. Sets up <code>ColorMap</code> for
+   * <code>INDEXED</code> access.
+   *
+   * @param colors Array of the Color objects.
+   *
+   * @see java.awt.Color
+   */
+  public CLIndexedColorMap(Color[] colors) {
+    colors_ = colors;
+  }
+  /**
+   * Create a copy of the <code>ColorMap</code>
+   */
+  public ColorMap copy() {
+    ColorMap newMap;
+    try {
+      newMap = (ColorMap)clone();
+    } catch (CloneNotSupportedException e) {
+      newMap = new CLIndexedColorMap(colors_);
+    }
+    return newMap;
+  }
+  /**
+   * Get a <code>Color</code>.
+   *
+   * @since 3.0
+   * @return color
+   */
+  public Color getColorByIndex(int indx) {
+    if(cl_ != null) {
+      try {
+        return getColor(cl_.getLevel(indx));
+      } catch (ContourLevelNotFoundException cfnf) {
+        return colors_[colors_.length-1];
+      }
+    } else {
+      return Color.white;
+    }
+  }
+   /**
+    * Get a <code>Color</code>.
+    *
+    * @param val Value
+    * @return Color
+    */
+   public Color getColor(double val) {
+     double ival = val;
+     int indx;
+     indx = cl_.getIndex(ival);
+     if(indx < 0) indx=0;
+     if(indx > colors_.length-1) indx = colors_.length-1;
+     return colors_[indx];
+   }
+
+  /**
+   * Get the current user range for the <code>Transform</code>.
+   *
+   * @return user range
+   */
+  public Range2D getRange() {
+    return cl_.getRange();
+  }
+  /**
+   * Change the <code>Color</code>.
+   *
+   * @param colr new <code>Color</code>
+   * @param indx index of color
+   */
+  public void setColor(int index, Color colr) {
+    setColor(index, colr.getRed(), colr.getGreen(), colr.getBlue());
+  }
+  /**
+   * Change the <code>Color</code>.
+   * <BR><B>Property Change:</B> <code>color</code>.
+   *
+   * @param red red component
+   * @param green green component
+   * @param blue blue component
+   * @param indx index of color
+   */
+  public void setColor(int indx, int red, int green, int blue) {
+    if(indx < 0 || indx > colors_.length) return;
+    Color newColor = new Color(red, green, blue);
+    if(!colors_[indx].equals(newColor)) {
+      Color tempOld = colors_[indx];
+      colors_[indx] = newColor;
+      firePropertyChange("color",
+                                  tempOld,
+                                  newColor);
+    }
+  }
+  /**
+   * Get the maximum color index.
+   *
+   * @return maximum legal color index
+   */
+  public int getMaximumIndex() {
+    return colors_.length - 1;
+  }
+  /**
+   * Set <code>ContourLevels</code>.
+   * <BR><B>Property Change:</B> <code>color</code>.
+   *
+   * @param cl <code>ContourLevels</code>
+   */
+  public void setContourLevels(ContourLevels cl) {
+    if(cl_ == null || !cl_.equals(cl)) {
+      ContourLevels tempOld = cl_;
+      cl_ = cl;
+      firePropertyChange("contourLevels",
+                                  tempOld,
+                                  cl_);
+    }
+  }
+  /**
+   * Get <code>ContourLevels</code>.
+   *
+   * @return <code>ContourLevels</code>
+   */
+  public ContourLevels getContourLevels() {
+    return cl_;
+  }
+  public boolean equals(ColorMap cm) {
+    if(cm == null || !(cm instanceof CLIndexedColorMap)) return false;
+    if(cl_ == null || !cl_.equals(((CLIndexedColorMap)cm).cl_)) return false;
+    if(colors_.length != ((CLIndexedColorMap)cm).colors_.length) return false;
+    for(int i=0; i < colors_.length; i++) {
+      if(!colors_[i].equals(((CLIndexedColorMap)cm).colors_[i])) return false;
+    }
+    return true;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CLTransformColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CLTransformColorMap.java
new file mode 100755
index 0000000..669e717
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CLTransformColorMap.java
@@ -0,0 +1,234 @@
+/*
+ * $Id: CLTransformColorMap.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * <code>CLTransformColorMap</code> provides a mapping from a value
+ * to a <code>Color</code> via a <code>ContourLevel</code> object.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public class CLTransformColorMap extends ColorMap
+  implements Cloneable, PropertyChangeListener, TransformColor, ContourLevelsAccess {
+  /**
+   * Red Transform
+
+   * @supplierCardinality 0..1
+   * @clientRole rTrans_
+   * @link aggregationByValue
+   */
+  private Transform rTrans_ = null;
+  /**
+   * Green Transform
+
+   * @supplierCardinality 0..1
+   * @clientRole gTrans_
+   * @link aggregationByValue
+   */
+  private Transform gTrans_ = null;
+  /**
+   * Blue Transform
+
+   * @supplierCardinality 0..1
+   * @clientRole bTrans_
+   * @link aggregationByValue
+   */
+  private Transform bTrans_ = null;
+  /**
+   * if not null use LEVEL_INDEXED or LEVEL_TRANSFORM
+   * @shapeType AggregationLink
+   * @label cl
+   */
+  private ContourLevels cl_ = null;
+  /**
+   * Initialize the color map to use red, green, and blue transforms.
+   * Each <code>Transform</code> should have identical user
+   * ranges.  The physical range will be set to 0.0 to 1.0 for each
+   * color component.
+   *
+   * @see Transform
+   */
+  public CLTransformColorMap(Transform rTrans,Transform gTrans,Transform bTrans) {
+    rTrans_ = rTrans;
+    rTrans_.setRangeP(0.0, 1.0);
+    gTrans_ = gTrans;
+    gTrans_.setRangeP(0.0, 1.0);
+    bTrans_ = bTrans;
+    bTrans_.setRangeP(0.0, 1.0);
+  }
+  /**
+   * Create a copy of the <code>ColorMap</code> object.
+   */
+  public ColorMap copy() {
+    ColorMap newMap;
+    try {
+      newMap = (ColorMap)clone();
+    } catch (CloneNotSupportedException e) {
+      newMap = null;
+    }
+    return newMap;
+  }
+  /**
+   * Get a <code>Color</code>.
+   *
+   * @param val Value
+   * @return Color
+   *
+   */
+  public Color getColor(double val) {
+    double ival = val;
+    int indx;
+    ival = (double)cl_.getIndex(ival)/(double)cl_.getMaximumIndex();
+    float red = (float)rTrans_.getTransP(ival);
+    float green = (float)gTrans_.getTransP(ival);
+    float blue = (float)bTrans_.getTransP(ival);
+    return new Color(red, green, blue);
+  }
+  /**
+   * Get the current user range for the <code>Transform</code>s.
+   *
+   * @return user range
+   */
+  public Range2D getRange() {
+    return cl_.getRange();
+  }
+  /**
+   * Set the color <code>Transform</code>s.
+   * <BR><B>Property Change:</B> <code>redColorTransform</code>,
+   * <code>greenColorTransform</code>, and
+   * <code>blueColorTransform</code>.
+   *
+   * @param rTrans red <code>Transform</code>
+   * @param gTrans green <code>Transform</code>
+   * @param bTrans blue <code>Transform</code>
+   */
+  public void setColorTransforms(Transform rTrans,
+                                 Transform gTrans,
+                                 Transform bTrans) {
+    if(!rTrans_.equals(rTrans) ||
+       !gTrans_.equals(gTrans) ||
+       !bTrans_.equals(bTrans)) {
+      if(rTrans_ != null) rTrans_.removePropertyChangeListener(this);
+      if(gTrans_ != null) gTrans_.removePropertyChangeListener(this);
+      if(bTrans_ != null) bTrans_.removePropertyChangeListener(this);
+
+      Transform tempOld = rTrans_;
+      rTrans_ = rTrans;
+      rTrans_.setRangeP(0.0, 1.0);
+      firePropertyChange("redColorTransform",
+                                  tempOld,
+                                  rTrans_);
+      tempOld = gTrans_;
+      gTrans_ = gTrans;
+      gTrans_.setRangeP(0.0, 1.0);
+      firePropertyChange("greenColorTransform",
+                                  tempOld,
+                                  gTrans_);
+      tempOld = bTrans_;
+      bTrans_ = bTrans;
+      bTrans_.setRangeP(0.0, 1.0);
+      firePropertyChange("blueColorTransform",
+                                  tempOld,
+                                  bTrans_);
+
+      rTrans_.addPropertyChangeListener(this);
+      gTrans_.addPropertyChangeListener(this);
+      bTrans_.addPropertyChangeListener(this);
+    }
+  }
+  /**
+   * Set the red transform.
+   */
+  public void setRedTransform(Transform red) {
+    rTrans_ = red;
+  }
+  /**
+   * Get the red color <code>Transform</code>.
+   *
+   * @return red <code>Transform</code>
+   */
+  public Transform getRedTransform() {
+    return rTrans_;
+  }
+  /**
+   * Set the green transform.
+   */
+  public void setGreenTransform(Transform green) {
+    gTrans_ = green;
+  }
+  /**
+   * Get the green color <code>Transform</code>.
+   *
+   * @return green <code>Transform</code>
+   */
+  public Transform getGreenTransform() {
+    return gTrans_;
+  }
+  /**
+   * Set the blue transform.
+   */
+  public void setBlueTransform(Transform blue) {
+    bTrans_ = blue;
+  }
+  /**
+   * Get the blue color <code>Transform</code>.
+   *
+   * @return blue <code>Transform</code>
+   */
+  public Transform getBlueTransform() {
+    return bTrans_;
+  }
+  /**
+   * Set <code>ContourLevels</code>.
+   * <BR><B>Property Change:</B> <code>contourLevels</code>.
+   *
+   * @param cl <code>ContourLevels</code>
+   */
+  public void setContourLevels(ContourLevels cl) {
+    if(!cl_.equals(cl)) {
+      ContourLevels tempOld = cl_;
+      cl_ = cl;
+      firePropertyChange("contourLevels",
+                                  tempOld,
+                                  cl_);
+    }
+  }
+  /**
+   * Get <code>ContourLevels</code> for the color mappings.
+   *
+   * @return <code>ContourLevels</code>
+   */
+  public ContourLevels getContourLevels() {
+    return cl_;
+  }
+  /**
+   * Test for color map equality
+   */
+  public boolean equals(ColorMap cm) {
+    if(cm == null || !(cm instanceof CLTransformColorMap)) return false;
+    if(!cl_.equals(((CLTransformColorMap)cm).cl_)) return false;
+    if(!(rTrans_.equals(((CLTransformColorMap)cm).rTrans_) &&
+         gTrans_.equals(((CLTransformColorMap)cm).gTrans_) &&
+         bTrans_.equals(((CLTransformColorMap)cm).bTrans_))) return false;
+    return true;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CartesianGraph.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CartesianGraph.java
new file mode 100755
index 0000000..c79f7a2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CartesianGraph.java
@@ -0,0 +1,1006 @@
+/*
+ * $Id: CartesianGraph.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTPoint;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Event;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * The <code>CartesianGraph</code> provides the transformation from user to
+ * physical coordinates. A Cartesian graph has
+ * horizontal and vertical transforms, from user to physical
+ * coordinates, that are independent.
+ * For example, yp = f(yu) and xp = g(xu), where
+ * f() and g() are the vertical and horizontal transformations.
+ * Multiple horizontal and vertical, X and Y, axes can be associated with
+ * a <code>CartesianGraph</code> and their mapping of user to physical
+ * coordinates is based on the <code>AxisTransform</code>s used.
+ * The <code>CartesianGraph</code> also provide the support for
+ * the rendering of data. The specific renderer is chosen based on
+ * the type of <code>SGTData</code> and the data <code>Attribute</code> used.
+ * <p>
+ * The following demonstrates how a <code>CartesianGraph</code> may be
+ * used.
+ *
+ * <pre>
+ *   // Create a CartesianGraph and transforms.
+ *
+ *    CartesianGraph graph;
+ *    LinearTransform xt, yt;
+ *    Range2D xPhysRange, xUserRange;
+ *    Range2D yPhysRange, yUserRange;
+ *    Point2D.Double origin;
+ *
+ *    graph = new CartesianGraph("Point Graph");
+ *    layer.setGraph(graph);
+ *    xt = new LinearTransform(xPhysRange, xUserRange);
+ *    yt = new LinearTransform(yPhysRange, yUserRange);
+ *    graph.setXTransform(xt);
+ *    graph.setYTransform(yt);
+ *    origin = new Point2D.Double(xUserRange.start,
+ *                                yUserRange.start);
+ *
+ *     // Create the bottom axis, set its range in user units
+ *     // and its origin. Add the axis to the graph.
+ *
+ *    PlainAxis xbot;
+ *
+ *    xbot = new PlainAxis("Botton Axis");
+ *    xbot.setRangeU(xUserRange);
+ *    xbot.setLocationU(origin);
+ *    graph.addXAxis(xbot);
+ *
+ *     // Create the left axis, set its range in user units
+ *     // and its origin. Add the axis to the graph.
+ *
+ *    PlainAxis yleft;
+ *
+ *    yleft = new PlainAxis("Left Axis");
+ *    yleft.setRangeU(yUserRange);
+ *    yleft.setLocationU(origin);
+ *    graph.addYAxis(yleft);
+ *
+ *     // Create a PointAttribute for the display of the
+ *     // Collection of points. The points will be marked
+ *     // with a red triangle and labelled at the NE corner
+ *     // in blue.
+ *
+ *    PointAttribute pattr;
+ *
+ *    pattr = new PointAttribute(10, Color.red);
+ *
+ *     // Associate the attribute and the point Collection
+ *     // with the graph.
+ *
+ *    graph.setData(col, pattr);
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public class CartesianGraph extends Graph {
+  /**@associates <b>Axis</b>
+   * @supplierCardinality 0..*
+   * @clientRole xAxis_ */
+  protected Vector xAxis_;
+  /** @associates <b>Axis</b>
+   * @clientRole yAxis_
+   * @supplierCardinality 0..* */
+  protected Vector yAxis_;
+  /** @clientRole xTransform_
+   * @link aggregation
+   * @undirected */
+  protected AxisTransform xTransform_;
+  /** @clientRole tTransfrom_
+   * @link aggregation
+   * @undirected */
+  protected AxisTransform yTransform_;
+  protected boolean clipping_ = false;
+  protected Range2D xClipRange_;
+  protected Range2D yClipRange_;
+  protected SoTRange.Time tClipRange_;
+  /**@shapeType AggregationLink
+   * @undirected
+   * @clientCardinality 1
+   * @supplierCardinality 1
+   * @label renderer */
+  private CartesianRenderer renderer_;
+  /**
+   * Default constructor.
+   */
+  public CartesianGraph() {
+    this("");
+  }
+  /**
+   * <code>CartesianGraph</code> constructor.
+   * Creates default unity transforms.
+   *
+   * @param id CartesianGraph identifier
+   */
+  public CartesianGraph(String id) {
+    this(id, new LinearTransform(0.0, 1.0, 0.0, 1.0),
+         new LinearTransform(0.0, 1.0, 0.0, 1.0));
+  }
+  /**
+   * Create a new <code>CartesianGraph</code>. Sets the identifier
+   * and sets the x and y transforms.
+   *
+   * @param id identifier
+   * @param xt x transform
+   * @param yt y transform
+   */
+  public CartesianGraph(String id,AxisTransform xt,AxisTransform yt) {
+    super(id);
+    xAxis_ = new Vector(2,2);
+    yAxis_ = new Vector(2,2);
+    xTransform_ = xt;
+    if(xTransform_ != null) xTransform_.addPropertyChangeListener(this);
+    yTransform_ = yt;
+    if(yTransform_ != null) yTransform_.addPropertyChangeListener(this);
+  }
+  /**
+   * Create a copy of the <code>CartesianGraph</code>
+   */
+  public Graph copy() {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Associates <code>SGTData</code> and <code>Attribute</code> with the
+   * <code>CartesianGraph</code>.
+   * A renderer is constucted based on the two arguements.
+   * <p>
+   * <TABLE BORDER="1" CELLPADDING="2" BGCOLOR="white">
+   *    <TR>
+   *            <TH WIDTH="25%" BGCOLOR="#FFFFCC">
+   *                    <P>SGTData
+   *            </TH>
+   *            <TH WIDTH="25%" BGCOLOR="#FFFFCC">
+   *                    <P>Attribute
+   *            </TH>
+   *            <TH WIDTH="50%" BGCOLOR="#FFFFCC">
+   *                    <P>CartesianRenderer
+   *            </TH>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">SGTPoint</TD>
+   *            <TD WIDTH="25%">PontAttribute</TD>
+   *            <TD WIDTH="50%">PointCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">SGTLine</TD>
+   *            <TD WIDTH="25%">LineAttribute</TD>
+   *            <TD WIDTH="50%">LineCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">SGTGrid</TD>
+   *            <TD WIDTH="25%">GridAttribute</TD>
+   *            <TD WIDTH="50%">GridCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">SGTVector</TD>
+   *            <TD WIDTH="25%">VectorAttribute</TD>
+   *            <TD WIDTH="50%">VectorCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">Collection</TD>
+   *            <TD WIDTH="25%">PointAttribute</TD>
+   *            <TD WIDTH="50%">PointCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">Collection</TD>
+   *            <TD WIDTH="25%">LineAttribute</TD>
+   *            <TD WIDTH="50%">LineCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">Collection</TD>
+   *            <TD WIDTH="25%">VectorAttribute</TD>
+   *            <TD WIDTH="50%">VectorCartesianRenderer</TD>
+   *    </TR>
+   *    <TR>
+   *            <TD WIDTH="25%">Annotation</TD>
+   *            <TD WIDTH="25%">n/a</TD>
+   *            <TD WIDTH="50%">AnnotationCartesianRenderer</TD>
+   *    </TR>
+   *</TABLE>
+   *<p>
+   * @param data data to be rendered
+   * @param attr rendering style information
+   * @see CartesianRenderer#getRenderer
+   */
+  public void setData(SGTData data, Attribute attr) {
+    renderer_ = CartesianRenderer.getRenderer(this, data, attr);
+    data.addPropertyChangeListener(this);
+  }
+  /**
+   * Get the renderer instance being used by the graph.
+   *
+   * @return renderer
+   */
+  public CartesianRenderer getRenderer() {
+    return renderer_;
+  }
+  /**
+   * Set the renderer used by the graph.
+   *
+   * @param rend a renderer object
+   */
+  public void setRenderer(CartesianRenderer rend) {
+    renderer_ = rend;
+  }
+  /**
+   * Draw the graph, axes, and render the data. This method should
+   * not be directly called.
+   *
+   * @see Pane#draw
+   */
+  public void draw(Graphics g) {
+    if(renderer_ != null) renderer_.draw(g);
+    if(!xAxis_.isEmpty()) {
+      for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) {
+        ((Axis)it.nextElement()).draw(g);
+      }
+    }
+    if(!yAxis_.isEmpty()) {
+      for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) {
+        ((Axis)it.nextElement()).draw(g);
+      }
+    }
+  }
+  /**
+   * Set the clipping rectangle in user coordinates.
+   *
+   * @param xmin minimum horizontal coordinate
+   * @param xmax maximum horizontal coordinate
+   * @param ymin minimum vertical coordinate
+   * @param ymax maximum vertical coordinate
+   */
+  public void setClip(double xmin,double xmax,double ymin,double ymax) {
+    if(xTransform_.isSpace() && yTransform_.isSpace()) {
+      clipping_ = true;
+      xClipRange_ = new Range2D(xmin, xmax);
+      yClipRange_ = new Range2D(ymin, ymax);
+    } else {
+      clipping_ = false;
+    }
+  }
+  /**
+   * Set the clipping rectangle in user coordinates.
+   *
+   * @param tmin mimimum time
+   * @param tmax maximum time
+   * @param min miminum user coordinate
+   * @param max maximum user coordinate
+   */
+  public void setClip(GeoDate tmin, GeoDate tmax, double min, double max) {
+    if(xTransform_.isTime() || yTransform_.isTime()) {
+      clipping_ = true;
+      tClipRange_ = new SoTRange.Time(tmin.getTime(), tmax.getTime());
+      if(xTransform_.isTime()) {
+        yClipRange_ = new Range2D(min, max);
+      } else {
+        xClipRange_ = new Range2D(min, max);
+      }
+    } else {
+      clipping_ = false;
+    }
+  }
+  /**
+   * Set the clipping rectangle in user coordinates.
+   *
+   * @since 3.0
+   * @param tmin mimimum time
+   * @param tmax maximum time
+   * @param min miminum user coordinate
+   * @param max maximum user coordinate
+   */
+  public void setClip(long tmin, long tmax, double min, double max) {
+    if(xTransform_.isTime() || yTransform_.isTime()) {
+      clipping_ = true;
+      tClipRange_ = new SoTRange.Time(tmin, tmax);
+      if(xTransform_.isTime()) {
+        yClipRange_ = new Range2D(min, max);
+      } else {
+        xClipRange_ = new Range2D(min, max);
+      }
+    } else {
+      clipping_ = false;
+    }
+  }
+  /**
+   * Set the clipping rectangle in user coordinates.
+   * @since 2.0
+   */
+  public void setClip(SoTRange xr, SoTRange yr) {
+    if(xr.isTime() || yr.isTime()) {
+      SoTRange.Double dub;
+      long tstart;
+      long tend;
+      if(xr.isTime()) {
+        tstart = xr.getStart().getLongTime();
+        tend = xr.getEnd().getLongTime();
+        dub = (SoTRange.Double)yr;
+      } else {
+        tstart = yr.getStart().getLongTime();
+        tend = yr.getEnd().getLongTime();
+        dub = (SoTRange.Double)xr;
+      }
+      setClip(tstart, tend, dub.start, dub.end);
+    } else {
+      SoTRange.Double xrd = (SoTRange.Double)xr;
+      SoTRange.Double yrd = (SoTRange.Double)yr;
+      setClip(xrd.start, xrd.end, yrd.start, yrd.end);
+    }
+  }
+  /**
+   * Set the clipping property.
+   *
+   * @param clip clipping
+   */
+  public void setClipping(boolean clip) {
+    clipping_ = clip;
+  }
+  /**
+   * Test the clipping property.
+   *
+   * @return true if clipping is active
+   */
+  public boolean isClipping() {
+    return clipping_;
+  }
+  /**
+   * Add a X axis (<code>Axis.HORIZONTAL</code>) to the graph.
+   *
+   * @param id axis identifier
+   * @param axis X axis
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void addXAxis(String id,Axis axis) {
+    if(id.length() != 0) axis.setId(id);
+    addXAxis(axis);
+  }
+  /**
+   * Add a X axis (<code>Axis.HORIZONTAL</code>) to the graph.
+   * Uses the existing axis identifier.
+   *
+   * @param axis X axis
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void addXAxis(Axis axis) {
+    axis.setOrientation(Axis.HORIZONTAL);
+    axis.setGraph(this);
+    xAxis_.addElement(axis);
+  }
+  /**
+   * Get a reference to an X axis.
+   *
+   * @param id axis identifier
+   * @return axis found
+   * @exception AxisNotFoundException An axis was not found with the correct identifier.
+   * @see Axis
+   * @see PlainAxis
+   */
+  public Axis getXAxis(String id) throws AxisNotFoundException  {
+    if(!xAxis_.isEmpty()) {
+      Axis ax;
+      for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        if(ax.getId() == id) return ax;
+      }
+      throw new AxisNotFoundException();
+    } else {
+      throw new AxisNotFoundException();
+    }
+  }
+  /**
+   * Remove an X axis from the graph.
+   *
+   * @param id axis identifier
+   * @exception AxisNotFoundException An axis was not found with the correct identifier.
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void removeXAxis(String id) throws AxisNotFoundException  {
+    if(!xAxis_.isEmpty()) {
+      Axis ax;
+      for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        if(ax.getId() == id) xAxis_.removeElement(ax);
+      }
+      throw new AxisNotFoundException();
+    } else {
+      throw new AxisNotFoundException();
+    }
+  }
+  /**
+   * Remove an X axis from the graph.
+   *
+   * @exception AxisNotFoundException An axis was not found with the correct identifier.
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void removeXAxis(Axis axis) throws AxisNotFoundException  {
+    if(!xAxis_.isEmpty()) {
+      Axis ax;
+      for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        if(ax.equals(axis)) xAxis_.removeElement(ax);
+      }
+      throw new AxisNotFoundException();
+    } else {
+      throw new AxisNotFoundException();
+    }
+  }
+  /**
+   * Remove all X axes from the graph.
+   */
+  public void removeAllXAxes() {
+    xAxis_.removeAllElements();
+  }
+  /**
+   * Get the number of X axes associated with the graph.
+   *
+   * @return number of axes
+   * @see Axis
+   * @see PlainAxis
+   */
+  public int getNumberXAxis() {
+    return xAxis_.size();
+  }
+  /**
+   * Get an <code>Enumeration</code> object for the X axes.
+   *
+   * @return enumeration
+   */
+  public Enumeration xAxisElements() {
+    return xAxis_.elements();
+  }
+  /**
+   * Add a Y axis (<code>Axis.VERTICAL</code>) to the graph.
+   *
+   * @param id axis identifier
+   * @param axis Y axis
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void addYAxis(String id,Axis axis) {
+    if(id.length() != 0) axis.setId(id);
+    addYAxis(axis);
+  }
+  /**
+   * Add a Y axis (<code>Axis.VERTICAL</code>) to the graph.
+   * Uses the existing axis identifier.
+   *
+   * @param axis Y axis
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void addYAxis(Axis axis) {
+    axis.setOrientation(Axis.VERTICAL);
+    axis.setGraph(this);
+    yAxis_.addElement(axis);
+  }
+  /**
+   * Get a reference to an Y axis.
+   *
+   * @param id axis identifier
+   * @return axis found
+   * @exception AxisNotFoundException An axis was not found with the correct identifier.
+   * @see Axis
+   * @see PlainAxis
+   */
+  public Axis getYAxis(String id) throws AxisNotFoundException  {
+    if(!yAxis_.isEmpty()) {
+      Axis ax;
+      for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        if(ax.getId() == id) return ax;
+      }
+      throw new AxisNotFoundException();
+    } else {
+      throw new AxisNotFoundException();
+    }
+  }
+  /**
+   * Remove an Y axis from the graph.
+   *
+   * @param id axis identifier
+   * @exception AxisNotFoundException An axis was not found with the correct identifier.
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void removeYAxis(String id) throws AxisNotFoundException  {
+    if(!yAxis_.isEmpty()) {
+      Axis ax;
+      for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        if(ax.getId() == id) yAxis_.removeElement(ax);
+      }
+      throw new AxisNotFoundException();
+    } else {
+      throw new AxisNotFoundException();
+    }
+  }
+  /**
+   * Remove an Y axis from the graph.
+   *
+   * @exception AxisNotFoundException An axis was not found with the correct identifier.
+   * @see Axis
+   * @see PlainAxis
+   */
+  public void removeYAxis(Axis axis) throws AxisNotFoundException  {
+    if(!yAxis_.isEmpty()) {
+      Axis ax;
+      for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        if(ax.equals(axis)) yAxis_.removeElement(ax);
+      }
+      throw new AxisNotFoundException();
+    } else {
+      throw new AxisNotFoundException();
+    }
+  }
+  /**
+   * Remove all Y axes from the graph.
+   */
+  public void removeAllYAxes() {
+    yAxis_.removeAllElements();
+  }
+  /**
+   * Get the number of Y axes associated with the graph.
+   *
+   * @return number of axes
+   * @see Axis
+   * @see PlainAxis
+   */
+  public int getNumberYAxis() {
+    return yAxis_.size();
+  }
+  /**
+   * Get an <code>Enumeration</code> object for the Y axes.
+   *
+   * @return enumeration
+   */
+  public Enumeration yAxisElements() {
+    return yAxis_.elements();
+  }
+  /**
+   * Set the X <code>AxisTransform</code>. This transform is used to convert
+   * to and from user to physical coordinates.
+   *
+   * @param xfrm X transform
+   * @see AxisTransform
+   * @see LinearTransform
+   */
+  public void setXTransform(AxisTransform xfrm) {
+    if(xTransform_ != null) xTransform_.removePropertyChangeListener(this);
+    xTransform_ = xfrm;
+    xTransform_.addPropertyChangeListener(this);
+  }
+  /**
+   * Get the current X <code>AxisTransform</code>.
+   *
+   * @return X Transform
+   * @see AxisTransform
+   * @see LinearTransform
+   */
+  public AxisTransform getXTransform() {
+    return xTransform_;
+  }
+  /**
+   * Set the Y <code>AxisTransform</code>. This transform is used to convert
+   * to and from user to physical coordinates.
+   *
+   * @param xfrm Y transform
+   * @see AxisTransform
+   * @see LinearTransform
+   */
+  public void setYTransform(AxisTransform xfrm) {
+    if(yTransform_ != null) yTransform_.removePropertyChangeListener(this);
+    yTransform_ = xfrm;
+    yTransform_.addPropertyChangeListener(this);
+  }
+  /**
+   * Get the current Y <code>AxisTransform</code>.
+   *
+   * @return Y Transform
+   * @see AxisTransform
+   * @see LinearTransform
+   */
+  public AxisTransform getYTransform() {
+    return yTransform_;
+  }
+  //
+  Object getObjectAt(Point pt) {
+    Rectangle bnds;
+    Axis ax;
+    SGLabel lab;
+    if(!xAxis_.isEmpty()) {
+      for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        bnds = ax.getBounds();
+        if(bnds.contains(pt)) {
+          return ax;
+        }
+        lab = ax.getTitle();
+        if((lab != null) && (lab.getLayer() != null)) {
+          bnds = lab.getBounds();
+          if(bnds.contains(pt)) {
+            return lab;
+          }
+        }
+      }
+    }
+    if(!yAxis_.isEmpty()) {
+      for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) {
+        ax = (Axis)it.nextElement();
+        bnds = ax.getBounds();
+        if(bnds.contains(pt)) {
+          return ax;
+        }
+        lab = ax.getTitle();
+        if(lab != null) {
+          bnds = lab.getBounds();
+          if(bnds.contains(pt)) {
+            return lab;
+          }
+        }
+      }
+    }
+    return (Object) null;
+  }
+  /**
+   * Transform user X coordinate to physical coordinate.
+   * @since 2.0
+   */
+  public double getXUtoP(double u) {
+    return xTransform_.getTransP(u);
+  }
+  /**
+   * Transform user X coordinate to device coordinate.
+   * @since 2.0
+   */
+  public int getXUtoD(double u) {
+    if(Double.isNaN(u)) return Integer.MIN_VALUE;
+    return getLayer().getXPtoD(xTransform_.getTransP(u));
+  }
+  /**
+   * Transform user X coordinate to device coordinate.
+   * @since 3.0
+   */
+  public double getXUtoD2(double u) {
+    if(Double.isNaN(u)) return u;
+    return getLayer().getXPtoD2(xTransform_.getTransP(u));
+  }
+  /**
+   * Transform <code>GeoDate</code> to physical coordinate.
+   * @since 2.0
+   */
+  public double getXUtoP(GeoDate t) {
+    return xTransform_.getTransP(t);
+  }
+  /**
+   * Transform <code>long</code> to physical coordinate.
+   * @since 3.0
+   */
+  public double getXUtoP(long t) {
+    return xTransform_.getTransP(t);
+  }
+  /**
+   * Transform <code>GeoDate</code> to device coordinate.
+   * @since 2.0
+   */
+  public int getXUtoD(GeoDate t) {
+    if(t == null) return Integer.MIN_VALUE;
+    return getLayer().getXPtoD(xTransform_.getTransP(t));
+  }
+  /**
+   * Transform <code>long</code> to device coordinate.
+   * @since 3.0
+   */
+  public int getXUtoD(long t) {
+    if(t == Long.MAX_VALUE) return Integer.MIN_VALUE;
+    return getLayer().getXPtoD(xTransform_.getTransP(t));
+  }
+  /**
+   * Transform <code>GeoDate</code> to device coordinate.
+   * @since 3.0
+   */
+  public double getXUtoD2(GeoDate t) {
+    if(t == null) return Double.NaN;
+    return getLayer().getXPtoD2(xTransform_.getTransP(t));
+  }
+  /**
+   * Transform <code>long</code> to device coordinate.
+   * @since 3.0
+   */
+  public double getXUtoD2(long t) {
+    if(t == Long.MAX_VALUE) return Double.NaN;
+    return getLayer().getXPtoD2(xTransform_.getTransP(t));
+  }
+  /**
+   * Transform X <code>SoTValue</code> to device coordinate.
+   * @since 3.0
+   */
+  public int getXUtoD(SoTValue val) {
+    if(val.isTime()) {
+      return getXUtoD(val.getLongTime());
+    } else {
+      return getXUtoD(((SoTValue.Double)val).getValue());
+    }
+  }
+  /**
+   * Transform Y <code>SoTValue</code> to device coordinate.
+   * @since 3.0
+   */
+  public int getYUtoD(SoTValue val) {
+    if(val.isTime()) {
+      return getYUtoD(val.getLongTime());
+    } else {
+      return getYUtoD(((SoTValue.Double)val).getValue());
+    }
+  }
+  /**
+   * Transform X <code>SoTValue</code> to device coordinate.
+   * @since 3.0
+   */
+  public double getXUtoD2(SoTValue val) {
+    if(val.isTime()) {
+      return getXUtoD2(val.getLongTime());
+    } else {
+      return getXUtoD2(((SoTValue.Double)val).getValue());
+    }
+  }
+  /**
+   * Transform Y <code>SoTValue</code> to device coordinate.
+   * @since 3.0
+   */
+  public double getYUtoD2(SoTValue val) {
+    if(val.isTime()) {
+      return getYUtoD2(val.getLongTime());
+    } else {
+      return getYUtoD2(((SoTValue.Double)val).getValue());
+    }
+  }
+  /**
+   * Transform X <code>SoTValue</code> to physical coordinate.
+   * @since 3.0
+   */
+  public double getXUtoP(SoTValue val) {
+    if(val.isTime()) {
+      return getXUtoP(val.getLongTime());
+    } else {
+      return getXUtoP(((SoTValue.Double)val).getValue());
+    }
+  }
+  /**
+   * Transform Y <code>SoTValue</code> to physical coordinate.
+   * @since 3.0
+   */
+  public double getYUtoP(SoTValue val) {
+    if(val.isTime()) {
+      return getYUtoP(val.getLongTime());
+    } else {
+      return getYUtoP(((SoTValue.Double)val).getValue());
+    }
+  }
+  /**
+   * Transform physical X coordinate to user coordinate using <code>SoTValue</code>
+   * @param p physical coordinate
+   * @return user coorindinate
+   * @since 3.0
+   */
+  public SoTValue getXPtoSoT(double p) {
+    if(xTransform_.isTime()) {
+      return new SoTValue.Time(xTransform_.getLongTimeTransU(p));
+    } else {
+      return new SoTValue.Double(xTransform_.getTransU(p));
+    }
+  }
+  /**
+   * Transform physical X coordinate to user coordinate.
+   *
+   * @param p physical coorindate
+   * @return user coordinate
+   **/
+  public double getXPtoU(double p) {
+    return xTransform_.getTransU(p);
+  }
+  /**
+   * Transform physical X coordinate to time.
+   *
+   * @param p physical coordinate
+   * @return time
+   **/
+  public GeoDate getXPtoTime(double p) {
+    return xTransform_.getTimeTransU(p);
+  }
+  /**
+   * Transform physical X coordinate to time.
+   *
+   * @param p physical coordinate
+   * @return time
+   * @since 3.0
+   **/
+  public long getXPtoLongTime(double p) {
+    return xTransform_.getLongTimeTransU(p);
+  }
+  /**
+   * Transform physical coordinate to a <code>SoTPoint</code>
+   *
+   * @since 3.0
+   * @param p physical coordinate
+   * @return <code>SoTPoint</code>
+   **/
+  public SoTPoint getPtoU(Point2D.Double loc) {
+    SoTValue xv;
+    SoTValue yv;
+    // x - transform
+    if(xTransform_.isTime()) {
+      xv = new SoTValue.Time(getXPtoLongTime(loc.x));
+    } else {
+      xv = new SoTValue.Double(getXPtoU(loc.x));
+    }
+    if(yTransform_.isTime()) {
+      yv = new SoTValue.Time(getYPtoLongTime(loc.y));
+    } else {
+      yv = new SoTValue.Double(getYPtoU(loc.y));
+    }
+    return new SoTPoint(xv, yv);
+  }
+  /**
+   * Transoform user Y coordinate to physical coordinate.
+   * @since 2.0
+   */
+  public double getYUtoP(double u) {
+    return yTransform_.getTransP(u);
+  }
+  /**
+   * Transform user Y coordinate to device coordinate
+   * @since 2.0
+   */
+  public int getYUtoD(double u) {
+    if(Double.isNaN(u)) return Integer.MIN_VALUE;
+    return getLayer().getYPtoD(yTransform_.getTransP(u));
+  }
+  /**
+   * Transform user Y coordinate to device coordinate
+   * @since 3.0
+   */
+  public double getYUtoD2(double u) {
+    if(Double.isNaN(u)) return u;
+    return getLayer().getYPtoD2(yTransform_.getTransP(u));
+  }
+  /**
+   * Transform time to physical coordinate.
+   * @since 2.0
+   */
+  public double getYUtoP(GeoDate t) {
+    return yTransform_.getTransP(t);
+  }
+  /**
+   * Transform time to physical coordinate.
+   * @since 3.0
+   */
+  public double getYUtoP(long t) {
+    if(t == Long.MAX_VALUE) return Double.NaN;
+    return yTransform_.getTransP(t);
+  }
+  /**
+   * Transform time to device coordinate.
+   * @since 2.0
+   */
+  public int getYUtoD(GeoDate t) {
+    if(t == null) return Integer.MIN_VALUE;
+    return getLayer().getYPtoD(yTransform_.getTransP(t));
+  }
+  /**
+   * Transform time to device coordinate.
+   * @since 3.0
+   */
+  public int getYUtoD(long t) {
+    if(t == Long.MAX_VALUE) return Integer.MIN_VALUE;
+    return getLayer().getYPtoD(yTransform_.getTransP(t));
+  }
+  /**
+   * Transform time to device coordinate.
+   * @since 3.0
+   */
+  public double getYUtoD2(GeoDate t) {
+    if(t == null) return Double.NaN;
+    return getLayer().getYPtoD2(yTransform_.getTransP(t));
+  }
+  /**
+   * Transform time to device coordinate.
+   * @since 3.0
+   */
+  public double getYUtoD2(long t) {
+    if(t == Long.MAX_VALUE) return Double.NaN;
+    return getLayer().getYPtoD2(yTransform_.getTransP(t));
+  }
+  /**
+   * Transform physical Y coordinate to user coordinate using <code>SoTValue</code>
+   * @param p physical coordinate
+   * @return user coorindinate
+   * @since 3.0
+   */
+  public SoTValue getYPtoSoT(double p) {
+    if(yTransform_.isTime()) {
+      return new SoTValue.Time(yTransform_.getLongTimeTransU(p));
+    } else {
+      return new SoTValue.Double(yTransform_.getTransU(p));
+    }
+  }
+  /**
+   * Transform physical Y coordinate to user coordinate.
+   *
+   * @param p physical coorindate
+   * @return user coordinate
+   **/
+  public double getYPtoU(double p) {
+    return yTransform_.getTransU(p);
+  }
+  /**
+   * Transform physical Y coordinate to time.
+   *
+   * @param p physical coordinate
+   * @return time
+   **/
+  public GeoDate getYPtoTime(double p) {
+    return yTransform_.getTimeTransU(p);
+  }
+  /**
+   * Transform physical Y coordinate to time.
+   *
+   * @param p physical coordinate
+   * @return time
+   * @since 3.0
+   **/
+  public long getYPtoLongTime(double p) {
+    return yTransform_.getLongTimeTransU(p);
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    //      if(Debug.EVENT) {
+    //        System.out.println("CartesianGraph: " + evt);
+    //        System.out.println("                " + evt.getPropertyName());
+    //      }
+    modified("CartesianGraph: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  /**
+   * Find data at point
+   * @since 3.0
+   */
+  public SGTData getDataAt(Point pt) {
+    return renderer_.getDataAt(pt);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CartesianRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CartesianRenderer.java
new file mode 100755
index 0000000..b01ff22
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/CartesianRenderer.java
@@ -0,0 +1,202 @@
+/*
+ * $Id: CartesianRenderer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTPoint;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SGTImage;
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.SGTVector;
+import gov.noaa.pmel.sgt.dm.Annotation;
+
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.beans.PropertyChangeListener;
+
+/**
+ * <code>CartesianRenderer</code> defines an interface to enable data to
+ * be rendered on a <code>CartesianGraph</code>.
+ *
+ * @see CartesianGraph
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public abstract class CartesianRenderer implements PropertyChangeListener {
+  /**
+   * Factory method to create a new Renderer instance given
+   * the <code>SGTData</code> object and <code>Attribute</code>.
+   * For example, a <code>LineCartesianRenderer</code>
+   * is created if <code>SGTData</code> object is a <code>SGTLine</code>.
+   * <p>
+   * A renderer is constucted based on the two arguements.
+   * <p>
+   * <TABLE BORDER="1" CELLPADDING="2" BGCOLOR="white">
+   *	<TR>
+   *		<TH WIDTH="25%" BGCOLOR="#FFFFCC">
+   *			<P>SGTData
+   *		</TH>
+   *		<TH WIDTH="25%" BGCOLOR="#FFFFCC">
+   *			<P>Attribute
+   *		</TH>
+   *		<TH WIDTH="50%" BGCOLOR="#FFFFCC">
+   *			<P>CartesianRenderer
+   *		</TH>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">SGTPoint</TD>
+   *		<TD WIDTH="25%">PointAttribute</TD>
+   *		<TD WIDTH="50%">PointCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">SGTLine</TD>
+   *		<TD WIDTH="25%">LineAttribute</TD>
+   *		<TD WIDTH="50%">LineCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">SGTGrid</TD>
+   *		<TD WIDTH="25%">GridAttribute</TD>
+   *		<TD WIDTH="50%">GridCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">SGTVector</TD>
+   *		<TD WIDTH="25%">VectorAttribute</TD>
+   *		<TD WIDTH="50%">VectorCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">Collection</TD>
+   *		<TD WIDTH="25%">PointAttribute</TD>
+   *		<TD WIDTH="50%">PointCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">Collection</TD>
+   *		<TD WIDTH="25%">LineAttribute</TD>
+   *		<TD WIDTH="50%">LineCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">Collection</TD>
+   *		<TD WIDTH="25%">VectorAttribute</TD>
+   *		<TD WIDTH="50%">VectorCartesianRenderer</TD>
+   *	</TR>
+   *	<TR>
+   *		<TD WIDTH="25%">Annotation</TD>
+   *		<TD WIDTH="25%">n/a</TD>
+   *		<TD WIDTH="50%">AnnotationCartesianRenderer</TD>
+   *	</TR>
+   *</TABLE>
+   *<p>
+   *
+   * @param dmo DataModel object
+   */
+  public static CartesianRenderer getRenderer(CartesianGraph cg,
+                                              SGTData dmo,
+                                              Attribute attr) {
+    if(dmo instanceof SGTPoint) {
+      return new PointCartesianRenderer(cg,
+                                        (SGTPoint)dmo,
+                                        (PointAttribute)attr);
+    } else if(dmo instanceof SGTLine) {
+      return new LineCartesianRenderer(cg,
+                                       (SGTLine)dmo,
+                                       (LineAttribute)attr);
+    } else if(dmo instanceof SGTGrid) {
+      return new GridCartesianRenderer(cg,
+                                       (SGTGrid)dmo,
+                                       (GridAttribute)attr);
+    } else if(dmo instanceof SGTVector) {
+      return new VectorCartesianRenderer(cg,
+                                         (SGTVector)dmo,
+                                         (VectorAttribute)attr);
+    } else if(dmo instanceof Collection) {
+      Object fe = ((Collection)dmo).firstElement();
+      if(fe instanceof SGTPoint) {
+        return new PointCartesianRenderer(cg,
+                                          (Collection)dmo,
+                                          (PointAttribute)attr);
+      } else if(fe instanceof SGTLine) {
+        return new LineCartesianRenderer(cg,
+                                         (Collection)dmo,
+                                         (LineAttribute)attr);
+      } else if(fe instanceof SGTVector) {
+        return new VectorCartesianRenderer(cg,
+                                           (Collection)dmo,
+                                           (VectorAttribute)attr);
+      }
+    } else if(dmo instanceof Annotation) {
+      return new AnnotationCartesianRenderer(cg,
+                                             (Annotation)dmo,
+                                             null);
+    }
+    return null;
+  }
+  /**
+   * Render the <code>SGTData</code> object. This method should
+   * never be called directly.
+   *
+   * @see Pane#draw
+   */
+  public abstract void draw(Graphics g);
+  /**
+   * Get the <code>Attribute</code> associated with the
+   * renderer.
+   *
+   * @return the <code>Attribute</code>
+   */
+  public abstract Attribute getAttribute();
+  /**
+   * Get the <code>CartesianGraph</code> associated with the
+   * renderer.
+   * @since 2.0
+   *
+   * @return the <code>CartesianGraph</code>
+   */
+  public abstract CartesianGraph getCartesianGraph();
+/** @directed
+ * @label cg*/
+  protected CartesianGraph cg_;
+  /**
+   * Get parent pane.
+   * @since 2.0
+   */
+  public AbstractPane getPane() {
+    return cg_.getPane();
+  }
+  /**
+   * For internal sgt use.
+   * @since 2.0
+   */
+  public void modified(String mess) {
+    if(cg_ != null)
+      cg_.modified(mess);
+  }
+  /**
+   * Find data object.
+   * @since 3.0
+   */
+  public SGTData getDataAt(int x, int y) {
+    return getDataAt(new Point(x, y));
+  }
+  /**
+   * Find data object.
+   * @since 3.0
+   */
+  public abstract SGTData getDataAt(Point pt);
+}
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ChildNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ChildNotFoundException.java
new file mode 100755
index 0000000..2f68ecb
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ChildNotFoundException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: ChildNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Child was not found during operation.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class ChildNotFoundException extends SGException {
+  public ChildNotFoundException() {
+    super();
+}
+  public ChildNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ColorKey.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ColorKey.java
new file mode 100755
index 0000000..d0ca29b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ColorKey.java
@@ -0,0 +1,744 @@
+/*
+ * $Id: ColorKey.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Insets;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.awt.Point;
+
+// jdk1.2
+//import java.awt.geom.Rectangle2D;
+//import java.awt.geom.Point2D;
+
+/**
+ * The <code>ColorKey</code> class provides a graphical depiction
+ * of the relationship between a <code>ColorMap</code>
+ * and user values. A single <code>ColorKey</code> can be
+ * attached to a <code>Layer</code>. A <code>ColorMap</code>
+ * is associated with the Key and therefor with a specific transformation
+ * and optionally a <code>SGTData</code> object.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see Ruler
+ * @see ColorMap
+ * @see Layer
+**/
+public class ColorKey implements Cloneable, DataKey,
+                                 PropertyChangeListener {
+  // Scale members
+  /**@label title
+   * @link aggregationByValue
+   * @undirected
+   */
+  private SGLabel title_ = null;
+  //
+  private String ident_;
+  /** @directed */
+  private Layer layer_;
+  /**@label scale
+   * @link aggregationByValue */
+  private Ruler scale_ = new Ruler(); // mod Tom Ewing
+  private int valign_;
+  private int halign_;
+  private int orient_;
+  private int style_;
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean visible_;
+  /**
+   * maximum bounds of key in p-space
+   */
+//  private Rectangle2D.Double pbounds_;
+  private Point2D.Double porigin_;
+  private Dimension2D psize_;
+  /**
+   * top, left, bottom, right in p-space
+   */
+  private double[] insets_ = {0.05, 0.15, 0.05, 0.15};
+  private double barWidth_ = 0.2;
+
+  /**
+   * @label cm
+   */
+  private ColorMap cm_ = null;
+  /**
+   * Use plain line border.
+   */
+  public static final int PLAIN_LINE = 0;
+  /**
+   * Use raised border.
+   */
+  public static final int RAISED = 1;
+  /**
+   * Do not draw a border.
+   */
+  public static final int NO_BORDER = 2;
+  /**
+   * Align to top of key.
+   */
+  public static final int TOP = 0;
+  /**
+   * Align to middle of key.
+   */
+  public static final int MIDDLE = 1;
+  /**
+   * Align to bottom of key.
+   */
+  public static final int BOTTOM = 2;
+  /**
+   * Align to left of key.
+   */
+  public static final int LEFT = 0;
+  /**
+   * Align to center of key.
+   */
+  public static final int CENTER = 1;
+  /**
+   * Align to right of key.
+   */
+  public static final int RIGHT = 2;
+  /**
+   * Orient key horizontally.
+   */
+  public static final int HORIZONTAL = 1;
+  /**
+   * Orient key vertically.
+   */
+  public static final int VERTICAL = 2;
+
+//  private boolean moveable_ = false;
+//  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  /**
+   * Default <code>ColorKey</code> constructor. The location and size
+   * must be specified before the <code>ColorKey</code> is
+   * attached to a layer!
+   **/
+  public ColorKey() {
+    this(new Rectangle2D.Double(), BOTTOM, LEFT);
+  }
+  /**
+   * <code>ColorKey</code> constructor that include location, size,
+   * and alignment information. Default orientation is
+   * <code>HORIZONTAL</code>.
+   *
+   * @param pr a Rectangle2D object that includes location and size
+   * @param valign vertical alignment
+   * @param halign horizontal alignment
+   **/
+  public ColorKey(Rectangle2D.Double pr,int valign,int halign) {
+    this(new Point2D.Double(pr.x, pr.y),
+         new Dimension2D(pr.width, pr.height),
+         valign, halign);
+  }
+  /**
+   * @since 3.0
+   */
+  public ColorKey(Point2D.Double pt, Dimension2D size, int valign, int halign) {
+    porigin_ = pt;
+    psize_ = size;
+//    pbounds_ = new Rectangle2D.Double(pt.x, pt.y, size.width, size.height);
+    valign_ = valign;
+    halign_ = halign;
+    //
+    // set defaults
+    //
+    orient_ = HORIZONTAL;
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+    style_ = PLAIN_LINE;
+//    moveable_ = false;
+
+  }
+  /**
+   * Create a copy of <code>ColorKey</code>.
+   *
+   * @return a copy of the key
+   */
+  public LayerChild copy() {
+    ColorKey newKey;
+    try {
+      newKey = (ColorKey)clone();
+    } catch (CloneNotSupportedException e) {
+      newKey = new ColorKey();
+    }
+    return (LayerChild)newKey;
+  }
+  /**
+   * Sets the <code>selected</code> property.
+   * @since 2.0
+   *
+   * @param sel true if selected, false if not.
+   */
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  /**
+   * Returns true if the <code>selected</code> property is set.
+   *
+   * @return true is selected, false if not.
+   */
+  public boolean isSelected() {
+    return selected_;
+  }
+  /**
+   * Sets the selectable property.
+   * @since 2.0
+   */
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  /**
+   * Tests the selectable property.
+   * @since 2.0
+   */
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  /**
+   * Set ColorKey identifier.
+   *
+   * @param id key identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get <code>ColorKey</code> identifier
+   *
+   * @return identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set parent <code>Layer</code>. Method should not be called
+   * directly, called when the <code>Layer.addChild</code>
+   * method is called.
+   *
+   * @param l parent layer
+   */
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  /**
+   * Returns the layer the ColorKey is attached.
+   *
+   * @return The parent layer.
+   * @see Layer
+   **/
+  public Layer getLayer() {
+    return layer_;
+  }
+  /**
+   * Get the parent pane.
+   * @since 2.0
+   */
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+  /**
+   * For internal sgt use.
+   * @since 2.0
+   */
+  public void modified(String mess) {
+    //    if(Debug.EVENT) System.out.println("ColorKey: modified()");
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Set color map.
+   *
+   * @param cm color map
+   */
+  public void setColorMap(ColorMap cm) {
+    if(cm_ == null || !cm_.equals(cm)) {
+      if(cm_ != null) cm_.removePropertyChangeListener(this);
+      cm_ = cm;
+      cm_.addPropertyChangeListener(this);
+      modified("ColorKey: setColorMap()");
+    }
+  }
+  /**
+   * Add a GridCartesianRenderer and label to the ColorKey.
+   *
+   * @param rend GridCartesianRenderer object
+   * @param label descriptive label
+   * @since 3.0
+   */
+  public void addGraph(CartesianRenderer rend, SGLabel label)
+      throws IllegalArgumentException {
+    if(!(rend instanceof GridCartesianRenderer))
+      throw new IllegalArgumentException("Renderer is not a GridCartesianRenderer");
+    GridAttribute ga = (GridAttribute)((GridCartesianRenderer)rend).getAttribute();
+    ColorMap cm = ga.getColorMap();
+    setColorMap(cm);
+    setTitle(label);
+ //   addVectorGraph((VectorCartesianRenderer)rend, label);
+  }
+  /**
+   * Get color map.
+   *
+   * @return color map
+   */
+  public ColorMap getColorMap() {
+    return cm_;
+  }
+  /**
+   * Set border style.
+   *
+   * @param style border style
+   * @see #PLAIN_LINE
+   * @see #RAISED
+   * @see #NO_BORDER
+   */
+  public void setBorderStyle(int style) {
+    if(style_ != style) {
+      style_ = style;
+      modified("LineKey: setBorderStyle()");
+    }
+  }
+  /**
+   * Get border style.
+   *
+   * @return border style
+   */
+  public int getBorderStyle() {
+    return style_;
+  }
+  /**
+   * Set color key alignment.
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   */
+  public void setAlign(int vert,int horz) {
+    if(valign_ != vert || halign_ != horz) {
+      valign_ = vert;
+      halign_ = horz;
+      modified("ColorKey: setAlign()");
+    }
+  }
+  /**
+   * Set orientation.
+   *
+   * @param orient key orientation
+   */
+  public void setOrientation(int orient) {
+    if(orient_ != orient) {
+      orient_ = orient;
+      modified("ColorKey: setOrientation()");
+    }
+  }
+  /**
+   * Set vertical alignment
+   *
+   * @param vert vertical alignment
+   */
+  public void setVAlign(int vert) {
+    if(valign_ != vert) {
+      valign_ = vert;
+      modified("ColorKey: setVAlign()");
+    }
+  }
+  /**
+   * Set horizontal alignment
+   *
+   * @param horz horizontal alignment
+   */
+  public void setHAlign(int horz) {
+    if(halign_ != horz) {
+      halign_ = horz;
+      modified("ColorKey: setHAlign()");
+    }
+  }
+  /**
+   * Get vertical alignment
+   *
+   * @return vertical alignment
+   */
+  public int getVAlign() {
+    return valign_;
+  }
+  /**
+   * Get horizontal alignment
+   *
+   * @return horizontal alignment
+   */
+  public int getHAlign() {
+    return halign_;
+  }
+  /**
+   * Set location of key in physical coordinates.
+   *
+   * @param loc key location
+   */
+  public void setLocationP(Point2D.Double loc) {
+    if(porigin_.x != loc.x || porigin_.y != loc.y) {
+//      Point2D.Double temp = new Point2D.Double(pbounds_.x, pbounds_.y);
+      porigin_.x = loc.x;
+      porigin_.y = loc.y;
+      modified("ColorKey: setLocationP()");
+//      changes_.firePropertyChange("location", temp, loc);
+    }
+  }
+  /**
+   * Set the size of the key in physical coordinates.
+   *
+   * @param d size of key
+   */
+  public void setSizeP(Dimension2D d) {
+    if(psize_.width != d.width || psize_.height != d.height) {
+      psize_.width = d.width;
+      psize_.height = d.height;
+      modified("ColorKey: setSizeP()");
+    }
+  }
+  /**
+   * Set the bounds of the key in physical coordinates.
+   *
+   * @param r bounding rectangle
+   */
+  public void setBoundsP(Rectangle2D.Double r) {
+    if(Debug.EVENT) System.out.println("ColorKey: porigin = " +
+                                       porigin_ + ", r = " + r);
+    setLocationP(new Point2D.Double(r.x, r.y));
+    setSizeP(new Dimension2D(r.width, r.height));
+//    if(pbounds_ == null || !pbounds_.equals(r)) {
+//      pbounds_ = r;
+//      modified("ColorKey: setBoundsP()");
+//    }
+  }
+  /**
+   * Get the bounding rectangle for the key in physical
+   * coordinates.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle2D.Double getBoundsP() {
+    return new Rectangle2D.Double(porigin_.x, porigin_.y,
+                                  psize_.width, psize_.height);
+  }
+  /**
+   * Gets the bounding rectangle in device
+   * coordinates.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds() {
+    int x, y, height, width;
+    x = layer_.getXPtoD(porigin_.x);
+    y = layer_.getYPtoD(porigin_.y);
+    width = layer_.getXPtoD(porigin_.x + psize_.width) - x;
+    height = layer_.getYPtoD(porigin_.y - psize_.height) - y;
+    switch(halign_) {
+    case RIGHT:
+      x = x - width;
+      break;
+    case CENTER:
+      x = x - width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y - height;
+      break;
+    case MIDDLE:
+      y = y - height/2;
+    }
+    if(false) {
+      StringBuffer sbuf = new StringBuffer("\nColorKey.getBounds(): ");
+      switch(halign_) {
+        case RIGHT:
+          sbuf.append("RIGHT");
+          break;
+        case LEFT:
+          sbuf.append("LEFT");
+          break;
+        case CENTER:
+          sbuf.append("CENTER");
+          break;
+      }
+      sbuf.append(", ");
+      switch(valign_) {
+        case TOP:
+          sbuf.append("TOP");
+          break;
+        case BOTTOM:
+          sbuf.append("BOTTOM");
+          break;
+        case MIDDLE:
+          sbuf.append("MIDDLE");
+          break;
+      }
+      System.out.println(sbuf);
+      System.out.println("    orig = " + porigin_ + ", " + "size = " + psize_);
+      System.out.println("    x,y,width,height = " + x + ", " + y + ", " +
+                         width + ", " + height);
+      System.out.println("   layer.getBounds() = " + layer_.getBounds());
+      System.out.println("   layer.getBoundsP() = " + layer_.getBoundsP());
+    }
+    return new Rectangle(x, y, width, height);
+  }
+  /**
+   * Change the selected objects bounding rectangle in
+   * device coordinates. The object will move to the new bounding
+   * rectangle.
+   *
+   * @param r new bounding rectangle
+   */
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  /**
+   * Change the selected objects bounding rectangle in
+   * device coordinates. The object will move to the new bounding
+   * rectangle.
+   *
+   * @param x horizontal location, positive right
+   * @param y vertical location, positive down
+   * @param width horizontal size
+   * @param height vertical size
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    switch(halign_) {
+    case RIGHT:
+      x = x + width;
+      break;
+    case CENTER:
+      x = x + width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y + height;
+      break;
+    case MIDDLE:
+      y = y + height/2;
+    }
+//    Point orig = new Point(layer_.getXPtoD(pbounds_.x),
+//                           layer_.getYPtoD(pbounds_.y));
+    double xp = layer_.getXDtoP(x);
+    double yp = layer_.getYDtoP(y);
+    if(porigin_.x != xp || porigin_.y != yp) {
+      porigin_.x = xp;
+      porigin_.y = yp;
+      modified("ColorKey: setBounds()");
+//      changes_.firePropertyChange("location",
+//                                  orig, new Point(x,y));
+    }
+  }
+  /**
+   * Set the title of the key.
+   *
+   * @param title key title
+   */
+  public void setTitle(SGLabel title) {
+    if(title_ == null || !title_.equals(title)) {
+      title_ = title;
+      modified("ColorKey: setTitle()");
+    }
+  }
+  /**
+   * Get the key's title.
+   *
+   * @return the title
+   */
+  public SGLabel getTitle() {
+    return title_;
+  }
+  /**
+   * Get the <code>Ruler</code> associated
+   * with the key.
+   *
+   * @return the ruler
+   */
+  public Ruler getRuler() {
+    return scale_;
+  }
+  /**
+   * Draw the ColorKey. This method should not be directly called.
+   *
+   * @see Pane#draw
+   */
+  public void draw(Graphics g) {
+    Rectangle bounds;
+    double xp, yp;  // lower-left coordinates in p-space
+    double ptop, pbottom, pleft, pright; // insets in p-space
+    double delta;
+    if(!visible_) return;
+    ptop = insets_[0];
+    pbottom =insets_[2];
+    pleft = insets_[1];
+    pright = insets_[3];
+    xp = porigin_.x;
+    yp = porigin_.y;
+    switch(halign_) {
+    case RIGHT:
+      xp = xp - psize_.width;
+      break;
+    case CENTER:
+      xp = xp - psize_.width/2;
+    }
+    switch(valign_) {
+    case TOP:
+      yp = yp - psize_.height;
+      break;
+    case MIDDLE:
+      yp = yp - psize_.height/2;
+    }
+    bounds = getBounds();
+    g.setColor(Color.black);
+    switch(style_) {
+    case PLAIN_LINE:
+      g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+      break;
+    case RAISED:
+      break;
+    default:
+    case NO_BORDER:
+    }
+
+    if(cm_ == null) return;
+    Range2D uRange = cm_.getRange();
+    //
+    if(Double.isNaN(uRange.delta)) {
+      Range2D rnge = Graph.computeRange(uRange.start, uRange.end, 10);
+      delta = rnge.delta;
+    } else {
+      delta = uRange.delta;
+    }
+    if(orient_ == HORIZONTAL) {
+      drawBar(g, xp + pleft, yp + psize_.height - ptop,
+              psize_.width - pleft - pright,
+              psize_.height - ptop - pbottom);
+      //scale_ = new Ruler(); // mod Tom Ewing
+      scale_.setOrientation(Ruler.HORIZONTAL);
+      scale_.setLayer(layer_);
+      scale_.setTitle(title_);
+      scale_.setTicPosition(Ruler.NEGATIVE_SIDE);
+      scale_.setLabelPosition(Ruler.NEGATIVE_SIDE);
+      scale_.setBoundsP(new Rectangle2D.Double(xp + pleft,
+                                               yp + psize_.height - ptop - barWidth_,
+                                               psize_.width - pleft - pright,
+                                               psize_.height - ptop - pbottom));
+      scale_.setRangeU(new Range2D(uRange.start, uRange.end, delta));
+      scale_.draw(g);
+    } else {
+      drawBar(g, xp + pleft, yp + pbottom,
+              psize_.width - pleft - pright,
+              psize_.height - ptop - pbottom);
+      //scale_ = new Ruler(); // mod dwd
+      scale_.setOrientation(Ruler.VERTICAL);
+      scale_.setLayer(layer_);
+      scale_.setTitle(title_);
+      scale_.setTicPosition(Ruler.POSITIVE_SIDE);
+      scale_.setLabelPosition(Ruler.POSITIVE_SIDE);
+      scale_.setBoundsP(new Rectangle2D.Double(xp + pleft + barWidth_,
+                                               yp + pbottom,
+                                               psize_.width - pleft - pright,
+                                               psize_.height - ptop - pbottom));
+      scale_.setRangeU(new Range2D(uRange.start, uRange.end, delta));
+      scale_.draw(g);
+    }
+  }
+  //
+  void drawBar(Graphics g,
+               double plocx, double plocy,
+               double pwidth, double pheight) {
+    int yloc, xloc, xend, yend;
+    int dBarHeight, dBarWidth;
+    Range2D uRange = cm_.getRange();
+    AxisTransform sTrans;
+    if(orient_ == HORIZONTAL) {
+      dBarHeight = layer_.getYPtoD(plocy - barWidth_) -
+        layer_.getYPtoD(plocy);
+      sTrans = new LinearTransform(plocx, plocx + pwidth,
+                                   uRange.start, uRange.end);
+      yloc = layer_.getYPtoD(plocy);
+      xloc = layer_.getXPtoD(sTrans.getTransP(uRange.start));
+      xend = layer_.getXPtoD(sTrans.getTransP(uRange.end));
+      for(int i=xloc; i <= xend; i++) {
+        g.setColor(cm_.getColor(sTrans.getTransU(layer_.getXDtoP(i))));
+        g.fillRect(i, yloc, 1, dBarHeight);
+      }
+    } else {
+      dBarWidth = layer_.getXPtoD(plocx + barWidth_) - layer_.getXPtoD(plocx);
+      sTrans = new LinearTransform(plocy, plocy + pheight,
+                                   uRange.start, uRange.end);
+      xloc = layer_.getXPtoD(plocx);
+      yloc = layer_.getYPtoD(sTrans.getTransP(uRange.start));
+      yend = layer_.getYPtoD(sTrans.getTransP(uRange.end));
+      for(int i=yend; i <= yloc; i++) {
+        g.setColor(cm_.getColor(sTrans.getTransU(layer_.getXDtoP(i))));
+        g.fillRect(xloc, i, dBarWidth, 1);
+      }
+    }
+  }
+  /**
+   * Get a string representation of the key.
+   *
+   * @return string representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  /**
+   * Check if ColorKey is visible.
+   * @since 2.0
+   */
+  public boolean isVisible() {
+    return visible_;
+  }
+  /**
+   * Set visibility state for ColorKey.
+   * @since 2.0
+   */
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("ColorKey: setVisible()");
+    }
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    modified("ColorKey: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+
+  /**
+   * Set columns. Unimplmented.
+   * @param col
+   * @since 3.0
+   */
+  public void setColumns(int col) {}
+  /**
+   * Set line lenght. Unimplemented.
+   * @since 3.0
+   */
+  public void setLineLengthP(double len) {}
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ColorMap.java
new file mode 100755
index 0000000..c42a709
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ColorMap.java
@@ -0,0 +1,137 @@
+/*
+ * $Id: ColorMap.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+import java.io.Serializable;
+
+/**
+ * <code>ColorMap</code> provides a mapping from an index or
+ * value to a <code>Color</code>. Several methods of mapping an
+ * index or value to a <code>Color</code> are summarized below. <br>
+ *
+ * <DL>
+ *   <DT><CODE>IndexedColorMap</CODE></DT>
+ *     <DD><CODE>Color</CODE> is determined from an array,
+ *         the index computed from a <CODE>Transform</CODE>.
+ *   <DT><CODE>TransformColorMap</CODE></DT>
+ *	 <DD>Red, green, blue <CODE>Color</CODE> components
+ *         are computed from <CODE>Transform</CODE>s.
+ *   <DT><CODE>CLIndexedColorMap</CODE></DT>
+ *	 <DD><CODE>Color</CODE> is determined from and array,
+ *         the index computed from a <CODE>ContourLevels</CODE> object.
+ *   <DT><CODE>CLTransformColorMap</CODE></DT>
+ *	 <DD>Red, green, blue <CODE>Color</CODE> components
+ *         are computed from <CODE>Transform</CODE>s, using
+ *         the index computed from a <CODE>ContourLevels</CODE>
+ *         object divided by the maximum index value.
+ * </DL>
+ *
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+abstract public class ColorMap implements Cloneable, PropertyChangeListener, Serializable {
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  protected boolean batch_ = false;
+  protected boolean local_ = true;
+  protected boolean modified_ = false;
+  abstract public ColorMap copy();
+  /**
+   * Get a <code>Color</code>.
+   *
+   * @param val Value
+   * @return Color
+   *
+   */
+  abstract public Color getColor(double val);
+
+  /**
+   * Get the current user range for the <code>Transform</code>s or
+   * <code>ContourLevel</code>.
+   *
+   * @return user range
+   */
+  abstract public Range2D getRange();
+  /**
+   * Test for equality of color maps.
+   */
+  abstract public boolean equals(ColorMap cm);
+  /**
+   * Add listener to changes in <code>ColorMap</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    changes_.addPropertyChangeListener(listener);
+  }
+  /**
+   * Remove listener.
+   */
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    if(Debug.EVENT) {
+      System.out.println("ColorMap: " + evt);
+      System.out.println("          " + evt.getPropertyName());
+    }
+    firePropertyChange(evt.getPropertyName(),
+                       evt.getOldValue(),
+                       evt.getNewValue());
+  }
+
+  protected void firePropertyChange(String name, Object oldValue, Object newValue) {
+    if(batch_) {
+      modified_ = true;
+      return;
+    }
+    AttributeChangeEvent ace = new AttributeChangeEvent(this, name,
+                                                        oldValue, newValue,
+                                                        local_);
+    changes_.firePropertyChange(ace);
+    modified_ = false;
+  }
+
+  /**
+   * Batch the changes to the ColorMap.
+   *
+   * @since 3.0
+   */
+  public void setBatch(boolean batch) {
+    setBatch(batch, true);
+  }
+  /**
+   * Batch the changes to the ColorMap and set local flag.
+   * Determines whether <code>AttributeChangeEvent</code> will be set local.
+   *
+   * @since 3.0
+   */
+  public void setBatch(boolean batch, boolean local) {
+    local_ = local;
+    batch_ = batch;
+    if(!batch && modified_) firePropertyChange("batch", Boolean.TRUE, Boolean.FALSE);
+  }
+  /**
+   * Is the attribute in batch mode?
+   *
+   * @since 3.0
+   */
+  public boolean isBatch() {
+    return batch_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevelNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevelNotFoundException.java
new file mode 100755
index 0000000..7ace164
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevelNotFoundException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: ContourLevelNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Contour level does not exist.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class ContourLevelNotFoundException extends SGException {
+  public ContourLevelNotFoundException() {
+    super();
+}
+  public ContourLevelNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevels.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevels.java
new file mode 100755
index 0000000..b9af084
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevels.java
@@ -0,0 +1,320 @@
+/*
+ * $Id: ContourLevels.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.awt.Color;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * Contains levels and line styles for contour graphics.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public class ContourLevels implements Cloneable {
+  /**
+   * @label defaultAttr
+   * @link aggregationByValue
+   * @supplierCardinality 1
+   */
+  private DefaultContourLineAttribute defaultAttr_ =
+    new DefaultContourLineAttribute();
+  private Vector levels_ = new Vector();
+  private Hashtable lineAttrMap_ = new Hashtable();
+  private boolean sorted_ = false;
+  /**
+   * @label solid
+   * @link aggregationByValue
+   */
+  static private ContourLineAttribute solid_ =
+    new ContourLineAttribute(ContourLineAttribute.SOLID);
+
+  /**
+   * @label heavy
+   * @link aggregationByValue
+   */
+  static private ContourLineAttribute heavy_ =
+    new ContourLineAttribute(ContourLineAttribute.HEAVY);
+
+  /**
+   * @label dashed
+   * @link aggregationByValue
+   */
+  static private ContourLineAttribute dashed_ =
+    new ContourLineAttribute(ContourLineAttribute.DASHED);
+
+  private PropertyChangeSupport changes_ =
+    new PropertyChangeSupport(this);
+
+  /**
+   * @directed
+   * @label lineAttrMap
+   * @link aggregation
+   * @supplierCardinality 1..*
+   */
+  private ContourLineAttribute lnkLineAttribute;
+  /**
+   * Construct a default <code>ContourLevels</code> object from a double[].
+   */
+  static public ContourLevels getDefault(double[] array) {
+    ContourLevels cl = new ContourLevels();
+    double val = 0.0;
+    for(int i=0; i < array.length; i++) {
+      cl.addLevel(array[i]);
+    }
+    return cl;
+  }
+  /**
+   * Construct a default <code>ContourLevels</code> object from a
+   * <code>Range2D</code>.
+   */
+  static public ContourLevels getDefault(Range2D range) {
+    ContourLevels cl = new ContourLevels();
+    double val = range.start;
+    while(val <= range.end) {
+      cl.addLevel(val);
+      val = val + range.delta;
+    }
+    return cl;
+  }
+  /**
+   * Create a deep copy.
+   */
+  public ContourLevels copy() {
+    ContourLevels newcls;
+    try {
+      newcls = (ContourLevels)clone();
+      //      newcls.defaultAttr_ =
+      //	(DefaultContourLineAttribute)this.defaultAttr_.copy();
+      newcls.levels_ = (Vector)this.levels_.clone();
+      newcls.lineAttrMap_ = (Hashtable)this.lineAttrMap_.clone();
+    } catch (CloneNotSupportedException e) {
+      newcls = null;
+    }
+    return newcls;
+  }
+  /**
+   * Get the contour level elements.
+   */
+  public Enumeration levelElements() {
+    if(!sorted_) sort();
+    return levels_.elements();
+  }
+  /**
+   * Set a the <code>ContourLineAttribute</code> for a value.
+   */
+  public void setContourLineAttribute(double val, ContourLineAttribute l)
+    throws ContourLevelNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Set a the <code>ContourLineAttribute</code> for an index.
+   */
+  public void setContourLineAttribute(int indx, ContourLineAttribute l)
+    throws ContourLevelNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Get the <code>ContourLineAttribute</code> for a value.
+   */
+  public ContourLineAttribute getContourLineAttribute(double val)
+    throws ContourLevelNotFoundException  {
+    ContourLineAttribute attr =
+      (ContourLineAttribute)lineAttrMap_.get(new Double(val));
+    if(attr == null) {
+      throw new ContourLevelNotFoundException();
+    }
+    return attr;
+  }
+  /**
+   * Get the <code>ContourLineAttribute</code> for an index.
+   */
+  public ContourLineAttribute getContourLineAttribute(int indx)
+    throws ContourLevelNotFoundException  {
+    if(!sorted_) sort();
+    return getContourLineAttribute(getLevel(indx));
+  }
+  /**
+   * Get the <code>DefaultContourLineAtrribute</code>
+   */
+  public DefaultContourLineAttribute getDefaultContourLineAttribute() {
+    return defaultAttr_;
+  }
+  /**
+   * Get the <code>DefaultContourLineAttribute</code> for index.
+   */
+  public DefaultContourLineAttribute getDefaultContourLineAttribute(int indx)
+    throws ContourLevelNotFoundException {
+    if(!sorted_) sort();
+    return
+      defaultAttr_.setContourLineAttribute(getContourLineAttribute(getLevel(indx)));
+  }
+  /**
+   * Get the <code>DefaultContourLineAttribute</code> for value.
+   */
+  public DefaultContourLineAttribute getDefaultContourLineAttribute(double val)
+    throws ContourLevelNotFoundException {
+    if(!sorted_) sort();
+    return
+      defaultAttr_.setContourLineAttribute(getContourLineAttribute(val));
+  }
+  /**
+   * Set the <code>DefaultContourLineAttribute</code>
+   */
+  public void setDefaultContourLineAttribute(DefaultContourLineAttribute attr) {
+    defaultAttr_ = attr;
+  }
+  /**
+   * Add a contour level with default <code>ContourLineAttribute</code>.
+   */
+  public void addLevel(double val) {
+    ContourLineAttribute attr = null;
+    if(val < 0.0) {
+      attr = (ContourLineAttribute)dashed_.copy();
+    } else if (val > 0.0) {
+      attr = (ContourLineAttribute)solid_.copy();
+    } else {
+      attr = (ContourLineAttribute)heavy_.copy();
+     }
+    attr.setStyleOverridden(true);
+    addLevel(val, attr);
+  }
+  /**
+   * Add a contour level with a specified
+   * <code>ContourLineAttribute</code>.
+   */
+  public void addLevel(double val, ContourLineAttribute l) {
+    Double value = new Double(val);
+    levels_.addElement(value);
+    lineAttrMap_.put(value, l);
+    sorted_ = false;
+  }
+  /**
+   * Get the value of level by index.
+   */
+  public double getLevel(int indx)
+    throws ContourLevelNotFoundException  {
+    if(indx < 0 || indx >= levels_.size())
+      throw new ContourLevelNotFoundException();
+    if(!sorted_) sort();
+    Double value = (Double)levels_.elementAt(indx);
+    return value.doubleValue();
+  }
+  /**
+   * Remove a level by value.
+   */
+  public void removeLevel(double val)
+    throws ContourLevelNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Remove a level by index.
+   */
+  public void removeLevel(int indx)
+    throws ContourLevelNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Get the index of a level by value
+   */
+  public int getIndex(Double dval) {
+    if(!sorted_) sort();
+    return levels_.indexOf(dval);
+  }
+  /**
+   * Get the index of a level by value
+   */
+  public int getIndex(double val) {
+    if(!sorted_) sort();
+    return getIndex(new Double(val));
+  }
+  /**
+   * Get the maximum level index.
+   */
+  public int getMaximumIndex() {
+    return levels_.size() - 1;
+  }
+  /**
+   * Get the range of levels
+   */
+  public Range2D getRange() {
+    double min = Double.MAX_VALUE;
+    double max = Double.MIN_VALUE;
+    double value;
+    for(int i=0; i < levels_.size(); i++) {
+      value = ((Double)levels_.get(i)).doubleValue();
+      min = Math.min(min, value);
+      max = Math.max(max, value);
+    }
+    return new Range2D(min, max);
+  }
+  /**
+   * Get the number of levels.
+   */
+  public int size() {
+    return levels_.size();
+  }
+
+  private void sort() {
+    //
+    // use brain-dead bubble sort (there will be few lines)
+    //
+    int i, temp;
+    int size = levels_.size();
+    Double a, b;
+    int[] index = new int[size];
+    boolean flipped = true;
+    for(i=0; i < size; i++) {
+      index[i] = i;
+    }
+    while(flipped) {
+      flipped = false;
+      for(i=0; i < size-1; i++) {
+        a = (Double)levels_.elementAt(index[i]);
+        b = (Double)levels_.elementAt(index[i+1]);
+        if(a.doubleValue() > b.doubleValue()) {
+          //	  if(a.compareTo(b) > 0) { // jdk1.2
+          temp = index[i];
+          index[i] = index[i+1];
+          index[i+1] = temp;
+          flipped = true;
+        }
+      }
+    }
+    Vector oldValues = levels_;
+    levels_ = new Vector(size);
+    for(i=0; i < size; i++) {
+      levels_.addElement(oldValues.elementAt(index[i]));
+    }
+    sorted_ = true;
+  }
+
+  /**
+   * Add listener to changes in <code>ColorMap</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    changes_.addPropertyChangeListener(listener);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevelsAccess.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevelsAccess.java
new file mode 100755
index 0000000..13ab55b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLevelsAccess.java
@@ -0,0 +1,27 @@
+/*
+ * $Id: ContourLevelsAccess.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+/**
+ * Defines the functionality for accessing contour level information
+ * for color maps.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public interface ContourLevelsAccess {
+
+  ContourLevels getContourLevels();
+
+  void setContourLevels(ContourLevels contourLevels);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLineAttribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLineAttribute.java
new file mode 100755
index 0000000..bfaf42d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/ContourLineAttribute.java
@@ -0,0 +1,627 @@
+/*
+ * $Id: ContourLineAttribute.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import  java.awt.*;
+
+/**
+ * Sets the rendering style for a contour line.
+ * <code>Color</code>, width, and dash characteristics are
+ * <code>ContourLineAttribute</code> properties.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ * @see LineCartesianRenderer
+ * @see ContourLevels
+ */
+public class ContourLineAttribute extends LineAttribute {
+  //
+  private String labelText_;
+  private boolean labelEnabled_ = false;
+  private Color labelColor_;
+  private Font labelFont_;
+  private double labelHeightP_;
+  private String labelFormat_;
+  private boolean autoLabel_ = true;
+  //
+  private boolean labelColorOverridden_ = false;
+  private boolean labelEnabledOverridden_ = false;
+  private boolean labelHeightPOverridden_ = false;
+  private boolean labelFontOverridden_ = false;
+  private boolean labelFormatOverridden_ = false;
+  //
+  private boolean colorOverridden_ = false;
+  private boolean styleOverridden_ = false;
+  private boolean widthOverridden_ = false;
+  private boolean dashArrayOverridden_ = false;
+  private boolean dashPhaseOverridden_ = false;
+  private boolean capStyleOverridden_ = false;
+  private boolean miterStyleOverridden_ = false;
+  private boolean miterLimitOverridden_ = false;
+  /**
+   * Default constructor.
+   */
+  public ContourLineAttribute() {
+    super();
+    init();
+  }
+  /**
+   * Constructor using default Color. Default are:
+   * <pre>
+   *   labelColor = <code>Color.black</code>
+   * labelHeightP = 0.16
+   *    labelFont = null
+   *  labelFormat = ""
+   * </pre>
+   */
+  public ContourLineAttribute(int style) {
+    super(style);
+    init();
+  }
+  /**
+   * <code>ContourLineAttribute</code> constructor.
+   *
+   * @param style line style
+   * @param color line <code>Color</code>
+   * @see java.awt.Color
+   **/
+  public ContourLineAttribute(int style, Color color) {
+    super(style, color);
+    init();
+  }
+  /**
+   * <code>ContourLineAttribute</code> constructor for plot marks.
+   *
+   * @param style line sytle
+   * @param mark plot mark
+   * @param color line <code>Color</code>
+   **/
+  public ContourLineAttribute(int style, int mark, Color color) {
+    super(style, mark, color);
+    init();
+  }
+
+  private void init() {
+    labelColor_ = Color.black;
+    labelHeightP_ = 0.16;
+    labelFont_ = null;
+    labelFormat_ = "";
+  }
+
+  /**
+   * Copy the <code>ContourLineAttribute</code>.
+   *
+   * @return new <code>ContourLineAttribute</code>
+   */
+  public Object copy() {
+    ContourLineAttribute newLine;
+    try {
+      newLine = (ContourLineAttribute)clone();
+    } catch (CloneNotSupportedException e) {
+      newLine = new ContourLineAttribute();
+    }
+    return newLine;
+  }
+  /**
+   * Set the text to be used for labelling the contour line.
+   * <BR><B>Property Change:</B> <code>labelText</code>.
+   */
+  public void setLabelText(String label) {
+    if(labelText_ == null || !labelText_.equals(label)) {
+      String tempOld = labelText_;
+      labelText_ = label;
+      labelEnabled_ = !(labelText_ == null);
+      changes_.firePropertyChange("labelText",
+                                  tempOld,
+                                  labelText_);
+    }
+  }
+  /**
+   * Get the label text.
+   */
+  public String getLabelText() {
+    return labelText_;
+  }
+  /**
+   * Enable/disable the contour label.
+   * <BR><B>Property Change:</B> <code>labelEnabled</code>.
+   */
+  public void setLabelEnabled(boolean sle) {
+    if(labelEnabled_ != sle) {
+      labelEnabledOverridden_ = true;
+      Boolean tempOld = new Boolean(labelEnabled_);
+      labelEnabled_ = sle;
+      changes_.firePropertyChange("labelEnabled",
+                                  tempOld,
+                                  new Boolean(labelEnabled_));
+    }
+  }
+  /**
+   * Test if the contour label is enabled.
+   */
+  public boolean isLabelEnabled() {
+    return labelEnabled_;
+  }
+  /**
+   * Change the color of the contour label
+   * <BR><B>Property Change:</B> <code>labelColor</code>.
+   */
+  public void setLabelColor(Color color) {
+    if(!labelColor_.equals(color)) {
+      labelColorOverridden_ = true;
+      Color tempOld = labelColor_;
+      labelColor_ = color;
+      changes_.firePropertyChange("labelColor",
+                                  tempOld,
+                                  labelColor_);
+    }
+  }
+  /**
+   * Get the color of the contour label
+   */
+  public Color getLabelColor() {
+    return labelColor_;
+  }
+  /**
+   * Set the label height in physical units
+   * <BR><B>Property Change:</B> <code>labelHeightP</code>.
+   */
+  public void setLabelHeightP(double height) {
+    if(labelHeightP_ != height) {
+      labelHeightPOverridden_ = true;
+      Double tempOld = new Double(labelHeightP_);
+      labelHeightP_ = height;
+      changes_.firePropertyChange("labelHeightP",
+                                  tempOld,
+                                  new Double(labelHeightP_));
+    }
+  }
+  /**
+   * Get the label height in physical units
+   */
+  public double getLabelHeightP() {
+    return labelHeightP_;
+  }
+  /**
+   * Set the contour label font.
+   * <BR><B>Property Change:</B> <code>labelFont</code>.
+   */
+  public void setLabelFont(Font font) {
+    if(labelFont_ == null || !labelFont_.equals(font)) {
+      labelFontOverridden_ = true;
+      Font tempOld = labelFont_;
+      labelFont_ = font;
+      changes_.firePropertyChange("labelFont",
+                                  tempOld,
+                                  labelFont_);
+    }
+  }
+  /**
+   * Get the contour label font
+   */
+  public Font getLabelFont() {
+    return labelFont_;
+  }
+  /**
+   * Set the format for the contour label.  The format is used with
+   * <code>Format</code>.
+   * <BR><B>Property Change:</B> <code>labelFormat</code>.
+   * @see Format
+   */
+  public void setLabelFormat(String format) {
+    if(!labelFormat_.equals(format)) {
+      labelFormatOverridden_ = true;
+      String tempOld = labelFormat_;
+      labelFormat_ = format;
+      changes_.firePropertyChange("labelFormat",
+                                  tempOld,
+                                  labelFormat_);
+    }
+  }
+  /**
+   * Get the contour label format
+   */
+  public String getLabelFormat() {
+    return labelFormat_;
+  }
+  /**
+   * Create contour label from value and format.
+   * <BR><B>Property Change:</B> <code>autoLabel</code>.
+   */
+  public void setAutoLabel(boolean auto) {
+    if(autoLabel_ != auto) {
+      Boolean tempOld = new Boolean(autoLabel_);
+      autoLabel_ = auto;
+      changes_.firePropertyChange("autoLabel",
+                                  tempOld,
+                                  new Boolean(autoLabel_));
+    }
+  }
+  /**
+   * Is auto labelling on?
+   */
+  public boolean isAutoLabel() {
+    return autoLabel_;
+  }
+  /**
+   * Test if labelEnabled is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isLabelEnabledOverridden() {
+    return labelEnabledOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * labelEnabled.
+   * <BR><B>Property Change:</B> <code>labelEnabledOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setLabelEnabledOverridden(boolean override) {
+    if(labelEnabledOverridden_ != override) {
+      Boolean tempOld = new Boolean(labelEnabledOverridden_);
+      labelEnabledOverridden_ = override;
+      changes_.firePropertyChange("labelEnabledOverridden",
+                                  tempOld,
+                                  new Boolean(labelEnabledOverridden_));
+    }
+  }
+  /**
+   * Test if labelColor is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isLabelColorOverridden() {
+    return labelColorOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * labelColor.
+   * <BR><B>Property Change:</B> <code>labelColorOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setLabelColorOverridden(boolean override) {
+    if(labelColorOverridden_ != override) {
+      Boolean tempOld = new Boolean(labelColorOverridden_);
+      labelColorOverridden_ = override;
+      changes_.firePropertyChange("labelColorOverridden",
+                                  tempOld,
+                                  new Boolean(labelColorOverridden_));
+    }
+  }
+  /**
+   * Test if labelHeightP is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isLabelHeightPOverridden() {
+    return labelHeightPOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * labelHeightP.
+   * <BR><B>Property Change:</B> <code>labelHeightPOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setLabelHeightPOverridden(boolean override) {
+    if(labelHeightPOverridden_ != override) {
+      Boolean tempOld = new Boolean(labelHeightPOverridden_);
+      labelHeightPOverridden_ = override;
+      changes_.firePropertyChange("labelHeightPOverridden",
+                                  tempOld,
+                                  new Boolean(labelHeightPOverridden_));
+    }
+  }
+  /**
+   * Test if labelFont is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isLabelFontOverridden() {
+    return labelFontOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * labelFont.
+   * <BR><B>Property Change:</B> <code>labelFontOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setLabelFontOverridden(boolean override) {
+    if(labelFontOverridden_ != override) {
+      Boolean tempOld = new Boolean(labelFontOverridden_);
+      labelFontOverridden_ = override;
+      changes_.firePropertyChange("labelFontOverridden",
+                                  tempOld,
+                                  new Boolean(labelFontOverridden_));
+    }
+  }
+  /**
+   * Test if labelFormat is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isLabelFormatOverridden() {
+    return labelFormatOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * labelFormat.
+   * <BR><B>Property Change:</B> <code>labelFormatOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setLabelFormatOverridden(boolean override) {
+    if(labelFormatOverridden_ != override) {
+      Boolean tempOld = new Boolean(labelFormatOverridden_);
+      labelFormatOverridden_ = override;
+      changes_.firePropertyChange("labelFormatOverridden",
+                                  tempOld,
+                                  new Boolean(labelFormatOverridden_));
+    }
+  }
+  public void setDashArray(float[] dashes) {
+    dashArrayOverridden_ = true;
+    super.setDashArray(dashes);
+  }
+  /**
+   * Test if dashArray is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isDashArrayOverridden() {
+    return dashArrayOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * dashArray.
+   * <BR><B>Property Change:</B> <code>dashArrayOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setDashArrayOverridden(boolean override) {
+    if(dashArrayOverridden_ != override) {
+      Boolean tempOld = new Boolean(dashArrayOverridden_);
+      dashArrayOverridden_ = override;
+      changes_.firePropertyChange("dashArrayOverridden",
+                                  tempOld,
+                                  new Boolean(dashArrayOverridden_));
+    }
+  }
+  public void setDashPhase(float phase) {
+    dashPhaseOverridden_ = true;
+    super.setDashPhase(phase);
+  }
+  /**
+   * Test if dashPhase is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isDashPhaseOverridden() {
+    return dashPhaseOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * dashPhase.
+   * <BR><B>Property Change:</B> <code>dashPhaseOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setDashPhaseOverridden(boolean override) {
+    if(dashPhaseOverridden_ != override) {
+      Boolean tempOld = new Boolean(dashPhaseOverridden_);
+      dashPhaseOverridden_ = override;
+      changes_.firePropertyChange("dashPhaseOverridden",
+                                  tempOld,
+                                  new Boolean(dashPhaseOverridden_));
+    }
+  }
+  public void setStyle(int st) {
+    if(st == MARK || st == MARK_LINE) return;
+    styleOverridden_ = true;
+    super.setStyle(st);
+  }
+  /**
+   * Test if style is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isStyleOverridden() {
+    return styleOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * style.
+   * <BR><B>Property Change:</B> <code>styleOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setStyleOverridden(boolean override) {
+    if(styleOverridden_ != override) {
+      Boolean tempOld = new Boolean(styleOverridden_);
+      styleOverridden_ = override;
+      changes_.firePropertyChange("styleOverridden",
+                                  tempOld,
+                                  new Boolean(styleOverridden_));
+    }
+  }
+  public void setColor(Color c) {
+    colorOverridden_ = true;
+    super.setColor(c);
+  }
+  /**
+   * Test if color is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isColorOverridden() {
+    return colorOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * color.
+   * <BR><B>Property Change:</B> <code>colorOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setColorOverridden(boolean override) {
+    if(colorOverridden_ != override) {
+      Boolean tempOld = new Boolean(colorOverridden_);
+      colorOverridden_ = override;
+      changes_.firePropertyChange("colorOverridden",
+                                  tempOld,
+                                  new Boolean(colorOverridden_));
+    }
+  }
+  public void setWidth(float t) {
+    widthOverridden_ = true;
+    super.setWidth(t);
+  }
+  /**
+   * Test if width is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isWidthOverridden() {
+    return widthOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * width.
+   * <BR><B>Property Change:</B> <code>widthOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setWidthOverridden(boolean override) {
+    if(widthOverridden_ != override) {
+      Boolean tempOld = new Boolean(widthOverridden_);
+      widthOverridden_ = override;
+      changes_.firePropertyChange("widthOverridden",
+                                  tempOld,
+                                  new Boolean(widthOverridden_));
+    }
+  }
+  public void setCapStyle(int style) {
+    capStyleOverridden_ = true;
+    super.setCapStyle(style);
+  }
+  /**
+   * Test if cap style is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isCapStyleOverridden() {
+    return capStyleOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * cap style.
+   * <BR><B>Property Change:</B> <code>capStyleOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setCapStyleOverridden(boolean override) {
+    if(capStyleOverridden_ != override) {
+      Boolean tempOld = new Boolean(capStyleOverridden_);
+      capStyleOverridden_ = override;
+      changes_.firePropertyChange("capStyleOverridden",
+                                  tempOld,
+                                  new Boolean(capStyleOverridden_));
+    }
+  }
+  public void setMiterStyle(int style) {
+    miterStyleOverridden_ = true;
+    super.setMiterStyle(style);
+  }
+  /**
+   * Test if miter style is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isMiterStyleOverridden() {
+    return miterStyleOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * miter style.
+   * <BR><B>Property Change:</B> <code>miterStyleOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setMiterStyleOverridden(boolean override) {
+    if(miterStyleOverridden_ != override) {
+      Boolean tempOld = new Boolean(miterStyleOverridden_);
+      miterStyleOverridden_ = override;
+      changes_.firePropertyChange("miterStyleOverridden",
+                                  tempOld,
+                                  new Boolean(miterStyleOverridden_));
+    }
+  }
+  public void setMiterLimit(float t) {
+    miterLimitOverridden_ = true;
+    super.setMiterLimit(t);
+  }
+  /**
+   * Test if miter limit is overridden by
+   * <code>DefaultContourLineAttribute</code>.
+   */
+  public boolean isMiterLimitOverridden() {
+    return miterLimitOverridden_;
+  }
+  /**
+   * Enable/disable having <code>DefaultContourLineAttribute</code>
+   * override <code>ContourLineAttribute</code> behavior of
+   * miter limit.
+   * <BR><B>Property Change:</B> <code>miterLimitOverridden</code>.
+   *
+   * @see DefaultContourLineAttribute
+   */
+  public void setMiterLimitOverridden(boolean override) {
+    if(miterLimitOverridden_ != override) {
+      Boolean tempOld = new Boolean(miterLimitOverridden_);
+      miterLimitOverridden_ = override;
+      changes_.firePropertyChange("miterLimitOverridden",
+                                  tempOld,
+                                  new Boolean(miterLimitOverridden_));
+    }
+  }
+  public String toString() {
+    Color col = getColor();
+    int style = getStyle();
+    String sstyle;
+    if(style == SOLID) {
+      sstyle = "SOLID";
+    } else if(style == DASHED) {
+      sstyle = "DASHED";
+    } else if(style == HEAVY) {
+      sstyle = "HEAVY";
+    } else if(style == HIGHLIGHT) {
+      sstyle = "HIGHLIGHT";
+    } else if(style == MARK) {
+      sstyle = "MARK - unsupported";
+    } else if(style == MARK_LINE) {
+      sstyle = "MARK_LINE - unsupported";
+    } else if(style == STROKE) {
+      sstyle = "STROKE";
+    } else {
+      sstyle = "";
+    }
+    String scol = "[" + col.getRed() + "," + col.getGreen() +
+      "," + col.getBlue() + "]";
+    return sstyle + ", " + scol + ", labelEnabled=" + labelEnabled_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataKey.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataKey.java
new file mode 100755
index 0000000..ab66893
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataKey.java
@@ -0,0 +1,37 @@
+/*
+ * $Id: DataKey.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+
+/**
+ * Inticates the class is a key or legend.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 3.0
+ * @stereotype container
+ **/
+public interface DataKey extends LayerChild {
+  public void setLocationP(Point2D.Double locP);
+  public void addGraph(CartesianRenderer rend, SGLabel label)
+      throws IllegalArgumentException;
+  public void setAlign(int vert, int horz);
+  public void setHAlign(int horz);
+  public void setVAlign(int vert);
+  public void setBorderStyle(int style);
+  public void setBoundsP(Rectangle2D.Double r);
+  public void setColumns(int col);
+  public void setLineLengthP(double len);
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotAssignedException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotAssignedException.java
new file mode 100755
index 0000000..53d034c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotAssignedException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: DataNotAssignedException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Graph could not be produced because no data has been assigned.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class DataNotAssignedException extends SGException {
+  public DataNotAssignedException() {
+    super();
+}
+  public DataNotAssignedException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotFoundException.java
new file mode 100755
index 0000000..f32fce2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotFoundException.java
@@ -0,0 +1,29 @@
+/*
+ * $Id: DataNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Graph could not be produced because no data has been assigned.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public class DataNotFoundException extends SGException {
+  public DataNotFoundException() {
+    super();
+}
+  public DataNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotSameShapeException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotSameShapeException.java
new file mode 100755
index 0000000..7b1169b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DataNotSameShapeException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: DataNotSameShapeException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Operation could not be completed since grids are not the same shape.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class DataNotSameShapeException extends SGException {
+  public DataNotSameShapeException() {
+    super();
+}
+  public DataNotSameShapeException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DayMonthAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DayMonthAxis.java
new file mode 100755
index 0000000..febda2a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DayMonthAxis.java
@@ -0,0 +1,115 @@
+/*
+ * $Id: DayMonthAxis.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.util.TimeRange;
+
+/**
+ * Draws time axes using the day/month style.
+ *
+ * <pre>
+ *        |...........|...........|...........|...........|
+ *             3           4           5           6
+ *                             jun 93
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @see Axis
+ * @see TimeAxis
+ */
+class DayMonthAxis implements TimeAxisStyle {
+  static final int MONTH_TEST__ = 3;
+  static final String defaultMinorLabelFormat__ = "dd";
+  static final String defaultMajorLabelFormat__ = "yyyy-MM";
+  static final int defaultNumSmallTics__ = 0;
+  int defaultMinorLabelInterval_ = 2;
+  int defaultMajorLabelInterval_ = 1;
+  static final double incrementValue__ = 1.0;
+  static final int incrementUnits__ = GeoDate.DAYS;
+  /**
+   * DayMonthAxis constructor.
+   */
+  public DayMonthAxis() {
+  }
+  public double computeLocation(double prev,double now) {
+    return (prev + now)*0.5;
+  }
+  public void computeDefaults(GeoDate delta) {
+    long days = delta.getTime()/GeoDate.MSECS_IN_DAY;
+    if(days > 30) {
+      defaultMinorLabelInterval_ = 5;
+    } else if(days > 10) {
+      defaultMinorLabelInterval_ = 2;
+    } else {
+      defaultMinorLabelInterval_ = 1;
+    }
+  }
+  public int getMinorValue(GeoDate time) {
+    return time.getGMTDay();
+  }
+  public int getMajorValue(GeoDate time) {
+    return time.getGMTMonth();
+  }
+  public boolean isRoomForMajorLabel(GeoDate delta) {
+    return delta.getTime()/GeoDate.MSECS_IN_DAY > MONTH_TEST__;
+  }
+  public boolean isStartOfMinor(GeoDate time) {
+    return time.getGMTDay() == 1;
+  }
+  public String getDefaultMinorLabelFormat() {
+    return defaultMinorLabelFormat__;
+  }
+  public String getDefaultMajorLabelFormat() {
+    return defaultMajorLabelFormat__;
+  }
+  public int getDefaultNumSmallTics() {
+    return defaultNumSmallTics__;
+  }
+  public int getDefaultMinorLabelInterval() {
+    return defaultMinorLabelInterval_;
+  }
+  public int getDefaultMajorLabelInterval() {
+    return defaultMajorLabelInterval_;
+  }
+  public GeoDate getStartTime(TimeRange tRange) {
+    boolean time_increasing;
+    GeoDate time = null;
+    time_increasing = tRange.end.after(tRange.start);
+    try {
+      if(time_increasing) {
+        time = new GeoDate(tRange.start.getGMTMonth(),
+         tRange.start.getGMTDay(),
+                           tRange.start.getGMTYear(), 0, 0, 0, 0);
+        if(!time.equals(tRange.start)) time.increment(1.0, GeoDate.DAYS);
+      } else {
+        time = new GeoDate(tRange.end.getGMTMonth(),
+         tRange.end.getGMTDay(),
+                           tRange.end.getGMTYear(), 0, 0, 0, 0);
+        if(!time.equals(tRange.end)) time.increment(1.0, GeoDate.DAYS);
+      }
+    } catch (IllegalTimeValue e) {}
+    return time;
+  }
+  public double getIncrementValue() {
+    return incrementValue__;
+  }
+  public int getIncrementUnits() {
+    return incrementUnits__;
+  }
+  public String toString() {
+    return "DayMonthAxis";
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DefaultContourLineAttribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DefaultContourLineAttribute.java
new file mode 100755
index 0000000..a0506f9
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/DefaultContourLineAttribute.java
@@ -0,0 +1,390 @@
+/*
+ * $Id: DefaultContourLineAttribute.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import  java.awt.*;
+import java.lang.CloneNotSupportedException;
+
+/**
+ * Sets the default rendering style for contour line data.
+ * <code>Color</code>, width, and dash characteristics are
+ * <code>DefaultContourLineAttribute</code> properties. For individual
+ * contour lines, the characteristics can be overridden by
+ * <code>ContourLineAttribute</code> when used with
+ * <code>ContourLevels</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ * @see GridCartesianRenderer
+ * @see ContourLevels
+ * @see ContourLineAttribute
+ */
+public class DefaultContourLineAttribute extends LineAttribute {
+  /**
+   * @label attr
+   */
+  private ContourLineAttribute attr_;
+  private boolean labelEnabled_ = true;
+  private Color labelColor_;
+  private Font labelFont_;
+  private double labelHeightP_;
+  private int sigDigits_;
+  private String labelFormat_;
+  /**
+   * Default constructor. Defaults are:
+   * <pre>
+   *   labelColor = <code>Color.black</code>
+   * labelHeightP = 0.16
+   *    labelFont = null
+   *  labelFormat = ""
+   *    sigDigits = 2
+   * </pre>
+   */
+  public DefaultContourLineAttribute() {
+    super(SOLID, Color.black);
+    labelColor_ = Color.black;
+    labelHeightP_ = 0.16;
+    labelFont_ = null;
+    sigDigits_ = 2;
+    labelFormat_ = "";
+  }
+  /**
+   * Set the <code>ContourLineAttribute</code> that will potentially
+   * override attributes.
+   */
+  public DefaultContourLineAttribute setContourLineAttribute(ContourLineAttribute attr) {
+    attr_ = attr;
+    return this;
+  }
+  /**
+   * Get the associated <code>ContourLineAttribute</code>
+   */
+  public ContourLineAttribute getContourLineAttribute() {
+    return attr_;
+  }
+  /**
+   * Set label text for associated <code>ContourLineAttribute</code>.
+   */
+  public void setLabelText(String label) {
+    if(attr_ != null) attr_.setLabelText(label);
+  }
+  /**
+   * Return label text from associated
+   * <code>ContourLineAttribute</code>, if none return empty string.
+   */
+  public String getLabelText() {
+    if(attr_ != null) {
+      return attr_.getLabelText();
+    } else {
+      return "";
+    }
+  }
+  /**
+   * Enable/disable the contour label.
+   * <BR><B>Property Change:</B> <code>labelEnabled</code>.
+   */
+  public void setLabelEnabled(boolean sle) {
+    if(labelEnabled_ != sle) {
+      Boolean tempOld = new Boolean(labelEnabled_);
+      labelEnabled_ = sle;
+      changes_.firePropertyChange("labelEnabled",
+                                  tempOld,
+                                  new Boolean(labelEnabled_));
+    }
+  }
+  /**
+   * Test if the contour label is enabled.  Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * labelEnabledOverrideen set to <code>false</code>.
+   */
+  public boolean isLabelEnabled() {
+    if(attr_ != null && attr_.isLabelEnabledOverridden()) {
+      return attr_.isLabelEnabled();
+    } else {
+      return labelEnabled_;
+    }
+  }
+  /**
+   * Set the default contour label color
+   * <BR><B>Property Change:</B> <code>labelColor</code>.
+   */
+  public void setLabelColor(Color color) {
+    if(!labelColor_.equals(color)) {
+      Color tempOld = labelColor_;
+      labelColor_ = color;
+      changes_.firePropertyChange("labelColor",
+                                  tempOld,
+                                  labelColor_);
+    }
+  }
+  /**
+   * Get the contour label color. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * labelColorOverrideen set to <code>false</code>.
+   */
+  public Color getLabelColor() {
+    if(attr_ != null && attr_.isLabelColorOverridden()) {
+      return attr_.getLabelColor();
+    } else {
+      return labelColor_;
+    }
+  }
+  /**
+   * Set the default contour label height.
+   * <BR><B>Property Change:</B> <code>labelHeightP</code>.
+   */
+  public void setLabelHeightP(double height) {
+    if(labelHeightP_ != height) {
+      Double tempOld = new Double(labelHeightP_);
+      labelHeightP_ = height;
+      changes_.firePropertyChange("labelHeightP",
+                                  tempOld,
+                                  new Double(labelHeightP_));
+    }
+  }
+  /**
+   * Get the contour label height.  Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * labelHeightPOverrideen set to <code>false</code>.
+   */
+  public double getLabelHeightP() {
+    if(attr_ != null && attr_.isLabelHeightPOverridden()) {
+      return attr_.getLabelHeightP();
+    } else {
+      return labelHeightP_;
+    }
+  }
+  /**
+   * Set the default contour label font.
+   * <BR><B>Property Change:</B> <code>labelFont</code>.
+   */
+  public void setLabelFont(Font font) {
+    if(labelFont_ == null || !labelFont_.equals(font)) {
+      Font tempOld = labelFont_;
+      labelFont_ = font;
+      changes_.firePropertyChange("labelFont",
+                                  tempOld,
+                                  labelFont_);
+    }
+  }
+  /**
+   * Get the contour label font. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * labelFontOverrideen set to <code>false</code>.
+   */
+  public Font getLabelFont() {
+    if(attr_ != null && attr_.isLabelFontOverridden()) {
+      return attr_.getLabelFont();
+    } else {
+      return labelFont_;
+    }
+  }
+  /**
+   * Set the number of significant digits for auto labelling.
+   * <BR><B>Property Change:</B> <code>significantDigits</code>.
+   */
+  public void setSignificantDigits(int sig) {
+    if(sigDigits_ != sig) {
+      Integer tempOld = new Integer(sigDigits_);
+      sigDigits_ = sig;
+      changes_.firePropertyChange("significantDigits",
+                                  tempOld,
+                                  new Integer(sigDigits_));
+    }
+  }
+  /**
+   * Get the number of significant digits for auto labelling.
+   */
+  public int getSignificantDigits() {
+    return sigDigits_;
+  }
+  /**
+   * Set the default contour label format.
+   * <BR><B>Property Change:</B> <code>labelFormat</code>.
+   */
+  public void setLabelFormat(String format) {
+    if(!labelFormat_.equals(format)) {
+      String tempOld = labelFormat_;
+      labelFormat_ = format;
+      changes_.firePropertyChange("labelFormat",
+                                  tempOld,
+                                  labelFormat_);
+    }
+  }
+  /**
+   * Get the contour label format. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * labelFormatOverrideen set to <code>false</code>.
+   */
+  public String getLabelFormat() {
+    if(attr_ != null && attr_.isLabelFormatOverridden()) {
+      return attr_.getLabelFormat();
+    } else {
+      return labelFormat_;
+    }
+  }
+  /**
+   * Test if auto label is enabled. Use associated
+   * <code>ContourLineAttribute</code> if it exists  otherwise always
+   * returns <code>true</code>.
+   */
+  public boolean isAutoLabel() {
+    if(attr_ != null) {
+      return attr_.isAutoLabel();
+    } else {
+      return true;
+    }
+  }
+  /**
+   * Get dash array. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * dashArrayOverrideen set to <code>false</code>.
+   */
+  public float[] getDashArray() {
+    if(attr_ != null && attr_.isDashArrayOverridden()) {
+      return attr_.getDashArray();
+    } else {
+      return super.getDashArray();
+    }
+  }
+  /**
+   * Get the dash phase. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * dashPhaseOverrideen set to <code>false</code>.
+   */
+  public float getDashPhase() {
+    if(attr_ != null && attr_.isDashPhaseOverridden()) {
+      return attr_.getDashPhase();
+    } else {
+      return super.getDashPhase();
+    }
+  }
+  /**
+   * Override the default setStyle.  Legal styles <em>do not</em>
+   * include MARK or MARK_LINE.
+   */
+  public void setStyle(int st) {
+    if(st == MARK || st == MARK_LINE) return;
+    super.setStyle(st);
+  }
+  /**
+   * Get the contour line style. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * styleOverrideen set to <code>false</code>.
+   */
+  public int getStyle() {
+    if(attr_ != null && attr_.isStyleOverridden()) {
+      return attr_.getStyle();
+    } else {
+      return super.getStyle();
+    }
+  }
+  /**
+   * Get the contour line color. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * colorOverrideen set to <code>false</code>.
+   */
+  public Color getColor() {
+    if(attr_ != null && attr_.isColorOverridden()) {
+      return attr_.getColor();
+    } else {
+      return super.getColor();
+    }
+  }
+  /**
+   * Get the contour line width. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * widthOverrideen set to <code>false</code>.
+   */
+  public float getWidth() {
+    if(attr_ != null && attr_.isWidthOverridden()) {
+      return attr_.getWidth();
+    } else {
+      return super.getWidth();
+    }
+  }
+  /**
+   * Get the contour line cap style. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * capStyleOverrideen set to <code>false</code>.
+   */
+  public int getCapStyle() {
+    if(attr_ != null && attr_.isCapStyleOverridden()) {
+      return attr_.getCapStyle();
+    } else {
+      return super.getCapStyle();
+    }
+  }
+  /**
+   * Get the contour line miter style. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * miterStyleOverrideen set to <code>false</code>.
+   */
+  public int getMiterStyle() {
+    if(attr_ != null && attr_.isMiterStyleOverridden()) {
+      return attr_.getMiterStyle();
+    } else {
+      return super.getMiterStyle();
+    }
+  }
+  /**
+   * Get the contour line miter limit. Use associated
+   * <code>ContourLineAttribute</code> if it exists and has
+   * miterLimitOverrideen set to <code>false</code>.
+   */
+  public float getMiterLimit() {
+    if(attr_ != null && attr_.isMiterLimitOverridden()) {
+      return attr_.getMiterLimit();
+    } else {
+      return super.getMiterLimit();
+    }
+  }
+
+  public String toString() {
+    Color col = getColor();
+    int style = getStyle();
+    String sstyle;
+    if(style == SOLID) {
+      sstyle = "SOLID";
+    } else if(style == DASHED) {
+      sstyle = "DASHED";
+    } else if(style == HEAVY) {
+      sstyle = "HEAVY";
+    } else if(style == HIGHLIGHT) {
+      sstyle = "HIGHLIGHT";
+    } else if(style == MARK) {
+      sstyle = "MARK - unsupported";
+    } else if(style == MARK_LINE) {
+      sstyle = "MARK_LINE - unsupported";
+    } else if(style == STROKE) {
+      sstyle = "STROKE";
+    } else {
+      sstyle = "";
+    }
+    String scol = "[" + col.getRed() + "," + col.getGreen() +
+      "," + col.getBlue() + "]";
+    return sstyle + ", " + scol + ", labelEnabled=" + labelEnabled_;
+  }
+
+  public Object copy() {
+    DefaultContourLineAttribute newAttr;
+    try {
+      newAttr = (DefaultContourLineAttribute)clone();
+    } catch (CloneNotSupportedException e) {
+      newAttr = new DefaultContourLineAttribute();
+    }
+    return newAttr;
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Format.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Format.java
new file mode 100755
index 0000000..7a6791a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Format.java
@@ -0,0 +1,534 @@
+/*
+ * $Id: Format.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * Gary Cornell and Cay S. Horstmann, Core Java (Book/CD-ROM)
+ * Published By SunSoft Press/Prentice-Hall
+ * Copyright (C) 1996 Sun Microsystems Inc.
+ * All Rights Reserved. ISBN 0-13-596891-7
+ *
+ * Permission to use, copy, modify, and distribute this 
+ * software and its documentation for NON-COMMERCIAL purposes
+ * and without fee is hereby granted provided that this 
+ * copyright notice appears in all copies. 
+ * 
+ * THE AUTHORS AND PUBLISHER MAKE NO REPRESENTATIONS OR 
+ * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER 
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHORS
+ * AND PUBLISHER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED 
+ * BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING 
+ * THIS SOFTWARE OR ITS DERIVATIVES.
+ */
+
+package  gov.noaa.pmel.sgt;
+import  java.io.*;
+/**
+ * A class for formatting numbers that follows printf conventions.
+ * Also implements C-like atoi and atof functions
+ *
+ * @version 1.01 15 Feb 1996 
+ * @since 1.0
+ * @author Cay Horstmann
+ */
+public class Format {
+  private int width;
+  private int precision;
+  private String pre;
+  private String post;
+  private boolean leading_zeroes;
+  private boolean show_plus;
+  private boolean alternate;
+  private boolean show_space;
+  private boolean left_align;
+  private char fmt;
+  private static long parseLong(String s,int base) {
+    int i = 0;  int sign = 1;
+    long r = 0;
+      
+    while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++;
+    if (i < s.length() && s.charAt(i) == '-') { sign = -1; i++; }
+    else if (i < s.length() && s.charAt(i) == '+') { i++; }
+    while (i < s.length())
+      {  char ch = s.charAt(i);
+      if ('0' <= ch && ch < '0' + base)
+	r = r * base + ch - '0';
+      else if ('A' <= ch && ch < 'A' + base - 10)
+	r = r * base + ch - 'A' + 10 ;
+      else if ('a' <= ch && ch < 'a' + base - 10)
+	r = r * base + ch - 'a' + 10 ;
+      else 
+	return r * sign;
+      i++;
+      }
+    return r * sign;
+  }
+  /**
+   * a test stub for the format class
+   */
+   /*public static void main(String[] a)
+       {  double x = 1.23456789012;
+       double xx= 1.0000006;
+       double y = 123;
+       double z = 1.2345e30;
+       double w = 1.02;
+       double u = 1.234e-5;
+       int d = 0xCAFE;
+       Format.print(System.out, "xx = |%.6f|\n", xx);
+       Format.print(System.out, "x = |%f|\n", x);
+       Format.print(System.out, "u = |%20f|\n", u);
+       Format.print(System.out, "x = |% .5f|\n", x);
+       Format.print(System.out, "w = |%20.5f|\n", w);
+       Format.print(System.out, "x = |%020.5f|\n", x);
+       Format.print(System.out, "x = |%+20.5f|\n", x);
+       Format.print(System.out, "x = |%+020.5f|\n", x);
+       Format.print(System.out, "x = |% 020.5f|\n", x);
+       Format.print(System.out, "y = |%#+20.5f|\n", y);
+       Format.print(System.out, "y = |%-+20.5f|\n", y);
+       Format.print(System.out, "z = |%20.5f|\n", z);
+      
+       Format.print(System.out, "x = |%e|\n", x);
+       Format.print(System.out, "u = |%20e|\n", u);
+       Format.print(System.out, "x = |% .5e|\n", x);
+       Format.print(System.out, "w = |%20.5e|\n", w);
+       Format.print(System.out, "x = |%020.5e|\n", x);
+       Format.print(System.out, "x = |%+20.5e|\n", x);
+       Format.print(System.out, "x = |%+020.5e|\n", x);
+       Format.print(System.out, "x = |% 020.5e|\n", x);
+       Format.print(System.out, "y = |%#+20.5e|\n", y);
+       Format.print(System.out, "y = |%-+20.5e|\n", y);
+      
+       Format.print(System.out, "x = |%g|\n", x);
+       Format.print(System.out, "z = |%g|\n", z);
+       Format.print(System.out, "w = |%g|\n", w);
+       Format.print(System.out, "u = |%g|\n", u);
+       Format.print(System.out, "y = |%.2g|\n", y);
+       Format.print(System.out, "y = |%#.2g|\n", y);
+ 
+       Format.print(System.out, "d = |%d|\n", d);
+       Format.print(System.out, "d = |%20d|\n", d);            
+       Format.print(System.out, "d = |%020d|\n", d);    
+       Format.print(System.out, "d = |%+20d|\n", d);
+       Format.print(System.out, "d = |% 020d|\n", d);
+       Format.print(System.out, "d = |%-20d|\n", d);
+       Format.print(System.out, "d = |%20.8d|\n", d);
+       Format.print(System.out, "d = |%x|\n", d);            
+       Format.print(System.out, "d = |%20X|\n", d);    
+       Format.print(System.out, "d = |%#20x|\n", d);
+       Format.print(System.out, "d = |%020X|\n", d);
+       Format.print(System.out, "d = |%20.8x|\n", d);
+       Format.print(System.out, "d = |%o|\n", d);            
+       Format.print(System.out, "d = |%020o|\n", d);    
+       Format.print(System.out, "d = |%#20o|\n", d);
+       Format.print(System.out, "d = |%#020o|\n", d);
+       Format.print(System.out, "d = |%20.12o|\n", d);
+      
+       Format.print(System.out, "s = |%-20s|\n", "Hello");      
+       Format.print(System.out, "s = |%-20c|\n", '!');      
+       }*/
+     
+  private static String repeat(char c,int n) {
+    if (n <= 0) return "";  StringBuffer s = new StringBuffer(n);
+    for (int i = 0; i < n; i++) s.append(c);
+    return s.toString();
+  }
+  private static String convert(long x,int n,int m,String d) {
+    if (x == 0) return "0";  String r = "";
+    while (x != 0)
+      {  r = d.charAt((int)(x & m)) + r;
+      x = x >>> n;
+      }
+    return r;
+  }
+  private String pad(String r) {
+    String p = repeat(' ', width - r.length());  if (left_align) return pre + r + p + post;
+    else return pre + p + r + post;
+  }
+  private String sign(int s,String r) {
+    String p = "";  if (s < 0) p = "-"; 
+    else if (s > 0)
+      {  if (show_plus) p = "+";
+      else if (show_space) p = " ";
+      }
+    else
+      {  if (fmt == 'o' && alternate && r.length() > 0 && r.charAt(0) != '0') p = "0";
+      else if (fmt == 'x' && alternate) p = "0x";
+      else if (fmt == 'X' && alternate) p = "0X";
+      }
+    int w = 0;
+    if (leading_zeroes) 
+      w = width;
+    else if ((fmt == 'd' || fmt == 'i' || fmt == 'x' || fmt == 'X' || fmt == 'o') 
+	     && precision > 0) w = precision;
+      
+    return p + repeat('0', w - p.length() - r.length()) + r;
+  }
+  private String fixed_format(double d) {
+    String f = "";
+    if (d > Long.MAX_VALUE) return exp_format(d);
+    //here is the first change to the code (04/03/02)
+    long l=(long) (d+=0.5*Math.pow(10D,-precision));
+    //long l = (long)(precision == 0 ? d + 0.5 : d);
+    f =f  + l;
+    double fr = d - l; // fractional part
+    if (fr >= 1 || fr < 0 && precision != 0) return exp_format(d);
+    
+    return f + frac_part(fr);
+  }
+  // precondition: 0 <= fr < 1
+  private String frac_part(double fr) {
+    String z = "";
+    if (precision > 0){
+    	double factor = 1;
+      	String leading_zeroes = "";
+      	for (int i = 1; i <= precision && factor <= Double.MAX_VALUE; i++) {
+      		factor *= 10; 
+			leading_zeroes = leading_zeroes + "0"; 
+		}
+     	//here is the second change to the code (04/03/02)
+     	long l = (long) (factor * fr );
+     	//long l = (long) (factor * fr + 0.5);
+     	z = leading_zeroes + l;
+      	z = z.substring(z.length() - precision, z.length());
+    }
+
+      
+    if (precision > 0 || alternate) z = "." + z;
+    if ((fmt == 'G' || fmt == 'g') && !alternate)
+      // remove trailing zeroes and decimal point
+      {  int t = z.length() - 1;
+      while (t >= 0 && z.charAt(t) == '0') t--;
+      if (t >= 0 && z.charAt(t) == '.') t--;
+      z = z.substring(0, t + 1);
+      }
+    return z;
+  }
+  private String exp_format(double d) {
+    String f = "";  int e = 0;
+    double dd = d;
+    double factor = 1;
+    if (dd == 0) return "0";
+    while (dd > 10) { e++; factor /= 10; dd = dd / 10; }
+    while (dd < 1) { e--; factor *= 10; dd = dd * 10; }
+    if ((fmt == 'g' || fmt == 'G') && e >= -4 && e < precision) 
+      return fixed_format(d);
+      
+    d = d * factor;
+    f = f + fixed_format(d);
+      
+    if (fmt == 'e' || fmt == 'g')
+      f = f + "e";
+    else
+      f = f + "E";
+
+    String p = "000";      
+    if (e >= 0) 
+      {  f = f + "+";
+      p = p + e;
+      }
+    else
+      {  f = f + "-";
+      p = p + (-e);
+      }
+         
+    return f + p.substring(p.length() - 3, p.length());
+  }
+  /** 
+   * Formats the number following printf conventions.
+   * Main limitation: Can only handle one format parameter at a time
+   * Use multiple Format objects to format more than one number
+   * @param s the format string following printf conventions
+   * The string has a prefix, a format code and a suffix. The prefix and suffix
+   * become part of the formatted output. The format code directs the
+   * formatting of the (single) parameter to be formatted. The code has the
+   * following structure
+   * <ul>
+   * <li> a % (required)
+   * <li> a modifier (optional)
+   * <dl>
+   * <dt> + <dd> forces display of + for positive numbers
+   * <dt> 0 <dd> show leading zeroes
+   * <dt> - <dd> align left in the field
+   * <dt> space <dd> prepend a space in front of positive numbers
+   * <dt> # <dd> use "alternate" format. Add 0 or 0x for octal or hexadecimal numbers. Don't suppress trailing zeroes in general floating point format.
+   * </dl>
+   * <li> an integer denoting field width (optional)
+   * <li> a period followed by an integer denoting precision (optional)
+   * <li> a format descriptor (required)
+   * <dl>
+   * <dt>f <dd> floating point number in fixed format
+   * <dt>e, E <dd> floating point number in exponential notation (scientific format). The E format results in an uppercase E for the exponent (1.14130E+003), the e format in a lowercase e.
+   * <dt>g, G <dd> floating point number in general format (fixed format for small numbers, exponential format for large numbers). Trailing zeroes are suppressed. The G format results in an uppercase E for the exponent (if any), the g format in a lowercase e.
+   * <dt>d, i <dd> integer in decimal
+   * <dt>x <dd> integer in hexadecimal
+   * <dt>o <dd> integer in octal
+   * <dt>s <dd> string
+   * <dt>c <dd> character
+   * </dl>
+   * </ul>
+   * @exception IllegalArgumentException if bad format
+   */
+  public Format(String s) {
+    width = 0;  precision = -1;
+    pre = "";
+    post = "";
+    leading_zeroes = false;
+    show_plus = false;
+    alternate = false;
+    show_space = false;
+    left_align = false;
+    fmt = ' '; 
+      
+    int state = 0; 
+    int length = s.length();
+    int parse_state = 0; 
+    // 0 = prefix, 1 = flags, 2 = width, 3 = precision,
+    // 4 = format, 5 = end
+    int i = 0;
+      
+    while (parse_state == 0)
+      {  if (i >= length) parse_state = 5;
+      else if (s.charAt(i) == '%')
+	{  if (i < length - 1)
+	  {  if (s.charAt(i + 1) == '%')
+	    {  pre = pre + '%';
+	    i++;
+	    }
+	  else
+	    parse_state = 1;
+	  }
+	else throw new java.lang.IllegalArgumentException();
+	}
+      else
+	pre = pre + s.charAt(i);
+      i++;
+      }
+    while (parse_state == 1)
+      {  if (i >= length) parse_state = 5;
+      else if (s.charAt(i) == ' ') show_space = true;
+      else if (s.charAt(i) == '-') left_align = true; 
+      else if (s.charAt(i) == '+') show_plus = true;
+      else if (s.charAt(i) == '0') leading_zeroes = true;
+      else if (s.charAt(i) == '#') alternate = true;
+      else { parse_state = 2; i--; }
+      i++;
+      }      
+    while (parse_state == 2)
+      {  if (i >= length) parse_state = 5;
+      else if ('0' <= s.charAt(i) && s.charAt(i) <= '9')
+	{  width = width * 10 + s.charAt(i) - '0';
+	i++;
+	}
+      else if (s.charAt(i) == '.')
+	{  parse_state = 3;
+	precision = 0;
+	i++;
+	}
+      else 
+	parse_state = 4;            
+      }
+    while (parse_state == 3)
+      {  if (i >= length) parse_state = 5;
+      else if ('0' <= s.charAt(i) && s.charAt(i) <= '9')
+	{  precision = precision * 10 + s.charAt(i) - '0';
+	i++;
+	}
+      else 
+	parse_state = 4;                  
+      }
+    if (parse_state == 4) 
+      {  if (i >= length) parse_state = 5;
+      else fmt = s.charAt(i);
+      i++;
+      }
+    if (i < length)
+      post = s.substring(i, length);
+  }
+  /** 
+   * prints a formatted number following printf conventions
+   * @param s a PrintStream
+   * @param fmt the format string
+   * @param x the double to print
+   */
+  public static void print(java.io.PrintStream s,String fmt,double x) {
+    s.print(new Format(fmt).form(x));
+  }
+  /** 
+   * prints a formatted number following printf conventions
+   * @param s a PrintStream
+   * @param fmt the format string
+   * @param x the long to print
+   */
+  public static void print(java.io.PrintStream s,String fmt,long x) {
+    s.print(new Format(fmt).form(x));
+  }
+  /** 
+   * prints a formatted number following printf conventions
+   * @param s a PrintStream
+   * @param fmt the format string
+   * @param x the character to 
+   */
+  public static void print(java.io.PrintStream s,String fmt,char x) {
+    s.print(new Format(fmt).form(x));
+  }
+  /** 
+   * prints a formatted number following printf conventions
+   * @param s a PrintStream, fmt the format string
+   * @param x a string that represents the digits to print
+   */
+  public static void print(java.io.PrintStream s,String fmt,String x) {
+    s.print(new Format(fmt).form(x));
+  }
+  /** 
+   * Converts a string of digits (decimal, octal or hex) to an integer
+   * @param s a string
+   * @return the numeric value of the prefix of s representing a base 10 integer
+   */
+  public static int atoi(String s) {
+    return (int)atol(s);
+  }
+  /** 
+   * Converts a string of digits (decimal, octal or hex) to a long integer
+   * @param s a string
+   * @return the numeric value of the prefix of s representing a base 10 integer
+   */
+  public static long atol(String s) {
+    int i = 0;
+    while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++;
+    if (i < s.length() && s.charAt(i) == '0')
+      {  if (i + 1 < s.length() && (s.charAt(i + 1) == 'x' || s.charAt(i + 1) == 'X'))
+	return parseLong(s.substring(i + 2), 16);
+      else return parseLong(s, 8);
+      }
+    else return parseLong(s, 10);
+  }
+  /**
+   * Computes the format based on desired prescision and 
+   * minimum, maximum values.
+   *
+   * @param min minimum value
+   * @param max maximum value
+   * @param pres prescision
+   */
+  public static String computeFormat(double min,double max,int pres) {
+    double dx, xx;
+    int ip, id, ib;
+    String frmt;
+          
+    dx = Math.abs(max - min);
+    xx = Math.abs(max);
+    if(xx < Math.abs(min)) xx = Math.abs(min);
+    if(pres >= 0 && (xx >= 1000000.0f || xx < 0.001f)) {
+      id = pres -1;
+      if(id < 0) id=0;
+      frmt = "%" + "." + id + "e";
+    } else {
+      ip = Math.abs(pres);
+      id = ip - (int)(log10(dx) + 0.5);
+      if(id < 0) id = 0;
+      frmt = "%" + "." + id + "f";
+    }
+    return frmt;
+  }
+  static final double log10(double x) {
+    return 0.4342944819*Math.log(x);
+  }
+  /** 
+   * Converts a string of digits to an double
+   * @param s a string
+   */
+  public static double atof(String s) {
+    int i = 0;  int sign = 1;
+    double r = 0; // integer part
+    double f = 0; // fractional part
+    double p = 1; // exponent of fractional part
+    int state = 0; // 0 = int part, 1 = frac part
+      
+    while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++;
+    if (i < s.length() && s.charAt(i) == '-') { sign = -1; i++; }
+    else if (i < s.length() && s.charAt(i) == '+') { i++; }
+    while (i < s.length())
+      {  char ch = s.charAt(i);
+      if ('0' <= ch && ch <= '9')
+	{  if (state == 0)
+	  r = r * 10 + ch - '0';
+	else if (state == 1)
+	  {  p = p / 10;
+	  r = r + p * (ch - '0');
+	  }
+	}
+      else if (ch == '.') 
+	{  if (state == 0) state = 1; 
+	else return sign * r;
+	}
+      else if (ch == 'e' || ch == 'E')
+	{  long e = (int)parseLong(s.substring(i + 1), 10);
+	return sign * r * Math.pow(10, e);
+	}
+      else return sign * r;
+      i++;
+      }
+    return sign * r;
+  }
+  /** 
+   * Formats a double into a string (like sprintf in C)
+   * @param x the number to format
+   * @return the formatted string 
+   * @exception IllegalArgumentException if bad argument
+   */
+  public String form(double x) {
+    String r;  if (precision < 0) precision = 6;
+    int s = 1;
+    if (x < 0) { x = -x; s = -1; }
+    if (fmt == 'f'){
+      r = fixed_format(x);
+    	}
+    else if (fmt == 'e' || fmt == 'E' || fmt == 'g' || fmt == 'G')
+      r = exp_format(x);
+    else throw new java.lang.IllegalArgumentException();
+    return pad(sign(s, r));
+  }
+  /** 
+   * Formats a long integer into a string (like sprintf in C)
+   * @param x the number to format
+   * @return the formatted string 
+   */
+  public String form(long x) {
+    String r;   int s = 0;
+    if (fmt == 'd' || fmt == 'i')
+      {  s = 1;
+      if (x < 0) { x = -x; s = -1; }
+      r = "" + x;
+      }
+    else if (fmt == 'o')
+      r = convert(x, 3, 7, "01234567");
+    else if (fmt == 'x')
+      r = convert(x, 4, 15, "0123456789abcdef");
+    else if (fmt == 'X')
+      r = convert(x, 4, 15, "0123456789ABCDEF");
+    else throw new java.lang.IllegalArgumentException();
+         
+    return pad(sign(s, r));
+  }
+  /** 
+   * Formats a character into a string (like sprintf in C)
+   * @param x the value to format
+   * @return the formatted string 
+   */
+  public String form(char c) {
+    if (fmt != 'c')    throw new java.lang.IllegalArgumentException();
+
+    String r = "" + c;
+    return pad(r);
+  }
+  /** 
+   * Formats a string into a larger string (like sprintf in C)
+   * @param x the value to format
+   * @return the formatted string 
+   */
+  public String form(String s) {
+    if (fmt != 's')    throw new java.lang.IllegalArgumentException();
+    if (precision >= 0) s = s.substring(0, precision);
+    return pad(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Graph.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Graph.java
new file mode 100755
index 0000000..95585f4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Graph.java
@@ -0,0 +1,290 @@
+/*
+ * $Id: Graph.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.Debug;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import java.awt.Graphics;
+import java.awt.Event;
+import java.awt.Point;
+import java.beans.PropertyChangeListener;
+
+/**
+ * Abstract base class for all graphics drawn on a <code>Layer</code>.  The
+ * <code>Graph</code> class defines the interfaces for the user to physical
+ * coordinate, user to device, and physical to user coordinate systems.
+ * <p>
+ * The following demonstrates how a {@link CartesianGraph} may be
+ * used.
+ * <p>
+ * <pre>
+ *   // Create a CartesianGraph and transforms.
+ *
+ *    CartesianGraph graph;
+ *    LinearTransform xt, yt;
+ *    Range2D xPhysRange, xUserRange;
+ *    Range2D yPhysRange, yUserRange;
+ *    Point2D.Double origin;
+ *
+ *    graph = new CartesianGraph("Point Graph");
+ *    layer.setGraph(graph);
+ *    xt = new LinearTransform(xPhysRange, xUserRange);
+ *    yt = new LinearTransform(yPhysRange, yUserRange);
+ *    graph.setXTransform(xt);
+ *    graph.setYTransform(yt);
+ *    origin = new Point2D.Double(xUserRange.start,
+ *                                yUserRange.start);
+ *
+ *     // Create the bottom axis, set its range in user units
+ *     // and its origin. Add the axis to the graph.
+ *
+ *    PlainAxis xbot;
+ *
+ *    xbot = new PlainAxis("Botton Axis");
+ *    xbot.setRangeU(xUserRange);
+ *    xbot.setLocationU(origin);
+ *    graph.addXAxis(xbot);
+ *
+ *     // Create the left axis, set its range in user units
+ *     // and its origin. Add the axis to the graph.
+ *
+ *    PlainAxis yleft;
+ *
+ *    yleft = new PlainAxis("Left Axis");
+ *    yleft.setRangeU(yUserRange);
+ *    yleft.setLocationU(origin);
+ *    graph.addYAxis(yleft);
+ *
+ *     // Create a PointAttribute for the display of the
+ *     // Collection of points. The points will be marked
+ *     // with a red triangle and labelled at the NE corner
+ *     // in blue.
+ *
+ *    PointAttribute pattr;
+ *
+ *    pattr = new PointAttribute(10, Color.red);
+ *
+ *     // Associate the attribute and the point Collection
+ *     // with the graph.
+ *
+ *    graph.setData(col, pattr);
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see Layer
+ * @see LinearTransform
+ * @see PlainAxis
+ * @see SGLabel
+ * @see CartesianGraph
+ */
+public abstract class Graph implements PropertyChangeListener {
+  private String ident_;
+/** @directed
+ * @label layer */
+  protected Layer layer_;
+  /**
+   * Default constructor.
+   **/
+  public Graph() {
+    this("");
+  }
+  /**
+   * Constructor for <code>Graph</code> class.
+   *
+   * @param id identifier
+   **/
+  public Graph(String id) {
+    ident_ = id;
+  }
+  /**
+   * Copy the <code>Graph</code> object and all attached classes.
+   */
+  public abstract Graph copy();
+  /**
+   * Get the <code>Graph</code> identifier
+   *
+   * @return ident
+   **/
+  public String getId() {
+    return ident_;
+  }
+  //
+  abstract void draw(Graphics g);
+  //
+  void setLayer(Layer l) {
+    layer_ = l;
+  }
+  /**
+   * Get the associated <code>Layer</code>.
+   *
+   * @return <code>Layer</code> object
+   **/
+  public Layer getLayer() {
+    return layer_;
+  }
+  /**
+   * Return parent pane.
+   * @since 2.0
+   */
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+  /**
+   * Used internally by sgt.
+   * @since 2.0
+   */
+  public void modified(String mess) {
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Compute a "nice" range from a range and number of intervals.
+   *
+   * @param range min and max values
+   * @param num number of intervals
+   * @return "nice" range
+   */
+  public static Range2D computeRange(Range2D range,int num) {
+    return computeRange(range.start, range.end, num);
+  }
+  /**
+   * Compute a "nice" range from a range and number of intervals.
+   *
+   * @since 2.0
+   * @param range min and max values
+   * @param num number of intervals
+   * @return "nice" range
+   */
+  public static SoTRange computeRange(SoTRange range, int num) {
+    if(!range.isTime()) {
+      SoTRange.Double drange = (SoTRange.Double)range;
+      return new SoTRange.Double(computeRange(drange.start,
+                                              drange.end, num));
+    }
+    return null;
+  }
+  /**
+   * Compute a "nice" range from the minimum, maximum, and number of intervals.
+   *
+   * @param min minimum value
+   * @param max maximum value
+   * @param num number of intervals
+   * @return "nice" range
+   *
+   **/
+  public static Range2D computeRange(double min,double max,int num) {
+    int interval = Math.abs(num);
+    double temp, pow, delta;
+    int nt;
+    boolean reversed = false;
+    //
+    // check inputs to make sure that they are valid
+    //
+    if(min == max) {
+      if(min == 0.0) {
+        min = -1.0;
+        max = 1.0;
+      } else {
+        min = 0.9*max;
+        max = 1.1*max;
+      }
+    }
+    if(min > max) {
+      temp = min;
+      min = max;
+      max = temp;
+      reversed = true;
+    }
+    if(interval == 0) interval = 1;
+    //
+    // find the approximate size of the interval
+    //
+    temp = (max - min)/(double)interval;
+    if(temp == 0.0) temp = max;
+    if(temp == 0.0) {
+      min = -1.0;
+      max = 1.0;
+      temp = 2.0/(double)interval;
+    }
+    //
+    // scale the interval size by powers of ten to a value between
+    // one and ten
+    //
+    nt = (int)log10(temp);
+    if(temp < 1.0) nt--;
+    pow = Math.pow(10.0, (double)nt);
+    temp = temp/pow;
+    //
+    // find the closest permissible value for the interval size
+    //
+    if(temp < 1.414213562) {
+      delta = pow;
+    } else if(temp < 3.162277660) {
+      delta = 2.0 * pow;
+    } else if(temp < 7.071067812) {
+      delta = 5.0 * pow;
+    } else {
+      delta = 10.0 * pow;
+    }
+    //
+    // calculate the minimum value of the range
+    //
+    temp = min / delta;
+    nt = (int) temp;
+    if(temp < 0.0) nt--;
+    min = delta*nt;
+    //
+    // calculate the maximum value of the range
+    //
+    temp = max /delta;
+    nt = (int) temp;
+    if(temp > 0.0) nt++;
+    max = delta*nt;
+    //
+    if(reversed) {
+      temp = min;
+      min = max;
+      max = temp;
+      delta = -delta;
+    }
+    return new Range2D(min, max, delta);
+  }
+  static final double log10(double x) {
+    return 0.4342944819*Math.log(x);
+  }
+  //
+  abstract Object getObjectAt(Point pt);
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>Graph</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  /**
+   * Find data at a <code>Point</code>
+   * @since 3.0
+   */
+  public abstract SGTData getDataAt(Point pt);
+}
+
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/GridAttribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/GridAttribute.java
new file mode 100755
index 0000000..e11b129
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/GridAttribute.java
@@ -0,0 +1,292 @@
+/*
+ * $Id: GridAttribute.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Sets the rendering style for grid data.  <code>ColorMap</code>,
+ * <code>ContourLevels</code> are <code>GridAttribute</code> properties.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see GridCartesianRenderer
+ * @see ContourLevels
+ */
+public class GridAttribute implements Attribute,
+                                      Cloneable,
+                                      PropertyChangeListener {
+  private transient PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  // serial version ref 1.18
+  private static final long serialVersionUID = 3822340406728567524L;
+  private boolean batch_ = false;
+  private boolean local_ = true;
+  private boolean modified_ = false;
+  private String id_ = null;
+  /**@shapeType AggregationLink
+   * @label cmap*/
+  private ColorMap cmap_;
+  /**@shapeType AggregationLink
+   * @label clev*/
+  private ContourLevels clev_;
+  private int style_;
+  /**
+   * Raster style.
+   */
+  public static final int RASTER = 0;
+  /**
+   * Area fill style.
+   **/
+  public static final int AREA_FILL = 1;
+  /**
+   * Contour line style.
+   */
+  public static final int CONTOUR = 2;
+  /**
+   * Raster and Contour style.
+   * @since 2.0
+   */
+  public static final int RASTER_CONTOUR = 3;
+  /**
+   * Area fill and Contour style.
+   * @since 2.0
+   */
+  public static final int AREA_FILL_CONTOUR = 4;
+  /**
+   * Default constructor.  Default style is <code>RASTER</code> and
+   * default <code>ColorMap</code> is null.
+   **/
+  public GridAttribute() {
+    this(RASTER, null);
+  }
+  /**
+   * <code>GridAttribute</code> constructor for <code>RASTER</code> and
+   * <code>AREA_FILL</code> styles.
+   *
+   * @param style grid style
+   * @param cmap <code>ColorMap</code>
+   **/
+  public GridAttribute(int style,ColorMap cmap) {
+    style_ = style;
+    cmap_ = cmap;
+    if(cmap_ != null) cmap_.addPropertyChangeListener(this);
+  }
+  /**
+   * <code>GridAttribute</code> constructor for <code>CONTOUR</code> style.
+   *
+   * @param clev <code>ContourLevels</code>
+   */
+  public GridAttribute(ContourLevels clev) {
+    style_ = CONTOUR;
+    cmap_ = null;
+    clev_ = clev;
+  }
+  /**
+   * Set the <code>ContourLevels</code>.
+   * <BR><B>Property Change:</B> <code>contourLevels</code>.
+   *
+   * @param clev <code>ContourLevels</code>
+   */
+  public void setContourLevels(ContourLevels clev) {
+    if(clev_ == null || !clev_.equals(clev)) {
+      ContourLevels tempOld = clev_;
+      clev_ = clev;
+      firePropertyChange("contourLevels",
+                                  tempOld,
+                                  clev_);
+    }
+  }
+  /**
+   * Get the <code>ContourLevels</code>.
+   *
+   * @return <code>ContourLevels</code>
+   */
+  public ContourLevels getContourLevels() {
+    return clev_;
+  }
+  /**
+   * Copy the <code>GridAttribute</code>.
+   *
+   * @return new <code>GridAttribute</code>
+   */
+  public GridAttribute copy() {
+    GridAttribute newGrid;
+    try {
+      newGrid = (GridAttribute)clone();
+    } catch (CloneNotSupportedException e) {
+      newGrid = new GridAttribute();
+    }
+    return newGrid;
+  }
+  /**
+   * Set the grid style.
+   * <BR><B>Property Change:</B> <code>style</code>.
+   *
+   * @param st grid style
+   **/
+  public void setStyle(int st) {
+    if(style_ != st) {
+      Integer tempOld = new Integer(style_);
+      style_ = st;
+      firePropertyChange("style",
+                                  tempOld,
+                                  new Integer(style_));
+    }
+  }
+  /**
+   * Get grid style.
+   *
+   * @return grid style
+   **/
+  public int getStyle() {
+    return style_;
+  }
+  /**
+   * Tests if <code>GridAttribute</code> style is either
+   * RASTER or RASTER_CONTOUR.
+   * @since 2.0
+   */
+  public boolean isRaster() {
+    return (style_ == RASTER ||
+            style_ == RASTER_CONTOUR);
+  }
+  /**
+   * Tests if <code>GridAttribute</code> style is either
+   * CONTOUR, RASTER_CONTOUR, or AREA_FILL_CONTOUR.
+   * @since 2.0
+   */
+  public boolean isContour() {
+    return (style_ == CONTOUR ||
+            style_ == RASTER_CONTOUR ||
+            style_ == AREA_FILL_CONTOUR);
+  }
+  /**
+   * Tests if <code>GridAttribute</code> style is eigther
+   * AREA_FILL or AREA_FILL_CONTOUR.
+   * @since 2.0
+   */
+  public boolean isAreaFill() {
+    return (style_ == AREA_FILL ||
+            style_ == AREA_FILL_CONTOUR);
+  }
+  /**
+   * Get the <code>ColorMap</code>.
+   *
+   * @return the <code>ColorMap</code>
+   **/
+  public ColorMap getColorMap() {
+    return cmap_;
+  }
+  /**
+   * Set the <code>ColorMap</code>.
+   * <BR><B>Property Change:</B> <code>colorMap</code>.
+   *
+   * @param cmap the <code>ColorMap</code>
+   */
+  public void setColorMap(ColorMap cmap) {
+    if(cmap_ == null && cmap == null) {
+      return;
+    } else {
+      if(cmap_ != null) cmap_.removePropertyChangeListener(this);
+      if(cmap_ == null || !cmap_.equals(cmap)) {
+        ColorMap tempOld = cmap_;
+        cmap_ = cmap;
+        firePropertyChange("colorMap",
+                                    tempOld,
+                                    cmap_);
+        cmap_.addPropertyChangeListener(this);
+      }
+    }
+  }
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>GridAttribute</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1);
+  }
+  /**
+   * Add listener to changes in <code>GridAttribute</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.addPropertyChangeListener(listener);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    if(Debug.EVENT) {
+      System.out.println("GridAttribute: " + evt);
+      System.out.println("                  " + evt.getPropertyName());
+    }
+    changes_.firePropertyChange(evt);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setId(String id) {
+    id_ = id;
+  }
+  /**
+   * @since 3.0
+   */
+  public String getId() {
+    return id_;
+  }
+
+  protected void firePropertyChange(String name, Object oldValue, Object newValue) {
+    if(batch_) {
+      modified_ = true;
+      return;
+    }
+    AttributeChangeEvent ace = new AttributeChangeEvent(this, name,
+                                                        oldValue, newValue,
+                                                        local_);
+    changes_.firePropertyChange(ace);
+    modified_ = false;
+  }
+
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch) {
+    setBatch(batch, true);
+  }
+
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch, boolean local) {
+    local_ = local;
+    batch_ = batch;
+    if(!batch && modified_) firePropertyChange("batch", Boolean.TRUE, Boolean.FALSE);
+  }
+
+  /**
+   * @since 3.0
+   */
+  public boolean isBatch() {
+    return batch_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/GridCartesianRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/GridCartesianRenderer.java
new file mode 100755
index 0000000..25c26f2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/GridCartesianRenderer.java
@@ -0,0 +1,623 @@
+/*
+ * $Id: GridCartesianRenderer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.contour.Contour;
+import gov.noaa.pmel.sgt.contour.ContourLine;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Font;
+import java.awt.Point;
+import java.awt.FontMetrics;
+import java.util.Enumeration;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Produces a cartesian plot from a <code>SGTGrid</code> object.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public class GridCartesianRenderer extends CartesianRenderer {
+  /**@shapeType AggregationLink
+   * @label grid
+   * @undirected
+   * @supplierCardinality 1*/
+  private SGTGrid grid_;
+  /**@shapeType AggregationLink
+   * @label attr
+   * @undirected
+   * @supplierCardinality 1*/
+  private GridAttribute attr_ = null;
+
+  /**
+   * @link aggregationByValue
+   * @supplierCardinality 1
+   * @label con
+   */
+  private Contour con_ = null;
+  //
+  private void drawRaster(Graphics g) {
+    int nT, nX, nY, nZ;
+    int[] xp, yp;
+    int i, j;
+    Color color;
+    int xSize, ySize, count;
+    double[] xValues, yValues, gValues;
+    double val;
+    GeoDate[] tValues;
+    //
+    if(grid_.isXTime()) {
+      if(grid_.getTimeArray().length <= 2) return;
+      if(grid_.hasXEdges()) {
+        tValues = grid_.getTimeEdges();
+        xSize = tValues.length;
+        xp = new int[xSize];
+        for(count=0; count < xSize; count++) {
+          xp[count] = cg_.getXUtoD(tValues[count]);
+        }
+      } else {
+        tValues = grid_.getTimeArray();
+        xSize = tValues.length;
+        xp = new int[xSize+1];
+        xp[0] = cg_.getXUtoD(tValues[0].subtract(
+                            (tValues[1].subtract(tValues[0])).divide(2.0)));
+        for(count=1; count < xSize; count++) {
+          xp[count] = cg_.getXUtoD(
+                    (tValues[count-1].add(tValues[count])).divide(2.0));
+        }
+        xp[xSize] = cg_.getXUtoD(tValues[xSize-1].add(
+                    (tValues[xSize-1].subtract(tValues[xSize-2])).divide(2.0)));
+      }
+    } else {
+      if(grid_.getXArray().length <= 2) return;
+      if(grid_.hasXEdges()) {
+        xValues = grid_.getXEdges();
+        xSize = xValues.length;
+        xp = new int[xSize];
+        for(count=0; count < xSize; count++) {
+          xp[count] = cg_.getXUtoD(xValues[count]);
+        }
+      } else {
+        xValues = grid_.getXArray();
+        xSize = xValues.length;
+        xp = new int[xSize+1];
+        xp[0] = cg_.getXUtoD(xValues[0]-(xValues[1]-xValues[0])*0.5);
+        for(count=1; count < xSize; count++) {
+          xp[count] = cg_.getXUtoD((xValues[count-1]+xValues[count])*0.5);
+        }
+        xp[xSize] = cg_.getXUtoD(xValues[xSize-1]+
+                                 (xValues[xSize-1]-xValues[xSize-2])*0.5);
+      }
+    }
+    if(grid_.isYTime()) {
+      if(grid_.getTimeArray().length <= 2) return;
+      if(grid_.hasYEdges()) {
+        tValues = grid_.getTimeEdges();
+        ySize = tValues.length;
+        yp = new int[ySize];
+        for(count=0; count < ySize; count++) {
+          yp[count] = cg_.getYUtoD(tValues[count]);
+        }
+      } else {
+        tValues = grid_.getTimeArray();
+        ySize = tValues.length;
+        yp = new int[ySize+1];
+        yp[0] = cg_.getYUtoD(tValues[0].subtract(
+                          (tValues[1].subtract(tValues[0])).divide(2.0)));
+        for(count=1; count < ySize; count++) {
+          yp[count] = cg_.getYUtoD((tValues[count-1].add(
+                               tValues[count])).divide(2.0));
+        }
+        yp[ySize] = cg_.getYUtoD(tValues[ySize-1].add(
+                     (tValues[ySize-1].subtract(tValues[ySize-2])).divide(2.0)));
+      }
+    } else {
+      if(grid_.getYArray().length <= 2) return;
+      if(grid_.hasYEdges()) {
+        yValues = grid_.getYEdges();
+        ySize = yValues.length;
+        yp = new int[ySize];
+        for(count=0; count < ySize; count++) {
+          yp[count] = cg_.getYUtoD(yValues[count]);
+        }
+      } else {
+        yValues = grid_.getYArray();
+        ySize = yValues.length;
+        yp = new int[ySize+1];
+        yp[0] = cg_.getYUtoD(yValues[0]-(yValues[1]-yValues[0])*0.5);
+        for(count=1; count < ySize; count++) {
+          yp[count] = cg_.getYUtoD((yValues[count-1]+yValues[count])*0.5);
+        }
+        yp[ySize] = cg_.getYUtoD(yValues[ySize-1]+
+                                 (yValues[ySize-1]-yValues[ySize-2])*0.5);
+      }
+    }
+    //
+    // draw raster
+    //
+    gValues = grid_.getZArray();
+    count=0;
+    for(i=0; i < xSize; i++) {
+      for(j=0; j < ySize; j++) {
+        val = gValues[count];
+        if(!Double.isNaN(val)) {
+          color = attr_.getColorMap().getColor(val);
+          g.setColor(color);
+          drawRect(g, xp[i], yp[j], xp[i+1], yp[j+1]);
+        }
+        count++;
+      }
+    }
+  }
+  /**
+   * Get the <code>Attribute</code> associated with
+   * the <code>SGTGrid</code> data.
+   *
+   * @return <code>Attribute</code>
+   */
+  public Attribute getAttribute() {
+    return attr_;
+  }
+  /**
+   * Set the <code>GridAttribute</code> for the renderer.
+   * @since 2.0
+   */
+  public void setAttribute(GridAttribute attr) {
+    if(attr_ != null) attr_.removePropertyChangeListener(this);
+    attr_ = attr;
+    attr_.addPropertyChangeListener(this);
+  }
+  private void drawRect(Graphics g,int x1,int y1,int x2,int y2) {
+    int x, y, width, height;
+    if(x1 < x2) {
+      x = x1;
+      width = x2 - x1;
+    } else {
+      x=x2;
+      width = x1 - x2;
+    }
+    if(y1 < y2) {
+      y = y1;
+      height = y2 - y1;
+    } else {
+      y = y2;
+      height = y1 - y2;
+    }
+    g.fillRect(x, y, width, height);
+  }
+  /**
+   * Default constructor. The <code>GridCartesianRenderer</code> should
+   * be created using the <code>CartesianRenderer.getRenderer</code>
+   * method.
+   *
+   * @see CartesianRenderer#getRenderer
+   * @see Graph
+   **/
+  public GridCartesianRenderer(CartesianGraph cg) {
+    this(cg, null, null);
+  }
+  /**
+   * Construct a <code>GridCartesianRenderer</code>.
+   * The <code>GridCartesianRenderer</code> should
+   * be created using the <code>CartesianRenderer.getRenderer</code>
+   * method.
+   *
+   * @see CartesianRenderer#getRenderer
+   * @see Graph
+   **/
+  public GridCartesianRenderer(CartesianGraph cg, SGTGrid data) {
+    this(cg, data, null);
+  }
+  /**
+   * Construct a <code>GridCartesianRenderer</code>.
+   * The <code>GridCartesianRenderer</code> should
+   * be created using the <code>CartesianRenderer.getRenderer</code>
+   * method.
+   *
+   * @see CartesianRenderer#getRenderer
+   * @see Graph
+   **/
+  public GridCartesianRenderer(CartesianGraph cg, SGTGrid grid, GridAttribute attr) {
+    cg_ = cg;
+    grid_ = grid;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Render the <code>SGTData</code>. This method should not
+   * be directly called.
+   *
+   * @param g graphics context
+   *
+   * @see Pane#draw
+   */
+  public void draw(Graphics g) {
+    if(cg_.clipping_) {
+      int xmin, xmax, ymin, ymax;
+      int x, y, width, height;
+      if(cg_.xTransform_.isSpace()) {
+        xmin = cg_.getXUtoD(cg_.xClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.xClipRange_.end);
+      } else {
+        xmin = cg_.getXUtoD(cg_.tClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.tClipRange_.end);
+      }
+      if(cg_.yTransform_.isSpace()) {
+        ymin = cg_.getYUtoD(cg_.yClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.yClipRange_.end);
+      } else {
+        ymin = cg_.getYUtoD(cg_.tClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.tClipRange_.end);
+      }
+      if(xmin < xmax) {
+        x = xmin;
+        width = xmax - xmin;
+      } else {
+        x=xmax;
+        width = xmin - xmax;
+      }
+      if(ymin < ymax) {
+        y = ymin;
+        height = ymax - ymin;
+      } else {
+        y = ymax;
+        height = ymin - ymax;
+      }
+      g.setClip(x, y, width, height);
+    }
+    if(attr_.isRaster()) {
+      drawRaster(g);
+    }
+    if(attr_.isAreaFill()) {
+      //
+      // This is a temporary method based on the
+      // PPLUS area fill algorthim
+      //
+      // To be replaced by a area fill method that
+      // uses the ContourLines
+      //
+      double[] x = xArrayP();
+      double[] y = yArrayP();
+      double[] z = grid_.getZArray();
+      int i,j;
+      int nx = x.length;
+      int ny = y.length;
+      double[] xt = new double[5];
+      double[] yt = new double[5];
+      double[] zt = new double[5];
+      for(i=0; i < nx-1; i++) {
+        for(j=0; j < ny-1; j++) {
+          xt[0] = x[i];
+          yt[0] = y[j];
+          zt[0] = z[j + i*ny];
+          //
+          xt[1] = x[i+1];
+          yt[1] = y[j];
+          zt[1] = z[j + (i+1)*ny];
+          //
+          xt[2] = x[i+1];
+          yt[2] = y[j+1];
+          zt[2] = z[j+1 + (i+1)*ny];
+          //
+          xt[3] = xt[0];
+          yt[3] = yt[2];
+          zt[3] = z[j+1 + i*ny];
+          //
+          // repeat first point
+          //
+          xt[4] = xt[0];
+          yt[4] = yt[0];
+          zt[4] = zt[0];
+          //
+          fillSquare(g, xt, yt, zt);
+        }
+      }
+    }
+    if(attr_.isContour()) {
+      double val;
+      String label;
+      Range2D range = computeRange(10);
+      Format format;
+      //	con_ = new Contour(cg_, grid_, range);
+      con_ = new Contour(cg_, grid_, attr_.getContourLevels());
+      ContourLevels clevels = con_.getContourLevels();
+      DefaultContourLineAttribute attr;
+      //
+      // set labels
+      //
+      for(int i=0; i < clevels.size(); i++) {
+        try {
+          val = clevels.getLevel(i);
+          attr = clevels.getDefaultContourLineAttribute(i);
+          if(attr.isAutoLabel()) {
+            if(attr.getLabelFormat().length() <= 0) {
+              format  = new Format(Format.computeFormat(range.start,
+                                                        range.end,
+                                                        attr.getSignificantDigits()));
+            } else {
+              format = new Format(attr.getLabelFormat());
+            }
+            label = format.form(val);
+            attr.setLabelText(label);
+          }
+        } catch (ContourLevelNotFoundException e) {
+          System.out.println(e);
+        }
+      }
+      con_.generateContourLines();
+      con_.generateContourLabels(g);
+      Enumeration elem = con_.elements();
+      ContourLine cl;
+      while(elem.hasMoreElements()) {
+        cl = (ContourLine)elem.nextElement();
+        if(Debug.CONTOUR) {
+          System.out.println(" level = " + cl.getLevel() +
+                             ", length = " + cl.getKmax() +
+                             ", closed = " + cl.isClosed());
+        }
+        cl.draw(g);
+      }
+    }
+    //
+    // reset clip
+    //
+    Rectangle rect = cg_.getLayer().getPane().getBounds();
+    g.setClip(rect);
+  }
+
+  private void fillSquare(Graphics g, double[] x,
+                          double[] y, double[] z) {
+    ContourLevels clevels = attr_.getContourLevels();
+    IndexedColor cmap = (IndexedColor)attr_.getColorMap();
+    int i,j,cindex, npoly, maxindex;
+    double zlev, zlevp1, f;
+    Color col;
+    double[] xpoly = new double[20];
+    double[] ypoly = new double[20];
+    double zmin = Math.min(z[0], z[1]);
+    double zmax = Math.max(z[0], z[1]);
+    for(i=2; i <= 3; i++) {
+      zmin = Math.min(zmin, z[i]);
+      zmax = Math.max(zmax, z[i]);
+    }
+    if(Double.isNaN(zmax)) return;
+    maxindex = clevels.getMaximumIndex();
+    for(cindex=-1; cindex <= maxindex; cindex++) {
+      try {
+        if(cindex == -1) {
+          zlev = -Double.MAX_VALUE;
+        } else {
+          zlev = clevels.getLevel(cindex);
+        }
+        if(cindex == maxindex) {
+          zlevp1 = Double.MAX_VALUE;
+        } else {
+          zlevp1 = clevels.getLevel(cindex+1);
+        }
+      } catch (ContourLevelNotFoundException e) {
+        System.out.println(e);
+        break;
+      }
+      col = cmap.getColorByIndex(cindex+1);
+      if(zmin > zlevp1 || zmax < zlev) continue;
+      if(zmin >= zlev && zmax <= zlevp1) {
+        fillPolygon(g, col, x, y, 4);
+        return;
+      }
+      npoly = -1;
+      for(j=0; j < 4; j++) {  /* sides */
+        if(z[j] < zlev) {
+          //
+          // z[j] is below
+          //
+          if(z[j+1] > zlevp1) {
+            //
+            // z[j+1] is above
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlev)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+          } else if(z[j+1] >= zlev &&
+                    z[j+1] <= zlevp1) {
+            //
+            // z[j+1] is inside
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlev)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+            //
+            npoly=npoly+1;
+            xpoly[npoly] = x[j+1];
+            ypoly[npoly] = y[j+1];
+          }
+        } else if(z[j] > zlevp1) {
+          //
+          // z[j] is above
+          //
+          if(z[j+1] < zlev) {
+            //
+            // z[j+1] is below
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlev)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+          } else if(z[j+1] >= zlev && z[j+1] <= zlevp1) {
+            //
+            // z[j+1] is inside
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+            //
+            npoly=npoly+1;
+            xpoly[npoly] = x[j+1];
+            ypoly[npoly] = y[j+1];
+          }
+        } else {
+          //
+          // x[j] is inside
+          //
+          if(z[j+1] > zlevp1) {
+            //
+            // z[j+1] is above
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+          } else if(z[j+1] < zlev) {
+            //
+            // z[j+1] is below
+            //
+            npoly=npoly+1;
+            f = (z[j]-zlev)/(z[j]-z[j+1]);
+            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
+            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
+          } else {
+            //
+            // z[j+1] is inside
+            //
+            npoly=npoly+1;
+            xpoly[npoly] = x[j+1];
+            ypoly[npoly] = y[j+1];
+          }
+        }
+      }
+      fillPolygon(g, col, xpoly, ypoly, npoly+1);
+    }
+  }
+
+  private void fillPolygon(Graphics g, Color c,
+                           double[] x, double[] y,
+                           int npoints) {
+    Layer layer = cg_.getLayer();
+    int[] xt = new int[20];
+    int[] yt = new int[20];
+    g.setColor(c);
+    for(int i=0; i < npoints; i++) {
+      xt[i] = layer.getXPtoD(x[i]);
+      yt[i] = layer.getYPtoD(y[i]);
+    }
+    g.fillPolygon(xt, yt, npoints);
+  }
+
+  private double[] xArrayP() {
+    int i;
+    double[] p;
+    if(grid_.isXTime()) {
+      GeoDate[] t = grid_.getTimeArray();
+      p = new double[t.length];
+      for(i=0; i < t.length; i++) {
+        p[i] = cg_.getXUtoP(t[i]);
+      }
+    } else {
+      double[] x = grid_.getXArray();
+      p = new double[x.length];
+      for(i=0; i < x.length; i++) {
+        p[i] = cg_.getXUtoP(x[i]);
+      }
+    }
+    return p;
+  }
+
+  private double[] yArrayP() {
+    int i;
+    double[] p;
+    if(grid_.isYTime()) {
+      GeoDate[] t = grid_.getTimeArray();
+      p = new double[t.length];
+      for(i=0; i < t.length; i++) {
+        p[i] = cg_.getYUtoP(t[i]);
+      }
+    } else {
+      double[] y = grid_.getYArray();
+      p = new double[y.length];
+      for(i=0; i < y.length; i++) {
+        p[i] = cg_.getYUtoP(y[i]);
+      }
+    }
+    return p;
+  }
+
+  private Range2D computeRange(int levels) {
+    Range2D range;
+    double zmin = Double.POSITIVE_INFINITY;
+    double zmax = Double.NEGATIVE_INFINITY;
+    double[] array = grid_.getZArray();
+    for(int i=0; i < array.length; i++) {
+      if(!Double.isNaN(array[i])) {
+        zmin = Math.min(zmin, array[i]);
+        zmax = Math.max(zmax, array[i]);
+      }
+    }
+    range = Graph.computeRange(zmin, zmax, levels);
+    return range;
+  }
+  /**
+   * Get the <code>SGTGrid</code>.
+   *
+   * @return <code>SGTGrid</code>
+   */
+  public SGTGrid getGrid() {
+    return grid_;
+  }
+  /**
+   * Get the associated <code>CartesianGraph</code> object.
+   * @since 2.0
+   * @return <code>CartesianGraph</code>
+   */
+  public CartesianGraph getCartesianGraph() {
+    return cg_;
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+//      if(Debug.EVENT) {
+//        System.out.println("GridCartesianRenderer: " + evt);
+//        System.out.println("                       " + evt.getPropertyName());
+//      }
+    modified("GridCartesianRenderer: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  /**
+   * @since 3.0
+   */
+  public SGTData getDataAt(Point pt) {
+    return null;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/HourDayAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/HourDayAxis.java
new file mode 100755
index 0000000..063691f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/HourDayAxis.java
@@ -0,0 +1,120 @@
+/*
+ * $Id: HourDayAxis.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+/**
+ * Draws time axes using the hour/day style.
+ *
+ * <pre>
+ *                  |..........|..........|..........|..........|
+ *                       3           4         5           6
+ *                                    jun 7
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @see Axis
+ * @see TimeAxis
+ */
+class HourDayAxis implements TimeAxisStyle {
+  static final int HOUR_TEST__ = 4;
+  static final String defaultMinorLabelFormat__ = "HH";
+  static final String defaultMajorLabelFormat__ = "yyyy-MM-dd";
+  static final int defaultNumSmallTics__ = 0;
+  int defaultMinorLabelInterval_ = 2;
+  int defaultMajorLabelInterval_ = 1;
+  static final double incrementValue__ = 1.0;
+  static final int incrementUnits__ = GeoDate.HOURS;
+  /**
+   * HourDayAxis constructor.
+   *
+   * @param id axis identifier
+   **/
+  public HourDayAxis() {
+  }
+  public double computeLocation(double prev,double now) {
+    return prev;
+  }
+  public void computeDefaults(GeoDate delta) {
+    long days = delta.getTime()/GeoDate.MSECS_IN_DAY;
+    long msec = delta.getTime() % GeoDate.MSECS_IN_DAY;
+    if(days > 2) {
+      defaultMinorLabelInterval_ = 6;
+    } else if((days > 0) || (msec > 43200000)) {
+      defaultMinorLabelInterval_ = 2;
+    } else {
+      defaultMinorLabelInterval_ = 1;
+    }
+  }
+  public int getMinorValue(GeoDate time) {
+    return time.getGMTHours();
+  }
+  public int getMajorValue(GeoDate time) {
+    return time.getGMTDay();
+  }
+  public boolean isRoomForMajorLabel(GeoDate delta) {
+    return 24.0*(((double)delta.getTime())/((double)GeoDate.MSECS_IN_DAY)) > HOUR_TEST__;
+  }
+  public boolean isStartOfMinor(GeoDate time) {
+    return time.getGMTHours() == 0;
+  }
+  public String getDefaultMinorLabelFormat() {
+    return defaultMinorLabelFormat__;
+  }
+  public String getDefaultMajorLabelFormat() {
+    return defaultMajorLabelFormat__;
+  }
+  public int getDefaultNumSmallTics() {
+    return defaultNumSmallTics__;
+  }
+  public int getDefaultMinorLabelInterval() {
+    return defaultMinorLabelInterval_;
+  }
+  public int getDefaultMajorLabelInterval() {
+    return defaultMajorLabelInterval_;
+  }
+  public GeoDate getStartTime(TimeRange tRange) {
+    boolean time_increasing;
+    GeoDate time = null;
+    time_increasing = tRange.end.after(tRange.start);
+    try {
+      if(time_increasing) {
+        time = new GeoDate(tRange.start.getGMTMonth(),
+         tRange.start.getGMTDay(),
+                           tRange.start.getGMTYear(),
+         tRange.start.getGMTHours(), 0, 0, 0);
+        if(!time.equals(tRange.start)) time.increment(1.0f, GeoDate.HOURS);
+      } else {
+        time = new GeoDate(tRange.end.getGMTMonth(),
+         tRange.end.getGMTDay(),
+                           tRange.end.getGMTYear(),
+         tRange.end.getGMTHours(), 0, 0, 0);
+        if(!time.equals(tRange.end)) time.increment(1.0f, GeoDate.HOURS);
+      }
+    } catch (IllegalTimeValue e) {}
+    return time;
+  }
+  public double getIncrementValue() {
+    return incrementValue__;
+  }
+  public int getIncrementUnits() {
+    return incrementUnits__;
+  }
+  public String toString() {
+    return "HourDayAxis";
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/IndexedColor.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/IndexedColor.java
new file mode 100755
index 0000000..cb93151
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/IndexedColor.java
@@ -0,0 +1,41 @@
+/*
+ * $Id: IndexedColor.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import java.awt.Color;
+
+/**
+ * Defines the access methods for color maps that support indexed color.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ **/
+public interface IndexedColor {
+
+  /**
+   *
+   * @param index
+   * @return
+   * @since 3.0
+   */
+  Color getColorByIndex(int index);
+
+  void setColor(int index, Color color);
+
+  void setColor(int index, int red, int green, int blue);
+  /**
+   * Get the maximum legal value of the color index.
+   */
+  int getMaximumIndex();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/IndexedColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/IndexedColorMap.java
new file mode 100755
index 0000000..d2b7ea0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/IndexedColorMap.java
@@ -0,0 +1,215 @@
+/*
+ * $Id: IndexedColorMap.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * <code>IndexedColorMap</code> provides a mapping from a value to a
+ * <code>Color</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public class IndexedColorMap extends ColorMap
+  implements Cloneable, PropertyChangeListener, IndexedColor, TransformAccess {
+  protected Color[] colors_;
+  /**
+   * index Transform.  Default transform is Linear.
+   * @supplierCardinality 0..1
+   * @clientRole iTrans_
+   * @link aggregationByValue
+   */
+  private Transform iTrans_ = new LinearTransform(0.0, 1.0, 0.0, 1.0);
+  /**
+   * Initialize the color map with int arrays of red, green, and blue.
+   * The arrays must be the same length. Sets up <code>ColorMap</code>
+   * for <code>INDEXED</code> access.
+   *
+   * @param red Array of the red component 0 - 255.
+   * @param green Array of the green component 0 - 255.
+   * @param blue Array of the blue component 0 - 255.
+   *
+   * @see java.awt.Color
+   */
+  public IndexedColorMap(int[] red,int[] green,int[] blue) {
+    int indx;
+    colors_ = new Color[red.length];
+    for (indx=0; indx < red.length; indx++) {
+      colors_[indx] = new Color(red[indx], green[indx], blue[indx]);
+    }
+    iTrans_.setRangeP(0.0, (double)colors_.length);
+  }
+  /**
+   * Initialize the color map with float arrays of red, green, and blue.
+   * The arrays must be the same length. Sets up <code>ColorMap</code>
+   * for <code>INDEXED</code> access.
+   *
+   * @param red Array of the red component 0.0 - 1.0.
+   * @param green Array of the green component 0.0 - 1.0.
+   * @param blue Array of the blue component 0.0 - 1.0.
+   *
+   * @see java.awt.Color
+   */
+  public IndexedColorMap(float[] red,float[] green,float[] blue) {
+    int indx;
+    colors_ = new Color[red.length];
+    for (indx=0; indx < red.length; indx++) {
+      colors_[indx] = new Color(red[indx], green[indx], blue[indx]);
+    }
+    iTrans_.setRangeP(0.0, (double)colors_.length);
+  }
+  /**
+   * Initialize the color map with an array of <code>Color</code>
+   * objects. Sets up <code>ColorMap</code> for
+   * <code>INDEXED</code> access.
+   *
+   * @param colors Array of the Color objects.
+   *
+   * @see java.awt.Color
+   */
+  public IndexedColorMap(Color[] colors) {
+    colors_ = colors;
+    iTrans_.setRangeP(0.0, (double)colors_.length);
+  }
+  /**
+   * Create a copy of the <code>ColorMap</code>
+   */
+  public ColorMap copy() {
+    ColorMap newMap;
+    try {
+      newMap = (ColorMap)clone();
+    } catch (CloneNotSupportedException e) {
+      newMap = new IndexedColorMap(colors_);
+    }
+    return newMap;
+  }
+  /**
+   * Get a <code>Color</code>.
+   *
+   * @return color
+   * @since 3.0
+   */
+  public Color getColorByIndex(int indx) {
+    return colors_[indx];
+  }
+
+  /**
+   * Get a <code>Color</code>.
+   *
+   * @param val Value
+   * @return Color
+   *
+   */
+  public Color getColor(double val) {
+    double ival = val;
+    int indx;
+    indx = (int)Math.round(iTrans_.getTransP(ival));
+    if(indx < 0) indx=0;
+    if(indx > colors_.length-1) indx = colors_.length-1;
+    return colors_[indx];
+  }
+  /**
+   * Set the user range for the <code>Transform</codes>.
+   *
+   */
+  public void setRange(Range2D range) {
+    iTrans_.setRangeU(range);
+  }
+  /**
+   * Get the current user range for the <code>Transform</code>.
+   *
+   * @return user range
+   */
+  public Range2D getRange() {
+    return iTrans_.getRangeU();
+  }
+  /**
+   * Change the <code>Color</code>.
+   *
+   * @param colr new <code>Color</code>
+   * @param indx index of color
+   */
+  public void setColor(int index, Color colr) {
+    setColor(index, colr.getRed(), colr.getGreen(), colr.getBlue());
+  }
+  /**
+   * Change the <code>Color</code>.
+   * <BR><B>Property Change:</B> <code>color</code>.
+   *
+   * @param red red component
+   * @param green green component
+   * @param blue blue component
+   * @param indx index of color
+   */
+  public void setColor(int indx, int red, int green, int blue) {
+    if(indx < 0 || indx > colors_.length) return;
+    Color newColor = new Color(red, green, blue);
+    if(!colors_[indx].equals(newColor)) {
+      Color tempOld = colors_[indx];
+      colors_[indx] = newColor;
+      firePropertyChange("color",
+                                  tempOld,
+                                  newColor);
+    }
+  }
+  /**
+   * Get the maximum color index.
+   *
+   * @return maximum legal color index
+   */
+  public int getMaximumIndex() {
+    return colors_.length - 1;
+  }
+  /**
+   * Set the transform for the color mapping.
+   * <BR><B>Property Change:</B> <code>transform</code>.
+   *
+   * @param trans index color <code>Transform</code>
+   */
+  public void setTransform(Transform trans) {
+    if(!trans.equals(iTrans_)) {
+      Transform tempOld = iTrans_;
+      if(iTrans_ != null) iTrans_.removePropertyChangeListener(this);
+      iTrans_ = trans;
+      iTrans_.setRangeP(0.0, (double)colors_.length);
+      firePropertyChange("transform",
+                                  tempOld,
+                                  iTrans_);
+      iTrans_.addPropertyChangeListener(this);
+    }
+  }
+  /**
+   * Get the transform for the color mapping.
+   *
+   * @return index color <code>Transform</code>
+   */
+  public Transform getTransform() {
+    return iTrans_;
+  }
+  public boolean equals(ColorMap cm) {
+    if(cm == null || !(cm instanceof IndexedColorMap)) return false;
+    if(!iTrans_.equals(((IndexedColorMap)cm).iTrans_)) return false;
+    if(colors_.length != ((IndexedColorMap)cm).colors_.length) return false;
+    for(int i=0; i < colors_.length; i++) {
+      if(!colors_[i].equals(((IndexedColorMap)cm).colors_[i])) return false;
+    }
+    return true;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/InvalidMethodError.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/InvalidMethodError.java
new file mode 100755
index 0000000..8d135e0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/InvalidMethodError.java
@@ -0,0 +1,28 @@
+/**
+ * $Id: InvalidMethodError.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Method called with invalid arguements.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class InvalidMethodError extends java.lang.Error {
+  public InvalidMethodError() {
+    super();
+}
+  public InvalidMethodError(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/JPane.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/JPane.java
new file mode 100755
index 0000000..8896690
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/JPane.java
@@ -0,0 +1,754 @@
+/*
+ * $Id: JPane.java,v 1.1.1.2 2008/12/19 13:29:30 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.sgt.beans.Panel;
+
+import java.awt.Rectangle;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.AWTEvent;
+
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.SwingConstants;
+//import javax.swing.RepaintManager;
+import javax.swing.border.Border;
+import java.awt.print.*;
+import java.awt.Graphics2D;
+import java.awt.Color;
+import java.awt.geom.AffineTransform;
+
+/**
+ * The <code>JPane</code> class is extended from
+ * <code>javax.swing.JLayeredPane</code>
+ * and is the basis for using the <code>gov.noaa.pmel.sgt</code>
+ * package with swing components.
+ * <p>
+ * The Java scientific graphics toolkit is designed to allow a
+ * graphics client developer a great deal of flexibility and freedom.
+ * <code>sgt</code> is a package that greatly aids a developer in
+ * creating graphics applets. <code>sgt</code> is not a general
+ * purpose graphics package, but provides the tools to enable
+ * scientific graphics to be easily incorporated into <code>JApplet</code>.
+ * <p>
+ * <code>sgt</code> has three main components, the "pane", on which
+ * all graphics are drawn. The <code>JPane</code> is a fairly simple
+ * class and all drawing is done in "device" coordinates (pixels).
+ * By default, the <code>JPane</code> will draw on the screen, but it is
+ * designed to allow drawing in an offscreen buffer that can be
+ * printed (for applications).
+ * <p>
+ * The next component is the <code>Layer</code>. Several
+ * <code>Layer</code>s can be associated with a single
+ * <code>JPane</code>. The <code>Layer</code> class insulates
+ * the developer from the details of device coordinates by
+ * using "physical" coordinates. Physical coordinates are
+ * a right-hand coordinate systems with an origin of (0.0, 0.0) in the
+ * lower-left-hand corner and have the same scale in both the vertical
+ * and horizontal directions. Thus, a <code>Layer</code> that is
+ * 5.0 units wide and 3.0 units high can be made larger and smaller
+ * on the screen by resizing the <code>JPane</code>, but will not be
+ * distorted. The <code>Layer</code> class is responsible for
+ * displaying labels, keys (color, vector, and line), and rulers.
+ * A <code>Layer</code> can contain a single <code>Graph</code>.
+ * <p>
+ * Finally, the <code>Graph</code> component transforms from
+ * user coordinates (e.g. cm/sec, time, degC, or meters) to
+ * physical coordinates. The <code>Graph</code>
+ * classes handle the display of axes and data. Children of
+ * the <code>Graph</code> class are capable of creating Cartesian,
+ * polar, and map graphics. For Cartesian graphs, several different
+ * axes (log, plain and time), transforms (linear, log, and
+ * tablelookup), and <code>CartesianGraph</code> (pixel,
+ * line, vector, and contour) classes are available. These classes can be
+ * combined in almost any combination.
+ * <p>
+ * While only one dataset may be plotted per <code>Layer</code>,
+ * co-plotting is supported by allowing layers to use the same
+ * transform objects. The order that the layers are plotted can
+ * be changed, allowing the developer (or user) to control what
+ * may be obscured.
+ * <p>
+ * Member functions, in package <code>gov.noaa.pmel.sgt</code>,
+ * follow the following naming convention.  Member functions that
+ * have a <B>P</B>, <B>U</B>, or <I>nothing</I> at the end of the
+ * function name are of type double in <B>P</B>hysical
+ * units, type double in <B>U</B>ser units, and type int in Device
+ * units, respectively.
+ * Variables that start with p, u, t, or d are coordinates of type physical,
+ * user, time, or device, respectively.
+ * <p>
+ * All graphics are rendered when the <code>draw()</code> method is invoked.
+ * <p>
+ * <B>Mouse Events</B>
+ * <p>
+ * Mouse events are processed by the <code>JPane</code> object to support
+ * object selection and zooming. Object selection is accomplished by
+ * left clicking the mouse on the desired object.  <code>JPane</code>
+ * then fires a <code>PropertyChangeEvent</code> of type
+ * "objectSelected" that can be listened for by the users application.
+ * The user application then invokes the
+ * <code>getSelectedObject()</code> method. Zooming is accomplished in
+ * several steps.
+ * <p>
+ *
+ * <pre>
+ * 1) Begin a zoom operation by pressing the left button.
+ * 2) Describe a zoom rectangle by dragging the mouse with the left
+ *    button down.
+ * 3) Finish the zoom operation by releasing the left mouse button.
+ * </pre>
+ *
+ * <p>
+ * When the mouse button has been release <code>JPane</code> fires a
+ * <code>PropertyChangeEvent</code> of type "zoomRectangle" that can
+ * be listened for by the users application.  The user application can
+ * then obtain the zoom rectangle by invoking the
+ * <code>getZoomBounds()</code> method.
+ *
+ * <A NAME="example"><!-- --></A>
+ * <pre>
+ * ...
+ * //
+ * // register the PropertyChangeListener listener with pane
+ * // (assuming that application implements <code>PropertyChangeListener</code>)
+ * //
+ * mainPane_.addPropertyChangeListener(this);
+ * //
+ * ...
+ * //
+ * // Implement the propertyChange() method and listen for events
+ * //
+ *  public void propertyChange(PropertyChangeEvent event) {
+ *    //
+ *    // Listen for property change events from JPane
+ *    //
+ *    String name = event.getPropertyName();
+ *    if(name.equals("zoomRectangle")) {
+ *      //
+ *      // compute zoom rectangle in user units
+ *      //
+ *      Range2D xr = new Range2D();
+ *      Range2D yr = new Range2D();
+ *      Rectangle zm = (Rectangle)event.getNewValue();
+ *      //
+ *      // if rectangle size is one pixel or less return
+ *      //
+ *      if(zm.width <= 1 || zm.height <= 1) return;
+ *      xr.start = graph_.getXPtoU(layer_.getXDtoP(zm.x));
+ *      xr.end = graph_.getXPtoU(layer_.getXDtoP(zm.x + zm.width));
+ *      if(xr.start > xr.end) {
+ *        double temp = xr.start;
+ *        xr.start = xr.end;
+ *        xr.end = temp;
+ *      }
+ *      yr.start = graph_.getYPtoU(layer_.getYDtoP(zm.y));
+ *      yr.end = graph_.getYPtoU(layer_.getYDtoP(zm.y + zm.height));
+ *      if(yr.start > yr.end) {
+ *        double temp = yr.start;
+ *        yr.start = yr.end;
+ *        yr.end = temp;
+ *      }
+ *      //
+ *      // turn batching on so all changes will appear at the
+ *      // same time
+ *      //
+ *      mainPane_.setBatch(true);
+ *      //
+ *      // set range for transforms
+ *      //
+ *      xt_.setRangeU(xr);
+ *      yt_.setRangeU(yr);
+ *      //
+ *      // set range and origin for axes
+ *      //
+ *      Point2D.Double orig = new Point2D.Double(xr.start, yr.start);
+ *      xbot_.setRangeU(xr);
+ *      xbot_.setLocationU(orig);
+ *
+ *      yleft_.setRangeU(yr);
+ *      yleft_.setLocationU(orig);
+ *      //
+ *      // set clipping on all graphs
+ *      //
+ *      Component[] comps = mainPane_.getComponents();
+ *      Layer ly;
+ *      for(int i=0; i < comps.length; i++) {
+ *        if(comps[i] instanceof Layer) {
+ *          ly = (Layer)comps[i];
+ *          ((CartesianGraph)ly.getGraph()).setClip(xr.start, xr.end,
+ *                                                  yr.start, yr.end);
+ *        }
+ *      }
+ *      //
+ *      // done with sgt modifications, turn batching off
+ *      //
+ *      mainPane_.setBatch(false);
+ *    } else if(name.equals("objectSelected")) {
+ *      //
+ *      // An sgt object has been selected.
+ *      // If it is a PointCartesianRenderer that means the key has been
+ *      // selected and so open a dialog to modified the PointAttribute.
+ *      //
+ *      if(event.getNewValue() instanceof PointCartesianRenderer) {
+ *	  PointAttribute pattr =
+ *	    ((PointCartesianRenderer)event.getNewValue()).getPointAttribute();
+ *	  if(pAttrDialog_ == null) {
+ *	    pAttrDialog_ = new PointAttributeDialog();
+ *	  }
+ *	  pAttrDialog_.setPointAttribute(pattr, mainPane_);
+ *	  pAttrDialog_.setVisible(true);
+ *      } else {
+ *	  //
+ *	  // Print the name of the object selected.
+ *	  //
+ *	  System.out.println("objectSelected = " + event.getNewValue());
+ *      }
+ *    }
+ *  }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:30 $
+ * @since 2.0
+ * @see Layer
+ * @see Graph
+ * @see java.awt.Graphics
+**/
+public class JPane extends javax.swing.JLayeredPane
+//public class JPane extends javax.swing.JComponent
+  implements AbstractPane, javax.swing.Scrollable, Printable {
+  //
+  private PaneProxy proxy_;
+  private int horizBlockIncrement = -1;
+  private int vertBlockIncrement = -1;
+  private int horizUnitIncrement = 1;
+  private int vertUnitIncrement = 1;
+  //
+  /**@shapeType AggregationLink
+   * @supplierCardinality 1..*
+   * @label components*/
+  /*#  Layer lnkUnnamed*/
+
+  /**
+   * Constructs a <code>Pane</code>.
+   *
+   * @param id the <code>Pane</code> identifier
+   * @param size the size of the <code>Pane</code> in pixels
+   **/
+  public JPane(String id, Dimension size) {
+    super();
+    proxy_ = new PaneProxy(this, id, size);
+    setSize(size);
+    //
+    // setup for Low-Level Events
+    //
+    this.enableEvents(AWTEvent.MOUSE_EVENT_MASK |
+                      AWTEvent.MOUSE_MOTION_EVENT_MASK);
+    setDoubleBuffered(false);
+    //
+    //    RepaintManager currentManager = RepaintManager.currentManager(this);
+    //    currentManager.setDoubleBufferingEnabled(false);
+    //
+  }
+  /**
+   * Default constructor.  The identifier is set to an empty string and
+   * the size is set to a width and height of 50 pixels. A default constructor
+   * is required to work as a component with Visual Cafe.
+   *
+   * <pre>
+   * import gov.noaa.pmel.sgt.JPane;
+   * ...
+   * JPane pane;
+   * ...
+   * pane = new JPane("main graph", new Dimension(400, 500));
+   * pane.setLayout(new StackedLayout());
+   * ...
+   * </pre>
+   *
+   * @see StackedLayout
+   *
+   **/
+  public JPane() {
+    this(new String(""), new Dimension(50,50));
+  }
+  /**
+   * Return the version of SGT.
+   * @since 3.0
+   */
+  public static String getVersion() {
+    return PaneProxy.getVersion();
+  }
+  public void draw() {
+    proxy_.setOpaque(isOpaque());
+    proxy_.draw();
+  }
+  /**
+   * No initialization required.
+   */
+  public void init() {
+  }
+  public void draw(Graphics g) {
+    proxy_.setOpaque(isOpaque());
+    proxy_.draw(g);
+  }
+  public void draw(Graphics g, int width, int height) {
+    proxy_.setOpaque(isOpaque());
+    proxy_.draw(g, width, height);
+  }
+  public boolean isPrinter() {
+    return proxy_.isPrinter();
+  }
+  /**
+   * Internal method to access jdk1.1 or Java2D line drawing.
+   */
+  public static StrokeDrawer getStrokeDrawer() {
+    return PaneProxy.strokeDrawer;
+  }
+  public Dimension getPageSize() {
+    return proxy_.getPageSize();
+  }
+  /**
+   * Override default painting by swing.
+   */
+  public void paintComponent(Graphics g) {
+	//System.out.println("Jpane.paintComponent called");
+    super.paintComponent(g);
+    proxy_.paint(g);
+  }
+
+  /**
+   * Adds the specified component to the end of the <code>Pane</code>.
+   *
+   * @param comp the component to be added
+   * @return component argument
+   */
+  public Component add(Component comp) {
+    if(comp instanceof LayerControl) {
+      ((LayerControl)comp).setPane(this);
+    }
+    return super.add(comp);
+  }
+  /**
+   * Adds the specified component to the <code>Pane</code> at the
+   * given position.
+   *
+   * @param comp the component to be added
+   * @param index the position at which to insert the component, or -1
+   to insert the component at the end.
+   * @return component argument
+   */
+  public Component add(Component comp, int index) {
+    if(comp instanceof LayerControl) {
+      ((LayerControl)comp).setPane(this);
+    }
+    return super.add(comp, index);
+  }
+  /**
+   * Adds the specified component to the end of this <code>Pane</code>.
+   * Also notifies the layout manager to add the component to this
+   * <code>Pane</code>'s layout using the specified constraints object.
+   *
+   * @param comp the component to be added
+   * @param constraints an object expressing layout constraints for
+   this component
+  */
+  public void add(Component comp, Object constraints) {
+    super.add(comp, constraints);
+    if(comp instanceof LayerControl) {
+      ((LayerControl)comp).setPane(this);
+    }
+  }
+  /**
+   * Adds the specified component to the end of this <code>Pane</code>
+   * at the specified index.
+   * Also notifies the layout manager to add the component to this
+   * <code>Pane</code>'s layout using the specified constraints object.
+   *
+   * @param comp the component to be added
+   * @param constraints an object expressing layout constraints for
+   this component
+   * @param index the position in the <code>Pane</code>'s list at which to
+   insert the component -1 means insert at the end.
+  */
+  public void add(Component comp, Object constraints, int index) {
+    super.add(comp, constraints, index);
+    if(comp instanceof LayerControl) {
+      ((LayerControl)comp).setPane(this);
+    }
+  }
+  /**
+   * Adds the specified component to this <code>Pane</code>. It
+   * is strongly advised to use add(Component, Object), in place
+   * of this method.
+   */
+  public Component add(String name, Component comp) {
+    if(comp instanceof LayerControl) {
+      ((LayerControl)comp).setPane(this);
+    }
+    return super.add(name, comp);
+  }
+
+  public String getId() {
+    return proxy_.getId();
+  }
+  public void setId(String id) {
+    proxy_.setId(id);
+  }
+  public void setPageAlign(int vert,int horz) {
+    proxy_.setPageAlign(vert, horz);
+  }
+  public void setPageVAlign(int vert) {
+    proxy_.setPageVAlign(vert);
+  }
+  public void setPageHAlign(int horz) {
+    proxy_.setPageHAlign(horz);
+  }
+  public int getPageVAlign() {
+    return proxy_.getPageVAlign();
+  }
+  public int getPageHAlign() {
+    return proxy_.getPageHAlign();
+  }
+  public void setPageOrigin(Point p) {
+    proxy_.setPageOrigin(p);
+  }
+  public Point getPageOrigin() {
+    return proxy_.getPageOrigin();
+  }
+  /**
+   * Set the size.
+   */
+  public void setSize(Dimension d) {
+    super.setSize(d);
+    if(Debug.DEBUG) System.out.println("JPane: setSize()");
+    proxy_.setSize(d);
+  }
+  public Layer getFirstLayer() {
+    return proxy_.getFirstLayer();
+  }
+  public Layer getLayer(String id) throws LayerNotFoundException  {
+    return proxy_.getLayer(id);
+  }
+  public Layer getLayerFromDataId(String id) throws LayerNotFoundException  {
+    return proxy_.getLayerFromDataId(id);
+  }
+  /**
+   * Move the <code>Layer</code> up in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> up causes the
+   * <code>Layer</code> to be drawn later and over earlier
+   * layers.
+   *
+   * @param lyr <code>Layer</code> object.
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerUp(Layer lyr) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Move the <code>Layer</code> up in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> up causes the
+   * <code>Layer</code> to be drawn later and over earlier
+   * layers.
+   *
+   * @param id identifier.
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerUp(String id) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Move the <code>Layer</code> down in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> down causes the
+   * <code>Layer</code> to be drawn earlier.
+   *
+   * @param lyr <code>Layer</code> object.
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerDown(Layer lyr) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Move the <code>Layer</code> down in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> down causes the
+   * <code>Layer</code> to be drawn earlier.
+   *
+   * @param id identifier
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerDown(String id) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  public Object getSelectedObject() {
+    return proxy_.getSelectedObject();
+  }
+  public void setSelectedObject(Object obj) {
+    proxy_.setSelectedObject(obj);
+  }
+  /**
+   * Overrides the default event methods.
+   **/
+  public void processMouseEvent(MouseEvent event) {
+    if(!proxy_.processMouseEvent(event))
+      super.processMouseEvent(event);
+  }
+  /**
+   * Used internally by sgt.
+   */
+  public void processMouseMotionEvent(MouseEvent event) {
+    if(!proxy_.processMouseMotionEvent(event))
+      super.processMouseMotionEvent(event);
+  }
+  /**
+   * Get the current zoom bounding box.
+   */
+  public Rectangle getZoomBounds() {
+    return proxy_.getZoomBounds();
+  }
+  /**
+   * @since 3.0
+   */
+  public Point getZoomStart() {
+    return proxy_.getZoomStart();
+  }
+  public Object getObjectAt(int x, int y) {
+    return proxy_.getObjectAt(x,y);
+  }
+  /**
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(int x, int y) {
+    return proxy_.getObjectsAt(x,y);
+  }
+  /**
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(Point pt) {
+    return proxy_.getObjectsAt(pt.x, pt.y);
+  }
+  public Component getComponent() {
+    return (Component)this;
+  }
+
+  public Dimension getMaximumSize() {
+    return proxy_.getMaximumSize();
+  }
+  public Dimension getMinimumSize() {
+    return proxy_.getMinimumSize();
+  }
+  public Dimension getPreferredSize() {
+    return proxy_.getPreferredSize();
+  }
+  /**
+   * Get a <code>String</code> representatinof the
+   * <code>Pane</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    return proxy_.toString();
+  }
+  public void setBatch(boolean batch, String msg) {
+    proxy_.setBatch(batch, msg);
+  }
+  public void setBatch(boolean batch) {
+    proxy_.setBatch(batch, "");
+  }
+  public boolean isBatch() {
+    return proxy_.isBatch();
+  }
+  public void setModified(boolean mod, String mess) {
+    proxy_.setModified(mod, mess);
+  }
+  public boolean isModified() {
+    return proxy_.isModified();
+  }
+  /**
+   * @since 3.0
+   */
+  public void setMouseEventsEnabled(boolean enable) {
+    proxy_.setMouseEventsEnabled(enable);
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean isMouseEventsEnabled() {
+    return proxy_.isMouseEventsEnabled();
+  }
+  /**
+   * Set the horizontal and vertical block increments.
+   */
+  public void setScrollableBlockIncrement(int horiz, int vert) {
+    horizBlockIncrement = horiz;
+    vertBlockIncrement = vert;
+  }
+  public int getScrollableBlockIncrement(Rectangle visibleRect,
+                                         int orientation,
+                                         int direction) {
+    if(orientation == SwingConstants.HORIZONTAL) {
+      if(horizBlockIncrement <= 0) {
+        return getVisibleRect().width;
+      } else {
+        return horizBlockIncrement;
+      }
+    } else {
+      if(vertBlockIncrement <= 0) {
+        return getVisibleRect().height;
+      } else {
+        return vertBlockIncrement;
+      }
+    }
+  }
+  /**
+   * Set the horizontal and vertical unit increments.
+   */
+  public void setScrollableUnitIncrement(int horiz, int vert) {
+    horizUnitIncrement = horiz;
+    vertUnitIncrement = vert;
+  }
+  public int getScrollableUnitIncrement(Rectangle visibleRect,
+                                        int orientation,
+                                        int direction) {
+    if(orientation == SwingConstants.HORIZONTAL) {
+      if(horizUnitIncrement <= 0) {
+        return 1;
+      } else {
+        return horizUnitIncrement;
+      }
+    } else {
+      if(vertUnitIncrement <= 0) {
+        return 1;
+      } else {
+        return vertUnitIncrement;
+      }
+    }
+  }
+  public Dimension getPreferredScrollableViewportSize() {
+    return getSize();
+  }
+  public boolean getScrollableTracksViewportHeight() {
+    return false;
+  }
+  public boolean getScrollableTracksViewportWidth() {
+    return false;
+  }
+
+  public int print(Graphics g, PageFormat pf, int pageIndex) {
+    if(pageIndex > 0) {
+      return NO_SUCH_PAGE;
+    } else {
+      drawPage(g, pf);
+      return PAGE_EXISTS;
+    }
+  }
+  public void setPageScaleMode(int mode) {
+    proxy_.setPageScaleMode(mode);
+  }
+  public int  getPageScaleMode() {
+    return proxy_.getPageScaleMode();
+  }
+
+  public void drawPage(Graphics g, PageFormat pf, boolean scale) {
+    if(scale) {
+      drawPage(g, pf);
+    } else {
+      proxy_.drawPage(g, pf.getImageableWidth(), pf.getImageableHeight());
+    }
+  }
+  /**
+   * Used by internally by sgt.
+   */
+  protected void drawPage(Graphics g, PageFormat pf) {
+    Dimension d = getSize();
+    Point pageOrigin = null;
+    pageOrigin = proxy_.getPageOrigin();
+    if(pageOrigin == null) pageOrigin = new Point(0,0);
+    Graphics2D g2 = (Graphics2D)g;
+
+    double scale = 1.0;
+    double dx = pf.getImageableX();
+    double dy = pf.getImageableY();
+    int scaleMode = proxy_.getPageScaleMode();
+    if(scaleMode == AbstractPane.TO_FIT ||
+       scaleMode == AbstractPane.SHRINK_TO_FIT) {
+      double yf = pf.getImageableHeight()/d.getHeight();
+      double xf = pf.getImageableWidth()/d.getWidth();
+      if(xf < yf) {
+        scale = xf;
+      } else if(xf > yf) {
+        scale = yf;
+      }
+      if(scaleMode == AbstractPane.SHRINK_TO_FIT && scale > 1.0) scale = 1.0;
+    }
+
+    switch(proxy_.getPageHAlign()) {
+      default:
+      case AbstractPane.CENTER:
+        dx += (pf.getImageableWidth() - scale*d.getWidth())/2.0;
+        break;
+      case AbstractPane.RIGHT:
+        dx += pf.getImageableWidth() - scale*d.getWidth();
+        break;
+      case AbstractPane.LEFT:
+        // do nothing
+        break;
+      case AbstractPane.SPECIFIED_LOCATION:
+        dx += pageOrigin.x;
+        break;
+    }
+
+    switch(proxy_.getPageVAlign()) {
+      default:
+      case AbstractPane.TOP:
+        // do nothing
+        break;
+      case AbstractPane.BOTTOM:
+        dy += pf.getImageableHeight() - scale*d.getHeight();
+        break;
+      case AbstractPane.MIDDLE:
+        dy += (pf.getImageableHeight() - scale*d.getHeight())/2.0;
+        break;
+      case AbstractPane.SPECIFIED_LOCATION:
+        dy += pageOrigin.y;
+        break;
+    }
+    g.clipRect(-1000, -1000, 2000, 2000);
+//    g.clipRect(Integer.MIN_VALUE, Integer.MIN_VALUE,
+//               Integer.MAX_VALUE, Integer.MAX_VALUE);
+    g2.translate(dx, dy);
+    g2.scale(scale, scale);
+    proxy_.drawPage(g, pf.getImageableWidth(), pf.getImageableHeight());
+  }
+  /*
+   * Pane PropertyChange methods
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    proxy_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    proxy_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer.java
new file mode 100755
index 0000000..8173296
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer.java
@@ -0,0 +1,207 @@
+/*
+ * $Id: LabelDrawer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.awt.*;
+
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import java.io.Serializable;
+
+/**
+ * Defines the methods that implement label drawing in sgt. This
+ * interface is necessary since sgt v2.0 will use Java2D functionality
+ * to draw labels if it is available.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public interface LabelDrawer extends Serializable {
+  /**
+   * Used internally by sgt.
+   */
+  public void draw(Graphics g) throws LayerNotFoundException;
+  /**
+   * Set the label text.
+   *
+   * @param lbl the label text
+   **/
+  public void setText(String lbl);
+  /**
+   * Get the label text.
+   *
+   * @return the label text
+   **/
+  public String getText();
+  /**
+   * Get the color.
+   *
+   * @return The current color of the label.
+   **/
+  public Color getColor();
+  /**
+   * Set the color.
+   *
+   * @param color The color of the label.
+   * @see java.awt.Color
+   **/
+  public void setColor(Color clr);
+  /**
+   * Set the font.
+   *
+   * @param fnt The Font to use to draw the label.
+   * @see java.awt.Font
+   **/
+  public void setFont(Font font);
+  /**
+   * Get the font.
+   *
+   * @return The current font for the label.
+   **/
+  public Font getFont();
+  /**
+   * Used internally by sgt.
+   **/
+  public void setLayer(Layer layer);
+  /**
+   * Get the layer.
+   *
+   * @return the layer object.
+   **/
+  public Layer getLayer();
+  /**
+   * Set the orientation. The orientation can be HORIZONTAL or
+   * VERTICAL.
+   *
+   * @param orient The orientation.
+   **/
+  public void setOrientation(int orient);
+  /**
+   * Get the origentation.
+   *
+   * @return the orientation
+   **/
+  public int getOrientation();
+  /**
+   * Set the horizontal alignment. The alignment can be LEFT, CENTER,
+   * or RIGHT.
+   *
+   * @param horz The horizontal alignment.
+   **/
+  public void setHAlign(int halign);
+  /**
+   * Get the horizontal alignment.
+   *
+   * @return the horizontal alignment.
+   **/
+  public int getHAlign();
+  /**
+   * Set the vertical alignment. The alignment can be TOP, MIDDLE,
+   * or BOTTOM.
+   *
+   * @param vert The vertical alignment.
+   **/
+  public void setVAlign(int valign);
+  /**
+   * Get the vertical alignment.
+   *
+   * @return the vertical alignment.
+   **/
+  public int getVAlign();
+  /**
+   * Set the label position in device coordinates.
+   *
+   * @param loc label position
+   **/
+  public void setLocation(Point loc);
+  /**
+   * Get the label position in device coordinates.
+   *
+   * @return the label position
+   **/
+  public Point getLocation();
+  /**
+   * Set the label bounds in device units.
+   *
+   * @param x x location of label
+   * @param y y location of label
+   * @param width label width
+   * @param height label height
+   */
+  public void setBounds(int x, int y, int width, int height);
+  /**
+   * Get the label bounds in device units.
+   *
+   * @return the label bounds
+   **/
+  public Rectangle getBounds();
+  /**
+   * Set the label reference location in physcial coordinates.
+   *
+   * @param loc physical location of label
+   **/
+  public void setLocationP(Point2D.Double loc);
+  /**
+   * Get the label reference location in physcial coordinates.
+   *
+   * @return the labels position.
+   **/
+  public Point2D.Double getLocationP();
+  /**
+   * Get the label reference location in physcial coordinates.
+   *
+   * @return the labels position.
+   **/
+  public Rectangle2D.Double getBoundsP();
+  /**
+   * Draw label at arbitrary rotation.  Warning: Rotated labels are
+   * not drawn very well when using JDK1.1. For best results use
+   * JDK1.2 or newer.
+   */
+  public void setAngle(double angle);
+  /**
+   * Get label drawing angle.
+   */
+  public double getAngle();
+  /**
+   * Set the height of the label in physical coordinates.
+   *
+   * @param hgt The label height.
+   **/
+  public void setHeightP(double hgt);
+  /**
+   * Get the label height in physical coordinates.
+   *
+   * @return The label height.
+   **/
+  public double getHeightP();
+  /**
+   * Set visibility of label.
+   */
+  public void setVisible(boolean vis);
+  /**
+   * Is label visible?
+   */
+  public boolean isVisible();
+  /**
+   * Get the string width in device units.
+   */
+  public float getStringWidth(Graphics g);
+  /**
+   * Get the string height in device units.
+   */
+  public float getStringHeight(Graphics g);
+}
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer1.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer1.java
new file mode 100755
index 0000000..e46e102
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer1.java
@@ -0,0 +1,578 @@
+/*
+ * $Id: LabelDrawer1.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+
+import  java.awt.image.PixelGrabber;
+import  java.awt.image.MemoryImageSource;
+import  java.awt.image.ColorModel;
+import  java.awt.image.ImageObserver;
+import  java.awt.*;
+
+/**
+ * Implements label drawing for JDK1.1
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public class LabelDrawer1 implements LabelDrawer, Cloneable {
+  private String label_;
+  private Color clr_;
+  private Font font_;
+  private transient Layer layer_;
+  private int orient_;
+  private int halign_;
+  private int valign_;
+  private Point dorigin_;
+  private Rectangle dbounds_;
+  private Point2D.Double porigin_;
+  private Rectangle2D.Double pbounds_;
+  private Polygon dpolygon_;
+  private double angle_;
+  private double sinthta_;
+  private double costhta_;
+  private double height_;
+  private boolean visible_;
+  private Rectangle savedBounds_ = null;
+  private Point savedLoc_ = null;
+
+  public LabelDrawer1(String lbl, double hgt, Point2D.Double loc,
+                      int valign, int halign) {
+    label_ = lbl;
+    height_ = hgt;
+    porigin_ = loc;
+    valign_ = valign;
+    halign_ = halign;
+    //
+    dbounds_ = new Rectangle();
+    dorigin_ = new Point(0,0);
+    pbounds_ = new Rectangle2D.Double();
+  }
+
+  public LabelDrawer copy() {
+    LabelDrawer1 newLabel = null;
+//      try {
+//        newLabel = (LabelDrawer1)clone();
+//      } catch (CloneNotSupportedException e) {
+//        newLabel = new LabelDrawer1(ident_, label_, height_,
+//  			     porigin_, valign_, halign_);
+//        newLabel.setColor(clr_);
+//        newLabel.setFont(font_);
+//        if(orient_ == ANGLE) {
+//  	newLabel.setAngle(angle_);
+//        } else {
+//  	newLabel.setOrientation(orient_);
+//        }
+//      }
+    return newLabel;
+  }
+  public void draw(Graphics g) throws LayerNotFoundException  {
+    FontMetrics fmet;
+    int xs, ys;
+    if((label_.length() <= 0) || !visible_ || g == null) return;
+    if(layer_ == (Layer) null) throw new LayerNotFoundException();
+    //
+    // set label heigth in physical units
+    //
+    computeBoundsD(g);
+    fmet = g.getFontMetrics();
+    if(clr_ == null) {
+      g.setColor(layer_.getPane().getComponent().getForeground());
+    } else {
+      g.setColor(clr_);
+    }
+    if(orient_ == SGLabel.HORIZONTAL) {
+      xs = dbounds_.x;
+      ys = dbounds_.y + fmet.getMaxAscent();
+      g.drawString(label_, xs, ys);
+    } else if(orient_ == SGLabel.VERTICAL) {
+      //
+      // draw text in offscreen image (horizontal)
+      //
+      int i, j;
+      // make sure bounds are >= 1 pixel!  RWS
+      if(dbounds_.height < 1) dbounds_.height = 1;
+      if(dbounds_.width < 1) dbounds_.width = 1;
+      //
+      Image buf = layer_.getPane().getComponent().createImage(dbounds_.height, dbounds_.width);
+      Graphics gbuf = buf.getGraphics();
+      gbuf.setFont(g.getFont());
+      //
+      gbuf.setColor(layer_.getPane().getComponent().getBackground());
+      gbuf.fillRect(0, 0, dbounds_.height, dbounds_.width);
+      if(clr_ == null) {
+        gbuf.setColor(layer_.getPane().getComponent().getForeground());
+      } else {
+        gbuf.setColor(clr_);
+      }
+      gbuf.drawString(label_, 0, fmet.getMaxAscent());
+      //
+      // create offscreen image (vertical) and copy pixels
+      //
+      int[] bufpix = new int[dbounds_.width * dbounds_.height];
+      int[] vbufpix = new int[dbounds_.width * dbounds_.height];
+      PixelGrabber pg =
+        new PixelGrabber(buf, 0, 0, dbounds_.height, dbounds_.width,
+                         bufpix, 0, dbounds_.height);
+      try {
+        pg.grabPixels();
+      } catch (InterruptedException e) {System.out.println(e);}
+      for(i=0; i < dbounds_.height; i++) {
+        for(j=0; j < dbounds_.width; j++) {
+          vbufpix[j + (dbounds_.height - i - 1)*dbounds_.width]
+            = bufpix[i + j*dbounds_.height];
+        }
+      }
+      ColorModel cm = ColorModel.getRGBdefault();
+      Image vbuf = layer_.getPane().getComponent().createImage(
+                      new MemoryImageSource(dbounds_.width,
+                                            dbounds_.height,
+                                            cm,
+                                            vbufpix,
+                                            0,
+                                            dbounds_.width));
+      //
+      // copy offscreen area to screen (with rotation)
+      //
+      g.setPaintMode();
+      g.drawImage(vbuf, dbounds_.x, dbounds_.y,
+                  layer_.getPane().getComponent());
+    } else {
+      //
+      // Angled text, draw in offscreen image and rotate
+      //
+      if(dbounds_.height < 1 || dbounds_.width < 1) return;
+      int i, j;
+      int ii, jj;
+      int pixel;
+      //
+      int[] xpoly = dpolygon_.xpoints;
+      int[] ypoly = dpolygon_.ypoints;
+      int rectHeight = fmet.getMaxAscent() + fmet.getMaxDescent();
+      int rectWidth = fmet.stringWidth(label_);
+      int xoff, yoff;
+      Image buf =
+        layer_.getPane().getComponent().createImage(rectWidth, rectHeight);
+      Graphics gbuf = buf.getGraphics();
+      gbuf.setFont(g.getFont());
+      //
+      gbuf.setColor(layer_.getPane().getComponent().getBackground());
+      gbuf.fillRect(0, 0, rectWidth, rectHeight);
+      if(clr_ == null) {
+        gbuf.setColor(layer_.getPane().getComponent().getForeground());
+      } else {
+        gbuf.setColor(clr_);
+      }
+      gbuf.drawString(label_, 0, fmet.getMaxAscent());
+      //
+      // create offscreen image (vertical) and copy pixels
+      //
+      int[] bufpix = new int[rectWidth * rectHeight];
+      int[] vbufpix = new int[dbounds_.width * dbounds_.height];
+      PixelGrabber pg =
+        new PixelGrabber(buf, 0, 0, rectWidth, rectHeight,
+                         bufpix, 0, rectWidth);
+      try {
+        pg.grabPixels();
+      } catch (InterruptedException e) {System.out.println(e);}
+      //
+      // compute transformation
+      //
+      xoff = 0;
+      yoff = 0;
+      for(i=1; i < 4; i++) {
+        xoff = Math.min(xoff, xpoly[i]-xpoly[0]);
+        yoff = Math.min(yoff, ypoly[i]-ypoly[0]);
+      }
+      xoff = -xoff;
+      yoff = -yoff;
+      //      double[] dx = {0.0, 0.5, -0.5,  0.5, -0.5};
+      //      double[] dy = {0.0, 0.5, -0.5, -0.5,  0.5};
+      double[] dx = {0.0, 0.5};
+      double[] dy = {0.0, 0.5};
+      double it, jt;
+      for(j=0; j < rectHeight; j++) {
+        for(i=0; i < rectWidth; i++) {
+          for(int k=0; k < dx.length; k++) {
+            it = i + dx[k];
+            jt = j + dy[k];
+            //	  pixel = bufpix[i + j*rectWidth];
+          pixel = bufpix[i + j*rectWidth];
+          if(pixel == -1) continue;
+          //	  ii = (int)(i*costhta_ + j*sinthta_ + 0.5) + xoff;
+          //	  jj = (int)(j*costhta_ - i*sinthta_ + 0.5) + yoff;
+          ii = (int)(it*costhta_ + jt*sinthta_ + 0.5) + xoff;
+          jj = (int)(jt*costhta_ - it*sinthta_ + 0.5) + yoff;
+          if(ii < 0) ii=0;
+          if(ii >= dbounds_.width) ii = dbounds_.width-1;
+          if(jj < 0) jj=0;
+          if(jj >= dbounds_.height) jj = dbounds_.height-1;
+          vbufpix[ii + jj*dbounds_.width] = pixel;
+          }
+        }
+      }
+      ColorModel cm = ColorModel.getRGBdefault();
+      Image vbuf = layer_.getPane().getComponent().createImage(
+                      new MemoryImageSource(dbounds_.width,
+                                            dbounds_.height,
+                                            cm,
+                                            vbufpix,
+                                            0,
+                                            dbounds_.width));
+      //
+      // copy offscreen area to screen (with rotation)
+      //
+      g.setPaintMode();
+      g.drawImage(vbuf, dbounds_.x, dbounds_.y,
+                  layer_.getPane().getComponent());
+    }
+  }
+
+  public void setText(String lbl) {
+    label_ = lbl;
+  }
+  public String getText() {
+    return label_;
+  }
+
+  public void setColor(Color clr) {
+    clr_ = clr;
+  }
+  public Color getColor() {
+    return clr_;
+  }
+
+  public void setFont(Font font) {
+    font_ = font;
+  }
+  public Font getFont() {
+    return font_;
+  }
+
+  public void setLayer(Layer layer) {
+    layer_ = layer;
+    if(savedBounds_ != null) {
+      setBounds(savedBounds_.x, savedBounds_.y,
+                savedBounds_.width, savedBounds_.height);
+      savedBounds_ = null;
+    }
+    if(savedLoc_ != null) {
+      setLocation(savedLoc_);
+      savedLoc_ = null;
+    }
+  }
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public void setOrientation(int orient) {
+    if(orient_ != orient) {
+      if(orient == SGLabel.HORIZONTAL) {
+        costhta_ = 1.0;
+        sinthta_ = 0.0;
+      } else if(orient == SGLabel.VERTICAL) {
+        costhta_ = 0.0;
+        sinthta_ = 1.0;
+      }
+      orient_ = orient;
+    }
+  }
+  public int getOrientation() {
+    return orient_;
+  }
+
+  public void setHAlign(int halign) {
+    halign_ = halign;
+  }
+  public int getHAlign() {
+    return halign_;
+  }
+
+  public void setVAlign(int valign) {
+    valign_ = valign;
+  }
+  public int getVAlign() {
+    return valign_;
+  }
+
+  public void setLocation(Point loc) {
+    if(layer_ == null) {
+      savedLoc_ = new Point(loc);
+      return;
+    }
+    computeBoundsD(layer_.getPane().getComponent().getGraphics());
+    //    if(dbounds_.x != loc.x || dbounds_.y != loc.y) {
+    //      Point temp = new Point(dbounds_.x, dbounds_.y);
+      setBounds(loc.x, loc.y, dbounds_.width, dbounds_.height);
+//        changes_.firePropertyChange("location",
+//  				  temp,
+//  				  loc);
+      //    }
+  }
+  public Point getLocation() {
+    if(savedLoc_ != null) return savedLoc_;
+    return dorigin_;
+  }
+
+  public void setBounds(int x, int y, int width, int height) {
+    int swidth, sascent, xd, yd;
+    FontMetrics fmet;
+    if(layer_ == null) {
+      savedBounds_ = new Rectangle(x, y, width, height);
+      return;
+    }
+    Graphics g = layer_.getPane().getComponent().getGraphics();
+    if(g == null) return;
+    g.setFont(font_);
+    fmet = g.getFontMetrics();
+    sascent = fmet.getAscent();
+    if(orient_ == SGLabel.HORIZONTAL) {
+      swidth = width;
+      xd = x;
+      //      yd = y + fmet.getMaxAscent();
+      yd = y -fmet.getMaxDescent() + height;
+      switch(valign_) {
+      case SGLabel.TOP:
+        yd = yd - sascent;
+        break;
+      case SGLabel.MIDDLE:
+        yd = yd - sascent/2;
+        break;
+      case SGLabel.BOTTOM:
+      }
+      switch(halign_) {
+      case SGLabel.RIGHT:
+        xd = xd + swidth;
+        break;
+      case SGLabel.CENTER:
+        xd = xd + swidth/2;
+        break;
+      case SGLabel.LEFT:
+      }
+    } else {
+      swidth = height;
+      yd = y + height;
+      xd = x + fmet.getMaxAscent();
+      switch(valign_) {
+      case SGLabel.TOP:
+        xd = xd - sascent;
+        break;
+      case SGLabel.MIDDLE:
+        xd = xd - sascent/2;
+        break;
+      case SGLabel.BOTTOM:
+      }
+      switch(halign_) {
+      case SGLabel.RIGHT:
+        yd = yd - swidth;
+        break;
+      case SGLabel.CENTER:
+        yd = yd - swidth/2;
+        break;
+      case SGLabel.LEFT:
+      }
+    }
+    if(dorigin_.x != xd || dorigin_.y != yd) {
+      dorigin_.x = xd;
+      dorigin_.y = yd;
+      porigin_.x = layer_.getXDtoP(xd);
+      porigin_.y = layer_.getYDtoP(yd);
+      //      modified("LabelDrawer1: setBounds()");
+    }
+  }
+  public Rectangle getBounds() {
+    if(savedBounds_ != null) return savedBounds_;
+    if(layer_ != null) computeBoundsD(layer_.getPane().getComponent().getGraphics());
+    return dbounds_;
+  }
+
+  public void setLocationP(Point2D.Double loc) {
+    porigin_ = loc;
+  }
+  public Point2D.Double getLocationP() {
+    return porigin_;
+  }
+
+  public Rectangle2D.Double getBoundsP() {
+    computeBoundsD(layer_.getPane().getComponent().getGraphics());
+    return pbounds_;
+  }
+
+  public void setAngle(double angle) {
+    angle_ = angle;
+    double thta = angle_*Math.PI/180.0;
+    if(Math.abs(thta) < 0.001) {
+      orient_ = SGLabel.HORIZONTAL;
+      costhta_ = 1.0;
+      sinthta_ = 0.0;
+    } else if(Math.abs(thta - 90.0) < 0.001) {
+      orient_ = SGLabel.VERTICAL;
+      costhta_ = 0.0;
+      sinthta_ = 1.0;
+    } else {
+      orient_ = SGLabel.ANGLE;
+      costhta_ = Math.cos(thta);
+      sinthta_ = Math.sin(thta);
+    }
+  }
+  public double getAngle() {
+    return angle_;
+  }
+
+  public void setHeightP(double hgt) {
+    height_ = hgt;
+  }
+  public double getHeightP() {
+    return height_;
+  }
+
+  public void setVisible(boolean vis) {
+    visible_ = vis;
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+
+  private void computeBoundsD(Graphics g) {
+    int swidth, sheight, sascent, xd, yd;
+    int xorig, yorig;
+    int[] xt = new int[4];
+    int[] yt = new int[4];
+    int[] xn = new int[4];
+    int[] yn = new int[4];
+    FontMetrics fmet;
+    //
+    // compute size of font and adjust to be height tall!
+    //
+    if(g == null) return;
+    font_ = computeFontSize(g);
+    g.setFont(font_);
+    fmet = g.getFontMetrics();
+    //
+    swidth = fmet.stringWidth(label_);
+    sascent = fmet.getAscent();
+    //
+    xd = layer_.getXPtoD(porigin_.x);
+    yd = layer_.getYPtoD(porigin_.y);
+    //
+    // set device origin
+    //
+    dorigin_.x = xd;
+    dorigin_.y = yd;
+    xorig = xd;
+    yorig = yd;
+    //
+    switch(valign_) {
+    case SGLabel.TOP:
+      yd = yd + sascent;
+      break;
+    case SGLabel.MIDDLE:
+      yd = yd + sascent/2;
+      break;
+    case SGLabel.BOTTOM:
+    }
+    switch(halign_) {
+    case SGLabel.RIGHT:
+      xd = xd - swidth;
+      break;
+    case SGLabel.CENTER:
+      xd = xd - swidth/2;
+      break;
+    case SGLabel.LEFT:
+    }
+    xt[0] = xd;
+    xt[1] = xt[0];
+    xt[2] = xt[0] + swidth;
+    xt[3] = xt[2];
+
+    sheight = fmet.getMaxAscent() + fmet.getMaxDescent();
+    yt[0] = yd + fmet.getMaxDescent() - sheight;
+    yt[1] = yt[0] + sheight;
+    yt[2] = yt[1];
+    yt[3] = yt[0];
+    //
+    // rotate
+    //
+    for(int i=0; i < 4; i++) {
+      xn[i] = (int)((xt[i]-xorig)*costhta_ + (yt[i]-yorig)*sinthta_) + xorig;
+      yn[i] = (int)((yt[i]-yorig)*costhta_ - (xt[i]-xorig)*sinthta_) + yorig;
+    }
+    dpolygon_ = new Polygon(xn, yn, 4);
+    dbounds_ = dpolygon_.getBounds();
+    //
+    // compute pbounds
+    //
+    pbounds_.x = layer_.getXDtoP(dbounds_.x);
+    pbounds_.y = layer_.getYDtoP(dbounds_.y);
+    pbounds_.width = layer_.getXDtoP(dbounds_.x +
+                                     dbounds_.width) - pbounds_.x;
+    pbounds_.height = pbounds_.y -
+      layer_.getYDtoP(dbounds_.y + dbounds_.height);
+  }
+
+  //
+  // a bad method to compute the font size!
+  //
+  Font computeFontSize(Graphics g) {
+    Font tfont;
+    FontMetrics fmet;
+    int pt_0, pt_1, hgt;
+    int count = 1;
+    double hgt_0, hgt_1, del_0, del_1;
+    double a, b;
+    //
+    // first guess
+    //
+    if(g == null) return font_;
+    hgt = layer_.getXPtoD(height_) - layer_.getXPtoD(0.0f);
+    pt_0 = hgt - 3;
+    tfont = new Font(font_.getName(), font_.getStyle(), pt_0);
+    g.setFont(tfont);
+    fmet = g.getFontMetrics();
+    hgt = fmet.getAscent() + fmet.getDescent();
+    hgt_0 = layer_.getXDtoP(hgt) - layer_.getXDtoP(0);
+    pt_0 = tfont.getSize();
+    pt_1 = (int)((double)pt_0*(height_/hgt_0));
+    while((pt_0 != pt_1) && (count < 5)) {
+      tfont = new Font(font_.getName(), font_.getStyle(), pt_1);
+      g.setFont(tfont);
+      fmet = g.getFontMetrics();
+      hgt = fmet.getAscent() + fmet.getDescent();
+      hgt_1 = layer_.getXDtoP(hgt) - layer_.getXDtoP(0);
+      del_0 = Math.abs(height_ - hgt_0);
+      del_1 = Math.abs(height_ - hgt_1);
+      if((Math.abs(pt_0 - pt_1) <= 1) && (del_0 > del_1)) return tfont;
+      pt_0 = pt_1;
+      hgt_0 = hgt_1;
+      pt_1 = (int)((double)pt_0*(height_/hgt_0));
+      count++;
+    }
+    return tfont;
+  }
+
+  public float getStringWidth(Graphics g) {
+    if(g == null) return 0.0f;
+    FontMetrics fmet = g.getFontMetrics(font_);
+    return (float)fmet.stringWidth(label_);
+  }
+
+  public float getStringHeight(Graphics g) {
+    if(g == null) return 0.0f;
+    FontMetrics fmet = g.getFontMetrics(font_);
+    return (float)(fmet.getAscent()*0.75)+1.0f;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer2.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer2.java
new file mode 100755
index 0000000..7bc09e5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelDrawer2.java
@@ -0,0 +1,580 @@
+/*
+ * $Id: LabelDrawer2.java,v 1.1.1.2 2008/12/19 13:29:30 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.swing.MRJUtil;
+
+import java.awt.*;
+import java.beans.*;
+import java.awt.image.PixelGrabber;
+import java.awt.image.MemoryImageSource;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.geom.AffineTransform;
+import java.awt.font.TextAttribute;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.text.AttributedString;
+
+/**
+ * Implements label drawing using Java2D functionality.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:30 $
+ * @since 2.0
+ */
+public class LabelDrawer2 implements LabelDrawer, Cloneable {
+  private String label_;
+  private Color clr_;
+  private Font font_;
+  private Graphics storedGraphics;
+  private transient Layer layer_;
+  private int orient_;
+  private int halign_;
+  private int valign_;
+  private Point dorigin_;
+  private Rectangle dbounds_;
+  private Point2D.Double porigin_;
+  private Rectangle2D.Double pbounds_;
+  private Polygon dpolygon_;
+  private double angle_;
+  private double sinthta_;
+  private double costhta_;
+  private double height_;
+  private boolean visible_;
+  private static boolean fixMetrics_ = MRJUtil.fixFontMetrics();
+
+  private int xoff_ = 0;
+  private int yoff_ = 0;
+
+  private boolean alwaysAntiAlias_ = true;
+
+  private Rectangle savedBounds_ = null;
+  private Point savedLoc_ = null;
+
+  public LabelDrawer2(String lbl, double hgt, Point2D.Double loc,
+                      int valign, int halign) {
+    label_ = lbl;
+    height_ = hgt;
+    porigin_ = loc;
+    valign_ = valign;
+    halign_ = halign;
+    //
+    dbounds_ = new Rectangle();
+    dorigin_ = new Point(0,0);
+    pbounds_ = new Rectangle2D.Double();
+    storedGraphics = null;
+  }
+
+  public LabelDrawer copy() {
+    LabelDrawer1 newLabel = null;
+//      try {
+//        newLabel = (LabelDrawer1)clone();
+//      } catch (CloneNotSupportedException e) {
+//        newLabel = new LabelDrawer1(ident_, label_, height_,
+//  			     porigin_, valign_, halign_);
+//        newLabel.setColor(clr_);
+//        newLabel.setFont(font_);
+//        if(orient_ == ANGLE) {
+//  	newLabel.setAngle(angle_);
+//        } else {
+//  	newLabel.setOrientation(orient_);
+//        }
+//      }
+    return newLabel;
+  }
+
+  public void draw(Graphics g) throws LayerNotFoundException  {
+    int xs, ys;
+    if((label_.length() <= 0) || !visible_ || g == null) return;
+    if(layer_ == (Layer) null) throw new LayerNotFoundException();
+    //
+    // set label heigth in physical units
+    //
+    computeBoundsD(g);
+    if(clr_ == null) {
+      g.setColor(layer_.getPane().getComponent().getForeground());
+    } else {
+      g.setColor(clr_);
+    }
+    if(orient_ == SGLabel.HORIZONTAL) {
+      xs = dbounds_.x + xoff_;
+      ys = dbounds_.y + yoff_;
+      drawString(g, xs, ys);
+    } else if(orient_ == SGLabel.VERTICAL) {
+      //
+      // draw text in offscreen image (horizontal)
+      //
+      xs = dbounds_.x + xoff_;
+      ys = dbounds_.y + yoff_;
+      drawString(g, xs, ys);
+    } else {
+      //
+      // Angled text, draw in offscreen image and rotate
+      //
+      xs = layer_.getXPtoD(porigin_.x);
+      ys = layer_.getYPtoD(porigin_.y);
+      drawString(g, xs, ys);
+    }
+  }
+
+  public void setText(String lbl) {
+    label_ = lbl;
+  }
+  public String getText() {
+    return label_;
+  }
+
+  public void setColor(Color clr) {
+    clr_ = clr;
+  }
+  public Color getColor() {
+    return clr_;
+  }
+
+  public void setFont(Font font) {
+    font_ = font;
+  }
+  public Font getFont() {
+    return font_;
+  }
+
+  public void setLayer(Layer layer) {
+    layer_ = layer;
+    if(savedBounds_ != null) {
+      setBounds(savedBounds_.x, savedBounds_.y,
+                savedBounds_.width, savedBounds_.height);
+      savedBounds_ = null;
+    }
+    if(savedLoc_ != null) {
+      setLocation(savedLoc_);
+      savedLoc_ = null;
+    }
+  }
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public void setOrientation(int orient) {
+    if(orient_ != orient) {
+      if(orient == SGLabel.HORIZONTAL) {
+        costhta_ = 1.0;
+        sinthta_ = 0.0;
+      } else if(orient == SGLabel.VERTICAL) {
+        costhta_ = 0.0;
+        sinthta_ = 1.0;
+      }
+      orient_ = orient;
+    }
+  }
+  public int getOrientation() {
+    return orient_;
+  }
+
+  public void setHAlign(int halign) {
+    halign_ = halign;
+  }
+  public int getHAlign() {
+    return halign_;
+  }
+
+  public void setVAlign(int valign) {
+    valign_ = valign;
+  }
+  public int getVAlign() {
+    return valign_;
+  }
+
+  public void setLocation(Point loc) {
+    if(layer_ == null) {
+      savedLoc_ = new Point(loc);
+      return;
+    }
+    computeBoundsD(layer_.getPane().getComponent().getGraphics());
+    if(dbounds_.x != loc.x || dbounds_.y != loc.y) {
+      setBounds(loc.x, loc.y, dbounds_.width, dbounds_.height);
+    }
+  }
+  public Point getLocation() {
+    if(savedLoc_ != null) return savedLoc_;
+    return dorigin_;
+  }
+
+  public void setBounds(int x, int y, int width, int height) {
+    int swidth, sascent, xd, yd;
+    if(layer_ == null) {
+      savedBounds_ = new Rectangle(x, y, width, height);
+      return;
+    }
+    Graphics g = layer_.getPane().getComponent().getGraphics();
+    if(g == null) return;
+    font_ = computeFontSize(g);
+    FontRenderContext frc = getFontRenderContext((Graphics2D)g);
+    TextLayout tlayout;
+    if(label_.length() == 0) {
+      tlayout = new TextLayout(" ", font_, frc);
+    } else {
+      tlayout = new TextLayout(label_, font_, frc);
+    }
+    java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
+    int theight = (int)tbounds.getHeight();
+    int twidth = (int)tbounds.getWidth();
+    int tx = (int)tbounds.getX();
+    int ty = (int)tbounds.getY();
+    if(fixMetrics_) ty -= (int)(0.7*tlayout.getAscent());  // hack for MacOS X java.runtime.version = 1.4.1_01-39
+    sascent = (int)tlayout.getAscent();
+
+    if(orient_ == SGLabel.HORIZONTAL) {
+      swidth = width;
+      xd = x;
+      yd = y - ty;
+      switch(valign_) {
+      case SGLabel.TOP:
+        yd = yd - sascent;
+        break;
+      case SGLabel.MIDDLE:
+        yd = yd + (ty + theight/2);
+        break;
+      case SGLabel.BOTTOM:
+      }
+      switch(halign_) {
+      case SGLabel.RIGHT:
+        xd = xd + swidth;
+        break;
+      case SGLabel.CENTER:
+        xd = xd + swidth/2;
+        break;
+      case SGLabel.LEFT:
+      }
+    } else {
+      swidth = height;
+      yd = y + height;
+      xd = x - ty;
+      switch(valign_) {
+      case SGLabel.TOP:
+        xd = xd - sascent;
+        break;
+      case SGLabel.MIDDLE:
+        xd = xd - sascent/2;
+        break;
+      case SGLabel.BOTTOM:
+      }
+      switch(halign_) {
+      case SGLabel.RIGHT:
+        yd = yd - swidth;
+        break;
+      case SGLabel.CENTER:
+        yd = yd - swidth/2;
+        break;
+      case SGLabel.LEFT:
+      }
+    }
+    if(dorigin_.x != xd || dorigin_.y != yd) {
+      dorigin_.x = xd;
+      dorigin_.y = yd;
+      porigin_.x = layer_.getXDtoP(xd);
+      porigin_.y = layer_.getYDtoP(yd);
+    }
+  }
+  public Rectangle getBounds() {
+    if(savedBounds_ != null) return savedBounds_;
+    if(layer_ != null) computeBoundsD(layer_.getPane().getComponent().getGraphics());
+    return dbounds_;
+  }
+
+  public void setLocationP(Point2D.Double loc) {
+    porigin_ = loc;
+  }
+  public Point2D.Double getLocationP() {
+    return porigin_;
+  }
+
+  public Rectangle2D.Double getBoundsP() {
+    computeBoundsD(layer_.getPane().getComponent().getGraphics());
+    return pbounds_;
+  }
+
+  public void setAngle(double angle) {
+    angle_ = angle;
+    double thta = angle_*Math.PI/180.0;
+    if(Math.abs(thta) < 0.001) {
+      orient_ = SGLabel.HORIZONTAL;
+      costhta_ = 1.0;
+      sinthta_ = 0.0;
+    } else if(Math.abs(thta - 90.0) < 0.001) {
+      orient_ = SGLabel.VERTICAL;
+      costhta_ = 0.0;
+      sinthta_ = 1.0;
+    } else {
+      orient_ = SGLabel.ANGLE;
+      costhta_ = Math.cos(thta);
+      sinthta_ = Math.sin(thta);
+    }
+  }
+  public double getAngle() {
+    return angle_;
+  }
+
+  public void setHeightP(double hgt) {
+    height_ = hgt;
+  }
+  public double getHeightP() {
+    return height_;
+  }
+
+  public void setVisible(boolean vis) {
+    visible_ = vis;
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+
+  private void computeBoundsD(Graphics g) {
+    int sascent, xd, yd;
+    int xorig, yorig;
+    int[] xt = new int[4];
+    int[] yt = new int[4];
+    int[] xn = new int[4];
+    int[] yn = new int[4];
+    //
+    // compute size of font and adjust to be height tall!
+    //
+    if(g == null) return;
+    font_ = computeFontSize(g);
+    FontRenderContext frc = getFontRenderContext((Graphics2D)g);
+    TextLayout tlayout;
+    if(label_.length() == 0) {
+      tlayout = new TextLayout(" ", font_, frc);
+    } else {
+      tlayout = new TextLayout(label_, font_, frc);
+    }
+    java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
+
+//    System.out.println("LabelDrawer2('" + label_ + "'): fixMetrics = " + fixMetrics_);
+//    System.out.println("LabelDrawer2('" + label_ + "'): TextLayout.bounds = " + tbounds);
+//    System.out.println("LabelDrawer2('" + label_ + "'): ascent, descent = " + tlayout.getAscent() + ", " + tlayout.getDescent());
+//    System.out.println("LabelDrawer2('" + label_ + "'): leading, baseline = " + tlayout.getLeading() + ", " + tlayout.getBaseline());
+//    System.out.println("LabelDrawer2('" + label_ + "'): TextLayout = " + tlayout);
+
+    int theight = (int)tbounds.getHeight();
+    int twidth = (int)tbounds.getWidth();
+    int tx = (int)tbounds.getX();
+    int ty = (int)tbounds.getY();
+    if(fixMetrics_) ty -= (int)(0.7*tlayout.getAscent());  // hack for MacOS X java.runtime.version = 1.4.1_01-39
+    sascent = (int)tlayout.getAscent();
+    //
+    xd = layer_.getXPtoD(porigin_.x);
+    yd = layer_.getYPtoD(porigin_.y);
+    //
+    // set device origin
+    //
+    dorigin_.x = xd;
+    dorigin_.y = yd;
+    xorig = xd;
+    yorig = yd;
+    //
+    switch(valign_) {
+    case SGLabel.TOP:
+      yd = yd + sascent;
+      break;
+    case SGLabel.MIDDLE:
+      yd = yd - (ty + theight/2);
+      break;
+    case SGLabel.BOTTOM:
+    }
+    switch(halign_) {
+    case SGLabel.RIGHT:
+      xd = xd - twidth;
+      break;
+    case SGLabel.CENTER:
+      xd = xd - twidth/2;
+      break;
+    case SGLabel.LEFT:
+    }
+    if(orient_ == SGLabel.HORIZONTAL) {
+      xoff_ = 0;
+      yoff_ = -ty;
+    } else if(orient_ == SGLabel.VERTICAL) {
+      xoff_ = -ty;
+      yoff_ = twidth;
+    }
+    xt[0] = xd + tx;
+    xt[1] = xt[0];
+    xt[2] = xt[0] + twidth;
+    xt[3] = xt[2];
+
+    yt[0] = yd + ty;
+    yt[1] = yt[0] + theight;
+    yt[2] = yt[1];
+    yt[3] = yt[0];
+    //
+    // rotate
+    //
+    for(int i=0; i < 4; i++) {
+      xn[i] = (int)((xt[i]-xorig)*costhta_ + (yt[i]-yorig)*sinthta_) + xorig;
+      yn[i] = (int)((yt[i]-yorig)*costhta_ - (xt[i]-xorig)*sinthta_) + yorig;
+    }
+
+    dpolygon_ = new Polygon(xn, yn, 4);
+    dbounds_ = dpolygon_.getBounds();
+    //
+    // compute pbounds
+    //
+    pbounds_.x = layer_.getXDtoP(dbounds_.x);
+    pbounds_.y = layer_.getYDtoP(dbounds_.y);
+    pbounds_.width = layer_.getXDtoP(dbounds_.x +
+                                     dbounds_.width) - pbounds_.x;
+    pbounds_.height = pbounds_.y -
+      layer_.getYDtoP(dbounds_.y + dbounds_.height);
+  }
+
+  //
+  // a bad method to compute the font size!
+  //
+  Font computeFontSize(Graphics g) {
+    Font tfont;
+    int pt_0, pt_1, hgt;
+    int count = 1;
+    double hgt_0, hgt_1, del_0, del_1;
+    double a, b;
+    FontRenderContext frc = getFontRenderContext((Graphics2D)g);
+    TextLayout tlayout;
+    //
+    // first guess
+    //
+    if(g == null || g == storedGraphics) return font_;  // return original font!
+    storedGraphics = g;
+    
+    hgt = layer_.getXPtoD(height_) - layer_.getXPtoD(0.0f);
+    pt_0 = hgt - 3;
+    tfont = new Font(font_.getName(), font_.getStyle(), pt_0);
+    if(label_.length() == 0) {
+      tlayout = new TextLayout(" ", tfont, frc);
+    } else {
+      tlayout = new TextLayout(label_, tfont, frc);
+    }
+    hgt = (int)(tlayout.getAscent() + tlayout.getDescent());
+    hgt_0 = layer_.getXDtoP(hgt) - layer_.getXDtoP(0);
+    pt_0 = tfont.getSize();
+    pt_1 = (int)((double)pt_0*(height_/hgt_0));
+    while((pt_0 != pt_1) && (count < 5)) {
+      tfont = new Font(font_.getName(), font_.getStyle(), pt_1);
+      if(label_.length() == 0) {
+        tlayout = new TextLayout(" ", tfont, frc);
+      } else {
+        tlayout = new TextLayout(label_, tfont, frc);
+      }
+      hgt = (int)(tlayout.getAscent() + tlayout.getDescent());
+      hgt_1 = layer_.getXDtoP(hgt) - layer_.getXDtoP(0);
+      del_0 = Math.abs(height_ - hgt_0);
+      del_1 = Math.abs(height_ - hgt_1);
+      if((Math.abs(pt_0 - pt_1) <= 1) && (del_0 > del_1)) return tfont;
+      pt_0 = pt_1;
+      hgt_0 = hgt_1;
+      pt_1 = (int)((double)pt_0*(height_/hgt_0));
+      count++;
+    }
+    return tfont;
+  }
+
+  private void drawString(Graphics g, int x, int y) {
+    float angle;
+    if(g == null) return;
+    if(orient_ == SGLabel.HORIZONTAL) {
+      angle = 0.0f;
+    } else if(orient_ == SGLabel.VERTICAL) {
+      angle = -90.0f;
+    } else {
+      angle = -(float)angle_;
+    }
+    RenderingHints oldRenderingHints = null;
+    Graphics2D g2 = (Graphics2D)g;
+    if(angle != 0.0f || alwaysAntiAlias_) {
+      oldRenderingHints = g2.getRenderingHints();
+      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                          RenderingHints.VALUE_ANTIALIAS_ON);
+      g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+                          RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+    }
+    AffineTransform oldTransform = g2.getTransform();
+    //    System.out.println("\n angle = " + angle + ", text = " + label_);
+    //    System.out.println("oldTransform = " + oldTransform);
+    AttributedString as = new AttributedString(label_);
+    as.addAttribute(TextAttribute.FONT, font_);
+    g2.translate(x, y);
+    //   System.out.println("translated = " + g2.getTransform());
+    g2.rotate(Math.PI * angle/180.0);
+    //   System.out.println("newTransform = " + g2.getTransform());
+    g2.drawString(as.getIterator(), 0, 0);
+    g2.setTransform(oldTransform);
+    if(angle != 0.0f || alwaysAntiAlias_) {
+      g2.setRenderingHints(oldRenderingHints);
+    }
+    //
+//      g2.setStroke(normal);
+//      Color oldColor = g.getColor();
+//      g.setColor(Color.red);
+//      int x1= x - 5;
+//      int x2= x + 5;
+//      int y1= y - 5;
+//      int y2= y + 5;
+//      g.drawLine(x1, y, x2, y);
+//      g.drawLine(x, y1, x, y2);
+//      g.setColor(oldColor);
+
+  }
+  public float getStringWidth(Graphics g) {
+    if(g == null) return 0.0f;
+    font_ = computeFontSize(g);
+    FontRenderContext frc = getFontRenderContext((Graphics2D)g);
+    TextLayout tlayout;
+    if(label_.length() == 0) {
+      tlayout = new TextLayout(" ", font_, frc);
+    } else {
+      tlayout = new TextLayout(label_, font_, frc);
+    }
+    java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
+    return (float)tbounds.getWidth();
+  }
+  public float getStringHeight(Graphics g) {
+    if(g == null) return 0.0f;
+    font_ = computeFontSize(g);
+    FontRenderContext frc = getFontRenderContext((Graphics2D)g);
+    TextLayout tlayout;
+    if(label_.length() == 0) {
+      tlayout = new TextLayout(" ", font_, frc);
+    } else {
+      tlayout = new TextLayout(label_, font_, frc);
+    }
+    java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
+    return (float)tbounds.getHeight();
+  }
+
+  FontRenderContext getFontRenderContext(Graphics2D g2) {
+    if(g2 == null) return null;
+    RenderingHints oldRenderingHints = null;
+    if(angle_ != 0.0 || alwaysAntiAlias_) {
+      oldRenderingHints = g2.getRenderingHints();
+      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                          RenderingHints.VALUE_ANTIALIAS_ON);
+    }
+    FontRenderContext frc = g2.getFontRenderContext();
+    if(angle_ != 0.0 || alwaysAntiAlias_) {
+      g2.setRenderingHints(oldRenderingHints);
+    }
+    return frc;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelNotFoundException.java
new file mode 100755
index 0000000..1e4cb41
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LabelNotFoundException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: LabelNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Label was not found during operation.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class LabelNotFoundException extends SGException {
+  public LabelNotFoundException() {
+    super();
+}
+  public LabelNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Layer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Layer.java
new file mode 100755
index 0000000..f22993b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Layer.java
@@ -0,0 +1,871 @@
+/*
+ * $Id: Layer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.sgt.swing.Draggable;
+
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.awt.*;
+
+// jdk1.2
+//import  java.awt.geom.Rectangle2D;
+
+/**
+ * A <code>Layer</code> contains a single <code>Graph</code> object
+ * and multiple <code>LayerChild</code> objects.
+ * There can be many <code>Layer</code> objects associated with each
+ * <code>Pane</code> object and
+ * the <code>Layer</code> objects can share <code>Transform</code>
+ * and <code>Axis</code> objects, but are not
+ * required to.  The <code>Layer</code> is also where keys
+ * related to <code>Color</code>, Vectors, and
+ * Lines are attached.  The can be at most one key of each type attached to a
+ * <code>Layer</code>.
+ * <p>
+ * The <code>Layer</code> object transforms physical coordinates
+ * to device coordinates. All objects that attach to a
+ * <code>Layer</code> use physical coordinates.
+ * The exception to this is the <code>Graph</code> object
+ * (and its children), since these objects transform user
+ * coordinates to physical coordinates.
+ * <p>
+ * The following is a simple example of using the <code>Pane</code>,
+ * <code>Layer</code>, and <code>SGLabel</code> objects
+ * together. In this example, the <code>Pane</code> and
+ * <code>Layer</code> objects are created such that,
+ * in the absence of any resizing, 100 pixels is equal to 1.0
+ * physical units. Two labels are created, the first contains
+ * the current time and is located in the bottom left of
+ * the <code>Layer</code>.  The second label is a title that is
+ * positioned near the top and centered.
+ * <pre>
+ * Pane pane;
+ * Layer layer;
+ * SGLabel title;
+ * SGLabel label;
+ * GeoDate stime;
+ * ...
+ * //
+ * // Instantiate Pane, Layer, and GeoDate objects.
+ * //
+ * pane = new Pane("test pane", new Dimension(400, 300));
+ * pane.setLayout(new StackedLayout());
+ * layer = new Layer("Test Layer", new Dimension2D(4.0, 3.0));
+ * stime = new GeoDate();
+ * //
+ * // Instatiate an SGLabel object as label, set its text to the
+ * // current time and position it near the lower-left corner
+ * // of the layer.
+ * //
+ * label = new SGLabel("test", stime.toString(), new Point2D.Double(0.05, 0.05));
+ * //
+ * // Set properties for label.
+ * //
+ * label.setAlign(SGLabel.BOTTOM, SGLabel.LEFT);
+ * label.setColor(Color.magenta);
+ * label.setHeightP(0.15);
+ * label.setFont(new Font("Dialog", Font.PLAIN, 10));
+ * //
+ * // Add label to layer.
+ * //
+ * layer.addChild(label);
+ * //
+ * // Instatiate an SGLabel object as title, set its text and position
+ * // it near the top of the layer and centered. Set the properties
+ * // for title.
+ * //
+ * title = new SGLabel("title", "SciGraph Test!", new Point2D.Double(2.125, 2.9));
+ * title.setAlign(SGLabel.TOP, SGLabel.CENTER);
+ * title.setHeightP(0.25);
+ * title.setFont(new Font("Helvetica", Font.BOLD, 14));
+ * //
+ * // Add title to layer and add layer to pane.
+ * //
+ * layer.addChild(title);
+ * pane.add(layer);
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see Pane
+ * @see Graph
+ * @see ColorKey
+ * @see SGLabel
+ * @see LineKey
+ * @see gov.noaa.pmel.util.GeoDate
+**/
+public class Layer extends Component implements Cloneable, LayerControl {
+  private String ident_;
+    /**@shapeType AggregationLink
+     * @clientCardinality 1
+     * @label graph*/
+    private Graph graph_;
+  /**@shapeType AggregationLink
+  @associates <b>LayerChild</b>
+  @supplierCardinality 0..*
+   * @undirected
+   * @label children */
+  private Vector children_;
+  private double pWidth_;
+  private double pHeight_;
+  private double ax_;
+  private double ay_;
+  private int xoff_;
+  private int yoff_;
+  private double xoff2_;
+  private double yoff2_;
+  protected AbstractPane pane_;
+
+  private void computeScale() {
+    Dimension d;
+    boolean hasG2 = getGraphics() instanceof Graphics2D;
+    // compute xoff and yoff as double then truncate to int
+    Rectangle pbnds = pane_.getBounds();
+    Rectangle bnds = getBounds();
+    if(pane_.isPrinter()) {
+      ax_ = 72; // java2 is in 1/72 of an inch
+      ay_ = ax_;
+      xoff2_ = (bnds.width - ax_*pWidth_)/2.0 + bnds.x;
+      yoff2_ = bnds.height - (bnds.height - ay_*pHeight_)/2.0 + bnds.y;
+    } else {
+      // not printer
+      ax_ = (double)bnds.width/pWidth_;
+      ay_ = (double)bnds.height/pHeight_;
+      if(ax_ > ay_) {
+        ax_ = ay_;
+      } else if(ay_ > ax_) {
+        ay_ = ax_;
+      }
+      xoff2_ = (bnds.width - ax_*pWidth_)/2.0 + bnds.x - pbnds.x;
+      yoff2_ = bnds.height - (bnds.height - ay_*pHeight_)/2.0 + bnds.y - pbnds.y;
+    }
+    xoff_ = (int)xoff2_;
+    yoff_ = (int)yoff2_;
+    if(Debug.DEBUG && pane_.isPrinter()) {
+      System.out.println("Layer.computeScale["+getId()+"] printer = " + pane_.isPrinter());
+      System.out.println("                  xd(min) = " + getXPtoD(0.0));
+      System.out.println("                  xd(max) = " + getXPtoD(pWidth_));
+      System.out.println("                  yd(min) = " + getYPtoD(0.0));
+      System.out.println("                  yd(max) = " + getYPtoD(pHeight_));
+    }
+  }
+  /**
+   * Set the size of the <code>Layer</code> in device units.
+   *
+   * @param sze dimension of the <code>Layer</code>
+   */
+  public void setSize(Dimension sze) {
+    super.setSize(sze);
+    computeScale();
+    modified("Layer: setSize(Dimension)");
+  }
+  /**
+   * Set the size of the <code>Layer</code> in device units.
+   *
+   * @param w width of the <code>Layer</code>
+   * @param h height of the <code>Layer</code>
+   */
+  public void setSize(int w, int h) {
+    super.setSize(w, h);
+    computeScale();
+    modified("Layer: setSize(int,int)");
+  }
+  /**
+   * Set the location of the <code>Layer</code> in device units.
+   *
+   * @param pt location of the <code>Layer</code>
+   */
+  public void setLocation(Point pt) {
+    super.setLocation(pt);
+    computeScale();
+    modified("Layer: setLocation(Point)");
+  }
+  /**
+   * Set the location of the <code>Layer</code> in device units.
+   *
+   * @param x horizontal location of the <code>Layer</code>
+   * @param y vertical location of the <code>Layer</code>
+   */
+  public void setLocation(int x, int y) {
+    super.setLocation(x, y);
+    computeScale();
+    modified("Layer: setLocation(int,int)");
+  }
+  /**
+   * Set the bounds of the <code>Layer</code> in device units.
+   *
+   * @param x horizontal location of the <code>Layer</code>
+   * @param y vertical location of the <code>Layer</code>
+   * @param w width of the <code>Layer</code>
+   * @param h height of the <code>Layer</code>
+   */
+  public void setBounds(int x, int y, int w, int h) {
+    super.setBounds(x, y, w, h);
+    computeScale();
+//    System.out.println("Layer.setBounds(" + x + ", " + y + ", " +
+//                       w + ", " + h + ")");
+    modified("Layer: setBounds(int,int,int,int)");
+  }
+  /**
+   * Set the bounds of the <code>Layer</code> in device units.
+   *
+   * @param bnds bounds of the <code>Layer</code>
+   */
+  public void setBounds(Rectangle bnds) {
+    super.setBounds(bnds);
+    computeScale();
+    modified("Layer: setBounds(Rectangle)");
+  }
+  /**
+   * Transform physical units to device for x coordinate.
+   *
+   * @param xp x physical coordinate
+   * @return x device coordinate
+   * @since 2.0
+   */
+  public int getXPtoD(double xp) {
+    return (int)(ax_*xp) + xoff_;
+  }
+  /**
+   * Transform physcial units to device for y coordinate.
+   *
+   * @param yp y physical coordinate
+   * @return y device coordinate
+   * @since 2.0
+   */
+  public int getYPtoD(double yp) {
+    return yoff_ - (int)(ay_*yp);
+  }
+  /**
+   * Transform physical units to device for x coordinate.
+   *
+   * @param xp x physical coordinate
+   * @return x device coordinate
+   * @since 3.0
+   */
+  public double getXPtoD2(double xp) {
+    return ax_*xp + xoff2_;
+  }
+  /**
+   * Transform physcial units to device for y coordinate.
+   *
+   * @param yp y physical coordinate
+   * @return y device coordinate
+   * @since 3.0
+   */
+  public double getYPtoD2(double yp) {
+    return yoff2_ - ay_*yp;
+  }
+  protected double getXSlope() {
+    return ax_;
+  }
+  protected double getYSlope() {
+    return ay_;
+  }
+  protected double getXOffset() {
+    return xoff2_;
+  }
+  protected double getYOffset() {
+    return yoff2_;
+  }
+  /**
+   * Transform device units to physical for the x direction.
+   *
+   * @param xd device x coordinate
+   *
+   * @return physical x coordinate
+   */
+  public double getXDtoP(int xd) {
+    return (double)(xd - xoff2_)/ax_;
+  }
+  /**
+   * Transform device units to physical for the y direction.
+   *
+   * @param yd device y coordinate
+   *
+   * @return physical y coordinate
+   */
+  public double getYDtoP(int yd) {
+    return (double)(yoff2_ - yd)/ay_;
+  }
+  /**
+   * Create a <code>Layer</code> object.
+   * The <code>Layer</code> is created with a default
+   * width and height equal to 1.0.
+   *
+   * @param id identifier for Layer
+   **/
+  public Layer(String id) {
+    this(id, new Dimension2D(1.0, 1.0));
+  }
+  /**
+   * Create a <code>Layer</code> object.
+   * The <code>Layer</code> is created with the specified
+   * dimensions and identifier.
+   *
+   * @param id identifier for Layer
+   * @param psize The physical dimensions of the Layer
+   **/
+  public Layer(String id,Dimension2D psize) {
+    ident_ = id;
+    pWidth_ = psize.width;
+    pHeight_ = psize.height;
+    children_ = new Vector(5,5);
+  }
+  /**
+   * Default constructor for <code>Layer</code>.
+   * The <code>Layer</code> is created with an
+   * empty identifier and a width and height equal to 1.0f.
+   **/
+  public Layer() {
+    this("");
+  }
+  /**
+   * Copy the <code>Layer</code> and its attached classes.
+   *
+   * @return copy
+   */
+  public Layer copy() {
+    Layer newLayer;
+    try {
+      newLayer = (Layer)clone();
+    } catch (CloneNotSupportedException e) {
+      newLayer = new Layer(ident_, new Dimension2D(pWidth_, pHeight_));
+    }
+    //
+    // copy children
+    //
+    newLayer.children_ = new Vector(5,5);
+    //
+    if(!children_.isEmpty()) {
+      LayerChild newChild;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        newChild = ((LayerChild)it.nextElement()).copy();
+        newLayer.addChild(newChild);
+      }
+    }
+    //
+    // copy Graph
+    //
+    if(graph_ != (Graph) null) {
+      Graph newGraph = graph_.copy();
+      newLayer.setGraph(newGraph);
+    }
+    return newLayer;
+  }
+  /**
+   * Draw the Layer and its attached classes.
+   *
+   * @param g graphics context
+   * @exception PaneNotFoundException if a pane object is not found
+   **/
+  public void draw(Graphics g) throws PaneNotFoundException  {
+    if(pane_ == null) throw new PaneNotFoundException();
+    computeScale();
+
+    if(false) {
+      System.out.println("\nLayer.draw(g): " + ident_);
+      System.out.println("   layer.getBounds(" + ident_ + ") = " + getBounds());
+      System.out.println("   layer.getBoundsP(" + ident_ + ") = " + getBoundsP());
+      System.out.println("   pane.getBounds(" + pane_.getId() + ") = " + pane_.getBounds());
+    }
+/*    int x0, y0, x1, y1;
+    x0 = getXPtoD(0.0f);
+    y0 = getYPtoD(0.0f);
+    Rectangle2D.Double psize_ = getBoundsP();
+    x1 = getXPtoD(psize_.width);
+    y1 = getYPtoD(psize_.height);
+    g.setColor(Color.blue);
+    g.drawRect(x0,y1,x1-x0-1,y0-y1-1); */
+//    System.out.println("Layer.draw(g): " + ident_ + ", [" + ax_ + ", " + ay_ + "], [" +
+//                       xoff2_ + ", " + yoff2_ + "]");
+
+    //
+    // draw Graph
+    //
+    if(graph_ != (Graph) null) graph_.draw(g);
+    //
+    // draw children
+    //
+    if(!children_.isEmpty()) {
+      LayerChild child;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        child = (LayerChild)it.nextElement();
+        if(!(child instanceof Draggable)) {
+          try {
+            child.draw(g);
+          } catch(LayerNotFoundException e) {
+          }
+        }
+      }
+    }
+  }
+
+  public void drawDraggableItems(Graphics g) throws PaneNotFoundException {
+    if(pane_ == null) throw new PaneNotFoundException();
+    //
+    // draw draggable items
+    //
+    if(!children_.isEmpty()) {
+      LayerChild child;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        child = (LayerChild)it.nextElement();
+        if(child instanceof Draggable) {
+          try {
+            child.draw(g);
+          } catch(LayerNotFoundException e) {
+          }
+        }
+      }
+    }
+  }
+  /**
+   * Associate a graph with the layer. Only one graph or its children may be attached to a
+   * layer.  Multiple graphs are created by using multiple layers.
+   *
+   * @param gr graph
+   * @return True if attachment was succesful
+   * @see Graph
+   **/
+  public boolean setGraph(Graph gr) {
+    graph_ = gr;
+    graph_.setLayer(this);
+    modified("Layer: setGraph()");
+    return true;
+  }
+  /**
+   * Get the <code>Graph</code> attached to the layer.
+   *
+   * @return Reference to the <code>Graph</code>.
+   **/
+  public Graph getGraph() {
+    return graph_;
+  }
+  /**
+   * Add a <code>LayerChild</code> to the <code>Layer</code>.
+   * Each <code>Layer</code> can contain as many children as needed.
+   *
+   * @param child A <code>LayerChild</code>
+   * @see SGLabel
+   * @see LineKey
+   * @see ColorKey
+   * @see Ruler
+   **/
+  public void addChild(LayerChild child) {
+    child.setLayer(this);
+    children_.addElement(child);
+    modified("Layer: addChild()");
+  }
+  /**
+   * Remove a <code>LayerChild</code> object from the <code>Layer</code>.
+   *
+   * @param child A <code>ChildLayer</code> object associated with the <code>Layer</code>
+   * @exception ChildNotFoundException The child is not associated with the <code>Layer</code>
+   * @see SGLabel
+   * @see LineKey
+   * @see ColorKey
+   * @see Ruler
+   **/
+  public void removeChild(LayerChild child) throws ChildNotFoundException  {
+    if(!children_.isEmpty()) {
+      LayerChild chld;
+      boolean found = false;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        chld = (LayerChild)it.nextElement();
+        if(chld.equals(child)) {
+            children_.removeElement(child);
+            found = true;
+      modified("Layer: removeChild(LayerChild)");
+        }
+      }
+      if(!found) throw new ChildNotFoundException();
+    } else {
+      throw new ChildNotFoundException();
+    }
+  }
+  /**
+   * Remove a <code>LayerChild</code> object from the <code>Layer</code>.
+   *
+   * @param labid An identifier for a <code>LayerChild</code> associated with the <code>Layer</code>
+   * @exception ChildNotFoundException The child is not associated with the <code>Layer</code>
+   * @see SGLabel
+   * @see LineKey
+   * @see ColorKey
+   * @see Ruler
+   **/
+  public void removeChild(String labid) throws ChildNotFoundException  {
+    if(!children_.isEmpty()) {
+      boolean found = false;
+      LayerChild child;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        child = (LayerChild)it.nextElement();
+        if(child.getId().equals(labid)) {
+          children_.removeElement(child);
+          found = true;
+    modified("Layer: removeChild(String)");
+        }
+      }
+      if(!found) throw new ChildNotFoundException();
+    } else {
+      throw new ChildNotFoundException();
+    }
+  }
+
+  /**
+   * Find <code>LayerChild</code> in <code>Layer</code>.
+   * @param id LayerChild identifier
+   * @return LayerChild
+   * @since 3.0
+   */
+  public LayerChild findChild(String id) {
+    LayerChild child = null;
+    for(Enumeration it=children_.elements(); it.hasMoreElements();) {
+      child = (LayerChild)it.nextElement();
+      if(child.getId().equals(id)) return child;
+    }
+    return null;
+  }
+  /**
+   * Tests if a <code>LayerChild</code> is attached to the
+   * <code>Layer</code>.
+   *
+   * @param child LayerChild to test
+   * @return true if attached to Layer
+   * @since 2.0
+   */
+  public boolean isChildAttached(LayerChild child) {
+    boolean found = false;
+    if(!children_.isEmpty()) {
+      LayerChild chld;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        chld = (LayerChild)it.nextElement();
+        if(chld.equals(child)) {
+            children_.removeElement(child);
+            found = true;
+      break;
+        }
+      }
+    }
+    return found;
+  }
+  /**
+   * Remove all <code>LayerChild</code> objects from the <code>Layer</code>.
+   */
+  public void removeAllChildren() {
+    children_.removeAllElements();
+    modified("Layer: removeAllChildren()");
+  }
+  /**
+   * Get a child associated with the <code>Layer</code>.
+   *
+   * @param labid A <code>LayerChild</code> object identifier
+   * @return layerChild with id
+   * @exception ChildNotFoundException The child is not associated with the <code>Layer</code>
+   * @see SGLabel
+   * @see LineKey
+   * @see ColorKey
+   * @see Ruler
+   **/
+  public LayerChild getChild(String labid) throws ChildNotFoundException  {
+    if(!children_.isEmpty()) {
+      LayerChild child;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        child = (LayerChild)it.nextElement();
+        if(child.getId() == labid) return child;
+      }
+      throw new ChildNotFoundException();
+    } else {
+      throw new ChildNotFoundException();
+    }
+  }
+  /**
+   * Create a <code>Enumeration</code> for the
+   * <code>LayerChild</code>'s associated with the <code>Layer</code>.
+   *
+   * @return <code>Enumeration</code> for the <code>LayerChild</code> objects.
+   * @see Enumeration
+   * @see SGLabel
+   * @see LineKey
+   * @see ColorKey
+   * @see Ruler
+   **/
+  public Enumeration childElements() {
+    return children_.elements();
+  }
+
+  /**
+   * @since 3.0
+   */
+  public Iterator childIterator() {
+    return children_.iterator();
+  }
+
+  /**
+   * @since 3.0
+   */
+  public LayerChild[] getChildren() {
+    LayerChild[] childs = new LayerChild[0];
+    childs = (LayerChild[])children_.toArray(childs);
+    return childs;
+  }
+  /**
+   * Set the size of the <code>Layer</code> in physical coordinates.
+   *
+   * @param psize The physical size of the <code>Layer</code>.
+   **/
+  public void setSizeP(Dimension2D psize) {
+    pWidth_ = psize.width;
+    pHeight_ = psize.height;
+    computeScale();
+    modified("Layer: setSizeP()");
+  }
+  /**
+   * Get the <code>Layer</code> size in physical coordinates.
+   * This returns the physical coordinate size
+   * of the <code>Layer</code>.
+   *
+   * @return A <code>Dimension2D</code> containing the physical size of the <code>Layer</code>.
+   * @see Dimension2D
+   **/
+  public Dimension2D getSizeP() {
+    return new Dimension2D(pWidth_, pHeight_);
+  }
+  /**
+   * Get the <code>Layer</code> bounds in physical coordinates.
+   * The origin of the bounding rectangle,
+   * for a <code>Layer</code>, is always (0,0).
+   *
+   * @return A <code>Rectangle2D.Double</code> containing the physical bounds of the <code>Layer</code>.
+   * @see java.awt.geom.Rectangle2D.Double
+   **/
+  public Rectangle2D.Double getBoundsP() {
+    return new Rectangle2D.Double(0.0, 0.0,
+                                  pWidth_, pHeight_);
+  }
+  /**
+   * Get the <code>Layer</code> identifier.
+   *
+   * @return The identifier.
+   **/
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set the <code>Layer</code> identifier.
+   *
+   * @param id identifier
+   **/
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Set the <code>Pane</code> the <code>Layer</code> is associated with.
+   * This method is called by <code>Pane</code> when the
+   * <code>Pane.add</code> method is exectued.
+   *
+   * @param p The <code>Pane</code>
+   **/
+  public void setPane(AbstractPane p) {
+    pane_ = p;
+    computeScale();
+    modified("Layer: setPane()");
+  }
+  /**
+   * Get the <code>Pane</code> the <code>Layer</code> is associated
+   * with.
+   *
+   * @return Refence to the <code>Pane</code>
+   **/
+  public AbstractPane getPane() {
+    return pane_;
+  }
+  /**
+   * Used internally by sgt.
+   * @param mess message
+   * @since 2.0
+   */
+  public void modified(String mess) {
+    if(pane_ != null) {
+//      if(Debug.EVENT) System.out.println("Layer: modified(" + mess + ")");
+      pane_.setModified(true, mess);
+    }
+  }
+  /**
+   * Find object associated with a MOUSE_DOWN event. The getObjectAt method
+   * scans through all the objects associated with the layer to find one
+   * whose bounding box contains the mouse location.
+   *
+   * This method should not be called by a user.
+   *
+   * @param pt device coordinates
+   * @param check if true requires that object isSelectable
+   * @return object at location
+   **/
+  public Object getObjectAt(int x, int y, boolean check) {
+    return getObjectAt(new Point(x, y), check);
+  }
+  /**
+   * Find object associated with a MOUSE_DOWN event. The getObjectAt method
+   * scans through all the objects associated with the layer to find one
+   * whose bounding box contains the mouse location.
+   *
+   * This method should not be called by a user.
+   *
+   * @param pt device coordinates
+   * @return object at location
+   **/
+  public Object getObjectAt(int x,int y) {
+    return getObjectAt(new Point(x, y), true);
+  }
+  /**
+   * Find object associated with a MOUSE_DOWN event. The getObjectAt method
+   * scans through all the objects associated with the layer to find one
+   * whose bounding box contains the mouse location.
+   *
+   * This method should not be called by a user.
+   *
+   * @param pt device coordinates
+   * @param check if true requires that object isSelectable
+   * @return object at location
+   **/
+  public Object getObjectAt(Point pt, boolean check) {
+    Rectangle bnds;
+    Object obj;
+    if(!children_.isEmpty()) {
+      LayerChild child;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        child = (LayerChild)it.nextElement();
+        bnds = child.getBounds();
+        if(bnds.contains(pt) && (!check || child.isSelectable()) &&
+           child.isVisible()) {
+          if(child instanceof LineKey) {
+            return ((LineKey)child).getObjectAt(pt);
+          } else if(child instanceof PointCollectionKey) {
+            return ((PointCollectionKey)child).getObjectAt(pt);
+          } else if(child instanceof VectorKey) {
+            return ((VectorKey)child).getObjectAt(pt);
+          } else {
+            return child;
+          }
+        }
+      }
+    }
+    if(graph_ != null) {
+      obj = graph_.getObjectAt(pt);
+      if(obj != null) return obj;
+    }
+    return (Object) null;
+  }
+
+  /**
+   * Find objects associated with a MOUSE_DOWN event. The getObjecstAt method
+   * scans through all the objects associated with the layer to find those
+   * whose bounding box contains the mouse location.
+   *
+   * This method should not be called by a user.
+   *
+   * @param x mouse coordinate
+   * @param y mouse coordinate
+   * @param check if selectable
+   * @return object array
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(int x, int y, boolean check) {
+    Point pt = new Point(x, y);
+    Vector obList = new Vector();
+    Object obj = null;
+    Rectangle bnds;
+    if(!children_.isEmpty()) {
+      LayerChild child;
+      for(Enumeration it = children_.elements(); it.hasMoreElements();) {
+        child = (LayerChild)it.nextElement();
+        bnds = child.getBounds();
+        if(bnds.contains(pt) && (!check || child.isSelectable()) &&
+           child.isVisible()) {
+          if(child instanceof LineKey) {
+            obj = ((LineKey)child).getObjectAt(pt);
+            if(obj != null) obList.add(obj);
+          } else if(child instanceof PointCollectionKey) {
+            obj = ((PointCollectionKey)child).getObjectAt(pt);
+            if(obj != null) obList.add(obj);
+          } else if(child instanceof VectorKey) {
+            obj = ((VectorKey)child).getObjectAt(pt);
+            if(obj != null) obList.add(obj);
+          } else {
+            if(child != null) obList.add(child);
+          }
+        }
+      }
+    }
+    if(graph_ != null) {
+      obj = graph_.getObjectAt(pt);
+      if(obj != null) obList.add(obj);
+    }
+
+    return obList.toArray();
+  }
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>Layer</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  /**
+   * Checks to see if a data id matches that data attached to the
+   * <code>Graph</code>.
+   * @param id data identifier
+   * @return true if data is in layer
+   * @since 2.0
+   */
+  public boolean isDataInLayer(String id) {
+    if(graph_ instanceof CartesianGraph) {
+      CartesianRenderer cr = ((CartesianGraph)graph_).getRenderer();
+      if(cr instanceof LineCartesianRenderer) {
+        if(((LineCartesianRenderer)cr).hasCollection()) {
+          Collection co = ((LineCartesianRenderer)cr).getCollection();
+          for(Enumeration it = co.elements(); it.hasMoreElements();) {
+            if(((SGTData)it.nextElement()).getId().equals(id)) return true;
+          }
+        } else {
+          return ((LineCartesianRenderer)cr).getLine().getId().equals(id);
+        }
+      } else if(cr instanceof GridCartesianRenderer) {
+        return ((GridCartesianRenderer)cr).getGrid().getId().equals(id);
+      } else if(cr instanceof PointCartesianRenderer) {
+        if(((PointCartesianRenderer)cr).hasCollection()) {
+          Collection co = ((PointCartesianRenderer)cr).getCollection();
+          for(Enumeration it = co.elements(); it.hasMoreElements();) {
+            if(((SGTData)it.nextElement()).getId().equals(id)) return true;
+          }
+        } else {
+          return ((PointCartesianRenderer)cr).getPoint().getId().equals(id);
+        }
+      }
+    }
+    return false;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerChild.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerChild.java
new file mode 100755
index 0000000..85fae96
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerChild.java
@@ -0,0 +1,103 @@
+/*
+ * $Id: LayerChild.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+ 
+/**
+ * <code>LayerChild</code> defines an interface to allow classes to be
+ * associated with a <code>Layer</code>. The interface is sufficient to
+ * provide scaling, translation, and mouse selection.
+ * 
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public interface LayerChild extends Selectable {
+
+  /**
+   * Draw the <code>LayerChild</code>.
+   * 
+   * @param g Graphics context
+   * @exception LayerNotFoundException No layer is associated with the <code>LayerChild</code>.
+   */
+  public void draw(Graphics g) throws LayerNotFoundException ;
+
+  /**
+   * Get the associated <code>Layer</code>.
+   * 
+   * @return Associated layer
+   */
+  public Layer getLayer();
+
+  /**
+   * Associate a <code>Layer</code> with the <code>LayerChild</code>.
+   * 
+   * @param l Parent layer.
+   */
+  public void setLayer(Layer l);
+
+  /**
+   * Get the identifier.
+   * 
+   * @return <code>LayerChild</code> identification.
+   */
+  public String getId();
+
+  /**
+   * Set the identifier.
+   * 
+   * @param id <code>LayerChild</code> identification.
+   */
+  public void setId(String id);
+
+  /**
+   * Create a copy of the <code>LayerChild</code>.
+   * 
+   * @return A copy of the <code>LayerChild</code>.
+   */
+  public LayerChild copy();
+
+  /**
+   * Return a string that represents the <code>LayerChild</code>.
+   * 
+   * @return Stringified <code>LayerChild</code> representation.
+   */
+  public String toString();
+
+  /**
+   * Check if <code>LayerChild</code> is visible.
+   *
+   * @since 2.0
+   * @return true if visible
+   */
+  public boolean isVisible();
+
+  /**
+   * Set visibility for a <code>LayerChild</code>.
+   *
+   * @since 2.0
+   * @param visible visible if true
+   */
+  public void setVisible(boolean visible);
+  /**
+   * Get <code>AbstractPane</code> of the <code>LayerChild</code>.
+   * @since 2.0
+   */
+  public AbstractPane getPane();
+  /**
+   * Used by sgt internally.
+   * @since 2.0
+   */
+  public void modified(String mess);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerContainer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerContainer.java
new file mode 100755
index 0000000..ae738ee
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerContainer.java
@@ -0,0 +1,63 @@
+/*
+ * $Id: LayerContainer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.awt.*;
+import java.beans.*;
+/**
+ * A <code>Container</code> designed hold <code>Layer</code>s.
+ * The <code>LayerContainer</code> improves the flexiblity in
+ * laying out multiple stacked <code>Layer</code>s on a <code>Pane</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see StackedLayout
+ * @see Pane
+ * @see Layer
+ */
+public class LayerContainer extends java.awt.Container implements LayerControl {
+  AbstractPane pane_;
+
+  public LayerContainer() {
+    super();
+  }
+  /**
+   * Used internally by sgt.
+   */
+  public void setPane(AbstractPane pane) {
+    pane_ = pane;
+  }
+  /**
+   * Used internally by sgt.
+   */
+  public void draw(Graphics g) throws PaneNotFoundException {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Used internally by sgt.
+   * @since 2.0
+   */
+  public void drawDraggableItems(Graphics g) throws PaneNotFoundException {
+    /**@todo Implement this gov.noaa.pmel.sgt.LayerControl method*/
+    throw new java.lang.UnsupportedOperationException("Method drawDraggableItems() not yet implemented.");
+  }
+
+  /**
+   * Get identifier.
+   * @return identifier/name
+   */
+  public String getId() {
+    return getName();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerControl.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerControl.java
new file mode 100755
index 0000000..7359fbe
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerControl.java
@@ -0,0 +1,50 @@
+/*
+ * $Id: LayerControl.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import java.awt.Graphics;
+
+/**
+ * Used internally by SGT to work with <code>Layer</code> and
+ * <code>LayerContainer</code>.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 3.0
+ **/
+public interface LayerControl {
+  /**
+   * Used internally by sgt.
+   * @param pane Parent pane
+   */
+  void setPane(AbstractPane pane);
+  /**
+   * Used internally by sgt.
+   * @param g Graphics object
+   * @throws PaneNotFoundException Pane not found.
+   */
+  void draw(Graphics g) throws PaneNotFoundException;
+  /**
+   * Used internally by sgt.
+   * @since 2.0
+   * @param g Graphics object.
+   * @throws PaneNotFoundException Pane not found.
+   */
+  void drawDraggableItems(Graphics g) throws PaneNotFoundException;
+
+  /**
+   * Get identifier of layer.  Internally uses getName() method for <code>Panel</code>.
+   * @since 3.0
+   * @return identifier
+   */
+  String getId();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerNotFoundException.java
new file mode 100755
index 0000000..97f4fa5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerNotFoundException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: LayerNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Operation failed because the layer was not found.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class LayerNotFoundException extends SGException {
+  public LayerNotFoundException() {
+    super();
+  }
+  public LayerNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerStack.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerStack.java
new file mode 100755
index 0000000..879b4f1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LayerStack.java
@@ -0,0 +1,40 @@
+/*
+ * $Id: LayerStack.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.awt.Container;
+import java.awt.Graphics;
+/**
+ * <code>LayerStack</code> is used to manage a group of layers together.
+ * @since 2.x
+ */
+public class LayerStack extends Container implements LayerControl {
+    public LayerStack() {
+        setLayout(new StackedLayout());
+    }
+  public void setPane(AbstractPane pane) {
+    /**@todo Implement this gov.noaa.pmel.sgt.LayerControl method*/
+    throw new java.lang.UnsupportedOperationException("Method setPane() not yet implemented.");
+  }
+  public void draw(Graphics g) {
+    /**@todo Implement this gov.noaa.pmel.sgt.LayerControl method*/
+    throw new java.lang.UnsupportedOperationException("Method draw() not yet implemented.");
+  }
+  public void drawDraggableItems(Graphics g) {
+    /**@todo Implement this gov.noaa.pmel.sgt.LayerControl method*/
+    throw new java.lang.UnsupportedOperationException("Method drawDraggableItems() not yet implemented.");
+  }
+  public String getId() {
+    return getName();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineAttribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineAttribute.java
new file mode 100755
index 0000000..35e750e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineAttribute.java
@@ -0,0 +1,475 @@
+/*
+ * $Id: LineAttribute.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * Sets the rendering style for line data.
+ * <code>Color</code>, width, and dash characteristics are
+ * <code>LineAttribute</code> properties.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see LineCartesianRenderer
+ * @see ContourLevels
+ */
+public class LineAttribute implements Attribute, Cloneable {
+  protected transient PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+
+  private boolean batch_ = false;
+  private boolean local_ = true;
+  private boolean modified_ = false;
+  private String id_ =  null;
+  private Color color_ = Color.black;
+  private int style_;
+  private int mark_ = 1;
+  private double markHeightP_ = 0.2;
+  private float width_ = 2.0f;
+  private float dashes_[] = {12.0f, 12.0f};
+  private float dashPhase_ = 0.0f;
+  private int cap_style_ = CAP_SQUARE;
+  private int miter_style_ = JOIN_MITER;
+  private float miter_limit_ = 10.0f;
+
+  private static float HEAVY_WIDTH = 2.0f;
+  /**
+   * Solid line style.
+   */
+  public static final int SOLID = 0;
+  /**
+   * Dashed line style.
+   */
+  public static final int DASHED = 1;
+  /**
+   * Heavy line style
+   * @since 2.0
+   */
+  public static final int HEAVY = 2;
+  /**
+   * Highlighted line style.  Accomplished by drawing
+   * the line over a contrasting polygon of the same shape.
+   */
+  public static final int HIGHLIGHT = 3;
+  /**
+   * Mark line style.
+   *
+   * @see PlotMark
+  **/
+  public static final int MARK = 4;
+  /**
+   * Mark with connecting lines style.
+   */
+  public static final int MARK_LINE = 5;
+  /**
+   * Stroke.
+   */
+  public static final int STROKE = 6;
+  /**
+   * Cap styles
+   */
+  public static final int CAP_BUTT = 0;
+  public static final int CAP_ROUND = 1;
+  public static final int CAP_SQUARE = 2;
+  /**
+   * Join styles
+   */
+  public static final int JOIN_MITER = 0;
+  public static final int JOIN_ROUND = 1;
+  public static final int JOIN_BEVEL = 2;
+
+
+  /**
+   * Default constructor.  Default style is SOLID and
+   * default color is red.
+   **/
+  public LineAttribute() {
+    this(SOLID, Color.red);
+  }
+  /**
+   * Construct <code>LineAttribute</code> with <code>Color.black</code>.
+   */
+  public LineAttribute(int style) {
+    style_ = style;
+    if(style_ == HEAVY) width_ = HEAVY_WIDTH;
+  }
+
+  /**
+   * <code>LineAttribute</code> constructor.
+   *
+   * @param style line style
+   * @param color line <code>Color</code>
+   * @see java.awt.Color
+   **/
+  public LineAttribute(int style,Color color) {
+    this(style, 1, color);
+  }
+  /**
+   * <code>LineAttribute</code> constructor for plot marks.
+   *
+   * @param style line sytle
+   * @param mark plot mark
+   * @param color line <code>Color</code>
+   **/
+  public LineAttribute(int style,int mark,Color color) {
+    style_ = style;
+    mark_ = mark;
+    color_ = color;
+  }
+  /**
+   * Copy the <code>LineAttribute</code>.
+   *
+   * @return new <code>LineAttribute</code>
+   */
+  public Object copy() {
+    LineAttribute newLine;
+    try {
+      newLine = (LineAttribute)clone();
+    } catch (CloneNotSupportedException e) {
+      newLine = new LineAttribute();
+    }
+    return newLine;
+  }
+
+  /**
+   * @since 3.0
+   */
+  public boolean equals(Object obj) {
+    if(obj == null || !(obj instanceof LineAttribute)) return false;
+    LineAttribute attr = (LineAttribute)obj;
+    if((id_ != attr.getId()) ||
+       (!color_.equals(attr.getColor())) ||
+       (style_ != attr.getStyle())) return false;
+    if(style_ == MARK || style_ == MARK_LINE) {
+      if((mark_ != attr.getMark()) ||
+         (markHeightP_ != attr.getMarkHeightP())) return false;
+    }
+    if(style_ == HEAVY) {
+      if(width_ != attr.getWidth()) return false;
+    }
+    if(style_ == STROKE) {
+      if(width_ != attr.getWidth()) return false;
+      if(dashes_.length != attr.getDashArray().length) {
+        return false;
+      } else {
+        float[] dar = attr.getDashArray();
+        for(int i=0; i < dashes_.length; i++) {
+          if(dashes_[i] != dar[i]) return false;
+        }
+      }
+      if((dashPhase_ != attr.getDashPhase()) ||
+         (cap_style_ != attr.getCapStyle()) ||
+         (miter_style_ != attr.getMiterStyle()) ||
+         (miter_limit_ != attr.getMiterLimit())) return false;
+    }
+    return true;
+  }
+  /**
+   * Set mark height.
+   * <BR><B>Property Change:</B> <code>markHeightP</code>.
+   *
+   * @param markh mark height
+   **/
+  public void setMarkHeightP(double markh) {
+    if(markHeightP_ != markh) {
+      Double tempOld = new Double(markHeightP_);
+      markHeightP_ = markh;
+      firePropertyChange("markHeightP",
+                                  tempOld,
+                                  new Double(markHeightP_));
+    }
+  }
+  /**
+   * Get mark height
+   *
+   * @return mark height
+   **/
+  public double getMarkHeightP() {
+    return markHeightP_;
+  }
+  /**
+   * Set the line style.
+   * <BR><B>Property Change:</B> <code>style</code>.
+   *
+   * @param st line style
+   **/
+  public void setStyle(int st) {
+    if(style_ != st) {
+      Integer tempOld = new Integer(style_);
+      style_ = st;
+      firePropertyChange("style",
+                                  tempOld,
+                                  new Integer(style_));
+    }
+  }
+  /**
+   * Set the line <code>Color</code>.
+   * <BR><B>Property Change:</B> <code>color</code>.
+   *
+   * @param c line <code>Color</code>
+   **/
+  public void setColor(Color c) {
+    if(!color_.equals(c)) {
+      Color tempOld = color_;
+      color_ = c;
+      firePropertyChange("color",
+                                  tempOld,
+                                  color_);
+    }
+  }
+  /**
+   * Set the line width in physical units.
+   * <BR><B>Property Change:</B> <code>width</code>.
+   *
+   * @param t line width
+   **/
+  public void setWidth(float t) {
+    if(width_ != t) {
+      Float tempOld = new Float(width_);
+      width_ = t;
+      firePropertyChange("width",
+                                  tempOld,
+                                  new Float(width_));
+    }
+  }
+  /**
+   * Set the dash characteristics.  Lengths are in physical units.
+   * <BR><B>Property Change:</B> <code>dashArray</code>.
+   *
+   **/
+  public void setDashArray(float[] dashes) {
+    if(dashes == null) return;
+    boolean changed = false;
+    if(dashes_.length != dashes.length) {
+      changed = true;
+    } else {
+      for(int i = 0; i < dashes_.length; i++) {
+        if(dashes_[i] != dashes[i]) {
+          changed = true;
+          break;
+        }
+      }
+    }
+    if(changed) {
+      float[] tempOld = dashes_;
+      dashes_ = dashes;
+      firePropertyChange("dashArray",
+                                  tempOld,
+                                  dashes_);
+    }
+  }
+  /**
+   * Get line dash array.
+   * @since 2.0
+   */
+  public float[] getDashArray() {
+    return dashes_;
+  }
+  /**
+   * Set line dash phase.
+   * <BR><B>Property Change:</B> <code>dashPhase</code>.
+   * @since 2.0
+   */
+  public void setDashPhase(float phase) {
+    if(dashPhase_ != phase) {
+      Float tempOld = new Float(dashPhase_);
+      dashPhase_ = phase;
+      firePropertyChange("dashPhase",
+                                  tempOld,
+                                  new Float(dashPhase_));
+    }
+  }
+  /**
+   * Get line dash phase.
+   * @since 2.0
+   */
+  public float getDashPhase() {
+    return dashPhase_;
+  }
+  /**
+   * Get line style.
+   *
+   * @return line style
+   **/
+  public int getStyle() {
+    return style_;
+  }
+  /**
+   * Get line <code>Color</code>.
+   *
+   * @return line <code>Color</code>
+   **/
+  public Color getColor() {
+    return color_;
+  }
+  /**
+   * Get line width.
+   *
+   * @return line width in physcial coordinates.
+   **/
+  public float getWidth() {
+    return width_;
+  }
+  /**
+   * Set plot mark
+   * <BR><B>Property Change:</B> <code>mark</code>.
+   *
+   * @param mark the plot mark
+   **/
+  public void setMark(int mark) {
+    if(mark_ != mark) {
+      Integer tempOld = new Integer(mark_);
+      if(mark <= 0) mark = 1;
+      if(mark > 51) mark = 51;
+      mark_ = mark;
+      firePropertyChange("mark",
+                                  tempOld,
+                                  new Integer(mark_));
+    }
+  }
+  /**
+   * Get plot mark
+   *
+   * @return plot mark
+   **/
+  public int getMark() {
+    return mark_;
+  }
+  /**
+   * Set the current line cap style.  Cap styles include
+   * <code>CAP_BUTT</code>, <code>CAP_ROUND</code>, and
+   * <code>CAP_SQUARE</code>.
+   * <BR><B>Property Change:</B> <code>capStyle</code>.
+   */
+  public void setCapStyle(int style) {
+    if(cap_style_ != style) {
+      Integer tempOld = new Integer(cap_style_);
+      cap_style_ = style;
+      firePropertyChange("capStyle",
+                                  tempOld,
+                                  new Integer(cap_style_));
+    }
+  }
+  /**
+   * Get the current line cap style.
+   */
+  public int getCapStyle() {
+    return cap_style_;
+  }
+  /**
+   * Set the current miter style. Styles include
+   * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code>, and
+   * <code>JOIN_BEVEL</code>.
+   * <BR><B>Property Change:</B> <code>miterStyle</code>.   */
+  public void setMiterStyle(int style) {
+    if(miter_style_ != style) {
+      Integer tempOld = new Integer(miter_style_);
+      miter_style_ = style;
+      firePropertyChange("miterStyle",
+                                  tempOld,
+                                  new Integer(miter_style_));
+    }
+  }
+  /**
+   * Get the current miter sytle.
+   */
+  public int getMiterStyle() {
+    return miter_style_;
+  }
+  /**
+   * Set the miter limit.
+   * <BR><B>Property Change:</B> <code>miterLimit</code>.
+   */
+  public void setMiterLimit(float limit) {
+    if(miter_limit_ != limit) {
+      Float tempOld = new Float(miter_limit_);
+      miter_limit_ = limit;
+      firePropertyChange("miterLimit",
+                                  tempOld,
+                                  new Float(miter_limit_));
+    }
+  }
+  /**
+   * Get the current miter limit.
+   */
+  public float getMiterLimit() {
+    return miter_limit_;
+  }
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>LineAttribute</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1);
+  }
+  /**
+   * Add listener to changes in <code>LineAttribute</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.addPropertyChangeListener(listener);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setId(String id) {
+    id_ = id;
+  }
+  /**
+   * @since 3.0
+   */
+  public String getId() {
+    return id_;
+  }
+
+  protected void firePropertyChange(String name, Object oldValue, Object newValue) {
+    if(batch_) {
+      modified_ = true;
+      return;
+    }
+    AttributeChangeEvent ace = new AttributeChangeEvent(this, name,
+                                                        oldValue, newValue,
+                                                        local_);
+    changes_.firePropertyChange(ace);
+    modified_ = false;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch) {
+    setBatch(batch, true);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch, boolean local) {
+    local_ = local;
+    batch_ = batch;
+    if(!batch && modified_) firePropertyChange("batch", Boolean.TRUE, Boolean.FALSE);
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean isBatch() {
+    return batch_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineCartesianRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineCartesianRenderer.java
new file mode 100755
index 0000000..eddea61
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineCartesianRenderer.java
@@ -0,0 +1,362 @@
+/*
+ * $Id: LineCartesianRenderer.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.Collection;
+
+//import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Event;
+import java.awt.Point;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Produces a line plot with optional coloring from a second data set. If
+ * a second data set is specified it must have the same shape as the first.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public class LineCartesianRenderer extends CartesianRenderer {
+  /**@shapeType AggregationLink
+   * @label attr
+   * @undirected
+   * @supplierCardinality 1 */
+  private LineAttribute attr_ = null;
+  /**@shapeType AggregationLink
+   * @supplierCardinality 0..1
+   * @label line
+   * @undirected */
+  private SGTLine line_ = null;
+  /**@shapeType AggregationLink
+   * @supplierCardinality 0..1 */
+  private Collection collection_ = null;
+
+  private StrokeDrawer stroke_ = null;
+
+  /**
+   * Get the <code>Attribute</code> associated with the data.
+   */
+  public Attribute getAttribute() {
+    return attr_;
+  }
+  private void drawLine(Graphics g, SGTLine line, LineAttribute attr) {
+    int[] xp, yp;
+    int[] xout, yout;
+    int count, size, nout;
+    double[] xValues, yValues;
+    long[] xTValues, yTValues;
+
+    if(line.isXTime()) {
+      xTValues = line.getGeoDateArray().getTime();
+      size = xTValues.length;
+      xp = new int[size];
+      for(count=0; count < size; count++) {
+        xp[count] = cg_.getXUtoD(xTValues[count]);
+      }
+    } else {
+      xValues = line.getXArray();
+      size = xValues.length;
+      xp = new int[size];
+      for(count=0; count < size; count++) {
+        xp[count] = cg_.getXUtoD(xValues[count]);
+      }
+    }
+    //
+    if(line.isYTime()) {
+      yTValues = line.getGeoDateArray().getTime();
+      size = yTValues.length;
+      yp = new int[size];
+      for(count=0; count < size; count++) {
+        yp[count] = cg_.getYUtoD(yTValues[count]);
+      }
+    } else {
+      yValues = line.getYArray();
+      size = yValues.length;
+      yp = new int[size];
+      for(count=0; count < size; count++) {
+        yp[count] = cg_.getYUtoD(yValues[count]);
+      }
+    }
+    //
+    // check for missing values a Double.NaN is converted to a Integer.MIN_VALUE
+    //
+    int first = 0;
+    int lsize = 0;
+    xout = new int[size];
+    yout = new int[size];
+    while (first < size) {
+      nout=-1;
+    line:
+      for(count=first; count < size; count++) {
+        if(xp[count] != Integer.MIN_VALUE && yp[count] != Integer.MIN_VALUE) {
+          nout++;
+          xout[nout] = xp[count];
+          yout[nout] = yp[count];
+        } else if (nout >= 0) {
+          break line;
+        }
+      }
+      first = count + 1;
+      lsize = nout + 1;
+      if(lsize <= 0) return;
+      //
+      // draw regular line
+      //
+      switch(attr.getStyle()) {
+      case LineAttribute.MARK:
+        drawMark(g, xout, yout, lsize, attr);
+        break;
+      case LineAttribute.HIGHLIGHT:
+        stroke_.drawHighlight(g, xout, yout, lsize, attr);
+        break;
+      case LineAttribute.HEAVY:
+        stroke_.drawHeavy(g, xout, yout, lsize, attr);
+        break;
+      case LineAttribute.DASHED:
+        stroke_.drawDashed(g, xout, yout, lsize, attr);
+        break;
+      case LineAttribute.STROKE:
+        stroke_.drawStroke(g, xout, yout , lsize, attr);
+        break;
+      case LineAttribute.MARK_LINE:
+        drawMark(g, xout, yout, lsize, attr);
+      default:
+      case LineAttribute.SOLID:
+        g.drawPolyline(xout, yout, lsize);
+      }
+    }
+  }
+  /**
+   * Draw a mark at the requested location. This routine is used by LineCartesianGraph and
+   * LineKey.
+   *
+   * @param g Graphics object
+   * @param xp horizontal coordinate
+   * @param yp vertical coordinate
+   * @param attr line attribute
+   * @see LineKey
+   */
+  protected void drawMark(Graphics g, int[] xp, int[] yp,
+                          int npoints, LineAttribute attr) {
+    Layer ly = cg_.getLayer();
+    PlotMark pm = new PlotMark(attr);
+
+    for(int i=0; i < npoints; i++) {
+      pm.paintMark(g, ly, xp[i], yp[i]);
+    }
+  }
+
+  /**
+   * Default constructor.
+   *
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public LineCartesianRenderer(CartesianGraph cg) {
+    this(cg, (SGTLine)null, null);
+  }
+  /**
+   * Construct a <code>LineCartesianRenderer</code>. The default
+   * <code>LineAttribute</code> will be used.
+   *
+   * @param cg the parent <code>CartesianGraph</code>
+   * @param data an <code>SGTLine</code> object
+   *
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public LineCartesianRenderer(CartesianGraph cg, SGTLine line) {
+    this(cg, line, null);
+    cg_ = cg;
+    line_ = line;
+  }
+  /**
+   * Construct a <code>LineCartesianRenderer</code>.
+   *
+   * @param cg the parent <code>CartesianGraph</code>
+   * @param data an <code>SGTLine</code>
+   * @param line the <code>LineAttribute</code>
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public LineCartesianRenderer(CartesianGraph cg, SGTLine line, LineAttribute attr) {
+    cg_ = cg;
+    line_ = line;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+    stroke_ = PaneProxy.strokeDrawer;
+  }
+  /**
+   * Construct a <code>LineCartesianRenderer</code>.
+   *
+   * @param cg the parent <code>CartesianGraph</code>
+   * @param col a <code>Collection</code> of <code>SGTLine</code> objects
+   * @param line the <code>LineAttribute</code>
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public LineCartesianRenderer(CartesianGraph cg, Collection col, LineAttribute attr) {
+    cg_ = cg;
+    collection_ = col;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+    stroke_ = PaneProxy.strokeDrawer;
+  }
+  /**
+   * Render the <code>SGTData</code>. This method should not
+   * be directly called.
+   *
+   * @param g graphics context
+   *
+   * @see Pane#draw
+   */
+  public void draw(Graphics g) {
+    LineAttribute attr;
+    Object line;
+
+    if(cg_.clipping_) {
+      int xmin, xmax, ymin, ymax;
+      int x, y, width, height;
+      if(cg_.xTransform_.isSpace()) {
+        xmin = cg_.getXUtoD(cg_.xClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.xClipRange_.end);
+      } else {
+        xmin = cg_.getXUtoD(cg_.tClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.tClipRange_.end);
+      }
+      if(cg_.yTransform_.isSpace()) {
+        ymin = cg_.getYUtoD(cg_.yClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.yClipRange_.end);
+      } else {
+        ymin = cg_.getYUtoD(cg_.tClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.tClipRange_.end);
+      }
+      if(xmin < xmax) {
+        x = xmin;
+        width = xmax - xmin;
+      } else {
+        x=xmax;
+        width = xmin - xmax;
+      }
+      if(ymin < ymax) {
+        y = ymin;
+        height = ymax - ymin;
+      } else {
+        y = ymax;
+        height = ymin - ymax;
+      }
+      g.setClip(x, y, width, height);
+    }
+    if(attr_ == null) {
+      attr = new LineAttribute(LineAttribute.SOLID,
+                cg_.getPane().getComponent().getForeground());
+    } else {
+      attr = attr_;
+    }
+    g.setColor(attr.getColor());
+    if(collection_ == null) {
+      drawLine(g, line_, attr);
+    } else {
+      for(Enumeration li = collection_.elements(); li.hasMoreElements();) {
+        line = li.nextElement();
+        if(line instanceof SGTLine) {
+          drawLine(g, (SGTLine)line, attr);
+        }
+      }
+    }
+
+    //
+    // reset clip
+    //
+    Rectangle rect = cg_.getLayer().getPane().getBounds();
+    g.setClip(rect);
+  }
+  /**
+   * Set the <code>LineAttribute</code>. The line appearance is controlled by
+   * this object.
+   *
+   * @param l <code>LineAttribute</code>
+   **/
+  public void setLineAttribute(LineAttribute l) {
+    if(attr_ != null) attr_.removePropertyChangeListener(this);
+    attr_ = l;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Get the <code>LineAttribute</code>.
+   *
+   * @return <code>LineAttribute</code>
+   **/
+  public LineAttribute getLineAttribute() {
+    return attr_;
+  }
+  /**
+   * Test if a <code>Collection</code> of <code>SGTLine</code>
+   * was using to construct this renderer.
+   *
+   * @return true if <code>Collection</code> was used
+   */
+  public boolean hasCollection() {
+    return (collection_ != null);
+  }
+  /**
+   * Get the <code>Collection</code> of <code>SGTLine</code> objects.
+   *
+   * @return <code>Collection</code>
+   */
+  public Collection getCollection() {
+    return collection_;
+  }
+  /**
+   * Get the <code>SGTLine</code> object.
+   *
+   * @return <code>SGTLine</code>
+   */
+  public SGTLine getLine(){
+    return line_;
+  }
+  /**
+   * Get the associated <code>CartesianGraph</code> object.
+   *
+   * @return <code>CartesianGraph</code>
+   */
+  public CartesianGraph getCartesianGraph() {
+    return cg_;
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+//      if(Debug.EVENT) {
+//        System.out.println("LineCartesianRenderer: " + evt);
+//        System.out.println("                       " + evt.getPropertyName());
+//      }
+    modified("LineCartesianRenderer: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  /**
+   * @since 3.0
+   */
+  public SGTData getDataAt(Point pt) {
+    return null;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineKey.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineKey.java
new file mode 100755
index 0000000..4c293c2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LineKey.java
@@ -0,0 +1,748 @@
+/*
+ * $Id: LineKey.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeSupport;
+
+// jdk1.2
+//import java.awt.geom.Point2D;
+
+/**
+ * <code>LineKey</code> is used to create a key for the
+ * <code>LineCartesianRenderer</code>. Multiple
+ * lines can be included in the key.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+**/
+public class LineKey implements Cloneable,
+        DataKey, Moveable, PropertyChangeListener {
+  private String ident_;
+/** @directed */
+  private Layer layer_;
+  /** @link aggregation
+   * @supplierCardinality *
+   * @label line*/
+  /*#LineCartesianRenderer lnkLineCartesianRenderer;*/
+  private Vector line_;
+  /** @link aggregation
+   * @supplierCardinality *
+   * @label label*/
+  /*#SGLabel lnkSGLabel;*/
+  private Vector label_;
+  private int columns_;
+  private int style_;
+  private int valign_;
+  private int halign_;
+  private Point2D.Double porigin_;
+  private double lineLengthP_;
+  private int maxLabelLength_;
+  private int maxLabelHeight_;
+  private StrokeDrawer stroke_ = null;
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean visible_;
+  private boolean moveable_;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private static final int VERTICAL_BORDER_ = 3;
+  private static final int HORIZONTAL_BORDER_ = 15;
+  private static final int COLUMN_SPACE_ = 10;
+  private static final int ROW_SPACE_ = 3;
+  private static final int LABEL_SPACE_ = 15;
+  /**
+   * Use plain line border.
+   */
+  public static final int PLAIN_LINE = 0;
+  /**
+   * Use raised border.
+   */
+  public static final int RAISED = 1;
+  /**
+   * Do not draw a border.
+   */
+  public static final int NO_BORDER = 2;
+  /**
+   * Align to top of key.
+   */
+  public static final int TOP = 0;
+  /**
+   * Align to middle of key.
+   */
+  public static final int MIDDLE = 1;
+  /**
+   * Align to bottom of key.
+   */
+  public static final int BOTTOM = 2;
+  /**
+   * Align to left of key.
+   */
+  public static final int LEFT = 0;
+  /**
+   * Align to center of key.
+   */
+  public static final int CENTER = 1;
+  /**
+   * Align to right of key.
+   */
+  public static final int RIGHT = 2;
+
+
+  /**
+   * Default constructor.
+   */
+  public LineKey() {
+    this(new Point2D.Double(0.0, 0.0), BOTTOM, LEFT);
+  }
+  /**
+   *
+   */
+  public LineKey(Point2D.Double loc,int valign,int halign) {
+    porigin_ = loc;
+    valign_ = valign;
+    halign_ = halign;
+    line_ = new Vector(2,2);
+    label_ = new Vector(2,2);
+    //
+    // set defaults
+    //
+    style_ = PLAIN_LINE;
+    columns_ = 1;
+    ident_ = "";
+    lineLengthP_ = 0.3f;
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+    moveable_ = true;
+    stroke_ = PaneProxy.strokeDrawer;
+  }
+  /**
+   * Create of copy of LineKey.
+   */
+  public LayerChild copy() {
+    LineKey newKey;
+    try {
+      newKey = (LineKey)clone();
+    } catch (CloneNotSupportedException e) {
+      newKey = new LineKey();
+    }
+    newKey.line_ = new Vector(2,2);
+    newKey.label_ = new Vector(2,2);
+    return newKey;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  public boolean isMoveable() {
+    return moveable_;
+  }
+  public void setMoveable(boolean moveable) {
+    moveable_ = moveable;
+  }
+  /**
+   * Set parent layer.
+   *
+   * @param l parent layer
+   */
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  /**
+   * Get layer.
+   *
+   * @return layer
+   */
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+
+  public void modified(String mess) {
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Set LineKey identifier.
+   *
+   * @param id key identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get LineKey identifier
+   *
+   * @return identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set line length.
+   *
+   * @param len line length
+   */
+  public void setLineLengthP(double len) {
+    if(lineLengthP_ != len) {
+      lineLengthP_ = len;
+      modified("LineKey: setLineLengthP()");
+    }
+  }
+  /**
+   * Get line length
+   *
+   * @return line length
+   */
+  public double getLineLengthP() {
+    return lineLengthP_;
+  }
+  /**
+   * Set the number of columns.
+   *
+   * @param col number of columns
+   */
+  public void setColumns(int col) {
+    if(columns_ != col) {
+      columns_ = col;
+      modified("LineKey: setColumms()");
+    }
+  }
+  /**
+   * Get the number of columns.
+   *
+   * @return number of columns
+   */
+  public int getColumns() {
+    return columns_;
+  }
+  /**
+   * Set border style.
+   *
+   * @param style border style
+   * @see #PLAIN_LINE
+   * @see #RAISED
+   * @see #NO_BORDER
+   */
+  public void setBorderStyle(int style) {
+    if(style_ != style) {
+      style_ = style;
+      modified("LineKey: setBorderStyle()");
+    }
+  }
+  /**
+   * Get border style.
+   *
+   * @return border style
+   */
+  public int getBorderStyle() {
+    return style_;
+  }
+  /**
+   * Set alignment.
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   */
+  public void setAlign(int vert,int horz) {
+    if(valign_ != vert || halign_ != horz) {
+      valign_ = vert;
+      halign_ = horz;
+      modified("LineKey: setAlign()");
+    }
+  }
+  /**
+   * Set vertical alignment
+   *
+   * @param vert vertical alignment
+   */
+  public void setVAlign(int vert) {
+    if(valign_ != vert) {
+      valign_ = vert;
+      modified("LineKey: setVAlign()");
+    }
+  }
+  /**
+   * Set horizontal alignment
+   *
+   * @param horz horizontal alignment
+   */
+  public void setHAlign(int horz) {
+    if(halign_ != horz) {
+      halign_ = horz;
+      modified("LineKey: setHAlign()");
+    }
+  }
+  /**
+   * Get vertical alignment
+   *
+   * @return vertical alignment
+   */
+  public int getVAlign() {
+    return valign_;
+  }
+  /**
+   * Get horizontal alignment
+   *
+   * @return horizontal alignment
+   */
+  public int getHAlign() {
+    return halign_;
+  }
+  /**
+   * Set location of key
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @param loc key location
+   */
+  public void setLocationP(Point2D.Double loc) {
+    if(porigin_ == null || !porigin_.equals(loc)) {
+      Point2D.Double temp = porigin_;
+      porigin_ = loc;
+      changes_.firePropertyChange("location",
+          temp,
+          porigin_);
+      modified("LineKey: setLocationP()");
+    }
+  }
+  /**
+   * Set the bounds of the <code>LineKey</code> in physical units.
+   */
+  public void setBoundsP(Rectangle2D.Double r) {
+    setLocationP(new Point2D.Double(r.x, r.y));
+  }
+  /**
+   * Get key bounds in physical coordinates.
+   * Not presently implemented.
+   */
+  public Rectangle2D.Double getBoundsP() {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Get location of key.
+   *
+   * @return Key location
+   */
+  public Point2D.Double getLocationP() {
+    return porigin_;
+  }
+  /**
+   * Add a LineCartesianRenderer and label to the LineKey.
+   *
+   * @param line LineCartesianGraph object
+   * @param label descriptive label
+   */
+  public void addLineGraph(LineCartesianRenderer line, SGLabel label) {
+    line_.addElement(line);
+    label.setLayer(layer_);
+    label.setMoveable(false);
+    label.setSelectable(false);
+    label_.addElement(label);
+    ((LineAttribute)line.getAttribute()).addPropertyChangeListener(this);
+    modified("LineKey: addLineGraph()");
+  }
+  /**
+   * Add a LineCartesianRenderer and label to the LineKey.
+   *
+   * @param rend LineCartesianRenderer object
+   * @param label descriptive label
+   * @since 3.0
+   */
+  public void addGraph(CartesianRenderer rend, SGLabel label)
+      throws IllegalArgumentException {
+    if(!(rend instanceof LineCartesianRenderer))
+      throw new IllegalArgumentException("Renderer is not a LineCartesianRenderer");
+    addLineGraph((LineCartesianRenderer)rend, label);
+  }
+  /**
+   * Remove a line from the LineKey.
+   *
+   */
+  public void removeLineGraph(SGLabel label) {
+  }
+  /**
+   * Remove a line from the LineKey.
+   *
+   */
+  public void removeLineRenderer(LineCartesianRenderer line) {
+  }
+  /**
+   * Remove a line from the LineKey.
+   *
+   */
+  public void removeLineGraph(String ident) {
+  }
+  /**
+   * Remove all lines from the LineKey.
+   */
+  public void clearAll() {
+    LineAttribute attr;
+    for(Enumeration e = line_.elements(); e.hasMoreElements(); ) {
+      attr = (LineAttribute)((LineCartesianRenderer)e.nextElement()).getAttribute();
+      attr.removePropertyChangeListener(this);
+    }
+    line_.removeAllElements();
+    label_.removeAllElements();
+    modified("LineKey: clearAll()");
+  }
+  /**
+   * Remove line associated with data id from LineKey.
+   * @since 2.0
+   */
+  public void clear(String data_id) {
+    LineCartesianRenderer lcr;
+    int indx = -1;
+    for(Enumeration it = line_.elements(); it.hasMoreElements();) {
+        indx++;
+        lcr = (LineCartesianRenderer)it.nextElement();
+        if(lcr.getLine().getId().equals(data_id)) {
+    lcr.getAttribute().removePropertyChangeListener(this);
+            line_.removeElement(lcr);
+            label_.removeElementAt(indx);
+      modified("LineKey: clear()");
+            break;
+        }
+    }
+  }
+  /**
+   * Return rowheight of key in pixels.
+   * @since 2.0
+   */
+  public int getRowHeight() {
+    Rectangle bounds;
+    bounds = getBounds();
+    return ROW_SPACE_ + maxLabelHeight_;
+  }
+  /**
+   * Draw the Key.
+   */
+  public void draw(Graphics g) {
+    double maxLabelLength, maxLabelHeight;
+    int numLines, numRows, i, lineLength;
+    int col, row, ytemp;
+    double xloc, labelSpace;
+    double[] xp, yp;
+    int[] xd, yd;
+    int[] xout, yout;
+    Rectangle bounds;
+    LineCartesianRenderer render = null;
+    SGLabel label;
+    LineAttribute attr = null;
+    //
+    numLines = line_.size();
+    if((numLines <= 0) || !visible_) return;
+
+    numRows = numLines/columns_;
+    if(numLines%columns_ != 0) numRows++;
+
+    xp = new double[columns_];
+    xd = new int[columns_];
+    yp = new double[numRows];
+    yd = new int[numRows];
+    xout = new int[2];
+    yout = new int[2];
+
+    g.setColor(layer_.getPane().getComponent().getForeground());
+    bounds = getBounds();
+    //
+    // compute location of rows and columns in device and physical coordinates
+    //
+    lineLength = layer_.getXPtoD(lineLengthP_) - layer_.getXPtoD(0.0f);
+    labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0);
+    //
+    yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_;
+    yp[0] = layer_.getYDtoP(yd[0]);
+    for(i=1; i < numRows; i++) {
+      yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_;
+      yp[i] = layer_.getYDtoP(yd[i]);
+    }
+    xd[0] = bounds.x + HORIZONTAL_BORDER_;
+    xp[0] = layer_.getXDtoP(xd[0]);
+    for(i=1; i < columns_; i++) {
+      xd[i] = xd[i-1] + COLUMN_SPACE_ + lineLength + LABEL_SPACE_ + maxLabelLength_;
+      xp[i] = layer_.getXDtoP(xd[i]);
+    }
+    //
+    row = 0;
+    col = 0;
+    Object obj;
+    Enumeration labelIt = label_.elements();
+    for(Enumeration lineIt = line_.elements(); lineIt.hasMoreElements();) {
+      obj = lineIt.nextElement();
+      render = (LineCartesianRenderer)obj;
+      attr = (LineAttribute)render.getAttribute();
+      label = (SGLabel)labelIt.nextElement();
+      //
+      // draw line
+      //
+      g.setColor(attr.getColor());
+      xout[0] = xd[col];
+      xout[1] = xout[0] + lineLength;
+      yout[0] = yd[row] - maxLabelHeight_/2;
+      yout[1] = yout[0];
+      switch(attr.getStyle()) {
+      case LineAttribute.MARK:
+        render.drawMark(g, xout, yout, 2, attr);
+        break;
+      case LineAttribute.HIGHLIGHT:
+        stroke_.drawHighlight(g, xout, yout, 2, attr);
+        break;
+      case LineAttribute.HEAVY:
+        stroke_.drawHeavy(g, xout, yout, 2, attr);
+        break;
+      case LineAttribute.DASHED:
+        stroke_.drawDashed(g, xout, yout, 2, attr);
+        break;
+      case LineAttribute.STROKE:
+        stroke_.drawStroke(g, xout, yout , 2, attr);
+        break;
+      case LineAttribute.MARK_LINE:
+        render.drawMark(g, xout, yout, 2, attr);
+      default:
+      case LineAttribute.SOLID:
+        g.drawLine(xout[0], yout[0], xout[1], yout[1]);
+      }
+      //
+      xloc = xp[col] + lineLengthP_ + labelSpace;
+      label.setLocationP(new Point2D.Double(xloc, yp[row]));
+      try {
+        label.draw(g);
+      } catch (SGException e) {}
+      //
+      col++;
+      if(col >= columns_) {
+        col = 0;
+        row++;
+      }
+    }
+    switch(style_) {
+    case PLAIN_LINE:
+      g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+      break;
+    case RAISED:
+      break;
+    default:
+    case NO_BORDER:
+    }
+  }
+  /**
+   * Get the bounding rectangle.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds() {
+    int lineLength;
+    int numLines, rows;
+    int x, y, height, width;
+
+    numLines = line_.size();
+    if(numLines <= 0) return new Rectangle(0, 0, 0, 0);
+    //
+    // find longest label
+    //
+    maxLabelLength_ = 0;
+    maxLabelHeight_ = 0;
+    SGLabel label;
+    for(Enumeration it = label_.elements(); it.hasMoreElements();) {
+      label = (SGLabel)it.nextElement();
+      Rectangle sz = label.getBounds();
+      maxLabelLength_ = Math.max(maxLabelLength_, sz.width);
+      maxLabelHeight_ = Math.max(maxLabelHeight_, sz.height);
+    }
+    //
+    rows = numLines/columns_;
+    if(numLines%columns_ != 0) rows++;
+    lineLength = layer_.getXPtoD(lineLengthP_) - layer_.getXPtoD(0.0f);
+    width = 2*HORIZONTAL_BORDER_ + columns_*(lineLength + LABEL_SPACE_ + maxLabelLength_)
+      + (columns_ - 1)*COLUMN_SPACE_;
+    height = 2*VERTICAL_BORDER_ + rows*maxLabelHeight_ + (rows-1)*ROW_SPACE_;
+    //
+    x = layer_.getXPtoD(porigin_.x);
+    y = layer_.getYPtoD(porigin_.y);
+    switch(halign_) {
+    case RIGHT:
+      x = x - width;
+      break;
+    case CENTER:
+      x = x - width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y - height;
+      break;
+    case MIDDLE:
+      y = y - height/2;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+  public Point getLocation() {
+    Rectangle bnds = getBounds();
+    return new Point(bnds.x, bnds.y);
+  }
+  public void setLocation(Point loc) {
+    Rectangle bnds = getBounds();
+    setBounds(loc.x, loc.y, bnds.width, bnds.height);
+  }
+  /**
+   * Set the bounds of the <code>LineKey</code>.
+   */
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  /**
+   * Set the bounds of the <code>LineKey</code>.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    switch(halign_) {
+    case RIGHT:
+      x = x + width;
+      break;
+    case CENTER:
+      x = x + width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y + height;
+      break;
+    case MIDDLE:
+      y = y + height/2;
+    }
+    double xp = layer_.getXDtoP(x);
+    double yp = layer_.getYDtoP(y);
+    if(porigin_.x != xp || porigin_.y != yp) {
+      Point2D.Double temp = porigin_;
+      porigin_.x = xp;
+      porigin_.y = yp;
+      changes_.firePropertyChange("location",
+          temp,
+          new Point2D.Double(xp, yp));
+      modified("LineKey: setBounds()");
+    }
+  }
+  Object getObjectAt(Point pt) {
+    Rectangle lbnds;
+    Rectangle bounds;
+    LineCartesianRenderer line;
+    int[] xout, yout;
+    int[] xd, yd;
+    int numLines, numRows;
+    int lineLength;
+    double labelSpace;
+    int i;
+
+    numLines = line_.size();
+    if(numLines <= 0) return null;
+
+    numRows = numLines/columns_;
+    if(numLines%columns_ != 0) numRows++;
+
+    xd = new int[columns_];
+    yd = new int[numRows];
+    xout = new int[2];
+    yout = new int[2];
+    bounds = getBounds();
+    //
+    // compute location of rows and columns in device and physical coordinates
+    //
+    lineLength = layer_.getXPtoD(lineLengthP_) - layer_.getXPtoD(0.0);
+    labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0);
+    //
+    yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_;
+    for(i=1; i < numRows; i++) {
+      yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_;
+    }
+    xd[0] = bounds.x + HORIZONTAL_BORDER_;
+    for(i=1; i < columns_; i++) {
+      xd[i] = xd[i-1] + COLUMN_SPACE_ + lineLength + LABEL_SPACE_ + maxLabelLength_;
+    }
+    // loop over all the lines
+    int row = 0;
+    int col = 0;
+    for(Enumeration lineIt = line_.elements(); lineIt.hasMoreElements();) {
+      line = (LineCartesianRenderer)lineIt.nextElement();
+      xout[0] = xd[col];
+      xout[1] = xout[0] + lineLength + LABEL_SPACE_ + maxLabelLength_;
+//        xout[1] = xout[0] + lineLength + LABEL_SPACE_;
+      yout[0] = yd[row] - maxLabelHeight_;
+      yout[1] = yd[row];
+      lbnds = new Rectangle(xout[0], yout[0],
+                            xout[1] - xout[0],
+                            yout[1] - yout[0]);
+      if(lbnds.contains(pt)) {
+        return line;
+      }
+      //
+      col++;
+      if(col >= columns_) {
+        col = 0;
+        row++;
+      }
+    }
+    if(bounds.contains(pt)) {
+      return this;
+    }
+    return null;
+  }
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("LineKey: setVisible()");
+    }
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+//      if(Debug.EVENT) {
+//        System.out.println("LineKey: " + evt);
+//        System.out.println("         " + evt.getPropertyName());
+//      }
+    modified("LineKey: propertyChange(" +
+       evt.getSource().toString() + "[" +
+       evt.getPropertyName() + "]" + ")");
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LinearTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LinearTransform.java
new file mode 100755
index 0000000..538ea7f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LinearTransform.java
@@ -0,0 +1,222 @@
+/*
+ * $Id: LinearTransform.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTRange;
+
+/**
+ * Performs a linear transformation on cartesian axes. If the
+ * transformtion is for space the equation is phys = a*user + b
+ * and if time is phys = at*time + bt.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public class LinearTransform extends AxisTransform implements Cloneable {
+  double at_;
+  double bt_;
+  double a_;
+  double b_;
+  /**
+   * Default constructor. Creates a transform with arguments
+   * <code>Transform(0.0, 1.0, 0.0, 1.0)</code>.
+   **/
+  public LinearTransform() {
+    super();
+  }
+  /**
+   * <code>LinearTransform</code> constructor.
+   * This constructor is used to define
+   * transforms that use double user values.
+   *
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @param u1 minimum value, user coordinates
+   * @param u2 maximum value, user coordinates
+   **/
+  public LinearTransform(double p1,double p2,double u1,double u2) {
+    super(p1, p2, u1, u2);
+  }
+  /**
+   * <code>LinearTransform</code> constructor.  This constructor is used to define
+   * transforms that use double user values.
+   *
+   * @param pr physical coordinate range
+   * @param ur user coordinate range
+   * @see Range2D
+   **/
+  public LinearTransform(Range2D pr,Range2D ur) {
+    super(pr, ur);
+  }
+  /**
+   * <code>LinearTransform</code> constructor.  This constructor is used to define
+   * transforms that use <code>GeoDate</code> user values.
+   *
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @param t1 minimum time
+   * @param t2 maximum time
+   * @see GeoDate
+   **/
+  public LinearTransform(double p1,double p2,GeoDate t1,GeoDate t2) {
+    super(p1, p2, t1, t2);
+  }
+  /**
+   * <code>LinearTransform</code> constructor.  This constructor is used to define
+   * transforms that use <code>GeoDate</code> user values.
+   *
+   * @param pr physical coordinates range
+   * @param tr time range
+   * @see Range2D
+   * @see TimeRange
+   * @see GeoDate
+   **/
+  public LinearTransform(Range2D pr,TimeRange tr) {
+    super(pr, tr);
+  }
+  /**
+   * <code>LinearTransform</code> constructor.  This constructor is used to define
+   * transforms that use <code>SoTRange</code> user values.
+   *
+   * @since 2.0
+   * @param pr physical coordinates range
+   * @param str space or time range
+   * @see SoTRange
+   * @see Range2D
+   **/
+  public LinearTransform(Range2D pr, SoTRange str) {
+    super(pr, str);
+  }
+  /**
+   * Transform from user to physical coordinates.
+   *
+   * @param u user value
+   * @return physical value
+   */
+  public double getTransP(double u) {
+    return a_*u + b_;
+  }
+  /**
+   * Create a copy of the <code>LinearTransform</code>.
+   *
+   * @return the copy
+   */
+  public AxisTransform copy() {
+    LinearTransform newTransform;
+    try {
+      newTransform = (LinearTransform)clone();
+    } catch (CloneNotSupportedException e) {
+      newTransform = new LinearTransform();
+    }
+    return (AxisTransform)newTransform;
+  }
+  //
+  /**
+   * Transform from time to physical coordinates.
+   *
+   * @param t time
+   * @return user value
+   */
+  public double getTransP(GeoDate t) {
+    return (double)(at_*t.getTime() + bt_);
+  }
+  public double getTransP(SoTValue v) {
+    if(v.isTime()) {
+      long t = v.getLongTime();
+      return (double)at_*t + bt_;
+    } else {
+      double u = ((SoTValue.Double)v).getValue();
+      return a_*u + b_;
+    }
+  }
+  /**
+   * Transform from <code>long</code> representation of time
+   * to physical coordinates.
+   *
+   * @since 3.0
+   */
+  public double getTransP(long t) {
+    return (double)at_*t + bt_;
+  }
+  /**
+   * Transform from physical to user coordinates.
+   *
+   * @param p physical value
+   * @return user value
+   */
+  public double getTransU(double p) {
+    return (p - b_)/a_;
+  }
+  /**
+   * Transform from physical coordinates to time.
+   *
+   * @param p physical value
+   * @return time value
+   */
+  public GeoDate getTimeTransU(double p) {
+    return new GeoDate((long)((p - bt_)/at_));
+  }
+  /**
+   * Transform from physical coordinates to <code>long</code>
+   * representation of time.
+   *
+   * @since 3.0
+   * @param p physical value
+   * @return milliseconds since 1970-01-01
+   */
+  public long getLongTimeTransU(double p) {
+    return (long)((p - bt_)/at_);
+  }
+
+  public SoTValue getSoTTransU(double p) {
+    if(!space_) {
+      return new SoTValue.Time((long)((p - bt_)/at_));
+    } else {
+      return new SoTValue.Double((p - b_)/a_);
+    }
+  }
+
+  //
+  void computeTransform() {
+    if(space_) {
+      double denom;
+      denom = u1_ - u2_;
+      if(denom == 0) {
+        a_ = 1.0f;
+        b_ = 0.0f;
+      } else {
+        a_ = (p1_ - p2_)/denom;
+        b_ = p1_ - a_*u1_;
+      }
+    } else {
+      double denom;
+      denom = t1_ - t2_;
+      if(denom == 0) {
+        at_ = 1.0;
+        bt_ = 0.0;
+      } else {
+        at_ = (p1_ - p2_)/denom;
+        bt_ = p1_ - at_*t1_;
+      }
+    }
+  }
+
+  public String toString() {
+    return "LinearTransform: " + a_ + ", " + b_ + "; " + at_ + ", " + bt_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LogAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LogAxis.java
new file mode 100755
index 0000000..7f81574
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LogAxis.java
@@ -0,0 +1,422 @@
+/*
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+// RCS $Id: LogAxis.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ 
+package  gov.noaa.pmel.sgt;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+
+/**
+ * Axis class for creation of "log" axes. An {@link gov.noaa.pmel.sgt.demo.JLogLogDemo
+ * exmample} is available demonstrating <code>LogAxis</code> use.
+ *
+ *--------------------------------------------------------------------------<br>
+ * NAME : LogAxis.java<br>
+ * FUNCTION :   Draws axes using "log" style axis.<br>
+ * ORIGIN  : GFI INFORMATIQUE<br>
+ * PROJECT : SONC DPS<br>
+ * -------------------------------------------------------------------------<br>
+ * HISTORY<br>
+ * VERSION : 03/07/2002 : V0.0 : LBE<br>
+ *        old version had no fonctionality. It was just written
+ *        for future evolutions. This new version complete the class<br>
+ * END-HISTORY<br>
+ * ------------------------------------------------------------------------<br>
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 3.0
+ *
+ */
+
+public class LogAxis extends SpaceAxis implements Cloneable {
+  public LogAxis(String id) {
+    super(id);
+    space_ = true;
+    numSmallTics_ = 9; //fixed number. only 8 shown
+  }
+
+  
+  public Axis copy() {
+    LogAxis newAxis;
+    try {
+      newAxis = (LogAxis)clone();
+    } catch (CloneNotSupportedException e) {
+      newAxis = new LogAxis(getId());
+    }
+    return (Axis)newAxis;
+  }
+  
+  
+  void draw(Graphics g) {
+    //throw new MethodNotImplementedError();
+    int xloc, yloc, xend, yend;
+    int istop, i;
+    double j;
+    double xt, yt, dir, x, y, xp, yp;
+    double xtitle, ytitle;
+    double delta = uRange_.delta;
+    Format format;
+    String labelText;
+    SGLabel title = getTitle();
+    if(!visible_) return;
+    if(Double.isNaN(delta)) delta = (uRange_.end - uRange_.start)/10.0;
+    if(title != null) title.setLayer(graph_.getLayer());
+    //
+    g.setColor(graph_.getLayer().getPane().getComponent().getForeground());
+    //
+
+    if(labelFormat_.length() <= 0) {
+      format = new Format(Format.computeFormat(uRange_.start, uRange_.end, sigDigits_));
+    } else {
+      format = new Format(labelFormat_);
+    }
+    if(orientation_ == Axis.HORIZONTAL) {
+      if(Debug.DEBUG) System.out.println("LogAxis: start drawing XAxis");
+      if(uLocation_ == null) {
+        yloc = graph_.getYUtoD(tLocation_.t);
+        yp = graph_.getYUtoP(tLocation_.t);
+      } else {
+        yloc = graph_.getYUtoD(uLocation_.y);
+        yp = graph_.getYUtoP(uLocation_.y);
+      }
+      xloc = graph_.getXUtoD(uRange_.start);
+      xend = graph_.getXUtoD(uRange_.end);
+      g.drawLine(xloc, yloc, xend, yloc);
+
+      //X tics drawing
+      dir = delta > 0? 1.0: -1.0;
+      xt = (int)((uRange_.start/delta + (dir*uRange_.start > 0? 1.0: -1.0)*0.00001))*delta;
+      
+      if(dir*xt < dir*uRange_.start) xt += delta;
+      istop = (int)((uRange_.end - xt)/delta + 0.00001);
+      
+      if(uRange_.start<=0) return;
+
+      int imin = (int)(Math.ceil(Math.log(uRange_.start)/Math.log(10))); // first large tic
+      int imax = (int)(Math.floor(Math.log(uRange_.end)/Math.log(10))); //last large tic
+      int nblabel = imax-imin +1;
+      
+      
+/*      System.out.println("uRange.start/end: "+uRange_.start+"/"+uRange_.end);
+      System.out.println("uRangeP: "+graph_.getYUtoP(uRange_.start)+"/"+graph_.getYUtoP(uRange_.end));
+*/    
+      double min = (double)Math.pow(10,imin);
+      double max = (double)Math.pow(10,imax);
+      
+      xt=min;
+      x = xt;
+      xp = graph_.getXUtoP(x);
+
+      for (j=min/10.0d;j<min;j=j+min/10.0d) {
+        xp = graph_.getXUtoP(j);
+        if(j>uRange_.start) drawXTic(g, xp, yp, smallTicHeight_);
+      }
+      
+      for (j=min;j<=max;j=j*10.0d) {
+        if(j>min) drawSmallXTics(g, j/10, uRange_.end, j, yp);
+        //if(j>min) drawSmallXTics(g, yp, j/10, uRange_.end, j);
+        xp = graph_.getXUtoP(j);
+        drawXTic(g, xp, yp, largeTicHeight_);
+      }
+      drawSmallXTics(g, j, uRange_.end, j, yp);
+      //drawSmallXTics(g, yp, j, uRange_.end, j);
+      
+      //
+      if(labelInterval_ <= 0 || labelPosition_ == NO_LABEL) return;
+      
+      SGLabel label;
+      int vertalign;
+      int horzalign;
+
+      if(dir*uRange_.start <= 0 && dir*uRange_.end >= 0) {
+        x = ((int)(uRange_.start/(delta*labelInterval_) - 0.00001))*delta*labelInterval_;
+      } else {
+        x = xt;
+      }
+      istop = (int)((uRange_.end - x)/(delta*labelInterval_) + 0.00001);
+      long jump = 10; // label display on each tic
+      if(istop<nblabel) jump = 100; // one on two
+
+      if(labelPosition_ == POSITIVE_SIDE) {
+        vertalign = SGLabel.BOTTOM;
+        horzalign = SGLabel.CENTER;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          yt = yp + TIC_RATIO*largeTicHeight_;
+        } else {
+          yt = yp + TIC_GAP;
+        }
+        ytitle = yt + LABEL_RATIO*labelHeight_;
+      } else {
+        vertalign = SGLabel.TOP;
+        horzalign = SGLabel.CENTER;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          yt = yp - TIC_RATIO*largeTicHeight_; 
+        } else {
+          yt = yp - TIC_GAP;
+        }
+        ytitle = yt - LABEL_RATIO*labelHeight_;
+      }
+      
+      for(j=min; j <= max; j*=jump) {
+        xt = graph_.getXUtoP(j)-LABEL_RATIO*labelHeight_*0.25;
+        //xt = graph_.getXUtoP(j);
+        //System.out.println("affich["+j+"]: 10e"+Math.round( Math.log(j)/Math.log(10) ));
+        labelText = "10e"+Math.round(Math.log(j)/Math.log(10));
+        label = new SGLabel("coordinate", labelText, new Point2D.Double(xt, yt)); 
+        label.setAlign(vertalign, horzalign);
+        label.setOrientation(SGLabel.HORIZONTAL);
+        label.setFont(labelFont_);
+	label.setColor(labelColor_);
+        label.setHeightP(labelHeight_);
+        label.setLayer(graph_.getLayer());
+        try {
+          label.draw(g);
+        } catch (LayerNotFoundException e) {} 
+        //x = x + delta*labelInterval_;
+      }
+      if(title_ != null) {
+        //xtitle = (uRange_.end + uRange_.start)*0.5;
+        xtitle = graph_.getXUtoP(uRange_.end) + graph_.getXUtoP(uRange_.start);
+        xt = xtitle*0.5; 
+        yt = ytitle;
+        xt = graph_.getXUtoP(xtitle);
+        title.setLocationP(new Point2D.Double(xt, yt));
+        title.setAlign(vertalign, SGLabel.CENTER);
+        title.setOrientation(SGLabel.HORIZONTAL);
+        try {
+          title.draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+    } else {                               // orientation is vertical
+      if(Debug.DEBUG) System.out.println("LogAxis: start drawing YAxis");
+      if(uLocation_ == null) {
+        xloc = graph_.getXUtoD(tLocation_.t);
+        xp = graph_.getXUtoP(tLocation_.t);
+      } else {
+        xloc = graph_.getXUtoD(uLocation_.x);
+        xp = graph_.getXUtoP(uLocation_.x);
+      }
+      yloc = graph_.getYUtoD(uRange_.start);
+      yend = graph_.getYUtoD(uRange_.end);
+      g.drawLine(xloc, yloc, xloc, yend);
+      
+      //draw Y tics
+      dir = delta > 0? 1.0: -1.0;
+      yt = (int)((uRange_.start/delta) + (dir*uRange_.start > 0? 1.0: -1.0)*0.00001)*delta;
+      if(dir*yt < dir*uRange_.start) yt += delta;
+      istop = (int)((uRange_.end - yt)/delta + 0.00001);
+
+      if(uRange_.start<=0) return;
+      
+      int imin = (int)(Math.ceil(Math.log(uRange_.start)/Math.log(10))); // premier large tic
+      int imax = (int)(Math.floor(Math.log(uRange_.end)/Math.log(10))); //dernier large tic
+      int nblabel = imax-imin +1;
+      
+      //System.out.println("uRange.start/end: "+uRange_.start+"/"+uRange_.end);
+      //System.out.println("uRangeP: "+graph_.getYUtoP(uRange_.start)+"/"+graph_.getYUtoP(uRange_.end));
+
+    
+      double min = (double)Math.pow(10,imin);
+      double max = (double)Math.pow(10,imax);
+
+      
+      yt=min;
+      y = yt;
+      yp = graph_.getYUtoP(y);
+
+      for (j=min/10.0d;j<min;j=j+min/10.0d) {
+        yp = graph_.getYUtoP(j);
+        if(j>uRange_.start) drawYTic(g, xp, yp, smallTicHeight_);
+      }        
+      
+      for (j=min;j<=max;j=j*10.0d) {
+        if(j>min) drawSmallYTics(g, xp, j/10, uRange_.end, j);
+        yp = graph_.getYUtoP(j);
+        drawYTic(g, xp, yp, largeTicHeight_);
+      }
+      drawSmallYTics(g, xp, j, uRange_.end, j);
+ 
+      //
+      if(labelInterval_ <= 0 || labelPosition_ == NO_LABEL) return;
+      //
+      SGLabel label;
+      int vertalign;
+      int horzalign;
+
+      if(dir*uRange_.start <= 0 && dir*uRange_.end >= 0) {
+        y = ((int)(uRange_.start/(delta*labelInterval_) - 0.00001))*delta*labelInterval_;
+      } else {
+        y = yt;
+      }
+      
+      istop = (int)((uRange_.end - y)/(delta*labelInterval_) + 0.00001);
+      long jump = 10; // label display on each tic
+      if(istop<nblabel) jump = 100; // one on two
+
+      Layer l = graph_.getLayer();
+      double widthP=0;
+      double maxWidthP=0;
+      if (l!=null) {
+        for(j=min; j <= max; j*=jump) {
+          labelText = "10e"+Math.round(Math.log(j)/Math.log(10));
+          //get Y Label size in Device unit
+          //widthP = l.getXDtoP(l.getFontMetrics(labelFont_).stringWidth(labelText));
+          label = new SGLabel("coordinate", labelText.trim(), new Point2D.Double(0, yt)); 
+          label.setOrientation(SGLabel.HORIZONTAL);
+          label.setFont(labelFont_);
+          label.setHeightP(labelHeight_);
+          label.setLayer(l);
+          widthP = l.getXDtoP((int)label.getStringWidth(g));
+          if (widthP>maxWidthP) maxWidthP = widthP;
+        }
+      }
+
+      if(labelPosition_ == NEGATIVE_SIDE) {
+        vertalign = SGLabel.BOTTOM;
+        horzalign = SGLabel.RIGHT;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xt = xp - TIC_RATIO*largeTicHeight_;
+        } else {
+          xt = xp - TIC_GAP;
+        }
+        //xtitle = xt - LABEL_RATIO*labelHeight_-LABEL_RATIO*maxWidthP*0.5;
+        xtitle = xt - maxWidthP;
+      } else {
+        vertalign = SGLabel.TOP;
+        horzalign = SGLabel.LEFT;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xt = xp + TIC_RATIO*largeTicHeight_; 
+        } else {
+          xt = xp + TIC_GAP;
+        }
+        //xtitle = xt + LABEL_RATIO*labelHeight_ + maxWidthP;
+        xtitle = xt + maxWidthP;
+      }
+      
+      //g.drawLine(l.getXPtoD(xt),l.getYPtoD(0.0),l.getXPtoD(xt),l.getYPtoD(4.0));
+      //g.drawLine(l.getXPtoD(xtitle),l.getYPtoD(0.0),l.getXPtoD(xtitle),l.getYPtoD(4.0));
+      
+      for(j=min; j <= max; j*=jump) {
+        yt = graph_.getYUtoP(j);//-LABEL_RATIO*labelHeight_*0.25;
+        //System.out.println("affich["+j+"]: 10e"+Math.round( Math.log(j)/Math.log(10) ));
+        labelText = "10e"+Math.round(Math.log(j)/Math.log(10));
+        label = new SGLabel("coordinate", labelText, new Point2D.Double(xt, yt)); 
+        label.setAlign(SGLabel.CENTER, horzalign);
+        label.setOrientation(SGLabel.HORIZONTAL);
+        label.setFont(labelFont_);
+    	label.setColor(labelColor_);
+        label.setHeightP(labelHeight_);
+        label.setLayer(graph_.getLayer());
+        try {
+          label.draw(g);
+        } catch (LayerNotFoundException e) {}
+        //y = j*10;//delta*labelInterval_;
+      }
+      if(title_ != null) {
+        ytitle = graph_.getYUtoP(uRange_.end) + graph_.getYUtoP(uRange_.start);
+        yt = ytitle*0.5; 
+        xt = xtitle;
+        title.setLocationP(new Point2D.Double(xt, yt));
+        title.setAlign(vertalign, SGLabel.CENTER);
+        title.setOrientation(SGLabel.VERTICAL);
+        try {
+          title.draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+    }
+  }
+
+  /**
+   * Get the bounding box for the axis in device units.
+   *
+   * @return bounding box
+   * @see Rectangle
+   **/
+  public Rectangle getBounds() {
+    double xp, yp, ymin, ymax, xmin, xmax;
+    int xd, yd, width, height, x, y;
+    if(orientation_ == Axis.HORIZONTAL) {
+      xd = graph_.getXUtoD(uRange_.start);
+      if(uLocation_ == null) {
+        yp = graph_.getYUtoP(tLocation_.t);
+      } else {
+        yp = graph_.getYUtoP(uLocation_.y);
+      }
+      width = graph_.getXUtoD(uRange_.end) - xd;
+      x = xd;
+      ymin = yp;
+      ymax = yp;
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+        ymax = ymax + largeTicHeight_;
+      } 
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+        ymin = ymin - largeTicHeight_;
+      }
+      if(labelPosition_ == POSITIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          ymax = ymax + (1.0 -TIC_RATIO)*largeTicHeight_ + labelHeight_;
+        } else {
+          ymax = ymax + TIC_GAP + labelHeight_;
+        }
+      } else if(labelPosition_ == NEGATIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          ymin = ymin - (1.0 - TIC_RATIO)*largeTicHeight_ - labelHeight_;
+        } else {
+          ymin = ymin - TIC_GAP - labelHeight_;
+        }
+      }
+      y = graph_.getLayer().getYPtoD(ymax);
+      height = graph_.getLayer().getYPtoD(ymin) - y;
+    } else {
+      yd = graph_.getYUtoD(uRange_.start);
+      if(uLocation_ == null) {
+        xp = graph_.getXUtoP(tLocation_.t);
+      } else {
+        xp = graph_.getXUtoP(uLocation_.x);
+      }
+      y = graph_.getYUtoD(uRange_.end);
+      height = yd - y;
+      xmin = xp;
+      xmax = xp;
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+        xmax = xmax + largeTicHeight_;
+      } 
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+        xmin = xmin - largeTicHeight_;
+      }
+      if(labelPosition_ == POSITIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xmax = xmax + (1.0 -TIC_RATIO)*largeTicHeight_ + labelHeight_;
+        } else {
+          xmax = xmax + TIC_GAP + labelHeight_;
+        }
+      } else if(labelPosition_ == NEGATIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xmin = xmin - (1.0 - TIC_RATIO)*largeTicHeight_ - labelHeight_;
+        } else {
+          xmin = xmin - TIC_GAP - labelHeight_;
+        }
+      }
+      x = graph_.getLayer().getXPtoD(xmin);
+      width = graph_.getLayer().getXPtoD(xmax) - x;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+
+  public void setBounds(int x, int y, int width, int height) {
+  }
+  public void setBounds(Rectangle rect) {
+    setBounds(rect.x, rect.y, rect.width, rect.height);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LogTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LogTransform.java
new file mode 100755
index 0000000..8e833b5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/LogTransform.java
@@ -0,0 +1,153 @@
+/*
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+// RCS $Id: LogTransform.java,v 1.1.1.2 2008/12/19 13:29:31 koennecke Exp $
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTRange;
+
+/**
+ * Transform class for creation of "log" axes. An {@link gov.noaa.pmel.sgt.demo.JLogLogDemo
+ * example} is available demonstrating <code>LogTransform</code> use.
+ *
+ *--------------------------------------------------------------------------<br>
+ * NAME : LogTransform.java<br>
+ * FUNCTION : Performs a logarithm transform on a cartesian axis.<br>
+ * ORIGIN  : GFI INFORMATIQUE<br>
+ * PROJECT : SONC DPS<br>
+ * -------------------------------------------------------------------------<br>
+ * HISTORY<br>
+ * VERSION : 03/07/2002 LBE<br>
+ *        old version had no functionality. It was just written<br>
+ *        for future evolutions. This new version complete the class<br>
+ * END-HISTORY<br>
+ * ------------------------------------------------------------------------<br>
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:31 $
+ * @since 3.0
+ */
+public class LogTransform extends AxisTransform implements Cloneable {
+  double at_;
+  double bt_;
+  double a_;
+  double b_;
+  int min_=-50;
+
+  public LogTransform() {
+    super();
+  }
+  public LogTransform(double p1,double p2,double u1,double u2){
+    super(p1, p2, u1, u2);
+  }
+  public LogTransform(Range2D pr,Range2D ur){
+    super(pr, ur);
+  }
+  public LogTransform(double p1,double p2,GeoDate t1,GeoDate t2){
+    super(p1, p2, t1, t2);
+  }
+  public LogTransform(Range2D pr,TimeRange tr) {
+    super(pr, tr);
+  }
+  public LogTransform(Range2D pr, SoTRange str){
+    super(pr, str);
+  }
+
+  AxisTransform copy() {
+    LogTransform newTransform;
+    try {
+      newTransform = (LogTransform)clone();
+    } catch (CloneNotSupportedException e) {
+      newTransform = new LogTransform();
+    }
+    return (AxisTransform)newTransform;
+  }
+
+  public double getTransP(double u) {
+      try {
+        if(u1_<=0 || u2_<=0) {
+          //System.out.println("ERROR Negative LOG");
+          throw new NegativeLogException("Can't Log negative values");
+        }
+      }catch(NegativeLogException e){e.printStackTrace();}
+    return a_*(Math.log(u)/Math.log(10)) + b_;
+  }
+  public double getTransP(GeoDate t) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransP(long t) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransP(SoTValue v) {
+    if(v.isTime()) {
+        throw new MethodNotImplementedError();
+    } else {
+      double u = ((SoTValue.Double)v).getValue();
+      try { //
+        if(u<=0) throw new NegativeLogException("Can't Log negative values");
+      }catch(NegativeLogException e){e.printStackTrace();}
+      return a_*(Math.log(u)/Math.log(10)) + b_;
+    }
+  }
+
+  public double getTransU(double p) {
+    if((p-b_)/a_<min_) {
+        return Math.pow(10,min_);
+    }
+    return Math.pow(10,(p - b_)/a_);
+  }
+
+  public GeoDate getTimeTransU(double p) {
+      throw new MethodNotImplementedError();
+  }
+
+  public long getLongTimeTransU(double p) {
+    throw new  MethodNotImplementedError();
+  }
+
+  public SoTValue getSoTTransU(double p) {
+    if((p-b_)/a_<min_){
+        return new SoTValue.Double(Math.pow(10,min_));
+    }
+    return new SoTValue.Double(Math.pow(10,(p - b_)/a_));
+  }
+
+  void computeTransform(){
+
+      try {
+        if(u1_<=0 || u2_<=0) {
+          //System.out.println("ERROR Negative LOG: "+u1_+"/"+u2_);
+          throw new NegativeLogException("Can't Log negative values");
+        }
+      }catch(NegativeLogException e){e.printStackTrace();}
+
+      double denom;
+      denom = Math.log(u1_)/Math.log(10) - Math.log(u2_)/Math.log(10);
+      if(denom == 0) {
+          a_ = 1.0f;
+          b_ = 0.0f;
+      } else {
+          a_ = (p1_ - p2_)/denom;
+          b_ = p1_ - a_*(Math.log(u1_)/Math.log(10));
+      }
+  }
+
+  public void setMinValue(int minVal){
+    min_=minVal;
+  }
+
+  public int getMinValue(){
+    return min_;
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Logo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Logo.java
new file mode 100755
index 0000000..623e44d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Logo.java
@@ -0,0 +1,420 @@
+/*
+ * $Id: Logo.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Panel;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.net.URL;
+import java.awt.Image;
+import java.awt.MediaTracker;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+// jdk1.2
+//import java.awt.geom.Point2D;
+
+/**
+ * Logo displays an Image on its parent Layer. Logo implements the
+ * LayerChild interface.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @see LayerChild
+**/
+public class Logo implements Cloneable, LayerChild, Moveable {
+  private String ident_;
+/** @directed */
+  private Layer layer_ = null;
+  private Point2D.Double porigin_;
+  private int valign_;
+  private int halign_;
+  private Image image_ = null;
+  private URL imageURL_;
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean visible_;
+  private boolean moveable_;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  /**
+   * Align to top of Logo.
+   */
+  public static final int TOP = 0;
+  /**
+   * Align to middle of Logo.
+   */
+  public static final int MIDDLE = 1;
+  /**
+   * Align to bottom of Logo.
+   */
+  public static final int BOTTOM = 2;
+  /**
+   * Align to left of Logo.
+   */
+  public static final int LEFT = 0;
+  /**
+   * Align to center of Logo.
+   */
+  public static final int CENTER = 1;
+  /**
+   * Align to right of Logo.
+   */
+  public static final int RIGHT = 2;
+  /**
+   * Default constructor. The default location for the Logo is at
+   * (0.0, 0.0) and aligned BOTTOM and LEFT.
+   */
+  public Logo() {
+    this(new Point2D.Double(0.0, 0.0), BOTTOM, LEFT);
+  }
+  /**
+   * Create a Logo object.  The initial object will not have
+   * an associated Image until setImage or setImageURL methods
+   * have been invoked. Vertical alignments include TOP, MIDDLE, and
+   * BOTTOM. Horizontal alignments include LEFT, CENTER, and RIGHT.
+   *
+   * @param loc Location of Logo
+   * @param valign vertical alignment
+   * @param halign horizontal alignment
+   *
+   * @see #setImageURL
+   * @see #setImage
+   * @see java.awt.Image
+   */
+  public Logo(Point2D.Double loc,int valign,int halign) {
+    porigin_ = loc;
+    valign_ = valign;
+    halign_ = halign;
+    ident_ = "";
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+    moveable_ = true;
+  }
+  /**
+   * Create of copy of Logo.
+   */
+  public LayerChild copy() {
+    Logo newLogo;
+    try {
+      newLogo = (Logo)clone();
+    } catch (CloneNotSupportedException e) {
+      newLogo = new Logo();
+    }
+    return newLogo;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  public boolean isMoveable() {
+    return moveable_;
+  }
+  public void setMoveable(boolean moveable) {
+    moveable_ = moveable;
+  }
+  /**
+   * Set the URL for the Logo image. The URL or the image
+   * must be set.
+   *
+   * @param url image URL
+   *
+   * @see #setImage
+   */
+  public void setImageURL(URL url) {
+    if(imageURL_ == null || !imageURL_.equals(url)) {
+      imageURL_ = url;
+      modified("Logo: setImageURL()");
+    }
+  }
+  /**
+   * Get the image URL. The URL will be null if no imageURL was
+   * specified.
+   *
+   * @return the imageURL
+   */
+  public URL getImageURL() {
+    return imageURL_;
+  }
+  /**
+   * Set the Logo image. The image or the imageURL
+   * must be set.
+   *
+   * @param img Logo image
+   *
+   * @see #setImageURL
+   */
+  public void setImage(Image img) {
+    if(image_ == null || !image_.equals(img)) {
+      image_ = img;
+      modified("Logo: setImage()");
+    }
+  }
+  /**
+   * Set parent layer.
+   *
+   * @param l parent layer
+   */
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  /**
+   * Get layer.
+   *
+   * @return layer
+   */
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+
+  public void modified(String mess) {
+    //    if(Debug.EVENT) System.out.println("Logo: modified()");
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Set Logo identifier.
+   *
+   * @param id logo identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get Logo identifier
+   *
+   * @return identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set alignment.
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   */
+  public void setAlign(int vert,int horz) {
+    if(valign_ != vert || halign_ != horz) {
+      valign_ = vert;
+      halign_ = horz;
+      modified("Logo: setAlign()");
+    }
+  }
+  /**
+   * Set vertical alignment
+   *
+   * @param vert vertical alignment
+   */
+  public void setVAlign(int vert) {
+    if(valign_ != vert) {
+      valign_ = vert;
+      modified("Logo: setVAlign()");
+    }
+  }
+  /**
+   * Set horizontal alignment
+   *
+   * @param horz horizontal alignment
+   */
+  public void setHAlign(int horz) {
+    if(halign_ != horz) {
+      halign_ = horz;
+      modified("Logo: setHAlign()");
+    }
+  }
+  /**
+   * Get vertical alignment
+   *
+   * @return vertical alignment
+   */
+  public int getVAlign() {
+    return valign_;
+  }
+  /**
+   * Get horizontal alignment
+   *
+   * @return horizontal alignment
+   */
+  public int getHAlign() {
+    return halign_;
+  }
+  /**
+   * Set location of logo
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @param loc logo location
+   */
+  public void setLocationP(Point2D.Double loc) {
+    if(porigin_ == null || !porigin_.equals(loc)) {
+      Point2D.Double temp = porigin_;
+      porigin_ = loc;
+      changes_.firePropertyChange("location",
+				  temp,
+				  porigin_);
+      modified("Logo: setLocationP()");
+    }
+  }
+  /**
+   * Get location of logo.
+   *
+   * @return Logo location
+   */
+  public Point2D.Double getLocationP() {
+    return porigin_;
+  }
+  /**
+   * Draw the Logo. If the imageURL was specified the image
+   * is retrieved using the URL and MediaTracker. The image
+   * is displayed after it is loaded.
+   */
+  public void draw(Graphics g) {
+    Rectangle bnds;
+    if(!visible_) return;
+    if (imageURL_ != null && layer_ != null && image_ == null) {
+      image_ = layer_.getPane().getComponent().getToolkit().getImage(imageURL_);
+      if (image_ != null) {
+        MediaTracker mt = new MediaTracker(layer_.getPane().getComponent());
+        try {
+          mt.addImage(image_, 0);
+          mt.waitForAll();
+          if(mt.isErrorAny())
+            System.err.println("Logo: Error loading image");
+        }
+        catch (InterruptedException ie) { }
+        System.out.println("MediaTracker: " + mt.checkAll());
+      }
+    }
+    layer_.getPane().getComponent().invalidate();
+    if(image_ != null) {
+      bnds = getBounds();
+      g.drawImage(image_, bnds.x, bnds.y,
+		  layer_.getPane().getComponent());
+    }
+  }
+  /**
+   * Get the bounding rectangle.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds() {
+    Rectangle bounds;
+    int x, y;
+    int width, height;
+    if(image_ != null) {
+      width = image_.getWidth(layer_.getPane().getComponent());
+      height = image_.getHeight(layer_.getPane().getComponent());
+      x = layer_.getXPtoD(porigin_.x);
+      y = layer_.getYPtoD(porigin_.y);
+      switch(halign_) {
+      case RIGHT:
+        x = x - width;
+        break;
+      case CENTER:
+        x = x - width/2;
+      }
+      switch(valign_) {
+      case BOTTOM:
+        y = y - height;
+        break;
+      case MIDDLE:
+        y = y - height/2;
+      }
+      return new Rectangle(x, y, width, height);
+    }
+    return null;
+  }
+  public Point getLocation() {
+    Rectangle bnds = getBounds();
+    return new Point(bnds.x, bnds.y);
+  }
+
+  public void setLocation(Point loc) {
+    Rectangle bnds = getBounds();
+    setBounds(loc.x, loc.y, bnds.width, bnds.height);
+  }
+  /**
+   * Set the bounds of the <code>Logo</code>
+   */
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  /**
+   * Set the bounds of the <code>Logo</code>
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    switch(halign_) {
+    case RIGHT:
+      x = x + width;
+      break;
+    case CENTER:
+      x = x + width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y + height;
+      break;
+    case MIDDLE:
+      y = y + height/2;
+    }
+    double xp = layer_.getXDtoP(x);
+    double yp = layer_.getYDtoP(y);
+    if(porigin_.x != xp || porigin_.y != yp) {
+      Point2D.Double temp = porigin_;
+      porigin_.x = xp;
+      porigin_.y = yp;
+      changes_.firePropertyChange("location",
+				  temp,
+				  new Point2D.Double(xp, yp));
+      modified("Logo: setBounds()");
+    }
+  }
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("Logo: setVisible()");
+    }
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MapGraph.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MapGraph.java
new file mode 100755
index 0000000..7d9913e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MapGraph.java
@@ -0,0 +1,60 @@
+/*
+ * $Id: MapGraph.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import java.awt.Graphics;
+import java.awt.Point;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Base class for all Map based Graphs and projections.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.x
+ */
+public class MapGraph extends Graph implements Cloneable {
+  /**@shapeType AggregationLink*/
+  private MapProj mproj_;
+  public MapGraph() {
+  }
+  public Graph copy() {
+    MapGraph newGraph;
+    try {
+      newGraph = (MapGraph)clone();
+    } catch (CloneNotSupportedException e) {
+      newGraph = new MapGraph();
+    }
+    return (Graph)newGraph;
+  }
+  void draw(Graphics g) {
+    throw new MethodNotImplementedError();
+  }
+  public void attachProj(MapProj proj) {
+    throw new MethodNotImplementedError();
+  }
+  public Object getObjectAt(Point pt) {
+    throw new MethodNotImplementedError();
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+  }
+  /**
+   * @since 3.0
+   */
+  public SGTData getDataAt(Point pt) {
+    throw new MethodNotImplementedError();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MapProj.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MapProj.java
new file mode 100755
index 0000000..8cd4fe8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MapProj.java
@@ -0,0 +1,25 @@
+/*
+ * $Id: MapProj.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package  gov.noaa.pmel.sgt;
+ 
+/**
+ * Base class for Map projections.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.x
+ */
+public class MapProj {
+  public MapProj() {
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MethodNotImplementedError.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MethodNotImplementedError.java
new file mode 100755
index 0000000..e547f8d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MethodNotImplementedError.java
@@ -0,0 +1,28 @@
+/**
+ * $Id: MethodNotImplementedError.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Method called has not been implemented.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ */
+public class MethodNotImplementedError extends java.lang.Error {
+  public MethodNotImplementedError() {
+    super();
+  }
+  public MethodNotImplementedError(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MinuteHourAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MinuteHourAxis.java
new file mode 100755
index 0000000..65f9019
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MinuteHourAxis.java
@@ -0,0 +1,129 @@
+/*
+ * $Id: MinuteHourAxis.java,v 1.1.1.2 2008/12/19 13:29:31 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+/**
+ * Draws time axes using the minute/hour style.
+ *
+ * <pre>
+ *                  |..........|..........|..........|..........|
+ *                       10         20         30         40
+ *                                 13:00 7-Jun-87
+ * or
+ *
+ *                  |..........|..........|..........|..........|
+ *                     13:10       13:20     13:30      13:40
+ *                                     7-Jun-87
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:31 $
+ * @see Axis
+ * @see TimeAxis
+ */
+class MinuteHourAxis implements TimeAxisStyle {
+  static final int MINUTE_TEST__ = 31;
+  static final String defaultMinorLabelFormat__ = "mm";
+  static final String defaultMajorLabelFormat__ = "yyyy-MM-dd HH";
+  static final int defaultNumSmallTics__ = 0;
+  int defaultMinorLabelInterval_ = 2;
+  int defaultMajorLabelInterval_ = 1;
+  static final double incrementValue__ = 1.0;
+  static final int incrementUnits__ = GeoDate.MINUTES;
+  /**
+   * MinuteHourAxis constructor.
+   *
+   * @param id axis identifier
+   **/
+  public MinuteHourAxis() {
+  }
+  public double computeLocation(double prev,double now) {
+    return prev;
+  }
+  public void computeDefaults(GeoDate delta) {
+    long msec = delta.getTime() % GeoDate.MSECS_IN_DAY;
+    if(msec > 7200000) {
+      defaultMinorLabelInterval_ = 15;
+      defaultMajorLabelInterval_ = 2;
+    } else if(msec > 1800000) {
+      defaultMinorLabelInterval_ = 5;
+      defaultMajorLabelInterval_ = 1;
+    } else {
+      defaultMinorLabelInterval_ = 1;
+      defaultMajorLabelInterval_ = 1;
+    }
+  }
+  public int getMinorValue(GeoDate time) {
+    return time.getGMTMinutes();
+  }
+  public int getMajorValue(GeoDate time) {
+    return time.getGMTHours() + 1;
+  }
+  public boolean isRoomForMajorLabel(GeoDate delta) {
+    return (1440.0*((double)delta.getTime())/((double)GeoDate.MSECS_IN_DAY)) > MINUTE_TEST__;
+  }
+  public boolean isStartOfMinor(GeoDate time) {
+    return time.getGMTMinutes() == 0;
+  }
+  public String getDefaultMinorLabelFormat() {
+    return defaultMinorLabelFormat__;
+  }
+  public String getDefaultMajorLabelFormat() {
+    return defaultMajorLabelFormat__;
+  }
+  public int getDefaultNumSmallTics() {
+    return defaultNumSmallTics__;
+  }
+  public int getDefaultMinorLabelInterval() {
+    return defaultMinorLabelInterval_;
+  }
+  public int getDefaultMajorLabelInterval() {
+    return defaultMajorLabelInterval_;
+  }
+  public GeoDate getStartTime(TimeRange tRange) {
+    boolean time_increasing;
+    GeoDate time = null;
+    time_increasing = tRange.end.after(tRange.start);
+    try {
+      if(time_increasing) {
+        time = new GeoDate(tRange.start.getGMTMonth(),
+         tRange.start.getGMTDay(),
+                           tRange.start.getGMTYear(),
+         tRange.start.getGMTHours(),
+                           tRange.start.getGMTMinutes(), 0, 0);
+        if(!time.equals(tRange.start)) time.increment(1.0, GeoDate.MINUTES);
+      } else {
+        time = new GeoDate(tRange.end.getGMTMonth(),
+         tRange.end.getGMTDay(),
+                           tRange.end.getGMTYear(),
+         tRange.end.getGMTHours(),
+                           tRange.end.getGMTMinutes(), 0, 0);
+        if(!time.equals(tRange.end)) time.increment(1.0, GeoDate.MINUTES);
+      }
+    } catch (IllegalTimeValue e) {}
+    return time;
+  }
+  public double getIncrementValue() {
+    return incrementValue__;
+  }
+  public int getIncrementUnits() {
+    return incrementUnits__;
+  }
+  public String toString() {
+    return "MinuteHourAxis";
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MonthYearAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MonthYearAxis.java
new file mode 100755
index 0000000..a93e519
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/MonthYearAxis.java
@@ -0,0 +1,112 @@
+/*
+ * $Id: MonthYearAxis.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+/**
+ * Draws time axes using the month/year style.
+ *
+ * <pre>
+ *            |..........|..........|..........|..........|
+ *                 mar         apr        may      jun
+ *                               1980
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @see Axis
+ * @see TimeAxis
+ */
+class MonthYearAxis implements TimeAxisStyle {
+  static final int YEAR_TEST__ = 31;
+  static final String defaultMinorLabelFormat__ = "MMM";
+  static final String defaultMajorLabelFormat__ = "yyyy";
+  static final int defaultNumSmallTics__ = 0;
+  int defaultMinorLabelInterval_ = 2;
+  int defaultMajorLabelInterval_ = 1;
+  static final double incrementValue__ = 1.0;
+  static final int incrementUnits__ = GeoDate.MONTHS;
+  /**
+   * MonthYearAxis constructor.
+   *
+   * @param id axis identifier
+   **/
+  public MonthYearAxis() {
+  }
+  public double computeLocation(double prev,double now) {
+    return (prev + now)*0.5;
+  }
+  public void computeDefaults(GeoDate delta) {
+    if(delta.getTime()/GeoDate.MSECS_IN_DAY > 240) {
+      defaultMinorLabelInterval_ = 2;
+    } else {
+      defaultMinorLabelInterval_ = 1;
+    }
+  }
+  public int getMinorValue(GeoDate time) {
+    return time.getGMTMonth();
+  }
+  public int getMajorValue(GeoDate time) {
+    return time.getGMTYear();
+  }
+  public boolean isRoomForMajorLabel(GeoDate delta) {
+    return delta.getTime()/GeoDate.MSECS_IN_DAY > YEAR_TEST__;
+  }
+  public boolean isStartOfMinor(GeoDate time) {
+    return time.getGMTMonth() == 1;
+  }
+  public String getDefaultMinorLabelFormat() {
+    return defaultMinorLabelFormat__;
+  }
+  public String getDefaultMajorLabelFormat() {
+    return defaultMajorLabelFormat__;
+  }
+  public int getDefaultNumSmallTics() {
+    return defaultNumSmallTics__;
+  }
+  public int getDefaultMinorLabelInterval() {
+    return defaultMinorLabelInterval_;
+  }
+  public int getDefaultMajorLabelInterval() {
+    return defaultMajorLabelInterval_;
+  }
+  public GeoDate getStartTime(TimeRange tRange) {
+    boolean time_increasing;
+    GeoDate time = null;
+    time_increasing = tRange.end.after(tRange.start);
+    try {
+      if(time_increasing) {
+        time = new GeoDate(tRange.start.getGMTMonth(), 1,
+                           tRange.start.getGMTYear(), 0, 0, 0, 0);
+        if(!time.equals(tRange.start)) time.increment(1.0, GeoDate.MONTHS);
+      } else {
+        time = new GeoDate(tRange.end.getGMTMonth(), 1,
+                           tRange.end.getGMTYear(), 0, 0, 0, 0);
+        if(!time.equals(tRange.end)) time.increment(1.0, GeoDate.MONTHS);
+      }
+    } catch (IllegalTimeValue e) {}
+    return time;
+  }
+  public double getIncrementValue() {
+    return incrementValue__;
+  }
+  public int getIncrementUnits() {
+    return incrementUnits__;
+  }
+  public String toString() {
+    return "MonthYearAxis";
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Moveable.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Moveable.java
new file mode 100755
index 0000000..1c264b4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Moveable.java
@@ -0,0 +1,74 @@
+/*
+ * $Id: Moveable.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeListener;
+ 
+/**
+ * Interface indicates that object can be moved with a mouse drag.
+ * Objects are notified of movement via the PropertyChange mechanism.
+ * 
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 2.0
+ */
+public interface Moveable {
+  /**
+   * Gets the bounding rectangle in device coordinates.
+   *
+   * @since 2.0
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds();
+  /**
+   * Gets the location in device coordinates.
+   *
+   * @since 2.0
+   * @return location
+   */
+  public Point getLocation();
+  /**
+   * Sets the location in device coordinates.
+   * @since 2.0
+   *
+   */
+  public void setLocation(Point point);
+  /**
+   * Returns true if the current state is moveable
+   *
+   * @since 2.0
+   * @return true if moveable
+   */
+  public boolean isMoveable();
+  /**
+   * Set the moveable property.
+   *
+   * @since 2.0
+   * @param select if true object is moveable
+   */
+  public void setMoveable(boolean move);
+  /**
+   * Add a new PropertyChangeListener.  Properties will include
+   * "moved".  Implementation of the following two methods will
+   * normally be via the PropertyChangeSupport class.
+   * @since 2.0
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l);
+  /**
+   * Remove a listener.
+   * @since 2.0
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/NegativeLogException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/NegativeLogException.java
new file mode 100755
index 0000000..07dee4c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/NegativeLogException.java
@@ -0,0 +1,30 @@
+/*
+ * $Id: NegativeLogException.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+/**
+ * Negative number used in LogTransform.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ */
+public class NegativeLogException extends SGException {
+
+  public NegativeLogException() {
+    super();
+  }
+  public NegativeLogException(String message) {
+    super(message);
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Pane.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Pane.java
new file mode 100755
index 0000000..6c09e59
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Pane.java
@@ -0,0 +1,500 @@
+/*
+ * $Id: Pane.java,v 1.1.1.1 2007/09/07 06:32:00 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Rectangle;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Graphics;
+import java.awt.AWTEvent;
+
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeListener;
+
+/**
+ * The <code>Pane</code> class is extended from <code>java.awt.Container</code>
+ * and is the basis for the <code>gov.noaa.pmel.sgt</code> package.
+ * <p>
+ * The Java scientific graphics toolkit is designed to allow a
+ * graphics client developer a great deal of flexibility and freedom.
+ * <code>sgt</code> is a package that greatly aids a developer in
+ * creating graphics applets. <code>sgt</code> is not a general
+ * purpose graphics package, but provides the tools to enable
+ * scientific graphics to be easily incorporated into <code>Applets</code>.
+ * <p>
+ * <code>sgt</code> has three main components, the "pane", on which
+ * all graphics are drawn. The <code>Pane</code> is a fairly simple
+ * class and all drawing is done in "device" coordinates (pixels).
+ * By default, the <code>Pane</code> will draw on the screen, but it is
+ * designed to allow drawing in an offscreen buffer that can be
+ * printed (for applications).
+ * <p>
+ * The next component is the <code>Layer</code>. Several
+ * <code>Layers</code> can be associated with a single
+ * <code>Pane</code>. The <code>Layer</code> class insulates
+ * the developer from the details of device coordinates by
+ * using "physical" coordinates. Physical coordinates are
+ * a right-hand coordinate systems with an origin of (0.0, 0.0) in the
+ * lower-left-hand corner and have the same scale in both the vertical
+ * and horizontal directions. Thus, a <code>Layer</code> that is
+ * 5.0 units wide and 3.0 units high can be made larger and smaller
+ * on the screen by resizing the <code>Pane</code>, but will not be
+ * distorted. The <code>Layer</code> class is responsible for
+ * displaying labels, keys (color, vector, and line), and rulers.
+ * A <code>Layer</code> can contain a single <code>Graph</code>.
+ * <p>
+ * Finally, the <code>Graph</code> component transforms from
+ * user coordinates (e.g. cm/sec, time, degC, or meters) to
+ * physical coordinates. The <code>Graph</code>
+ * classes handle the display of axes and data. Children of
+ * the <code>Graph</code> class are capable of creating Cartesian,
+ * polar, and map graphics. For Cartesian graphs, several different
+ * axes (log, plain and time), transforms (linear, log, and
+ * tablelookup), and <code>CartesianGraph</code> (pixel,
+ * line, vector, and contour) classes are available. These classes can be
+ * combined in almost any combination.
+ * <p>
+ * While only one dataset may be plotted per <code>Layer</code>,
+ * co-plotting is supported by allowing layers to use the same
+ * transform objects. The order that the layers are plotted can
+ * be changed, allowing the developer (or user) to control what
+ * may be obscured.
+ * <p>
+ * Member functions, in package <code>gov.noaa.pmel.sgt</code>,
+ * follow the following naming convention.  Member functions that
+ * have a <B>P</B>, <B>U</B>, or <I>nothing</I> at the end of the
+ * function name are of type double in <B>P</B>hysical
+ * units, type double in <B>U</B>ser units, and type int in Device
+ * units, respectively.
+ * Variables that start with p, u, t, or d are coordinates of type physical,
+ * user, time, or device, respectively.
+ * <p>
+ * All graphics are rendered when the <code>draw()</code> method is invoked.
+ * <p>
+ * <B>Mouse Events</B>
+ * <p>
+ * Mouse events are processed by the <code>JPane</code> object to support
+ * object selection and zooming. Object selection is accomplished by
+ * left clicking the mouse on the desired object.  <code>JPane</code>
+ * then fires a <code>PropertyChangeEvent</code> of type
+ * "objectSelected" that can be listened for by the users application.
+ * The user application then invokes the
+ * <code>getSelectedObject()</code> method. Zooming is accomplished in
+ * several steps.
+ * <p>
+ *
+ * <pre>
+ * 1) Begin a zoom operation by pressing the left button.
+ * 2) Describe a zoom rectangle by dragging the mouse with the left
+ *    button down.
+ * 3) Finish the zoom operation by releasing the left mouse button.
+ * </pre>
+ *
+ * <p>
+ * When the mouse button has been release <code>JPane</code> fires a
+ * <code>PropertyChangeEvent</code> of type "zoomRectangle" that can
+ * be listened for by the users application.  The user application can
+ * then obtain the zoom rectangle by invoking the
+ * <code>getZoomBounds()</code> method.
+ *
+ * <p> An example of object selection and zooming can be found in the
+ * {@link JPane} documentation.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:00 $
+ * @since 1.0
+ * @deprecated As of sgt 3.0, use {@link gov.noaa.pmel.sgt.JPane JPane}.
+ * @see Layer
+ * @see Graph
+ * @see java.awt.Graphics
+**/
+public class Pane extends Container implements AbstractPane {
+  //
+  private PaneProxy proxy_;
+  //
+  /**@shapeType AggregationLink
+   * @supplierCardinality 1..**/
+  /*#  Layer lnkUnnamed*/
+  /**
+   * Constructs a <code>Pane</code>.
+   *
+   * @param id the <code>Pane</code> identifier
+   * @param size the size of the <code>Pane</code> in pixels
+   **/
+  public Pane(String id, Dimension size) {
+    proxy_ = new PaneProxy(this, id, size);
+    setSize(size);
+    //
+    // setup for Low-Level Events
+    //
+    this.enableEvents(AWTEvent.MOUSE_EVENT_MASK |
+                      AWTEvent.MOUSE_MOTION_EVENT_MASK);
+  }
+  /**
+   * Default constructor.  The identifier is set to an empty string and
+   * the size is set to a width and height of 50 pixels. A default constructor
+   * is required to work as a component with Visual Cafe.
+   *
+   * <pre>
+   * import gov.noaa.pmel.sgt.Pane;
+   * ...
+   * Pane pane;
+   * ...
+   * pane = new Pane("main graph", new Dimension(400, 500));
+   * pane.setLayout(new StackedLayout());
+   * ...
+   * </pre>
+   *
+   * @see StackedLayout
+   *
+   **/
+  public Pane() {
+    this(new String(""), new Dimension(50,50));
+  }
+  /**
+   * Return the version of SGT.
+   * @since 3.0
+   */
+  public static String getVersion() {
+    return PaneProxy.getVersion();
+  }
+  public void draw() {
+    proxy_.draw();
+  }
+  /**
+   * No initialization required by Pane.
+   */
+  public void init() {
+  }
+  public void draw(Graphics g) {
+    proxy_.draw(g);
+  }
+  public void draw(Graphics g, int width, int height) {
+    proxy_.draw(g, width, height);
+  }
+  public boolean isPrinter() {
+    return proxy_.isPrinter();
+  }
+  /**
+   * Internal access to jdk1.1 or Java2D line drawing.
+   */
+  public static StrokeDrawer getStrokeDrawer() {
+    return PaneProxy.strokeDrawer;
+  }
+  public Dimension getPageSize() {
+    return proxy_.getPageSize();
+  }
+  /**
+   * Updates the <code>Pane</code>
+   */
+  public void update(Graphics g) {
+    if(Debug.DEBUG) System.out.println("Pane: " + proxy_.getId() + ": update(g)");
+    super.update(g);
+    paint(g);
+  }
+  /**
+   * Override of the parent <code>paint</code> method. This method should not be
+   * called by a user.
+   **/
+  public void paint(Graphics g) {
+    proxy_.paint(g);
+  }
+  /**
+   * Adds the specified component to the end of the <code>Pane</code>.
+   *
+   * @param comp the component to be added
+   * @return component argument
+   */
+  public Component add(Component comp) {
+    if(comp instanceof Layer) {
+      ((Layer)comp).setPane(this);
+    } else if(comp instanceof LayerContainer) {
+      ((LayerContainer)comp).setPane(this);
+    }
+    return super.add(comp);
+  }
+  /**
+   * Adds the specified component to the <code>Pane</code> at the
+   * given position.
+   *
+   * @param comp the component to be added
+   * @param index the position at which to insert the component, or -1
+   to insert the component at the end.
+   * @return component argument
+   */
+  public Component add(Component comp, int index) {
+    if(comp instanceof Layer) {
+      ((Layer)comp).setPane(this);
+    } else if(comp instanceof LayerContainer) {
+      ((LayerContainer)comp).setPane(this);
+    }
+    return super.add(comp, index);
+  }
+  /**
+   * Adds the specified component to the end of this <code>Pane</code>.
+   * Also notifies the layout manager to add the component to this
+   * <code>Pane</code>'s layout using the specified constraints object.
+   *
+   * @param comp the component to be added
+   * @param constraints an object expressing layout constraints for
+   this component
+  */
+  public void add(Component comp, Object constraints) {
+    super.add(comp, constraints);
+    if(comp instanceof Layer) {
+      ((Layer)comp).setPane(this);
+    } else if(comp instanceof LayerContainer) {
+      ((LayerContainer)comp).setPane(this);
+    }
+  }
+  /**
+   * Adds the specified component to the end of this <code>Pane</code>
+   * at the specified index.
+   * Also notifies the layout manager to add the component to this
+   * <code>Pane</code>'s layout using the specified constraints object.
+   *
+   * @param comp the component to be added
+   * @param constraints an object expressing layout constraints for
+   this component
+   * @param index the position in the <code>Pane</code>'s list at which to
+   insert the component -1 means insert at the end.
+  */
+  public void add(Component comp, Object constraints, int index) {
+    super.add(comp, constraints, index);
+    if(comp instanceof Layer) {
+      ((Layer)comp).setPane(this);
+    } else if(comp instanceof LayerContainer) {
+      ((LayerContainer)comp).setPane(this);
+    }
+  }
+  /**
+   * Adds the specified component to this <code>Pane</code>. It
+   * is strongly advised to use add(Component, Object), in place
+   * of this method.
+   */
+  public Component add(String name, Component comp) {
+    if(comp instanceof Layer) {
+      ((Layer)comp).setPane(this);
+    } else if(comp instanceof LayerContainer) {
+      ((LayerContainer)comp).setPane(this);
+    }
+    return super.add(name, comp);
+  }
+
+  public String getId() {
+    return proxy_.getId();
+  }
+  public void setId(String id) {
+    proxy_.setId(id);
+  }
+  public void setPageAlign(int vert,int horz) {
+    proxy_.setPageAlign(vert, horz);
+  }
+  public void setPageVAlign(int vert) {
+    proxy_.setPageVAlign(vert);
+  }
+  public void setPageHAlign(int horz) {
+    proxy_.setPageHAlign(horz);
+  }
+  public int getPageVAlign() {
+    return proxy_.getPageVAlign();
+  }
+  public int getPageHAlign() {
+    return proxy_.getPageHAlign();
+  }
+  public void setPageOrigin(Point p) {
+    proxy_.setPageOrigin(p);
+  }
+  public Point getPageOrigin() {
+    return proxy_.getPageOrigin();
+  }
+  /**
+   * Set the size.
+   */
+  public void setSize(Dimension d) {
+    super.setSize(d);
+    proxy_.setSize(d);
+  }
+  public Layer getFirstLayer() {
+    return proxy_.getFirstLayer();
+  }
+  public Layer getLayer(String id) throws LayerNotFoundException  {
+    return proxy_.getLayer(id);
+  }
+  public Layer getLayerFromDataId(String id) throws LayerNotFoundException  {
+    return proxy_.getLayerFromDataId(id);
+  }
+  /**
+   * Move the <code>Layer</code> up in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> up causes the
+   * <code>Layer</code> to be drawn later and over earlier
+   * layers.
+   *
+   * @param lyr <code>Layer</code> object.
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerUp(Layer lyr) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Move the <code>Layer</code> up in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> up causes the
+   * <code>Layer</code> to be drawn later and over earlier
+   * layers.
+   *
+   * @param id identifier.
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerUp(String id) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Move the <code>Layer</code> down in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> down causes the
+   * <code>Layer</code> to be drawn earlier.
+   *
+   * @param lyr <code>Layer</code> object.
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerDown(Layer lyr) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Move the <code>Layer</code> down in the stack.
+   * The order of the layers determine when they
+   * are drawn.  Moving the <code>Layer</code> down causes the
+   * <code>Layer</code> to be drawn earlier.
+   *
+   * @param id identifier
+   * @exception LayerNotFoundException The specified <code>Layer</code> was not found in the list.
+   * @see Layer
+   **/
+  public void moveLayerDown(String id) throws LayerNotFoundException  {
+    throw new MethodNotImplementedError();
+  }
+  public Object getSelectedObject() {
+    return proxy_.getSelectedObject();
+  }
+  public void setSelectedObject(Object obj) {
+    proxy_.setSelectedObject(obj);
+  }
+  /**
+   * Overrides the default event methods.
+   **/
+  public void processMouseEvent(MouseEvent event) {
+    if(!proxy_.processMouseEvent(event))
+      super.processMouseEvent(event);
+  }
+
+  public void processMouseMotionEvent(MouseEvent event) {
+    if(!proxy_.processMouseMotionEvent(event))
+      super.processMouseMotionEvent(event);
+  }
+  public Rectangle getZoomBounds() {
+    return proxy_.getZoomBounds();
+  }
+  /**
+   * @since 3.0
+   */
+  public Point getZoomStart() {
+    return proxy_.getZoomStart();
+  }
+  public Object getObjectAt(int x, int y) {
+    return proxy_.getObjectAt(x, y);
+  }
+  /**
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(int x, int y) {
+    return proxy_.getObjectsAt(x, y);
+  }
+  /**
+   * @since 3.0
+   */
+  public Object[] getObjectsAt(Point pt) {
+    return proxy_.getObjectsAt(pt.x, pt.y);
+  }
+  public Component getComponent() {
+    return (Component)this;
+  }
+  public Dimension getMaximumSize() {
+    return proxy_.getMaximumSize();
+  }
+  public Dimension getMinimumSize() {
+    return proxy_.getMinimumSize();
+  }
+  public Dimension getPreferredSize() {
+    return proxy_.getPreferredSize();
+  }
+  /**
+   * Get a <code>String</code> representatinof the
+   * <code>Pane</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    return proxy_.toString();
+  }
+  public void setBatch(boolean batch, String msg) {
+    proxy_.setBatch(batch, msg);
+  }
+  public void setBatch(boolean batch) {
+    proxy_.setBatch(batch, "");
+  }
+  public boolean isBatch() {
+    return proxy_.isBatch();
+  }
+  public void setModified(boolean mod, String mess) {
+    proxy_.setModified(mod, mess);
+  }
+  public boolean isModified() {
+    return proxy_.isModified();
+  }
+  /**
+   * @since 3.0
+   */
+  public void setMouseEventsEnabled(boolean enable) {
+    proxy_.setMouseEventsEnabled(enable);
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean isMouseEventsEnabled() {
+    return proxy_.isMouseEventsEnabled();
+  }
+  public void setPageScaleMode(int mode) {
+    proxy_.setPageScaleMode(mode);
+  }
+  public int getPageScaleMode() {
+    return proxy_.getPageScaleMode();
+  }
+  /*
+   * Pane PropertyChange methods
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    proxy_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    proxy_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneBeanInfo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneBeanInfo.java
new file mode 100755
index 0000000..651adce
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneBeanInfo.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import java.beans.*;
+
+/**
+ *    BeanInfo for <code>Pane</code>.
+ */
+public class PaneBeanInfo extends SimpleBeanInfo {
+  // getAdditionalBeanInfo method allows to return any number of additional
+  // BeanInfo objects which provide information about the Bean that this BeanInfo
+  // describes.
+  public BeanInfo[] getAdditionalBeanInfo() {
+    try {
+      BeanInfo[] bi = new BeanInfo[1];
+      bi[0] = Introspector.getBeanInfo(beanClass.getSuperclass());
+      return bi;
+    }
+    catch (IntrospectionException e) {
+      throw new Error(e.toString());
+    }
+  }
+
+  // getIcon returns an image object which can be used by toolboxes, toolbars
+  // to represent this bean. Icon images are in GIF format.
+  public java.awt.Image getIcon(int iconKind) {
+    if (iconKind == BeanInfo.ICON_COLOR_16x16 ||
+        iconKind == BeanInfo.ICON_MONO_16x16) {
+      java.awt.Image img = loadImage("PaneIcon16.gif");
+      return img;
+    }
+    if (iconKind == BeanInfo.ICON_COLOR_32x32 ||
+        iconKind == BeanInfo.ICON_MONO_32x32) {
+      java.awt.Image img = loadImage("PaneIcon32.gif");
+      return img;
+    }
+    return null;
+  }
+
+  // getPropertyDescriptors returns an array of PropertyDescriptors which describe
+  // the editable properties of this bean.
+  public PropertyDescriptor[] getPropertyDescriptors() {
+    try {
+      PropertyDescriptor id = new PropertyDescriptor("id", beanClass);
+      id.setBound(false);
+      id.setDisplayName("Pane Identifier");
+
+      PropertyDescriptor rv[] = {id};
+      return rv;
+    } catch (IntrospectionException e) {
+      throw new Error(e.toString());
+    }
+  }
+
+  public BeanDescriptor getBeanDescriptor() {
+    return new BeanDescriptor(beanClass);
+  }
+
+  private final static Class beanClass = Pane.class;
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneIcon16.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneIcon16.gif
new file mode 100755
index 0000000..5ebb6e2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneIcon32.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneIcon32.gif
new file mode 100755
index 0000000..33b6e99
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneNotFoundException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneNotFoundException.java
new file mode 100755
index 0000000..69728cf
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneNotFoundException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: PaneNotFoundException.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Operation failed because the layer was not found.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ */
+public class PaneNotFoundException extends SGException {
+  public PaneNotFoundException() {
+    super();
+}
+  public PaneNotFoundException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneProxy.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneProxy.java
new file mode 100755
index 0000000..9eaca02
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PaneProxy.java
@@ -0,0 +1,913 @@
+/*
+ * $Id: PaneProxy.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.swing.Draggable;
+import gov.noaa.pmel.sgt.beans.Panel;
+
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics2D;
+import java.awt.Stroke;
+
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.PrintGraphics;
+import java.awt.Container;
+import java.awt.Component;
+import java.awt.Color;
+import java.awt.Cursor;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.InputEvent;
+
+import java.util.Vector;
+import java.util.Properties;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * PaneProxy implements the functionality common to <code>JPane</code>
+ * and <code>Pane</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ */
+class PaneProxy {
+  public static String SGTVersion = "3.0";
+  public static boolean Java2D = false;
+  public static StrokeDrawer strokeDrawer = null;
+
+  private Container pane_;
+
+  private String ident_;
+  private Dimension panesize_;
+  private Image offscreen_;
+  private Dimension pagesize_;
+  private Point pageOrigin_ = new Point(0, 0);
+  private boolean printer_ = false;
+  private boolean opaque_ = true;
+  private int halign_ = AbstractPane.CENTER;
+  private int valign_ = AbstractPane.MIDDLE;
+  private int printMode_ = AbstractPane.SHRINK_TO_FIT;
+  private Object selectedobject_;
+  private Object old_selectedobject_ = null;
+  private Rectangle selectedRect_;
+  private Rectangle zoom_rect_ = new Rectangle(0, 0, 0, 0);
+  private Rectangle old_zoom_rect_;
+  private Point zoom_start_ = new Point(0, 0);
+  private boolean in_zoom_ = false;
+  private boolean in_select_ = false;
+  private boolean in_move_ = false;
+  private boolean moved_ = false;
+  private boolean draggable_ = false;
+  private boolean moveable_ = false;
+  private Point move_ref_;
+  private boolean batch_ = true;
+  private boolean modified_ = false;
+  private boolean ignoreModified_ = false;
+  private boolean firstDraw_ = true;
+  private boolean mouseEventsEnabled_ = true;
+
+  private PropertyChangeSupport changes_ = null;
+
+  public PaneProxy(Container pane, String id, Dimension size) {
+    ident_ = id;
+    panesize_ = size;
+    pane_ = pane;
+    changes_ = new PropertyChangeSupport(pane_);
+    //
+    testJava2D();
+  }
+  /**
+   * @since 3.0
+   */
+  public static String getVersion() {
+    return SGTVersion;
+  }
+
+  private void testJava2D() {
+    Class cl;
+    boolean java2d = true;
+    try {
+      cl = Class.forName("java.awt.Graphics2D");
+    } catch (ClassNotFoundException e) {
+      java2d = false;
+    }
+    Java2D = java2d;
+    if(Java2D) {
+      strokeDrawer = new StrokeDrawer2();
+    } else {
+      strokeDrawer = new StrokeDrawer1();
+    }
+  }
+
+  public Dimension getSize() {
+    return panesize_;
+  }
+
+  void draw() {
+    ignoreModified_ = true;
+    if(Debug.DEBUG) System.out.println("PaneProxy: [" + ident_ + "] " +
+                         " draw(), batch=" + batch_);
+    printer_ = false;
+    Graphics g = pane_.getGraphics();
+    //
+    // test existance of graphics context.
+    //
+    if(g ==  null) {
+      ignoreModified_ = false;
+      return;
+    }
+    if(firstDraw_) {
+      ((AbstractPane)pane_).init();
+      firstDraw_ = false;
+    }
+    Graphics goff;
+    Dimension isze = pane_.getSize();
+    if(offscreen_ == (Image) null) {
+      offscreen_ = pane_.createImage(isze.width, isze.height);
+    } else {
+      if(isze.width != panesize_.width || isze.height != panesize_.height) {
+        offscreen_ = pane_.createImage(isze.width, isze.height);
+      }
+    }
+    panesize_ = isze;
+    goff = offscreen_.getGraphics();
+    //        super.paint(g);
+    Rectangle clip = pane_.getBounds();
+    goff.setClip(0, 0, clip.width, clip.height);
+
+    drawLayers(goff);
+    g.drawImage(offscreen_, 0, 0, pane_);
+    drawDraggableItems(g);
+    modified_ = false;
+    ignoreModified_ = false;
+    pane_.repaint();
+  }
+
+  void draw(Graphics g) {
+    Rectangle clip = pane_.getBounds();
+    draw(g, clip.width, clip.height);
+  }
+
+  void draw(Graphics g, int width, int height) {
+    ignoreModified_ = true;
+    if(Debug.DEBUG) System.out.println("PaneProxy: [" + ident_ + "] draw(g), batch="+batch_);
+    if(g instanceof PrintGraphics) {
+      printer_ = true;
+      pagesize_ = ((PrintGraphics)g).getPrintJob().getPageDimension();
+    } else {
+      printer_ = false;
+      pagesize_ = null;
+    }
+    g.setClip(0, 0, width, height);
+    drawLayers(g);
+    drawDraggableItems(g);
+    modified_ = false;
+    ignoreModified_ = false;
+  }
+
+  void drawPage(Graphics g, double width, double height) {
+    ignoreModified_ = true;
+    if(Debug.DEBUG) System.out.println("PaneProxy: [" + ident_ + "] drawPage(g), batch="+batch_);
+    printer_ = true;
+
+    Color saved = g.getColor();
+    g.setColor(pane_.getBackground());
+    Rectangle r = pane_.getBounds();
+    g.fillRect(r.x, r.y, r.width, r.height);
+    g.setColor(saved);
+
+    drawLayers(g);
+    drawDraggableItems(g);
+    modified_ = false;
+    ignoreModified_ = false;
+    printer_ = false;
+  }
+  void setOpaque(boolean opaque) {
+    opaque_ = opaque;
+  }
+  boolean isOpaque() {
+    return opaque_;
+  }
+  void drawLayers(Graphics g) {
+    if(!printer_) {
+      if(opaque_) {
+        Rectangle r = pane_.getBounds();
+        g.setColor(pane_.getBackground());
+        g.fillRect(0, 0, r.width, r.height);
+      }
+      g.setColor(pane_.getForeground());
+    }
+//    System.out.println("PaneProxy.drawLayers("+getId()+"): print = " + printer_ + ", pane = " + pane_.getBounds());
+    //        g.drawRect(2,2,r.width-5,r.height-5);
+    //
+    // draw Layers
+    //
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      try {
+        if(comps[i] instanceof Layer) {
+          ((Layer)comps[i]).draw(g);
+        } else if(comps[i] instanceof LayerControl) {
+          ((LayerControl)comps[i]).draw(g);
+        }
+ /*       if(printer_ && comps[i] instanceof Panel) {
+          ((Panel)comps[i]).paintBorder(g);
+        } */
+      } catch (PaneNotFoundException e) {}
+    }
+  }
+  void drawDraggableItems(Graphics g) {
+    if(Debug.DEBUG) System.out.println("PaneProxy: [" + ident_ +
+                                       "] drawDraggableItems, batch="+batch_);
+    //
+    // draw draggable items in each layer
+    //
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      try {
+        if(comps[i] instanceof LayerControl) {
+          ((LayerControl)comps[i]).drawDraggableItems(g);
+        }
+      } catch (PaneNotFoundException e) {}
+    }
+  }
+
+  void paint(Graphics g) {
+    if(Debug.DEBUG || Debug.DRAW_TRACE)
+      System.out.println("PaneProxy: [" + ident_ +
+                         "] paint(g): "+g.getClipBounds()+
+                         ", batch="+batch_+", modified="+modified_);
+    Dimension isze = pane_.getSize();
+    if(isze.width != panesize_.width || isze.height != panesize_.height) offscreen_ = null;
+    if(offscreen_ != null && !modified_) {
+      g.drawImage(offscreen_, 0, 0, pane_);
+      drawDraggableItems(g);
+    } else {
+      if(Debug.DRAW_TRACE) System.out.println("PaneProxy: [" + ident_ +
+                                              "] paint: calling draw(), batch="+batch_);
+      draw();
+    }
+    modified_ = false;
+  }
+
+  String getId() {
+    return ident_;
+  }
+  void setId(String id) {
+    ident_ = id;
+  }
+  void setPageAlign(int vert, int horz) {
+    valign_ = vert;
+    halign_ = horz;
+  }
+  void setPageVAlign(int vert) {
+    valign_ = vert;
+  }
+  void setPageHAlign(int horz) {
+    halign_ = horz;
+  }
+  int getPageVAlign() {
+    return valign_;
+  }
+  int getPageHAlign() {
+    return halign_;
+  }
+  void setPageOrigin(Point p) {
+    pageOrigin_ = p;
+  }
+  Point getPageOrigin() {
+    return pageOrigin_;
+  }
+  boolean isPrinter() {
+    return printer_;
+  }
+  Dimension getPageSize() {
+    return pagesize_;
+  }
+  void setSize(Dimension d) {
+    panesize_ = d;
+    offscreen_ = null;
+  }
+  Layer getFirstLayer() {
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        return (Layer)comps[i];
+      }
+    }
+    return null;
+  }
+  Layer getLayer(String id) throws LayerNotFoundException {
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        if(((Layer)comps[i]).getId() == id) return (Layer)comps[i];
+      } else if(comps[i] instanceof Panel) {
+        if(((Panel)comps[i]).hasLayer(id)) return (Layer)((Panel)comps[i]).getLayer(id);
+      }
+    }
+    throw new LayerNotFoundException();
+  }
+
+  Layer getLayerFromDataId(String id) throws LayerNotFoundException {
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        if(((Layer)comps[i]).isDataInLayer(id)) return (Layer)comps[i];
+      } else if(comps[i] instanceof Panel) {
+        if(((Panel)comps[i]).isDataInPanel(id)) return (Layer)((Panel)comps[i]).getLayerFromDataId(id);
+      }
+    }
+    throw new LayerNotFoundException();
+  }
+  Object getSelectedObject() {
+    return selectedobject_;
+  }
+  void setSelectedObject(Object obj) {
+    old_selectedobject_ = selectedobject_;
+    selectedobject_ = obj;
+  }
+  Rectangle getZoomBounds() {
+    return zoom_rect_;
+  }
+  /**
+   * @since 3.0
+   */
+  Point getZoomStart() {
+    return zoom_start_;
+  }
+
+  Object getObjectAt(int x, int y) {
+    Object obj = null;
+    Component[] comps = pane_.getComponents();
+    if(comps.length != 0) {
+      Layer ly;
+      for(int i=0; i < comps.length; i++) {
+        if(comps[i] instanceof Layer) {
+          obj = ((Layer)comps[i]).getObjectAt(x, y, false);
+          if(obj != null) return obj;
+        } else if(comps[i] instanceof Panel) {
+          obj = ((Panel)comps[i]).getObjectAt(x, y, false);
+          if(obj != null) return obj;
+        }
+      }
+    }
+    return obj;
+  }
+  /**
+   * @since 3.0
+   */
+  Object[] getObjectsAt(int x, int y) {
+    Vector obList = new Vector();
+    Object obj = null;
+    Component[] comps = pane_.getComponents();
+    if(comps.length != 0) {
+      Layer ly;
+      for(int i=0; i < comps.length; i++) {
+        if(comps[i] instanceof Layer) {
+          obj = ((Layer)comps[i]).getObjectAt(x, y, false);
+          if(obj != null) obList.addElement(obj);
+        } else if(comps[i] instanceof Panel) {
+          obj = ((Panel)comps[i]).getObjectAt(x, y, false);
+          if(obj != null) obList.addElement(obj);
+        }
+      }
+    }
+    return obList.toArray();
+  }
+
+  boolean processMouseEvent(MouseEvent event) {
+    boolean event_handled = false;
+    if(!mouseEventsEnabled_) return event_handled;
+    if (event.getID() == MouseEvent.MOUSE_CLICKED) {
+      event_handled = Pane_MouseClicked(event);
+    } else if (event.getID() == MouseEvent.MOUSE_PRESSED) {
+      event_handled = Pane_MouseDown(event);
+    } else if (event.getID() == MouseEvent.MOUSE_RELEASED) {
+      event_handled = Pane_MouseUp(event);
+    }
+    return event_handled;
+  }
+
+  boolean processMouseMotionEvent(MouseEvent event) {
+    boolean event_handled = false;
+    if(!mouseEventsEnabled_) return event_handled;
+    if (event.getID() == MouseEvent.MOUSE_DRAGGED) {
+      event_handled = Pane_MouseDrag(event);
+    } else if(event.getID() == MouseEvent.MOUSE_MOVED) {
+      event_handled = Pane_MouseMoved(event);
+    }
+    return event_handled;
+  }
+
+  private boolean Pane_MouseClicked(MouseEvent event) {
+    Object obj;
+    Rectangle rect;
+    Selectable savedobj = null;
+    int mod = event.getModifiers();
+    //
+    // button 1 must be clicked.  Modifiers are now allowed!
+    //
+    //      if(!(((mod & MouseEvent.BUTTON1_MASK) != 0) &&
+    //           ((mod - MouseEvent.BUTTON1_MASK) == 0))) return false;
+    if(!((mod & MouseEvent.BUTTON1_MASK) != 0)) return false;
+    in_zoom_ = false;
+    in_select_ = false;
+//    if(in_move_ && !moved_ && selectedobject_ instanceof Selectable) {
+    if(!moved_ && selectedobject_ instanceof Selectable) {
+      if(Debug.DEBUG) System.out.println("MouseClicked (in_move_ && !moved_ && Selectable)");
+      //
+      // second click of selected object   de-select
+      //
+      if(((Selectable)selectedobject_).isSelected()) {
+        if(Debug.DEBUG) System.out.println("MouseClicked (isSelected)");
+        savedobj = (Selectable)selectedobject_;
+        //
+        // remove box
+        //
+        Graphics g = pane_.getGraphics();
+        if(moveable_) {
+          g.setColor(Color.red);
+        } else {
+          g.setColor(Color.blue);
+        }
+        g.setXORMode(pane_.getBackground());
+        g.drawRect(selectedRect_.x, selectedRect_.y,
+                   selectedRect_.width, selectedRect_.height);
+        g.setPaintMode();
+        savedobj.setSelected(false);
+        pane_.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+        return false;
+      }
+    }
+    //    old_selectedobject_ = selectedobject_;
+    selectedobject_ = null;
+    Component[] comps = pane_.getComponents();
+    if(comps.length != 0) {
+      Layer ly;
+      for(int i=0; i < comps.length; i++) {
+        if(comps[i] instanceof Layer) {
+          obj = ((Layer)comps[i]).getObjectAt(event.getX(), event.getY());
+          if(obj != null) {
+            selectedobject_ = obj;
+            break;
+          }
+        } else if(comps[i] instanceof Panel) {
+          obj = ((Panel)comps[i]).getObjectAt(event.getX(), event.getY(), false);
+          if(obj != null) {
+            selectedobject_ = obj;
+            break;
+          }
+        }
+      }
+      if(selectedobject_ instanceof Selectable) {
+        if(Debug.DEBUG) System.out.println("MouseClicked (new Selectable)");
+        if(!selectedobject_.equals(savedobj) &&
+           ((Selectable)selectedobject_).isSelectable()) {
+          if(Debug.DEBUG) System.out.println("MouseClicked (new isSelectable)");
+          ((Selectable)selectedobject_).setSelected(true);
+          //
+          // mouseclick on selectable object select object
+          //
+          in_select_ = true;
+          if(!in_move_) {
+            if(Debug.DEBUG) System.out.println("MouseClicked (new !in_move_)");
+            //
+            // if in_move_ = true, already have drawn box
+            //
+            //
+            // draw initial box
+            //
+            selectedRect_ = new Rectangle(((Selectable)selectedobject_).getBounds());
+            Graphics g = pane_.getGraphics();
+            if(moveable_) {
+              g.setColor(Color.red);
+            } else {
+              g.setColor(Color.blue);
+            }
+            g.setXORMode(pane_.getBackground());
+            g.drawRect(selectedRect_.x, selectedRect_.y,
+                       selectedRect_.width, selectedRect_.height);
+            g.setPaintMode();
+          }
+          in_move_ = false;
+          changes_.firePropertyChange("objectSelected",
+                                      old_selectedobject_,
+                                      selectedobject_);
+        }
+      } else if(selectedobject_ != null) {
+        //
+        // selectedobject is in a Key
+        //
+        changes_.firePropertyChange("objectSelected",
+                                    old_selectedobject_,
+                                    selectedobject_);
+      }
+    }
+    return false;     // pass event to next level
+  }
+  private boolean Pane_MouseMoved(MouseEvent event) {
+    if(in_select_) {
+      if(selectedRect_.contains(event.getX(), event.getY())) {
+        pane_.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+      } else {
+        pane_.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+      }
+      return true;
+    } else {
+      pane_.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+    }
+    return false;
+  }
+  private boolean Pane_MouseDown(MouseEvent event) {
+    Object obj;
+    Selectable savedobj = null;
+    //
+    // continue only if button1 is pressed
+    //
+    if((event.getModifiers() & InputEvent.BUTTON1_MASK) == 0) return false;
+    //
+    // reset logicals
+    //
+
+    old_zoom_rect_ = new Rectangle(zoom_rect_);
+
+    zoom_rect_.x = 0;
+    zoom_rect_.y = 0;
+    zoom_rect_.width = 0;
+    zoom_rect_.height = 0;
+
+    if(event.isShiftDown()) {
+      //
+      // shift mousedown start zoom
+      //
+      in_zoom_ = true;
+      zoom_start_.x = event.getX();
+      zoom_start_.y = event.getY();
+      zoom_rect_.x = event.getX();
+      zoom_rect_.y = event.getY();
+      zoom_rect_.width = 1;
+      zoom_rect_.height = 1;
+      Graphics g = pane_.getGraphics();
+      g.setColor(pane_.getForeground());
+      g.setXORMode(pane_.getBackground());
+      g.drawRect(zoom_rect_.x, zoom_rect_.y,
+                 zoom_rect_.width, zoom_rect_.height);
+      g.setPaintMode();
+      return true;     // handled event here!
+    } else if(event.isControlDown()) {
+      //
+      // control mousedown ends zoom
+      //
+      return false;    // pass event to next level
+    } else if(in_select_ && moveable_ &&
+              selectedRect_.contains(event.getX(), event.getY())) {
+      if(Debug.DEBUG) System.out.println("MouseDown (in_select_ && in Rect)");
+      //
+      // object selected start move operation
+      //
+      in_move_ = true;
+      moved_ = false;
+      move_ref_ = new Point(event.getX(), event.getY());
+      return true;
+    } else if(in_select_ && !moveable_ &&
+              selectedRect_.contains(event.getX(), event.getY())) {
+      in_move_ = false;
+      moved_ = false;
+      return true;
+    } else {
+      //
+      // object not selected begin move operation
+      //
+      if(selectedobject_ instanceof Selectable)
+        savedobj = (Selectable)selectedobject_;
+      else
+        savedobj = null;
+      selectedobject_ = null;
+      Component[] comps = pane_.getComponents();
+      if(comps.length != 0) {
+        Layer ly;
+        for(int i=0; i < comps.length; i++) {
+          if(comps[i] instanceof Layer) {
+            obj = ((Layer)comps[i]).getObjectAt(event.getX(), event.getY());
+            if(obj != null) {
+              selectedobject_ = obj;
+              break;
+            }
+          } else if(comps[i] instanceof Panel) {
+            obj = ((Panel)comps[i]).getObjectAt(event.getX(), event.getY(), false);
+            if(obj != null) {
+              selectedobject_ = obj;
+              break;
+            }
+          }
+        }
+        if(selectedobject_ instanceof Selectable) {
+          if(Debug.DEBUG) System.out.println("MouseDown (Selectable)");
+          //
+          // found selectable object begin single operation move
+          //
+          if(((Selectable)selectedobject_).isSelectable()) {
+            if(Debug.DEBUG) System.out.println("MouseDown (isSelectable)");
+            draggable_ = selectedobject_ instanceof Draggable;
+            if(selectedobject_ instanceof Moveable) {
+              moveable_ =  ((Moveable)selectedobject_).isMoveable();
+            } else {
+              moveable_ = false;
+            }
+            if(moveable_ || draggable_) {
+              in_move_ = true;
+            } else {
+              in_move_ = false;
+            }
+            moved_ = false;
+            if(Debug.DEBUG) System.out.println("MouseDown (isDraggable) " +  draggable_);
+            ((Selectable)selectedobject_).setSelected(false);
+            selectedRect_ = new Rectangle(((Selectable)selectedobject_).getBounds());
+            if(!draggable_ && moveable_) {
+              //
+              // draw initial box
+              //
+              Graphics g = pane_.getGraphics();
+              g.setColor(Color.red);
+              g.setXORMode(pane_.getBackground());
+              g.drawRect(selectedRect_.x, selectedRect_.y,
+                         selectedRect_.width, selectedRect_.height);
+              g.setPaintMode();
+            }
+            if(!draggable_) pane_.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+            move_ref_ = new Point(event.getX(), event.getY());
+            return true;
+          }
+        }
+      }
+      //
+      // mousedown start zoom if object not found
+      //
+      in_zoom_ = true;
+      zoom_start_.x = event.getX();
+      zoom_start_.y = event.getY();
+      zoom_rect_.x = event.getX();
+      zoom_rect_.y = event.getY();
+      zoom_rect_.width = 1;
+      zoom_rect_.height = 1;
+      Graphics g = pane_.getGraphics();
+      g.setColor(pane_.getForeground());
+      g.setXORMode(pane_.getBackground());
+      g.drawRect(zoom_rect_.x, zoom_rect_.y,
+                 zoom_rect_.width, zoom_rect_.height);
+      g.setPaintMode();
+      return true;     // handled event here!
+    }
+    //    return false;
+  }
+  private boolean Pane_MouseDrag(MouseEvent event) {
+    boolean handled = false;
+    //
+    // continue only if button1 is pressed
+    //
+    //    if((event.getModifiers() & InputEvent.BUTTON1_MASK) == 0) return handled;
+
+    if(in_zoom_) {
+      handled = true;
+      Graphics g = pane_.getGraphics();
+      g.setColor(pane_.getForeground());
+      g.setXORMode(pane_.getBackground());
+      g.drawRect(zoom_rect_.x, zoom_rect_.y,
+                 zoom_rect_.width, zoom_rect_.height);
+      zoom_rect_.width = event.getX() - zoom_start_.x;
+      if(zoom_rect_.width < 0) {
+        zoom_rect_.x = event.getX();
+        zoom_rect_.width = Math.abs(zoom_rect_.width);
+      } else {
+        zoom_rect_.x = zoom_start_.x;
+      }
+      zoom_rect_.height = event.getY() - zoom_start_.y;
+      if(zoom_rect_.height < 0) {
+        zoom_rect_.y = event.getY();
+        zoom_rect_.height = Math.abs(zoom_rect_.height);
+      } else {
+        zoom_rect_.y = zoom_start_.y;
+      }
+      g.drawRect(zoom_rect_.x, zoom_rect_.y,
+                 zoom_rect_.width, zoom_rect_.height);
+      g.setPaintMode();
+    } else if(in_move_) {
+      handled = true;
+      moved_ = true;
+      Graphics g = pane_.getGraphics();
+      if(!draggable_ && moveable_) {
+        g.setColor(Color.red);
+        g.setXORMode(pane_.getBackground());
+        g.drawRect(selectedRect_.x, selectedRect_.y,
+                   selectedRect_.width, selectedRect_.height);
+      } else if(draggable_){
+        ((LayerChild)selectedobject_).setVisible(false);
+        Rectangle rect = ((LayerChild)selectedobject_).getBounds();
+        pane_.repaint(rect.x - 1, rect.y - 1,
+                      rect.width + 2, rect.height + 2);
+      }
+      selectedRect_.x += event.getX() - move_ref_.x;
+      selectedRect_.y += event.getY() - move_ref_.y;
+      if(!draggable_ && moveable_) {
+        g.drawRect(selectedRect_.x, selectedRect_.y,
+                   selectedRect_.width, selectedRect_.height);
+        g.setPaintMode();
+      } else if(draggable_) {
+        try {
+          ((LayerChild)selectedobject_).setVisible(true);
+          ((Draggable)selectedobject_).setLocation(new
+                        Point(selectedRect_.x, selectedRect_.y), false);
+        //      ((Draggable)selectedobject_).setLocationNoVeto(selectedRect_.x,
+        //                                                      selectedRect_.y);
+          ((LayerChild)selectedobject_).draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+      move_ref_ = new Point(event.getX(), event.getY());
+    }
+    return handled;
+  }
+  private boolean Pane_MouseUp(MouseEvent event) {
+    //
+    // continue only if button1 is pressed
+    //
+    if((event.getModifiers() & InputEvent.BUTTON1_MASK) == 0) return false;
+
+    if(in_zoom_) {
+      //
+      // finish zoom
+      //
+      in_zoom_ = false;
+      Graphics g = pane_.getGraphics();
+      g.setColor(pane_.getForeground());
+      g.setXORMode(pane_.getBackground());
+      g.drawRect(zoom_rect_.x, zoom_rect_.y,
+                 zoom_rect_.width, zoom_rect_.height);
+      changes_.firePropertyChange("zoomRectangle", old_zoom_rect_, zoom_rect_);
+      //      if(!event.isShiftDown()) return true;  // abort zoom!
+      return false;   // pass event to next level
+    } else if(in_move_ && moved_) {
+      if(Debug.DEBUG) System.out.println("MouseUp (in_move_ && moved_)");
+      //
+      // finish move
+      //
+      Graphics g = pane_.getGraphics();
+      if(!draggable_ && moveable_) {
+        g.setColor(Color.red);
+        g.setXORMode(pane_.getBackground());
+        g.drawRect(selectedRect_.x, selectedRect_.y,
+                   selectedRect_.width, selectedRect_.height);
+        g.setPaintMode();
+      }
+      // redraw, but should this only be if actually moved?
+      if(Debug.DRAW_TRACE)System.out.println("PaneProxy: Pane_MouseUp: calling draw(), batch="+batch_);
+      Point loc = new Point(selectedRect_.x, selectedRect_.y);
+      if(draggable_) {
+        ((Draggable)selectedobject_).setLocation(loc);
+        paint(g);
+      } else if(moveable_){
+        ((Moveable)selectedobject_).setLocation(loc);
+        //draw();
+        modified_ = true;
+        pane_.repaint();
+      }
+      in_move_ = false;
+      in_select_ = false;
+      moved_ = false;
+      draggable_ = false;
+      moveable_ = false;
+      ((Selectable)selectedobject_).setSelected(false);
+      pane_.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+      return true;
+    }
+    return false;
+  }
+  Dimension getMaximumSize() {
+    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  }
+  /**
+   * Returns the minimum size of this <code>Pane</code>.
+   *
+   * @return minimum size
+   */
+  Dimension getMinimumSize() {
+    return new Dimension(panesize_.width, panesize_.height);
+  }
+  /**
+   * Returns the preferred size of this <code>Pane</code>.
+   *
+   * @return preferred size
+   */
+  Dimension getPreferredSize() {
+    return new Dimension(panesize_.width, panesize_.height);
+  }
+  /**
+   * Get a <code>String</code> representatinof the
+   * <code>Pane</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = pane_.getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  void setBatch(boolean batch, String msg) {
+    batch_ = batch;
+    if(Debug.EVENT) System.out.println("PaneProxy: [" + ident_ +
+                                       "] setBatch("+batch_+"): "+msg);
+    if(!batch_ && modified_) {
+      /*
+       * batching turned off and environment has been modified
+       * re-draw pane()
+       */
+      if(Debug.EVENT)
+        System.out.println("PaneProxy: [" + ident_ +
+                           "] modified=true, draw(): batch off");
+      //draw();
+      if(Debug.DRAW_TRACE)System.out.println("PaneProxy: [" + ident_ +
+          "] setBatch: calling repaint(), batch="+batch_
+          +", modified="+modified_);
+      pane_.repaint();
+//      modified_ = false;
+    }
+  }
+  boolean isBatch() {
+    return batch_;
+  }
+  void setIgnoreModified(boolean ig) {
+    ignoreModified_ = ig;
+  }
+  void clearModified() {
+    modified_ = false;
+  }
+  void setModified(boolean mod, String mess) {
+    if(ignoreModified_) return;
+    modified_ = mod;
+    if(Debug.EVENT && batch_) {
+      System.out.println("PaneProxy: [" + ident_ +
+                         "] setModified("+modified_+"), Batch on: " + mess);
+    }
+    if(modified_ && !batch_) {
+      if(Debug.EVENT)
+        System.out.println("PaneProxy: [" + ident_ +
+                           "] setModified("+modified_+"), Batch off: " + mess);
+      //draw();
+      if(Debug.DRAW_TRACE)System.out.println("PaneProxy.setModified: calling repaint(), batch="+batch_
+          + ", modified="+modified_);
+      pane_.repaint();
+    }
+  }
+  boolean isModified() {
+    return modified_;
+  }
+  /**
+   * @since 3.0
+   */
+  void setMouseEventsEnabled(boolean enable) {
+    mouseEventsEnabled_ = enable;
+  }
+  /**
+   * @since 3.0
+   */
+  boolean isMouseEventsEnabled() {
+    return mouseEventsEnabled_;
+  }
+  /**
+   * @since 3.0
+   */
+  void setPageScaleMode(int mode) {
+    printMode_ = mode;
+  }
+  /**
+   * @since 3.0
+   */
+  int getPageScaleMode() {
+    return printMode_;
+  }
+  /*
+   * Pane PropertyChange methods
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PlainAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PlainAxis.java
new file mode 100755
index 0000000..342fe1f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PlainAxis.java
@@ -0,0 +1,331 @@
+/*
+ * $Id: PlainAxis.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.util.Vector;
+// jdk1.2
+//import java.awt.geom.Point2D;
+
+/**
+ * Axis class for creation of standard "plain" linear axes. An
+ * {@link SpaceAxis example} is available demonstrating
+ * <code>PlainAxis</code> use.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ */
+public class PlainAxis extends SpaceAxis implements Cloneable {
+  static final double TIC_GAP = 0.05;
+  static final double TIC_RATIO = 1.3;
+  static final double LABEL_RATIO = 1.1;
+  /**
+   * Default constructor for PlainAxis.
+   **/
+  public PlainAxis() {
+    this("");
+  }
+  /**
+   * Constructor for Axis. Sets the axis identifier and initializes
+   * the defaults.
+   *
+   * @param id axis identification
+   **/
+  public PlainAxis(String id) {
+    super(id);
+  }
+  public Axis copy() {
+    PlainAxis newAxis;
+    try {
+      newAxis = (PlainAxis)clone();
+    } catch (CloneNotSupportedException e) {
+      newAxis = new PlainAxis();
+    }
+    //
+    // remove registered axes and transforms
+    //
+    newAxis.registeredAxes_ = new Vector(2,2);
+    newAxis.registeredTransforms_ = new Vector(2,2);
+    //
+    return newAxis;
+  }
+  //
+  void draw(Graphics g) {
+    int xloc, yloc, xend, yend;
+    int istop, i;
+    double xt, yt, dir, x, y, xp, yp;
+    double xtitle, ytitle;
+    double delta = uRange_.delta;
+    Format format;
+    String labelText;
+    SGLabel title = getTitle();
+    if(!visible_) return;
+    if(Double.isNaN(delta)) delta = (uRange_.end - uRange_.start)/10.0;
+    if(title != null) title.setLayer(graph_.getLayer());
+    //
+    if(lineColor_ == null) {
+      g.setColor(graph_.getLayer().getPane().getComponent().getForeground());
+    } else {
+      g.setColor(lineColor_);
+    }
+    //
+    if(labelFormat_.length() <= 0) {
+      format = new Format(Format.computeFormat(uRange_.start, uRange_.end, sigDigits_));
+    } else {
+      format = new Format(labelFormat_);
+    }
+    if(orientation_ == Axis.HORIZONTAL) {
+      if(uLocation_ == null) {
+        yloc = graph_.getYUtoD(tLocation_.t);
+        yp = graph_.getYUtoP(tLocation_.t);
+      } else {
+        yloc = graph_.getYUtoD(uLocation_.y);
+        yp = graph_.getYUtoP(uLocation_.y);
+      }
+      xloc = graph_.getXUtoD(uRange_.start);
+      xend = graph_.getXUtoD(uRange_.end);
+      g.drawLine(xloc, yloc, xend, yloc);
+      //
+      dir = delta > 0? 1.0: -1.0;
+      xt = ((uRange_.start/delta + (dir*uRange_.start > 0? 1.0: -1.0)*0.00001))*delta;
+      if(dir*xt < dir*uRange_.start) xt += delta;
+      istop = (int)((uRange_.end - xt)/delta + 0.00001);
+      x = xt;
+      xp = graph_.getXUtoP(x);
+      drawSmallXTics(g, x, uRange_.start, -delta, yp);
+      drawXTic(g, xp, yp, largeTicHeight_);
+      for(i=0; i < istop; i++) {
+        drawSmallXTics(g, x, uRange_.end, delta, yp);
+        x += delta;
+        xp = graph_.getXUtoP(x);
+        drawXTic(g, xp, yp, largeTicHeight_);
+      }
+      drawSmallXTics(g, x, uRange_.end, delta, yp);
+      //
+      if(labelInterval_ <= 0 || labelPosition_ == NO_LABEL) return;
+      //
+      SGLabel label;
+      int vertalign;
+      if(labelPosition_ == POSITIVE_SIDE) {
+        vertalign = SGLabel.BOTTOM;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          yt = yp + TIC_RATIO*largeTicHeight_;
+        } else {
+          yt = yp + TIC_GAP;
+        }
+        ytitle = yt + LABEL_RATIO*labelHeight_;
+      } else {
+        vertalign = SGLabel.TOP;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          yt = yp - TIC_RATIO*largeTicHeight_;
+        } else {
+          yt = yp - TIC_GAP;
+        }
+        ytitle = yt - LABEL_RATIO*labelHeight_;
+      }
+      if(dir*uRange_.start <= 0 && dir*uRange_.end >= 0) {
+        x = ((int)(uRange_.start/(delta*labelInterval_) - 0.00001))*delta*labelInterval_;
+      } else {
+        x = xt;
+      }
+      istop = (int)((uRange_.end - x)/(delta*labelInterval_) + 0.00001);
+      for(i=0; i <= istop; i++) {
+        xt = graph_.getXUtoP(x);
+        labelText = format.form(x);
+        label = new SGLabel("coordinate", labelText, new Point2D.Double(xt, yt));
+        label.setAlign(vertalign, SGLabel.MIDDLE);
+        label.setOrientation(SGLabel.HORIZONTAL);
+        label.setFont(labelFont_);
+        label.setColor(labelColor_);
+        label.setHeightP(labelHeight_);
+        label.setLayer(graph_.getLayer());
+        try {
+          label.draw(g);
+        } catch (LayerNotFoundException e) {}
+        x = x + delta*labelInterval_;
+      }
+      if(title_ != null) {
+        xtitle = (uRange_.end + uRange_.start)*0.5;
+        yt = ytitle;
+        xt = graph_.getXUtoP(xtitle);
+        title.setLocationP(new Point2D.Double(xt, yt));
+        title.setAlign(vertalign, SGLabel.CENTER);
+        title.setOrientation(SGLabel.HORIZONTAL);
+        try {
+          title.draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+    } else {                               // orientation is vertical
+      if(uLocation_ == null) {
+        xloc = graph_.getXUtoD(tLocation_.t);
+        xp = graph_.getXUtoP(tLocation_.t);
+      } else {
+        xloc = graph_.getXUtoD(uLocation_.x);
+        xp = graph_.getXUtoP(uLocation_.x);
+      }
+      yloc = graph_.getYUtoD(uRange_.start);
+      yend = graph_.getYUtoD(uRange_.end);
+      g.drawLine(xloc, yloc, xloc, yend);
+      //
+      dir = delta > 0? 1.0: -1.0;
+      yt = ((uRange_.start/delta) + (dir*uRange_.start > 0? 1.0: -1.0)*0.00001)*delta;
+      if(dir*yt < dir*uRange_.start) yt += delta;
+      istop = (int)((uRange_.end - yt)/delta + 0.00001);
+      y = yt;
+      yp = graph_.getYUtoP(y);
+      drawSmallYTics(g, xp, y, uRange_.start, -delta);
+      drawYTic(g, xp, yp, largeTicHeight_);
+      for(i=0; i < istop; i++) {
+        drawSmallYTics(g, xp, y, uRange_.end, delta);
+        y += delta;
+        yp = graph_.getYUtoP(y);
+        drawYTic(g, xp, yp, largeTicHeight_);
+      }
+      drawSmallYTics(g, xp, y, uRange_.end, delta);
+      //
+      if(labelInterval_ <= 0 || labelPosition_ == NO_LABEL) return;
+      //
+      SGLabel label;
+      int vertalign;
+      if(labelPosition_ == NEGATIVE_SIDE) {
+        vertalign = SGLabel.BOTTOM;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xt = xp - TIC_RATIO*largeTicHeight_;
+        } else {
+          xt = xp - TIC_GAP;
+        }
+        xtitle = xt - LABEL_RATIO*labelHeight_;
+      } else {
+        vertalign = SGLabel.TOP;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xt = xp + TIC_RATIO*largeTicHeight_;
+        } else {
+          xt = xp + TIC_GAP;
+        }
+        xtitle = xt + LABEL_RATIO*labelHeight_;
+      }
+      if(dir*uRange_.start <= 0 && dir*uRange_.end >= 0) {
+        y = ((int)(uRange_.start/(delta*labelInterval_) - 0.00001))*delta*labelInterval_;
+      } else {
+        y = yt;
+      }
+      istop = (int)((uRange_.end - y)/(delta*labelInterval_) + 0.00001);
+      for(i=0; i <= istop; i++) {
+        yt = graph_.getYUtoP(y);
+        labelText = format.form(y);
+        label = new SGLabel("coordinate", labelText, new Point2D.Double(xt, yt));
+        label.setAlign(vertalign, SGLabel.CENTER);
+        label.setOrientation(SGLabel.VERTICAL);
+        label.setFont(labelFont_);
+        label.setColor(labelColor_);
+        label.setHeightP(labelHeight_);
+        label.setLayer(graph_.getLayer());
+        try {
+          label.draw(g);
+        } catch (LayerNotFoundException e) {}
+        y = y + delta*labelInterval_;
+      }
+      if(title_ != null) {
+        ytitle = (uRange_.end + uRange_.start)*0.5;
+        yt = graph_.getYUtoP(ytitle);
+        xt = xtitle;
+        title.setLocationP(new Point2D.Double(xt, yt));
+        title.setAlign(vertalign, SGLabel.CENTER);
+        title.setOrientation(SGLabel.VERTICAL);
+        try {
+          title.draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+    }
+  }
+  /**
+   * Get the bounding box for the axis in device units.
+   *
+   * @return bounding box
+   * @see Rectangle
+   **/
+  public Rectangle getBounds() {
+    double xp, yp, ymin, ymax, xmin, xmax;
+    int xd, yd, width, height, x, y;
+    if(orientation_ == Axis.HORIZONTAL) {
+      xd = graph_.getXUtoD(uRange_.start);
+      if(uLocation_ == null) {
+        yp = graph_.getYUtoP(tLocation_.t);
+      } else {
+        yp = graph_.getYUtoP(uLocation_.y);
+      }
+      width = graph_.getXUtoD(uRange_.end) - xd;
+      x = xd;
+      ymin = yp;
+      ymax = yp;
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+        ymax = ymax + largeTicHeight_;
+      }
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+        ymin = ymin - largeTicHeight_;
+      }
+      if(labelPosition_ == POSITIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          ymax = ymax + (1.0 -TIC_RATIO)*largeTicHeight_ + labelHeight_;
+        } else {
+          ymax = ymax + TIC_GAP + labelHeight_;
+        }
+      } else if(labelPosition_ == NEGATIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          ymin = ymin - (1.0 - TIC_RATIO)*largeTicHeight_ - labelHeight_;
+        } else {
+          ymin = ymin - TIC_GAP - labelHeight_;
+        }
+      }
+      y = graph_.getLayer().getYPtoD(ymax);
+      height = graph_.getLayer().getYPtoD(ymin) - y;
+    } else {
+      yd = graph_.getYUtoD(uRange_.start);
+      if(uLocation_ == null) {
+        xp = graph_.getXUtoP(tLocation_.t);
+      } else {
+        xp = graph_.getXUtoP(uLocation_.x);
+      }
+      y = graph_.getYUtoD(uRange_.end);
+      height = yd - y;
+      xmin = xp;
+      xmax = xp;
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+        xmax = xmax + largeTicHeight_;
+      }
+      if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+        xmin = xmin - largeTicHeight_;
+      }
+      if(labelPosition_ == POSITIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xmax = xmax + (1.0 -TIC_RATIO)*largeTicHeight_ + labelHeight_;
+        } else {
+          xmax = xmax + TIC_GAP + labelHeight_;
+        }
+      } else if(labelPosition_ == NEGATIVE_SIDE) {
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xmin = xmin - (1.0 - TIC_RATIO)*largeTicHeight_ - labelHeight_;
+        } else {
+          xmin = xmin - TIC_GAP - labelHeight_;
+        }
+      }
+      x = graph_.getLayer().getXPtoD(xmin);
+      width = graph_.getLayer().getXPtoD(xmax) - x;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PlotMark.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PlotMark.java
new file mode 100755
index 0000000..e0d5bf3
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PlotMark.java
@@ -0,0 +1,262 @@
+/*
+ * $Id: PlotMark.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.BorderLayout;
+import java.awt.FontMetrics;
+import java.awt.Font;
+import java.awt.Color;
+
+import javax.swing.*;
+
+import gov.noaa.pmel.util.Dimension2D;
+
+/**
+ * Support class used to draw a PlotMark. Plot mark codes are defined
+ * in the following table. <br>
+ *
+ * <P ALIGN="CENTER"><IMG SRC="plotmarkcodes.gif" ALIGN="BOTTOM" BORDER="0">
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.0
+ * @see PointCartesianRenderer
+ * @see gov.noaa.pmel.sgt.swing.PlotMarkIcon
+ */
+public class PlotMark {
+  protected int mark_;
+  protected int tableSize_ = 51;
+  protected int firstPoint_;
+  protected int lastPoint_;
+  protected double markHeight_;
+  protected int fillMark_ = 44;
+  protected boolean fill_ = false;
+  protected boolean circle_ = false;
+
+  protected static final int[][] markTable
+    = {{  5,   9}, { 11,  15}, { 14,  15}, { 11,  12},  //  0
+       { 26,  31}, { 32,  37}, { 38,  43}, { 44,  49},  //  4
+       {  1,   5}, { 64,  67}, {  5,  15}, { 50,  54},  //  8
+       {  1,   9}, { 55,  63}, { 15,  19}, { 21,  25},  // 12
+       { 50,  53}, { 51,  54}, { 72,  77}, { 84,  98},  // 16
+       { 18,  22}, { 11,  19}, { 64,  66}, { 68,  71},  // 20
+       { 68,  70}, { 78,  83}, {102, 106}, {113, 118},  // 24
+       {119, 124}, {125, 130}, {131, 136}, {105, 110},  // 28
+       {107, 112}, {137, 139}, { 99, 106}, {103, 108},  // 32
+       {140, 144}, {140, 147}, {156, 163}, {148, 155},  // 36
+       {170, 183}, {184, 189}, {188, 193}, {164, 169},  // 40
+       {  1,   5}, { 64,  67}, { 55,  63}, { 15,  19},  // 44
+       { 68,  71}, {164, 169}, {164, 169}}; // 48
+
+
+  protected static final int[] table
+    = {   9, 41, 45, 13,  9, 45,  0, 13, 41,  0,  //   0
+         25, 29,  0, 11, 43, 29, 11, 25, 43, 11,  //  10
+         25, 29, 11, 43, 29, 18, 27, 34,  0, 27,  //  20
+         24, 20, 27, 36,  0, 27, 30, 20, 27, 18,  //  30
+          0,  3, 27, 36, 27, 34,  0, 27, 51, 41,  //  40
+         13, 45,  9, 41,  4,  2, 16, 32, 50, 52,  //  50
+         38, 22,  4,  9, 29, 41,  9, 13, 25, 45,  //  60
+         13, 13, 27, 31,  0, 27, 45,  9, 27, 29,  //  70
+          0, 27, 41, 13, 20, 18,  9,  0, 18, 34,  //  80
+          0, 20, 36,  0, 45, 36, 34, 41, 19, 35,  //  90
+          0, 21, 17, 33, 37, 21, 19, 35, 33, 17,  // 100
+         21, 37, 20, 29, 25,  0, 17, 33, 21, 37,  // 110
+         35, 19, 17, 33, 21, 37, 19, 35, 33, 17,  // 120
+         21, 19, 43,  0, 37, 33, 21, 37, 25, 12,  // 130
+         44,  0, 42, 10,  0, 17, 37, 26, 30,  0,  // 140
+         12, 44,  0,  8, 40, 13, 45,  0, 43, 11,  // 150
+          0,  9, 41,  4, 41, 30,  9, 52,  4, 12,  // 160
+         20, 21, 13, 12,  0,  9, 45,  0, 33, 41,  // 170
+         42, 34, 33, 14, 44, 10,  0,  9, 41,  0,  // 180
+         42, 12, 46,  0,  0,  0,  0,  0,  0,  0}; // 190
+
+  /**
+   * Construct a <code>PlotMark</code> using the code and height from the
+   * <code>LineAttribute</code>.
+   */
+  public PlotMark(LineAttribute attr) {
+    setLineAttribute(attr);
+  }
+  /**
+   * Construct a <code>PlotMark</code> using the code and height from the
+   * <code>PointAttribute</code>.
+   */
+  public PlotMark(PointAttribute attr) {
+    setPointAttribute(attr);
+  }
+  /**
+   * Construct a <code>PlotMark</code> using the code from the
+   * mark code.  Default height = 0.08.
+   */
+  public PlotMark(int mark) {
+    setMark(mark);
+    markHeight_ = 0.08;
+  }
+  /**
+   * Set the mark and height from the <code>PointAttribute</code>.
+   */
+  public void setPointAttribute(PointAttribute attr) {
+    int mark = attr.getMark();
+    setMark(mark);
+    markHeight_ = attr.getMarkHeightP()/8.0;
+  }
+  /**
+   * Set the mark and height from the <code>LineAttribute</code>.
+   */
+  public void setLineAttribute(LineAttribute attr) {
+    int mark = attr.getMark();
+    setMark(mark);
+    markHeight_ = attr.getMarkHeightP()/8.0;
+  }
+  /**
+   * Set the mark.
+   */
+  public void setMark(int mark) {
+    if(mark <= 0) mark = 0;
+    fill_ = mark > fillMark_;
+    circle_ = mark >= 50;
+    if(circle_) fill_ = mark == 51;
+    if(mark > tableSize_) mark = tableSize_;
+    firstPoint_ = markTable[mark-1][0]-1;
+    lastPoint_ = markTable[mark-1][1];
+    mark_ = mark;
+  }
+  /**
+   * Get the mark code.
+   */
+  public int getMark() {
+    return mark_;
+  }
+  /**
+   * Set the mark height.
+   */
+  public void setMarkHeightP(double mHeight) {
+    markHeight_ = mHeight/8.0;
+  }
+  /**
+   * Get the mark height
+   */
+  public double getMarkHeightP() {
+    return markHeight_*8.0;
+  }
+  /**
+   * Used internally by sgt.
+   */
+  public void paintMark(Graphics g, Layer ly, int xp, int yp) {
+    int count, ib;
+    int xdOld = 0, ydOld = 0;
+    int movex, movey;
+    int xt, yt;
+    double xscl = ly.getXSlope()*markHeight_;
+    double yscl = ly.getYSlope()*markHeight_;
+
+    if(circle_) {
+      xt = (int)(xscl*-2) + xp;
+      yt = (int)(xscl*-2) + yp;
+      int w = (int)(xscl*4.0) - 1;
+      if(fill_) {
+        g.fillOval(xt, yt, w, w);
+      } else {
+        g.drawOval(xt, yt, w, w);
+      }
+      return;
+    }
+
+    int[] xl = new int[lastPoint_-firstPoint_];
+    int[] yl = new int[lastPoint_-firstPoint_];
+
+    boolean penf = false;
+    int i=0;
+    for(count = firstPoint_; count < lastPoint_; count++) {
+      ib = table[count];
+      if(ib == 0) {
+        penf = false;
+      } else {
+        movex = (ib>>3) - 3;
+        movey = -((ib&7) - 3);
+
+        xt = (int)(xscl*(double)movex) + xp;
+        yt = (int)(yscl*(double)movey) + yp;
+
+        if(penf) {
+          if(fill_) {
+            xl[i] = xt;
+            yl[i] = yt;
+            i++;
+          } else {
+            g.drawLine(xdOld, ydOld, xt, yt);
+          }
+        }
+        penf = true;
+        xdOld = xt;
+        ydOld = yt;
+      }
+      if(fill_) g.fillPolygon(xl, yl, i);
+    }
+  }
+
+  public static void main(String[] args) {
+    /**
+     * hack code to create a "list" of plot marks.
+     */
+    JFrame frame = new JFrame("Plot Marks");
+    frame.getContentPane().setLayout(new BorderLayout());
+    frame.setSize(500, 700);
+    JPane pane = new JPane("Plot Mark Pane", frame.getSize());
+    Layer layer = new Layer("Plot Mark Layer", new Dimension2D(5.0, 7.0));
+    pane.setBatch(true);
+    pane.setLayout(new StackedLayout());
+    frame.getContentPane().add(pane, BorderLayout.CENTER);
+    pane.add(layer);
+    frame.setVisible(true);
+    pane.setBatch(false);
+    PlotMark pm = new PlotMark(1);
+    Graphics g = pane.getGraphics();
+    g.setFont(new Font("Helvetica", Font.PLAIN, 18));
+    pm.setMarkHeightP(0.32);
+    int w = pane.getSize().width;
+    int h = pane.getSize().height;
+    g.setColor(Color.white);
+    g.fillRect(0, 0, w, h);
+    g.setColor(Color.black);
+    FontMetrics fm = g.getFontMetrics();
+    int hgt = fm.getAscent()/2;
+    String label;
+    int xt = 100;
+    int yt = 400;
+    int wid = 0;
+    int mark = 1;
+    for(int j=0; j < 13; j++) {
+      yt = 45*j + 100;
+      for(int i=0; i < 4; i++) {
+        xt = 120*i + 75;
+        label = mark + ":";
+        wid = fm.stringWidth(label) + 20;
+        g.setColor(Color.blue.brighter());
+        g.drawString(label, xt - wid, yt);
+        pm.setMark(mark);
+        g.setColor(Color.black);
+        pm.paintMark(g, layer, xt, yt - hgt);
+        mark++;
+        if(mark > 51) break;
+      }
+    }
+  }
+
+  public String toString() {
+    return "PlotMark: " + mark_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointAttribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointAttribute.java
new file mode 100755
index 0000000..6de3e6e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointAttribute.java
@@ -0,0 +1,404 @@
+/*
+ * $Id: PointAttribute.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * Set the rendereing style for point data.
+ * <code>Color</code>, width, and mark type are
+ * <code>PointAttribute</code> properties.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ * @see CartesianGraph
+ * @see PointCartesianRenderer
+ * @see PlotMark
+ */
+public class PointAttribute implements Attribute, Cloneable {
+  private transient PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  // serial version ref 1.10.2.2
+  private static final long serialVersionUID = -1147362012307247472L;
+  private boolean batch_ = false;
+  private boolean local_ = true;
+  private boolean modified_ = false;
+  private String id_ = "";
+  private Color color_;
+  private int mark_;
+  private double markHeightP_;
+  private double pwidth_;
+  //
+  private boolean drawLabel_ = false;
+  private int labelPosition_;
+  private Font labelFont_ = null;
+  private Color labelColor_ = null;
+  private double labelHeightP_;
+  /**
+   * Position label over the point
+   */
+  public static final int CENTERED = 0;
+  /**
+   * Position label north of the point
+   */
+  public static final int N = 1;
+  /**
+   * Position label northeast of the point
+   */
+  public static final int NE = 2;
+  /**
+   * Position label east of the point
+   */
+  public static final int E = 3;
+  /**
+   * Position label southeast of the point
+   */
+  public static final int SE = 4;
+  /**
+   * Position label south of the point
+   */
+  public static final int S = 5;
+  /**
+   * Position label southwest of the point
+   */
+  public static final int SW = 6;
+  /**
+   * Position label west of the point
+   */
+  public static final int W = 7;
+  /**
+   * Position label northwest of the point
+   */
+  public static final int NW = 8;
+  /**
+   * Default constructor.  Default mark is 2 and
+   * default color is red.
+   **/
+  public PointAttribute() {
+    this(2, Color.red);
+}
+  /**
+   * Constructor for plot marks.
+   *
+   * @param mark plot mark
+   * @param color Point color
+   * @see PlotMark
+   **/
+  public PointAttribute(int mark, Color color) {
+    mark_ = mark;
+    color_ = color;
+    markHeightP_ = 0.1;
+    labelHeightP_ = 0.1;
+    labelColor_ = Color.black;
+    drawLabel_ = false;
+  }
+  /**
+   * Copy the <code>PointAttribute</code>.
+   *
+   * @return new <code>PointAttribute</code>
+   */
+  public PointAttribute copy() {
+    PointAttribute newPoint;
+    try {
+      newPoint = (PointAttribute)clone();
+    } catch (CloneNotSupportedException e) {
+      newPoint = new PointAttribute();
+    }
+    return newPoint;
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean equals(Object obj) {
+    if(obj == null || !(obj instanceof PointAttribute)) return false;
+    PointAttribute attr = (PointAttribute)obj;
+    if((!id_.equals(attr.getId())) ||
+       (!color_.equals(attr.getColor())) ||
+       (mark_ != attr.getMark()) ||
+       (markHeightP_ != attr.getMarkHeightP()) ||
+       (pwidth_ != attr.getWidthP()) ||
+       (drawLabel_ != attr.isDrawLabel())) return false;
+    if(drawLabel_) {
+      if(labelFont_ == null) {
+        if(attr.getLabelFont() != null) return false;
+      } else {
+        if(attr.getLabelFont() == null) return false;
+        if(!labelFont_.equals(attr.getLabelFont())) return false;
+      }
+      if(labelColor_ == null) {
+        if(attr.getLabelColor() != null) return false;
+      } else {
+        if(attr.getLabelColor() == null) return false;
+        if(!labelColor_.equals(attr.getLabelColor())) return false;
+      }
+      if((labelPosition_ != attr.getLabelPosition()) ||
+         (labelHeightP_ != attr.getLabelHeightP())) return false;
+    }
+    return true;
+  }
+  /**
+   * Set mark height.
+   * <BR><B>Property Change:</B> <code>markHeightP</code>.
+   *
+   * @param markh mark height
+   **/
+  public void setMarkHeightP(double markh) {
+    if(markHeightP_ != markh) {
+      Double tempOld = new Double(markHeightP_);
+      markHeightP_ = markh;
+      firePropertyChange("markHeightP",
+                                  tempOld,
+                                  new Double(markHeightP_));
+    }
+  }
+  /**
+   * Get mark height
+   *
+   * @return mark height
+   **/
+  public double getMarkHeightP() {
+    return markHeightP_;
+  }
+  /**
+   * Set the point <code>Color</code>.
+   * <BR><B>Property Change:</B> <code>color</code>.
+   *
+   * @param c point <code>Color</code>
+   **/
+  public void setColor(Color c) {
+    if(!color_.equals(c)) {
+      Color tempOld = color_;
+      color_ = c;
+      firePropertyChange("color",
+                                  tempOld,
+                                  color_);
+    }
+  }
+  /**
+   * Set the Point width in physical units.
+   * <BR><B>Property Change:</B> <code>widthP</code>.
+   *
+   * @param t Point width
+   **/
+  public void setWidthP(double t) {
+    if(pwidth_ != t) {
+      Double tempOld = new Double(pwidth_);
+      pwidth_ = t;
+      firePropertyChange("widthP",
+                                  tempOld,
+                                  new Double(pwidth_));
+    }
+  }
+  /**
+   * Get Point <code>Color</code>.
+   *
+   * @return Point <code>Color</code>
+   **/
+  public Color getColor() {
+    return color_;
+  }
+  /**
+   * Get Point width.
+   *
+   * @return Point width in physcial coordinates.
+   **/
+  public double getWidthP() {
+    return pwidth_;
+  }
+  /**
+   * Set plot mark
+   * <BR><B>Property Change:</B> <code>mark</code>.
+   *
+   * @param mark the plot mark
+   * @see PlotMark
+   **/
+  public void setMark(int mark) {
+    if(mark_ != mark) {
+      Integer tempOld = new Integer(mark_);
+      mark_ = mark;
+      firePropertyChange("mark",
+                                  tempOld,
+                                  new Integer(mark_));
+    }
+  }
+  /**
+   * Get plot mark
+   *
+   * @return plot mark
+   * @see PlotMark
+   **/
+  public int getMark() {
+    return mark_;
+  }
+  /**
+   * Set label position.
+   * <BR><B>Property Change:</B> <code>labelPosition</code>.
+   */
+  public void setLabelPosition(int pos) {
+    if(labelPosition_ != pos) {
+      Integer tempOld = new Integer(labelPosition_);
+      labelPosition_ = pos;
+      firePropertyChange("labelPosition",
+                                  tempOld,
+                                  new Integer(labelPosition_));
+    }
+  }
+  /**
+   * Get label position.
+   */
+  public int getLabelPosition() {
+    return labelPosition_;
+  }
+  /**
+   * Set label <code>Color</code>.
+   * <BR><B>Property Change:</B> <code>labelColor</code>.
+   */
+  public void setLabelColor(Color col) {
+    if(labelColor_ == null || !labelColor_.equals(col)) {
+      Color tempOld = labelColor_;
+      labelColor_ = col;
+      firePropertyChange("labelColor",
+                                  tempOld,
+                                  labelColor_);
+    }
+  }
+  /**
+   * Get label <code>Color</code>.
+   */
+  public Color getLabelColor() {
+    return labelColor_;
+  }
+  /**
+   * Set label <code>Font</code>.
+   * <BR><B>Property Change:</B> <code>labelFont</code>.
+   */
+  public void setLabelFont(Font font) {
+    if(labelFont_ == null || !labelFont_.equals(font)) {
+      Font tempOld = labelFont_;
+      labelFont_ = font;
+      firePropertyChange("labelFont",
+                                  tempOld,
+                                  labelFont_);
+    }
+  }
+  /**
+   * Get label <code>Font</code>.
+   */
+  public Font getLabelFont() {
+    return labelFont_;
+  }
+  /**
+   * Set label height.
+   * <BR><B>Property Change:</B> <code>labelHeightP</code>.
+   */
+  public void setLabelHeightP(double h) {
+    if(labelHeightP_ != h) {
+      Double tempOld = new Double(labelHeightP_);
+      labelHeightP_ = h;
+      firePropertyChange("labelHeightP",
+                                  tempOld,
+                                  new Double(labelHeightP_));
+    }
+  }
+  /**
+   * Get label height.
+   */
+  public double getLabelHeightP() {
+    return labelHeightP_;
+  }
+  /**
+   * Set label drawing.
+   * <BR><B>Property Change:</B> <code>drawLabel</code>.
+   */
+  public void setDrawLabel(boolean dl) {
+    if(drawLabel_ != dl) {
+      Boolean tempOld = new Boolean(drawLabel_);
+      drawLabel_ = dl;
+      firePropertyChange("drawLabel",
+                                  tempOld,
+                                  new Boolean(drawLabel_));
+    }
+  }
+  /**
+   * Is label drawing on?
+   */
+  public boolean isDrawLabel() {
+    return drawLabel_;
+  }
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>PointAttribute</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1);
+  }
+  /**
+   * Add listener to changes in <code>PointAttribute</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.addPropertyChangeListener(listener);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setId(String id) {
+    id_ = id;
+  }
+  /**
+   * @since 3.0
+   */
+  public String getId() {
+    return id_;
+  }
+
+  protected void firePropertyChange(String name, Object oldValue, Object newValue) {
+    if(batch_) {
+      modified_ = true;
+      return;
+    }
+    AttributeChangeEvent ace = new AttributeChangeEvent(this, name,
+                                                        oldValue, newValue,
+                                                        local_);
+    changes_.firePropertyChange(ace);
+    modified_ = false;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch) {
+    setBatch(batch, true);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch, boolean local) {
+    batch_ = batch;
+    local_ = local;
+    if(!batch && modified_) firePropertyChange("batch", Boolean.TRUE, Boolean.FALSE);
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean isBatch() {
+    return batch_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointCartesianRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointCartesianRenderer.java
new file mode 100755
index 0000000..47489ad
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointCartesianRenderer.java
@@ -0,0 +1,350 @@
+/*
+ * $Id: PointCartesianRenderer.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTPoint;
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Event;
+import java.awt.Point;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Produces a point plot with optional coloring from a second data set. If
+ * a second data set is specified it must have the same shape as the first.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.0
+ */
+public class PointCartesianRenderer extends CartesianRenderer {
+  /**@shapeType AggregationLink
+   * @label attr
+   * @supplierCardinality 1
+   * @undirected */
+  private PointAttribute attr_ = null;
+  /**@shapeType AggregationLink
+   * @supplierCardinality 0..1
+   * @label point
+   * @undirected */
+  private SGTPoint point_ = null;
+  /**@shapeType AggregationLink
+   * @supplierCardinality 0..1 */
+  private Collection collection_ = null;
+
+  /**
+   * Get the Attribute associated with the data.
+   */
+  public Attribute getAttribute() {
+    return attr_;
+  }
+  private void drawPoint(Graphics g, SGTPoint point, PlotMark pm) {
+    int xp, yp;
+
+    if(pm.getMark() == 0) return;
+
+    if(point.isXTime()) {
+      xp = cg_.getXUtoD(point.getLongTime());
+    } else {
+      xp = cg_.getXUtoD(point.getX());
+    }
+    if(point.isYTime()) {
+      yp = cg_.getYUtoD(point.getLongTime());
+    } else {
+      yp = cg_.getYUtoD(point.getY());
+    }
+    //
+    // check for missing values a Double.NaN is converted to a Integer.MIN_VALUE
+    //
+    if(xp == Integer.MIN_VALUE || yp == Integer.MIN_VALUE) {
+      return;
+    }
+    //
+    // draw regular point
+    //
+    pm.paintMark(g, cg_.getLayer(), xp, yp);
+  }
+  private void drawLabel(Graphics g, SGTPoint point, PointAttribute attr) {
+    int valign,  halign;
+    Point2D.Double loc;
+    double xp, yp;
+    double xl, yl, loff;
+    Layer ly = cg_.getLayer();
+
+    if(point.isXTime()) {
+      xp = cg_.getXUtoP(point.getLongTime());
+    } else {
+      xp = cg_.getXUtoP(point.getX());
+    }
+    if(point.isYTime()) {
+      yp = cg_.getYUtoP(point.getLongTime());
+    } else {
+      yp = cg_.getYUtoP(point.getY());
+    }
+
+    loff = attr.getMarkHeightP()/2.0;
+    xl = 0.0;
+    yl = 0.0;
+    switch(attr.getLabelPosition()) {
+    case PointAttribute.CENTERED:
+      valign = SGLabel.MIDDLE;
+      halign = SGLabel.CENTER;
+      break;
+    case PointAttribute.N:
+      valign = SGLabel.BOTTOM;
+      halign = SGLabel.CENTER;
+      yl = loff;
+      break;
+    default:
+    case PointAttribute.NE:
+      valign = SGLabel.BOTTOM;
+      halign = SGLabel.LEFT;
+      yl = loff;
+      xl = loff;
+      break;
+    case PointAttribute.E:
+      valign = SGLabel.MIDDLE;
+      halign = SGLabel.LEFT;
+      xl = loff;
+      break;
+    case PointAttribute.SE:
+      valign = SGLabel.TOP;
+      halign = SGLabel.LEFT;
+      yl = -loff;
+      xl = loff;
+      break;
+    case PointAttribute.S:
+      valign = SGLabel.TOP;
+      halign = SGLabel.CENTER;
+      yl = -loff;
+      break;
+    case PointAttribute.SW:
+      valign = SGLabel.TOP;
+      halign = SGLabel.RIGHT;
+      yl = -loff;
+      xl = -loff;
+      break;
+    case PointAttribute.W:
+      valign = SGLabel.MIDDLE;
+      halign = SGLabel.RIGHT;
+      xl = -loff;
+      break;
+    case PointAttribute.NW:
+      valign = SGLabel.BOTTOM;
+      halign = SGLabel.RIGHT;
+      yl = loff;
+      xl = -loff;
+      break;
+    }
+    SGLabel pl = new SGLabel("point",
+                             point.getTitle(),
+                             attr.getLabelHeightP(),
+                             new Point2D.Double(xp + xl, yp + yl),
+                             valign,
+                             halign);
+    pl.setColor(attr.getLabelColor());
+    pl.setFont(attr.getLabelFont());
+    pl.setLayer(ly);
+    try {
+      pl.draw(g);
+    } catch (LayerNotFoundException e) {}
+
+  }
+  /**
+   * Default constructor.
+   *
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public PointCartesianRenderer(CartesianGraph cg) {
+    this(cg, (SGTPoint)null, null);
+  }
+  /**
+   * Construct a PointCartesianRenderer. The default
+   * PointAttribute will be used.
+   *
+   * @param cg the parent CartesianGraph
+   * @param data an SGTPoint object
+   *
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public PointCartesianRenderer(CartesianGraph cg, SGTPoint point) {
+    this(cg, point, null);
+    cg_ = cg;
+    point_ = point;
+  }
+  /**
+   * Construct a PointCartesianRenderer.
+   *
+   * @param cg the parent CartesianGraph
+   * @param data an SGTPoint object
+   * @param Point the PointAttribute
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public PointCartesianRenderer(CartesianGraph cg, SGTPoint point, PointAttribute attr) {
+    cg_ = cg;
+    point_ = point;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Construct a PointCartesianRenderer.
+   *
+   * @param cg the parent CartesianGraph
+   * @param col a Collection of SGTPoint objects
+   * @param point the PointAttribute
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public PointCartesianRenderer(CartesianGraph cg, Collection col, PointAttribute attr) {
+    cg_ = cg;
+    collection_ = col;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  public void draw(Graphics g) {
+    PointAttribute attr;
+    Object point;
+    PlotMark pm;
+
+    if(cg_.clipping_) {
+      int xmin, xmax, ymin, ymax;
+      int x, y, width, height;
+      if(cg_.xTransform_.isSpace()) {
+        xmin = cg_.getXUtoD(cg_.xClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.xClipRange_.end);
+      } else {
+        xmin = cg_.getXUtoD(cg_.tClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.tClipRange_.end);
+      }
+      if(cg_.yTransform_.isSpace()) {
+        ymin = cg_.getYUtoD(cg_.yClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.yClipRange_.end);
+      } else {
+        ymin = cg_.getYUtoD(cg_.tClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.tClipRange_.end);
+      }
+      if(xmin < xmax) {
+        x = xmin;
+        width = xmax - xmin;
+      } else {
+        x=xmax;
+        width = xmin - xmax;
+      }
+      if(ymin < ymax) {
+        y = ymin;
+        height = ymax - ymin;
+      } else {
+        y = ymax;
+        height = ymin - ymax;
+      }
+      g.setClip(x, y, width, height);
+    }
+    if(attr_ == null) {
+      attr = new PointAttribute(2,
+                                cg_.layer_.getPane().getComponent().getForeground());
+    } else {
+      attr = attr_;
+    }
+    pm = new PlotMark(attr);
+    if(collection_ == null) {
+      g.setColor(attr.getColor());
+      drawPoint(g, point_, pm);
+      if(attr.isDrawLabel()) drawLabel(g, point_, attr);
+    } else {
+      for(Enumeration li = collection_.elements(); li.hasMoreElements();) {
+        point = li.nextElement();
+        if(point instanceof SGTPoint) {
+          g.setColor(attr.getColor());
+          drawPoint(g, (SGTPoint)point, pm);
+          if(attr.isDrawLabel()) drawLabel(g, (SGTPoint)point, attr);
+        }
+      }
+    }
+
+    //
+    // reset clip
+    //
+    Rectangle rect = cg_.getLayer().getPane().getBounds();
+    g.setClip(rect);
+  }
+  /**
+   * Set the Point attribute object. The Point appearance is controlled by
+   * this object.
+   *
+   * @param l Point attribute
+   **/
+  public void setPointAttribute(PointAttribute l) {
+    if(attr_ != null) attr_.removePropertyChangeListener(this);
+    attr_ = l;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Get the Point attribute object.
+   *
+   * @return Point attribute
+   **/
+  public PointAttribute getPointAttribute() {
+    return attr_;
+  }
+  /**
+   * Is point data as a collection?
+   */
+  public boolean hasCollection() {
+    return (collection_ != null);
+  }
+  /**
+   * Get the <code>Collection</code> of points.
+   */
+  public Collection getCollection() {
+    return collection_;
+  }
+  public SGTPoint getPoint() {
+    return point_;
+  }
+  /**
+   * Get the associated <code>CartesianGraph</code> object.
+   *
+   * @return <code>CartesianGraph</code>
+   */
+  public CartesianGraph getCartesianGraph() {
+    return cg_;
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+//      if(Debug.EVENT) {
+//        System.out.println("PointCartesianRenderer: " + evt);
+//        System.out.println("                        " + evt.getPropertyName());
+//      }
+    modified("PointCartesianRenderer: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  /**
+   * @since 3.0
+   */
+  public SGTData getDataAt(Point pt) {
+    return null;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointCollectionKey.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointCollectionKey.java
new file mode 100755
index 0000000..5c179f0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PointCollectionKey.java
@@ -0,0 +1,733 @@
+/*
+ * $Id: PointCollectionKey.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeSupport;
+
+// jdk1.2
+//import java.awt.geom.Point2D;
+
+/**
+ * <code>PointCollectionKey</code> is used to create a key for the
+ * <code>PointCartesianRenderer</code>. Multiple
+ * lines can be included in the key.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.0
+**/
+public class PointCollectionKey implements Cloneable,
+        DataKey, Moveable, PropertyChangeListener {
+  private String ident_;
+/** @directed */
+  private Layer layer_;
+  private Vector points_;
+  private Vector label_;
+  private int columns_;
+  private int style_;
+  private int valign_;
+  private int halign_;
+  private Point2D.Double porigin_;
+  private double lineLengthP_;
+  private int maxLabelLength_;
+  private int maxLabelHeight_;
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean visible_;
+  private boolean moveable_;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private static final int VERTICAL_BORDER_ = 3;
+  private static final int HORIZONTAL_BORDER_ = 15;
+  private static final int COLUMN_SPACE_ = 10;
+  private static final int ROW_SPACE_ = 3;
+  private static final int LABEL_SPACE_ = 15;
+  /**
+   * Use plain line border.
+   */
+  public static final int PLAIN_LINE = 0;
+  /**
+   * Use raised border.
+   */
+  public static final int RAISED = 1;
+  /**
+   * Do not draw a border.
+   */
+  public static final int NO_BORDER = 2;
+  /**
+   * Align to top of key.
+   */
+  public static final int TOP = 0;
+  /**
+   * Align to middle of key.
+   */
+  public static final int MIDDLE = 1;
+  /**
+   * Align to bottom of key.
+   */
+  public static final int BOTTOM = 2;
+  /**
+   * Align to left of key.
+   */
+  public static final int LEFT = 0;
+  /**
+   * Align to center of key.
+   */
+  public static final int CENTER = 1;
+  /**
+   * Align to right of key.
+   */
+  public static final int RIGHT = 2;
+
+  /**
+   * @link aggregation
+   * @supplierCardinality *
+   * @label points
+   */
+  /*#PointCartesianRenderer lnkPointCartesianRenderer;*/
+
+  /** @link aggregation
+   * @label label
+   * @supplierCardinality **/
+  /*#SGLabel lnkSGLabel;*/
+
+  /**
+   * Default constructor.
+   */
+  public PointCollectionKey() {
+    this(new Point2D.Double(0.0, 0.0), BOTTOM, LEFT);
+  }
+  /**
+   * Create <code>PointCollectionKey</code>.
+   */
+  public PointCollectionKey(Point2D.Double loc,int valign,int halign) {
+    porigin_ = loc;
+    valign_ = valign;
+    halign_ = halign;
+    points_ = new Vector(2,2);
+    label_ = new Vector(2,2);
+    //
+    // set defaults
+    //
+    style_ = PLAIN_LINE;
+    columns_ = 1;
+    ident_ = "";
+    lineLengthP_ = 0.3f;
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+    moveable_ = true;
+  }
+  /**
+   * Create of copy of PointCollectionKey.
+   */
+  public LayerChild copy() {
+    PointCollectionKey newKey;
+    try {
+      newKey = (PointCollectionKey)clone();
+    } catch (CloneNotSupportedException e) {
+      newKey = new PointCollectionKey();
+    }
+    newKey.points_ = new Vector(2,2);
+    newKey.label_ = new Vector(2,2);
+    return newKey;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  public boolean isMoveable() {
+    return moveable_;
+  }
+  public void setMoveable(boolean moveable) {
+    moveable_ = moveable;
+  }
+  /**
+   * Set parent layer.
+   *
+   * @param l parent layer
+   */
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  /**
+   * Get layer.
+   *
+   * @return layer
+   */
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+
+  public void modified(String mess) {
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Set PointCollectionKey identifier.
+   *
+   * @param id key identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get PointCollectionKey identifier
+   *
+   * @return identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set line length.
+   *
+   * @param len line length
+   */
+  public void setLineLengthP(double len) {
+    if(lineLengthP_ != len) {
+      lineLengthP_ = len;
+      modified("PointCollectionKey: setLineLengthP()");
+    }
+  }
+  /**
+   * Get line length
+   *
+   * @return line length
+   */
+  public double getLineLengthP() {
+    return lineLengthP_;
+  }
+  /**
+   * Set the number of columns.
+   *
+   * @param col number of columns
+   */
+  public void setColumns(int col) {
+    if(columns_ != col) {
+      columns_ = col;
+      modified("PointCollectionKey: setColumms()");
+    }
+  }
+  /**
+   * Get the number of columns.
+   *
+   * @return number of columns
+   */
+  public int getColumns() {
+    return columns_;
+  }
+  /**
+   * Set border style.
+   *
+   * @param style border style
+   * @see #PLAIN_LINE
+   * @see #RAISED
+   * @see #NO_BORDER
+   */
+  public void setBorderStyle(int style) {
+    if(style_ != style) {
+      style_ = style;
+      modified("PointCollectionKey: setBorderStyle()");
+    }
+  }
+  /**
+   * Get border style.
+   *
+   * @return border style
+   */
+  public int getBorderStyle() {
+    return style_;
+  }
+  /**
+   * Set alignment.
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   */
+  public void setAlign(int vert,int horz) {
+    if(valign_ != vert || halign_ != horz) {
+      valign_ = vert;
+      halign_ = horz;
+      modified("PointCollectionKey: setAlign()");
+    }
+  }
+  /**
+   * Set vertical alignment
+   *
+   * @param vert vertical alignment
+   */
+  public void setVAlign(int vert) {
+    if(valign_ != vert) {
+      valign_ = vert;
+      modified("PointCollectionKey: setVAlign()");
+    }
+  }
+  /**
+   * Set horizontal alignment
+   *
+   * @param horz horizontal alignment
+   */
+  public void setHAlign(int horz) {
+    if(halign_ != horz) {
+      halign_ = horz;
+      modified("PointCollectionKey: setHAlign()");
+    }
+  }
+  /**
+   * Get vertical alignment
+   *
+   * @return vertical alignment
+   */
+  public int getVAlign() {
+    return valign_;
+  }
+  /**
+   * Get horizontal alignment
+   *
+   * @return horizontal alignment
+   */
+  public int getHAlign() {
+    return halign_;
+  }
+  /**
+   * Set location of key
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @param loc key location
+   */
+  public void setLocationP(Point2D.Double loc) {
+    if(porigin_ == null || !porigin_.equals(loc)) {
+      Point2D.Double temp = porigin_;
+      porigin_ = loc;
+      changes_.firePropertyChange("location",
+          temp,
+          porigin_);
+      modified("PointCollectionKey: setLocationP()");
+    }
+  }
+  /**
+   * Set the bounds, in physical units, of the <code>PointCollectionKey</code>
+   */
+  public void setBoundsP(Rectangle2D.Double r) {
+    setLocationP(new Point2D.Double(r.x, r.y));
+  }
+  public Rectangle2D.Double getBoundsP() {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Get location of key.
+   *
+   * @return Key location
+   */
+  public Point2D.Double getLocationP() {
+    return porigin_;
+  }
+  /**
+   * Add a PointCartesianRenderer and label to the PointCollectionKey.
+   *
+   * @param line PointCartesianRenderer object
+   * @param label descriptive label
+   */
+  public void addPointGraph(PointCartesianRenderer points, SGLabel label) {
+    points_.addElement(points);
+    label.setLayer(layer_);
+    label.setMoveable(false);
+    label.setSelectable(false);
+    label_.addElement(label);
+    ((PointAttribute)points.getAttribute()).addPropertyChangeListener(this);
+    modified("PointCollectionKey: addPointGraph()");
+  }
+  /**
+   * Add a PointCartesianRenderer and label to the PointCollectionKey.
+   *
+   * @param rend CartesianRenderer object
+   * @param label descriptive label
+   * @since 3.0
+   */
+  public void addGraph(CartesianRenderer rend, SGLabel label)
+      throws IllegalArgumentException {
+    if(!(rend instanceof PointCartesianRenderer))
+      throw new IllegalArgumentException("Renderer is not a PointCartesianRenderer");
+    addPointGraph((PointCartesianRenderer)rend, label);
+  }
+  /**
+   * Remove a line from the PointCollectionKey.
+   *
+   */
+  public void removePointGraph(SGLabel label) {
+  }
+  /**
+   * Remove a line from the PointCollectionKey.
+   *
+   */
+  public void removePointRenderer(PointCartesianRenderer line) {
+  }
+  /**
+   * Remove a line from the PointCollectionKey.
+   *
+   */
+  public void removePointGraph(String ident) {
+  }
+  /**
+   * Remove all lines from the PointCollectionKey.
+   */
+  public void clearAll() {
+    PointAttribute attr;
+    for(Enumeration e = points_.elements(); e.hasMoreElements(); ) {
+      attr = (PointAttribute)((PointCartesianRenderer)e.nextElement()).getAttribute();
+      attr.removePropertyChangeListener(this);
+    }
+    points_.removeAllElements();
+    label_.removeAllElements();
+    modified("PointCollectionKey: clearAll()");
+  }
+  /**
+   * Remove data from key by id.
+   */
+  public void clear(String data_id) {
+    PointCartesianRenderer pcr;
+    int indx = -1;
+    for(Enumeration it = points_.elements(); it.hasMoreElements();) {
+      indx++;
+      pcr = (PointCartesianRenderer)it.nextElement();
+//        if(pcr.getLine().getId().equals(data_id)) {
+//  	pcr.getAttribute().removePropertyChangeListener(this);
+//  	points_.removeElement(lcr);
+//  	label_.removeElementAt(indx);
+//  	modified("PointCollectionKey: clear()");
+//  	break;
+//        }
+    }
+  }
+  /**
+   * Return height of key row in pixels.
+   */
+  public int getRowHeight() {
+    Rectangle bounds;
+    bounds = getBounds();
+    return ROW_SPACE_ + maxLabelHeight_;
+  }
+  /**
+   * Draw the Key.
+   */
+  public void draw(Graphics g) {
+    double maxLabelLength, maxLabelHeight;
+    int numLines, numRows, i, lineLength;
+    int col, row, ytemp;
+    double xloc, labelSpace;
+    double[] xp, yp;
+    int[] xd, yd;
+    int[] xout, yout;
+    Rectangle bounds;
+    PointCartesianRenderer render = null;
+    SGLabel label;
+    PointAttribute attr = null;
+    //
+    numLines = points_.size();
+    if((numLines <= 0) || !visible_) return;
+
+    numRows = numLines/columns_;
+    if(numLines%columns_ != 0) numRows++;
+
+    xp = new double[columns_];
+    xd = new int[columns_];
+    yp = new double[numRows];
+    yd = new int[numRows];
+    xout = new int[2];
+    yout = new int[2];
+
+    g.setColor(layer_.getPane().getComponent().getForeground());
+    bounds = getBounds();
+    //
+    // compute location of rows and columns in device and physical coordinates
+    //
+    lineLength = layer_.getXPtoD(lineLengthP_) - layer_.getXPtoD(0.0f);
+    labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0);
+    //
+    yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_;
+    yp[0] = layer_.getYDtoP(yd[0]);
+    for(i=1; i < numRows; i++) {
+      yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_;
+      yp[i] = layer_.getYDtoP(yd[i]);
+    }
+    xd[0] = bounds.x + HORIZONTAL_BORDER_;
+    xp[0] = layer_.getXDtoP(xd[0]);
+    for(i=1; i < columns_; i++) {
+      xd[i] = xd[i-1] + COLUMN_SPACE_ + lineLength + LABEL_SPACE_ + maxLabelLength_;
+      xp[i] = layer_.getXDtoP(xd[i]);
+    }
+    //
+    row = 0;
+    col = 0;
+    Object obj;
+    Enumeration labelIt = label_.elements();
+    for(Enumeration lineIt = points_.elements(); lineIt.hasMoreElements();) {
+      obj = lineIt.nextElement();
+      render = (PointCartesianRenderer)obj;
+      attr = (PointAttribute)render.getAttribute();
+      label = (SGLabel)labelIt.nextElement();
+      //
+      // draw line
+      //
+      g.setColor(attr.getColor());
+      xout[0] = xd[col];
+      xout[1] = xout[0] + lineLength;
+      yout[0] = yd[row] - maxLabelHeight_/2;
+      yout[1] = yout[0];
+
+      // hack because mark is a little too high
+      int ymark = yout[0]
+;
+      PlotMark pm = new PlotMark(attr);
+      pm.setMarkHeightP(label.getHeightP());
+      pm.paintMark(g, layer_, xout[0], ymark);
+      pm.paintMark(g, layer_, xout[1], ymark);
+      //
+      xloc = xp[col] + lineLengthP_ + labelSpace;
+      label.setLocationP(new Point2D.Double(xloc, yp[row]));
+      try {
+        label.draw(g);
+      } catch (SGException e) {}
+      //
+      col++;
+      if(col >= columns_) {
+        col = 0;
+        row++;
+      }
+    }
+    switch(style_) {
+    case PLAIN_LINE:
+      g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+      break;
+    case RAISED:
+      break;
+    default:
+    case NO_BORDER:
+    }
+  }
+  /**
+   * Get the bounding rectangle.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds() {
+    int lineLength;
+    int numLines, rows;
+    int x, y, height, width;
+
+    numLines = points_.size();
+    if(numLines <= 0) return new Rectangle(0, 0, 0, 0);
+    //
+    // find longest label
+    //
+    maxLabelLength_ = 0;
+    maxLabelHeight_ = 0;
+    SGLabel label;
+    for(Enumeration it = label_.elements(); it.hasMoreElements();) {
+      label = (SGLabel)it.nextElement();
+      Rectangle sz = label.getBounds();
+      maxLabelLength_ = Math.max(maxLabelLength_, sz.width);
+      maxLabelHeight_ = Math.max(maxLabelHeight_, sz.height);
+    }
+    //
+    rows = numLines/columns_;
+    if(numLines%columns_ != 0) rows++;
+    lineLength = layer_.getXPtoD(lineLengthP_) - layer_.getXPtoD(0.0f);
+    width = 2*HORIZONTAL_BORDER_ +
+      columns_*(lineLength + LABEL_SPACE_ + maxLabelLength_) +
+      (columns_ - 1)*COLUMN_SPACE_;
+    height = 2*VERTICAL_BORDER_ + rows*maxLabelHeight_ +
+      (rows-1)*ROW_SPACE_;
+    // temp fudge
+    height = height + 5;
+    //
+    x = layer_.getXPtoD(porigin_.x);
+    y = layer_.getYPtoD(porigin_.y);
+    switch(halign_) {
+    case RIGHT:
+      x = x - width;
+      break;
+    case CENTER:
+      x = x - width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y - height;
+      break;
+    case MIDDLE:
+      y = y - height/2;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+  public Point getLocation() {
+    Rectangle bnds = getBounds();
+    return new Point(bnds.x, bnds.y);
+  }
+  public void setLocation(Point loc) {
+    Rectangle bnds = getBounds();
+    setBounds(loc.x, loc.y, bnds.width, bnds.height);
+  }
+  /**
+   * Set the bounds, in pixels, of the <code>PointCollectionKey</code>
+   */
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  /**
+   * Set the bounds, in pixels, of the <code>PointCollectionKey</code>
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    switch(halign_) {
+    case RIGHT:
+      x = x + width;
+      break;
+    case CENTER:
+      x = x + width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y + height;
+      break;
+    case MIDDLE:
+      y = y + height/2;
+    }
+    double xp = layer_.getXDtoP(x);
+    double yp = layer_.getYDtoP(y);
+    if(porigin_.x != xp || porigin_.y != yp) {
+      Point2D.Double temp = porigin_;
+      porigin_.x = xp;
+      porigin_.y = yp;
+      changes_.firePropertyChange("location",
+          temp,
+          new Point2D.Double(xp, yp));
+      modified("PointCollectionKey: setBounds()");
+    }
+  }
+  Object getObjectAt(Point pt) {
+    Rectangle lbnds;
+    Rectangle bounds;
+    PointCartesianRenderer point;
+    int[] xout, yout;
+    int[] xd, yd;
+    int numLines, numRows;
+    int lineLength;
+    double labelSpace;
+    int i;
+
+    numLines = points_.size();
+    if(numLines <= 0) return null;
+
+    numRows = numLines/columns_;
+    if(numLines%columns_ != 0) numRows++;
+
+    xd = new int[columns_];
+    yd = new int[numRows];
+    xout = new int[2];
+    yout = new int[2];
+    bounds = getBounds();
+    //
+    // compute location of rows and columns in device and physical coordinates
+    //
+    lineLength = layer_.getXPtoD(lineLengthP_) - layer_.getXPtoD(0.0);
+    labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0);
+    //
+    yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_;
+    for(i=1; i < numRows; i++) {
+      yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_;
+    }
+    xd[0] = bounds.x + HORIZONTAL_BORDER_;
+    for(i=1; i < columns_; i++) {
+      xd[i] = xd[i-1] + COLUMN_SPACE_ + lineLength + LABEL_SPACE_ + maxLabelLength_;
+    }
+    // loop over all the lines
+    int row = 0;
+    int col = 0;
+    for(Enumeration lineIt = points_.elements(); lineIt.hasMoreElements();) {
+      point = (PointCartesianRenderer)lineIt.nextElement();
+      xout[0] = xd[col];
+//        xout[1] = xout[0] + lineLength + LABEL_SPACE_ + maxLabelLength_;
+      xout[1] = xout[0] + lineLength + LABEL_SPACE_;
+      yout[0] = yd[row] - maxLabelHeight_;
+      yout[1] = yd[row];
+      lbnds = new Rectangle(xout[0], yout[0],
+                            xout[1] - xout[0],
+                            yout[1] - yout[0]);
+      if(lbnds.contains(pt)) {
+        return point;
+      }
+      //
+      col++;
+      if(col >= columns_) {
+        col = 0;
+        row++;
+      }
+    }
+    if(bounds.contains(pt)) {
+      return this;
+    }
+    return null;
+  }
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("PointCollectionKey: setVisible()");
+    }
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+//      if(Debug.EVENT) {
+//        System.out.println("PointCollectionKey: " + evt);
+//        System.out.println("         " + evt.getPropertyName());
+//      }
+    modified("PointCollectionKey: propertyChange(" +
+       evt.getSource().toString() + "[" +
+       evt.getPropertyName() + "]" + ")");
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PolarGraph.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PolarGraph.java
new file mode 100755
index 0000000..ba5c6e2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/PolarGraph.java
@@ -0,0 +1,53 @@
+/*
+ * $Id: PolarGraph.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import java.awt.Graphics;
+import java.awt.Point;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Description of Class PolarGraph
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.x
+ */
+public class PolarGraph extends Graph implements Cloneable {
+  public PolarGraph() {
+  }
+  public Graph copy() {
+    PolarGraph newGraph;
+    try {
+      newGraph = (PolarGraph)clone();
+    } catch (CloneNotSupportedException e) {
+      newGraph = new PolarGraph();
+    }
+    return (Graph)newGraph;
+  }
+  void draw(Graphics g) {
+    throw new MethodNotImplementedError();
+  }
+  public Object getObjectAt(Point pt) {
+    throw new MethodNotImplementedError();
+  }
+  public SGTData getDataAt(Point pt) {
+    throw new MethodNotImplementedError();
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+  }
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/README.txt b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/README.txt
new file mode 100755
index 0000000..f7c64b6
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/README.txt
@@ -0,0 +1,7 @@
+This directory contains the scientific graphics toolkit (sgt).
+The sgt is jdk1.2 compatible.
+
+Thanks to:
+
+Laurent Beigbeder for development of LogAxis and LogTransform. (2003-02-26)
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt
new file mode 100755
index 0000000..091b58c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.0.txt
@@ -0,0 +1,158 @@
+              Notes for Scientific Graphics Toolkit (sgt)
+                           version 2.0
+                        February 12, 2001
+
+$Id: RELEASE-NOTES-2.0.txt,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+
+The major incompatability is the package name changes.  The root package
+gov.noaa.noaaserver has been changed to gov.noaa.pmel.  This was done
+to reflect the organization of origin rather than the project
+responsible for the toolkits inception.  The
+gov.noaa.noaaserver.sgt.datamodel package was renamed to the shorted
+gov.noaa.pmel.sgt.dm, since all the packages were renamed anyway.
+
+Packages gov.noaa.pmel.sgt.contour, gov.noaa.pmel.sgt.swing, and
+gov.noaa.pmel.sgt.swing.prop added.  These packages were added to
+support contouring, swing, and attribute editing with swing dialogs.
+The swing components replace and extend the awt classes which have
+been deprecated.  The current development plan for sgt includes
+removing the deprecated classes from sgt.
+
+Package gov.noaa.pmel.sgt.demo older awt classes moved to
+gov.noaa.pmel.sgt.demo.awt.  These classes were moved out of demo to
+prelude the dropping of support for awt.
+
+Packages gov.noaa.pmel.sgt.awt and gov.noaa.pmel.sgt.util have been
+deprecated.  These packages contain classes based on awt whose
+functionality has been superceeded by classes in
+gov.noaa.pmel.sgt.swing and gov.noaa.pmel.sgt.swing.prop.
+
+NOTE: 
+
+Package gov.noaa.pmel.sgt  (formerly gov.noaa.noaaserver.sgt)
+
+New Interfaces:
+    AbstractPane
+    ContourLevelAccess
+    IndexedColor
+    LabelDrawer
+    Moveable
+    TransformAccess
+    TransformColor
+
+New Classes:
+    CLIndexedColorMap
+    CLTransformColorMap
+    ContourLineAttribute
+    DefaultContourLineAttribute
+    IndexedColorMap
+    JPane
+    LabelDrawer1
+    LabelDrawer2
+    LayerStack
+    PlotMark
+    PointCollectionKey
+    TransformColorMap
+
+New Exception:
+    DataNotFoundException
+
+Classes moved to gov.noaa.pmel.util:
+    GeoDate
+    Point2D
+    Range
+    Range2D
+    Rectangle2D
+    TimePoint
+    TimeRange
+    IllegalTimeValueException
+
+Package gov.noaa.pmel.sgt.dm  (formerly gov.noaa.noaaserver.sgt.datamodel)
+
+New Classes:
+    PointCollection
+
+
+Package gov.noaa.pmel.sgt.awt  (formerly gov.noaa.noaaserver.sgt.awt)
+    Entire package deprecated support of awt will be removed after
+    version 2.0. See gov.noaa.pmel.sgt.swing for replacement classes.
+
+Package gov.noaa.pmel.sgt.contour
+    Contour and ContourLine support contouring in sgt.  These classes
+    used by GridCartesianRenderer.  The classes were designed so that
+    the ContourLine would be accessible by the user application.
+    Labeling is handled such that labels can be added or removed after
+    the contour line has been generated.
+
+Package gov.noaa.pmel.sgt.demo  (formerly gov.noaa.noaaserver.sgt.demo)
+
+New Classes: (These classes all use swing)
+    JGridDemo
+    JLayoutDemo
+    JPointDemo
+    JProfileDemo
+    JRealTimeDemo
+    JTimeSeriesDemo
+    PseudoRealTimeData
+    TAOMap
+
+Classes moved to gov.noaa.pmel.sgt.demo.awt
+    GridDemo
+    LayoutDemo
+    PointDemo
+    ProfileDemo
+    TimeSeriesDemo
+
+
+Package gov.noaa.pmel.sgt.util  (formerly gov.noaa.noaaserver.sgt.util)
+    Package deprecated.  Support for awt will be removed after version
+    2.0.  See gov.noaa.pmel.sgt.swing.prop for replacement utility
+    classes.
+
+    JClassTree moved to gov.noaa.pmel.sgt.swing and Units moved to
+    gov.noaa.pmel.util 
+
+Utility classes in package gov.noaa.pmel.util
+
+New classes:
+    Domain
+    Point2D.Float
+    SoTDomain
+    SoTPoint
+    SoTRange
+    SoTRange.Double
+    SoTRange.GeoDate
+    SoTValue
+    SoTValue.Double
+    SoTValue.GeoDate
+
+The SoT classes were introduced to make creating Time/Space neutral
+applications easier.  The SoT classes are used by the Transform and
+Axis classes.
+
+JDK 1.1.8 compatability.  
+
+The following classes will not compile using a jdk 1.1.8 compiler.
+
+   JPane   (imports java.awt.print.*, java.awt.Graphics2D)
+   LabelDrawer2  (depends on Java2D)
+   JGraphicLayout (extends JPane)
+   JPlotLayout (extends JPane)
+   JLineProfileLayout (extends JPane, deprecated)
+
+   All the demonstration applications in gov.noaa.pmel.sgt.demo use
+   JPane.
+
+   The following ..swing.prop classes refrence JPane
+   GridAttributeDialog
+   LogoDialog
+   PointAttributeDialog
+   SGLabelDialog
+   SpaceAxisDialog
+   TimeAxisDialog
+
+While these classes won't compile using jdk1.1.8, if compiled with a
+Java 2 compiler they will run under jdk1.1.8 if you don't print.  The
+swing classes haven't been tested under the jdk1.1.8 swing
+implementation. 
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt
new file mode 100755
index 0000000..69d6e21
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-2.1.txt
@@ -0,0 +1,68 @@
+	    Scientific Graphics Toolkit (sgt) Version 2.1  
+			    Release Notes
+
+$Id: RELEASE-NOTES-2.1.txt,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+
+Introduction:
+-------------
+
+This document describes the changes in the Scientific Graphics Toolkit
+from version 2.0 to 2.1. 
+
+Bug reports, comments, and suggestions can be sent to
+dwd at pmel.noaa.gov or sgt at epic.noaa.gov.
+
+New Features:
+-------------
+
+Two major new features have been added to SGT since its last
+release. Both features require Java2D, which is available in JDK
+version 1.2 and newer.
+
+Vectors. The datatype SGTVector has been implemented and the
+    VectorAttribute, VectorKey, VectorCartesianRenderer, and
+    VectorAttributeDialog classes have been added to support vector
+    drawing.  The VectorAttribute class enables users to customize
+    vector head attributes (e.g. scale, min and max head size), color,
+    line attributes (width, cap and miter style), and optionally
+    placing a plot mark at the vector origin.  See the javadoc for
+    more information.
+
+    JPlotLayout has been expanded to include support for the
+    SGTVector datatype.
+
+Stroke lines.  Stroke lines, where the width, dash properties, cap and
+    miter styles, are all selectable have been added.  Line and
+    contour plotting now make use of the new stroke lines.
+
+Line key title.  To better support dynamic changes in data a SGLabel
+    can be specified to describe a data object in a LineKey,
+    PointCollectionKey, and VectorKey.  This feature was added so that
+    the key could be automatically updated when the data changed.
+
+GridAttributeDialog, LineAttributeDialog, PointAttributeDialog, and
+    VectorAttributeDialog now allow multiple JPanes to be registered.
+    This enables the dialog to notifiy both the main graphic JPane and
+    a JPane that contains a key that attribute changes have occured.
+
+Bug Fixes and Improvements:
+---------------------------
+
+A bug that required a Graphics object to be available before
+setBatch(false) could be called has been fixed. This feature uses the
+new init() method that is available in Pane and JPane.  The init()
+method is called with the Pane or JPane first becomes visible,
+initializing those features that require a Graphics object reference. 
+
+Several bugs have been fixed in JPlotLayout, relating to LineKey
+placement, and using the new init() method.
+
+Known Issues This Release:
+--------------------------
+
+GridAttributeDialog is still not complete.  It presently only works
+with an IndexedColorMap.
+
+Java2D is required for the new Stroke lines and Vector graphics to
+work.
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt
new file mode 100755
index 0000000..c797baf
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/RELEASE-NOTES-3.0.txt
@@ -0,0 +1,509 @@
+	    Scientific Graphics Toolkit (sgt) Version 3.0
+                      SGT Beans Initial Release
+			    Release Notes
+
+$Id: RELEASE-NOTES-3.0.txt,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+
+Introduction:
+-------------
+
+This document describes the changes in the Scientific Graphics Toolkit
+from version 2.1 to 3.0 and introduces the first release of SGT Beans.
+
+Bug reports, comments, and suggestions can be sent to
+Donald.W.Denbo at noaa.gov, sgt at epic.noaa.gov or preferrably reported 
+using the Mantis system at http://heron.pmel.noaa.gov:8082/mantis. 
+
+New Features:
+-------------
+
+The biggest new feature is the initial delivery of SGT Beans. The
+three main beans Page, PanelModel, and DataModel can be used to
+produce graphics more easily. These beans also enable a user to more
+easily change the layout of existing graphics. [I will be making a
+tutorial available in about 2 months.] 
+
+New classes have been added to support graphical annotation.  And a
+new GeoDateArray class has been added to improve performance.
+
+Bug Fixes:
+----------
+
+To many to list.  The major fixes include using repaint() internally
+to make the drawing more robust. Problems with placing multiple JPanes
+in a single JFrame have been addressed and printing has been updated
+to work after the above bug fixes :-).  
+
+Known Existing Problems:
+------------------------
+
+SGT Beans require jdk 1.4.  This requirement is because I use
+XMLEncoder to serialize SGT Beans.
+
+The JRealTimeDemo demonstrates a problem that occurs when SGT is
+forced to redraw too rapidly.  On Solaris, the JPanel goes blank until
+the repainting is done.
+
+Printing SGT Beans with titled borders cause the graphic to be shifted
+down but not rescaled.  The result is the border overplot on the
+graphic.
+
+The Page SGT Bean doesn't account for the extra space a pixel
+rendering requires, causing the pixels to overlap the axes.
+
+Future Features:
+---------------
+
+Presently SGT Beans don't use a LayoutManager to position Panels on
+the Page.  I will be developing the interface and visual customization
+classes necessary to support SpringLayout. Eventually :-(.
+
+Deprecated Classes:
+------------------
+
+The following classes are now deprecated and will be removed at some
+future sgt release.
+
+gov.noaa.pmel.sgt.Pane -- use gov.noaa.pmel.sgt.JPane
+gov.noaa.pmel.sgt.swing.JLineProfileLayout -- use gov.noaa.pmel.sgt.swing.JPlotLayout
+
+in gov.noaa.pmel.util:
+
+SoTRange.GeoDate -- use SoTRange.Time
+SoTValue.GeoDate -- use SoTValue.Time
+TimePoint -- use SoTPoint
+TimeRange -- use SoTRange
+
+New Packages:
+-------------
+
+gov.noaa.pmel.sgt.beans
+
+New Classes:
+------------
+For details see the JavaDoc.
+
+gov.noaa.pmel.sgt
+	AnnotationCartesianRenderer
+	AttributeChangeEvent
+	DataKey
+	LayerControl
+	NegativeLogException
+
+gov.noaa.pmel.sgt.demo
+	JLogLogDemo
+	BeanDemo
+
+gov.noaa.pmel.sgt.dm
+	Annotation
+	Annote
+	SGT3DVector
+
+gov.noaa.pmel.sgt.swing.prop
+	ColorDialog
+	ColorEntryPanel
+	RulerDialog
+
+gov.noaa.pmel.swing
+	FocusableSwatch
+	MRJUtil
+	Swatch
+	SwatchGroup
+	ThreeDotsButton
+	ThreeDotsIcon
+
+gov.noaa.pmel.util
+	EPICSystem
+	GeoDateArray
+	SimpleFileFilter
+
+New Methods and Constructors:
+-----------------------------
+For details see the JavaDoc.
+
+gov.noaa.pmel.sgt
+	AbstractPane 
+	  new fields
+            DEFAULT_SCALE
+	    TO_FIT
+	    SHRINK_TO_FIT
+	  new methods
+	    Object[] getObjectsAt(int x,int y),
+	    Object[] getObjectsAt(Point pt)
+	    Point getZoomStart()
+	    void setMouseEventsEnabled(boolean en)
+	    boolean isMouseEventsEnabled()
+	    void setPageScaleMode(int mode)
+	    int getPageScaleMode()
+
+	Attribute
+	  new methods
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	Axis	    
+          new methods
+	    void setLineColor(Color color)
+	    Color getLineColor()
+
+	AxisTransform
+	  new constructors
+	    AxisTransform(double p1, double p2, long t1, long t2)
+	  new methods
+	    double getTransP(long t)
+	    long getLongTimeTransU(double p)
+
+	CLIndexedColorMap
+	  new methods
+	    Color getColorByIndex(int indx)
+
+	CartesianGraph
+	  new methods
+	    void setClip(long tmin, long tmax, double min, double max)
+	    double getXUtoD2(double u)
+	    double getYUtoD2(double u)
+	    double getXUtoP(long t)
+	    double getYUtoP(long t)
+	    int getXUtoD(long t)
+	    int getYUtoD(long t)
+	    double getXUtoD2(GeoDate t)
+	    double getYUtoD2(GeoDate t)
+	    double getXUtoD2(long t)
+	    double getYUtoD2(long t)
+	    int getXUtoD(SoTValue val)
+	    int getYUtoD(SoTValue val)
+	    double getXUtoD2(SoTValue val)
+	    double getYUtoD2(SoTValue val)
+	    double getXUtoP(SoTValue val)
+	    double getYUtoP(SoTValue val)
+	    SoTValue getXPtoSoT(double p)
+	    SoTValue getYPtoSoT(double p)
+	    long getXPtoLongTime(double p)
+	    long getYPtoLongTime(double p)
+	    SoTPoint getPtoU(Point2D.Double loc)
+	    SGTData getDataAt(Point pt)
+
+	CartesianRenderer
+	  new methdos
+	    SGTData getDataAt(int x, int y)
+	    SGTData getDataAt(Point pt)
+
+	ColorKey
+	  Fixed vertical orientation.
+	  new constructor
+	    ColorKey(Point2D.Double pt, Dimension2D size, int valign, int halign)
+	  new methods
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+	    void setColumns(int col)
+	    void setLineLengthP(double len)
+
+	ColorMap
+	  new methods
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	Graph
+	  new methods
+	    SGTData getDataAt(Point pt)
+
+	GridAttribute
+	  new methods
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	GridCartesianRenderer
+	  new methdos
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	IndexedColor
+	  new methods
+	    Color getColorByIndex(int index)
+
+	IndexedColorMap
+	  new methods
+	    Color getColorByIndex(int index)
+
+	JPane
+	  new methods
+	    String getVersion()
+	    Point getZoomStart()
+	    Object[] getObjectsAt(int x, int y)
+	    Object[] getObjectsAt(Point pt)
+	    void setMouseEventsEnabled(boolean enable)
+	    boolean isMouseEventsEnabled()
+	    void setPageScaleMode(int mode)
+	    int getPageScaleMode()
+
+	Layer
+	  new methods
+	    double getXPtoD2(double xp)
+	    double getYPtoD2(double yp)
+	    LayerChild findChild(String id)
+	    Iterator childIterator()
+	    LayerChild[] getChildren()
+	    Object[] getObjectsAt(int x, int y, boolean check)
+
+	LayerContainer - unimplemented
+
+	LayerStack - unimplemented
+
+	LineAttribute
+	  new methods
+	    boolean  equals(Object obj)
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	LineCartesianRenderer
+	  new methods
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	LineKey
+	  new methods
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+
+	LinearTransform
+	  new methods
+	    double getTransP(long t)
+	    long  getLongTimeTransU(double p)
+
+	LogAxis - new implementation
+
+	LogTransform - new implementation
+
+	Pane
+	  mew methods
+	    String getVersion()
+	    Point getZoomStart()
+	    Object[] getObjectsAt(int x, int y)
+	    Object[] getObjectsAt(point pt)
+	    void setMouseEventsEnabled(boolean enable)
+	    boolean isMouseEventsEnabled()
+	    void setPageScaleMode(int mode)
+	    int getPageScaleMode()
+
+	PaneProxy
+	  new methods
+	    String getVersion()
+	    Object[] getObjectsAt(int x, int y)
+	    void setMouseEventsEnabled(boolean enable)
+	    boolean isMouseEventsEnabled()
+
+	PointAttribute
+	  new methods
+	    boolean equals(Object obj)
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	PointCartesianRenderer
+	  new methods
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	PointCollectionKey
+	  new methods
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+
+	Ruler
+	  new methods
+	    int getLabelInterval()
+	    void setLabelInterval(int interval)
+	    int getSignificantDigits()
+	    void setSignificantDigist(int sig)
+	    String getLabelFormat()
+	    void setLabelFormat(String format)
+	    Color getLabelColor()
+	    void setLabelColor(Color color)
+	    Color getLineColor()
+	    void setLineColor(Color color)
+
+	SGLabel
+	  new methods
+	    boolean equals(Object obj)
+
+	VectorAttribute
+	  new methods
+	    void setId(String id)
+	    String getId()
+	    void setBatch(boolean batch)
+	    void setBatch(boolean batch, boolean local)
+	    boolean isBatch()
+
+	VectorCartesianRenderer
+	  new methods
+	    SGTData getDataAt(Point pt) - unimplemented
+
+	VectorKey
+	  new methods
+	    void setLineLengthP(double len)
+	    void addGraph(CartesianRenderer rend, SGLabel label)
+
+gov.noaa.pmel.sgt.beans
+	all new package
+
+gov.noaa.pmel.sgt.contour
+
+gov.noaa.pmel.sgt.demo
+
+gov.noaa.pmel.sgt.dm
+	SGTGrid
+	  new methods
+	    GeoDateArray getGeoDateArray()
+	    GeoDateArray getGeoDateArrayEdges()
+
+	SGTLine
+	  new methods
+	    GeoDateArray getGeoDateArray()
+
+	SGTPoint
+	  new methods
+	    long getLongTime()
+
+	SGTTuple
+
+	SGTVector
+
+	SimpleGrid
+	  new methods
+	    GeoDateArray getGeoDateArray()
+	    GeoDateArray getGeoDateArrayEdges()
+	    void setTimeEdges(GeoDateArray tarray)
+	    void setTimeArray(GeoDateArray tarray)
+
+	SimpleLine
+	  new constructor
+	    SimpleLine(GeoDateArray tloc, double[] yloc, String title)
+	    SimpleLine(double[] xloc, GeoDateArray tloc, String title)
+	  new methods
+	    GeoDateArray getGeoDateArray()
+	    void setTimeArray(GeodDateArray tarray)
+
+	SimplePoint
+	  new constructor
+	    SimplePoint(SoTPoint loc, String title)
+	  new methods
+	    long getLongTime()
+	    void setTime(GeoDate date)
+	    void setTime(long t)
+
+	SimpleTuple
+	  new methods
+	    void setXArray(GeoDateArray tArray)
+	    void setYArray(GeoDateArray tArray)
+	    GeoDateArray getGeoDateArray()
+
+gov.noaa.pmel.sgt.swing
+	Draggable
+	  new method
+	    void setLocation(Point loc, boolean fireEvent)
+
+	JGraphicLayout
+	  new methods
+	    Attribute findAttribute(String id)
+	    void setAllClip(long tmin, long tmax, double min, double max)
+
+	JPlotLayout
+	  new methods
+	    SoTDomain getGraphDomain()
+
+	UserIcon
+	  new methods
+	    SoTPoint getLocationU()
+	    void setLocationUNoVeto(SoTPoint loc)
+	    void setLocationU(SoTPoint loc)
+
+	ValueIcon
+	  new methods
+	    SoTPoint getLocationU()
+	    void setLocationUNoVeto(SoTPoint loc)
+	    void setLocationU(SoTPoint loc)
+
+	ValueIconFormat
+	  new methods
+	    void setTimeFormat(String tfrmt)
+	    String format(SoTPoint pt)
+
+gov.noaa.pmel.sgt.swing.prop
+
+gov.noaa.pmel.swing
+	SelectTimeDialog
+	  new method
+	    void setRange(long min, long max)
+
+gov.noaa.pmel.util
+	Domain
+	  new constructors
+	    Domain(Range2D xRange, Range2D yrange, boolean xRev, boolean yRev)
+	    Domain(TimeRange tRange, Range2D yRange, boolean xRev, boolean yRev)
+	    Domain(Range2D xRange, TimeRange tRange, boolean xRev, boolean yRev)
+	  new methods
+	    void setYReversed(boolean rev)
+	    boolean isYReversed()
+	    void setXReversed(boolean rev)
+	    boolean isXReversed()
+
+	Point2D
+	  new methods
+	    boolean equals(Object obj)
+	    Point2D copy()
+
+	Rectangle2D
+	  new subclass
+  	    Rectangle2D.Float
+	  new methods
+	    void setWidth(double w)
+	    double getWidth()
+	    void setHeight(double h)
+	    double getHeight()
+	    void setX(double x)
+	    double getX()
+	    void setY(double y)
+	    double getY()
+	    Rectangle2D copy()
+
+	SoTDomain
+	  new constructor
+	    SoTDomain(SoTRange xRange, SoTRange yRange, boolean xRev, boolean yRev)
+	  new methods
+	    SoTPoint getCenter()
+	    void setXReversed(boolean rev)
+	    boolean isXReversed()
+	    void setYReversed(boolean rev)
+	    boolean isYReversed()
+
+	SoTPoint
+	  new constructors
+	    SoTPoint(double x, long y)
+	    SoTPoint(long x, double y)
+	  new methods
+	    void setX(SoTValue x)
+	    void setY(SoTValue y)
+	    void add(SoTPoint point)
+	    SoTPoint copy()
+
+	SoTRange
+	  new subclass
+	    SoTRange.Time
+
+	SoTValue
+	  new sublcass
+	    SoTValue.Time
+	  new methods
+	    void add(SoTValue val)
+	    long getLongTime()
+	    GeoDate getGeoDate()
+
+	TimeRange
+	  new constructor
+	    TimeRange(long start, long end, long delta)
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Ruler.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Ruler.java
new file mode 100755
index 0000000..ba298f9
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Ruler.java
@@ -0,0 +1,748 @@
+/*
+ * $Id: Ruler.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Font;
+import java.awt.Color;
+// jdk1.2
+//import java.awt.geom.Rectangle2D;
+//import java.awt.geom.Point2D;
+
+/**
+ * Description of Class Ruler
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ */
+public class Ruler implements Cloneable, LayerChild {
+  private String ident_;
+/** @directed */
+  private Layer layer_;
+  private int orient_;
+  //
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean visible_;
+    /**@label title
+     * @link aggregationByValue */
+    private SGLabel title_ = null;
+  private String labelFormat_ = "";
+  protected Range2D uRange_;
+//  protected Point2D.Double uLocation_;
+  protected Rectangle2D.Double pBounds_;
+  protected int numSmallTics_ = 0;
+  protected double largeTicHeight_ = 0.1;
+  protected double smallTicHeight_ = 0.05;
+  protected int ticPosition_ = NEGATIVE_SIDE;
+  protected int labelPosition_ = NEGATIVE_SIDE;
+  protected int labelInterval_ = 2;
+  protected Font labelFont_ = new Font("Helvetica", Font.ITALIC, 10);
+  protected Color labelColor_ = Color.black;
+  protected Color lineColor_ = Color.black;
+  //  protected double labelHeight_ = 0.15;
+  protected double labelHeight_ = 0.20;
+  protected int sigDigits_ = 2;
+  /**
+   * Orient Key horizontally.
+   */
+  public static final int HORIZONTAL = 1;
+  /**
+   * Orient Key vertically.
+   */
+  public static final int VERTICAL = 2;
+  /**
+   * Place the label and/or tic on the positive side of the axis.
+   * The right side of VERTICAL axes and the top of HORIZONTAL axes.
+   */
+  public static final int POSITIVE_SIDE = 0;
+  /**
+   * Place the label and/or tic on the negative side of the axis.
+   * The left side of VERTICAL axes and the bottom of HORIZONTAL axes.
+   */
+  public static final int NEGATIVE_SIDE = 1;
+  /**
+   * Do not draw a label and/or tic.
+   */
+  public static final int NO_LABEL = 2;
+  /**
+   * Draw the tics on both sides of the axes.
+   */
+  public static final int BOTH_SIDES = 2;
+  //
+  static final double TIC_GAP = 0.05;
+  static final double TIC_RATIO = 1.3;
+  static final double LABEL_RATIO = 1.3;
+  protected void drawXTic(Graphics g,double xp,double yp,double ticHeight) {
+    int x0, y0, y1;
+    double yp0, yp1;
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      yp0 = yp + ticHeight;
+    } else {
+      yp0 = yp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      yp1 = yp - ticHeight;
+    } else {
+      yp1 = yp;
+    }
+    x0 = layer_.getXPtoD(xp);
+    y0 = layer_.getYPtoD(yp0);
+    y1 = layer_.getYPtoD(yp1);
+    g.drawLine(x0, y0, x0, y1);
+  }
+  //
+  protected void drawYTic(Graphics g,double xp,double yp,double ticHeight) {
+    int x0, x1, y0;
+    double xp0, xp1;
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      xp0 = xp + ticHeight;
+    } else {
+      xp0 = xp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      xp1 = xp - ticHeight;
+    } else {
+      xp1 = xp;
+    }
+    y0 = layer_.getYPtoD(yp);
+    x0 = layer_.getXPtoD(xp0);
+    x1 = layer_.getXPtoD(xp1);
+    g.drawLine(x0, y0, x1, y0);
+  }
+  //
+  protected void drawSmallXTics(Graphics g,double xu,double xtest,double del,double yp) {
+    int x0, y0, y1, i;
+    double yp0, yp1, smdel, xt;
+    if(numSmallTics_ <= 0) return;
+    //        yp = graph_.getYUtoP(yu);
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      yp0 = yp + smallTicHeight_;
+    } else {
+      yp0 = yp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      yp1 = yp - smallTicHeight_;
+    } else {
+      yp1 = yp;
+    }
+    y0 = layer_.getYPtoD(yp0);
+    y1 = layer_.getYPtoD(yp1);
+    smdel = del/(numSmallTics_ + 1);
+    for(i=0; i <= numSmallTics_; i++) {
+      xt = xu + smdel*i;
+      if((xtest - xt)/del >= 0) {
+        x0 = layer_.getXPtoD(xt);
+        g.drawLine(x0, y0, x0, y1);
+      }
+    }
+  }
+  //
+  protected void drawSmallYTics(Graphics g,double xp,double yu,double ytest,double del) {
+    int x0, x1, y0, i;
+    double xp0, xp1, smdel, yt;
+    if(numSmallTics_ <= 0) return;
+    //        xp = graph_.getXUtoP(xu);
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      xp0 = xp + smallTicHeight_;
+    } else {
+      xp0 = xp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      xp1 = xp - smallTicHeight_;
+    } else {
+      xp1 = xp;
+    }
+    x0 = layer_.getXPtoD(xp0);
+    x1 = layer_.getXPtoD(xp1);
+    smdel = del/(numSmallTics_ + 1);
+    for(i=0; i <= numSmallTics_; i++) {
+      yt = yu + smdel*i;
+      if((ytest - yt)/del >= 0) {
+        y0 = layer_.getYPtoD(yt);
+        g.drawLine(x0, y0, x1, y0);
+      }
+    }
+  }
+  /**
+   * Default constructor for Ruler.
+   */
+  public Ruler() {
+    this("");
+}
+  /**
+   * Constructor for Ruler. Sets the ruler identifier and initializes
+   * the defaults. Default values are:
+   *
+   * <PRE>
+   *   numberSmallTics = 0
+   *   largeTicHeightP = 0.1
+   *   smallTicHeightP = 0.05
+   *       ticPosition = NEGATIVE_SIDE
+   *     labelPosition = NEGATIVE_SIDE
+   *     labelInterval = 2
+   *         labelFont = Font("Helvetica", Font.ITALIC, 10);
+   *      labelHeightP = 0.15
+   * significantDigits = 2;
+   *       labelFormat = ""
+   *             title = null
+   *       orientation = HORIZONTAL
+   *                Id = ""
+   * </PRE>
+   *
+   * @param id axis identification
+   */
+  public Ruler(String ident) {
+    ident_ = ident;
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+  }
+  public LayerChild copy() {
+    Ruler newRuler;
+    try {
+      newRuler = (Ruler)clone();
+    } catch (CloneNotSupportedException e) {
+      newRuler = new Ruler();
+    }
+    return (LayerChild)newRuler;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  /**
+   * Set the large tic height in physical units.
+   *
+   * @param lthgt large tic height.
+   */
+  public void setLargeTicHeightP(double lthgt) {
+    if(largeTicHeight_ != lthgt) {
+      largeTicHeight_ = lthgt;
+      modified("Ruler: setLargeTicHeightP()");
+    }
+  }
+  /**
+   * Get the large tic height.
+   *
+   * @return large tic height in physcial units.
+   */
+  public double getLargeTicHeightP() {
+    return largeTicHeight_;
+  }
+  /**
+   * Set the number of small tics between large tics.
+   *
+   * @param nstic number of small tics.
+   */
+  public void setNumberSmallTics(int nstic) {
+    if(numSmallTics_ != nstic) {
+      numSmallTics_ = nstic;
+      modified("Ruler: setNumberSmallTics()");
+    }
+  }
+  /**
+   * Get the number of small tics between large tics.
+   *
+   * @return number of small tics.
+   */
+  public int getNumberSmallTics() {
+    return numSmallTics_;
+  }
+  /**
+   * Set the small tic height in physical units.
+   *
+   * @param sthgt small tic height.
+   */
+  public void setSmallTicHeightP(double sthgt) {
+    if(smallTicHeight_ != sthgt) {
+      smallTicHeight_ = sthgt;
+      modified("Ruler: setSmallTicHeightP()");
+    }
+  }
+  /**
+   * Get the small tic height.
+   *
+   * @return small tic height in physical units.
+   */
+  public double getSmallTicHeightP() {
+    return smallTicHeight_;
+  }
+  /**
+   * Set the tic position. Tic position can be POSITIVE_SIDE, NEGATIVE_SIDE,
+   * or BOTH_SIDES.
+   *
+   * @param tpos tic position
+   */
+  public void setTicPosition(int tpos) {
+    if(ticPosition_ != tpos) {
+      ticPosition_ = tpos;
+      modified("Ruler: setTicPosition()");
+    }
+  }
+  /**
+   * Get the tic position.
+   *
+   * @return tic position
+   */
+  public int getTicPosition() {
+    return ticPosition_;
+  }
+  /**
+   * Set the label position. Label position can be POSITIVE_SIDE, NEGATIVE_SIDE,
+   * and NO_LABEL.
+   *
+   * @param lapb label position.
+   */
+  public void setLabelPosition(int labp) {
+    if(labelPosition_ != labp) {
+      labelPosition_ = labp;
+      modified("Ruler: setLabelPosition()");
+    }
+  }
+  /**
+   * Get the label position.
+   *
+   * @return label position
+   */
+  public int getLabelPosition() {
+    return labelPosition_;
+  }
+  /**
+   * Set the label font.
+   *
+   * @param fnt label font
+   */
+  public void setLabelFont(Font fnt) {
+    if(labelFont_ == null || !labelFont_.equals(fnt)) {
+      labelFont_ = fnt;
+      modified("Ruler: setLabelFont()");
+    }
+  }
+  /**
+   * Get the label font.
+   *
+   * @return label font
+   */
+  public Font getLabelFont() {
+    return labelFont_;
+  }
+  /**
+   * Set the label height in physical units.
+   *
+   * @param lhgt label height.
+   */
+  public void setLabelHeightP(double lhgt) {
+    if(labelHeight_ != lhgt) {
+      labelHeight_ = lhgt;
+      modified("Ruler: setLabelHeightP()");
+    }
+  }
+  /**
+   * Get the label height.
+   *
+   * @return label height
+   */
+  public double getLabelHeightP() {
+    return labelHeight_;
+  }
+  /**
+   * Set the axis identifier.
+   *
+   * @param id identifier
+   **/
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Set the axis identifier.
+   *
+   * @param id identifier
+   **/
+  public String getId() {
+    return ident_;
+  }
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  public Layer getLayer() {
+    return layer_;
+  }
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+  public void modified(String mess) {
+    //    if(Debug.EVENT) System.out.println("Ruler: modified()");
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Change the user unit range of <code>Ruler</code>
+   */
+  public void setRangeU(Range2D range) {
+    if(uRange_ == null || !uRange_.equals(range)) {
+      uRange_ = range;
+      modified("Ruler: setRangeU()");
+    }
+  }
+  public Range2D getRangeU() {
+    return uRange_;
+  }
+  /**
+   * Set the bounding box for the axis in physical units.
+   *
+   * @return bounding box
+   */
+  public void setBoundsP(Rectangle2D.Double bounds) {
+    if(pBounds_ == null || !pBounds_.equals(bounds)) {
+      if(Debug.EVENT)
+  System.out.println("pBounds_ = " +
+         pBounds_ +
+         ", bounds = " +
+         bounds);
+      pBounds_ = bounds;
+      modified("Ruler: setBoundsP()");
+    }
+  }
+  /**
+   * Get the bounding box for the axis in physical units.
+   *
+   * @return bounding box
+   */
+  public Rectangle2D.Double getBoundsP() {
+    return pBounds_;
+  }
+  /**
+   * Set ruler orientation.  Allowed orientations are HORIZONATAL and
+   * VERTICAL.
+   *
+   * @param or orientation
+   */
+  public void setOrientation(int orient) {
+    if(orient_ != orient) {
+      orient_ = orient;
+      modified("Ruler: setOrientation()");
+    }
+  }
+  /**
+   * Get axis orientation
+   *
+   * @return axis orientation
+   */
+  public int getOrientation() {
+    return orient_;
+  }
+  /**
+   * Set the axis title.
+   *
+   * @param title axis title
+   */
+  public void setTitle(SGLabel title) {
+    if(title_ == null || !title_.equals(title)) {
+      title_ = title;
+      modified("Ruler: setTitle()");
+    }
+  }
+  /**
+   * Get the axis title.
+   *
+   * @return axis title
+   */
+  public SGLabel getTitle() {
+    return title_;
+  }
+  /**
+   * Get the bounding box for the axis in device units.
+   *
+   * @return bounding box
+   */
+  public Rectangle getBounds() {
+    int x, y, height, width;
+    x = layer_.getXPtoD(pBounds_.x);
+    y = layer_.getYPtoD(pBounds_.y);
+    width = layer_.getXPtoD(pBounds_.x + pBounds_.width) - x;
+    height = layer_.getYPtoD(pBounds_.y - pBounds_.height) - y;
+    if(orient_ == HORIZONTAL) {
+      y = y - height;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  public void setBounds(int x, int y, int width, int height) {
+  }
+  public void draw(Graphics g) {
+    int xloc, yloc, xend, yend;
+    int istop, i;
+    double xt, yt, dir, x, y, xp, yp;
+    double xtitle, ytitle;
+    Format format;
+    String labelText = null;
+    AxisTransform sTrans;
+    if(!visible_) return;
+    if(title_ != null) title_.setLayer(layer_);
+    //
+    if(lineColor_ == null) {
+      g.setColor(layer_.getPane().getComponent().getForeground());
+    } else {
+      g.setColor(lineColor_);
+    }
+    //
+    if(labelFormat_.length() <= 0) {
+      format = new Format(Format.computeFormat(uRange_.start, uRange_.end, sigDigits_));
+    } else {
+      format = new Format(labelFormat_);
+    }
+    if(orient_ == HORIZONTAL) {
+      sTrans = new LinearTransform(pBounds_.x, pBounds_.x + pBounds_.width,
+                                   uRange_.start, uRange_.end);
+      yloc = layer_.getYPtoD(pBounds_.y);
+      yp = pBounds_.y;
+      xloc = layer_.getXPtoD(sTrans.getTransP(uRange_.start));
+      xend = layer_.getXPtoD(sTrans.getTransP(uRange_.end));
+      g.drawLine(xloc, yloc, xend, yloc);
+      //
+      dir = uRange_.delta > 0? 1.0: -1.0;
+      xt = (int)((uRange_.start/uRange_.delta + (dir*uRange_.start > 0? 1.0: -1.0)*0.00001))*uRange_.delta;
+      if(dir*xt < dir*uRange_.start) xt += uRange_.delta;
+      istop = (int)((uRange_.end - xt)/uRange_.delta + 0.00001);
+      x = xt;
+      xp = sTrans.getTransP(x);
+      drawSmallXTics(g, x, uRange_.start, -uRange_.delta, yp);
+      drawXTic(g, xp, yp, largeTicHeight_);
+      for(i=0; i < istop; i++) {
+        drawSmallXTics(g, x, uRange_.end, uRange_.delta, yp);
+        x += uRange_.delta;
+        xp = sTrans.getTransP(x);
+        drawXTic(g, xp, yp, largeTicHeight_);
+      }
+      drawSmallXTics(g, x, uRange_.end, uRange_.delta, yp);
+      //
+      if(labelInterval_ <= 0 || labelPosition_ == NO_LABEL) return;
+      //
+      SGLabel label;
+      int vertalign;
+      if(labelPosition_ == POSITIVE_SIDE) {
+        vertalign = SGLabel.BOTTOM;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          yt = yp + TIC_RATIO*largeTicHeight_;
+        } else {
+          yt = yp + TIC_GAP;
+        }
+        ytitle = yt + LABEL_RATIO*labelHeight_;
+      } else {
+        vertalign = SGLabel.TOP;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          yt = yp - TIC_RATIO*largeTicHeight_;
+        } else {
+          yt = yp - TIC_GAP;
+        }
+        ytitle = yt - LABEL_RATIO*labelHeight_;
+      }
+      if(dir*uRange_.start <= 0 && dir*uRange_.end >= 0) {
+        x = ((int)(uRange_.start/(uRange_.delta*labelInterval_) -
+                   0.00001))*uRange_.delta*labelInterval_;
+      } else {
+        x = xt;
+      }
+      istop = (int)((uRange_.end - x)/(uRange_.delta*labelInterval_) + 0.00001);
+      for(i=0; i <= istop; i++) {
+        xt = sTrans.getTransP(x);
+        labelText = format.form(x);
+        label = new SGLabel("coordinate", labelText, new Point2D.Double(xt, yt));
+        label.setFont(labelFont_);
+        label.setHeightP(labelHeight_);
+        label.setAlign(vertalign, SGLabel.CENTER);
+        label.setLayer(layer_);
+        label.setColor(labelColor_);
+        try {
+          label.draw(g);
+        } catch (LayerNotFoundException e) {}
+        x = x + uRange_.delta*labelInterval_;
+      }
+      if(title_ != null) {
+        xtitle = (uRange_.end + uRange_.start)*0.5;
+        yt = ytitle;
+        xt = sTrans.getTransP(xtitle);
+        title_.setLocationP(new Point2D.Double(xt, yt));
+        title_.setAlign(vertalign, SGLabel.CENTER);
+        title_.setOrientation(SGLabel.HORIZONTAL);
+        try {
+          title_.draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+    } else {                               // orientation is vertical
+      sTrans = new LinearTransform(pBounds_.y, pBounds_.y + pBounds_.height,
+                                   uRange_.start, uRange_.end);
+      xloc = layer_.getXPtoD(pBounds_.x);
+      xp = pBounds_.x;
+      yloc = layer_.getYPtoD(sTrans.getTransP(uRange_.start));
+      yend = layer_.getYPtoD(sTrans.getTransP(uRange_.end));
+      g.drawLine(xloc, yloc, xloc, yend);
+      //
+      dir = uRange_.delta > 0? 1.0: -1.0;
+      yt = (int)((uRange_.start/uRange_.delta) + (dir*uRange_.start > 0? 1.0: -1.0)*0.00001)*uRange_.delta;
+      if(dir*yt < dir*uRange_.start) yt += uRange_.delta;
+      istop = (int)((uRange_.end - yt)/uRange_.delta + 0.00001);
+      y = yt;
+      yp = sTrans.getTransP(y);
+      drawSmallYTics(g, xp, y, uRange_.start, -uRange_.delta);
+      drawYTic(g, xp, yp, largeTicHeight_);
+      for(i=0; i < istop; i++) {
+        drawSmallYTics(g, xp, y, uRange_.end, uRange_.delta);
+        y += uRange_.delta;
+        yp = sTrans.getTransP(y);
+        drawYTic(g, xp, yp, largeTicHeight_);
+      }
+      drawSmallYTics(g, xp, y, uRange_.end, uRange_.delta);
+      //
+      if(labelInterval_ <= 0 || labelPosition_ == NO_LABEL) return;
+      //
+      SGLabel label;
+      int vertalign;
+      if(labelPosition_ == NEGATIVE_SIDE) {
+        vertalign = SGLabel.BOTTOM;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xt = xp - TIC_RATIO*largeTicHeight_;
+        } else {
+          xt = xp - TIC_GAP;
+        }
+        xtitle = xt - LABEL_RATIO*labelHeight_;
+      } else {
+        vertalign = SGLabel.TOP;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xt = xp + TIC_RATIO*largeTicHeight_;
+        } else {
+          xt = xp + TIC_GAP;
+        }
+        xtitle = xt + LABEL_RATIO*labelHeight_;
+      }
+      if(dir*uRange_.start <= 0 && dir*uRange_.end >= 0) {
+        y = ((int)(uRange_.start/(uRange_.delta*labelInterval_) - 0.00001))*uRange_.delta*labelInterval_;
+      } else {
+        y = yt;
+      }
+      istop = (int)((uRange_.end - y)/(uRange_.delta*labelInterval_) + 0.00001);
+      for(i=0; i <= istop; i++) {
+        yt = sTrans.getTransP(y);
+        labelText = format.form(y);
+        label = new SGLabel("coordinate", labelText, new Point2D.Double(xt, yt));
+        label.setAlign(vertalign, SGLabel.CENTER);
+        label.setOrientation(SGLabel.VERTICAL);
+        label.setFont(labelFont_);
+        label.setHeightP(labelHeight_);
+        label.setLayer(layer_);
+        try {
+          label.draw(g);
+        } catch (LayerNotFoundException e) {}
+        y = y + uRange_.delta*labelInterval_;
+      }
+      if(title_ != null) {
+        ytitle = (uRange_.end + uRange_.start)*0.5;
+        yt = sTrans.getTransP(ytitle);
+        xt = xtitle;
+        title_.setLocationP(new Point2D.Double(xt, yt));
+        title_.setAlign(vertalign, SGLabel.CENTER);
+        title_.setOrientation(SGLabel.VERTICAL);
+        try {
+          title_.draw(g);
+        } catch (LayerNotFoundException e) {}
+      }
+    }
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("Ruler: setVisible()");
+    }
+  }
+  /**
+   * @since 3.0
+   */
+  public int getLabelInterval() {
+    return labelInterval_;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setLabelInterval(int labelInterval) {
+    labelInterval_ = labelInterval;
+  }
+  /**
+   * @since 3.0
+   */
+  public int getSignificantDigits() {
+    return sigDigits_;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setSignificantDigits(int sigDigits) {
+    sigDigits_ = sigDigits;
+  }
+  /**
+   * @since 3.0
+   */
+  public String getLabelFormat() {
+    return labelFormat_;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setLabelFormat(String labelFormat) {
+    labelFormat_ = labelFormat;
+  }
+  /**
+   * @since 3.0
+   */
+  public Color getLabelColor() {
+    return labelColor_;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setLabelColor(Color labelColor) {
+    labelColor_ = labelColor;
+  }
+  /**
+   * @since 3.0
+   */
+  public Color getLineColor() {
+    return lineColor_;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setLineColor(Color lineColor) {
+    lineColor_ = lineColor;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SGException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SGException.java
new file mode 100755
index 0000000..4d1f11e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SGException.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: SGException.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+/**
+ * Base class for gov.noaa.pmel.sgt exceptions.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ */
+public class SGException extends java.lang.Exception {
+  public SGException() {
+    super();
+  }
+  public SGException(String s) {
+    super(s);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SGLabel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SGLabel.java
new file mode 100755
index 0000000..ba86de4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SGLabel.java
@@ -0,0 +1,577 @@
+/*
+ * $Id: SGLabel.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+
+import  java.awt.image.PixelGrabber;
+import  java.awt.image.MemoryImageSource;
+import  java.awt.image.ColorModel;
+import  java.awt.image.ImageObserver;
+import  java.awt.*;
+import  java.beans.*;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.Serializable;
+// jdk1.2
+//import  java.awt.geom.Rectangle2D;
+//import  java.awt.geom.Point2D;
+
+/**
+ * Draws text on a layer object. SGLabel uses the drawString() method
+ * of the Graphics class.  SGLabel allows the user to align the text
+ * both vertically (TOP, MIDDLE, and BOTTOM) and horizontally
+ * (LEFT, MIDDLE, and RIGHT).  The font, color, and height (in user
+ * coordinates) can also be specified.  The SGLabel can also be drawn
+ * either HORIZONTAL or VERTICAL.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ * @see java.awt.Graphics
+ */
+public class SGLabel implements Cloneable, LayerChild, Moveable, Serializable {
+  private String ident_;
+  private LabelDrawer proxy_;
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean moveable_;
+  private transient PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  /**
+   * Align top of label
+   **/
+  public static final int TOP = 0;
+  /**
+   * Align middle of label
+   **/
+  public static final int MIDDLE = 1;
+  /**
+   * Align bottom of label
+   **/
+  public static final int BOTTOM = 2;
+  /**
+   * Align left of label
+   **/
+  public static final int LEFT = 0;
+  /**
+   * Align center of label
+   **/
+  public static final int CENTER = 1;
+  /**
+   * Align right of label
+   **/
+  public static final int RIGHT = 2;
+  /**
+   * Orient label horizontal
+   */
+  public static final int HORIZONTAL = 0;
+  /**
+   * Orient label vertical
+   */
+  public static final int VERTICAL = 1;
+  /**
+   * Orient label at an angle
+   * @since 2.0
+   */
+  public static final int ANGLE = 2;
+
+  static {
+    try {
+      BeanInfo info = Introspector.getBeanInfo(SGLabel.class);
+      PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+      for(int i=0; i < descriptors.length; i++) {
+        PropertyDescriptor pd = descriptors[i];
+        if(pd.getName().equals("layer")) {
+          pd.setValue("transient", Boolean.TRUE);
+        }
+      }
+    } catch (IntrospectionException ie) {
+      ie.printStackTrace();
+    }
+  }
+  /**
+   * Quick SGLabel constructor. Default alignment of BOTTOM and LEFT are
+   * used.  Default height is 0.12.
+   *
+   * @param id Label identifier
+   * @param lbl String to be plotted.
+   */
+  public SGLabel(String id,String lbl,Point2D.Double loc) {
+    this(id, lbl, 0.12, loc, BOTTOM, LEFT);
+  }
+  /**
+   * Long SGLabel constructor.
+   *
+   * @param id Label identifier
+   * @param lbl String to be plotted
+   * @param hgt String height in physical units
+   * @param loc Location to plot label in physical units
+   * @param valign Vertical alignment
+   * @param halign Horizontal alignment
+   **/
+  public SGLabel(String id, String lbl, double hgt,
+                 Point2D.Double loc, int valign, int halign) {
+    if(PaneProxy.Java2D) {
+      proxy_ = new LabelDrawer2(lbl, hgt, loc, valign, halign);
+    } else {
+      proxy_ = new LabelDrawer1(lbl, hgt, loc, valign, halign);
+    }
+    ident_ = id;
+    proxy_.setOrientation(HORIZONTAL);
+    proxy_.setAngle(0.0);
+    proxy_.setColor(null);
+    proxy_.setFont(new Font("Helvetica", Font.PLAIN, 14));
+    selected_ = false;
+    selectable_ = true;
+    proxy_.setVisible(true);
+    moveable_ = true;
+  }
+//    private void bindStringDrawer() {
+//      Class cl;
+//      boolean java2d = true;
+//      try {
+//        cl = Class.forName("java.awt.Graphics2D");
+//      } catch (ClassNotFoundException e) {
+//        java2d = false;
+//      }
+//      if(java2d) {
+//        stringDraw_ = new StringDrawer2();
+//      } else {
+//        stringDraw_ = new StringDrawer1();
+//      }
+//    }
+
+  public LayerChild copy() {
+    SGLabel newLabel;
+    try {
+      newLabel = (SGLabel)clone();
+    } catch (CloneNotSupportedException e) {
+      newLabel = new SGLabel(ident_,
+                             proxy_.getText(),
+                             proxy_.getHeightP(),
+                             proxy_.getLocationP(),
+                             proxy_.getVAlign(),
+                             proxy_.getHAlign());
+      newLabel.setColor(proxy_.getColor());
+      newLabel.setFont(proxy_.getFont());
+      if(proxy_.getOrientation() == ANGLE) {
+        newLabel.setAngle(proxy_.getAngle());
+      } else {
+        newLabel.setOrientation(proxy_.getOrientation());
+      }
+    }
+    return newLabel;
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean equals(Object obj) {
+    if(obj == null || !(obj instanceof SGLabel)) return false;
+    SGLabel sg = (SGLabel)obj;
+/*    boolean t1 = !ident_.equals(sg.getId());
+    boolean t2 = !proxy_.getText().equals(sg.getText());
+    boolean t3 = proxy_.getHeightP() != sg.getHeightP();
+    boolean t4 = !proxy_.getLocationP().equals(sg.getLocationP());
+    boolean t5 = proxy_.getVAlign() != sg.getVAlign();
+    boolean t6 = proxy_.getHAlign() != sg.getHAlign();
+    boolean t7 = (proxy_.getColor() != null) && !proxy_.getColor().equals(sg.getColor());
+    boolean t8 = (proxy_.getFont() != null) && !proxy_.getFont().equals(sg.getFont());
+    boolean t9 = proxy_.getOrientation() != sg.getOrientation();
+    if(t1 || t2 || t3 || t4 || t5 || t6 || t7 || t8 || t9) return false; */
+    if((!ident_.equals(sg.getId())) ||
+       (!proxy_.getText().equals(sg.getText())) ||
+       (proxy_.getHeightP() != sg.getHeightP()) ||
+       (!proxy_.getLocationP().equals(sg.getLocationP())) ||
+       (proxy_.getVAlign() != sg.getVAlign()) ||
+       (proxy_.getHAlign() != sg.getHAlign()) ||
+       (proxy_.getColor() != null) && (!proxy_.getColor().equals(sg.getColor())) ||
+       (proxy_.getFont() != null) && (!proxy_.getFont().equals(sg.getFont())) ||
+       (proxy_.getOrientation() != sg.getOrientation())) return false;
+    if(proxy_.getOrientation() == ANGLE) {
+      if(proxy_.getAngle() != sg.getAngle()) return false;
+    }
+    return true;
+  }
+
+  public void draw(Graphics g) throws LayerNotFoundException  {
+    proxy_.draw(g);
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  /**
+   * Set the color.
+   *
+   * @param color The color of the label.
+   * @see java.awt.Color
+   **/
+  public void setColor(Color color) {
+    Color clr = proxy_.getColor();
+    if(clr == null || !clr.equals(color)) {
+      proxy_.setColor(color);
+      modified("SGLabel: setColor()");
+    }
+  }
+  /**
+   * Get the color.
+   *
+   * @return The current color of the label.
+   **/
+  public Color getColor() {
+    return proxy_.getColor();
+  }
+  /**
+   * Set the font.
+   *
+   * @param fnt The Font to use to draw the label.
+   * @see java.awt.Font
+   **/
+  public void setFont(Font fnt) {
+    Font font = proxy_.getFont();
+    if(font == null || !font.equals(fnt)) {
+      proxy_.setFont(fnt);
+      modified("SGLabel: setFont()");
+    }
+  }
+  /**
+   * Get the font.
+   *
+   * @return The current font for the label.
+   **/
+  public Font getFont() {
+    return proxy_.getFont();
+  }
+  /**
+   * Set the height of the label in physical coordinates.
+   *
+   * @param hgt The label height.
+   **/
+  public void setHeightP(double hgt) {
+    double height = proxy_.getHeightP();
+    if(height != hgt) {
+      proxy_.setHeightP(hgt);
+      modified("SGLabel: setHeightP()");
+    }
+  }
+  /**
+   * Get the label height in physical coordinates.
+   *
+   * @return The label height.
+   **/
+  public double getHeightP() {
+    return proxy_.getHeightP();
+  }
+  /**
+   * Set the vertical and horizontal alignment.  The vertical alignment
+   * can be TOP, MIDDLE, or BOTTOM, and the horizontal alignment
+   * LEFT, CENTER, or RIGHT.
+   *
+   * @param vert The vertical alignment.
+   * @param horz The horizontal alignment.
+   **/
+  public void setAlign(int vert,int horz) {
+    int valign = proxy_.getVAlign();
+    int halign = proxy_.getHAlign();
+    if(valign != vert || halign != horz) {
+      proxy_.setVAlign(vert);
+      proxy_.setHAlign(horz);
+      modified("SGLabel: setAlign()");
+    }
+  }
+  /**
+   * Set the horizontal alignment. The alignment can be LEFT, CENTER,
+   * or RIGHT.
+   *
+   * @param horz The horizontal alignment.
+   **/
+  public void setHAlign(int horz) {
+    int halign = proxy_.getHAlign();
+    if(halign != horz) {
+      proxy_.setHAlign(horz);
+      modified("SGLabeo: setHAlign()");
+    }
+  }
+  /**
+   * Get the horizontal alignment.
+   *
+   * @return the horizontal alignment.
+   **/
+  public int getHAlign() {
+    return  proxy_.getHAlign();
+  }
+  /**
+   * Set the vertical alignment. The alignment can be TOP, MIDDLE,
+   * or BOTTOM.
+   *
+   * @param vert The vertical alignment.
+   **/
+  public void setVAlign(int vert) {
+    int valign = proxy_.getVAlign();
+    if(valign != vert) {
+      proxy_.setVAlign(vert);
+      modified("SGLabel: setVAlign()");
+    }
+  }
+  /**
+   * Get the vertical alignment.
+   *
+   * @return the vertical alignment.
+   **/
+  public int getVAlign() {
+    return proxy_.getVAlign();
+  }
+  /**
+   * Set the label reference location in physcial coordinates.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @param loc physical location of label
+   **/
+  public void setLocationP(Point2D.Double loc) {
+    Point2D.Double porigin = proxy_.getLocationP();
+    if(porigin == null || !porigin.equals(loc)) {
+      Point2D.Double temp = porigin;
+      porigin = loc;
+      proxy_.setLocationP(loc);
+      if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+      changes_.firePropertyChange("location",
+                                  temp,
+                                  porigin);
+      modified("SGLabel: setLocationP()");
+    }
+  }
+  /**
+   * Get the label reference location in physcial coordinates.
+   *
+   * @return the labels position.
+   **/
+  public Point2D.Double getLocationP() {
+    return proxy_.getLocationP();
+  }
+  /**
+   * Set the orientation. The orientation can be HORIZONTAL or
+   * VERTICAL.
+   *
+   * @param orient The orientation.
+   **/
+  public void setOrientation(int orient) {
+    int or = proxy_.getOrientation();
+    if(or != orient) {
+      proxy_.setOrientation(orient);
+      modified("SGLabel: setOrientation()");
+    }
+  }
+  /**
+   * Get the origentation.
+   *
+   * @return the orientation
+   **/
+  public int getOrientation() {
+    return proxy_.getOrientation();
+  }
+  /**
+   * Draw label at arbitrary rotation.  Warning: Rotated labels are
+   * not drawn very well when using JDK1.1. For best results use
+   * JDK1.2 or newer.
+   * @since 2.0
+   */
+  public void setAngle(double angle) {
+    proxy_.setAngle(angle);
+  }
+  /**
+   * Get label drawing angle.
+   * @since 2.0
+   */
+  public double getAngle() {
+    return proxy_.getAngle();
+  }
+  /**
+   *
+   **/
+  public void setLayer(Layer l) {
+    proxy_.setLayer(l);
+  }
+  /**
+   * Get the layer.
+   *
+   * @return the layer object.
+   **/
+  public Layer getLayer() {
+    return proxy_.getLayer();
+  }
+
+  public AbstractPane getPane() {
+    return proxy_.getLayer().getPane();
+  }
+
+  public void modified(String text) {
+    Layer layer = proxy_.getLayer();
+    if(layer != null) {
+      layer.modified(text);
+    }
+  }
+
+  /**
+   * Get the label text.
+   *
+   * @return the label text
+   **/
+  public String getText() {
+    return proxy_.getText();
+  }
+  /**
+   * Set the label text.
+   *
+   * @param lbl the label text
+   **/
+  public void setText(String lbl) {
+    String label = proxy_.getText();
+    if(label == null || !label.equals(lbl)) {
+      proxy_.setText(lbl);
+      modified("SGLabel: setText()");
+    }
+  }
+  /**
+   * Get the label identifier.
+   *
+   * @return the identifier
+   **/
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set the label identifier.
+   *
+   * @param  id the label identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get the label height in device coordinates.
+   *
+   * @return the label height
+   **/
+  public int getHeight() {
+    return 0;
+  }
+  /**
+   * Get the label position in device coordinates.
+   *
+   * @return the label position
+   **/
+  public Point getLocation() {
+    return proxy_.getLocation();
+  }
+  /**
+   * Set the label reference location in pixel coordinates.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @param loc physical location of label
+   **/
+  public void setLocation(Point loc) {
+    Point dloc = proxy_.getLocation();
+    if(dloc.x != loc.x || dloc.y != loc.y) {
+      Point temp = new Point(dloc.x, dloc.y);
+      proxy_.setLocation(loc);
+      if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+      changes_.firePropertyChange("location",
+                                  temp,
+                                  loc);
+    }
+  }
+  /**
+   * Get the label bounds in physical units.
+   *
+   * @return the label bounds
+   **/
+  public Rectangle2D.Double getBoundsP() {
+    return proxy_.getBoundsP();
+  }
+  /**
+   * Get the label bounds in device units.
+   *
+   * @return the label bounds
+   **/
+  public Rectangle getBounds() {
+    return proxy_.getBounds();
+  }
+  /**
+   * Set the label bounds in device units.
+   */
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  /**
+   * Set the label bounds in device units.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    proxy_.setBounds(x, y, width, height);
+  }
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  public boolean isVisible() {
+    return proxy_.isVisible();
+  }
+  public void setVisible(boolean visible) {
+    boolean vis = proxy_.isVisible();
+    if(vis != visible) {
+      proxy_.setVisible(visible);
+      modified("SGLabel: setVisible()");
+    }
+  }
+  public boolean isMoveable() {
+    return moveable_;
+  }
+  public void setMoveable(boolean moveable) {
+    if(moveable_ != moveable) {
+      moveable_ = moveable;
+      modified("SGLabel: setMoveable()");
+    }
+  }
+  /**
+   * Get the string width in device units.
+   * @since 2.0
+   */
+  public float getStringWidth(Graphics g) {
+    return proxy_.getStringWidth(g);
+  }
+  /**
+   * Get the string height in device units.
+   * @since 2.0
+   */
+  public float getStringHeight(Graphics g) {
+    return proxy_.getStringHeight(g);
+  }
+
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Selectable.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Selectable.java
new file mode 100755
index 0000000..a28ad96
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Selectable.java
@@ -0,0 +1,66 @@
+/*
+ * $Id: Selectable.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt;
+
+import java.awt.Rectangle;
+ 
+/**
+ * Interface indicates that object can be selected with a mouse click.
+ * To be moveable the object must implement the <code>Moveable</code>
+ * interface.
+ * 
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ * @see Moveable
+ */
+public interface Selectable {
+  /**
+   * Sets the selected property.
+   * 
+   * @param sel true if selected, false if not.
+   */
+  public void setSelected(boolean sel);
+  /**
+   * Returns true if the object's selected property is set.
+   * 
+   * @return true if selected, false if not.
+   */
+  public boolean isSelected();
+  /**
+   * Gets the bounding rectangle in device
+   * coordinates.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds();
+  /**
+   * Returns true if the current state is selectable.
+   *
+   * @return true if selectable
+   */
+  public boolean isSelectable();
+  /**
+   * Set the Selectable property.
+   *
+   * @param select if true object is selectable
+   */
+  public void setSelectable(boolean select);
+  /**
+   * Change the selected objects bounding rectangle
+   * in device coordinates.
+   * The object will move to the new bounding rectangle.
+   *
+   * @param bnds new bounding rectangle
+   */
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SineTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SineTransform.java
new file mode 100755
index 0000000..98330f5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SineTransform.java
@@ -0,0 +1,83 @@
+/*
+ * $Id: SineTransform.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTRange;
+
+/**
+ * Performs a sine(x) transform on a cartesian axis.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.x
+ */
+public class SineTransform extends AxisTransform implements Cloneable {
+  public SineTransform() {
+    super();
+  }
+  public SineTransform(double p1,double p2,double u1,double u2) {
+    super(p1, p2, u1, u2);
+  }
+  public SineTransform(Range2D pr,Range2D ur) {
+    super(pr, ur);
+  }
+  public SineTransform(double p1,double p2,GeoDate t1,GeoDate t2) {
+    super(p1, p2, t1, t2);
+  }
+  public SineTransform(Range2D pr,TimeRange tr) {
+    super(pr, tr);
+  }
+  public SineTransform(Range2D pr, SoTRange str) {
+    super(pr, str);
+  }
+  public AxisTransform copy() {
+    SineTransform newTransform;
+    try {
+      newTransform = (SineTransform)clone();
+    } catch (CloneNotSupportedException e) {
+      newTransform = new SineTransform();
+    }
+    return (AxisTransform)newTransform;
+  }
+  public double getTransP(double u) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransP(GeoDate t) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransP(long t) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransP(SoTValue v) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransU(double p) {
+    throw new MethodNotImplementedError();
+  }
+  public GeoDate getTimeTransU(double p) {
+    throw new MethodNotImplementedError();
+  }
+  public long getLongTimeTransU(double p) {
+    throw new MethodNotImplementedError();
+  }
+  public SoTValue getSoTTransU(double p) {
+    throw new MethodNotImplementedError();
+  }
+  void computeTransform() {
+    throw new MethodNotImplementedError();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SpaceAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SpaceAxis.java
new file mode 100755
index 0000000..616159e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/SpaceAxis.java
@@ -0,0 +1,414 @@
+/*
+ * $Id: SpaceAxis.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimePoint;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Rectangle;
+// jdk1.2
+//import java.awt.geom.Point2D;
+
+/**
+ * Abstract base class for axes whose user coordinates are double values.
+ * The following is an example of using a {@link PlainAxis}.
+ * <A NAME="example"><!-- --></A>
+ * <pre>
+ * import gov.noaa.pmel.sgt.PlainAxis;
+ * import gov.noaa.pmel.sgt.LinearTransform;
+ * import gov.noaa.pmel.sgt.Graph;
+ * ...
+ * Graph graph;
+ * PlainAxis xbot, xtop;
+ * LinearTransform xt;
+ * Point2D.Double lowerleft = new Point2D.Double(10.0, 100.0);
+ * ...
+ * //
+ * // Instatiate xt and set it as the x transform.
+ * //
+ * xt = new LinearTransform(0.75, 3.5, 10.0, 100.0);
+ * graph.setXTransform(xt);
+ * ...
+ * //
+ * // Instatiate xbot and set its range, delta, and
+ * // location.  Set xbot the numberSmallTics property
+ * // for xbot.
+ * //
+ * xbot = new PlainAxis("Bottom Axis");
+ * xbot.setRangeU(new Range2D(10.0, 100.0));
+ * xbot.setDeltaU(20.0);
+ * xbot.setNumberSmallTics(4);
+ * xbot.setLocationU(lowerleft);
+ * //
+ * // Create title for xbot.
+ * //
+ * Font xbfont = new Font("Helvetica", Font.ITALIC, 14);
+ * xbot.setLabelFont(xbfont);
+ * SGLabel xtitle = new SGLabel("xaxis title",
+ *                              "Test X-Axis Title",
+ *                              new Point2D.Double(0.0, 0.0));
+ * Font xtfont = new Font("Helvetica", Font.PLAIN, 14);
+ * xtitle.setFont(xtfont);
+ * xtitle.setHeightP(0.2);
+ * xbot.setTitle(xtitle);
+ * graph.setXAxis(xbot);
+ * ...
+ * //
+ * // Instatiate xtop and set its range, delta, and
+ * // location.  Set xtop properties on ticPosition and
+ * // labelPosition.
+ * //
+ * xtop = new PlainAxis("Top Axis");
+ * xtop.setRangeU(new Range2D(10.0, 100.0));
+ * xtop.setDeltaU(20.0);
+ * xtop.setNumberSmallTics(0);
+ * xtop.setLocationU(new Point2D.Double(10.0, 300.0));
+ * xtop.setLabelFont(xbfont);
+ * xtop.setTicPosition(Axis.POSITIVE_SIDE);
+ * xtop.setLabelPosition(Axis.NO_LABEL);
+ * graph.setXAxis(xtop);
+ * ...
+ * //
+ * // Register the x transform and the top x axis with the bottom x axis.
+ * // By registering xt and xtop, any updates to the user or physical range
+ * // of xbot will be automatically performed on xt and xtop.
+ * //
+ * xbot.register(xt);
+ * xbot.register(xtop);
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ * @see Axis
+ * @see PlainAxis
+ * @see TimeAxis
+**/
+public abstract class SpaceAxis extends Axis {
+  protected Range2D uRange_;
+  protected Point2D.Double uLocation_;
+  protected TimePoint tLocation_;
+  static final double TIC_GAP = 0.05;
+  static final double TIC_RATIO = 1.3;
+  static final double LABEL_RATIO = 1.3;
+  //
+  protected void updateRegisteredTransforms() {
+    if(!registeredTransforms_.isEmpty()) {
+      AxisTransform trns;
+      for(Enumeration it = registeredTransforms_.elements();
+          it.hasMoreElements();) {
+        trns = (AxisTransform)it.nextElement();
+        trns.setRangeP(pRange_);
+        trns.setRangeU(uRange_);
+      }
+    }
+  }
+  //
+  protected void updateRegisteredAxes() {
+    if(!registeredAxes_.isEmpty()) {
+      SpaceAxis ax;
+      for(Enumeration it = registeredAxes_.elements();
+          it.hasMoreElements();) {
+        ax = (SpaceAxis)it.nextElement();
+        ax.setRangeU(uRange_);
+        ax.setRangeP(pRange_);
+      }
+    }
+  }
+  //
+  protected void drawSmallXTics(Graphics g,double xu,double xtest,double del,double yp) {
+    int x0, y0, y1, i;
+    double yp0, yp1, smdel, xt;
+    if(numSmallTics_ <= 0) return;
+    //        yp = graph_.getYUtoP(yu);
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      yp0 = yp + smallTicHeight_;
+    } else {
+      yp0 = yp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      yp1 = yp - smallTicHeight_;
+    } else {
+      yp1 = yp;
+    }
+    y0 = graph_.getLayer().getYPtoD(yp0);
+    y1 = graph_.getLayer().getYPtoD(yp1);
+    smdel = del/(numSmallTics_ + 1);
+    for(i=0; i <= numSmallTics_; i++) {
+      xt = xu + smdel*i;
+      if((xtest - xt)/del >= 0) {
+        x0 = graph_.getXUtoD(xt);
+        g.drawLine(x0, y0, x0, y1);
+      }
+    }
+  }
+  //
+  protected void drawSmallYTics(Graphics g,double xp,double yu,double ytest,double del) {
+    int x0, x1, y0, i;
+    double xp0, xp1, smdel, yt;
+    if(numSmallTics_ <= 0) return;
+    //        xp = graph_.getXUtoP(xu);
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+      xp0 = xp + smallTicHeight_;
+    } else {
+      xp0 = xp;
+    }
+    if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+      xp1 = xp - smallTicHeight_;
+    } else {
+      xp1 = xp;
+    }
+    x0 = graph_.getLayer().getXPtoD(xp0);
+    x1 = graph_.getLayer().getXPtoD(xp1);
+    smdel = del/(numSmallTics_ + 1);
+    for(i=0; i <= numSmallTics_; i++) {
+      yt = yu + smdel*i;
+      if((ytest - yt)/del >= 0) {
+        y0 = graph_.getYUtoD(yt);
+        g.drawLine(x0, y0, x1, y0);
+      }
+    }
+  }
+  /**
+   * Default constructor for SpaceAxis.
+   **/
+  public SpaceAxis() {
+    this("");
+  }
+  /**
+   * Constructor for Axis. Sets the axis identifier and initializes
+   * the defaults.
+   *
+   * @param id axis identification
+   **/
+  public SpaceAxis(String id) {
+    super(id);
+    space_ = true;
+    numSmallTics_ = 0;
+  }
+  /**
+   * Set the number of significant digits in the label.  This is
+   * used if a format is not specified.
+   *
+   * @param nsig number of significant digits
+   **/
+  public void setSignificantDigits(int nsig) {
+    if(sigDigits_ != nsig) {
+      sigDigits_ = nsig;
+      modified("SpaceAxis: setSignificantDigits()");
+    }
+  }
+  /**
+   * Get the number of significant digits in the label.
+   *
+   * @return number of significant digits.
+   **/
+  public int getSignificantDigits() {
+    return sigDigits_;
+  }
+  /**
+   * Set the label interval.
+   *
+   * @param lint label interval.
+   **/
+  public void setLabelInterval(int lint) {
+    if(labelInterval_ != lint) {
+      labelInterval_ = lint;
+      modified("SpaceAxis: setLabelInterval()");
+    }
+  }
+  /**
+   * Get the label interval.
+   *
+   * @return label interval
+   **/
+  public int getLabelInterval() {
+    return labelInterval_;
+  }
+  /**
+   * Set the label format. Format should be in the sprintf style.
+   * The formating uses the Format class in the Core Java book.
+   * A null or empty string will cause formating to use the significant
+   * digits.
+   *
+   * <PRE>
+   * Gary Cornell and Cay S. Horstmann, Core Java (Book/CD-ROM)
+   * Published By SunSoft Press/Prentice-Hall
+   * Copyright (C) 1996 Sun Microsystems Inc.
+   * All Rights Reserved. ISBN 0-13-596891-7
+   * </PRE>
+   *
+   * @param frmt label format.
+   **/
+  public void setLabelFormat(String frmt) {
+    if(labelFormat_ == null || !labelFormat_.equals(frmt)) {
+      if(frmt == null) {
+        labelFormat_ = "";
+      } else {
+        labelFormat_ = frmt;
+      }
+      modified("SpaceAxis: setLabelFormat()");
+    }
+  }
+  /**
+   * Get the label format.
+   *
+   * @return label format
+   **/
+  public String getLabelFormat() {
+    return labelFormat_;
+  }
+  /**
+   * Set the user range to draw the axis.  Registered Axes and AxisTransforms
+   * will be updated.
+   *
+   * @param ur range in user coordinates
+   **/
+  public void setRangeU(Range2D ur) {
+    if(uRange_ == null || !uRange_.equals(ur)) {
+      uRange_ = ur;
+      updateRegisteredAxes();
+      updateRegisteredTransforms();
+      modified("SpaceAxis: setRangeU()");
+    }
+  }
+  public void setRangeU(SoTRange ur) {
+    setRangeU(new Range2D(((SoTRange.Double)ur).start,
+                          ((SoTRange.Double)ur).end,
+                          ((SoTRange.Double)ur).delta));
+  }
+  /**
+   * Get the user range.
+   *
+   * @return range in user coordinates
+   **/
+  public Range2D getRangeU() {
+    return uRange_;
+  }
+  public SoTRange getSoTRangeU() {
+    return new SoTRange.Double(uRange_);
+  }
+  /**
+   * Set the increment between large tics.
+   *
+   * @param delta increment in user coordinates
+   **/
+  public void setDeltaU(double delta) {
+    if(uRange_.delta != delta) {
+      uRange_.delta = delta;
+      modified("SpaceAxis: setDeltaU()");
+    }
+  }
+  /**
+   * Get the increment between large tics.
+   *
+   * @return user coordinate increment
+   **/
+  public double getDeltaU() {
+    return uRange_.delta;
+  }
+  /**
+   * Set the origin in user units of the axis.
+   *
+   * @param upt origin in user units
+   **/
+  public void setLocationU(TimePoint uptt) {
+    if(tLocation_ == null || !tLocation_.equals(uptt)) {
+      tLocation_ = uptt;
+      uLocation_ = null;
+      modified("SpaceAxis: setLocationU(TimePoint)");
+    }
+  }
+  /**
+   * Set the origin in user units of the axis.
+   *
+   * @param upt origin in user units
+   **/
+  public void setLocationU(Point2D.Double upt) {
+    if(uLocation_ == null || !uLocation_.equals(upt)) {
+      uLocation_ = upt;
+      tLocation_ = null;
+      modified("SpaceAxis: setLocationU(Point2D)");
+    }
+  }
+  public void setLocationU(SoTPoint upt) {
+    double x;
+    double y;
+    if(upt.isXTime() || upt.isYTime()) {
+      long t;
+      if(upt.isXTime()) {
+        t = upt.getX().getLongTime();
+        x = ((SoTValue.Double)upt.getY()).getValue();
+      } else {
+        t = upt.getY().getLongTime();
+        x = ((SoTValue.Double)upt.getX()).getValue();
+      }
+      setLocationU(new TimePoint(x, new GeoDate(t)));
+    } else {
+      x = ((SoTValue.Double)upt.getX()).getValue();
+      y = ((SoTValue.Double)upt.getY()).getValue();
+      setLocationU(new Point2D.Double(x,y));
+    }
+  }
+  /**
+   * Get the origin in user units of the axis
+   *
+   * @return origin
+   **/
+  public Point2D.Double getLocationU() {
+    return uLocation_;
+  }
+  /**
+   * Get the origin in user units of the axis
+   *
+   * @return origin
+   **/
+  public TimePoint getTimeLocationU() {
+    return tLocation_;
+  }
+  public SoTPoint getSoTLocationU() {
+    if(tLocation_ == null) {
+      return new SoTPoint(uLocation_.x, uLocation_.y);
+    } else {
+      if(orientation_ == HORIZONTAL) {
+        return new SoTPoint(tLocation_.t, tLocation_.x);
+      } else {
+        return new SoTPoint(tLocation_.x, tLocation_.t);
+      }
+    }
+  }
+  //
+  abstract void draw(Graphics g);
+  /**
+   * Get the bounding box for the axis in device units.
+   *
+   * @return bounding box
+   * @see Rectangle
+   **/
+  public abstract Rectangle getBounds();
+
+  public void modified(String mess) {
+    //    if(Debug.EVENT) System.out.println("SpaceAxis: modified()");
+    if(graph_ != null)
+      graph_.modified(mess);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StackedLayout.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StackedLayout.java
new file mode 100755
index 0000000..76ddafe
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StackedLayout.java
@@ -0,0 +1,75 @@
+/*
+ * $Id: StackedLayout.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.beans.Panel;
+import java.awt.LayoutManager;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.Component;
+import java.awt.Insets;
+
+/**
+ * <code>StackedLayout</code> works with <code>Pane</code> to
+ * position multiple <code>Layer</code>s directly over each other.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ * @see Pane#setLayout
+ * @see Layer
+ */
+public class StackedLayout implements LayoutManager {
+  public Dimension preferredLayoutSize(Container parent) {
+    synchronized (parent.getTreeLock()) {
+      return parent.getSize();
+    }
+  }
+  public Dimension minimumLayoutSize(Container parent) {
+    synchronized (parent.getTreeLock()) {
+      return parent.getSize();
+    }
+  }
+  public void layoutContainer(Container parent) {
+    synchronized (parent.getTreeLock()) {
+      JPane pane = null;
+      boolean batch = false;
+      if(parent instanceof JPane) {
+        pane = (JPane)parent;
+        batch = pane.isBatch();
+        pane.setBatch(true, "StackedLayout");
+      } else if(parent instanceof Panel) {
+        pane = ((Panel)parent).getPane();
+        batch = pane.isBatch();
+        pane.setBatch(true, "StackedLayout");
+      }
+      Insets insets = parent.getInsets();
+      Rectangle rect = parent.getBounds();
+      int ncomponents = parent.getComponentCount();
+      int x, y, w, h;
+      x = rect.x + insets.left;
+      y = rect.y + insets.top;
+      w = rect.width - (insets.left + insets.right);
+      h = rect.height - (insets.top + insets.bottom);
+      for(int i=0; i < ncomponents; i++) {
+        parent.getComponent(i).setBounds(x, y, w, h);
+      }
+      if(!batch) pane.setBatch(false, "StackedLayout");
+    }
+  }
+  public void removeLayoutComponent(Component comp) {
+  }
+  public void addLayoutComponent(String name, Component comp) {
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer.java
new file mode 100755
index 0000000..eff9149
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer.java
@@ -0,0 +1,51 @@
+/*
+ * $Id: StrokeDrawer.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.awt.*;
+
+
+/**
+ * Defines the methods that implement stroke drawing in sgt. This
+ * interface is necessary since sgt v2.0 will use Java2D functionality
+ * to draw strokes if it is available.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.1
+ */
+public interface StrokeDrawer {
+
+  public void drawHeavy(Graphics g, int[] xout, int[] yout, int size,
+                        LineAttribute attr);
+
+  public void drawDashed(Graphics g, int[] xout, int[] yout, int size,
+                         LineAttribute attr);
+
+  public void drawStroke(Graphics g, int[] xout, int[] yout, int size,
+                         LineAttribute attr);
+
+  public void drawHighlight(Graphics g, int[] xout, int[] yout, int size,
+			    LineAttribute attr);
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer1.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer1.java
new file mode 100755
index 0000000..9e419b8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer1.java
@@ -0,0 +1,69 @@
+/*
+ * $Id: StrokeDrawer1.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import  java.awt.*;
+
+/**
+ * Implements stroke drawing for JDK1.1
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.1
+ */
+public class StrokeDrawer1 implements StrokeDrawer, Cloneable {
+
+  public void drawHeavy(Graphics g, int[] xout, int[] yout, int size,
+                        LineAttribute attr) {
+    g.drawPolyline(xout, yout, size);
+  }
+
+  public void drawDashed(Graphics g, int[] xout, int[] yout, int size,
+                         LineAttribute attr) {
+    g.drawPolyline(xout, yout, size);
+  }
+
+  public void drawStroke(Graphics g, int[] xout, int[] yout, int size,
+                         LineAttribute attr) {
+    g.drawPolyline(xout, yout, size);
+  }
+
+  public void drawHighlight(Graphics g, int[] x, int[] y, int size,
+			    LineAttribute attr) {
+    int[] xr = new int[size];
+    int[] yr = new int[size];
+    int i;
+    Color col = attr.getColor();
+    Color rev = new Color(255 - col.getRed(),
+                          255 - col.getGreen(),
+                          255 - col.getBlue());
+    //
+    // simple hightlight draw with pixel displacements in reverse
+    // color
+    //
+    g.setPaintMode();
+    for(i=0; i < size; i++) {
+      xr[i] = x[i] + 1;
+      yr[i] = y[i] + 1;
+    }
+    g.setColor(col);
+    g.drawPolyline(xr, yr, size);
+    for(i=0; i < size; i++) {
+      xr[i] = x[i] - 1;
+      yr[i] = y[i] - 1;
+    }
+    g.drawPolyline(xr, yr, size);
+    g.setColor(rev);
+    g.drawPolyline(x, y, size);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer2.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer2.java
new file mode 100755
index 0000000..8257ec7
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/StrokeDrawer2.java
@@ -0,0 +1,95 @@
+/*
+ * $Id: StrokeDrawer2.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+/**
+ * Implements stroke drawing using Java2D functionality.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.1
+ */
+public class StrokeDrawer2 implements StrokeDrawer, Cloneable {
+
+  public void drawHeavy(Graphics g, int[] xout, int[] yout, int size,
+                        LineAttribute attr) {
+    Graphics2D g2 = (Graphics2D)g;
+    Stroke saved = g2.getStroke();
+    BasicStroke stroke = new BasicStroke(attr.getWidth());
+    g2.setStroke(stroke);
+    g2.drawPolyline(xout, yout, size);
+    g2.setStroke(saved);
+  }
+
+  public void drawDashed(Graphics g, int[] xout, int[] yout, int size,
+                         LineAttribute attr) {
+    Graphics2D g2 = (Graphics2D)g;
+    Stroke saved = g2.getStroke();
+    float[] dashes = {4.0f, 4.0f};
+    BasicStroke stroke = new BasicStroke(1.0f,
+                                         BasicStroke.CAP_SQUARE,
+                                         BasicStroke.JOIN_MITER,
+                                         10.0f,
+                                         dashes,
+                                         0.0f);
+    g2.setStroke(stroke);
+    g2.drawPolyline(xout, yout, size);
+    g2.setStroke(saved);
+  }
+
+  public void drawStroke(Graphics g, int[] xout, int[] yout, int size,
+                         LineAttribute attr) {
+
+    Graphics2D g2 = (Graphics2D)g;
+    Stroke saved = g2.getStroke();
+    BasicStroke stroke;
+    float[] arr = attr.getDashArray();
+    if(arr == null || (arr.length <= 1)) {
+    stroke = new BasicStroke(attr.getWidth(),
+                             attr.getCapStyle(),
+                             attr.getMiterStyle(),
+                             attr.getMiterLimit());
+    } else {
+    stroke = new BasicStroke(attr.getWidth(),
+                             attr.getCapStyle(),
+                             attr.getMiterStyle(),
+                             attr.getMiterLimit(),
+                             attr.getDashArray(),
+                             attr.getDashPhase());
+    }
+    g2.setStroke(stroke);
+    g2.drawPolyline(xout, yout, size);
+    g2.setStroke(saved);
+  }
+
+  public void drawHighlight(Graphics g, int[] xout, int[] yout, int size,
+			    LineAttribute attr) {
+    Graphics2D g2 = (Graphics2D)g;
+    Stroke saved = g2.getStroke();
+    BasicStroke stroke = new BasicStroke(2.75f);
+    Color col = attr.getColor();
+    Color rev = new Color(255 - col.getRed(),
+			  255 - col.getGreen(),
+			  255 - col.getBlue());
+    g2.setColor(rev);
+    g2.setStroke(stroke);
+    g2.drawPolyline(xout, yout, size);
+    g2.setColor(col);
+    g2.setStroke(saved);
+    g2.drawPolyline(xout, yout, size);
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TableLookupTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TableLookupTransform.java
new file mode 100755
index 0000000..8b5304a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TableLookupTransform.java
@@ -0,0 +1,81 @@
+/*
+ * $Id: TableLookupTransform.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+ 
+/**
+ * Description of Class TableLookupTransform
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.x
+ */
+public class TableLookupTransform implements Cloneable, Transform {
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private double[] pvals_;
+  private double[] uvals_;
+  public TableLookupTransform() {
+  }
+  public TableLookupTransform(double p1,double p2,double u1,double u2) {
+  }
+  public TableLookupTransform(Range2D pr,Range2D ur) {
+  }
+  public TableLookupTransform(double[] p,double[] u) throws DataNotSameShapeException  {
+  }
+  public void setRangeP(Range2D pr) {
+    throw new MethodNotImplementedError();
+  }
+  public void setRangeP(double pmin,double pmax) {
+    throw new MethodNotImplementedError();
+  }
+  public Range2D getRangeP() {
+    throw new MethodNotImplementedError();
+  }
+  public void setRangeU(Range2D ur) {
+    throw new MethodNotImplementedError();
+  }
+  public void setRangeU(double umin,double umax) {
+    throw new MethodNotImplementedError();
+  }
+  public Range2D getRangeU() {
+    throw new MethodNotImplementedError();
+  }
+  public void setDoInteger(boolean si) {
+    throw new MethodNotImplementedError();
+  }
+  public boolean getDoInteger() {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransP(double u) {
+    throw new MethodNotImplementedError();
+  }
+  public double getTransU(double p) {
+    throw new MethodNotImplementedError();
+  }
+  void computeTransform() {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Add listener to changes in <code>TableLookupTransform</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    changes_.addPropertyChangeListener(listener);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TimeAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TimeAxis.java
new file mode 100755
index 0000000..a0be4d4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TimeAxis.java
@@ -0,0 +1,784 @@
+/*
+ * $Id: TimeAxis.java,v 1.1.1.2 2008/12/19 13:29:32 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.TimePoint;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Color;
+// jdk1.2
+//import java.awt.geom.Point2D;
+
+/**
+ * Base class for time axes.  A time axis is an axis whose user units
+ * are GeoDate objects.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:32 $
+ * @since 1.0
+ * @see Axis
+ */
+public class TimeAxis extends Axis implements Cloneable{
+  //
+  protected TimeRange tRange_;
+  protected TimePoint tLocation_;
+  //
+  protected String minorLabelFormat_;
+  protected int minorLabelInterval_;
+  protected String majorLabelFormat_;
+  protected int majorLabelInterval_;
+  //
+  protected double yminor_;
+  //
+  protected double ymajor_;
+  protected double xminor_;
+  protected double xmajor_;
+  protected int vertalign_;
+  //
+  /**@shapeType AggregationLink
+     @associates <b>TimeAxisStyle</b>
+     * @supplierCardinality 1
+     * @byValue */
+  protected TimeAxisStyle txt_;
+  protected int axisStyle_;
+  static final double TIC_RATIO__ = 1.3;
+  static final double TIC_GAP__ = 0.05;
+  static final double LABEL_RATIO__ = 1.0;
+  static final double MAJOR_LABEL_RATIO__ = 1.25;
+
+  static final double defaultLargeTicHeight__ = 0.1;
+  static final double defaultSmallTicHeight__ = 0.05;
+  static final int defaultTicPosition__ = Axis.NEGATIVE_SIDE;
+  static final int defaultLabelPosition__ = Axis.NEGATIVE_SIDE;
+  static final double defaultLabelHeight__ = 0.15;
+  /**
+   * Automatically select the time axis style
+   */
+  public static final int AUTO = 0;
+  /**
+   * Use the YearDecadeAxis style.
+   * <pre>
+   *   |..........|..........|..........|..........|
+   *        84         85         86         87
+   *                       1980
+   * </pre>
+   */
+  public static final int YEAR_DECADE = 1;
+  /**
+   * Use the MonthYearAxis style.
+   * <pre>
+   *   |..........|..........|..........|..........|
+   *        Mar        Apr        May       Jun
+   *                       1980
+   * </pre>
+   */
+  public static final int MONTH_YEAR = 2;
+  /**
+   * Use the DayMonthAxis style.
+   * <pre>
+   *   |..........|..........|..........|..........|
+   *        3          4          5           6
+   *                        1993-04
+   * </pre>
+   */
+  public static final int DAY_MONTH = 3;
+  /**
+   * Use the HourDayAxis style.
+   * <pre>
+   *   |..........|..........|..........|..........|
+   *   03         04         05         06         07
+   *                     1987-06-07
+   * </pre>
+   */
+  public static final int HOUR_DAY = 4;
+  /**
+   * Use the MinuteHourAxis style.
+   * <pre>
+   *   |..........|..........|..........|..........|
+   *   15         30         45         00         15
+   *                   1987-06-07 13
+   * </pre>
+   */
+  public static final int MINUTE_HOUR = 5;
+
+  private void setAuto() {
+    TimeAxisStyle newStyle = null;
+
+    GeoDate delta = tRange_.end.subtract(tRange_.start);
+    double days = ((double)Math.abs(delta.getTime()))/((double)GeoDate.MSECS_IN_DAY);
+    if(Debug.TAXIS) {
+      System.out.println("setAuto: days = " + days);
+    }
+    if(days > 1000.0) {
+      if(!(txt_ instanceof YearDecadeAxis)) {
+        newStyle = (TimeAxisStyle)new YearDecadeAxis();
+      }
+    } else if(days > 91.0) {
+      if(!(txt_ instanceof MonthYearAxis)) {
+        newStyle = (TimeAxisStyle)new MonthYearAxis();
+      }
+    } else if(days > 5.0) {
+      if(!(txt_ instanceof DayMonthAxis)) {
+        newStyle = (TimeAxisStyle)new DayMonthAxis();
+      }
+    } else if((days > 0.1666667)) {                      // 6 hours
+      if(!(txt_ instanceof HourDayAxis)) {
+        newStyle = (TimeAxisStyle)new HourDayAxis();
+      }
+    } else {
+      if(!(txt_ instanceof MinuteHourAxis)) {
+        newStyle = (TimeAxisStyle)new MinuteHourAxis();
+      }
+    }
+    if(newStyle != null) {
+      txt_ = newStyle;
+      //    } else {
+      //      return;
+    }
+    txt_.computeDefaults(delta);
+
+    minorLabelFormat_ = txt_.getDefaultMinorLabelFormat();
+    majorLabelFormat_ = txt_.getDefaultMajorLabelFormat();
+    minorLabelInterval_ = txt_.getDefaultMinorLabelInterval();
+    majorLabelInterval_ = txt_.getDefaultMajorLabelInterval();
+    numSmallTics_ = txt_.getDefaultNumSmallTics();
+//    largeTicHeight_ = txt_.getDefaultLargeTicHeight();
+//    smallTicHeight_ = txt_.getDefaultSmallTicHeight();
+//    ticPosition_ = txt_.getDefaultTicPosition();
+//    labelPosition_ = txt_.getDefaultLabelPosition();
+//    labelHeight_ = txt_.getDefaultLabelHeight();
+    if(Debug.TAXIS) {
+      System.out.println("    style, ticPosition, labelPostiion = " +
+                         txt_.toString() + ", " + ticPosition_ + ", " + labelPosition_);
+      System.out.println("    minorFormat, majorFormat, minorInterval, majorInterval = " +
+                         minorLabelFormat_ + ", " + majorLabelFormat_ + ", " +
+                         minorLabelInterval_ + ", " + majorLabelInterval_);
+      System.out.println("    smallTics, largeHgt, smallHgt, labelHgt = " +
+                         numSmallTics_ + ", " + largeTicHeight_ + ", " + smallTicHeight_ + ", " + labelHeight_);
+    }
+  }
+  protected void updateRegisteredTransforms() {
+    if(!registeredTransforms_.isEmpty()) {
+      AxisTransform trns;
+      for(Enumeration it = registeredTransforms_.elements();
+          it.hasMoreElements();) {
+        trns = (AxisTransform)it.nextElement();
+        trns.setRangeP(pRange_);
+        trns.setRangeU(tRange_);
+      }
+    }
+  }
+  //
+  protected void updateRegisteredAxes() {
+    if(!registeredAxes_.isEmpty()) {
+      TimeAxis ax;
+      for(Enumeration it = registeredAxes_.elements();
+          it.hasMoreElements();) {
+        ax = (TimeAxis)it.nextElement();
+        ax.setRangeU(tRange_);
+        ax.setRangeP(pRange_);
+      }
+    }
+  }
+  protected void setupDraw(double val) {
+    if(orientation_ == Axis.HORIZONTAL) {
+      if(labelPosition_ == POSITIVE_SIDE) {
+        vertalign_ = SGLabel.BOTTOM;
+        if(minorLabelInterval_ == 0) {
+          yminor_ = val;
+        } else if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          yminor_ = val + TIC_RATIO__*largeTicHeight_;
+        } else {
+          yminor_ = val + TIC_GAP__;
+        }
+        ymajor_ = yminor_ + LABEL_RATIO__*labelHeight_;
+      } else {
+        vertalign_ = SGLabel.TOP;
+        if(minorLabelInterval_ == 0) {
+          yminor_ = val;
+        } else if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          yminor_ = val - TIC_RATIO__*largeTicHeight_;
+        } else {
+          yminor_ = val - TIC_GAP__;
+        }
+        ymajor_ = yminor_ - LABEL_RATIO__*labelHeight_;
+      }
+    } else {
+      if(labelPosition_ == NEGATIVE_SIDE) {
+        vertalign_ = SGLabel.BOTTOM;
+        if(minorLabelInterval_ == 0) {
+          xminor_ = val;
+        } else if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xminor_ = val - TIC_RATIO__*largeTicHeight_;
+        } else {
+          xminor_ = val - TIC_GAP__;
+        }
+        xmajor_ = xminor_ - LABEL_RATIO__*labelHeight_;
+      } else {
+        vertalign_ = SGLabel.TOP;
+        if(minorLabelInterval_ == 0) {
+          xminor_ = val;
+        } else if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xminor_ = val + TIC_RATIO__*largeTicHeight_;
+        } else {
+          xminor_ = val + TIC_GAP__;
+        }
+        xmajor_ = xminor_ + LABEL_RATIO__*labelHeight_;
+      }
+    }
+  }
+  protected void drawMinorLabel(Graphics g,double val,GeoDate time) {
+    SGLabel label;
+    Color saved = g.getColor();
+    if(orientation_ == Axis.HORIZONTAL) {
+      label = new SGLabel("minor", time.toString(minorLabelFormat_),
+                          new Point2D.Double(val, yminor_));
+      label.setOrientation(SGLabel.HORIZONTAL);
+    } else {
+      label = new SGLabel("minor", time.toString(minorLabelFormat_),
+                          new Point2D.Double(xminor_, val));
+      label.setOrientation(SGLabel.VERTICAL);
+    }
+    label.setAlign(vertalign_, SGLabel.CENTER);
+    label.setFont(labelFont_);
+    label.setColor(labelColor_);
+    label.setHeightP(labelHeight_);
+    label.setLayer(graph_.getLayer());
+    try {
+      label.draw(g);
+    } catch (LayerNotFoundException e) {}
+    g.setColor(saved);
+  }
+  protected void drawMajorLabel(Graphics g,double val,GeoDate time) {
+    Color saved = g.getColor();
+    SGLabel label;
+    if(orientation_ == Axis.HORIZONTAL) {
+      label = new SGLabel("major", time.toString(majorLabelFormat_),
+                          new Point2D.Double(val, ymajor_));
+      label.setOrientation(SGLabel.HORIZONTAL);
+    } else {
+      label = new SGLabel("major", time.toString(majorLabelFormat_),
+                          new Point2D.Double(xmajor_, val));
+      label.setOrientation(SGLabel.VERTICAL);
+    }
+    label.setAlign(vertalign_, SGLabel.CENTER);
+    label.setFont(labelFont_);
+    label.setColor(labelColor_);
+    label.setHeightP(MAJOR_LABEL_RATIO__*labelHeight_);
+    label.setLayer(graph_.getLayer());
+    try {
+      label.draw(g);
+    } catch (LayerNotFoundException e) {}
+    g.setColor(saved);
+  }
+  //
+  /**
+   * Default contructor.
+   **/
+  public TimeAxis(int style) {
+    this("", style);
+  }
+  /**
+   * TimeAxis constructor.
+   *
+   * @param id axis identifier
+   **/
+  public TimeAxis(String id,int style) {
+    super(id);
+    minorLabelInterval_ = 2;
+    majorLabelInterval_ = 1;
+    numSmallTics_ = 0;
+    space_ = false;
+    axisStyle_ = style;
+    //
+    if(axisStyle_ == AUTO || axisStyle_ == MONTH_YEAR) {
+      txt_ = (TimeAxisStyle)new MonthYearAxis();
+    } else if(axisStyle_ == YEAR_DECADE) {
+      txt_ = (TimeAxisStyle)new YearDecadeAxis();
+    } else if(axisStyle_ == DAY_MONTH) {
+      txt_ = (TimeAxisStyle)new DayMonthAxis();
+    } else if(axisStyle_ == HOUR_DAY) {
+      txt_ = (TimeAxisStyle)new HourDayAxis();
+    } else {
+      txt_ = (TimeAxisStyle)new MinuteHourAxis();
+    }
+    minorLabelFormat_ = txt_.getDefaultMinorLabelFormat();
+    majorLabelFormat_ = txt_.getDefaultMajorLabelFormat();
+    minorLabelInterval_ = txt_.getDefaultMinorLabelInterval();
+    majorLabelInterval_ = txt_.getDefaultMajorLabelInterval();
+    numSmallTics_ = txt_.getDefaultNumSmallTics();
+//
+    largeTicHeight_ = defaultLargeTicHeight__;
+    smallTicHeight_ = defaultSmallTicHeight__;
+    ticPosition_ = defaultTicPosition__;
+    labelPosition_ = defaultLabelPosition__;
+    labelHeight_ = defaultLabelHeight__;
+    tRange_ = null;
+    tLocation_ = null;
+  }
+  public Axis copy() {
+    TimeAxis newAxis;
+    try {
+      newAxis = (TimeAxis)clone();
+    } catch (CloneNotSupportedException e) {
+      newAxis = new TimeAxis(getStyle());
+    }
+    //
+    // remove registered axes and transforms
+    //
+    newAxis.registeredAxes_ = new Vector(2,2);
+    newAxis.registeredTransforms_ = new Vector(2,2);
+    //
+    return newAxis;
+  }
+  /**
+   * Set the minor and major label formats.
+   *
+   * @param minor minor label format
+   * @param major major label format
+   **/
+  public void setLabelFormat(String minor,String major) {
+    if(minorLabelFormat_ == null ||
+       majorLabelFormat_ == null ||
+      !minorLabelFormat_.equals(minor) ||
+      !majorLabelFormat_.equals(major)) {
+
+      minorLabelFormat_ = minor;
+      majorLabelFormat_ = major;
+      modified("TimeAxis: setLabelFormat()");
+    }
+  }
+  /**
+   * Set the minor label format.
+   *
+   * @param minor minor label format
+   **/
+  public void setMinorLabelFormat(String minor) {
+    if(minorLabelFormat_ == null || !minorLabelFormat_.equals(minor)) {
+      minorLabelFormat_ = minor;
+      modified("TimeAxis: setMinorLabelFormat()");
+    }
+  }
+  /**
+   * Set the major label format.
+   *
+   * @param major major label format
+   **/
+  public void setMajorLabelFormat(String major) {
+    if(majorLabelFormat_ == null || !majorLabelFormat_.equals(major)) {
+      majorLabelFormat_ = major;
+      modified("TimeAxis: setMajorLabelFormat()");
+    }
+  }
+  /**
+   * Get the minor label format.
+   *
+   * @return minor label format
+   **/
+  public String getMinorLabelFormat() {
+    return minorLabelFormat_;
+  }
+  /**
+   * Get the major label format.
+   *
+   * @return major label format
+   **/
+  public String getMajorLabelFormat() {
+    return majorLabelFormat_;
+  }
+  /**
+   * Set the minor and major label intervals.
+   *
+   * @param minor minor label interval
+   * @param major major label interval
+   **/
+  public void setLabelInterval(int minor,int major) {
+    if(minorLabelInterval_ != minor || majorLabelInterval_ != major) {
+      minorLabelInterval_ = minor;
+      majorLabelInterval_ = major;
+      modified("TimeAxis: setLabelInterval()");
+    }
+  }
+  /**
+   * Set the minor label interval.
+   *
+   * @param minor minor label interval
+   **/
+  public void setMinorLabelInterval(int minor) {
+    if(minorLabelInterval_ != minor) {
+      minorLabelInterval_ = minor;
+      modified("TimeAxis: setMinorLabelInterval()");
+    }
+  }
+  /**
+   * Set the major label interval.
+   *
+   * @param major major label interval
+   **/
+  public void setMajorLabelInterval(int major) {
+    if(majorLabelInterval_ != major) {
+      majorLabelInterval_ = major;
+      modified("TimeAxis: setMajorLabelInterval()");
+    }
+  }
+  /**
+   * Get the minor label interval.
+   *
+   * @return minor label interval
+   **/
+  public int getMinorLabelInterval() {
+    return minorLabelInterval_;
+  }
+  /**
+   * Get the major label interval.
+   *
+   * @return major label interval
+   **/
+  public int getMajorLabelInterval() {
+    return majorLabelInterval_;
+  }
+  /**
+   * Set the time axis style.
+   *
+   * @param style new time axis style
+   */
+  public void setStyle(int style) {
+    if(axisStyle_ != style) {
+      axisStyle_ = style;
+      if(axisStyle_ == AUTO && tRange_ != null) {
+        setAuto();
+      }
+      modified("TimeAxis: setStyle()");
+    }
+  }
+  /**
+   * Get the time axis style.
+   *
+   * @return time axis style
+   */
+  public int getStyle() {
+    return axisStyle_;
+  }
+  /**
+   * Set the user range to draw the axis.  Registered Axes and Transforms
+   * will be updated.
+   *
+   * @param tr TimeRange of axis.
+   **/
+  public void setRangeU(TimeRange tr) {
+    if(tRange_ == null || !tRange_.equals(tr)) {
+      tRange_ = tr;
+      if(axisStyle_ == AUTO) {
+        setAuto();
+      }
+      updateRegisteredAxes();
+      updateRegisteredTransforms();
+      modified("TimeAxis: setRangeU()");
+    }
+  }
+  /**
+   * Get the time range of the axis.
+   *
+   * @return TimeRange of axis
+   **/
+  public TimeRange getTimeRangeU() {
+    return tRange_;
+  }
+  public void setRangeU(SoTRange tr) {
+    setRangeU(new TimeRange(tr.getStart().getLongTime(),
+                            tr.getEnd().getLongTime(),
+                            tr.getDelta().getLongTime()));
+  }
+  public SoTRange getSoTRangeU() {
+    return new SoTRange.Time(tRange_);
+  }
+  /**
+   * Set the origin in user units of the axis.
+   *
+   * @param tp origin of axis in user units
+   **/
+  public void setLocationU(TimePoint tp) {
+    if(tLocation_ == null || !tLocation_.equals(tp)) {
+      tLocation_ = tp;
+      modified("TimeAxis: setLocationU()");
+    }
+  }
+  public void setLocationU(SoTPoint tp) {
+    double x;
+    long t;
+    if(tp.isXTime()) {
+      t = tp.getX().getLongTime();
+      x = ((SoTValue.Double)tp.getY()).getValue();
+    } else {
+      t = tp.getY().getLongTime();
+      x = ((SoTValue.Double)tp.getX()).getValue();
+    }
+    setLocationU(new TimePoint(x, new GeoDate(t)));
+  }
+  /**
+   * Returns origin as a <code>SoTPoint</code>.
+   */
+  public SoTPoint getSoTLocationU() {
+    if(orientation_ == HORIZONTAL) {
+      return new SoTPoint(tLocation_.t, tLocation_.x);
+    } else {
+      return new SoTPoint(tLocation_.x, tLocation_.t);
+    }
+  }
+  /**
+   * Get the origin in user units.
+   *
+   * @return origin in user units
+   **/
+  public TimePoint getLocationU() {
+    return tLocation_;
+  }
+  //
+  public Rectangle getBounds() {
+    double xp, yp, ymin, ymax, xmin, xmax;
+    int xd, yd, width, height, x, y;
+    if(orientation_ == Axis.HORIZONTAL) {
+      //
+      yp = graph_.getYUtoP(tLocation_.x);
+
+      setupDraw(yp);
+
+      xd = graph_.getXUtoD(tRange_.start);
+      width = graph_.getXUtoD(tRange_.end) - xd;
+      x = xd;
+      ymax = yp;
+      ymin = yp;
+      if(labelPosition_ == POSITIVE_SIDE) {
+        ymax = ymajor_ + MAJOR_LABEL_RATIO__*labelHeight_;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          ymin = ymin - 1.3*largeTicHeight_;
+        }
+      } else {
+        ymin = ymajor_ - MAJOR_LABEL_RATIO__*labelHeight_;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          ymax = ymax + 1.3*largeTicHeight_;
+        }
+      }
+      y = graph_.getLayer().getYPtoD(ymax);
+      height = graph_.getLayer().getYPtoD(ymin) - y;
+    } else {
+      xp = graph_.getXUtoP(tLocation_.x);
+
+      setupDraw(xp);
+      yd = graph_.getYUtoD(tRange_.start);
+      y = graph_.getYUtoD(tRange_.end);
+      height = yd - y;
+      xmin = xp;
+      xmax = xp;
+      if(labelPosition_ == POSITIVE_SIDE) {
+        xmax = xmajor_ + MAJOR_LABEL_RATIO__*labelHeight_;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == NEGATIVE_SIDE) {
+          xmin = xmin - 1.3*largeTicHeight_;
+        }
+      } else {
+        xmin = xmajor_ - MAJOR_LABEL_RATIO__*labelHeight_;
+        if(ticPosition_ == BOTH_SIDES || ticPosition_ == POSITIVE_SIDE) {
+          xmax = xmax + 1.3*largeTicHeight_;
+        }
+      }
+      x = graph_.getLayer().getXPtoD(xmin);
+      width = graph_.getLayer().getXPtoD(xp) - x;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  public void setBounds(int x, int y, int width, int height) {
+  }
+  public void modified(String mess) {
+    //    if(Debug.EVENT) System.out.println("TimeAxis: modified()");
+    if(graph_ != null)
+      graph_.modified(mess);
+  }
+  //
+  void draw(Graphics g) {
+    int xloc, yloc, xend, yend;
+    int vertalign;
+    int minor_val, minor_val_old;
+    int major_val, major_val_old;
+    double xp, yp;
+    double xp_minor_old, yp_minor_old;
+    double x, y;
+    double xp_major_old, yp_major_old;
+    boolean draw_minor, draw_major;
+    boolean time_increasing;
+    GeoDate time = new GeoDate();
+    GeoDate minor_time_old;
+    GeoDate major_time_old;
+    GeoDate time_end = new GeoDate();
+    SGLabel label;
+    if(!visible_) return;
+    //
+    if(lineColor_ == null) {
+      g.setColor(graph_.getLayer().getPane().getComponent().getForeground());
+    } else {
+      g.setColor(lineColor_);
+    }
+    //
+    draw_minor = minorLabelInterval_ != 0 && labelPosition_ != NO_LABEL;
+    draw_major = majorLabelInterval_ != 0 && labelPosition_ != NO_LABEL;
+    //
+    time_increasing = tRange_.end.after(tRange_.start);
+    //
+    time = txt_.getStartTime(tRange_);
+    if(time_increasing) {
+      time_end = new GeoDate(tRange_.end);
+    } else {
+      time_end = new GeoDate(tRange_.start);
+    }
+    //System.out.println("start" + time.toLocaleString() + " end " + time_end.toLocaleString());
+    //
+    if(orientation_ == Axis.HORIZONTAL) {
+      yloc = graph_.getYUtoD(tLocation_.x);
+      xloc = graph_.getXUtoD(tRange_.start);
+      xend = graph_.getXUtoD(tRange_.end);
+      g.drawLine(xloc, yloc, xend, yloc);
+      //
+      yp = graph_.getYUtoP(tLocation_.x);
+      xp = graph_.getXUtoP(time);
+
+      setupDraw(yp);
+
+      if(txt_.isStartOfMinor(time)) {
+        drawThickXTic(g, xp, yp, 1.3f*largeTicHeight_);
+      } else {
+        drawXTic(g, xp, yp, largeTicHeight_);
+      }
+      major_val = txt_.getMajorValue(time);
+      major_val_old = major_val;
+      minor_val_old = txt_.getMinorValue(time);
+      xp_major_old = xp;
+      xp_minor_old = xp;
+      minor_time_old = new GeoDate(time);
+      major_time_old = new GeoDate(time);
+      time.increment(txt_.getIncrementValue(), txt_.getIncrementUnits());
+      //
+      while (time.before(time_end)) {
+        xp = graph_.getXUtoP(time);
+        minor_val = txt_.getMinorValue(time);
+        if(txt_.isStartOfMinor(time)) {
+          drawThickXTic(g, xp, yp, 1.3f*largeTicHeight_);
+        } else {
+          drawXTic(g, xp, yp, largeTicHeight_);
+        }
+        if(draw_minor && minor_val_old%minorLabelInterval_ == 0) {
+          x = txt_.computeLocation(xp_minor_old, xp);
+          drawMinorLabel(g, x, minor_time_old);
+        }
+        major_val = txt_.getMajorValue(time);
+        if(major_val != major_val_old) {
+          if(draw_major && major_val_old%majorLabelInterval_ == 0) {
+            x = (xp_major_old + xp)*0.5;
+            drawMajorLabel(g, x, major_time_old);
+          }
+          xp_major_old = xp;
+          major_val_old = major_val;
+          major_time_old = new GeoDate(time);
+        }
+        xp_minor_old = xp;
+        minor_val_old = minor_val;
+        minor_time_old = new GeoDate(time);
+        time.increment(txt_.getIncrementValue(), txt_.getIncrementUnits());
+      } // end of while
+      if(draw_major && major_val_old%majorLabelInterval_ == 0) {
+        GeoDate delta = time_end.subtract(major_time_old);
+        if(txt_.isRoomForMajorLabel(delta)) {
+          xp = graph_.getXUtoP(time_end);
+          x = (xp_major_old + xp)*0.5;
+          drawMajorLabel(g, x, major_time_old);
+        }
+      }
+    } else {          // vertical axis
+      xloc = graph_.getXUtoD(tLocation_.x);
+      yloc = graph_.getYUtoD(tRange_.start);
+      yend = graph_.getYUtoD(tRange_.end);
+      g.drawLine(xloc, yloc, xloc, yend);
+      //
+      xp = graph_.getXUtoP(tLocation_.x);
+      yp = graph_.getYUtoP(time);
+
+      setupDraw(xp);
+
+      if(txt_.isStartOfMinor(time)) {
+        drawThickYTic(g, xp, yp, 1.3f*largeTicHeight_);
+      } else {
+        drawYTic(g, xp, yp, largeTicHeight_);
+      }
+      major_val = txt_.getMajorValue(time);
+      major_val_old = major_val;
+      minor_val_old = txt_.getMinorValue(time);
+      yp_major_old = yp;
+      yp_minor_old = yp;
+      minor_time_old = new GeoDate(time);
+      major_time_old = new GeoDate(time);
+      time.increment(txt_.getIncrementValue(), txt_.getIncrementUnits());
+      //
+      while (time.before(time_end)) {
+        yp = graph_.getYUtoP(time);
+        minor_val = txt_.getMinorValue(time);
+        if(txt_.isStartOfMinor(time)) {
+          drawThickYTic(g, xp, yp, 1.3f*largeTicHeight_);
+        } else {
+          drawYTic(g, xp, yp, largeTicHeight_);
+        }
+        if(draw_minor && minor_val_old%minorLabelInterval_ == 0) {
+          y = txt_.computeLocation(yp_minor_old, yp);
+          drawMinorLabel(g, y, minor_time_old);
+        }
+        major_val = txt_.getMajorValue(time);
+        if(major_val != major_val_old) {
+          if(draw_major && major_val_old%majorLabelInterval_ == 0) {
+            y = (yp_major_old + yp)*0.5;
+            drawMajorLabel(g, y, major_time_old);
+          }
+          yp_major_old = yp;
+          major_val_old = major_val;
+          major_time_old = new GeoDate(time);
+        }
+        yp_minor_old = yp;
+        minor_val_old = minor_val;
+        minor_time_old = new GeoDate(time);
+        time.increment(txt_.getIncrementValue(), txt_.getIncrementUnits());
+      } // end of while
+      if(draw_major && major_val_old%majorLabelInterval_ == 0) {
+        GeoDate delta = time_end.subtract(major_time_old);
+        if(txt_.isRoomForMajorLabel(delta)) {
+          yp = graph_.getYUtoP(time_end);
+          y = (yp_major_old + yp)*0.5;
+          drawMajorLabel(g, y, major_time_old);
+        }
+      }
+    }
+  }
+  public void setTitle(SGLabel title) {
+  // Time axes don't use title_
+    title_ = null;
+  }
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TimeAxisStyle.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TimeAxisStyle.java
new file mode 100755
index 0000000..f46a86e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TimeAxisStyle.java
@@ -0,0 +1,156 @@
+/*
+ * $Id: TimeAxisStyle.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+/**
+ * <code>TimeAxisStyle</code> defines an interface to
+ * create a specific time axis style. Currently there are
+ * five time axes styles, <code>MINUTE_HOUR</code>,
+ * <code>HOUR_DAY</code>, <code>DAY_MONTH</code>,
+ * <code>MONTH_YEAR</code>, and <code>YEAR_DECADE</code>. All time
+ * axes have two labeling levels, minor and major.  For example,
+ * <code>DAY_MONTH</code> style has a minor level of days and a
+ * major level of months.
+ *
+ * @see TimeAxis
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ */
+public interface TimeAxisStyle {
+  /**
+   * Get the minor time value for labeling.
+   *
+   * @param time current date
+   * @return minor time value
+   */
+  public int getMinorValue(GeoDate time);
+  /**
+   * Get the major time value for labeling.
+   *
+   * @param time current date
+   * @return major time value
+   */
+  public int getMajorValue(GeoDate time);
+  /**
+   * Determines if there is enough room in <code>delta</code> time
+   * for another major label.
+   *
+   * @return true if enough room exists
+   */
+  public boolean isRoomForMajorLabel(GeoDate delta);
+  /**
+   * Determines if <code>time</code> is the start of a
+   * minor interval.
+   *
+   * @return true if start of minor interval
+   */
+  public boolean isStartOfMinor(GeoDate time);
+  /**
+   * Get the default minor label format. The default minor labels are
+   * "mm", "HH", "dd", "MMM", and "yy" for <code>MINUTE_HOUR</code>,
+   * <code>HOUR_DAY</code>, <code>DAY_MONTH</code>, <code>MONTH_YEAR</code>,
+   * and <code>YEAR_DECADE</code>, respectively.
+   *
+   * @return minor label format
+   */
+  public String getDefaultMinorLabelFormat();
+  /**
+   * Get the default major label format. The default major labels are
+   * "yyyy-MM-dd HH", "yyyy-MM-dd", "yyyy-MM", "yyyy", and "yyyy" for
+   * <code>MINUTE_HOUR</code>,
+   * <code>HOUR_DAY</code>, <code>DAY_MONTH</code>, <code>MONTH_YEAR</code>,
+   * and <code>YEAR_DECADE</code>, respectively.
+   *
+   * @return major label format
+   */
+  public String getDefaultMajorLabelFormat();
+  /**
+   * Get the default minor label interval.
+   *
+   * @return minor label interval
+   */
+  public int getDefaultMinorLabelInterval();
+  /**
+   * Get the default major label interval.
+   *
+   * @return major label interval
+   */
+  public int getDefaultMajorLabelInterval();
+  /**
+   * Get the default number of small tics between
+   * each minor tic.
+   *
+   * @return number of small tics
+   */
+  public int getDefaultNumSmallTics();
+  /**
+   * Returns a beginning time rounded to the nearest minor
+   * increment. For example, for <code>DAY_MONTH</code>
+   * if time is increasing then round to the day before
+   * <code>tRange.start</code> otherwise
+   * the nearest day after <code>tRange.end</code>.
+   *
+   * @param tRange time range of the axis
+   */
+  public GeoDate getStartTime(TimeRange trange);
+  /**
+   * Get the increment value for the minor labeling. The value
+   * is 1.0 for all styles.
+   *
+   * @return increment value
+   */
+  public double getIncrementValue();
+  /**
+   * Get the increment units for the minor labeling. The value is
+   * <code>GeoDate.MINUTES</code>, <code>GeoDate.HOURS</code>,
+   * <code>GeoDate.DAYS</code>, <code>GeoDate.MONTHS</code>, and
+   * <code>GoeDate.YEARS</code> for  <code>MINUTE_HOUR</code>,
+   * <code>HOUR_DAY</code>, <code>DAY_MONTH</code>, <code>MONTH_YEAR</code>,
+   * and <code>YEAR_DECADE</code>, respectively.
+   *
+   * @return increment units
+   * @see GeoDate
+   */
+  public int getIncrementUnits();
+  /**
+   * Determine the minor label interval from the time
+   * extent of the axis. For example, if <code>delta</code> is greater
+   * than 30 days, greater than 10 and less that 30 days, or
+   * less than 10 days, the interval is 5, 2, or 1, respectively,
+   * for <code>DAY_MONTH</code> style.
+   *
+   * @param delta time extent
+   */
+  public void computeDefaults(GeoDate delta);
+  /**
+   * Determines the location of the minor time label. Positions
+   * the label between the tic marks for <code>DAY_MONTH</code>,
+   * <code>MONTH_YEAR</code>, and <code>YEAR_DECADE</code>, or
+   * at the tic mark for <code>MINUTES_HOURS</code> and
+   * <code>HOURS_DAYS</code>.
+   *
+   * @param prev previous tic location
+   * @param now current tic location
+   */
+  public double computeLocation(double prev,double now);
+
+  public String toString();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Transform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Transform.java
new file mode 100755
index 0000000..7847f7b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/Transform.java
@@ -0,0 +1,102 @@
+/*
+ * $Id: Transform.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import java.beans.PropertyChangeListener;
+
+import gov.noaa.pmel.util.Range2D;
+import java.io.Serializable;
+
+/**
+ * <code>Transform</code> defines an interface for transformations between
+ * user and physical coordinates.
+ *
+ * @see AxisTransform
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 1.0
+ */
+public interface Transform extends Serializable {
+  /**
+   * Set physical coordinate range.
+   *
+   * @param p1 minimum value, physical coordinates
+   * @param p2 maximum value, physical coordinates
+   * @see LinearTransform
+   **/
+  public void setRangeP(double p1,double p2);
+  /**
+   * Set physical coordinate range.
+   *
+   * @param prange physcial coordinate range
+   * @see Range2D
+   * @see LinearTransform
+   **/
+  public void setRangeP(Range2D prange);
+  /**
+   * Get the physical coordinate range.
+   *
+   * @return physcial coordinate range
+   * @see Range2D
+   **/
+  public Range2D getRangeP();
+  /**
+   * Set the user coordinate range for double values.
+   *
+   * @param u1 minimum value, user coordinates
+   * @param u2 maximum value, user coordinates
+   * @see LinearTransform
+   **/
+  public void setRangeU(double u1,double u2);
+  /**
+   * Set the user coordinate range for double values.
+   *
+   * @param urange user coordinate range
+   * @see Range2D
+   * @see LinearTransform
+   **/
+  public void setRangeU(Range2D urange);
+  /**
+   * Get the user coordinate range for double values.
+   *
+   * @return user range
+   * @see Range2D
+   **/
+  public Range2D getRangeU();
+  /**
+   * Transform from user to physical coordinates.
+   *
+   * @param u user value
+   * @return physical value
+   */
+  abstract double getTransP(double u);
+  /**
+   * Transform from physical to user coordinates.
+   *
+   * @param p physical value
+   * @return user value
+   */
+  abstract double getTransU(double p);
+  /**
+   * Add listener for changes to transform properties.
+   * @since 2.0
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener);
+  /**
+   * Remove listener.
+   * @since 2.0
+   */
+  public void removePropertyChangeListener(PropertyChangeListener listener);
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformAccess.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformAccess.java
new file mode 100755
index 0000000..de67990
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformAccess.java
@@ -0,0 +1,26 @@
+/*
+ * $Id: TransformAccess.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+
+/**
+ * Interface indicates that the color map uses a transform to map
+ * levels.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.0
+ */
+public interface TransformAccess {
+  void setRange(Range2D range);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformColor.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformColor.java
new file mode 100755
index 0000000..048ec93
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformColor.java
@@ -0,0 +1,36 @@
+/*
+ * $Id: TransformColor.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+/**
+ * Interface provides support for accessing color transforms for a
+ * color map.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.0
+ */
+public interface TransformColor {
+  Transform getRedTransform();
+
+  void setRedTransform(Transform redTransform);
+
+  Transform getGreenTransform();
+
+  void setGreenTransform(Transform greenTransform);
+
+  Transform getBlueTransform();
+
+  void setBlueTransform(Transform blueTransform);
+
+  void setColorTransforms(Transform red, Transform green, Transform blue);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformColorMap.java
new file mode 100755
index 0000000..41df368
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/TransformColorMap.java
@@ -0,0 +1,213 @@
+/*
+ * $Id: TransformColorMap.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * <code>TransformColorMap</code> provides a mapping from a value
+ * to a <code>Color</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.0
+ */
+public class TransformColorMap extends ColorMap
+  implements Cloneable, PropertyChangeListener,
+             TransformColor, TransformAccess {
+  /**
+   * Red Transform
+
+   * @supplierCardinality 0..1
+   * @clientRole rTrans_
+   * @link aggregationByValue
+   */
+  private Transform rTrans_ = null;
+  /**
+   * Green Transform
+
+   * @supplierCardinality 0..1
+   * @clientRole gTrans_
+   * @link aggregationByValue
+   */
+  private Transform gTrans_ = null;
+  /**
+   * Blue Transform
+
+   * @supplierCardinality 0..1
+   * @clientRole bTrans_
+   * @link aggregationByValue
+   */
+  private Transform bTrans_ = null;
+  /**
+   * Initialize the color map to use red, green, and blue transforms. Sets up
+   * <code>ColorMap</code> for <code>TRANSFORM</code> access.
+   * Each <code>Transform</code> should have identical user
+   * ranges.  The physical range will be set to 0.0 to 1.0 for each
+   * color component.
+   *
+   * @see Transform
+   */
+  public TransformColorMap(Transform rTrans,Transform gTrans,Transform bTrans) {
+    rTrans_ = rTrans;
+    rTrans_.setRangeP(0.0, 1.0);
+    gTrans_ = gTrans;
+    gTrans_.setRangeP(0.0, 1.0);
+    bTrans_ = bTrans;
+    bTrans_.setRangeP(0.0, 1.0);
+  }
+  /**
+   * Create a copy of the <code>ColorMap</code> object.
+   */
+  public ColorMap copy() {
+    ColorMap newMap;
+    try {
+      newMap = (ColorMap)clone();
+    } catch (CloneNotSupportedException e) {
+      newMap = null;
+    }
+    return newMap;
+  }
+  /**
+   * Get a <code>Color</code>. Returns a <code>Color</code> by
+   * one of four methods. <code>INDEXED</code>, <code>TRANSFORM</code>,
+   * <code>LEVEL_INDEXED</code>, and <code>LEVEL_TRANSFORM</code>.
+   *
+   * @param val Value
+   * @return Color
+   *
+   */
+  public Color getColor(double val) {
+    double ival = val;
+    float red = (float)rTrans_.getTransP(ival);
+    float green = (float)gTrans_.getTransP(ival);
+    float blue = (float)bTrans_.getTransP(ival);
+    return new Color(red, green, blue);
+  }
+  /**
+   * Set the user range for all the <code>Transform</codes>s.
+   *
+   */
+  public void setRange(Range2D range) {
+    rTrans_.setRangeU(range);
+    gTrans_.setRangeU(range);
+    bTrans_.setRangeU(range);
+  }
+  /**
+   * Get the current user range for the <code>Transform</code>s.
+   *
+   * @return user range
+   */
+  public Range2D getRange() {
+    return rTrans_.getRangeU();
+  }
+  /**
+   * Set the color <code>Transform</code>s.
+   * <BR><B>Property Change:</B> <code>redColorTransform</code>,
+   * <code>greenColorTransform</code>, and
+   * <code>blueColorTransform</code>.
+   *
+   * @param rTrans red <code>Transform</code>
+   * @param gTrans green <code>Transform</code>
+   * @param bTrans blue <code>Transform</code>
+   */
+  public void setColorTransforms(Transform rTrans,
+                                 Transform gTrans,
+                                 Transform bTrans) {
+    if(!rTrans_.equals(rTrans) ||
+       !gTrans_.equals(gTrans) ||
+       !bTrans_.equals(bTrans)) {
+      if(rTrans_ != null) rTrans_.removePropertyChangeListener(this);
+      if(gTrans_ != null) gTrans_.removePropertyChangeListener(this);
+      if(bTrans_ != null) bTrans_.removePropertyChangeListener(this);
+
+      Transform tempOld = rTrans_;
+      rTrans_ = rTrans;
+      rTrans_.setRangeP(0.0, 1.0);
+      firePropertyChange("redColorTransform",
+                                  tempOld,
+                                  rTrans_);
+      tempOld = gTrans_;
+      gTrans_ = gTrans;
+      gTrans_.setRangeP(0.0, 1.0);
+      firePropertyChange("greenColorTransform",
+                                  tempOld,
+                                  gTrans_);
+      tempOld = bTrans_;
+      bTrans_ = bTrans;
+      bTrans_.setRangeP(0.0, 1.0);
+      firePropertyChange("blueColorTransform",
+                                  tempOld,
+                                  bTrans_);
+
+      rTrans_.addPropertyChangeListener(this);
+      gTrans_.addPropertyChangeListener(this);
+      bTrans_.addPropertyChangeListener(this);
+    }
+  }
+  /**
+   * Set the red color <code>Transform</code>
+   */
+  public void setRedTransform(Transform red) {
+    rTrans_ = red;
+  }
+  /**
+   * Get the red color <code>Transform</code>.
+   *
+   * @return red <code>Transform</code>
+   */
+  public Transform getRedTransform() {
+    return rTrans_;
+  }
+  /**
+   * Set the green color <code>Transform</code>
+   */
+  public void setGreenTransform(Transform green) {
+    gTrans_ = green;
+  }
+  /**
+   * Get the green color <code>Transform</code>.
+   *
+   * @return green <code>Transform</code>
+   */
+  public Transform getGreenTransform() {
+    return gTrans_;
+  }
+  /**
+   * Set the blue color <code>Transform</code>
+   */
+  public void setBlueTransform(Transform blue) {
+    bTrans_ = blue;
+  }
+  /**
+   * Get the blue color <code>Transform</code>.
+   *
+   * @return blue <code>Transform</code>
+   */
+  public Transform getBlueTransform() {
+    return bTrans_;
+  }
+
+  public boolean equals(ColorMap cm) {
+    if(cm == null || !(cm instanceof TransformColorMap)) return false;
+    if(!(rTrans_.equals(((TransformColorMap)cm).rTrans_) &&
+         gTrans_.equals(((TransformColorMap)cm).gTrans_) &&
+         bTrans_.equals(((TransformColorMap)cm).bTrans_))) return false;
+    return true;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorAttribute.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorAttribute.java
new file mode 100755
index 0000000..402b0c2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorAttribute.java
@@ -0,0 +1,556 @@
+/*
+ * $Id: VectorAttribute.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import  java.awt.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * Sets the rendering style for line data.
+ * <code>Color</code>, width, and dash characteristics are
+ * <code>VectorAttribute</code> properties.
+ * <BR><FONT color="#FF0000">Warning: The SGT implementation of
+ * Vectors requires Java2D. To use Vectors you must be using jdk1.2 or
+ * newer.</FONT>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.1
+ * @see LineCartesianRenderer
+ * @see ContourLevels
+ */
+public class VectorAttribute
+  implements Attribute, Cloneable, java.io.Serializable {
+
+  protected transient PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private boolean batch_ = false;
+  private boolean local_ = true;
+  private boolean modified_ = false;
+  private String id_ = null;
+  private int vectorStyle_ = HEAD;
+  private Color vectorColor_ = Color.black;
+  private double vectorScale_ = 0.01;  // User units to physical
+  private double vectorMaxSize_ = 100.0;
+  private double offsetAngle_ = 0.0;
+
+  private double headScale_ = 1.0;  // User units to physical
+  private double headMaxSize_ = 100.0;
+  private double headMinSize_ = 0.05;
+  private double headFixedSize_ = 0.2;  // Physical units
+
+  private int originStyle_ = NO_MARK;
+  private Color markColor_ = Color.black;
+  private int mark_ = 1;
+  private double markHeightP_ = 0.2;
+
+  private float width_ = 1.0f;
+  private int capStyle_ = LineAttribute.CAP_SQUARE;
+  private int miterStyle_ = LineAttribute.JOIN_MITER;
+  private float miterLimit_ = 10.0f;
+  /**
+   * Vector head style, None.  No arrow head will be drawn.
+   */
+  public static final int NO_HEAD = 0;
+  /**
+   * Vector head style, Un-scaled (default).  Head will be drawn a
+   * constant size.
+   */
+  public static final int HEAD = 1;
+  /**
+   * Vector head style, Scaled.  The size of the head will be
+   * proportional to the length of the vector.
+   */
+  public static final int SCALED_HEAD = 2;
+  /**
+   * Vector origin style, no mark (default).  The origin of the vector
+   * will be drawn without a plot mark.
+   */
+  public static final int NO_MARK = 0;
+  /**
+   * Vector origin style, Mark.  A plot mark will be drawn at the
+   * origin of the vector.
+   */
+  public static final int MARK = 1;
+  /**
+   * Default constructor.  Default vector style is HEAD,
+   * default color is red, and scale = 1.0;
+   **/
+  public VectorAttribute() {
+    this(1.0, Color.red);
+  }
+  /**
+   * <code>VectorAttribute</code> constructor.  Default vector style
+   * is HEAD.
+   *
+   * @param scale vector scale
+   * @param color vector <code>Color</code>
+   * @see java.awt.Color
+   **/
+  public VectorAttribute(double scale, Color color) {
+    vectorStyle_ = HEAD;
+    vectorScale_ = scale;
+    vectorColor_ = color;
+  }
+  /**
+   * <code>VectorAttribute</code> constructor.
+   *
+   * @param style vector style
+   * @param scale vector scale
+   * @param color vector <code>Color</code>
+   * @param head_scale scale of vector head
+   * @see java.awt.Color
+   **/
+  public VectorAttribute(int style, double scale, Color color,
+                         double head_scale) {
+    vectorStyle_ = style;
+    vectorScale_ = scale;
+    vectorColor_ = color;
+    headScale_ = head_scale;
+  }
+  /**
+   * Copy the <code>VectorAttribute</code>.
+   *
+   * @return new <code>VectorAttribute</code>
+   */
+  public Object copy() {
+    VectorAttribute newVector;
+    try {
+      newVector = (VectorAttribute)clone();
+    } catch (CloneNotSupportedException e) {
+      newVector = new VectorAttribute();
+    }
+    return newVector;
+  }
+  /**
+   * Change the head style.  Options include <code>NO_HEAD</code>,
+   * <code>HEAD</code>, and <code>SCALED_HEAD</code>.
+   * <BR><B>Property Change:</B> <code>vectorStyle</code>.
+   *
+   * @see #setVectorColor(java.awt.Color)
+   * @see #setVectorMaxSize(double)
+   * @see #setVectorScale(double)
+   * @see #setOffsetAngle(double)
+   *
+   */
+  public void setVectorStyle(int style) {
+    if(vectorStyle_ != style) {
+      Integer tempOld = new Integer(vectorStyle_);
+      vectorStyle_ = style;
+      firePropertyChange("vectorStyle",
+                                  tempOld,
+                                  new Integer(vectorStyle_));
+    }
+  }
+  /** Get the vector head style. */
+  public int getVectorStyle() {
+    return vectorStyle_;
+  }
+  /**
+   * Change the vector color.
+   * <BR><B>Property Change:</B> <code>vectorColor</code>.
+   *
+   */
+  public void setVectorColor(Color color) {
+    if(!vectorColor_.equals(color)) {
+      Color tempOld = vectorColor_;
+      vectorColor_ = color;
+      firePropertyChange("vectorColor",
+                                  tempOld,
+                                  vectorColor_);
+    }
+  }
+  /** Get the vector color. */
+  public Color getVectorColor() {
+    return vectorColor_;
+  }
+  /**
+   * Change the vector scale.  The vector length is determined
+   * by the data value times the vector scale.  The
+   * vector length is bounded by the maximum allowed
+   * vector length.
+   * <BR><B>Property Change:</B> <code>vectorScale</code>.
+   *
+   * @see #setVectorMaxSize(double)
+   *
+   */
+  public void setVectorScale(double scale) {
+    if(vectorScale_ != scale) {
+      Double tempOld = new Double(vectorScale_);
+      vectorScale_ = scale;
+      firePropertyChange("vectorScale",
+                                  tempOld,
+                                  new Double(vectorScale_));
+    }
+  }
+  /** Geth the vector head scale. */
+  public double getVectorScale() {
+    return vectorScale_;
+  }
+  /**
+   * Set the maximum size for a vector.
+   * <BR><B>Property Change:</B> <code>vectorMaxSize</code>.
+   *
+   */
+  public void setVectorMaxSize(double size) {
+    if(vectorMaxSize_ != size) {
+      Double tempOld = new Double(vectorMaxSize_);
+      vectorMaxSize_ = size;
+      firePropertyChange("vectorMaxSize",
+                                  tempOld,
+                                  new Double(vectorMaxSize_));
+    }
+  }
+  /** Get the maximum vector length allowed. */
+  public double getVectorMaxSize() {
+    return vectorMaxSize_;
+  }
+  /**
+   * Set the angle (clockwize positive) to rotate the vector.
+   * <BR><B>Property Change:</B> <code>offsetAngle</code>.
+   * @param angle in degrees
+   */
+  public void setOffsetAngle(double angle) {
+    if(offsetAngle_ != angle) {
+      Double tempOld = new Double(offsetAngle_);
+      offsetAngle_ = angle;
+      firePropertyChange("offsetAngle",
+                                  tempOld,
+                                  new Double(offsetAngle_));
+    }
+  }
+  /** Get the vector rotation angle. */
+  public double getOffsetAngle() {
+    return offsetAngle_;
+  }
+  /**
+   * Change the vector head scale.  The vector head size is determined
+   * by the length of the vector times the vector head scale.  The
+   * vector head size is bounded by the minimum and maximum allowed
+   * head size.
+   * <BR><B>Property Change:</B> <code>headScale</code>.
+   *
+   * @see #setHeadMinSize(double)
+   * @see #setHeadMaxSize(double)
+   *
+   */
+  public void setHeadScale(double scale) {
+    if(headScale_ != scale) {
+      Double tempOld = new Double(headScale_);
+      headScale_ = scale;
+      firePropertyChange("headScale",
+                                  tempOld,
+                                  new Double(headScale_));
+    }
+  }
+  /** Get the vector head scale. */
+  public double getHeadScale() {
+    return headScale_;
+  }
+  /**
+   * Set the maximum size for a scaled vector head.
+   * <BR><B>Property Change:</B> <code>headMaxSize</code>.
+   *
+   */
+  public void setHeadMaxSize(double size) {
+    if(headMaxSize_ != size) {
+      Double tempOld = new Double(headMaxSize_);
+      headMaxSize_ = size;
+      firePropertyChange("headMaxSize",
+                                  tempOld,
+                                  new Double(headMaxSize_));
+    }
+  }
+  /** Get the maximum vector head size. */
+  public double getHeadMaxSize() {
+    return headMaxSize_;
+  }
+  /**
+   * Set the minimum size for a scaled vector head.
+   * <BR><B>Property Change:</B> <code>headMinSize</code>.
+   *
+   */
+  public void setHeadMinSize(double size) {
+    if(headMinSize_ != size) {
+      Double tempOld = new Double(headMinSize_);
+      headMinSize_ = size;
+      firePropertyChange("headMinSize",
+                                  tempOld,
+                                  new Double(headMinSize_));
+    }
+  }
+  /** Get the minimum vector head size. */
+  public double getHeadMinSize() {
+    return headMinSize_;
+  }
+  /**
+   * Set the fixed size for a unscaled vector head.
+   * <BR><B>Property Change:</B> <code>headFixedSize</code>.
+   *
+   */
+  public void setHeadFixedSize(double size) {
+    if(headFixedSize_ != size) {
+      Double tempOld = new Double(headFixedSize_);
+      headFixedSize_ = size;
+      firePropertyChange("headFixedSize",
+                                  tempOld,
+                                  new Double(headFixedSize_));
+    }
+  }
+  /** Get the fixed vector head size. */
+  public double getHeadFixedSize() {
+    return headFixedSize_;
+  }
+  /**
+   * Set the vector origin style.  Options are <code>NO_MARK</code>
+   * and <code>MARK</code>.
+   * <BR><B>Property Change:</B> <code>originStyle</code>.
+   *
+   * @see #setMarkColor(java.awt.Color)
+   * @see #setMark(int)
+   * @see #setMarkHeightP(double)
+   */
+  public void setOriginStyle(int style) {
+    if(originStyle_ != style) {
+      Integer tempOld = new Integer(originStyle_);
+      originStyle_ = style;
+      firePropertyChange("originStyle",
+                                  tempOld,
+                                  new Integer(originStyle_));
+    }
+  }
+  /** Get vector origin style. */
+  public int getOriginStyle() {
+    return originStyle_;
+  }
+  /**
+   * Set the color for the origin mark.
+   * <BR><B>Property Change:</B> <code>markColor</code>.
+   */
+  public void setMarkColor(Color color) {
+    if(!markColor_.equals(color)) {
+      Color tempOld = markColor_;
+      markColor_ = color;
+      firePropertyChange("markColor",
+                                  tempOld,
+                                  markColor_);
+    }
+  }
+  /** Get the color for the origin mark. */
+  public Color getMarkColor() {
+    return markColor_;
+  }
+  /**
+   * Set the mark for the origin.
+   * <BR><B>Property Change:</B> <code>mark</code>.
+   *
+   * @param mark the plot mark
+   * @see PlotMark
+   */
+  public void setMark(int mark) {
+    if(mark_ != mark) {
+      Integer tempOld = new Integer(mark_);
+      if(mark <= 0) mark = 1;
+      if(mark > 51) mark = 51;
+      mark_ = mark;
+      firePropertyChange("mark",
+                                  tempOld,
+                                  new Integer(mark_));
+    }
+  }
+  /**
+   * Get plot mark for the origin.
+   *
+   * @return plot mark
+   **/
+  public int getMark() {
+    return mark_;
+  }
+  /**
+   * Set mark height for the origin.
+   * <BR><B>Property Change:</B> <code>markHeightP</code>.
+   *
+   * @param markh mark height
+   **/
+  public void setMarkHeightP(double markh) {
+    if(markHeightP_ != markh) {
+      Double tempOld = new Double(markHeightP_);
+      markHeightP_ = markh;
+      firePropertyChange("markHeightP",
+                                  tempOld,
+                                  new Double(markHeightP_));
+    }
+  }
+  /**
+   * Get mark height for the origin.
+   *
+   * @return mark height
+   **/
+  public double getMarkHeightP() {
+    return markHeightP_;
+  }
+  /**
+   * Set the line width in physical units.
+   * <BR><B>Property Change:</B> <code>width</code>.
+   *
+   * @param t line width
+   **/
+  public void setWidth(float t) {
+    if(width_ != t) {
+      Float tempOld = new Float(width_);
+      width_ = t;
+      firePropertyChange("width",
+                                  tempOld,
+                                  new Float(width_));
+    }
+  }
+  /**
+   * Get line width.
+   *
+   * @return line width in physcial coordinates.
+   **/
+  public float getWidth() {
+    return width_;
+  }
+  /**
+   * Set the line Cap Style.  Styles include
+   * <code>LineAttribute.CAP_BUTT</code>,
+   * <code>LineAttribute.CAP_ROUND</code>, and
+   * <code>LineAttribute.CAP_SQUARE</code>.
+   * <BR><B>Property Change:</B> <code>capStyle</code>.
+   *
+   * @see LineAttribute#CAP_BUTT
+   * @see LineAttribute#CAP_ROUND
+   * @see LineAttribute#CAP_SQUARE
+   */
+  public void setCapStyle(int style) {
+    if(capStyle_ != style) {
+      Integer tempOld = new Integer(capStyle_);
+      capStyle_ = style;
+      firePropertyChange("capStyle",
+                                  tempOld,
+                                  new Integer(capStyle_));
+    }
+  }
+  /** Get the line cap style. */
+  public int getCapStyle() {
+    return capStyle_;
+  }
+  /**
+   * Set the line miter style.  Styles include
+   * <code>LineAttribute.JOIN_BEVEL</code>,
+   * <code>LineAttribute.JOIN_MITER</code>, and
+   * <code>LineAttribute.JOIN_ROUND</code>.
+   * <BR><B>Property Change:</B> <code>miterStyle</code>.
+   *
+   * @see LineAttribute#JOIN_BEVEL
+   * @see LineAttribute#JOIN_MITER
+   * @see LineAttribute#JOIN_ROUND
+   */
+  public void setMiterStyle(int style) {
+    if(miterStyle_ != style) {
+      Integer tempOld = new Integer(miterStyle_);
+      miterStyle_ = style;
+      firePropertyChange("miterStyle",
+                                  tempOld,
+                                  new Integer(miterStyle_));
+    }
+
+  }
+  /** Get the line miter sytle. */
+  public int getMiterStyle() {
+    return miterStyle_;
+  }
+  /**
+   * Set the line miter limit.
+   * <BR><B>Property Change:</B> <code>miterLimit</code>.
+   */
+  public void setMiterLimit(float limit) {
+    if(miterLimit_ != limit) {
+      Float tempOld = new Float(miterLimit_);
+      miterLimit_ = limit;
+      firePropertyChange("miterLimit",
+                                  tempOld,
+                                  new Float(miterLimit_));
+    }
+  }
+  /** Get the line miter limit. */
+  public float getMiterLimit() {
+    return miterLimit_;
+  }
+
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>VectorAttribute</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1);
+  }
+  /**
+   * Add listener to changes in <code>VectorAttribute</code> properties.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener listener) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.addPropertyChangeListener(listener);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener listener) {
+    changes_.removePropertyChangeListener(listener);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setId(String id) {
+    id_ = id;
+  }
+  /**
+   * @since 3.0
+   */
+  public String getId() {
+    return id_;
+  }
+
+  protected void firePropertyChange(String name, Object oldValue, Object newValue) {
+    if(batch_) {
+      modified_ = true;
+      return;
+    }
+    AttributeChangeEvent ace = new AttributeChangeEvent(this, name,
+                                                        oldValue, newValue,
+                                                        local_);
+    changes_.firePropertyChange(ace);
+    modified_ = false;
+  }
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch) {
+    setBatch(batch, true);
+  }
+  /**
+   * @since 3.0
+   */
+  public void setBatch(boolean batch, boolean local) {
+    local_ = local;
+    batch_ = batch;
+    if(!batch && modified_) firePropertyChange("batch", Boolean.TRUE, Boolean.FALSE);
+  }
+  /**
+   * @since 3.0
+   */
+  public boolean isBatch() {
+    return batch_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorCartesianRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorCartesianRenderer.java
new file mode 100755
index 0000000..6cfb90e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorCartesianRenderer.java
@@ -0,0 +1,458 @@
+/*
+ * $Id: VectorCartesianRenderer.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.sgt.dm.SGTVector;
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.Collection;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics2D;
+import java.awt.BasicStroke;
+import java.awt.Stroke;
+import java.awt.geom.GeneralPath;
+//import java.awt.geom.AffineTransform;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Event;
+import java.awt.Point;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Produces a vector plot.  If
+ * a second data set is specified it must have the same shape as the first.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.1
+ */
+public class VectorCartesianRenderer extends CartesianRenderer {
+  /**
+   * @link aggregation
+   * @label attr
+   */
+  private VectorAttribute attr_ = null;
+
+  /**
+   * @link aggregation
+   * @label vector
+   */
+  private SGTVector vector_ = null;
+  private Collection collection_ = null;
+  private float slope_;
+  private float xoff_;
+  private float yoff_;
+
+  /**
+   * Get the <code>Attribute</code> associated with the data.
+   */
+  public Attribute getAttribute() {
+    return attr_;
+  }
+
+  private void drawVector(Graphics g, SGTVector vector,
+                          VectorAttribute attr) {
+
+    Layer ly = cg_.getLayer();
+    Graphics2D g2 = (Graphics2D)g;
+    slope_ = (float)ly.getXSlope();
+    xoff_ = (float)ly.getXOffset();
+    yoff_ = (float)ly.getYOffset();
+    GeneralPath gp = null;
+    Stroke savedStroke = g2.getStroke();
+    BasicStroke stroke = new BasicStroke(attr_.getWidth(),
+                                         attr_.getCapStyle(),
+                                         attr_.getMiterStyle(),
+                                         attr_.getMiterLimit());
+    g2.setStroke(stroke);
+    //
+    // a 1 unit lenght vector with a headScale of 1.0 will
+    // create a head barb that is 1.05948 long.  A factor of
+    // 0.94386 is required to remove this effect
+    //
+    float scale = (float)attr_.getVectorScale();
+    float headScale = (float)attr_.getHeadScale()*0.94386f;
+    float fixedScale = (float)(headScale*attr_.getHeadFixedSize());
+    float minSize = (float)attr_.getHeadMinSize();
+    float maxSize = (float)attr_.getHeadMaxSize();
+    double angle = attr_.getOffsetAngle()*0.017453293;
+    float tScale;
+    float[] xp, yp;
+    int[] xtail, ytail;
+    int xdhead, ydhead;
+    int xdtemp, ydtemp;
+    float xphead, yphead;
+    int count, size, nout, idx;
+    double[] xValues, yValues;
+    GeoDate[] xTValues, yTValues;
+    double[] uValues, vValues;
+    float vx, vy, vclen;
+    double vdx, vdy;
+
+    float hx1, hx2;
+    float hy1, hy2;
+    float headX, headY;
+    float orgX, orgY;
+    //
+    // get axes
+    //
+    if(vector.isXTime()) {
+      xTValues = vector.getU().getTimeArray();
+      size = xTValues.length;
+      xp = new float[size];
+      for(count=0; count < size; count++) {
+        xp[count] = (float)cg_.getXUtoP(xTValues[count]);
+      }
+    } else {
+      xValues = vector.getU().getXArray();
+      size = xValues.length;
+      xp = new float[size];
+      for(count=0; count < size; count++) {
+        xp[count] = (float)cg_.getXUtoP(xValues[count]);
+      }
+    }
+    //
+    if(vector.isYTime()) {
+      yTValues = vector.getU().getTimeArray();
+      size = yTValues.length;
+      yp = new float[size];
+      for(count=0; count < size; count++) {
+        yp[count] = (float)cg_.getYUtoP(yTValues[count]);
+      }
+    } else {
+      yValues = vector.getU().getYArray();
+      size = yValues.length;
+      yp = new float[size];
+      for(count=0; count < size; count++) {
+        yp[count] = (float)cg_.getYUtoP(yValues[count]);
+      }
+    }
+    //
+    // get u & v
+    //
+    uValues = vector.getU().getZArray();
+    vValues = vector.getV().getZArray();
+    //
+    xtail = new int[uValues.length];
+    ytail = new int[uValues.length];
+    count = 0;
+//    int nx = xp.length;
+    int ny = yp.length;
+    int idx_ny;
+    for(int i=0; i < xp.length; i++) {
+      idx_ny = i*ny;
+      for(int j=0; j < yp.length; j++) {
+        idx = j + idx_ny;
+        if(Double.isNaN(uValues[idx]) || Double.isNaN(vValues[idx])) continue;
+        orgX = xPtoD(xp[i]);
+        orgY = yPtoD(yp[j]);
+        xtail[count] = (int)orgX;
+        ytail[count] = (int)orgY;
+        vdx = uValues[idx]*scale;
+        vdy = vValues[idx]*scale;
+        if(angle != 0.0) {
+          vx = (float)(vdx*Math.cos(angle)-vdy*Math.sin(angle));
+          vy = (float)(vdy*Math.cos(angle)+vdx*Math.sin(angle));
+        } else {
+          vx = (float)vdx;
+          vy = (float)vdy;
+        }
+        xphead = xp[i] + vx;
+        yphead = yp[j] + vy;
+        //
+        // draw line
+        //
+        gp = new GeneralPath();
+        gp.moveTo(orgX, orgY);
+        headX = xPtoD(xphead);
+        headY = yPtoD(yphead);
+        gp.lineTo(headX, headY);
+        //
+        // draw head
+        //
+        //        if(true) continue;
+        vclen = (float)Math.sqrt((double)(vx*vx+vy*vy));
+        if(vclen == 0.0) {
+          g.drawLine((int)headX, (int)headY, (int)headX, (int)headY);
+        } else {
+          if(attr_.getVectorStyle() != VectorAttribute.NO_HEAD) {
+            if(attr_.getVectorStyle() == VectorAttribute.HEAD) {
+              // unscaled head
+              tScale = fixedScale/vclen;
+              hx1 = xPtoD(xphead + (-vx-0.35f*vy)*tScale);
+              hy1 = yPtoD(yphead + (-vy+0.35f*vx)*tScale);
+              hx2 = xPtoD(xphead + (-vx+0.35f*vy)*tScale);
+              hy2 = yPtoD(yphead + (-vy-0.35f*vx)*tScale);
+              gp.moveTo(hx1, hy1);
+              gp.lineTo(headX, headY);
+              gp.lineTo(hx2, hy2);
+            } else {
+              // scaled head
+              if(vclen >= maxSize) {
+                tScale = maxSize*headScale/vclen;
+              } else if(vclen <= minSize) {
+                tScale = minSize*headScale/vclen;
+              } else {
+                tScale = headScale;
+              }
+              hx1 = xPtoD(xphead + (-vx-0.35f*vy)*tScale);
+              hy1 = yPtoD(yphead + (-vy+0.35f*vx)*tScale);
+              hx2 = xPtoD(xphead + (-vx+0.35f*vy)*tScale);
+              hy2 = yPtoD(yphead + (-vy-0.35f*vx)*tScale);
+              gp.moveTo(hx1, hy1);
+              gp.lineTo(headX, headY);
+              gp.lineTo(hx2, hy2);
+            }
+          }
+        }
+        count++;
+        g2.draw(gp);
+      }
+    }
+    g2.setStroke(savedStroke);
+    //
+    // draw mark
+    //
+    if(attr_.getOriginStyle() == VectorAttribute.MARK) {
+      g.setColor(attr_.getMarkColor());
+      drawMark(g, xtail, ytail, xtail.length, attr_);
+    }
+  }
+
+  private float xPtoD(float xp) {
+    return slope_*xp + xoff_;
+  }
+
+  private float yPtoD(float yp) {
+    return yoff_ - slope_*yp;
+  }
+  /**
+   * Draw a mark at the requested location. This routine is used by
+   * VectorCartesianGraph and VectorKey.
+   *
+   * @param g Graphics object
+   * @param xp horizontal coordinate
+   * @param yp vertical coordinate
+   * @param attr vector attribute
+   * @see VectorKey
+   */
+  protected void drawMark(Graphics g, int[] xp, int[] yp,
+                          int npoints, VectorAttribute attr) {
+    Layer ly = cg_.getLayer();
+
+    PlotMark pm = new PlotMark(attr.getMark());
+    pm.setMarkHeightP(attr.getMarkHeightP());
+
+    for(int i=0; i < npoints; i++) {
+      pm.paintMark(g, ly, xp[i], yp[i]);
+    }
+  }
+
+  /**
+   * Default constructor.
+   *
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public VectorCartesianRenderer(CartesianGraph cg) {
+    this(cg, (SGTVector)null, null);
+  }
+  /**
+   * Construct a <code>VectorCartesianRenderer</code>. The default
+   * <code>VectorAttribute</code> will be used.
+   *
+   * @param cg the parent <code>CartesianGraph</code>
+   * @param data an <code>SGTVector</code> object
+   *
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public VectorCartesianRenderer(CartesianGraph cg, SGTVector vector) {
+    this(cg, vector, null);
+    cg_ = cg;
+    vector_ = vector;
+  }
+  /**
+   * Construct a <code>VectorCartesianRenderer</code>.
+   *
+   * @param cg the parent <code>CartesianGraph</code>
+   * @param vector a <code>SGTVector</code>
+   * @param attr the <code>VectorAttribute</code>
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public VectorCartesianRenderer(CartesianGraph cg,
+                                 SGTVector vector,
+                                 VectorAttribute attr) {
+    cg_ = cg;
+    vector_ = vector;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Construct a <code>VectorCartesianRenderer</code>.
+   *
+   * @param cg the parent <code>CartesianGraph</code>
+   * @param col a <code>Collection</code> of <code>SGTVector</code> objects
+   * @param attr the <code>VectorAttribute</code>
+   * @see CartesianGraph
+   * @see Graph
+   **/
+  public VectorCartesianRenderer(CartesianGraph cg, Collection col,
+                                 VectorAttribute attr) {
+    cg_ = cg;
+    collection_ = col;
+    attr_ = attr;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Render the <code>SGTData</code>. This method should not
+   * be directly called.
+   *
+   * @param g graphics context
+   *
+   * @see Pane#draw
+   */
+  public void draw(Graphics g) {
+    VectorAttribute attr;
+    Object vector;
+
+    if(cg_.clipping_) {
+      int xmin, xmax, ymin, ymax;
+      int x, y, width, height;
+      if(cg_.xTransform_.isSpace()) {
+        xmin = cg_.getXUtoD(cg_.xClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.xClipRange_.end);
+      } else {
+        xmin = cg_.getXUtoD(cg_.tClipRange_.start);
+        xmax = cg_.getXUtoD(cg_.tClipRange_.end);
+      }
+      if(cg_.yTransform_.isSpace()) {
+        ymin = cg_.getYUtoD(cg_.yClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.yClipRange_.end);
+      } else {
+        ymin = cg_.getYUtoD(cg_.tClipRange_.start);
+        ymax = cg_.getYUtoD(cg_.tClipRange_.end);
+      }
+      if(xmin < xmax) {
+        x = xmin;
+        width = xmax - xmin;
+      } else {
+        x=xmax;
+        width = xmin - xmax;
+      }
+      if(ymin < ymax) {
+        y = ymin;
+        height = ymax - ymin;
+      } else {
+        y = ymax;
+        height = ymin - ymax;
+      }
+      g.setClip(x, y, width, height);
+    }
+    if(attr_ == null) {
+      attr = new VectorAttribute(1.0,
+                                 cg_.getPane().getComponent().getForeground());
+    } else {
+      attr = attr_;
+    }
+    g.setColor(attr.getVectorColor());
+    if(collection_ == null) {
+      drawVector(g, vector_, attr);
+    } else {
+      for(Enumeration li = collection_.elements(); li.hasMoreElements();) {
+        vector = li.nextElement();
+        if(vector instanceof SGTVector) {
+          drawVector(g, (SGTVector)vector, attr);
+        }
+      }
+    }
+
+    //
+    // reset clip
+    //
+    Rectangle rect = cg_.getLayer().getPane().getBounds();
+    g.setClip(rect);
+  }
+  /**
+   * Set the <code>VectorAttribute</code>. The line appearance is controlled by
+   * this object.
+   *
+   * @param l <code>VectorAttribute</code>
+   **/
+  public void setVectorAttribute(VectorAttribute l) {
+    if(attr_ != null) attr_.removePropertyChangeListener(this);
+    attr_ = l;
+    if(attr_ != null) attr_.addPropertyChangeListener(this);
+  }
+  /**
+   * Get the <code>VectorAttribute</code>.
+   *
+   * @return <code>VectorAttribute</code>
+   **/
+  public VectorAttribute getVectorAttribute() {
+    return attr_;
+  }
+  /**
+   * Test if a <code>Collection</code> of <code>SGTVector</code>
+   * was using to construct this renderer.
+   *
+   * @return true if <code>Collection</code> was used
+   */
+  public boolean hasCollection() {
+    return (collection_ != null);
+  }
+  /**
+   * Get the <code>Collection</code> of <code>SGTVector</code> objects.
+   *
+   * @return <code>Collection</code>
+   */
+  public Collection getCollection() {
+    return collection_;
+  }
+  /**
+   * Get the <code>SGTVector</code> object.
+   *
+   * @return <code>SGTVector</code>
+   */
+  public SGTVector getVector(){
+    return vector_;
+  }
+  /**
+   * Get the associated <code>CartesianGraph</code> object.
+   *
+   * @return <code>CartesianGraph</code>
+   */
+  public CartesianGraph getCartesianGraph() {
+    return cg_;
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    //      if(Debug.EVENT) {
+    //        System.out.println("VectorCartesianRenderer: " + evt);
+    //        System.out.println("                       " + evt.getPropertyName());
+    //      }
+    modified("VectorCartesianRenderer: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  public SGTData getDataAt(Point pt) {
+    return null;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorKey.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorKey.java
new file mode 100755
index 0000000..8b4805b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/VectorKey.java
@@ -0,0 +1,910 @@
+/*
+ * $Id: VectorKey.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Debug;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Stroke;
+import java.awt.BasicStroke;
+import java.awt.geom.GeneralPath;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.text.DecimalFormat;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * <code>VectorKey</code> is used to create a key for the
+ * <code>VectorCartesianRenderer</code>. Multiple
+ * lines can be included in the key.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 2.1
+**/
+public class VectorKey implements Cloneable,
+    DataKey, Moveable, PropertyChangeListener {
+  private String ident_;
+  /** @directed */
+  private Layer layer_;
+  /** @link aggregation
+   * @supplierCardinality *
+   * @label vectors*/
+  /*#VectorCartesianRenderer lnkVectorCartesianRenderer; */
+  private Vector vectors_;
+  /**
+     *@link aggregation
+     *     @associates <{SGLabel}>
+     * @label label
+     * @supplierCardinality *
+     * @undirected
+     */
+  /* private Vector lnkSGLabel; */
+  private Vector label_;
+  private Vector scaleLabel_;
+  private int columns_;
+  private int style_;
+  private int valign_;
+  private int halign_;
+  private Point2D.Double porigin_;
+  private double vectorLengthP_;
+  private int maxLabelLength_;
+  private int maxLabelHeight_;
+  private int maxScaleLength_;
+  private String floatScaleFormat_ = "###.##";
+  private String expScaleFormat_ = "0.####E0";
+  private DecimalFormat floatFormat_;
+  private DecimalFormat expFormat_;
+  private float xoff_;
+  private float yoff_;
+  private float slope_;
+  private boolean selected_;
+  private boolean selectable_;
+  private boolean visible_;
+  private boolean moveable_;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private static final int VERTICAL_BORDER_ = 3;
+  private static final int HORIZONTAL_BORDER_ = 15;
+  private static final int COLUMN_SPACE_ = 10;
+  private static final int ROW_SPACE_ = 3;
+  private static final int LABEL_SPACE_ = 10;
+  private static final int SCALE_SPACE_ = 7;
+  /**
+   * Use plain line border.
+   */
+  public static final int PLAIN_LINE = 0;
+  /**
+   * Use raised border.
+   */
+  public static final int RAISED = 1;
+  /**
+   * Do not draw a border.
+   */
+  public static final int NO_BORDER = 2;
+  /**
+   * Align to top of key.
+   */
+  public static final int TOP = 0;
+  /**
+   * Align to middle of key.
+   */
+  public static final int MIDDLE = 1;
+  /**
+   * Align to bottom of key.
+   */
+  public static final int BOTTOM = 2;
+  /**
+   * Align to left of key.
+   */
+  public static final int LEFT = 0;
+  /**
+   * Align to center of key.
+   */
+  public static final int CENTER = 1;
+  /**
+   * Align to right of key.
+   */
+  public static final int RIGHT = 2;
+
+
+  /**
+   * Default constructor.
+   */
+  public VectorKey() {
+    this(new Point2D.Double(0.0, 0.0), BOTTOM, LEFT);
+  }
+  /**
+   * Create <code>VectorKey</code>.
+   */
+  public VectorKey(Point2D.Double loc,int valign,int halign) {
+    porigin_ = loc;
+    valign_ = valign;
+    halign_ = halign;
+    vectors_ = new Vector(2,2);
+    label_ = new Vector(2,2);
+    scaleLabel_ = new Vector(2,2);
+    //
+    // set defaults
+    //
+    style_ = PLAIN_LINE;
+    columns_ = 1;
+    ident_ = "";
+    vectorLengthP_ = 0.3f;
+    selected_ = false;
+    selectable_ = true;
+    visible_ = true;
+    moveable_ = true;
+
+    floatFormat_ = new DecimalFormat(floatScaleFormat_);
+    expFormat_ = new DecimalFormat(expScaleFormat_);
+  }
+  /**
+   * Create of copy of VectorKey.
+   */
+  public LayerChild copy() {
+    VectorKey newKey;
+    try {
+      newKey = (VectorKey)clone();
+    } catch (CloneNotSupportedException e) {
+      newKey = new VectorKey();
+    }
+    newKey.vectors_ = new Vector(2,2);
+    newKey.label_ = new Vector(2,2);
+    return newKey;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  public boolean isMoveable() {
+    return moveable_;
+  }
+  public void setMoveable(boolean moveable) {
+    moveable_ = moveable;
+  }
+  /**
+   * Set parent layer.
+   *
+   * @param l parent layer
+   */
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  /**
+   * Get layer.
+   *
+   * @return layer
+   */
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+
+  public void modified(String mess) {
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  /**
+   * Set VectorKey identifier.
+   *
+   * @param id key identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get VectorKey identifier
+   *
+   * @return identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set line length.
+   *
+   * @param len line length
+   */
+  public void setVectorLengthP(double len) {
+    if(vectorLengthP_ != len) {
+      vectorLengthP_ = len;
+      modified("VectorKey: setVectorLengthP()");
+    }
+  }
+  /**
+   * @since 3.0
+   */
+  public void setLineLengthP(double len) {
+    setVectorLengthP(len);
+  }
+  /**
+   * Get line length
+   *
+   * @return line length
+   */
+  public double getVectorLengthP() {
+    return vectorLengthP_;
+  }
+  /**
+   * Set the number of columns.
+   *
+   * @param col number of columns
+   */
+  public void setColumns(int col) {
+    if(columns_ != col) {
+      columns_ = col;
+      modified("VectorKey: setColumms()");
+    }
+  }
+  /**
+   * Get the number of columns.
+   *
+   * @return number of columns
+   */
+  public int getColumns() {
+    return columns_;
+  }
+  /**
+   * Set border style.
+   *
+   * @param style border style
+   * @see #PLAIN_LINE
+   * @see #RAISED
+   * @see #NO_BORDER
+   */
+  public void setBorderStyle(int style) {
+    if(style_ != style) {
+      style_ = style;
+      modified("VectorKey: setBorderStyle()");
+    }
+  }
+  /**
+   * Get border style.
+   *
+   * @return border style
+   */
+  public int getBorderStyle() {
+    return style_;
+  }
+  /**
+   * Set alignment.
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   */
+  public void setAlign(int vert,int horz) {
+    if(valign_ != vert || halign_ != horz) {
+      valign_ = vert;
+      halign_ = horz;
+      modified("VectorKey: setAlign()");
+    }
+  }
+  /**
+   * Set vertical alignment
+   *
+   * @param vert vertical alignment
+   */
+  public void setVAlign(int vert) {
+    if(valign_ != vert) {
+      valign_ = vert;
+      modified("VectorKey: setVAlign()");
+    }
+  }
+  /**
+   * Set horizontal alignment
+   *
+   * @param horz horizontal alignment
+   */
+  public void setHAlign(int horz) {
+    if(halign_ != horz) {
+      halign_ = horz;
+      modified("VectorKey: setHAlign()");
+    }
+  }
+  /**
+   * Get vertical alignment
+   *
+   * @return vertical alignment
+   */
+  public int getVAlign() {
+    return valign_;
+  }
+  /**
+   * Get horizontal alignment
+   *
+   * @return horizontal alignment
+   */
+  public int getHAlign() {
+    return halign_;
+  }
+  /**
+   * Set location of key
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @param loc key location
+   */
+  public void setLocationP(Point2D.Double loc) {
+    if(porigin_ == null || !porigin_.equals(loc)) {
+      Point2D.Double temp = porigin_;
+      porigin_ = loc;
+      changes_.firePropertyChange("location",
+                                  temp,
+                                  porigin_);
+      modified("VectorKey: setLocationP()");
+    }
+  }
+  /**
+   * Set the bounds, in physical units, of the <code>VectorKey</code>
+   */
+  public void setBoundsP(Rectangle2D.Double r) {
+    setLocationP(new Point2D.Double(r.x, r.y));
+  }
+  public Rectangle2D.Double getBoundsP() {
+    throw new MethodNotImplementedError();
+  }
+  /**
+   * Get location of key.
+   *
+   * @return Key location
+   */
+  public Point2D.Double getLocationP() {
+    return porigin_;
+  }
+  /**
+   * Add a VectorCartesianRenderer and label to the VectorKey.
+   *
+   * @param line VectorCartesianRenderer object
+   * @param label descriptive label
+   */
+  public void addVectorGraph(VectorCartesianRenderer vector, SGLabel label) {
+    vectors_.addElement(vector);
+    label.setLayer(layer_);
+    label.setMoveable(false);
+    label.setSelectable(false);
+    label_.addElement(label);
+    SGLabel scale = new SGLabel("scale label",
+                                " ",
+                                label.getHeightP(),
+                                label.getLocationP(),
+                                label.getVAlign(),
+                                label.getHAlign());
+    scale.setFont(label.getFont());
+    scale.setLayer(label.getLayer());
+    scale.setMoveable(false);
+    scale.setSelectable(false);
+    scaleLabel_.addElement(scale);
+    ((VectorAttribute)vector.getAttribute()).addPropertyChangeListener(this);
+    modified("VectorKey: addVectorGraph()");
+  }
+  /**
+   * Add a VectorCartesianRenderer and label to the VectorKey.
+   *
+   * @param rend CartesianRenderer object
+   * @param label descriptive label
+   * @since 3.0
+   */
+  public void addGraph(CartesianRenderer rend, SGLabel label)
+      throws IllegalArgumentException {
+    if(!(rend instanceof VectorCartesianRenderer))
+      throw new IllegalArgumentException("Renderer is not a VectorCartesianRenderer");
+    addVectorGraph((VectorCartesianRenderer)rend, label);
+  }
+  /**
+   * Remove a line from the VectorKey.
+   *
+   */
+  public void removeVectorGraph(SGLabel label) {
+  }
+  /**
+   * Remove a line from the VectorKey.
+   *
+   */
+  public void removeVectorRenderer(VectorCartesianRenderer line) {
+  }
+  /**
+   * Remove a line from the VectorKey.
+   *
+   */
+  public void removeVectorGraph(String ident) {
+  }
+  /**
+   * Remove all lines from the VectorKey.
+   */
+  public void clearAll() {
+    VectorAttribute attr;
+    for(Enumeration e = vectors_.elements(); e.hasMoreElements(); ) {
+      attr = (VectorAttribute)((VectorCartesianRenderer)e.nextElement()).getAttribute();
+      attr.removePropertyChangeListener(this);
+    }
+    vectors_.removeAllElements();
+    label_.removeAllElements();
+    modified("VectorKey: clearAll()");
+  }
+  /**
+   * Remove data from key by id.
+   */
+  public void clear(String data_id) {
+    VectorCartesianRenderer vcr;
+    int indx = -1;
+    for(Enumeration it = vectors_.elements(); it.hasMoreElements();) {
+      indx++;
+      vcr = (VectorCartesianRenderer)it.nextElement();
+      //        if(pcr.getLine().getId().equals(data_id)) {
+      //  	pcr.getAttribute().removePropertyChangeListener(this);
+      //  	points_.removeElement(lcr);
+      //  	label_.removeElementAt(indx);
+      //  	modified("VectorKey: clear()");
+      //  	break;
+      //        }
+    }
+  }
+  /**
+   * Return height of key row in pixels.
+   */
+  public int getRowHeight() {
+    Rectangle bounds;
+    bounds = getBounds();
+    return ROW_SPACE_ + maxLabelHeight_;
+  }
+  /**
+   * Draw the Key.
+   */
+  public void draw(Graphics g) {
+    double maxLabelLength, maxLabelHeight;
+    int numLines, numRows, i;
+    float vectorLength;
+    float vectorLengthU;
+    int col, row, ytemp;
+    double xloc, labelSpace, scaleSpace, scaleLength;
+    double[] xp, yp;
+    int[] xd, yd;
+    int[] xout, yout;
+    float hx1, hx2;
+    float hy1, hy2;
+    float headX, headY;
+    float orgX, orgY;
+    float xphead, yphead;
+    float tScale, fixedScale;
+    float scale;
+    float headScale;
+    float minSize;
+    float maxSize;
+    Rectangle bounds;
+    VectorCartesianRenderer render = null;
+    SGLabel label;
+    SGLabel scaleLabel;
+    String scaleStr;
+    VectorAttribute attr = null;
+    Graphics2D g2 = (Graphics2D)g;
+    GeneralPath gp;
+    Stroke savedStroke = g2.getStroke();
+    BasicStroke stroke;
+    slope_ = (float)layer_.getXSlope();
+    xoff_ = (float)layer_.getXOffset();
+    yoff_ = (float)layer_.getYOffset();
+    //
+    numLines = vectors_.size();
+    if((numLines <= 0) || !visible_) return;
+
+    numRows = numLines/columns_;
+    if(numLines%columns_ != 0) numRows++;
+
+    xp = new double[columns_];
+    xd = new int[columns_];
+    yp = new double[numRows];
+    yd = new int[numRows];
+    xout = new int[2];
+    yout = new int[2];
+
+    g.setColor(layer_.getPane().getComponent().getForeground());
+    bounds = getBounds();
+    //
+    // compute location of rows and columns in device and physical coordinates
+    //
+    vectorLength = xPtoD((float)vectorLengthP_) - xPtoD(0.0f);
+    labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0);
+    scaleLength = layer_.getXDtoP(maxScaleLength_) - layer_.getXDtoP(0);
+    scaleSpace = layer_.getXDtoP(SCALE_SPACE_) - layer_.getXDtoP(0);
+    //
+    yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_;
+    yp[0] = layer_.getYDtoP(yd[0]);
+    for(i=1; i < numRows; i++) {
+      yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_;
+      yp[i] = layer_.getYDtoP(yd[i]);
+    }
+    xd[0] = bounds.x + HORIZONTAL_BORDER_;
+    xp[0] = layer_.getXDtoP(xd[0]);
+    for(i=1; i < columns_; i++) {
+      xd[i] = xd[i-1] + COLUMN_SPACE_ + (int)vectorLength +
+        SCALE_SPACE_ + maxScaleLength_ +
+        LABEL_SPACE_ + maxLabelLength_;
+      xp[i] = layer_.getXDtoP(xd[i]);
+    }
+    //
+    row = 0;
+    col = 0;
+    Object obj;
+    Enumeration labelIt = label_.elements();
+    Enumeration scaleIt = scaleLabel_.elements();
+    for(Enumeration lineIt = vectors_.elements(); lineIt.hasMoreElements();) {
+      obj = lineIt.nextElement();
+      render = (VectorCartesianRenderer)obj;
+      attr = (VectorAttribute)render.getAttribute();
+      label = (SGLabel)labelIt.nextElement();
+      scaleLabel = (SGLabel)scaleIt.nextElement();
+      //
+      // draw line
+      //
+      g2.setColor(attr.getVectorColor());
+      stroke = new BasicStroke(attr.getWidth(),
+                               attr.getCapStyle(),
+                               attr.getMiterStyle(),
+                               attr.getMiterLimit());
+      scale = (float)attr.getVectorScale();
+      headScale = (float)attr.getHeadScale()*0.94386f;
+      fixedScale = (float)(headScale*attr.getHeadFixedSize());
+      minSize = (float)attr.getHeadMinSize();
+      maxSize = (float)attr.getHeadMaxSize();
+      vectorLengthU = (float)(vectorLengthP_/scale);
+      g2.setStroke(stroke);
+      gp = new GeneralPath();
+      orgX = (float)xd[col];
+      orgY = (float)(yd[row] - maxLabelHeight_/2);
+      headX = orgX + vectorLength;
+      headY = orgY;
+      xphead = xDtoP(headX);
+      yphead = yDtoP(headY);
+      gp.moveTo(orgX, orgY);
+      gp.lineTo(headX, headY);
+      //
+      // add head
+      //
+      if(vectorLength == 0.0) {
+        g.drawLine((int)headX, (int)headY, (int)headX, (int)headY);
+      } else {
+        if(attr.getVectorStyle() != VectorAttribute.NO_HEAD) {
+          if(attr.getVectorStyle() == VectorAttribute.HEAD) {
+            // unscaled head
+            tScale = fixedScale;
+            hx1 = xPtoD(xphead - tScale);
+            hy1 = yPtoD(yphead + 0.35f*tScale);
+            hx2 = xPtoD(xphead - tScale);
+            hy2 = yPtoD(yphead - 0.35f*tScale);
+            gp.moveTo(hx1, hy1);
+            gp.lineTo(headX, headY);
+            gp.lineTo(hx2, hy2);
+          } else {
+            // scaled head
+            if(vectorLengthP_ >= maxSize) {
+              tScale = maxSize*headScale;
+            } else if(vectorLengthP_ <= minSize) {
+              tScale = minSize*headScale;
+            } else {
+              tScale = (float)(vectorLengthP_*headScale);
+            }
+            hx1 = xPtoD(xphead - tScale);
+            hy1 = yPtoD(yphead + 0.35f*tScale);
+            hx2 = xPtoD(xphead - tScale);
+            hy2 = yPtoD(yphead - 0.35f*tScale);
+            gp.moveTo(hx1, hy1);
+            gp.lineTo(headX, headY);
+            gp.lineTo(hx2, hy2);
+          }
+        }
+      }
+
+      g2.draw(gp);
+      g2.setStroke(savedStroke);
+      //
+      // draw mark
+      //
+      xout[0] = (int)orgX;
+      yout[0] = (int)orgY;
+      if(attr.getOriginStyle() == VectorAttribute.MARK) {
+        g.setColor(attr.getMarkColor());
+        render.drawMark(g, xout, yout, 1, attr);
+      }
+      //
+      // scale label
+      //
+      xloc = xp[col] + vectorLengthP_ + scaleSpace;
+      if(vectorLengthU > 1000.0 || vectorLengthU < 0.01) {
+        scaleStr = expFormat_.format(vectorLengthU);
+      } else {
+        scaleStr = floatFormat_.format(vectorLengthU);
+      }
+      scaleLabel.setText(scaleStr);
+      scaleLabel.setLocationP(new Point2D.Double(xloc, yp[row]));
+
+      //
+      // user label
+      //
+      xloc = xloc + scaleLength + labelSpace;
+      label.setLocationP(new Point2D.Double(xloc, yp[row]));
+      try {
+        scaleLabel.draw(g);
+        label.draw(g);
+      } catch (SGException e) { System.out.println(e);}
+      //
+      col++;
+      if(col >= columns_) {
+        col = 0;
+        row++;
+      }
+    }
+    switch(style_) {
+    case PLAIN_LINE:
+      g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+      break;
+    case RAISED:
+      break;
+    default:
+    case NO_BORDER:
+    }
+  }
+
+  private float xPtoD(float xp) {
+    return slope_*xp + xoff_;
+  }
+
+  private float yPtoD(float yp) {
+    return yoff_ - slope_*yp;
+  }
+
+  private float xDtoP(float xd) {
+    return (xd - xoff_)/slope_;
+  }
+
+  private float yDtoP(float yd) {
+    return (yoff_ - yd)/slope_;
+  }
+
+  /**
+   * Get the bounding rectangle.
+   *
+   * @return bounding rectangle
+   */
+  public Rectangle getBounds() {
+    int vectorLength;
+    int numLines, rows;
+    int x, y, height, width;
+
+    numLines = vectors_.size();
+    if(numLines <= 0) return new Rectangle(0, 0, 0, 0);
+    //
+    // find longest label and scale
+    //
+    maxLabelLength_ = 0;
+    maxLabelHeight_ = 0;
+    maxScaleLength_ = 0;
+    Object obj;
+    VectorCartesianRenderer render;
+    VectorAttribute attr;
+    double vectorLengthU;
+    Enumeration lineIt = vectors_.elements();
+    Enumeration scaleIt = scaleLabel_.elements();
+    SGLabel label;
+    String scaleStr;
+    SGLabel scaleLabel;
+    for(Enumeration it = label_.elements(); it.hasMoreElements();) {
+      label = (SGLabel)it.nextElement();
+      Rectangle sz = label.getBounds();
+      maxLabelLength_ = Math.max(maxLabelLength_, sz.width);
+      maxLabelHeight_ = Math.max(maxLabelHeight_, sz.height);
+      //
+      obj = lineIt.nextElement();
+      render = (VectorCartesianRenderer)obj;
+      attr = (VectorAttribute)render.getAttribute();
+      vectorLengthU = vectorLengthP_/attr.getVectorScale();
+      if(vectorLengthU > 1000.0 || vectorLengthU < 0.01) {
+        scaleStr = expFormat_.format(vectorLengthU);
+      } else {
+        scaleStr = floatFormat_.format(vectorLengthU);
+      }
+      scaleLabel = (SGLabel)scaleIt.nextElement();
+      scaleLabel.setText(scaleStr);
+      sz = scaleLabel.getBounds();
+      maxScaleLength_ = Math.max(maxScaleLength_, sz.width);
+    }
+    //
+    rows = numLines/columns_;
+    if(numLines%columns_ != 0) rows++;
+    vectorLength = layer_.getXPtoD(vectorLengthP_) - layer_.getXPtoD(0.0f);
+    width = 2*HORIZONTAL_BORDER_ +
+      columns_*(vectorLength + SCALE_SPACE_ + maxScaleLength_ +
+                LABEL_SPACE_ + maxLabelLength_) +
+      (columns_ - 1)*COLUMN_SPACE_;
+    height = 2*VERTICAL_BORDER_ + rows*maxLabelHeight_ +
+      (rows-1)*ROW_SPACE_;
+    // temp fudge
+    height = height + 5;
+    //
+    x = layer_.getXPtoD(porigin_.x);
+    y = layer_.getYPtoD(porigin_.y);
+    switch(halign_) {
+    case RIGHT:
+      x = x - width;
+      break;
+    case CENTER:
+      x = x - width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y - height;
+      break;
+    case MIDDLE:
+      y = y - height/2;
+    }
+    return new Rectangle(x, y, width, height);
+  }
+  public Point getLocation() {
+    Rectangle bnds = getBounds();
+    return new Point(bnds.x, bnds.y);
+  }
+  public void setLocation(Point loc) {
+    Rectangle bnds = getBounds();
+    setBounds(loc.x, loc.y, bnds.width, bnds.height);
+  }
+  /**
+   * Set the bounds, in pixels, of the <code>VectorKey</code>
+   */
+  public void setBounds(Rectangle r) {
+    setBounds(r.x, r.y, r.width, r.height);
+  }
+  /**
+   * Set the bounds, in pixels, of the <code>VectorKey</code>
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    switch(halign_) {
+    case RIGHT:
+      x = x + width;
+      break;
+    case CENTER:
+      x = x + width/2;
+    }
+    switch(valign_) {
+    case BOTTOM:
+      y = y + height;
+      break;
+    case MIDDLE:
+      y = y + height/2;
+    }
+    double xp = layer_.getXDtoP(x);
+    double yp = layer_.getYDtoP(y);
+    if(porigin_.x != xp || porigin_.y != yp) {
+      Point2D.Double temp = porigin_;
+      porigin_.x = xp;
+      porigin_.y = yp;
+      changes_.firePropertyChange("location",
+                                  temp,
+                                  new Point2D.Double(xp, yp));
+      modified("VectorKey: setBounds()");
+    }
+  }
+  Object getObjectAt(Point pt) {
+    Rectangle lbnds;
+    Rectangle bounds;
+    VectorCartesianRenderer vector;
+    int[] xout, yout;
+    int[] xd, yd;
+    int numLines, numRows;
+    int vectorLength;
+    double labelSpace, scaleSpace;
+    int i;
+
+    numLines = vectors_.size();
+    if(numLines <= 0) return null;
+
+    numRows = numLines/columns_;
+    if(numLines%columns_ != 0) numRows++;
+
+    xd = new int[columns_];
+    yd = new int[numRows];
+    xout = new int[2];
+    yout = new int[2];
+    bounds = getBounds();
+    //
+    // compute location of rows and columns in device and physical coordinates
+    //
+    vectorLength = layer_.getXPtoD(vectorLengthP_) - layer_.getXPtoD(0.0);
+    labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0);
+    scaleSpace = layer_.getXDtoP(SCALE_SPACE_) - layer_.getXDtoP(0);
+    //
+    yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_;
+    for(i=1; i < numRows; i++) {
+      yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_;
+    }
+    xd[0] = bounds.x + HORIZONTAL_BORDER_;
+    for(i=1; i < columns_; i++) {
+      xd[i] = xd[i-1] + COLUMN_SPACE_ + vectorLength + SCALE_SPACE_ +
+        maxScaleLength_ + LABEL_SPACE_ + maxLabelLength_;
+    }
+    // loop over all the lines
+    int row = 0;
+    int col = 0;
+    for(Enumeration lineIt = vectors_.elements(); lineIt.hasMoreElements();) {
+      vector = (VectorCartesianRenderer)lineIt.nextElement();
+      xout[0] = xd[col];
+      //        xout[1] = xout[0] + vectorLength + 2*LABEL_SPACE_ +
+      //                  maxScaleLenght_ + maxLabelLength_;
+      xout[1] = xout[0] + vectorLength + SCALE_SPACE_;
+      yout[0] = yd[row] - maxLabelHeight_;
+      yout[1] = yd[row];
+      lbnds = new Rectangle(xout[0], yout[0],
+                            xout[1] - xout[0],
+                            yout[1] - yout[0]);
+
+      if(lbnds.contains(pt)) {
+        return vector;
+      }
+      //
+      col++;
+      if(col >= columns_) {
+        col = 0;
+        row++;
+      }
+    }
+    if(bounds.contains(pt)) {
+      return this;
+    }
+    return null;
+  }
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + ident_;
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+  public void setVisible(boolean visible) {
+    if(visible_ != visible) {
+      visible_ = visible;
+      modified("VectorKey: setVisible()");
+    }
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    //      if(Debug.EVENT) {
+    //        System.out.println("VectorKey: " + evt);
+    //        System.out.println("         " + evt.getPropertyName());
+    //      }
+    modified("VectorKey: propertyChange(" +
+             evt.getSource().toString() + "[" +
+             evt.getPropertyName() + "]" + ")");
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/YearDecadeAxis.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/YearDecadeAxis.java
new file mode 100755
index 0000000..673c090
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/YearDecadeAxis.java
@@ -0,0 +1,111 @@
+/*
+ * $Id: YearDecadeAxis.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+/**
+ * Draws time axes using the year/decade style.
+ *
+ * <pre>
+ *            |..........|..........|..........|..........|
+ *                 84         85         86         87
+ *                               1980
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @see Axis
+ * @see TimeAxis
+ */
+class YearDecadeAxis implements TimeAxisStyle {
+  static final int DECADE_TEST__ = 1000;
+  static final String defaultMinorLabelFormat__ = "yy";
+  //  static final String defaultMajorLabelFormat__ = "yyyy";
+  static final String defaultMajorLabelFormat__ = "decade";
+  int defaultMinorLabelInterval_ = 2;
+  int defaultMajorLabelInterval_ = 1;
+  static final int defaultNumSmallTics__ = 0;
+  static final double incrementValue__ = 1.0;
+  static final int incrementUnits__ = GeoDate.YEARS;
+  /**
+   * YearDecadeAxis constructor.
+   *
+   * @param id axis identifier
+   **/
+  public YearDecadeAxis() {
+  }
+  public void computeDefaults(GeoDate delta) {
+    if(delta.getTime()/GeoDate.MSECS_IN_DAY > 2500) {
+      defaultMinorLabelInterval_ = 2;
+    } else {
+      defaultMinorLabelInterval_ = 1;
+    }
+  }
+  public double computeLocation(double prev,double now) {
+    return (prev + now)*0.5;
+  }
+  public int getMinorValue(GeoDate time) {
+    return time.getGMTYear() - (time.getGMTYear()/10)*10 + 1;
+  }
+  public int getMajorValue(GeoDate time) {
+    return (time.getGMTYear()/10)*10;
+  }
+  public boolean isRoomForMajorLabel(GeoDate delta) {
+    return delta.getTime()/GeoDate.MSECS_IN_DAY > DECADE_TEST__;
+  }
+  public boolean isStartOfMinor(GeoDate time) {
+    return (time.getGMTYear() % 10) == 0;
+  }
+  public String getDefaultMinorLabelFormat() {
+    return defaultMinorLabelFormat__;
+  }
+  public String getDefaultMajorLabelFormat() {
+    return defaultMajorLabelFormat__;
+  }
+  public int getDefaultNumSmallTics() {
+    return defaultNumSmallTics__;
+  }
+  public int getDefaultMajorLabelInterval() {
+    return defaultMajorLabelInterval_;
+  }
+  public int getDefaultMinorLabelInterval() {
+    return defaultMinorLabelInterval_;
+  }
+  public GeoDate getStartTime(TimeRange tRange) {
+    boolean time_increasing;
+    GeoDate time = null;
+    time_increasing = tRange.end.after(tRange.start);
+    try {
+      if(time_increasing) {
+        time = new GeoDate(1, 1, tRange.start.getGMTYear(), 0, 0, 0, 0);
+        if(!time.equals(tRange.start)) time.increment(1.0, GeoDate.YEARS);
+      } else {
+        time = new GeoDate(1, 1, tRange.end.getGMTYear(), 0, 0, 0, 0);
+        if(!time.equals(tRange.end)) time.increment(1.0, GeoDate.YEARS);
+      }
+    } catch (IllegalTimeValue e) {}
+    return time;
+  }
+  public double getIncrementValue() {
+    return incrementValue__;
+  }
+  public int getIncrementUnits() {
+    return incrementUnits__;
+  }
+  public String toString() {
+    return "YearDecadeAxis";
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolder.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolder.java
new file mode 100755
index 0000000..ac4b674
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolder.java
@@ -0,0 +1,972 @@
+/*
+ * $Id: AxisHolder.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import gov.noaa.pmel.sgt.*;
+import gov.noaa.pmel.util.*;
+import java.awt.*;
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.event.*;
+
+/**
+ * Contains the data necessary to instantiate an axis.
+ * This class is used with <code>DataGroup</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+public class AxisHolder implements Serializable {
+  private Vector changeListeners;
+
+  /**
+   * @label dataGroup
+   */
+  private DataGroup dataGroup_;
+  transient private ChangeEvent changeEvent_ = new ChangeEvent(this);
+  // general axis properties
+  /**
+   * axisType = DataGroup.PLAIN, DataGroup.TIME, or DataGroup.LOG
+   */
+  private int axisType = -1; // must be defined
+  /**
+   * axisOrientation = DataGroup.X_DIR or DataGroup.Y_DIR
+   */
+  private int axisOrientation = -1; // must be defined
+  /**
+   * transformType = DataGroup.LINEAR, DataGroup.LOG, DataGroup.REFERENCE
+   */
+  private int transformType = DataGroup.LINEAR;
+  private String transformGroup = "";
+  /**
+   * <pre>
+   * axisPosition = DataGroup.TOP, DataGroup.BOTTOM, (for x axes)
+   *                DataGroup.LEFT, DataGroup.RIGHT, (for y axes)
+   *                DataGroup.MANUAL
+   * </pre>
+   */
+  private int axisPosition = -1;
+  /**
+   * used if axisPosition = MANUAL, always computed
+   */
+  private Point2D.Double axisOriginP = new Point2D.Double(0.0, 0.0);
+  private boolean locationAtOrigin = false;
+  private Color axisColor = Color.black;
+  private boolean autoRange = true;
+  /**
+   * used if axisPosition = MANUAL, always computed
+   */
+  private Rectangle2D boundsP = new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0);
+//  private double originP = 0.0;  //  y origin for X_DIR, x origin for Y_DIR if axisPosition = MANUAL
+  private SoTRange userRange = new SoTRange.Double(1.0, 10.0, 1.0);
+  private Color labelColor = Color.black;
+  private Font labelFont = new Font("Helvetica", Font.ITALIC, 10);
+  private double labelHeightP = 0.15;
+  /**
+   * <pre>
+   * labelPosition = Axis.AUTO, Axis.POSITIVE_SIDE,
+   *                 Axis.NEGATIVE_SIDE, Axis.NO_LABEL
+   * </pre>
+   */
+  private int labelPosition = Axis.AUTO; // Expert
+  private double largeTicHeightP = 0.1; // Expert
+  private double smallTicHeightP = 0.05; // Expert
+  private int numSmallTics = 0;
+  private double thickTicWidth = 0.025; // Expert
+  /**
+   * <pre>
+   * ticPosition = Axis.AUTO, Axis.POSITIVE_SIDE,
+   *               Axis.NEGATIVE_SIDE, Axis.BOTH_SIDES
+   * </pre>
+   */
+  private int ticPosition = Axis.AUTO; // Expert
+  private SGLabel title = new SGLabel("title", "", 0.20,
+                                      new Point2D.Double(0.0, 0.0),
+                                      SGLabel.BOTTOM, SGLabel.LEFT);
+  private boolean titleAuto = true;
+  private boolean selectable = true;
+  private boolean visible = true;
+  // SpaceAxis properties
+  private String labelFormat = ""; // Expert
+  private int labelInterval = 2;
+  private int labelSignificantDigits = 2;
+  // TimeAxis properties defaults appropriate for MONTH_YEAR
+  private String minorFormat = "MMM"; // Expert
+  private String majorFormat = "yyyy"; // Expert
+  private int minorInterval = 2; // Expert
+  private int majorInterval = 1; // Expert
+  /**
+   * <pre>
+   * timeAxisStyle = TimeAxis.AUTO, TimeAxis.DAY_MONTH, TimeAxis.HOUR_DAY,
+   *                 TimeAxis.MINUTE_HOUR, TimeAxis.MONTH_YEAR,
+   *                 TimeAxis.YEAR_DECADE
+   * </pre>
+   */
+  private int timeAxisStyle = TimeAxis.AUTO;
+
+  private boolean suppressEvent_ = false;
+
+  /**
+   * Static code to make sure that dataGroup doesn't get serialized by
+   * XMLEncode
+   */
+  static {
+    try {
+      BeanInfo info = Introspector.getBeanInfo(AxisHolder.class);
+      PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+      for(int i=0; i < descriptors.length; i++) {
+        PropertyDescriptor pd = descriptors[i];
+        if(pd.getName().equals("dataGroup")) {
+          pd.setValue("transient", Boolean.TRUE);
+        }
+      }
+    } catch (IntrospectionException ie) {
+      ie.printStackTrace();
+    }
+  }
+
+  /**
+   * Default constructor.  The methods setAxisType, setAxisOrientation, and
+   * setDataGroup must be called.
+   */
+  public AxisHolder() {
+    title.setColor(Color.black);
+  }
+
+  /**
+   * Construct a new <code>AxisHolder</code>. This constructor includes the
+   * necessary fields.
+   *
+   * @param type Type of axis
+   * @param dir Direction of axis
+   * @param dataGroup DataGroup parent
+   * @see #setAxisType setAxisType
+   * @see #setAxisOrientation setAxisOrientation
+   * @see #setDataGroup setDataGroup
+   */
+  public AxisHolder(int type, int dir, DataGroup dataGroup) {
+    axisType = type;
+    axisOrientation = dir;
+    dataGroup_ = dataGroup;
+    if(axisOrientation == DataGroup.X_DIR) {
+      title.setText("X Axis");
+      axisPosition = DataGroup.BOTTOM;
+    } else {
+      title.setText("Y Axis");
+      axisPosition = DataGroup.LEFT;
+    }
+    transformGroup = dataGroup.getId();
+    title.setColor(Color.black);
+  }
+
+  /**
+   * Get the <code>DataGroup</code> parent.
+   * @return DataGroup parent
+   */
+  public DataGroup getDataGroup() {
+    return dataGroup_;
+  }
+
+  /**
+   * Set the parent <code>DataGroup</code>. No default.
+   *
+   * @param dataGroup Parent object to AxisHolder
+   */
+  public void setDataGroup(DataGroup dataGroup) {
+    dataGroup_ = dataGroup;
+    transformGroup = dataGroup_.getId();
+  }
+
+  /**
+   * Test if the axis time.
+   * @return True if axis is time.
+   */
+  public boolean isTime() {
+    return axisType == DataGroup.TIME;
+  }
+
+  /**
+   * Remove a <code>ChangeListener</code>.
+   * @param l ChangeListener to remove
+   */
+  public synchronized void removeChangeListener(ChangeListener l) {
+    if (changeListeners != null && changeListeners.contains(l)) {
+      Vector v = (Vector) changeListeners.clone();
+      v.removeElement(l);
+      changeListeners = v;
+    }
+  }
+
+  /**
+   * Add a <code>ChangeListener</code>.  Listener will be notified if a change
+   * occurs.
+   * @param l ChangeListener to add.
+   */
+  public synchronized void addChangeListener(ChangeListener l) {
+    Vector v = changeListeners == null ? new Vector(2) : (Vector) changeListeners.clone();
+    if (!v.contains(l)) {
+      v.addElement(l);
+      changeListeners = v;
+    }
+  }
+
+  /**
+   * Remove all <code>ChangeListener</code>s that implement the
+   * <code>DesignListener</code> interface.
+   *
+   * @see DesignListener
+   */
+  public synchronized void removeDesignChangeListeners() {
+    if(changeListeners != null) {
+      Vector v = (Vector) changeListeners.clone();
+      Iterator iter = v.iterator();
+      while(iter.hasNext()) {
+        Object obj = iter.next();
+        if(obj instanceof DesignListener) changeListeners.removeElement(obj);
+      }
+    }
+  }
+
+  /**
+   * Remove all <code>ChangeListener</code>s.
+   */
+  public void removeAllChangeListeners() {
+    changeListeners.removeAllElements();
+  }
+
+  void fireStateChanged() {
+    if(suppressEvent_) return;
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(changeEvent_);
+      }
+    }
+  }
+  // general axis properties
+
+  /**
+   * Set the axis type.  The possible types include:
+   * <pre>
+   * axisType = DataGroup.PLAIN, DataGroup.TIME, or DataGroup.LOG
+   * </pre>
+   * No default.
+   * @param axisType (see above)
+   */
+  public void setAxisType(int axisType) {
+    int saved = this.axisType;
+    this.axisType = axisType;
+    if(saved != this.axisType) fireStateChanged();
+  }
+
+  /**
+   * Get the axis type.
+   * @return axis type
+   */
+  public int getAxisType() {
+    return axisType;
+  }
+
+  /**
+   * Get the axis orientation.
+   * @return axis orientation.
+   */
+  public int getAxisOrientation() {
+    return axisOrientation;
+  }
+
+  /**
+   * Set the axis orientation.  Orientations are:
+   * <pre>
+   * axisOrientation = DataGroup.X_DIR or DataGroup.Y_DIR
+   * </pre>
+   * No default.
+   * @param dir axis orientation
+   */
+  public void setAxisOrientation(int dir) {
+    axisOrientation = dir;
+    if(axisOrientation == DataGroup.X_DIR) {
+      title.setText("X Axis");
+      axisPosition = DataGroup.BOTTOM;
+    } else {
+      title.setText("Y Axis");
+      axisPosition = DataGroup.LEFT;
+    }
+  }
+
+  /**
+   * Set axis color. Default = black.
+   * @param axisColor axis color
+   */
+  public void setAxisColor(Color axisColor) {
+    Color saved = new Color(this.axisColor.getRed(),
+                            this.axisColor.getGreen(),
+                            this.axisColor.getBlue(),
+                            this.axisColor.getAlpha());
+    this.axisColor = axisColor;
+    if(!saved.equals(this.axisColor)) fireStateChanged();
+  }
+
+  /**
+   * Get the axis color.
+   * @return axis color
+   */
+  public Color getAxisColor() {
+    return axisColor;
+  }
+
+  /**
+   * Set autoRange property. True to automatically compute the axis range from
+   * the data. Default = true.
+   * @param autoRange auto range
+   */
+  public void setAutoRange(boolean autoRange) {
+    boolean saved = this.autoRange;
+    this.autoRange = autoRange;
+    if(saved != autoRange) fireStateChanged();
+  }
+
+  /**
+   * Test if the axis in autoRange mode.
+   * @return True, if in autoRange mode.
+   */
+  public boolean isAutoRange() {
+    return autoRange;
+  }
+
+  /**
+   * Set the user range. User range is only used if autoRange is false.
+   * Default = (1, 10, 1)
+   * @param userRange user supplied range
+   */
+  public void setUserRange(SoTRange userRange) {
+    SoTRange saved = userRange.copy();
+    this.userRange = userRange;
+    if(!saved.equals(this.userRange)) fireStateChanged();
+  }
+
+ /**
+  * Get the user range.
+  * @return user range
+  */
+  public SoTRange getUserRange() {
+    return userRange;
+  }
+
+  /**
+   * Set axis label color. Default = black.
+   * @param labelColor label color
+   */
+  public void setLabelColor(Color labelColor) {
+    Color saved = new Color(this.labelColor.getRed(),
+                            this.labelColor.getGreen(),
+                            this.labelColor.getBlue(),
+                            this.labelColor.getAlpha());
+    this.labelColor = labelColor;
+    if(!saved.equals(this.labelColor)) fireStateChanged();
+  }
+
+  /**
+   * Get the axis label color.
+   * @return axis label color
+   */
+  public Color getLabelColor() {
+    return labelColor;
+  }
+
+  /**
+   * Set the axis label font. Default = ("Helvetica", ITALIC, 10).
+   * @param labelFont  label font
+   */
+  public void setLabelFont(Font labelFont) {
+    Font saved = new Font(this.labelFont.getName(),
+                          this.labelFont.getStyle(),
+                          this.labelFont.getSize());
+    this.labelFont = labelFont;
+    if(!saved.equals(this.labelFont)) fireStateChanged();
+  }
+
+  /**
+   * Get the axis label font.
+   * @return axis label font
+   */
+  public Font getLabelFont() {
+    return labelFont;
+  }
+
+  /**
+   * Set label height in physical coordinates (inches). Default = 0.15.
+   * @param labelHeightP  label height
+   */
+  public void setLabelHeightP(double labelHeightP) {
+    double saved = this.labelHeightP;
+    this.labelHeightP = labelHeightP;
+    if(saved != this.labelHeightP) fireStateChanged();
+  }
+
+  /**
+   * Get label height.
+   * @return label height in physical coordinates
+   */
+  public double getLabelHeightP() {
+    return labelHeightP;
+  }
+
+  /**
+   * Set the label position.  Label position can be:
+   * <pre>
+   * labelPosition = Axis.AUTO, Axis.POSITIVE_SIDE,
+   *                 Axis.NEGATIVE_SIDE, Axis.NO_LABEL
+   * </pre>
+   * Default = AUTO.
+   * @param labelPosition label position
+   */
+  public void setLabelPosition(int labelPosition) {
+    int saved = this.labelPosition;
+    this.labelPosition = labelPosition;
+    if(saved != this.labelPosition) fireStateChanged();
+  }
+
+/**
+ * Test if label position in auto mode.
+ * @return true if in auto mode
+ */
+  public boolean isLabelPositionAuto() {
+    return labelPosition == Axis.AUTO;
+  }
+
+  /**
+   * If labelPosition is AUTO then return computed labelPosition,
+   * otherwise return stored value
+   * @return label position
+   */
+  public int getLabelPosition() {
+    int labPos = Axis.NEGATIVE_SIDE;
+    if(isLabelPositionAuto()) {
+      switch(axisPosition) {
+        case DataGroup.MANUAL:
+        case DataGroup.BOTTOM:
+        case DataGroup.LEFT:
+          labPos = Axis.NEGATIVE_SIDE;
+          break;
+        case DataGroup.TOP:
+        case DataGroup.RIGHT:
+          labPos = Axis.POSITIVE_SIDE;
+          break;
+      }
+    } else {
+      labPos = labelPosition;
+    }
+    return labPos;
+  }
+
+  /**
+   * Set bounds of axis in physical coordinates.  Default = (0, 0, 0, 0).
+   * @param boundsP axis bounds
+   */
+  public void setBoundsP(Rectangle2D boundsP) {
+    Rectangle2D saved = getBoundsP();
+//    if(this.boundsP != null) saved = this.boundsP.copy();
+    this.boundsP = boundsP;
+    boolean changed = true;
+    if(saved != null) changed = !saved.equals(this.boundsP);
+    if(changed) fireStateChanged();
+  }
+
+  /**
+   * Get axis bounds.
+   * @return axis bounds in physical coordinates.
+   */
+  public Rectangle2D getBoundsP() {
+    return boundsP;
+    /** @todo bounds isn't  cloned should be see note */
+//    return boundsP == null? null: boundsP.copy();
+  }
+
+  /**
+   * Get range of axis (long direction) in physical coordinates.
+   * The bounds are used to determine the axis range.
+   * @return axis range (long direction)
+   */
+  public Range2D getRangeP() {
+    Rectangle2D.Double dbl = (Rectangle2D.Double)boundsP;
+    if(axisOrientation == DataGroup.X_DIR) {
+      return new Range2D(dbl.x, dbl.x + dbl.width);
+    } else {
+      return new Range2D(dbl.y, dbl.y + dbl.height);
+    }
+  }
+
+  /**
+   * Set large tic height in physical coordinates. Default = 0.1.
+   * @param largeTicHeightP large tic height
+   */
+  public void setLargeTicHeightP(double largeTicHeightP) {
+    double saved = this.largeTicHeightP;
+    this.largeTicHeightP = largeTicHeightP;
+    if(saved != this.largeTicHeightP) fireStateChanged();
+  }
+
+  /**
+   * Get large tic height.
+   * @return large tic height in physical coordinates.
+   */
+  public double getLargeTicHeightP() {
+    return largeTicHeightP;
+  }
+
+  /**
+   * Set small tic height in physical coordinates. Default = 0.05.
+   * @param smallTicHeightP small tic height
+   */
+  public void setSmallTicHeightP(double smallTicHeightP) {
+    double saved = this.smallTicHeightP;
+    this.smallTicHeightP = smallTicHeightP;
+    if(saved != this.smallTicHeightP) fireStateChanged();
+  }
+
+  /**
+   * Get small tic height.
+   * @return small tic height in physical coordinates
+   */
+  public double getSmallTicHeightP() {
+    return smallTicHeightP;
+  }
+
+  /**
+   * Set the number of small tics between the large tics.  This should be one less
+   * than the number of intervals you want. Default = 0.
+   * @param numSmallTics number of small tics
+   */
+  public void setNumSmallTics(int numSmallTics) {
+    int saved = this.numSmallTics;
+    this.numSmallTics = numSmallTics;
+    if(saved != this.numSmallTics) fireStateChanged();
+  }
+
+  /**
+   * Get the number of small tics.
+   * @return number of small tics between large tics
+   */
+  public int getNumSmallTics() {
+    return numSmallTics;
+  }
+
+  /**
+   * Set the thick  tic width (for Time axes). Default = 0.025.
+   * @param thickTicWidth thick tic width
+   */
+  public void setThickTicWidth(double thickTicWidth) {
+    double saved = this.thickTicWidth;
+    this.thickTicWidth = thickTicWidth;
+    if(saved != this.thickTicWidth) fireStateChanged();
+  }
+
+  /**
+   * Get the thick tic width.  Valid for Time axes
+   * @return thick tic width
+   */
+  public double getThickTicWidth() {
+    return thickTicWidth;
+  }
+
+  /**
+   * Set the tic position.  Tic position include:
+   * <pre>
+   * ticPosition = Axis.AUTO, Axis.POSITIVE_SIDE,
+   *               Axis.NEGATIVE_SIDE, Axis.BOTH_SIDES
+   * </pre>
+   * Default = AUTO.
+   * @param ticPosition tic position
+   */
+  public void setTicPosition(int ticPosition) {
+    int saved = this.ticPosition;
+    this.ticPosition = ticPosition;
+    if(saved != this.ticPosition) fireStateChanged();
+  }
+
+/**
+ * Test if tic position in auto mode.
+ * @return true if in auto mode
+ */
+  public boolean isTicPositionAuto() {
+    return ticPosition == Axis.AUTO;
+  }
+
+  /**
+   * If ticPosition is AUTO then returns computed position, otherwise
+   * returns stored value.
+   * @return tic position
+   */
+  public int getTicPosition() {
+    int ticPos = Axis.NEGATIVE_SIDE;
+    if(isTicPositionAuto()) {
+      switch(axisPosition) {
+        case DataGroup.MANUAL:
+        case DataGroup.BOTTOM:
+        case DataGroup.LEFT:
+          ticPos = Axis.NEGATIVE_SIDE;
+          break;
+        case DataGroup.TOP:
+        case DataGroup.RIGHT:
+          ticPos = Axis.POSITIVE_SIDE;
+          break;
+      }
+    } else {
+      ticPos = ticPosition;
+    }
+    return ticPos;
+  }
+
+  /**
+   * Set the axis title.  Axis title is a <code>SGLabel</code> enabling the Color,
+   * Font, size to be set.
+   * @param title axis title
+   */
+  public void setTitle(SGLabel title) {
+    SGLabel saved = (SGLabel)this.title.copy();
+    this.title = title;
+    if(!saved.equals(this.title)) fireStateChanged();
+  }
+
+  /**
+   * Get the axis title.
+   * @return axis title
+   */
+  public SGLabel getTitle() {
+    return title;
+  }
+
+  /**
+   * Set the selecatability of the axis. If true, axis can be selected with
+   * the mouse. Default = true.
+   * @param selectable selectable
+   */
+  public void setSelectable(boolean selectable) {
+    boolean saved = this.selectable;
+    this.selectable = selectable;
+    if(saved != this.selectable) fireStateChanged();
+  }
+
+  /**
+   * Test if the axis selectable.
+   * @return true, if the axis can be selected
+   */
+  public boolean isSelectable() {
+    return selectable;
+  }
+
+  /**
+   * Set/unset the axis visibility.  If true, the axis will be displayed.
+   * Default = true.
+   * @param visible visible
+   */
+  public void setVisible(boolean visible) {
+    boolean saved = this.visible;
+    this.visible = visible;
+    if(saved != this.visible) fireStateChanged();
+  }
+
+  /**
+   * Test if the axis visible.
+   * @return true, if axis is set visible
+   */
+  public boolean isVisible() {
+    return visible;
+  }
+  // spaceaxis properties
+
+  /**
+   * Set the axis label format.  Not used with time axes. Default = ""
+   * @param labelFormat axis label format
+   */
+  public void setLabelFormat(String labelFormat) {
+    String saved = this.labelFormat;
+    this.labelFormat = labelFormat;
+    if(!saved.equals(this.labelFormat)) fireStateChanged();
+  }
+
+  /**
+   * Get the label format.
+   * @return label format.
+   */
+  public String getLabelFormat() {
+    return labelFormat;
+  }
+
+  /**
+   * Set the label interval.  Not used with time axes. Default = 2.
+   * @param labelInterval axis label interval
+   */
+  public void setLabelInterval(int labelInterval) {
+    int saved = this.labelInterval;
+    this.labelInterval = labelInterval;
+    if(saved != this.labelInterval) fireStateChanged();
+  }
+
+  /**
+   * Get the label interval.
+   * @return label interval
+   */
+  public int getLabelInterval() {
+    return labelInterval;
+  }
+
+  /**
+   * Set the axis label significant digits. Not used with time axes.
+   * Default = 2.
+   * @param labelSignificantDigits axis label significant digits
+   */
+  public void setLabelSignificantDigits(int labelSignificantDigits) {
+    int saved = this.labelSignificantDigits;
+    this.labelSignificantDigits = labelSignificantDigits;
+    if(saved != this.labelSignificantDigits) fireStateChanged();
+  }
+
+  /**
+   * Get axis label significant digits
+   * @return significant digits
+   */
+  public int getLabelSignificantDigits() {
+    return labelSignificantDigits;
+  }
+  // timeaxis properties
+
+  /**
+   * Set the time axis minor label format. Default = "MMM", appropriate for MONTH_YEAR.
+   * @param minorFormat time axis minor format
+   */
+  public void setMinorFormat(String minorFormat) {
+    String saved = this.minorFormat;
+    this.minorFormat = minorFormat;
+    if(!saved.equals(this.minorFormat)) fireStateChanged();
+  }
+
+  /**
+   * Get time axis minor label format.
+   * @return minor label format
+   */
+  public String getMinorFormat() {
+    return minorFormat;
+  }
+
+  /**
+   * Get the time axis major label format. Default = "yyyy", appropriate for MONTH_YEAR.
+   * @param majorFormat time axis major format
+   */
+  public void setMajorFormat(String majorFormat) {
+    String saved = this.majorFormat;
+    this.majorFormat = majorFormat;
+    if(!saved.equals(this.majorFormat)) fireStateChanged();
+  }
+
+  /**
+   * Get time axis major label format
+   * @return major label format
+   */
+  public String getMajorFormat() {
+    return majorFormat;
+  }
+
+  /**
+   * Set time axis minor label interval. Default = 2.
+   * @param minorInterval time axis minor interval
+   */
+  public void setMinorInterval(int minorInterval) {
+    int saved = this.minorInterval;
+    this.minorInterval = minorInterval;
+    if(saved != this.minorInterval) fireStateChanged();
+  }
+
+  /**
+   * Get time axis minor label interval
+   * @return minor label interval
+   */
+  public int getMinorInterval() {
+    return minorInterval;
+  }
+
+  /**
+   * Set time axis major label interval. Default = 1.
+   * @param majorInterval time axis major interval
+   */
+  public void setMajorInterval(int majorInterval) {
+    int saved = this.majorInterval;
+    this.majorInterval = majorInterval;
+    if(saved != this.majorInterval) fireStateChanged();
+  }
+
+  /**
+   * Get time axis major label interval
+   * @return major label interval
+   */
+  public int getMajorInterval() {
+    return majorInterval;
+  }
+
+  /**
+   * Set the time axis style.  Styles include:
+   * <pre>
+   * timeAxisStyle = TimeAxis.AUTO, TimeAxis.DAY_MONTH, TimeAxis.HOUR_DAY,
+   *                 TimeAxis.MINUTE_HOUR, TimeAxis.MONTH_YEAR,
+   *                 TimeAxis.YEAR_DECADE
+   * </pre>
+   * Default = AUTO.
+   * @param timeAxisStyle time axis style
+   */
+  public void setTimeAxisStyle(int timeAxisStyle) {
+    int saved = this.timeAxisStyle;
+    this.timeAxisStyle = timeAxisStyle;
+    if(saved != this.timeAxisStyle) fireStateChanged();
+  }
+
+  /**
+   * Get the time axis style.
+   * @return time axis style
+   */
+  public int getTimeAxisStyle() {
+    return timeAxisStyle;
+  }
+
+  /**
+   * Set the axis transform type.  Transform types include:
+   * <pre>
+   * transformType = DataGroup.LINEAR, DataGroup.LOG, DataGroup.REFERENCE
+   * </pre>
+   * Default = LINEAR.
+   * @param transformType axis transform type
+   */
+  public void setTransformType(int transformType) {
+    int saved = this.transformType;
+    this.transformType = transformType;
+    if(saved != this.transformType) fireStateChanged();
+  }
+
+  /**
+   * Get the axis transform type.
+   * @return transform type
+   */
+  public int getTransformType() {
+    return transformType;
+  }
+
+  /**
+   * Set the transform group.  The transform group is used when the
+   * transformType = DataGroup.REFERENCE.  The transformGroup is the
+   * <code>DataGroup</code> id containing the transform to be referenced.
+   * No default.
+   * @param transformGroup axis transform group name
+   */
+  public void setTransformGroup(String transformGroup) {
+    String saved = this.transformGroup;
+    this.transformGroup = transformGroup;
+    if(saved == null || !saved.equals(this.transformGroup)) fireStateChanged();
+  }
+
+  /**
+   * Get transform group name.
+   * @return transform group
+   */
+  public String getTransformGroup() {
+    return transformGroup;
+  }
+
+  /**
+   * Set the axis position.  Axis positions include:
+   * <pre>
+   * axisPosition = DataGroup.TOP, DataGroup.BOTTOM, (for x axes)
+   *                DataGroup.LEFT, DataGroup.RIGHT, (for y axes)
+   *                DataGroup.MANUAL
+   * </pre>
+   * No default.
+   * @param axisPosition axis position
+   */
+  public void setAxisPosition(int axisPosition) {
+    int saved = this.axisPosition;
+    this.axisPosition = axisPosition;
+    if(saved != this.axisPosition) fireStateChanged();
+  }
+
+  /**
+   * Get the axis position
+   * @return axis position
+   */
+  public int getAxisPosition() {
+    return axisPosition;
+  }
+
+  /**
+   * Set the axis origin in physical coordinates.  This is used when axisPosition = MANUAL.
+   * Default = (0, 0).
+   * @param axisOriginP axis origin
+   */
+  public void setAxisOriginP(Point2D.Double axisOriginP) {
+    Point2D saved = getAxisOriginP();
+//    if(this.axisOriginP != null) saved = this.axisOriginP.copy();
+    this.axisOriginP = axisOriginP;
+    boolean changed = true;
+    if(saved != null) changed = !saved.equals(this.axisOriginP);
+//    if(Page.DEBUG) System.out.println("AxisHolder.setAxisOriginP: " + changed +
+//                                      ", " + saved + ", " + this.axisOriginP);
+    if(changed) fireStateChanged();
+  }
+
+  /**
+   * Get axis origin.
+   * @return axis origin
+   */
+  public Point2D.Double getAxisOriginP() {
+    return axisOriginP == null? null: (Point2D.Double)axisOriginP.copy();
+  }
+
+  /**
+   * Set axis at origin  of perpendicular axis.  Not implemented.
+   * Default = false.
+   * @param locationAtOrigin set location at origin
+   */
+  public void setLocationAtOrigin(boolean locationAtOrigin) {
+    boolean saved = this.locationAtOrigin;
+    this.locationAtOrigin = locationAtOrigin;
+    if(saved != this.locationAtOrigin) fireStateChanged();
+  }
+
+  /**
+   * Test if the axis at the origin.  Not presently implemented.
+   * @return true, if axis will be at origin
+   */
+  public boolean isLocationAtOrigin() {
+    return locationAtOrigin;
+  }
+
+  /**
+   * Set the title auto property.  Set true to determine the title from the
+   * data. Default = true.
+   * @param titleAuto auto title property
+   */
+  public void setTitleAuto(boolean titleAuto) {
+    boolean saved = this.titleAuto;
+    this.titleAuto = titleAuto;
+    if(saved != this.titleAuto) fireStateChanged();
+  }
+
+  /**
+   * Test if the title in auto mode.
+   * @return true, if title is automatically generated
+   */
+  public boolean isTitleAuto() {
+    return titleAuto;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolderDragBox.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolderDragBox.java
new file mode 100755
index 0000000..781b7db
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolderDragBox.java
@@ -0,0 +1,439 @@
+/*
+ * $Id: AxisHolderDragBox.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.sgt.Axis;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class AxisHolderDragBox extends DragBox implements ChangeListener {
+  // box dimensions
+//  private static int BOX_HEIGHT = 25;
+  private static int TIC_LENGTH = 10;
+  private static int TIC_SPACE = 5;
+  private static int TIC_INCREMENT = 25;
+  private static int TITLE_HEIGHT = 10;
+  private static int TITLE_SPACE = 5;
+  // handle
+  public static final int ORIGIN = 0;
+  public static final int SIZE = 1;
+  public static final int DUMMY_ORIGIN = 2;
+  public static final int DUMMY_SIZE = 3;
+  //
+  private AxisHolder axHolder_;
+  private Rectangle boundsD_ = null;
+  private Point originD_ = null;
+  private String id_ = null;
+  private DataGroup dg_ = null;
+
+  public AxisHolderDragBox(AxisHolder axHolder, DataGroup dg, PanelHolder pHolder) {
+    super(pHolder);
+    axHolder_ = axHolder;
+    axHolder_.addChangeListener(this);
+    dg_ = dg;
+    dg_.addChangeListener(this);
+    for(int i=0; i < handles_.length;  i++) {
+      handles_[i] = new Rectangle(0,0,0,0);
+    }
+    id_ = axHolder_.getDataGroup().getId() +
+          (axHolder_.getAxisOrientation() == DataGroup.X_DIR? "_X": "_Y");
+
+    Point2D.Double orig = axHolder_.getAxisOriginP();
+    if(orig != null) originD_ = toLocation(orig);
+    Rectangle2D.Double bnds = (Rectangle2D.Double)axHolder_.getBoundsP();
+    if(bnds != null) boundsD_ = toRectangle(bnds);
+
+    update("AxisHolderDragBox.new()");
+  }
+
+  public AxisHolder getAxisHolder() {
+    return axHolder_;
+  }
+
+  public void setBounds(Rectangle bounds) {
+//    System.out.println("AxisHolderDragBox.setBounds: bounds updated");
+    boundsD_ = bounds;
+    axHolder_.setBoundsP(toRectangle(bounds));
+    computeHandles();
+  }
+
+  public void setOrigin(Point pt) {
+    originD_ = pt;
+    axHolder_.setAxisOriginP(toLocation(originD_));
+    computeHandles();
+  }
+
+  public Point getOrigin() {
+    return (Point)originD_.clone();
+  }
+
+  public Point getLocation() {
+    return new Point(boundsD_.x, boundsD_.y);
+  }
+
+  public void setId(String id) {
+    // operation not allowed
+  }
+
+  public void draw(Graphics g) {
+    Color savedColor = g.getColor();
+    if(selected_) {
+      g.setColor(Color.red);
+    } else {
+      g.setColor(Color.darkGray);
+    }
+    int xticStart, xticEnd;
+    int yticStart, yticEnd;
+    int xorg, yorg;
+    Rectangle dgBounds = computeDataGroupBounds();  // if not MANUAL
+    if(axHolder_.getAxisOrientation() == DataGroup.X_DIR) {
+    // XAxis
+      if(axHolder_.getAxisPosition() != DataGroup.MANUAL) {
+        switch(axHolder_.getAxisPosition()) {
+          default:
+          case DataGroup.BOTTOM:
+            yorg = dgBounds.y + dgBounds.height;
+            break;
+          case DataGroup.TOP:
+            yorg = dgBounds.y;
+            break;
+        }
+      } else { // MANUAL
+        yorg = originD_.y;
+      }
+      switch(axHolder_.getTicPosition()) {
+        default:
+        case Axis.NEGATIVE_SIDE:
+          yticStart = yorg;
+          yticEnd = yorg + TIC_LENGTH;
+          break;
+        case Axis.POSITIVE_SIDE:
+          yticStart = yorg - TIC_LENGTH;
+          yticEnd = yorg;
+          break;
+        case Axis.BOTH_SIDES:
+          yticStart = yorg - TIC_LENGTH;
+          yticEnd = yorg + TIC_LENGTH;
+      }
+      if(axHolder_.isVisible()) {
+        g.drawRect(boundsD_.x, boundsD_.y,
+                   boundsD_.width, boundsD_.height);
+        g.drawLine(boundsD_.x, yorg, boundsD_.x+boundsD_.width, yorg);
+        // Some X tics
+        for(int i=boundsD_.x; i < boundsD_.x+boundsD_.width; i += TIC_INCREMENT) {
+          g.drawLine(i, yticStart, i, yticEnd);
+        }
+      }
+    } else { // Y_DIR
+      // YAxis
+      if(axHolder_.getAxisPosition() != DataGroup.MANUAL) {
+        switch(axHolder_.getAxisPosition()) {
+          default:
+          case DataGroup.LEFT:
+            xorg = dgBounds.x;
+            break;
+          case DataGroup.RIGHT:
+            xorg = dgBounds.x + dgBounds.width;
+            break;
+        }
+      } else { // MANUAL
+        xorg = originD_.x;
+      }
+      switch(axHolder_.getTicPosition()) {
+        default:
+        case Axis.NEGATIVE_SIDE:
+          xticStart = xorg;
+          xticEnd = xorg - TIC_LENGTH;
+          break;
+        case Axis.POSITIVE_SIDE:
+          xticStart = xorg + TIC_LENGTH;
+          xticEnd = xorg;
+          break;
+        case Axis.BOTH_SIDES:
+          xticStart = xorg - TIC_LENGTH;
+          xticEnd = xorg + TIC_LENGTH;
+      }
+      if(axHolder_.isVisible()) {
+        g.drawRect(boundsD_.x, boundsD_.y,
+                   boundsD_.width, boundsD_.height);
+        g.drawLine(xorg, boundsD_.y, xorg, boundsD_.y+boundsD_.height);
+        // Some Y tics
+        for(int i=boundsD_.y; i < boundsD_.y+boundsD_.height;  i += TIC_INCREMENT) {
+          g.drawLine(xticStart, i, xticEnd, i);
+        }
+      }
+      // Name
+/*      if(dg_.getXPosition() == DataGroup.BOTTOM) {
+        yString += BOX_HEIGHT - 2;
+      } else {
+        yString += BOX_HEIGHT - TIC_LENGTH - 2;
+      }
+      g.drawString(dg_.getId(), boundsD_.x + 5, yString); */
+    }
+    if(selected_) {
+      for(int i=0; i < handles_.length; i++) {
+        Rectangle r = handles_[i];
+        g.fillRect(r.x, r.y, r.width-1, r.height-1);
+      }
+    }
+
+    g.setColor(savedColor);
+  }
+
+  private Rectangle computeDataGroupBounds() {
+    Rectangle panel = pHolder_.getBounds();
+    Margin margin = dg_.getMargin();
+    float dpi = pHolder_.getPanelModel().getDpi();
+    int left = (int)(margin.left*dpi);
+    int right = (int)(margin.right*dpi);
+    int top = (int)(margin.top*dpi);
+    int bottom = (int)(margin.bottom*dpi);
+    return new Rectangle(panel.x + left,
+                         panel.y + top,
+                         panel.width - (left + right),
+                         panel.height - (top + bottom));
+  }
+
+  private static int exCount_ = 0;
+
+  public void update(String message) {
+    /** @todo can't use dgBounds when MANUAL! */
+//    if(Page.DEBUG) System.out.println("AxisHolderDragBox.update(" + message + ")");
+//    if(Page.DEBUG && exCount_++ <= 25) (new Exception()).printStackTrace();
+//    if(exCount_ >= 25) System.exit(0);
+    int ticPos = Axis.NEGATIVE_SIDE;
+    int labPos = Axis.NEGATIVE_SIDE;
+    int x, y, width, height;
+    int xOrig, yOrig;
+    Rectangle dgBounds = computeDataGroupBounds();
+    if(axHolder_.getAxisOrientation() == DataGroup.X_DIR) {
+      width = dgBounds.width;
+      x = dgBounds.x;
+      ticPos = axHolder_.getTicPosition();
+      labPos = axHolder_.getLabelPosition();
+      if(axHolder_.getAxisPosition() != DataGroup.MANUAL) {
+        switch(axHolder_.getAxisPosition()) {
+          default:
+          case DataGroup.BOTTOM:
+            y = dgBounds.y + dgBounds.height;
+            break;
+          case DataGroup.TOP:
+            y = dgBounds.y;
+            break;
+        }
+      } else { // MANUAL
+        y = originD_.y;
+        x = boundsD_.x;
+        width = boundsD_.width;
+      }
+      xOrig = x;
+      yOrig = y;
+
+      height = TIC_SPACE + TITLE_SPACE;
+      switch(labPos) {
+        case Axis.NEGATIVE_SIDE:
+          height += TITLE_HEIGHT;
+          break;
+        case Axis.POSITIVE_SIDE:
+          height += TITLE_HEIGHT;
+          y -= (TITLE_HEIGHT + TITLE_SPACE);
+          break;
+        case Axis.NO_LABEL:
+      }
+      switch(ticPos) {
+        case Axis.NEGATIVE_SIDE:
+          height += TIC_LENGTH;
+          break;
+        case Axis.POSITIVE_SIDE:
+          height += TIC_LENGTH;
+          y -= (TIC_LENGTH + TIC_SPACE);
+          break;
+        case Axis.BOTH_SIDES:
+          height += 2*TIC_LENGTH + TIC_SPACE;
+          y -= (TIC_LENGTH + TIC_SPACE);
+          break;
+      }
+    } else { // Y_DIR
+      height = dgBounds.height;
+      y = dgBounds.y;
+      ticPos = axHolder_.getTicPosition();
+      labPos = axHolder_.getLabelPosition();
+      if(axHolder_.getAxisPosition() != DataGroup.MANUAL) {
+        switch(axHolder_.getAxisPosition()) {
+          default:
+          case DataGroup.LEFT:
+            x = dgBounds.x;
+            break;
+          case DataGroup.RIGHT:
+            x = dgBounds.x + dgBounds.width;
+            break;
+        }
+      } else { // MANUAL
+        x = originD_.x;
+        y = boundsD_.y;
+        height = boundsD_.height;
+      }
+      xOrig = x;
+      yOrig = y;
+
+      width = TIC_SPACE + TITLE_SPACE;
+      switch(labPos) {
+        case Axis.NEGATIVE_SIDE:
+          width += TITLE_HEIGHT;
+          x -= (TITLE_HEIGHT + TITLE_SPACE);
+          break;
+        case Axis.POSITIVE_SIDE:
+          width += TITLE_HEIGHT;
+          break;
+        case Axis.NO_LABEL:
+      }
+      switch(ticPos) {
+        case Axis.NEGATIVE_SIDE:
+          width += TIC_LENGTH;
+          x -= (TIC_LENGTH + TIC_SPACE);
+          break;
+        case Axis.POSITIVE_SIDE:
+          width += TIC_LENGTH;
+          break;
+        case Axis.BOTH_SIDES:
+          width += 2*TIC_LENGTH + TIC_SPACE;
+          x -= (TIC_LENGTH + TIC_SPACE);
+          break;
+      }
+    }
+    setOrigin(new Point(xOrig, yOrig));
+    setBounds(new Rectangle(x, y, width, height));
+    computeHandles();
+  }
+
+  public void setLocation(Point point) {
+    boundsD_.x = point.x;
+    boundsD_.y = point.y;
+    axHolder_.setBoundsP(toRectangle(boundsD_));
+    computeHandles();
+  }
+
+  public Rectangle getBounds() {
+    return (Rectangle)boundsD_.clone();
+  }
+
+  public String getId() {
+    return id_;
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    update("AxisHolderDragBox.stateChanged()");
+  }
+
+  private Rectangle2D getBoundsP() {
+    return null;
+  }
+
+  protected void computeHandles() {
+    if(boundsD_ == null) return;
+    int x, y;
+    int ticPos = axHolder_.getTicPosition();
+    Rectangle dgBounds = computeDataGroupBounds();
+    if(axHolder_.getAxisOrientation() == DataGroup.X_DIR) {
+      if(axHolder_.getAxisPosition() != DataGroup.MANUAL) {
+        switch(axHolder_.getAxisPosition()) {
+          default:
+          case DataGroup.BOTTOM:
+            y = dgBounds.y + dgBounds.height;
+            break;
+          case DataGroup.TOP:
+            y = dgBounds.y;
+            break;
+        }
+      } else { // MANUAL
+        y = originD_.y;
+      }
+      if(ticPos == Axis.POSITIVE_SIDE ||
+         ticPos == Axis.BOTH_SIDES) {
+        y -= handleSize_ + 1;
+      }
+      handles_[ORIGIN].setBounds(boundsD_.x + 1,
+                                 y,
+                                 handleSize_, handleSize_);
+      handles_[SIZE].setBounds(boundsD_.x + boundsD_.width - handleSize_ + 1,
+                               boundsD_.y + (boundsD_.height - handleSize_)/2,
+                               handleSize_, handleSize_);
+    } else { // Y_DIR
+      if(axHolder_.getAxisPosition() != DataGroup.MANUAL) {
+        switch(axHolder_.getAxisPosition()) {
+          default:
+          case DataGroup.LEFT:
+            x = dgBounds.x;
+            break;
+          case DataGroup.RIGHT:
+            x = dgBounds.x + dgBounds.width;
+            break;
+        }
+      } else { // MANUAL
+        x = originD_.x;
+      }
+      if(ticPos == Axis.NEGATIVE_SIDE ||
+         ticPos == Axis.BOTH_SIDES) {
+        x -= handleSize_;
+      }
+      handles_[ORIGIN].setBounds(x,
+                                 boundsD_.y + boundsD_.height - handleSize_ + 1,
+                                 handleSize_, handleSize_);
+      handles_[SIZE].setBounds(boundsD_.x + (boundsD_.width - handleSize_)/2,
+                               boundsD_.y + 1,
+                               handleSize_, handleSize_);
+    }
+  }
+
+  public void mouseOperation(int op, int dx, int dy) {
+    if(op == -1) return;
+//    System.out.println("AxisHolderDragBox.mouseOperation(" + op +
+//                      ", " + dx + ", " + dy + ")");
+    Point pt;
+    Rectangle rect;
+    switch (op) {
+      case ORIGIN:
+        pt = getLocation();
+        pt.x += dx;
+        pt.y += dy;
+        setLocation(pt);
+        pt = getOrigin();
+        pt.x += dx;
+        pt.y += dy;
+        setOrigin(pt);
+        break;
+      case SIZE:
+        rect = getBounds();
+        if(axHolder_.getAxisOrientation() == DataGroup.X_DIR) {
+          rect.width += dx;
+        } else {
+          rect.height -= dy;
+          rect.y += dy;
+        }
+        setBounds(rect);
+        break;
+      case DUMMY_ORIGIN:
+      case DUMMY_SIZE:
+    }
+    axHolder_.setAxisPosition(DataGroup.MANUAL);
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolderPropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolderPropertyPanel.java
new file mode 100755
index 0000000..7c903d3
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/AxisHolderPropertyPanel.java
@@ -0,0 +1,694 @@
+/*
+ * $Id: AxisHolderPropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import javax.swing.JComponent;
+import javax.swing.JTextField;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.Icon;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.swing.ColorSwatchIcon;
+import gov.noaa.pmel.sgt.swing.prop.SGLabelDialog;
+import gov.noaa.pmel.sgt.swing.prop.FontDialog;
+import gov.noaa.pmel.sgt.swing.prop.ColorDialog;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class AxisHolderPropertyPanel extends PropertyPanel
+    implements ActionListener, FocusListener, ChangeListener {
+  private boolean expert_ = false;
+  private String[] pNames_ =
+  { "AutoScale",               "AxisColor",       "Axis Position",
+    "Axis Location",           "AxisType",        "Bounds",
+    "Label Color",             "Label Font",      "Label Format",
+    "Label Height",            "Label Interval",  "Label Position",
+    "Label SignificantDigits", "Large TicHeight", "Location At Origin",
+    "Major Format",            "Major Interval",  "Minor Format",
+    "Minor Interval",          "Num Small Tics",   "OriginP",
+    "Selectable",
+    "Small TicHeight",         "Tic Position",    "Time AxisStyle",
+    "Title Auto",              "Title",           "Transform Type",
+    "User Range",              "Visible"};
+  private boolean[] expertItem =
+  { false,                     true,              false,  //autoScale
+    true,                      false,              true,   //axisLocation
+    true,                      false,              true,   //labelColor
+    false,                     false,              true,   //labelHeight
+    false,                     true,               true,  //sigDigits
+    true,                      true,               true,   //majorFormat
+    true,                      false,              true,   //minorInterval
+    true,  //selectable
+    true,                      true,               false,  //smallTicheight
+    false,                     false,              false,  //titleAuto
+    false,                      false};                     //userRange
+  private JComponent[] comps_ = new JComponent[pNames_.length];
+  private AxisHolder axHolder_;
+  private PanelHolder pHolder_;
+  private boolean suppressEvent_ = false;
+  private int autoScale, userRange;
+  private int titleAuto, title;
+  private String format_ = "yyyy-MM-dd hh:mm";
+  private String[] xAxisPosition = {"Bottom", "Top", "Manual"};
+  private String[] yAxisPosition = {"Left", "Right", "Manual"};
+
+  public AxisHolderPropertyPanel(AxisHolder axHolder, boolean expert) {
+    axHolder_ = axHolder;
+    axHolder_.addChangeListener(this);
+    expert_ = expert;
+    pHolder_ = axHolder_.getDataGroup().getPanelHolder();
+    create();
+  }
+
+  public void setAxisHolder(AxisHolder axHolder, boolean expert) {
+    if(axHolder_ != null) axHolder_.removeChangeListener(this);
+    axHolder_ = axHolder;
+    axHolder_.addChangeListener(this);
+    expert_ = expert;
+    reset();
+  }
+
+  void update() {
+    int i = -1;
+    suppressEvent_ = true;
+    int item = -1;
+    ((JCheckBox)comps_[++i]).setSelected(axHolder_.isAutoRange());
+    updateColor((JButton)comps_[++i], axHolder_.getAxisColor());
+    switch(axHolder_.getAxisPosition()) {
+      default:
+      case DataGroup.BOTTOM:
+        item = 0;
+        break;
+      case DataGroup.TOP:
+        item = 1;
+        break;
+      case DataGroup.LEFT:
+        item = 0;
+        break;
+      case DataGroup.RIGHT:
+        item = 1;
+        break;
+      case DataGroup.MANUAL:
+        item = 2;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JLabel)comps_[++i]).setText(format(axHolder_.getAxisOriginP(), true));
+    switch(axHolder_.getAxisType()) {
+      default:
+      case DataGroup.PLAIN:
+        item = 0;
+        break;
+      case DataGroup.TIME:
+        item = 1;
+        break;
+      case DataGroup.LOG:
+        item = 2;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JLabel)comps_[++i]).setText(format((Rectangle2D.Double)axHolder_.getBoundsP(), true));  // bounds?
+    updateColor((JButton)comps_[++i], axHolder_.getLabelColor());
+    updateFont((JButton)comps_[++i], axHolder_.getLabelFont());
+    ((JTextField)comps_[++i]).setText(axHolder_.getLabelFormat());
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getLabelHeightP()));
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getLabelInterval()));
+    if(axHolder_.isLabelPositionAuto()) {
+      item = 0;
+    } else {
+      switch(axHolder_.getLabelPosition()) {
+        default:
+          break;
+        case Axis.NEGATIVE_SIDE:
+          item = 1;
+          break;
+        case Axis.POSITIVE_SIDE:
+          item = 2;
+          break;
+        case Axis.NO_LABEL:
+          item = 3;
+          break;
+      }
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getLabelSignificantDigits()));
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getLargeTicHeightP()));
+    ((JCheckBox)comps_[++i]).setSelected(axHolder_.isLocationAtOrigin());
+    ((JTextField)comps_[++i]).setText(axHolder_.getMajorFormat());
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getMajorInterval()));
+    ((JTextField)comps_[++i]).setText(axHolder_.getMajorFormat());
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getMinorInterval()));
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getNumSmallTics()));
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getAxisOriginP(), true));
+    ((JCheckBox)comps_[++i]).setSelected(axHolder_.isSelectable());
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getSmallTicHeightP()));
+    if(axHolder_.isTicPositionAuto()) {
+      item = 0;
+    } else {
+      switch(axHolder_.getTicPosition()) {
+        default:
+          break;
+        case Axis.NEGATIVE_SIDE:
+          item = 1;
+          break;
+        case Axis.POSITIVE_SIDE:
+          item = 2;
+          break;
+        case Axis.BOTH_SIDES:
+          item = 3;
+          break;
+      }
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    switch(axHolder_.getTimeAxisStyle()) {
+      default:
+      case TimeAxis.AUTO:
+        item = 0;
+        break;
+      case TimeAxis.DAY_MONTH:
+        item = 1;
+        break;
+      case TimeAxis.HOUR_DAY:
+        item = 2;
+        break;
+      case TimeAxis.MINUTE_HOUR:
+        item = 3;
+        break;
+      case TimeAxis.MONTH_YEAR:
+        item = 4;
+        break;
+      case TimeAxis.YEAR_DECADE:
+        item = 5;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JCheckBox)comps_[++i]).setSelected(axHolder_.isTitleAuto());
+    updateSGLabel((JButton)comps_[++i], axHolder_.getTitle());
+    Vector transItems = new Vector(5);
+    transItems.add("LinearTransform");
+    transItems.add("LogTransform");
+    addOtherDataGroupTransforms(transItems);
+    item = findTransformItem(transItems, axHolder_.getTransformType(),
+                             axHolder_.getTransformGroup());
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JTextField)comps_[++i]).setText(format(axHolder_.getUserRange(), false));
+    ((JCheckBox)comps_[++i]).setSelected(axHolder_.isVisible());
+
+    suppressEvent_ = false;
+  }
+
+  void create() {
+    int i = -1;
+    int item = -1;
+    comps_[++i] = createCheckBox(axHolder_.isAutoRange(), pNames_[i], this);
+    autoScale = i;
+    comps_[++i] = createColor(axHolder_.getAxisColor(), pNames_[i], this);
+    String[] axisPosition;
+    if(axHolder_.getAxisOrientation() == DataGroup.X_DIR) {
+      axisPosition = xAxisPosition;
+    } else {
+      axisPosition = yAxisPosition;
+    }
+    switch(axHolder_.getAxisPosition()) {
+      default:
+      case DataGroup.BOTTOM:
+        item = 0;
+        break;
+      case DataGroup.TOP:
+        item = 1;
+        break;
+      case DataGroup.LEFT:
+        item = 0;
+        break;
+      case DataGroup.RIGHT:
+        item = 1;
+        break;
+      case DataGroup.MANUAL:
+        item = 2;
+        break;
+    }
+    comps_[++i] = createComboBox(axisPosition, item, pNames_[i], this, true);
+    comps_[++i] = createLabel(format(axHolder_.getAxisOriginP(), true));
+    String[] axisItems = {"PlainAxis", "TimeAxis", "LogAxis"};
+    switch(axHolder_.getAxisType()) {
+      default:
+      case DataGroup.PLAIN:
+        item = 0;
+        break;
+      case DataGroup.TIME:
+        item = 1;
+        break;
+      case DataGroup.LOG:
+        item = 2;
+        break;
+    }
+    comps_[++i] = createComboBox(axisItems, item, pNames_[i], this, true);
+    comps_[++i] = createLabel(format((Rectangle2D.Double)axHolder_.getBoundsP(), true));  // bounds ?
+    comps_[++i] = createColor(axHolder_.getLabelColor(), pNames_[i], this);
+    comps_[++i] = createFont(axHolder_.getLabelFont(), pNames_[i], this);
+    comps_[++i] = createTextField(axHolder_.getLabelFormat(), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getLabelHeightP()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getLabelInterval()), pNames_[i], this, true);
+    String[] labelPos = {"Auto", "Negative Side", "Positive Side", "No Label"};
+    if(axHolder_.isLabelPositionAuto()) {
+      item = 0;
+    } else {
+      switch(axHolder_.getLabelPosition()) {
+        default:
+          break;
+        case Axis.NEGATIVE_SIDE:
+          item = 1;
+          break;
+        case Axis.POSITIVE_SIDE:
+          item = 2;
+          break;
+        case Axis.NO_LABEL:
+          item = 3;
+          break;
+      }
+    }
+    comps_[++i] = createComboBox(labelPos, item, pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getLabelSignificantDigits()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getLargeTicHeightP()), pNames_[i], this, true);
+    comps_[++i] = createCheckBox(axHolder_.isLocationAtOrigin(), pNames_[i], this);
+    comps_[++i] = createTextField(axHolder_.getMajorFormat(), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getMajorInterval()), pNames_[i], this, true);
+    comps_[++i] = createTextField(axHolder_.getMinorFormat(), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getMinorInterval()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getNumSmallTics()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getAxisOriginP(), true), pNames_[i], this, true);
+    comps_[++i] = createCheckBox(axHolder_.isSelectable(), pNames_[i], this);
+    comps_[++i] = createTextField(format(axHolder_.getSmallTicHeightP()), pNames_[i], this, true);
+    String[] ticPos = {"Auto", "Negative Side", "Positive Side", "Both Sides"};
+    if(axHolder_.isTicPositionAuto()) {
+      item = 0;
+    } else {
+      switch(axHolder_.getTicPosition()) {
+        default:
+          break;
+        case Axis.NEGATIVE_SIDE:
+          item = 1;
+          break;
+        case Axis.POSITIVE_SIDE:
+          item = 2;
+          break;
+        case Axis.BOTH_SIDES:
+          item = 3;
+          break;
+      }
+    }
+    comps_[++i] = createComboBox(ticPos, item, pNames_[i], this, true);
+    String[] timeStyle = {"Auto", "Day-Month", "Hour-Day",
+      "Minute-Hour", "Month-Year", "Year-Decade"};
+    switch(axHolder_.getTimeAxisStyle()) {
+      default:
+      case TimeAxis.AUTO:
+        item = 0;
+        break;
+      case TimeAxis.DAY_MONTH:
+        item = 1;
+        break;
+      case TimeAxis.HOUR_DAY:
+        item = 2;
+        break;
+      case TimeAxis.MINUTE_HOUR:
+        item = 3;
+        break;
+      case TimeAxis.MONTH_YEAR:
+        item = 4;
+        break;
+      case TimeAxis.YEAR_DECADE:
+        item = 5;
+        break;
+    }
+    comps_[++i] = createComboBox(timeStyle, item, pNames_[i], this, true);
+    comps_[++i] = createCheckBox(axHolder_.isTitleAuto(), pNames_[i], this);
+    titleAuto = i;
+    comps_[++i] = createSGLabel(axHolder_.getTitle(), pNames_[i], this);
+    title = i;
+
+    Vector transItems = new Vector(5);
+    transItems.add("LinearTransform");
+    transItems.add("LogTransform");
+    addOtherDataGroupTransforms(transItems);
+    item = findTransformItem(transItems, axHolder_.getTransformType(),
+                             axHolder_.getTransformGroup());
+    comps_[++i] = createComboBox(transItems, item, pNames_[i], this, true);
+    comps_[++i] = createTextField(format(axHolder_.getUserRange(), false), pNames_[i], this, true);
+    userRange = i;
+    comps_[++i] = createCheckBox(axHolder_.isVisible(),  pNames_[i], this);
+    setFieldsEnabled();
+//
+    int row = 0;
+    for(i=0; i < comps_.length; i++) {
+      if(expert_ || ! expertItem[i]) {
+        addProperty(++row, pNames_[i], comps_[i], false);
+      }
+    }
+    addProperty(row + 1, " ", new JLabel(" "), true);
+  }
+
+  void resetFields() {
+    for(int i=0; i < comps_.length; i++) {
+      if(comps_[i] instanceof JTextField) {
+        ((JTextField)comps_[i]).removeActionListener(this);
+        ((JTextField)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JCheckBox) {
+        ((JCheckBox)comps_[i]).removeActionListener(this);
+        ((JCheckBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JComboBox) {
+        ((JComboBox)comps_[i]).removeActionListener(this);
+        ((JComboBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JButton) {
+        ((JButton)comps_[i]).removeActionListener(this);
+        ((JButton)comps_[i]).removeFocusListener(this);
+      }
+    }
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    if(suppressEvent_) return;
+    Object obj = e.getSource();
+//    String str = null;
+    String command = e.getActionCommand();
+    processEvent(obj, command);
+    setFieldsEnabled();
+//    System.out.println(e.paramString() + ",rslt=" + str);
+  }
+
+  private void setFieldsEnabled() {
+    ((JTextField)comps_[userRange]).setEnabled(!((JCheckBox)comps_[autoScale]).isSelected());
+//    ((JButton)comps_[title]).setEnabled(!((JCheckBox)comps_[titleAuto]).isSelected());
+  }
+
+  private void processEvent(Object obj, String command) {
+    if(Page.DEBUG) System.out.println("AxisHolderPropertyPanel.processEvent(" + obj + ", " + command + ")");
+    int item = -1;
+    String str = null;
+    SoTRange range = null;
+    if(command.equals("AutoScale")) {
+      axHolder_.setAutoRange(((JCheckBox)obj).isSelected());
+    } else if(command.equals("AxisColor")) {
+      ColorDialog cd = new ColorDialog(getFrame(), "Select Axis Color", true);
+      cd.setColor(axHolder_.getAxisColor());
+      cd.setVisible(true);
+      Color newcolor = cd.getColor();
+      if(newcolor != null) axHolder_.setAxisColor(newcolor);
+    } else if(command.equals("Axis Position")) {
+      str = (String)((JComboBox)obj).getSelectedItem();
+      item = -1;
+      if(str.equals("Bottom")) {
+        item = DataGroup.BOTTOM;
+      } else if(str.equals("Top")) {
+        item = DataGroup.TOP;
+      } else if(str.equals("Left")) {
+        item = DataGroup.LEFT;
+      } else if(str.equals("Right")) {
+        item = DataGroup.RIGHT;
+      } else if(str.equals("Manual")) {
+        item = DataGroup.MANUAL;
+      }
+      axHolder_.setAxisPosition(item);
+    } else if(command.equals("Axis Location")) {
+/** @todo SoTPoint axisLocation */
+    } else if(command.equals("AxisType")) {
+      str = (String)((JComboBox)obj).getSelectedItem();
+      axHolder_.setAxisType(axis(str));
+      if(str.equals("PlainAxis") || str.equals("TimeAxis")) {
+        axHolder_.setTransformType(DataGroup.LINEAR);
+      } else if(str.equals("LogAxis")) {
+        axHolder_.setTransformType(DataGroup.LOG);
+      }
+      if(str.equals("TimeAxis") && !axHolder_.getUserRange().isTime()) {
+        try {
+          range = new SoTRange.Time(new GeoDate("2000-01-01 00:00", format_),
+                                    new GeoDate("2001-01-01 00:00", format_),
+                                    new GeoDate(172800000));
+        } catch (IllegalTimeValue itv) {
+          itv.printStackTrace();
+        }
+        axHolder_.setUserRange(range);
+      }
+    } else if(command.equals("Bounds")) {
+      Rectangle2D bounds = parseBounds(((JTextField)obj).getText());
+      if(bounds != null) axHolder_.setBoundsP(bounds);
+    } else if(command.equals("Label Color")) {
+      ColorDialog cd = new ColorDialog(getFrame(), "Select Label Color", true);
+      cd.setColor(axHolder_.getAxisColor());
+      cd.setVisible(true);
+      Color newcolor = cd.getColor();
+      if(newcolor != null) axHolder_.setLabelColor(newcolor);
+    } else if(command.equals("Label Font")) {
+      FontDialog fd = new FontDialog("Label Font");
+      int result = fd.showDialog(axHolder_.getLabelFont());
+      if(result == fd.OK_RESPONSE) {
+        axHolder_.setLabelFont(fd.getFont());
+      }
+    } else if(command.equals("Label Format")) {
+      axHolder_.setLabelFormat(((JTextField)obj).getText());
+    } else if(command.equals("Label Height")) {
+      axHolder_.setLabelHeightP(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Label Interval")) {
+      axHolder_.setLabelInterval(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Label Position")) {
+      str = (String)((JComboBox)obj).getSelectedItem();
+      item = -1;
+      if(str.equals("Auto")) {
+        item = Axis.AUTO;
+      } else if(str.equals("Negative Side")) {
+        item = Axis.NEGATIVE_SIDE;
+      } else if(str.equals("Positive Side")) {
+        item = Axis.POSITIVE_SIDE;
+      } else if(str.equals("No Label")) {
+        item = Axis.NO_LABEL;
+      }
+      axHolder_.setLabelPosition(item);
+    } else if(command.equals("Label SignificantDigits")) {
+      axHolder_.setLabelSignificantDigits(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Large TicHeight")) {
+      axHolder_.setLargeTicHeightP(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Location At Origin")) {
+      axHolder_.setLocationAtOrigin(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Major Format")) {
+      axHolder_.setMajorFormat(((JTextField)obj).getText());
+    } else if(command.equals("Major Interval")) {
+      axHolder_.setMajorInterval(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Minor Format")) {
+      axHolder_.setMinorFormat(((JTextField)obj).getText());
+    } else if(command.equals("Minor Interval")) {
+      axHolder_.setMinorInterval(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Num Small Tics")) {
+      axHolder_.setNumSmallTics(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("OriginP")) {
+      axHolder_.setAxisOriginP(parsePoint2D(((JTextField)obj).getText()));
+    } else if(command.equals("Selectable")) {
+      axHolder_.setSelectable(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Small TicHeight")) {
+      axHolder_.setSmallTicHeightP(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Tic Position")) {
+      str = (String)((JComboBox)obj).getSelectedItem();
+      item = -1;
+      if(str.equals("Auto")) {
+        item = Axis.AUTO;
+      } else if(str.equals("Negative Side")) {
+        item = Axis.NEGATIVE_SIDE;
+      } else if(str.equals("Positive Side")) {
+        item = Axis.POSITIVE_SIDE;
+      } else if(str.equals("Both Sides")) {
+        item = Axis.BOTH_SIDES;
+      }
+      axHolder_.setTicPosition(item);
+    } else if(command.equals("Time AxisStyle")) {
+        str = (String)((JComboBox)obj).getSelectedItem();
+        item = -1;
+        if(str.equals("Auto")) {
+          item = TimeAxis.AUTO;
+        } else if(str.equals("Day-Month")) {
+          item = TimeAxis.DAY_MONTH;
+        } else if(str.equals("Hour-Day")) {
+          item = TimeAxis.HOUR_DAY;
+        } else if(str.equals("Minute-Hour")) {
+          item = TimeAxis.MINUTE_HOUR;
+        } else if(str.equals("Month-Year")) {
+          item = TimeAxis.MONTH_YEAR;
+        } else if(str.equals("Year-Decade")) {
+          item = TimeAxis.YEAR_DECADE;
+        }
+        axHolder_.setTimeAxisStyle(item);
+    } else if(command.equals("Title Auto")) {
+      axHolder_.setTitleAuto(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Title")) {
+      SGLabelDialog sgd = new SGLabelDialog("Axis Title");
+      sgd.setSGLabel(axHolder_.getTitle());
+      sgd.setModal(true);
+      sgd.setVisible(true);
+      axHolder_.fireStateChanged();
+    } else if(command.equals("Transform Type")) {
+      str = (String)((JComboBox)obj).getSelectedItem();
+      int trans = transform(str);
+      if(trans == DataGroup.REFERENCE) {
+        axHolder_.setTransformGroup(str.substring(5));
+      }
+      axHolder_.setTransformType(trans);
+      if(trans == DataGroup.REFERENCE &&  circularReference(DataGroup.X_DIR, str.substring(5))) {
+        JOptionPane.showMessageDialog(this, "Creates a circular reference in DataGroup transform",
+                                      "Error Selecting Transform", JOptionPane.ERROR_MESSAGE);
+        axHolder_.setTransformType(-1);
+        axHolder_.setTransformGroup(null);
+        ((JComboBox)obj).setSelectedIndex(-1);
+        return;
+      }
+    } else if(command.equals("User Range")) {
+      range = parseRange(((JTextField)obj).getText(), axHolder_.isTime());
+      if(range != null) axHolder_.setUserRange(range);
+    } else if(command.equals("Visible")) {
+      axHolder_.setVisible(((JCheckBox)obj).isSelected());
+    }
+    update();
+  }
+
+  private int axis(String value) {
+    if(value.equals("PlainAxis")) {
+      return DataGroup.PLAIN;
+    } else if(value.equals("TimeAxis")) {
+      return DataGroup.TIME;
+    } else if(value.equals("LogAxis")) {
+      return DataGroup.LOG;
+    }
+    return -1;
+  }
+
+  private int transform(String value) {
+    if(value.equals("LinearTransform")) {
+      return DataGroup.LINEAR;
+    } else if(value.equals("LogTransform")) {
+      return DataGroup.LOG;
+    } else {
+      return DataGroup.REFERENCE;
+    }
+  }
+
+  public void focusGained(FocusEvent e) {
+  }
+
+  public void focusLost(FocusEvent e) {
+    Object obj = e.getSource();
+    if(obj instanceof JTextField) {
+      JTextField tf = (JTextField)obj;
+      String name = tf.getName();
+      processEvent(obj, name);
+    }
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    update();
+  }
+
+  void addOtherDataGroupTransforms(Vector list) {
+//    PanelHolder ph = axHolder_.getDataGroup().getPanelHolder();
+    if(pHolder_.getDataGroupSize() <= 1) return;
+    Iterator iter = pHolder_.dataGroupIterator();
+    while(iter.hasNext()) {
+      DataGroup dg = (DataGroup)iter.next();
+      if(dg.getId().equals(axHolder_.getDataGroup().getId())) continue;
+      list.add("Use: " + dg.getId());
+    }
+  }
+
+  int findTransformItem(Vector transItems, int transType,
+                        String transformGroup) {
+    int item = -1;
+    switch(transType) {
+      default:
+      case DataGroup.LINEAR:
+        item = 0;
+        break;
+      case DataGroup.LOG:
+        item = 1;
+        break;
+      case DataGroup.REFERENCE:
+        if(transItems.size() >= 3) {
+          for(int i = 2; i < transItems.size(); i++) {
+            if(((String)transItems.get(i)).endsWith(transformGroup)) {
+              return i;
+            }
+          }
+        }
+        break;
+    }
+    return item;
+  }
+
+  boolean circularReference(int dir, String datagroup) {
+//    PanelHolder ph = axHolder_.getDataGroup().getPanelHolder();
+    String dgLast = datagroup;
+    boolean stillLooking = true;
+    int tType = -1;
+    String newDG = null;
+    while(stillLooking) {
+      DataGroup dg = pHolder_.findDataGroup(dgLast);
+      if(dir == DataGroup.X_DIR) {
+        tType = dg.getXAxisHolder().getTransformType();
+      } else {
+        tType = dg.getYAxisHolder().getTransformType();
+      }
+      if(tType != DataGroup.REFERENCE) return false;
+      if(dir == DataGroup.X_DIR) {
+        newDG = dg.getXAxisHolder().getTransformGroup();
+      } else {
+        newDG = dg.getYAxisHolder().getTransformGroup();
+      }
+      if(datagroup.equals(newDG)) return true;
+      dgLast = newDG;
+    }
+    return false;
+  }
+
+  public void setExpert(boolean expert) {
+    boolean save = expert_;
+    expert_ = expert;
+    if(expert_ != save) reset();
+  }
+
+  public boolean isExpert() {
+    return expert_;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/BorderDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/BorderDialog.java
new file mode 100755
index 0000000..ce15d51
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/BorderDialog.java
@@ -0,0 +1,596 @@
+/*
+ * $Id: BorderDialog.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.awt.event.*;
+
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import gov.noaa.pmel.sgt.swing.prop.ColorEntryPanel;
+import gov.noaa.pmel.sgt.swing.prop.FontDialog;
+
+/**
+ * Edit/create a <code>Border</code> object to be used with <code>PanelHolder</code>.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+public class BorderDialog extends JDialog {
+  private JPanel panel1 = new JPanel();
+  private BorderLayout borderLayout1 = new BorderLayout();
+  private JPanel cardPanel = new JPanel();
+  private JPanel bevelPanel = new JPanel();
+  private JPanel jPanel3 = new JPanel();
+  private JPanel etchedPanel = new JPanel();
+  private JLabel jLabel1 = new JLabel();
+  private JPanel borderPanel = new JPanel();
+  private BorderLayout borderLayout2 = new BorderLayout();
+  private CardLayout cardLayout1 = new CardLayout();
+  private JPanel linePanel = new JPanel();
+  private GridBagLayout gridBagLayout8 = new GridBagLayout();
+  private GridBagLayout gridBagLayout5 = new GridBagLayout();
+  private GridBagLayout gridBagLayout3 = new GridBagLayout();
+  private JPanel buttonPanel = new JPanel();
+  private JButton okButton = new JButton();
+  private JButton cancelButton = new JButton();
+  private JPanel emptyPanel = new JPanel();
+  private String[] args = {"None", "Beveled",
+      "Etched", "Line"};
+  private String[] typeargs = {"Raised", "Lowered"};
+  private JComboBox borderTypeCB = new JComboBox(args);
+  private JComboBox bevelStyleCB = new JComboBox(typeargs);
+  private JComboBox etchedStyleCB = new JComboBox(typeargs);
+
+  private Border border_ = null;
+  private Border working_ = null;
+  private JLabel jLabel2 = new JLabel();
+  private JLabel jLabel3 = new JLabel();
+  private JLabel jLabel4 = new JLabel();
+  private JLabel jLabel5 = new JLabel();
+  private JLabel jLabel6 = new JLabel();
+  private ColorEntryPanel bevelHOColorPanel = new ColorEntryPanel();
+  private ColorEntryPanel bevelHIColorPanel = new ColorEntryPanel();
+  private ColorEntryPanel bevelSOColorPanel = new ColorEntryPanel();
+  private ColorEntryPanel bevelSIColorPanel = new ColorEntryPanel();
+  private JLabel jLabel8 = new JLabel();
+  private JLabel jLabel10 = new JLabel();
+  private JLabel jLabel11 = new JLabel();
+  private ColorEntryPanel etchedSColorPanel = new ColorEntryPanel();
+  private ColorEntryPanel etchedHColorPanel = new ColorEntryPanel();
+  private JLabel jLabel12 = new JLabel();
+  private JLabel jLabel13 = new JLabel();
+  private JLabel jLabel9 = new JLabel();
+  private ColorEntryPanel lineColorPanel = new ColorEntryPanel();
+  private JTextField lineTF = new JTextField();
+  private JCheckBox lineCB = new JCheckBox();
+  private JPanel titledPanel = new JPanel();
+  private JCheckBox titledCB = new JCheckBox();
+  private GridBagLayout gridBagLayout1 = new GridBagLayout();
+  private JTextField titleTF = new JTextField();
+  private JLabel jLabel7 = new JLabel();
+  private JLabel jLabel14 = new JLabel();
+  private JPanel jPanel1 = new JPanel();
+  String[] justargs = {"Left", "Center", "Right"};
+  private JComboBox justCB = new JComboBox(justargs);
+  private JLabel jLabel15 = new JLabel();
+  String[] posargs = {"Above Top", "Top", "Below Top",
+                      "Above Bottom", "Bottom", "Below Bottom"};
+  private JComboBox positionCB = new JComboBox(posargs);
+  private GridBagLayout gridBagLayout2 = new GridBagLayout();
+  private JLabel jLabel16 = new JLabel();
+  private JLabel jLabel17 = new JLabel();
+  private ColorEntryPanel titleColorPanel = new ColorEntryPanel();
+  private ThreeDotsButton fontEditor = new ThreeDotsButton();
+  private FlowLayout flowLayout1 = new FlowLayout();
+  private JPanel fontPanel = new javax.swing.JPanel();
+  private JLabel fontLabel = new javax.swing.JLabel();
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  private Font labelFont_ = getFont();
+  private boolean createNewBorder_ = true;
+
+  /**
+   * Dialog constructor.
+   * @param frame parent frame
+   * @param title dialog title
+   * @param modal set true if modal dialog
+   */
+  public BorderDialog(Frame frame, String title, boolean modal) {
+    super(frame, title, modal);
+    init(frame);
+  }
+
+  /**
+   * Default constructor.
+   */
+  public BorderDialog() {
+    this(null, "", false);
+  }
+
+  private void init(Window win) {
+    try {
+      jbInit();
+      pack();
+    }
+    catch(Exception ex) {
+      ex.printStackTrace();
+    }
+    this.setSize(520, 520);
+    ((CardLayout)cardPanel.getLayout()).show(cardPanel, "none");
+    if(win != null) {
+      Rectangle fBounds = win.getBounds();
+      Point fLoc = win.getLocationOnScreen();
+      Rectangle bounds = getBounds();
+      int x = fLoc.x + fBounds.width/2 - bounds.width/2;
+      int y = fLoc.y + fBounds.height/2 - bounds.height/2;
+      setLocation(x, y);
+    } else {
+      setLocation(200, 200);
+    }
+  }
+
+  /**
+   * Set the border.
+   * @param border initialize dialog to this
+   */
+  public void setBorder(Border border) {
+    border_ = border;
+    if(border_ instanceof TitledBorder) {
+      titledCB.setSelected(true);
+      working_ = ((TitledBorder)border_).getBorder();
+    } else {
+      titledCB.setSelected(false);
+      working_ = border_;
+    }
+    init();
+  }
+
+  /**
+   * Get the new <code>Border</code>.
+   * @return border
+   */
+  public Border getBorder() {
+    return border_;
+  }
+
+  private void jbInit() throws Exception {
+    panel1.setLayout(borderLayout1);
+    cardPanel.setLayout(cardLayout1);
+    borderTypeCB.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        borderTypeCB_actionPerformed(e);
+      }
+    });
+    bevelPanel.setLayout(gridBagLayout5);
+    etchedPanel.setLayout(gridBagLayout3);
+    jLabel1.setText("Border Type");
+    borderPanel.setMinimumSize(new Dimension(163, 300));
+    borderPanel.setPreferredSize(new Dimension(167, 300));
+    borderPanel.setLayout(borderLayout2);
+    linePanel.setLayout(gridBagLayout8);
+    okButton.setText("OK");
+    okButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        okButton_actionPerformed(e);
+      }
+    });
+    cancelButton.setText("Cancel");
+    cancelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        cancelButton_actionPerformed(e);
+      }
+    });
+    jLabel2.setText("Style:");
+    jLabel3.setText("Highlight Outer:");
+    jLabel4.setText("Highlight Inner:");
+    jLabel5.setText("Shadow Outer:");
+    jLabel6.setText("Shadow Inner:");
+    jLabel8.setText("Shadow:");
+    jLabel10.setText("Highlight:");
+    jLabel11.setText("Style:");
+    jLabel12.setText("Color:");
+    jLabel13.setText("Thickness:");
+    jLabel9.setText("Rounded Corners:");
+    lineTF.setText("2");
+    lineTF.setColumns(5);
+    lineColorPanel.setTitle("Set Line Color");
+    bevelHOColorPanel.setTitle("Set Highlight Outer Color");
+    bevelHIColorPanel.setTitle("Set Highlight Inner Color");
+    bevelSOColorPanel.setTitle("Set Shadow Outer Color");
+    bevelSIColorPanel.setTitle("Set Shadow Inner Color");
+    etchedHColorPanel.setTitle("Set Highlight Color");
+    etchedSColorPanel.setTitle("Set Shadow Color");
+    buttonPanel.setBorder(BorderFactory.createEtchedBorder());
+    titledPanel.setBorder(BorderFactory.createEtchedBorder());
+    titledPanel.setLayout(gridBagLayout1);
+    titledCB.setText("Titled");
+    titledCB.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        titledCB_actionPerformed(e);
+      }
+    });
+    jLabel7.setText("Title:");
+    jLabel14.setText("Position:");
+    jLabel15.setText("Justification:");
+    jPanel1.setLayout(gridBagLayout2);
+    jLabel16.setText("Color:");
+    jLabel17.setText("Font:");
+    titleColorPanel.setEnabled(false);
+    titleColorPanel.setTitle("Set Title Color");
+    fontEditor.setEnabled(false);
+    fontEditor.setAlignmentY((float) 0.0);
+    fontEditor.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        fontEditor_actionPerformed(e);
+      }
+    });
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.setLayout(flowLayout1);
+    fontLabel.setAlignmentY((float) 0.0);
+    fontLabel.setText("Dialog, 12, Bold");
+    fontLabel.setForeground(java.awt.Color.black);
+    titleTF.setEnabled(false);
+    positionCB.setEnabled(false);
+    justCB.setEnabled(false);
+    cardPanel.setMinimumSize(new Dimension(451, 225));
+    cardPanel.setPreferredSize(new Dimension(451, 225));
+    cardPanel.setToolTipText("");
+    panel1.setMinimumSize(new Dimension(163, 360));
+    panel1.setPreferredSize(new Dimension(187, 360));
+    getContentPane().add(panel1);
+    panel1.add(borderPanel,  BorderLayout.CENTER);
+    jPanel3.add(jLabel1, null);
+    jPanel3.add(borderTypeCB, null);
+    borderPanel.add(titledPanel, BorderLayout.SOUTH);
+    borderPanel.add(cardPanel, BorderLayout.CENTER);
+    borderPanel.add(jPanel3, BorderLayout.NORTH);
+    cardPanel.add(bevelPanel,  "bevel");
+    bevelPanel.add(jLabel2,                   new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    bevelPanel.add(bevelStyleCB,                    new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    bevelPanel.add(jLabel3,                    new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(jLabel4,                    new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(jLabel5,                     new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(jLabel6,                     new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(bevelHOColorPanel,                     new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(bevelHIColorPanel,                 new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(bevelSOColorPanel,             new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    bevelPanel.add(bevelSIColorPanel,        new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    cardPanel.add(etchedPanel,  "etched");
+    etchedPanel.add(jLabel8,                  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    etchedPanel.add(jLabel10,                 new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    etchedPanel.add(jLabel11,              new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    etchedPanel.add(etchedSColorPanel,              new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    etchedPanel.add(etchedStyleCB,            new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    etchedPanel.add(etchedHColorPanel,              new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    cardPanel.add(linePanel,  "line");
+    linePanel.add(jLabel9,           new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    linePanel.add(lineColorPanel,             new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    linePanel.add(jLabel12,       new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    linePanel.add(jLabel13,       new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    panel1.add(buttonPanel,  BorderLayout.SOUTH);
+    buttonPanel.add(okButton, null);
+    buttonPanel.add(cancelButton, null);
+    cardPanel.add(emptyPanel,  "none");
+    linePanel.add(lineTF,   new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    linePanel.add(lineCB,    new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    titledPanel.add(titledCB,               new GridBagConstraints(0, 0, 1, 1, 0.7, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 15, 0));
+    titledPanel.add(titleTF,              new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 5, 15), 0, 0));
+    titledPanel.add(jLabel7,           new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    titledPanel.add(jLabel14,            new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    titledPanel.add(jPanel1,           new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    jPanel1.add(positionCB,     new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    jPanel1.add(jLabel15,     new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    jPanel1.add(justCB,    new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    titledPanel.add(jLabel16,        new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    titledPanel.add(titleColorPanel,      new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    titledPanel.add(jLabel17,         new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 10, 5), 0, 0));
+    titledPanel.add(fontPanel,     new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 10, 5), 0, 0));
+    fontPanel.add(fontLabel, null);
+    fontPanel.add(fontEditor, null);
+    positionCB.setSelectedIndex(1);
+  }
+
+  void init() {
+//    working_ = null;
+    createNewBorder_ = false;
+    String type = "none";
+    int index = 0;
+    if(working_ != null) {
+      if(working_ instanceof BevelBorder) {
+        BevelBorder bb = (BevelBorder)working_;
+
+/*        working_ = new BevelBorder(bb.getBevelType(),
+                                   bb.getHighlightOuterColor(),
+                                   bb.getHighlightInnerColor(),
+                                   bb.getShadowOuterColor(),
+                                   bb.getShadowInnerColor()); */
+
+        bevelHIColorPanel.setColor(bb.getHighlightInnerColor(this));
+        bevelHOColorPanel.setColor(bb.getHighlightOuterColor(this));
+        bevelSIColorPanel.setColor(bb.getShadowInnerColor(this));
+        bevelSOColorPanel.setColor(bb.getShadowOuterColor(this));
+
+        int style = bb.getBevelType();
+        if(style == BevelBorder.RAISED) {
+          bevelStyleCB.setSelectedItem("Raised");
+        } else if(style == BevelBorder.LOWERED) {
+          bevelStyleCB.setSelectedItem("Lowered");
+        }
+
+        type = "bevel";
+        index = 1;
+      } else if(working_ instanceof EtchedBorder) {
+        EtchedBorder eb = (EtchedBorder)working_;
+
+/*        working_ = new EtchedBorder(eb.getEtchType(),
+                                    eb.getHighlightColor(),
+                                    eb.getShadowColor()); */
+
+        etchedHColorPanel.setColor(eb.getHighlightColor(this));
+        etchedSColorPanel.setColor(eb.getShadowColor(this));
+
+        int style = eb.getEtchType();
+        if(style == EtchedBorder.RAISED) {
+          etchedStyleCB.setSelectedItem("Raised");
+        } else if(style == EtchedBorder.LOWERED) {
+          etchedStyleCB.setSelectedItem("Lowered");
+        }
+
+        type = "etched";
+        index = 2;
+      } else if(working_ instanceof LineBorder) {
+        LineBorder lb = (LineBorder)working_;
+
+/*        working_ = new LineBorder(lb.getLineColor(),
+                                  lb.getThickness(),
+                                  lb.getRoundedCorners()); */
+
+        lineColorPanel.setColor(lb.getLineColor());
+
+        int thick = lb.getThickness();
+        lineTF.setText(Integer.toString(thick));
+        boolean round = lb.getRoundedCorners();
+        lineCB.setSelected(round);
+
+        type = "line";
+        index = 3;
+      }
+      if(titledCB.isSelected()) {
+        TitledBorder tb = (TitledBorder)border_;
+        titleTF.setText(tb.getTitle());
+        titleColorPanel.setColor(tb.getTitleColor());
+        int tindex = -1;
+        switch(tb.getTitlePosition()) {
+          case TitledBorder.ABOVE_TOP:
+            tindex = 0;
+            break;
+          default:
+          case TitledBorder.TOP:
+            tindex = 1;
+            break;
+          case TitledBorder.BELOW_TOP:
+            tindex = 2;
+            break;
+          case TitledBorder.ABOVE_BOTTOM:
+            tindex = 3;
+            break;
+          case TitledBorder.BOTTOM:
+            tindex = 4;
+            break;
+          case TitledBorder.BELOW_BOTTOM:
+            tindex = 5;
+            break;
+        }
+        positionCB.setSelectedIndex(tindex);
+        tindex = -1;
+        switch(tb.getTitleJustification()) {
+          default:
+          case TitledBorder.LEFT:
+            tindex = 0;
+            break;
+          case TitledBorder.CENTER:
+            tindex = 1;
+            break;
+          case TitledBorder.RIGHT:
+            tindex = 2;
+            break;
+        }
+        justCB.setSelectedIndex(tindex);
+        labelFont_ = tb.getTitleFont();
+        fontLabel.setText(fontString(labelFont_));
+      }
+    }
+    setTitledEnabled(titledCB.isEnabled());
+    borderTypeCB.setSelectedIndex(index);
+    ((CardLayout)cardPanel.getLayout()).show(cardPanel, type);
+    createNewBorder_ = true;
+  }
+
+  void borderTypeCB_actionPerformed(ActionEvent e) {
+    if(Page.DEBUG) System.out.println("ActionPerformed: new value = " + borderTypeCB.getSelectedItem());
+    int index = borderTypeCB.getSelectedIndex();
+    switch(index) {
+      case 0:
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "none");
+        break;
+      case 1:
+        if(createNewBorder_) working_ = new BevelBorder(BevelBorder.LOWERED);
+        init();
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "bevel");
+        break;
+      case 2:
+        if(createNewBorder_) working_ = new EtchedBorder(EtchedBorder.LOWERED);
+        init();
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "etched");
+        break;
+      case 3:
+        if(createNewBorder_) working_ = new LineBorder(Color.gray);
+        init();
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "line");
+        break;
+      default:
+        JOptionPane.showMessageDialog(this, "Selection Not Yet Implemented",
+                                      "Not Implemented", JOptionPane.ERROR_MESSAGE);
+        borderTypeCB.setSelectedIndex(0);
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "none");
+    }
+
+  }
+
+  void cancelButton_actionPerformed(ActionEvent e) {
+    setVisible(false);
+    dispose();
+  }
+
+  void okButton_actionPerformed(ActionEvent e) {
+    String borderType = (String)borderTypeCB.getSelectedItem();
+    if(borderType.equals("None")) {
+      working_ = null;
+      titledCB.setSelected(false);
+    } else if(borderType.equals("Beveled")) {
+      Color highlighto = bevelHOColorPanel.getColor();
+      Color highlighti = bevelHIColorPanel.getColor();
+      Color shadowo = bevelSOColorPanel.getColor();
+      Color shadowi = bevelSIColorPanel.getColor();
+      int style = BevelBorder.RAISED;
+      if(etchedStyleCB.getSelectedIndex() == 1) {
+        style = BevelBorder.LOWERED;
+      }
+      working_ = new BevelBorder(style, highlighto, highlighti,
+                                shadowo, shadowi);
+    } else if(borderType.equals("Etched")) {
+      Color highlight = etchedHColorPanel.getColor();
+      Color shadow = etchedSColorPanel.getColor();
+      int style = EtchedBorder.RAISED;
+      if(etchedStyleCB.getSelectedIndex() == 1) {
+        style = EtchedBorder.LOWERED;
+      }
+      working_ = new EtchedBorder(style, highlight, shadow);
+    } else if(borderType.equals("Line")) {
+      Color color = lineColorPanel.getColor();
+      int thick = Integer.parseInt(lineTF.getText());
+      boolean round = lineCB.isSelected();
+
+      working_ = new LineBorder(color, thick, round);
+    }
+    if(titledCB.isSelected()) {
+      int just = 0;
+      int pos = 0;
+      String posStr = (String)positionCB.getSelectedItem();
+      if(posStr.equals("Above Top")) {
+        pos = TitledBorder.ABOVE_TOP;
+      } else if (posStr.equals("Below Top")) {
+        pos = TitledBorder.BELOW_TOP;
+      } else if (posStr.equals("Above Bottom")) {
+        pos = TitledBorder.ABOVE_BOTTOM;
+      } else if (posStr.equals("Bottom")) {
+        pos = TitledBorder.BOTTOM;
+      } else if (posStr.equals("Below Bottom")) {
+        pos = TitledBorder.BELOW_BOTTOM;
+      } else {
+        pos = TitledBorder.TOP;
+      }
+      String justStr = (String)justCB.getSelectedItem();
+      if(justStr.equals("Rigt")) {
+        just = TitledBorder.RIGHT;
+      } else if(justStr.equals("Center")) {
+        just = TitledBorder.CENTER;
+      } else {
+        just = TitledBorder.LEFT;
+      }
+      border_ = new TitledBorder(working_,
+                                 titleTF.getText(),
+                                 just,
+                                 pos,
+                                 labelFont_,
+                                 titleColorPanel.getColor());
+    } else {
+      border_ = working_;
+    }
+    setVisible(false);
+    dispose();
+  }
+
+  void titledCB_actionPerformed(ActionEvent e) {
+    if(Page.DEBUG) System.out.println("ActionPerformed: new value = " + titledCB.isSelected());
+    setTitledEnabled(titledCB.isSelected());
+    if(titledCB.isSelected()) {
+      if(border_ instanceof TitledBorder) {
+        ((TitledBorder)border_).setBorder(working_);
+      } else {
+        border_ = new TitledBorder(working_,
+                                   titleTF.getText());
+        init();
+      }
+    }
+  }
+
+  void setTitledEnabled(boolean en) {
+    titleTF.setEnabled(en);
+    positionCB.setEnabled(en);
+    justCB.setEnabled(en);
+    titleColorPanel.setEnabled(en);
+    fontEditor.setEnabled(en);
+  }
+
+  void fontEditor_actionPerformed(ActionEvent e) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroup.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroup.java
new file mode 100755
index 0000000..6681ff2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroup.java
@@ -0,0 +1,431 @@
+/*
+ * $Id: DataGroup.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Graphics;
+import java.awt.Color;
+
+import gov.noaa.pmel.sgt.AxisTransform;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import javax.swing.event.*;
+import java.util.*;
+import java.io.*;
+import java.beans.*;
+
+/**
+ * A holder for the X and Y transforms and optionally references to the
+ * X and Y axes for a <code>CartesianGraph</code>.  This class is used with <code>DataModel</code>
+ * and <code>Panel</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+public class DataGroup implements Serializable, ChangeListener {
+  // axis position
+  /**
+   * X axis placed at top of <code>DataGroup</code> area.
+   */
+  public static final int TOP = 0;
+  /**
+   * X axis placed at bottom of <code>DataGroup</code> area.
+   */
+  public static final int BOTTOM = 1;
+  /**
+   * Y axis placed left of <code>DataGroup</code> area.
+   */
+  public static final int LEFT = 2;
+  /**
+   * Y axis placed right of <code>DataGroup</code> area.
+   */
+  public static final int RIGHT = 3;
+  /**
+   * Axes placed in default locations.
+   */
+  public static final int MANUAL = 4;
+  // axis transform / axis type
+  /**
+   * Linear transform type.
+   */
+  public static final int LINEAR = 0;
+  /**
+   * Log transform type.
+   */
+  public static final int LOG = 1;
+  /**
+   * Refer to a transform in another <code>DataGroup</code>.
+   */
+  public static final int REFERENCE = 2;
+  /**
+   * Time axis type.
+   */
+  public static final int TIME = 3;
+  /**
+   * Plain linear axis type.
+   */
+  public static final int PLAIN = 4;
+  //
+  /**
+   * X direction.
+   */
+  public static final int X_DIR = 0;
+  /**
+   * Y direction.
+   */
+  public static final int Y_DIR = 1;
+  //
+  private String id = "";
+  //
+  /**
+   * @label margin
+   */
+  private Margin margin = new Margin(0.25f, 0.5f, 0.5f, 0.25f);
+  private boolean zoomable = true;
+  //
+  /**
+   * @label xAxisHolder
+   * @supplierCardinality 1
+   * @undirected
+   * @link aggregation
+   */
+  private AxisHolder xAxisHolder_ = new AxisHolder(PLAIN, X_DIR, this);
+  /**
+   * @label yAxisHolder
+   * @link aggregation
+   * @undirected
+   * @supplierCardinality 1
+   */
+  private AxisHolder yAxisHolder_ = new AxisHolder(PLAIN, Y_DIR, this);
+  //
+  private boolean zAutoScale = true;
+  private SoTRange zRangeU = new SoTRange.Double(0.0, 1.0, 0.1);
+  private int numberAutoContourLevels = 10;
+  //
+  /**
+   * @label pHolder
+   */
+  private PanelHolder pHolder_ = null;
+  transient private Vector changeListeners;
+  transient private ChangeEvent changeEvent_ = new ChangeEvent(this);
+  transient private boolean instantiated = false;
+
+  static {
+    try {
+      BeanInfo info = Introspector.getBeanInfo(DataGroup.class);
+      PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+      for(int i=0; i < descriptors.length; i++) {
+        PropertyDescriptor pd = descriptors[i];
+        if(pd.getName().equals("instantiated")) {
+          pd.setValue("transient", Boolean.TRUE);
+        } else if(pd.getName().equals("panelHolder")) {
+          pd.setValue("transient", Boolean.TRUE);
+        }
+      }
+    } catch (IntrospectionException ie) {
+     ie.printStackTrace();
+    }
+  }
+  /**
+   * Default constructor.  <code>PanelHodler</code> is set to <code>null</code>.
+   * X and Y transforms are LINEAR and axes PLAIN.
+   */
+  public DataGroup() {
+    this("Default Id", null);
+  }
+  /**
+   * Simple constructor.  X and Y transforms are LINEAR and axes PLAIN.
+   * @param id data group id
+   * @param ph panelholder parent
+   */
+  public DataGroup(String id, PanelHolder ph) {
+    this(id, ph,
+         LINEAR, PLAIN,
+         LINEAR, PLAIN);
+  }
+  /**
+   * Full constructor.
+   * @param id data group id
+   * @param ph panelholder parent
+   * @param xt x transform type
+   * @param xAxis x axis type
+   * @param yt y transform type
+   * @param yAxis y axis type
+   */
+  public DataGroup(String id, PanelHolder ph,
+                   int xt, int xAxis,
+                   int yt, int yAxis) {
+    this.id = id;
+    pHolder_ = ph;
+    if(xAxisHolder_ == null) {
+      xAxisHolder_ = new AxisHolder(xAxis, X_DIR, this);
+    } else {
+      xAxisHolder_.setAxisType(xAxis);
+      xAxisHolder_.setAxisOrientation(X_DIR);
+      xAxisHolder_.setDataGroup(this);
+    }
+    xAxisHolder_.setTransformType(xt);
+    xAxisHolder_.addChangeListener(this);
+    if(yAxisHolder_ == null) {
+      yAxisHolder_ = new AxisHolder(yAxis, Y_DIR, this);
+    } else {
+      yAxisHolder_.setAxisType(yAxis);
+      yAxisHolder_.setAxisOrientation(Y_DIR);
+      yAxisHolder_.setDataGroup(this);
+    }
+    yAxisHolder_.setTransformType(yt);
+    yAxisHolder_.addChangeListener(this);
+  }
+  /**
+   * Set panelhodler parent.
+   * @param ph panelholder parent
+   */
+  public void setPanelHolder(PanelHolder ph) {
+    if(pHolder_ != null) removeChangeListener(pHolder_);
+    pHolder_ = ph;
+    addChangeListener(pHolder_);
+  }
+  /**
+   * Get parent.
+   * @return panelholder parent
+   */
+  public PanelHolder getPanelHolder() {
+    return pHolder_;
+  }
+  /**
+   * Get X axisholder
+   * @return x axisholder
+   */
+  public AxisHolder getXAxisHolder() {
+    return xAxisHolder_;
+  }
+  /**
+   * Set X axisholder
+   * @param xah x axisholder
+   */
+  public void setXAxisHolder(AxisHolder xah) {
+    xAxisHolder_ = xah;
+    xAxisHolder_.addChangeListener(this);
+  }
+  /**
+   * Get Y axisholder.
+   * @return y axisholder
+   */
+  public AxisHolder getYAxisHolder() {
+    return yAxisHolder_;
+  }
+  /**
+   * Set Y axisholder
+   * @param yah y axisholder
+   */
+  public void setYAxisHolder(AxisHolder yah) {
+    yAxisHolder_ = yah;
+    yAxisHolder_.addChangeListener(this);
+  }
+  /**
+   * Get datagroup id.
+   * @return datagroup id
+   */
+  public String getId() {
+    return id;
+  }
+  /**
+   * Set datagroup id.
+   * @param id datagroup id
+   */
+  public void setId(String id) {
+    String saved = this.id;
+    this.id = id;
+    if(!saved.equals(this.id)) fireStateChanged();
+  }
+  /**
+   * Get the margin.
+   * @return margin
+   */
+  public Margin getMargin() {
+    return (Margin)margin.copy();
+  }
+  /**
+   * Set the margin.  The margin is used to automatically place the axes in a
+   * <code>Panel</code>.  The margin is the distance from each edge of the
+   * <code>Panel</code> to the <code>DataGroup</code>.
+   * Default is (0.25f, 0.5f, 0.5f, 0.25f)
+   * @param margin margin
+   */
+  public void setMargin(Margin margin) {
+   Margin saved = this.margin;
+    this.margin = margin;
+    if(!saved.equals(this.margin)) fireStateChanged();
+  }
+  /**
+   * Set the Margin. Default is (0.25f, 0.5f, 0.5f, 0.25f)
+   * @param top top margin
+   * @param left left margin
+   * @param bottom bottom margin
+   * @param right right margin
+   */
+  public void setMargin(float top, float left, float bottom, float right) {
+    Margin saved = margin;
+    margin = new Margin(top, left, bottom, right);
+    if(!saved.equals(margin)) fireStateChanged();
+  }
+  /**
+   * Remove all <code>ChangeListener</code>s.
+   */
+  public void removeAllChangeListeners() {
+    changeListeners = null;
+  }
+  /**
+   * Set auto Z scale.  Auto Z scale is only effective for grids. Default = true.
+   * @param zAutoScale autoscale if true
+   */
+  public void setZAutoScale(boolean zAutoScale) {
+    boolean saved = this.zAutoScale;
+    this.zAutoScale = zAutoScale;
+    if(saved != zAutoScale) fireStateChanged();
+  }
+  /**
+   * Is auto Z scale?
+   * @return true, if auto z scale
+   */
+  public boolean isZAutoScale() {
+    return zAutoScale;
+  }
+  /**
+   * Set Z range, user units.  Only used if Auto Z Scale is false. Default =
+   * (0, 1, 0.1).
+   * @param zRange Z range
+   */
+  public void setZRangeU(SoTRange zRange) {
+    zRangeU = zRange;
+  }
+  /**
+   * Get Z range.
+   * @return Z range
+   */
+  public SoTRange getZRangeU() {
+    return zRangeU;
+  }
+  /**
+   * Set datagroup zoomable.  If true, datagroup can be zoomed using the mouse.
+   * Default = true.
+   * @param zoomable datagroup zoomable
+   */
+  public void setZoomable(boolean zoomable) {
+    boolean saved = this.zoomable;
+    this.zoomable = zoomable;
+    if(saved != this.zoomable) fireStateChanged();
+  }
+  /**
+   * Is datagroup zoomable?
+   * @return true, if datagroup zoomable
+   */
+  public boolean isZoomable() {
+    return zoomable;
+  }
+  /**
+   * Remove changelistener.
+   * @param l changelistener
+   */
+  public synchronized void removeChangeListener(ChangeListener l) {
+    if (changeListeners != null && changeListeners.contains(l)) {
+      Vector v = (Vector) changeListeners.clone();
+      v.removeElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Add changelistener
+   * @param l changelistener
+   */
+  public synchronized void addChangeListener(ChangeListener l) {
+    Vector v = changeListeners == null ? new Vector(2) : (Vector) changeListeners.clone();
+    if (!v.contains(l)) {
+      v.addElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Remove all <code>ChangeListener</code>s that implement the
+   * <code>DesignListener</code> interface.
+   *
+   * @see DesignListener
+   */
+  public synchronized void removeDesignChangeListeners() {
+    if(changeListeners != null) {
+      Vector v = (Vector) changeListeners.clone();
+      Iterator iter = v.iterator();
+      while(iter.hasNext()) {
+        Object obj = iter.next();
+        if(obj instanceof DesignListener) changeListeners.removeElement(obj);
+      }
+    }
+  }
+
+  protected void fireStateChanged() {
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(changeEvent_);
+      }
+    }
+  }
+  /**
+   * Set instantiated.  Once associated <code>DataGroupLayer</code> object has been created
+   * this property is set true.  Used internally.
+   * @param instantiated true if instantiated
+   */
+  public void setInstantiated(boolean instantiated) {
+    this.instantiated = instantiated;
+  }
+  /**
+   * Is datagrouplayer instantiated?
+   * @return true, if datagrouplayer instantiated
+   */
+  public boolean isInstantiated() {
+    return instantiated;
+  }
+  /**
+   * <code>ChangeListner</code> callback.
+   * @param e ChangeEvent
+   */
+  public void stateChanged(ChangeEvent e) {
+    fireStateChanged();
+  }
+  /**
+   * Get number of auto contour levels.  Valid for grid type data only.
+   * @return number of auto contour levels
+   */
+  public int getNumberAutoContourLevels() {
+    return numberAutoContourLevels;
+  }
+  /**
+   * Set number of auto contour levels. Valid for grid type data only.
+   * @param numberAutoContourLevels number of contour levels
+   */
+  public void setNumberAutoContourLevels(int numberAutoContourLevels) {
+    int saved = this.numberAutoContourLevels;
+    this.numberAutoContourLevels = numberAutoContourLevels;
+    if(saved != this.numberAutoContourLevels) fireStateChanged();
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupDragBox.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupDragBox.java
new file mode 100755
index 0000000..e12b1a2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupDragBox.java
@@ -0,0 +1,161 @@
+/*
+ * $Id: DataGroupDragBox.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+//import gov.noaa.pmel.util.Rectangle2D;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class DataGroupDragBox extends DragBox implements ChangeListener {
+  private Rectangle boundsD_ = new Rectangle();
+  private DataGroup dg_ = null;
+  private AxisHolderDragBox xAxDB_ = null;
+  private AxisHolderDragBox yAxDB_ = null;
+
+  public DataGroupDragBox(DataGroup dg, PanelHolder pHolder) {
+    super(pHolder);
+    dg_ = dg;
+    dg_.addChangeListener(this);
+    for(int i=0; i < handles_.length;  i++) {
+      handles_[i] = new Rectangle(0,0,0,0);
+    }
+    update("DataGroupDragBox.new()");
+  }
+
+  public DataGroup getDataGroup() {
+    return dg_;
+  }
+
+  public void setBounds(Rectangle bounds) {
+    boundsD_ = bounds;
+    dg_.setMargin(computeMargin());
+    computeHandles();
+  }
+
+  private Margin computeMargin() {
+    Rectangle panel = pHolder_.getBounds();
+    float dpi = pHolder_.getPanelModel().getDpi();
+    float top = ((float)(boundsD_.y - panel.y))/dpi;
+    float bottom = ((float)((panel.y + panel.height) - (boundsD_.y + boundsD_.height)))/dpi;
+    float left = ((float)(boundsD_.x - panel.x))/dpi;
+    float right = ((float)((panel.x + panel.width) - (boundsD_.x + boundsD_.width)))/dpi;
+    return new Margin(top, left, bottom, right);
+  }
+
+  public void draw(Graphics g) {
+    Rectangle bounds = getBounds();
+    Color savedColor = g.getColor();
+    if(selected_) {
+      g.setColor(Color.red);
+    } else {
+      g.setColor(Color.green);
+    }
+    // draw AxisHolder
+
+    // draw rectangle dashed
+    Rectangle2D rect = new Rectangle2D.Float(bounds.x, bounds.y,
+        bounds.width, bounds.height);
+    Graphics2D g2 = (Graphics2D)g;
+    Stroke saved = g2.getStroke();
+    float[] dashes = {4.0f, 4.0f};
+    BasicStroke stroke = new BasicStroke(1.0f,
+                                         BasicStroke.CAP_SQUARE,
+                                         BasicStroke.JOIN_MITER,
+                                         10.0f,
+                                         dashes,
+                                         0.0f);
+    g2.setStroke(stroke);
+    g2.draw(rect);
+    g2.setStroke(saved);
+    // Name
+/*    if(dg_.getXPosition() == DataGroup.BOTTOM) {
+      yString += BOX_HEIGHT - 2;
+    } else {
+      yString += BOX_HEIGHT - TIC_LENGTH - 2;
+    }
+    g.drawString(dg_.getId(), xBoundsD_.x + 5, yString); */
+
+    if(selected_) {
+      for(int i=0; i < handles_.length; i++) {
+        Rectangle r = handles_[i];
+        g.fillRect(r.x, r.y, r.width-1, r.height-1);
+      }
+    }
+
+    g.setColor(savedColor);
+  }
+
+
+  public void update(String message) {
+//    if(Page.DEBUG) System.out.println("DataGroupDragBox.update(" + message + ")");
+    Rectangle panel = pHolder_.getBounds();
+    Margin margin = dg_.getMargin();
+    float dpi = pHolder_.getPanelModel().getDpi();
+    int left = (int)(margin.left*dpi);
+    int right = (int)(margin.right*dpi);
+    int top = (int)(margin.top*dpi);
+    int bottom = (int)(margin.bottom*dpi);
+    boundsD_.x = panel.x + left;
+    boundsD_.y = panel.y + top;
+    boundsD_.width = panel.width - (left + right);
+    boundsD_.height = panel.height - (top + bottom);
+    computeHandles();
+  }
+
+  public void setLocation(Point pt) {
+    boundsD_.x = pt.x;
+    boundsD_.y = pt.y;
+    dg_.setMargin(computeMargin());
+    computeHandles();
+  }
+
+  public Point getLocation() {
+    return new Point(boundsD_.x, boundsD_.y);
+  }
+
+  public Rectangle getBounds() {
+    return boundsD_;
+  }
+
+  public String getId() {
+    return dg_.getId();
+  }
+
+  public void setId(String id) {
+    dg_.setId(id);
+  }
+
+  public void setAxisHolderDB(AxisHolderDragBox x, AxisHolderDragBox y) {
+    xAxDB_ = x;
+    yAxDB_ = y;
+  }
+
+  public AxisHolderDragBox getXAxisHolderDB() {
+    return xAxDB_;
+  }
+
+  public AxisHolderDragBox getYAxisHolderDB() {
+    return yAxDB_;
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    update("DataGroupDragBox.stateChanged()");
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupLayer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupLayer.java
new file mode 100755
index 0000000..c1080dd
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupLayer.java
@@ -0,0 +1,782 @@
+/*
+ * $Id: DataGroupLayer.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.util.List;
+import java.util.Vector;
+import java.util.Iterator;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.Graphics;
+
+import javax.swing.JOptionPane;
+
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.AxisTransform;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.LogTransform;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.LogAxis;
+import gov.noaa.pmel.sgt.AxisNotFoundException;
+import gov.noaa.pmel.sgt.Attribute;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.CartesianRenderer;
+import gov.noaa.pmel.sgt.PaneNotFoundException;
+import gov.noaa.pmel.sgt.DataKey;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.sgt.TransformAccess;
+import gov.noaa.pmel.sgt.ContourLevelsAccess;
+import gov.noaa.pmel.sgt.ContourLevels;
+
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTDomain;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+
+/**
+ * A holder for <code>DataGroup</code> and <code>Layer</code> associated with
+ * axes and <code>Graph</code>. Multiple sets of data can be added to a DataGroupLayer,
+ * but each will share the same <code>DataGroup</code>.  I.e., the same axes and
+ * transforms.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ * @see Page Page for UML diagram
+ * @stereotype container
+ **/
+public class DataGroupLayer extends Layer {
+  private List dataLayers_ = new Vector();
+
+  /**
+   * @label dg
+   */
+  private DataGroup dg_ = null;
+
+  /**
+   * @label pHolder
+   */
+  private PanelHolder pHolder_ = null;
+  private Panel panel_ = null;
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private boolean clipping_ = false;
+  private SoTDomain clipDomain_ = null;
+  //
+  private SoTRange xZoomRange_ = null;
+  private SoTRange yZoomRange_ = null;
+  private boolean inZoom_ = false;
+  //
+  private SGLabel xLabel_ = null;
+  private SGLabel yLabel_ = null;
+
+  /**
+   * Default constructor.  <code>Panel</code> and <code>DataGroup</code> must
+   * be specified.
+   */
+  public DataGroupLayer() {
+    this(null, null);
+  }
+
+  /**
+   * Construct <code>DataGroupLayer</code>.
+   * @param panel parent
+   * @param dg datagroup
+   */
+  public DataGroupLayer(Panel panel, DataGroup dg) {
+    super();
+    panel_ = panel;
+    setPane(panel.getPane());
+    pHolder_ = dg.getPanelHolder();
+    setGraph(new CartesianGraph("Graph"));
+    dg_ = dg;
+    setId(dg_.getId());
+    update();
+  }
+
+  /**
+   * Get the <code>Panel</code> parent.
+   * @return panel
+   */
+  public Panel getPanel() {
+    return panel_;
+  }
+
+  /**
+   * Get <code>DataGroup</code>
+   * @return the datagroup
+   */
+  public DataGroup getDataGroup() {
+    return dg_;
+  }
+
+  /**
+   * Get <code>Layer</code> <code>Iterator</code>.
+   * @return iterator of Layers
+   */
+  public Iterator getLayerIterator() {
+    return dataLayers_.iterator();
+  }
+
+  /**
+   * Get a <code>List</code> of the <code>Layer</code>s.
+   * @return layer list
+   */
+  public List getLayerList() {
+    return dataLayers_;
+  }
+
+  private String getNextLayerId() {
+    int count = dataLayers_.size() + 1;
+    return getId() + "_" + count;
+  }
+
+  /**
+   * Add data to the <code>DataGroupLayer</code>.
+   * @param data SGTData
+   * @param attr Attribute associated with data
+   * @param key DataKey
+   * @throws DataTargetMismatchException
+   */
+  public void addData(SGTData data, Attribute attr, DataKey key) throws DataTargetMismatchException {
+    if(Page.DEBUG) {
+      System.out.println("DataGroupLayer.addData: data = " + data.toString());
+      System.out.println("DataGroupLayer.addData: xTime = " + data.isXTime() + ", yTime = " + data.isYTime());
+      System.out.println("DataGroupLayer.addData: attr = " + attr.toString());
+      System.out.println("DataGroupLayer.addData: key = " + key);
+      System.out.println("DataGroupLayer.addData: xRange = " + data.getXRange());
+      System.out.println("DataGroupLayer.addData: yRange = " + data.getYRange());
+      if(data instanceof SGTGrid)
+        System.out.println("DataGroupLayer.addData: zRange = " + ((SGTGrid)data).getZRange());
+      else
+        System.out.println("DataGroupLayer.addData: zRange = <no zRange>");
+    }
+    /** @todo add data check */
+    CartesianGraph graph = (CartesianGraph)getGraph();
+    if((graph.getXTransform().isTime() != data.isXTime()) ||
+       graph.getYTransform().isTime() != data.isYTime()) {
+      JOptionPane.showMessageDialog(this, "Added data does not have the\n" +
+                                    "same axis types as the DataGroup\n\n" +
+                                    "Time or Space axis does not match.",
+                                    "DataGroup Error", JOptionPane.ERROR_MESSAGE);
+      throw new DataTargetMismatchException("Data - Axis Mismatch");
+    }
+
+    CartesianRenderer rend = graph.getRenderer();
+    if(rend == null) {  // first data on DataGroupLayer
+      xRange_ = data.getXRange();
+      yRange_ = data.getYRange();
+      graph.setData(data, attr);
+      dataLayers_.add(this);
+
+      StringBuffer label = new StringBuffer(data.getXMetaData().getName());
+      String units = data.getXMetaData().getUnits();
+      if(units != null && units.length() > 0) {
+        label.append(" (").append(units).append(")");
+      }
+      xLabel_ = new SGLabel("X Axis Label", label.toString(), new Point2D.Double(0.0, 0.0));
+
+      label = new StringBuffer(data.getYMetaData().getName());
+      units = data.getYMetaData().getUnits();
+      if(units != null && units.length() > 0) {
+        label.append(" (").append(units).append(")");
+      }
+      yLabel_ = new SGLabel("Y Axis Label", label.toString(), new Point2D.Double(0.0, 0.0));
+    } else {  // adding data to DataGroupLayer
+      xRange_.add(data.getXRange());
+      yRange_.add(data.getYRange());
+      // more data, create new layer
+      Layer ly = new Layer(getNextLayerId());
+      CartesianGraph cg = new CartesianGraph("Graph_"+ly.getId(),
+          graph.getXTransform(), graph.getYTransform());
+      ly.setPane(getPane());
+      ly.setSizeP(getSizeP());
+      ly.setBounds(getBounds());
+      ly.setGraph(cg);
+      cg.setData(data, attr);
+      dataLayers_.add(ly);
+      if(clipping_) cg.setClip(clipDomain_.getXRange(), clipDomain_.getYRange());
+      graph = cg;
+    }
+
+    if(dg_.isZAutoScale() && attr != null && attr instanceof GridAttribute) {
+      Range2D zRange = ((SGTGrid)data).getZRange();
+      ColorMap cmap = ((GridAttribute)attr).getColorMap();
+      if(cmap instanceof TransformAccess) {
+        ((TransformAccess)cmap).setRange(zRange);
+      } else if(cmap instanceof ContourLevelsAccess) {
+        ContourLevels cl = ((ContourLevelsAccess)cmap).getContourLevels();
+        int levels = dg_.getNumberAutoContourLevels();
+        Range2D newRange = Graph.computeRange(zRange, levels);
+        ((ContourLevelsAccess)cmap).setContourLevels(ContourLevels.getDefault(newRange));
+      }
+    }
+
+    if(key != null) {
+      rend = graph.getRenderer();
+      SGLabel label = getLabel(data, key);
+      key.addGraph(rend, label);
+    }
+    update();
+  }
+
+  private SGLabel getLabel(SGTData data, DataKey key) {
+    SGLabel lineTitle = data.getKeyTitle();
+    if(lineTitle == null) {
+      lineTitle = xLabel_;
+    }
+    Legend lg = pHolder_.findLegend(key.getId());
+    lineTitle.setHeightP(lg.getKeyLabelHeightP());
+    return lineTitle;
+  }
+
+  /**
+   * Update <code>DataGroupLayer</code>.  Used internally.
+   */
+  public void update() {
+    Rectangle bnds = pHolder_.getBounds();
+    double dpi = pHolder_.getPanelModel().getDpi();
+    double width = bnds.width/dpi;
+    double height = bnds.height/dpi;
+    SoTRange xRange = null;
+    SoTRange yRange = null;
+    SoTPoint xOrig = null;
+    SoTPoint yOrig = null;
+
+    boolean batch = getPane().isBatch();
+    getPane().setBatch(true);
+
+    AxisHolder xAxHolder = dg_.getXAxisHolder();
+    AxisHolder yAxHolder = dg_.getYAxisHolder();
+    CartesianGraph gr = (CartesianGraph)getGraph();
+
+    this.setSizeP(new Dimension2D(width, height));
+    // determine correct range
+    if(inZoom_) {
+      xRange = xZoomRange_;
+      yRange = yZoomRange_;
+    } else {
+      if(!xAxHolder.isAutoRange() || xRange_ == null) {
+        xRange = xAxHolder.getUserRange();
+      } else {
+        xRange = xRange_;
+      }
+      if(!yAxHolder.isAutoRange() || yRange_ == null) {
+        yRange = yAxHolder.getUserRange();
+      } else {
+        yRange = yRange_;
+      }
+    }
+    // transform setup
+    updateTransform(DataGroup.X_DIR, xRange);
+    updateTransform(DataGroup.Y_DIR, yRange);
+    // determine axes origins
+    // xaxis
+    Margin marg = dg_.getMargin();
+    if(xAxHolder.getAxisPosition() == DataGroup.MANUAL) {
+      xOrig = new SoTPoint(gr.getXPtoSoT(xAxHolder.getAxisOriginP().x),
+                           gr.getYPtoSoT(xAxHolder.getAxisOriginP().y));
+    } else {
+      SoTValue yloc = null;
+      SoTRange range = null;
+      if(yAxHolder.getAxisPosition() == DataGroup.MANUAL) {
+        if(gr.getYTransform().isTime()) {
+          range = new SoTRange.Time(gr.getYPtoLongTime(marg.bottom),
+                                    gr.getYPtoLongTime(marg.top));
+        } else {
+          range = new SoTRange.Double(gr.getYPtoU(marg.bottom), gr.getYPtoU(marg.top));
+        }
+      } else {
+        range = yRange;
+      }
+      switch(xAxHolder.getAxisPosition()) {
+        case DataGroup.BOTTOM:
+          yloc = range.getStart();
+          break;
+        case DataGroup.TOP:
+          yloc = range.getEnd();
+          break;
+      }
+      xOrig = new SoTPoint(xRange.getStart(), yloc);
+    }
+    // yaxis
+    if(yAxHolder.getAxisPosition() == DataGroup.MANUAL) {
+      yOrig = new SoTPoint(gr.getXPtoSoT(yAxHolder.getAxisOriginP().x),
+                           gr.getYPtoSoT(yAxHolder.getAxisOriginP().y));
+    } else {
+      SoTValue xloc = null;
+      SoTRange range = null;
+      if(xAxHolder.getAxisPosition() == DataGroup.MANUAL) {
+        if(gr.getXTransform().isTime()) {
+          range = new SoTRange.Time(gr.getXPtoLongTime(marg.left),
+                                    gr.getXPtoLongTime(marg.right));
+        } else {
+          range = new SoTRange.Double(gr.getXPtoU(marg.left), gr.getXPtoU(marg.right));
+        }
+      } else {
+        range = xRange;
+      }
+      switch(yAxHolder.getAxisPosition()) {
+        case DataGroup.LEFT:
+          xloc = range.getStart();
+          break;
+        case DataGroup.RIGHT:
+          xloc = range.getEnd();
+          break;
+      }
+      yOrig = new SoTPoint(xloc, yRange.getStart());
+    }
+
+    updateAxis(DataGroup.X_DIR, xRange, xOrig, xLabel_);
+    updateAxis(DataGroup.Y_DIR, yRange, yOrig, yLabel_);
+
+    getPane().setBatch(batch);
+
+    if(Page.DEBUG) {
+      System.out.println("layer: " + getSize() + ", " + getSizeP());
+      System.out.println("xTrans: " + gr.getXTransform().getRangeP() + ", " +
+                         gr.getXTransform().getSoTRangeU());
+      System.out.println("yTrans: " + gr.getYTransform().getRangeP() + ", " +
+                         gr.getYTransform().getSoTRangeU());
+    }
+  }
+
+  private void updateTransform(int dir, SoTRange range) {
+    AxisTransform at;
+    AxisHolder ah;
+    CartesianGraph gr = (CartesianGraph)getGraph();
+
+    if(dir == DataGroup.X_DIR) {
+      ah = dg_.getXAxisHolder();
+      at = gr.getXTransform();
+    } else {
+      ah = dg_.getYAxisHolder();
+      at = gr.getYTransform();
+    }
+
+    switch(ah.getTransformType()) {
+      case DataGroup.LINEAR:
+        if(at instanceof LinearTransform) {
+          at.setRangeU(range);
+          at.setRangeP(ah.getRangeP());
+        } else  {
+          at = new LinearTransform(ah.getRangeP(), range);
+          gr.setXTransform(at);
+        }
+        break;
+      case DataGroup.LOG:
+        if(at instanceof LogTransform) {
+          at.setRangeU(range);
+          at.setRangeP(ah.getRangeP());
+        } else {
+          at = new LogTransform(ah.getRangeP(), range);
+          gr.setXTransform(at);
+        }
+        break;
+      case DataGroup.REFERENCE:
+        at = getReferenceTransform(DataGroup.X_DIR, ah.getTransformGroup());
+        gr.setXTransform(at);
+    }
+  }
+
+  private void updateAxis(int dir, SoTRange range,
+                          SoTPoint origin, SGLabel title) {
+    String axis;
+    Axis ax = null;
+    AxisTransform at;
+    AxisHolder ah;
+    boolean newAxis = true;
+    CartesianGraph gr = (CartesianGraph)getGraph();
+
+    if(dir == DataGroup.X_DIR) {
+      axis = "X Axis";
+      ah = dg_.getXAxisHolder();
+      at = gr.getXTransform();
+    } else {
+      axis = "Y Axis";
+      ah = dg_.getYAxisHolder();
+      at = gr.getYTransform();
+    }
+
+    try {
+      ax = gr.getXAxis(axis);
+    } catch (AxisNotFoundException anfe) {
+      ax = null;
+    }
+    newAxis = false;
+    switch(ah.getAxisType()) {
+      case DataGroup.PLAIN:
+        PlainAxis pax = null;
+        if(ax != null) {
+          if(ax instanceof PlainAxis) {
+            pax = (PlainAxis)ax;
+          } else {
+            pax = new PlainAxis(axis);
+            newAxis = true;
+          }
+        } else {
+          pax = new PlainAxis(axis);
+          newAxis = true;
+        }
+        ax = pax;
+        pax.setRangeP(ah.getRangeP());
+        pax.setRangeU(range);
+        pax.setLabelFormat(ah.getLabelFormat());
+        pax.setLabelInterval(ah.getLabelInterval());
+        pax.setSignificantDigits(ah.getLabelSignificantDigits());
+        break;
+      case DataGroup.TIME:
+        TimeAxis tax = null;
+        if(ax != null) {
+          if(ax instanceof TimeAxis) {
+            tax = (TimeAxis)ax;
+          } else {
+            tax = new TimeAxis(axis, ah.getTimeAxisStyle());
+            newAxis = true;
+          }
+        } else {
+          tax = new TimeAxis(axis, ah.getTimeAxisStyle());
+          newAxis = true;
+        }
+        ax = tax;
+        tax.setRangeP(ah.getRangeP());
+        tax.setRangeU(range);
+        if(ah.getTimeAxisStyle() != TimeAxis.AUTO) {
+          tax.setLabelFormat(ah.getMinorFormat(),
+                             ah.getMajorFormat());
+          tax.setLabelInterval(ah.getMinorInterval(),
+                               ah.getMajorInterval());
+        }
+        break;
+      case DataGroup.LOG:
+        LogAxis lax = null;
+        if(ax != null) {
+          if(ax instanceof LogAxis) {
+            lax = (LogAxis)ax;
+          } else {
+            lax = new LogAxis(axis);
+            newAxis = true;
+          }
+        } else {
+          lax = new LogAxis(axis);
+          newAxis = true;
+        }
+        ax = lax;
+        lax.setRangeP(ah.getRangeP());
+        lax.setRangeU(range);
+        lax.setLabelFormat(ah.getLabelFormat());
+        lax.setLabelInterval(ah.getLabelInterval());
+        lax.setSignificantDigits(ah.getLabelSignificantDigits());
+    }
+    if(dir == DataGroup.X_DIR) {
+      ax.setOrientation(Axis.HORIZONTAL);
+    } else {
+      ax.setOrientation(Axis.VERTICAL);
+    }
+    ax.setLocationU(origin);
+    ax.setLineColor(ah.getAxisColor());
+    ax.setTicPosition(ah.getTicPosition());
+    ax.setLabelColor(ah.getLabelColor());
+    ax.setLabelFont(ah.getLabelFont());
+    ax.setLabelHeightP(ah.getLabelHeightP());
+    ax.setLargeTicHeightP(ah.getLargeTicHeightP());
+    ax.setNumberSmallTics(ah.getNumSmallTics());
+    ax.setSmallTicHeightP(ah.getSmallTicHeightP());
+    ax.setThickTicWidthP(ah.getThickTicWidth());
+    ax.setLabelPosition(ah.getLabelPosition());
+    ax.setVisible(ah.isVisible());
+    if(title != null && ah.isTitleAuto()) {
+      SGLabel def = ah.getTitle();
+      title.setColor(def.getColor());
+      title.setFont(def.getFont());
+      title.setHeightP(def.getHeightP());
+      title.setVisible(def.isVisible());
+      ax.setTitle(title);
+    } else {
+      ax.setTitle(ah.getTitle());
+    }
+    ax.register(at);
+    if(dir == DataGroup.X_DIR) {
+      if(gr.getNumberXAxis() > 0 && newAxis) {
+        gr.removeAllXAxes();
+      }
+      if(newAxis) gr.addXAxis(ax);
+    } else {
+      if(gr.getNumberYAxis() > 0 && newAxis) {
+        gr.removeAllYAxes();
+      }
+      if(newAxis) gr.addYAxis(ax);
+    }
+  }
+
+  //
+  // replicate Layer methods and pass on to
+  // all children Layer's
+  //
+  public void draw(Graphics g) throws PaneNotFoundException {
+    super.draw(g);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).draw(g);
+    }
+  }
+
+  public void drawDraggableItems(Graphics g) throws PaneNotFoundException {
+    super.drawDraggableItems(g);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).drawDraggableItems(g);
+    }
+  }
+
+  public void setBounds(int x, int y, int w, int h) {
+    super.setBounds(x, y, w, h);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setBounds(x, y, w, h);
+    }
+  }
+
+  public void setBounds(Rectangle rect) {
+    super.setBounds(rect);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setBounds(rect);
+    }
+  }
+
+  public void setLocation(int x, int y) {
+    super.setLocation(x, y);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setLocation(x, y);
+    }
+  }
+
+  public void setLocation(Point pt) {
+    super.setLocation(pt);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setLocation(pt);
+    }
+  }
+
+  public void setSize(Dimension size) {
+    super.setSize(size);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setSize(size);
+    }
+  }
+
+  public void setSize(int w, int h) {
+    super.setSize(w, h);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setSize(w, h);
+    }
+  }
+
+  public void setSizeP(Dimension2D size) {
+    super.setSizeP(size);
+    for(int i=1; i < dataLayers_.size(); i++) {
+      ((Layer)dataLayers_.get(i)).setSizeP(size);
+    }
+  }
+
+  private AxisTransform getReferenceTransform(int dir, String datagroup) {
+//    PanelHolder ph = dg_.getPanelHolder();
+    String dgLast = datagroup;
+    boolean stillLooking = true;
+    int tType = -1;
+    String newDG = null;
+    while(stillLooking) {
+      DataGroup dg = pHolder_.findDataGroup(dgLast);
+      if(dir == DataGroup.X_DIR) {
+        tType = dg.getXAxisHolder().getTransformType();
+      } else {
+        tType = dg.getYAxisHolder().getTransformType();
+      }
+      if(tType != DataGroup.REFERENCE) {
+        CartesianGraph graph = null;
+        Layer dgl = null;
+        /** @todo resolve instatiation order issue */
+        if(dir == DataGroup.X_DIR) {
+          dgl =  panel_.findDataGroupLayer(dg.getXAxisHolder().getTransformGroup());
+          graph = (CartesianGraph)dgl.getGraph();
+          if(graph == null) return null;  // graph and transform not yet created
+          return graph.getXTransform();
+        } else {
+          dgl = panel_.findDataGroupLayer(dg.getYAxisHolder().getTransformGroup());
+          graph = (CartesianGraph)dgl.getGraph();
+          if(graph == null) return null;
+          return graph.getYTransform();
+        }
+      }
+      if(dir == DataGroup.X_DIR) {
+        newDG = dg.getXAxisHolder().getTransformGroup();
+      } else {
+        newDG = dg.getYAxisHolder().getTransformGroup();
+      }
+      dgLast = newDG;
+    }
+    return null;
+  }
+
+  /**
+   * Set clipping for <code>DataGroupLayer</code>
+   * @param clip if true clip data to bounds.
+   */
+  public void setClipping(boolean clip) {
+    if(!dg_.isZoomable()) return;
+    if(Page.DEBUG) System.out.println("DataGroupLayer: " + getId() + ": clip = " + clip);
+    clipping_ = clip;
+    setAllClipping(clipping_);
+  }
+
+  /**
+   * Zoom <code>DataGroupLayer</code>.  Zoom to <code>Rectangle</code> if zoom
+   * operation started within bounds.
+   * @param start start point
+   * @param rect zoom rectangle
+   */
+  void zoomTo(Point start, Rectangle rect) {
+    if(!dg_.isZoomable()) return;
+    CartesianGraph graph = (CartesianGraph)getGraph();
+    Rectangle gbnds = getGraphBounds();
+    Rectangle bnds = getPanelBounds();
+    if(!gbnds.contains(start)) return;
+    setClipping(true);
+    double xStartP = getXDtoP(rect.x);
+    double yStartP = getYDtoP(rect.y + rect.height);
+    double xEndP = getXDtoP(rect.x + rect.width);
+    double yEndP = getYDtoP(rect.y);
+    SoTRange xRangeU = null;
+    SoTRange yRangeU = null;
+    if(graph.getXTransform().isTime()) {
+      xRangeU = new SoTRange.Time(graph.getXPtoLongTime(xStartP), graph.getXPtoLongTime(xEndP));
+    } else {
+      xRangeU = new SoTRange.Double(graph.getXPtoU(xStartP), graph.getXPtoU(xEndP));
+    }
+    if(graph.getYTransform().isTime()) {
+      yRangeU = new SoTRange.Time(graph.getYPtoLongTime(yStartP), graph.getYPtoLongTime(yEndP));
+    } else {
+      yRangeU = new SoTRange.Double(graph.getYPtoU(yStartP), graph.getYPtoU(yEndP));
+    }
+    inZoom_ = true;
+    setDomain(new SoTDomain(xRangeU, yRangeU));
+  }
+
+  /**
+   * Reset the zoom for this <code>DataGroupLayer</code> if it contains the point.
+   * @param x x device coordinate
+   * @param y y device coordinate
+   */
+  void resetZoom(int x, int y) {
+    if(!dg_.isZoomable()) return;
+    Rectangle bnds = getGraphBounds();
+    if(!bnds.contains(x, y)) return;
+    if(Page.DEBUG) System.out.println("DataGroupLayer: " + getId() + ": " + x +", " + y);
+    inZoom_ = false;
+    xZoomRange_ = null;
+    yZoomRange_ = null;
+    setClipping(false);
+    update();
+  }
+  /**
+   * Reset the zoom for this <code>DataGroupLayer</code>.
+   */
+  public void resetZoom() {
+    inZoom_ = false;
+    xZoomRange_ = null;
+    yZoomRange_ = null;
+    setClipping(false);
+    update();
+  }
+
+  /**
+   * Set <code>DataGroupLayer</code> domain.
+   * @param domain domain
+   */
+  public void setDomain(SoTDomain domain) {
+    setXRange(domain.getXRange(), domain.isXReversed());
+    setYRange(domain.getYRange(), domain.isYReversed());
+    if(clipping_) {
+      clipDomain_ = domain;
+      setAllClip(domain);
+    } else {
+      clipDomain_ = null;
+      setAllClipping(false);
+    }
+    update();
+    if(Page.DEBUG) {
+      System.out.println("DataGroupLayer().setDomain: " + getId());
+      System.out.println("        domain.XRange = " + domain.getXRange());
+      System.out.println("        domain.YRange = " + domain.getYRange());
+      System.out.println("           isClipping = " + clipping_);
+    }
+  }
+
+  private void setXRange(SoTRange range, boolean reversed) {
+    xZoomRange_ = range.copy();
+  }
+
+  private void setYRange(SoTRange range, boolean reversed) {
+    yZoomRange_ = range.copy();
+  }
+
+  private void setAllClip(SoTDomain domain) {
+    Iterator iter = dataLayers_.iterator();
+    while(iter.hasNext()) {
+      Object obj = iter.next();
+      if(obj instanceof Layer) {
+        Layer ly = (Layer)obj;
+        ((CartesianGraph)ly.getGraph()).setClip(domain.getXRange(),
+                                                domain.getYRange());
+      }
+    }
+  }
+
+  private void setAllClipping(boolean clip) {
+    Iterator iter = dataLayers_.iterator();
+    while(iter.hasNext()) {
+      Object obj = iter.next();
+      if(obj instanceof Layer) {
+        Layer ly = (Layer)obj;
+        ((CartesianGraph)ly.getGraph()).setClipping(clip);
+      }
+    }
+  }
+
+  private Rectangle getPanelBounds() {
+    return pHolder_.getBounds();
+  }
+
+  private Rectangle getGraphBounds() {
+    CartesianGraph graph = (CartesianGraph)getGraph();
+    AxisTransform xTrans = graph.getXTransform();
+    AxisTransform yTrans = graph.getYTransform();
+    Range2D xRange = xTrans.getRangeP();
+    Range2D yRange = yTrans.getRangeP();
+    int x = getXPtoD(xRange.start);
+    int y = getYPtoD(yRange.end);
+    int width = getXPtoD(xRange.end) - x;
+    int height = getYPtoD(yRange.start) - y;
+    return new Rectangle(x, y, width, height);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupPropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupPropertyPanel.java
new file mode 100755
index 0000000..56b7879
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataGroupPropertyPanel.java
@@ -0,0 +1,204 @@
+/*
+ * $Id: DataGroupPropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import javax.swing.*;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Iterator;
+
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.LogAxis;
+import gov.noaa.pmel.sgt.LogTransform;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class DataGroupPropertyPanel extends PropertyPanel
+    implements ActionListener, ChangeListener, FocusListener {
+  private boolean expert_ = false;
+  private String[] pNames_ = {"Id", "Margin", "Zoomable", "Z AutoScale", "Z Auto Levels", "Z User Range"};
+  private JComponent[] comps_ = new JComponent[pNames_.length];
+  private DataGroup dataGroup_ = null;
+  private boolean suppressEvent_ = false;
+  private int zAutoScale, zUserRange, zAutoLevels;
+
+  public DataGroupPropertyPanel(DataGroup dg, boolean expert) {
+    super();
+    dataGroup_ = dg;
+    dataGroup_.addChangeListener(this);
+    expert_ = expert;
+    create();
+  }
+
+  public void setDataGroup(DataGroup dg, boolean expert) {
+    if(dataGroup_ != null) dataGroup_.removeChangeListener(this);
+    dataGroup_ = dg;
+    dataGroup_.addChangeListener(this);
+    expert_ = expert;
+    reset();
+  }
+
+  void update() {
+    int i = -1;
+    suppressEvent_ = true;
+    int item = -1;
+    ((JTextField)comps_[++i]).setText(dataGroup_.getId());
+    ((JLabel)comps_[++i]).setText(dataGroup_.getMargin().toString());
+    ((JCheckBox)comps_[++i]).setSelected(dataGroup_.isZoomable());
+    //
+    // z stuff
+    //
+    ((JCheckBox)comps_[++i]).setSelected(dataGroup_.isZAutoScale());
+    ((JTextField)comps_[++i]).setText(format(dataGroup_.getNumberAutoContourLevels()));
+    ((JTextField)comps_[++i]).setText(format(dataGroup_.getZRangeU(), false));
+    //
+    setFieldsEnabled();
+    //
+    suppressEvent_ = false;
+  }
+
+  void create() {
+    int i = -1;
+    int item = -1;
+    comps_[++i] = createTextField(dataGroup_.getId(), pNames_[i], this, !dataGroup_.isInstantiated());
+    comps_[++i] = createLabel(dataGroup_.getMargin().toString());
+    comps_[++i] = createCheckBox(dataGroup_.isZoomable(), pNames_[i], this);
+    //
+    // z stuff
+    //
+    comps_[++i] = createCheckBox(dataGroup_.isZAutoScale(), pNames_[i], this);
+    zAutoScale = i;
+    comps_[++i] = createTextField(format(dataGroup_.getNumberAutoContourLevels()), pNames_[i], this, true);
+    zAutoLevels = i;
+    comps_[++i] = createTextField(format(dataGroup_.getZRangeU(), false), pNames_[i], this, true);
+    zUserRange = i;
+    //
+    setFieldsEnabled();
+//
+    for(i=0; i < comps_.length; i++) {
+      addProperty(i+1, pNames_[i], comps_[i], false);
+    }
+    addProperty(comps_.length + 1, " ", new JLabel(" "), true);
+  }
+
+  void resetFields() {
+    for(int i=0; i < comps_.length; i++) {
+      if(comps_[i] instanceof JTextField) {
+        ((JTextField)comps_[i]).removeActionListener(this);
+        ((JTextField)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JCheckBox) {
+        ((JCheckBox)comps_[i]).removeActionListener(this);
+        ((JCheckBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JComboBox) {
+        ((JComboBox)comps_[i]).removeActionListener(this);
+        ((JComboBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JButton) {
+        ((JButton)comps_[i]).removeActionListener(this);
+        ((JButton)comps_[i]).removeFocusListener(this);
+      }
+    }
+  }
+
+  private void setFieldsEnabled() {
+    ((JTextField)comps_[zUserRange]).setEnabled(!((JCheckBox)comps_[zAutoScale]).isSelected());
+    ((JTextField)comps_[zAutoLevels]).setEnabled(((JCheckBox)comps_[zAutoScale]).isSelected());
+  }
+
+  private void processEvent(Object obj, String command) {
+    String str = null;
+    SoTRange range = null;
+    if(command.equals("Id")) {
+      String oldId = dataGroup_.getId();
+      dataGroup_.getPanelHolder().getDataGroups().remove(oldId);
+      dataGroup_.setId(((JTextField)obj).getText());
+      dataGroup_.getPanelHolder().getDataGroups().put(dataGroup_.getId(), dataGroup_);
+    } else if(command.equals("Zoomable")) {
+      dataGroup_.setZoomable(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Z AutoScale")) {
+      dataGroup_.setZAutoScale(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Z Auto Levels")) {
+      dataGroup_.setNumberAutoContourLevels(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Z User Range")) {
+      range = parseRange(((JTextField)obj).getText(), false);
+      if(range != null) dataGroup_.setZRangeU(range);
+    }
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    if(suppressEvent_) return;
+    Object obj = e.getSource();
+//    String str = null;
+    String command = e.getActionCommand();
+    processEvent(obj, command);
+    setFieldsEnabled();
+//    System.out.println(e.paramString() + ",rslt=" + str);
+  }
+
+
+  public void stateChanged(ChangeEvent e) {
+    update();
+  }
+
+  public void focusGained(FocusEvent e) {
+//    Object obj = e.getSource();
+//    System.out.println("DataGroupPropertyPanel.focusGained: " + obj.toString());
+  }
+
+  public void focusLost(FocusEvent e) {
+    Object obj = e.getSource();
+    if(obj instanceof JTextField) {
+      JTextField tf = (JTextField)obj;
+      String name = tf.getName();
+      processEvent(obj, name);
+    }
+  }
+
+/*  SoTRange parseRange(String value, boolean isTime) {
+    StringTokenizer tok = new StringTokenizer(value, ",\t\n\r\f");
+    if(tok.countTokens() != 3) {
+      JOptionPane.showMessageDialog(this, "Three values required", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    SoTRange range = null;
+    double start = Double.parseDouble(tok.nextToken().trim());
+    double end = Double.parseDouble(tok.nextToken().trim());
+    double delta  = Double.parseDouble(tok.nextToken().trim());
+    range = new SoTRange.Double(start, end, delta);
+    return range;
+  } */
+
+  public void setExpert(boolean expert) {
+    boolean save = expert_;
+    expert_ = expert;
+    if(expert_ != save) reset();
+  }
+
+  public boolean isExpert() {
+    return expert_;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataHolder.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataHolder.java
new file mode 100755
index 0000000..37220f4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataHolder.java
@@ -0,0 +1,98 @@
+/*
+ * $Id: DataHolder.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.Attribute;
+
+/**
+ * Object to associate <code>SGTData</code>, <code>Attribute</code>,
+ * <code>Panel</code>, and <code>DataGroup</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class DataHolder {
+  /**
+   * @undirected
+   * @supplierCardinality 1
+   * @link aggregation
+   * @label data
+   */
+  private SGTData data_;
+
+  /**
+   * @link aggregation
+   * @undirected
+   * @supplierCardinality 1
+   * @label attr
+   */
+  private Attribute attr_;
+
+  /**
+   * @supplierCardinality 1
+   * @label pHolder
+   */
+  private PanelHolder pHolder_;
+
+  /**
+   * @supplierCardinality 1
+   * @label dataGroup */
+  private DataGroup dataGroup_;
+
+  /**
+   * @label legend
+   */
+  private Legend legend_;
+
+  /**
+   * @label dModel 
+   */
+  private DataModel dModel_;
+
+  public DataHolder(DataModel model, SGTData data, Attribute attr,
+                    PanelHolder pHolder, DataGroup dataGroup,
+                    Legend legend) {
+    dModel_ = model;
+    data_ = data;
+    attr_ = attr;
+    pHolder_ = pHolder;
+    dataGroup_ = dataGroup;
+    legend_ = legend;
+  }
+
+  SGTData getData() {
+    return data_;
+  }
+
+  Attribute getAttribute() {
+    return attr_;
+  }
+
+  PanelHolder getPanelHolder() {
+    return pHolder_;
+  }
+
+  DataGroup getDataGroup() {
+    return dataGroup_;
+  }
+
+  Legend getLegend() {
+    return legend_;
+  }
+
+  public void notifyPanel() throws DataTargetMismatchException {
+    dModel_.getPage().findPanel(pHolder_).addData(data_, attr_, dataGroup_, legend_);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModel.java
new file mode 100755
index 0000000..fc940ab
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModel.java
@@ -0,0 +1,134 @@
+/*
+ * $Id: DataModel.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.util.List;
+import java.util.Vector;
+import java.util.Iterator;
+
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.Attribute;
+
+/**
+ * A model that supplies the relationship between <code>SGTData</code> objects,
+ * its <code>Attribute</code> and the
+ * <code>Panel</code> and <code>DataGroup</code> in which it is displayed and the
+ * <code>Legend</code>.
+ * <p> Some classes have been omitted for display purposes.
+ * <P ALIGN="CENTER"><IMG SRC="images/DataModelSimple.png" ALIGN="BOTTOM" BORDER="0">
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ * @stereotype bean
+ **/
+public class DataModel {
+  private PropertyChangeSupport support_ = new PropertyChangeSupport(this);
+  private List dataList_;
+
+  /**
+   * @label page
+   */
+  private Page page;
+
+  /** @link aggregation
+   * @supplierCardinality 1..*
+   * @label dataList*/
+  /*#DataHolder lnkDataHolder;*/
+
+  /**
+   * Default constructor.
+   */
+  public DataModel() {
+    dataList_ = new Vector();
+  }
+
+  /**
+   * Add data to the <code>DataModel</code>.  Throws a "addData" property change.
+   * @param data SGTData
+   * @param attr Attribute for data
+   * @param pHolder PanelHolder
+   * @param dataGroup DataGroup
+   * @param legend Legend
+   */
+  public void addData(SGTData data, Attribute attr,
+                      PanelHolder pHolder, DataGroup dataGroup,
+                      Legend legend) {
+    DataHolder dh = new DataHolder(this, data, attr, pHolder,
+                                   dataGroup, legend);
+    dataList_.add(dh);
+    support_.firePropertyChange("addData", null, dh);
+  }
+
+  /**
+   * Get <code>Iterator</code> of the <code>DataHolder</code> objects.
+   * @return
+   */
+  public Iterator dataIterator() {
+    return dataList_.iterator();
+  }
+
+  /**
+   * Add property change listener.
+   * @param l property change listener
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    support_.addPropertyChangeListener(l);
+  }
+
+  /**
+   * Listen for specific property change.
+   * @param name property name
+   * @param l property change listner
+   */
+  public void addPropertyChangeListener(String name, PropertyChangeListener l) {
+    support_.addPropertyChangeListener(name, l);
+  }
+
+  /**
+   * Remove property change listener.
+   * @param l property change listener
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    support_.removePropertyChangeListener(l);
+  }
+
+  /**
+   * Remove specific property change listener
+   * @param name property name
+   * @param l property change listener
+   */
+  public void removePropertyChangeListener(String name, PropertyChangeListener l) {
+    support_.removePropertyChangeListener(name, l);
+  }
+
+  /**
+   * Set <code>Page</code>.
+   * @param page Page
+   */
+  public void setPage(Page page) {
+    this.page = page;
+  }
+
+  /**
+   * Get Page.
+   * @return Page
+   */
+  public Page getPage() {
+    return page;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelBeanInfo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelBeanInfo.java
new file mode 100755
index 0000000..6be376e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelBeanInfo.java
@@ -0,0 +1,45 @@
+package gov.noaa.pmel.sgt.beans;
+
+import java.beans.*;
+
+/**
+ * BeanInfo object for <code>DataModel</code>.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+public class DataModelBeanInfo extends SimpleBeanInfo {
+  private Class beanClass = DataModel.class;
+  private String iconColor16x16Filename = "DataModelIcon16.gif";
+  private String iconColor32x32Filename = "DataModelIcon32.gif";
+  private String iconMono16x16Filename;
+  private String iconMono32x32Filename;
+
+  public DataModelBeanInfo() {
+  }
+  public PropertyDescriptor[] getPropertyDescriptors() {
+    try {
+      PropertyDescriptor _page = new PropertyDescriptor("page", beanClass, "getPage", "setPage");
+      PropertyDescriptor[] pds = new PropertyDescriptor[] {
+        _page};
+      return pds;
+    }
+    catch(IntrospectionException ex) {
+      ex.printStackTrace();
+      return null;
+    }
+  }
+  public java.awt.Image getIcon(int iconKind) {
+    switch (iconKind) {
+      case BeanInfo.ICON_COLOR_16x16:
+        return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null;
+      case BeanInfo.ICON_COLOR_32x32:
+        return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null;
+      case BeanInfo.ICON_MONO_16x16:
+        return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null;
+      case BeanInfo.ICON_MONO_32x32:
+        return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null;
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelEditor.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelEditor.java
new file mode 100755
index 0000000..575c4da
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelEditor.java
@@ -0,0 +1,48 @@
+/*
+ * $Id: DataModelEditor.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import javax.swing.JComponent;
+
+/**
+ * Used at run-time to modify the <code>DataModel</code>. Not implemented at this
+ * time.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class DataModelEditor extends JComponent {
+  /**
+   * @supplierCardinality 1
+   */
+  private DataModel dataModel_;
+
+  public DataModelEditor() {
+    super();
+    dataModel_ = null;
+  }
+
+  public DataModelEditor(DataModel model) {
+    super();
+    setDataModel(model);
+  }
+
+  public DataModel getDataModel(){
+    return dataModel_;
+  }
+
+  public void setDataModel(DataModel dataModel){
+    dataModel_ = dataModel;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelIcon16.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelIcon16.gif
new file mode 100755
index 0000000..65a026f
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelIcon32.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelIcon32.gif
new file mode 100755
index 0000000..5df5338
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataModelIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataTargetMismatchException.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataTargetMismatchException.java
new file mode 100755
index 0000000..16879c6
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DataTargetMismatchException.java
@@ -0,0 +1,33 @@
+/*
+ * $Id: DataTargetMismatchException.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+/**
+ * <code>SGTData</code> does not match the target of <code>Panel</code> and
+ * <code>DataGroup</code> or <code>Legend</code> type.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ * @stereotype bean
+ **/
+public class DataTargetMismatchException extends Exception {
+
+  public DataTargetMismatchException() {
+    super();
+  }
+
+  public DataTargetMismatchException(String message) {
+    super(message);
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DesignListener.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DesignListener.java
new file mode 100755
index 0000000..354a6f4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DesignListener.java
@@ -0,0 +1,24 @@
+/*
+ * $Id: DesignListener.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+/**
+ * Used to identify those objects that only need to have their listeners active
+ * during design-time.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+interface DesignListener {
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DesignPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DesignPanel.java
new file mode 100755
index 0000000..6a7905c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DesignPanel.java
@@ -0,0 +1,541 @@
+/*
+ * $Id: DesignPanel.java,v 1.1.1.1 2007/09/07 06:32:01 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Dimension;
+import java.awt.Component;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.InputEvent;
+
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:01 $
+ * @since 3.0
+ **/
+class DesignPanel extends JComponent implements MouseListener,
+    MouseMotionListener, ChangeListener, DesignListener, PropertyChangeListener {
+  public static final int ALIGN_TOP = 0;
+  public static final int ALIGN_BOTTOM = 1;
+  public static final int ALIGN_LEFT = 2;
+  public static final int ALIGN_RIGHT = 3;
+  public static final int JUSTIFY_VERTICAL = 4;
+  public static final int JUSTIFY_HORIZONTAL = 5;
+
+  private Map pDragBoxes_ = new HashMap();
+  private Vector selectedBoxes_ = new Vector();
+  private boolean inMove_ = false;
+  private DragBox dragBox_ = null;
+  private int dragState_ = -1;
+  private Point move_ref_ = null;
+  private PanelModel model_ = null;
+  private DataGroup selectedDG_ = null;
+  private Dimension size = new Dimension(100, 100);
+
+//  private boolean inSelect_ = false;
+  private int selectCount_ = 0;
+  private Point firstSelectedPoint_ = new Point(-1, -1);
+  private DragBox[] selectList_ = null;
+  private static int SELECT_DISTANCE = 2;
+
+  public DesignPanel() {
+    super();
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  public DesignPanel(PanelModel model) {
+    this();
+    setPanelModel(model);
+  }
+
+  void jbInit() {
+    addMouseListener(this);
+    addMouseMotionListener(this);
+  }
+
+  public Dimension getMinimumSize() {
+    return size;
+  }
+
+  public Dimension getPreferredSize() {
+    return size;
+  }
+
+  public Dimension getMaximumSize() {
+    return size;
+  }
+
+  public Dimension getWorkSize() {
+    return size;
+  }
+
+  public void setPanelModel(PanelModel model) {
+    pDragBoxes_.clear();
+    selectedBoxes_.clear();
+
+    if(model != null) model.removeChangeListener(this);
+    model_ = model;
+    if(model_ == null) return;
+
+    model_.addChangeListener(this);
+    Page pg = model_.getPage();
+    if(pg == null) {
+      size = model_.getPageSize();
+      System.out.println("No page found!: size = " + size);
+      setSize(size);
+    } else {
+      size = pg.getSize();
+      if(Page.DEBUG) System.out.println("DeisignPanel: size = " + size);
+      setSize(size);
+    }
+
+    Iterator iter = model_.panelIterator();
+    while(iter.hasNext()) {
+      PanelHolder ph = (PanelHolder)iter.next();
+      ph.addChangeListener(this);
+      PanelHolderDragBox pdb = new PanelHolderDragBox(ph);
+      pDragBoxes_.put(ph, pdb);
+    }
+    repaint();
+  }
+
+  public PanelModel getPanelModel() {
+    return model_;
+  }
+
+  public void addPanel(PanelHolderDragBox panel) {
+    panel.getPanelHolder().addChangeListener(this);
+    pDragBoxes_.put(panel.getPanelHolder(), panel);
+  }
+
+  public void addDataGroup(DataGroup dg) {
+    PanelHolder ph = getSelectedPanel();
+    if(ph == null) return;
+    PanelHolderDragBox pdb = (PanelHolderDragBox)pDragBoxes_.get(ph);
+    if(pdb == null) return;
+    if(ph.getDataGroupSize() >= 1) {
+      dg.getXAxisHolder().setAxisPosition(DataGroup.TOP);
+      dg.getYAxisHolder().setAxisPosition(DataGroup.RIGHT);
+    }
+    pdb.addDragBox(dg);
+    ph.addDataGroup(dg);
+    // little fix
+  }
+
+  public void addLabel(Label label) {
+    PanelHolder ph = getSelectedPanel();
+    if(ph == null) return;
+    PanelHolderDragBox pdb = (PanelHolderDragBox)pDragBoxes_.get(ph);
+    if(pdb == null) return;
+    pdb.addDragBox(label);
+    ph.addLabel(label);
+   }
+
+  public void addLegend(Legend legend) {
+    PanelHolder ph = getSelectedPanel();
+    if(ph == null) return;
+    PanelHolderDragBox pdb = (PanelHolderDragBox)pDragBoxes_.get(ph);
+    pdb.addDragBox(legend);
+    ph.addLegend(legend);
+  }
+
+  public void alignBoxes(int mode) {
+    int count = getSelectedCount();
+    if(count < 0) return;
+    int y, x;
+    PanelHolderDragBox pdb;
+    PanelHolderDragBox box = (PanelHolderDragBox)selectedBoxes_.firstElement();
+    Rectangle bounds = box.getBounds();
+    switch (mode) {
+      case ALIGN_TOP:
+        if(count <= 1) return;
+        y = bounds.y;
+        for(int i=1; i < count; i++) {
+          pdb = (PanelHolderDragBox)selectedBoxes_.elementAt(i);
+          pdb.setLocation(pdb.getLocation().x, y);
+        }
+        break;
+      case ALIGN_BOTTOM:
+        if(count <= 1) return;
+        int y2 = bounds.y + bounds.height;
+        for(int i=1; i < count; i++) {
+          pdb = (PanelHolderDragBox)selectedBoxes_.elementAt(i);
+          y = y2 - pdb.getBounds().height;
+          pdb.setLocation(pdb.getLocation().x, y);
+        }
+        break;
+      case ALIGN_LEFT:
+        if(count <= 1) return;
+        x = bounds.x;
+        for(int i=1; i < count; i++) {
+          pdb = (PanelHolderDragBox)selectedBoxes_.elementAt(i);
+          pdb.setLocation(x, pdb.getLocation().y);
+        }
+        break;
+      case ALIGN_RIGHT:
+        if(count <= 1) return;
+        int x2 = bounds.x + bounds.width;
+        for(int i=1; i < count; i++) {
+          pdb = (PanelHolderDragBox)selectedBoxes_.elementAt(i);
+          x = x2 - pdb.getBounds().width;
+          pdb.setLocation(x, pdb.getLocation().y);
+        }
+        break;
+      case JUSTIFY_VERTICAL:
+        if(count >= 2) {
+          for(int i=1; i < count; i++) {
+            pdb = (PanelHolderDragBox)selectedBoxes_.elementAt(i);
+            Rectangle bnds = pdb.getBounds();
+            bnds.y = bounds.y;
+            bnds.height = bounds.height;
+            pdb.setBounds(bnds);
+          }
+        } else {
+          Dimension sze = getWorkSize();
+          bounds.y = 0;
+          bounds.height = sze.height;
+          box.setBounds(bounds);
+        }
+        break;
+      case JUSTIFY_HORIZONTAL:
+        if(count >= 2) {
+          for(int i=1; i < count; i++) {
+            pdb = (PanelHolderDragBox)selectedBoxes_.elementAt(i);
+            Rectangle bnds = pdb.getBounds();
+            bnds.x = bounds.x;
+            bnds.width = bounds.width;
+            pdb.setBounds(bnds);
+          }
+        } else {
+          Dimension sze = getWorkSize();
+          bounds.x = 0;
+          bounds.width = sze.width;
+          box.setBounds(bounds);
+        }
+    }
+    repaint();
+  }
+
+  public void removeSelected() {
+    PanelHolderDragBox pdb;
+    PanelHolder ph;
+    if(selectedBoxes_.size() == 1) {
+      pdb = (PanelHolderDragBox)selectedBoxes_.firstElement();
+      pdb.getPanelHolder().removeAllChangeListeners();
+      // remove contents
+      DragBox[] dbArray = pdb.getDragBoxArray();
+      for(int i=0; i < dbArray.length; i++) {
+        ph = pdb.getPanelHolder();
+        if(dbArray[i] instanceof DataGroupDragBox) {
+          DataGroup ag = ((DataGroupDragBox)dbArray[i]).getDataGroup();
+          ph.removeDataGroup(ag);
+          pdb.removeDragBox((DataGroupDragBox)dbArray[i]);
+        } else if(dbArray[i] instanceof LegendDragBox) {
+          Legend legend = ((LegendDragBox)dbArray[i]).getLegend();
+          ph.removeLegend(legend);
+          pdb.removeDragBox((LegendDragBox)dbArray[i]);
+        } else if(dbArray[i] instanceof LabelDragBox) {
+          Label label = ((LabelDragBox)dbArray[i]).getLabel();
+          ph.removeLabel(label);
+          pdb.removeDragBox((LabelDragBox)dbArray[i]);
+        }
+      }
+      //    pdb.getPanelHolder().removeChangeListener(this);
+      ph = pdb.getPanelHolder();
+      pDragBoxes_.remove(ph);
+      model_.removePanel(ph);
+      ph.removeAllChangeListeners();
+    } else {
+      Iterator iter = pDragBoxes_.values().iterator();
+      while(iter.hasNext()) {
+        pdb = (PanelHolderDragBox)iter.next();
+        Iterator dbIter = pdb.getDragBoxIterator();
+        while(dbIter.hasNext()) {
+          DragBox db = (DragBox)dbIter.next();
+          if(db.isSelected()) {
+            ph = pdb.getPanelHolder();
+            if(db instanceof DataGroupDragBox) {
+              DataGroup ag = ((DataGroupDragBox)db).getDataGroup();
+              ph.removeDataGroup(ag);
+              pdb.removeDragBox((DataGroupDragBox)db);
+            } else if(db instanceof LegendDragBox) {
+              Legend legend = ((LegendDragBox)db).getLegend();
+              ph.removeLegend(legend);
+              pdb.removeDragBox((LegendDragBox)db);
+            } else if(db instanceof LabelDragBox) {
+              Label label = ((LabelDragBox)db).getLabel();
+              ph.removeLabel(label);
+              pdb.removeDragBox((LabelDragBox)db);
+            }
+            break;
+          }
+        }
+      }
+    }
+    repaint();
+  }
+
+  boolean isAxisHolderDragBoxSelected() {
+    PanelHolderDragBox pdb;
+    Iterator iter = pDragBoxes_.values().iterator();
+    while(iter.hasNext()) {
+      pdb = (PanelHolderDragBox)iter.next();
+      Iterator dbIter = pdb.getDragBoxIterator();
+      while(dbIter.hasNext()) {
+        DragBox db = (DragBox)dbIter.next();
+        if(db.isSelected() && db instanceof AxisHolderDragBox) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  boolean isChildDragBoxSelected() {
+    PanelHolderDragBox pdb;
+    Iterator iter = pDragBoxes_.values().iterator();
+    while(iter.hasNext()) {
+      pdb = (PanelHolderDragBox)iter.next();
+      Iterator dbIter = pdb.getDragBoxIterator();
+      while(dbIter.hasNext()) {
+        DragBox db = (DragBox)dbIter.next();
+        if(db.isSelected()) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  int getSelectedCount() {
+    return selectedBoxes_.size();
+  }
+
+  PanelHolder getSelectedPanel() {
+    if(selectedBoxes_.size() != 1) return null;
+    return ((PanelHolderDragBox)selectedBoxes_.firstElement()).getPanelHolder();
+  }
+
+  public void paintComponent(Graphics g) {
+    g.setColor(model_.getPageBackgroundColor());
+    g.fillRect(0, 0, size.width, size.height);
+    Iterator iter = pDragBoxes_.values().iterator();
+    while(iter.hasNext()) {
+      ((PanelHolderDragBox)iter.next()).draw(g);
+    }
+  }
+
+  void clearAllSelections() {
+    Iterator pIter = pDragBoxes_.values().iterator();
+    while(pIter.hasNext()) {
+      PanelHolderDragBox pdb = (PanelHolderDragBox)pIter.next();
+      pdb.setSelected(false);
+      Iterator dbIter = pdb.getDragBoxIterator();
+      while(dbIter.hasNext()) {
+        ((DragBox)dbIter.next()).setSelected(false);
+      }
+    }
+  }
+
+  private DragBox[] dragBoxesThatContain(Point pt) {
+    PanelHolderDragBox pDragBox;
+    Vector boxes = new Vector(4);
+    Iterator pIter = pDragBoxes_.values().iterator();
+    while(pIter.hasNext()) {
+      pDragBox = (PanelHolderDragBox)pIter.next();
+      if(pDragBox.contains(pt)) {
+        Iterator dbIter = pDragBox.getDragBoxIterator();
+        while(dbIter.hasNext()) {
+          DragBox db = (DragBox)dbIter.next();
+          if(db.contains(pt))  {
+            boxes.add(db);  // add dragBox
+          }
+        } // dbIter
+        boxes.add(pDragBox);  // add panelDragBox
+      } // pDragBox contains pt
+    } // pIter
+    return (DragBox[])boxes.toArray(new DragBox[boxes.size()]);
+  }
+
+  private void resetSelect() {
+    selectList_ = null;
+    selectCount_ = 0;
+    firstSelectedPoint_.setLocation(-1,-1);
+  }
+
+  private boolean newSelectPoint(Point pt) {
+    int dx = Math.abs(pt.x - firstSelectedPoint_.x);
+    int dy = Math.abs(pt.y - firstSelectedPoint_.y);
+
+    return dx > SELECT_DISTANCE || dy > SELECT_DISTANCE;
+  }
+
+  // mouse listener
+  public void mouseClicked(MouseEvent e) {
+    // object selection/deselection
+    DragBox dragBox = null;
+    boolean dble = e.getClickCount() >= 2;
+    int mods = e.getModifiers();
+    Point pt = e.getPoint();
+    boolean shiftctrl = (mods & InputEvent.CTRL_MASK) != 0 ||
+                        (mods & InputEvent.SHIFT_MASK) != 0;
+    // get selected DragBox
+    if(selectList_ == null || newSelectPoint(pt)) {
+      selectList_ = dragBoxesThatContain(pt);
+      if(selectList_.length <= 0) {
+        resetSelect();
+        // nothing selected
+        clearAllSelections();
+        int old = getSelectedCount();
+        selectedBoxes_.removeAllElements();
+        repaint();
+        firePropertyChange("allUnselected", null, null);
+
+        inMove_ = false;
+        dragState_ = -1;
+        return;
+      }
+      selectCount_ = 0;
+      firstSelectedPoint_.setLocation(pt);
+      dragBox = selectList_[selectCount_];
+    } else {
+      selectCount_++;
+      if(selectCount_ >= selectList_.length) selectCount_ = 0;
+      dragBox = selectList_[selectCount_];
+    }
+    // process selected DragBox
+    if(dragBox instanceof PanelHolderDragBox) {
+      if(!shiftctrl && !dragBox.isSelected()) {
+        clearAllSelections();
+        selectedBoxes_.removeAllElements();
+      }
+      dragBox.setSelected(!dragBox.isSelected());
+      if(dragBox.isSelected()) {
+        selectedBoxes_.add(dragBox);
+      } else {
+        selectedBoxes_.remove(dragBox);
+      }
+      repaint();
+      firePropertyChange("panelSelected", null, dragBox);
+      return;
+    } else {
+      clearAllSelections();
+      selectedBoxes_.removeAllElements();
+      dragBox.setSelected(true);
+      repaint();
+      if(dragBox instanceof DataGroupDragBox) {
+        firePropertyChange("dataGroupSelected", null, dragBox);
+      } else if(dragBox instanceof AxisHolderDragBox) {
+        firePropertyChange("axisSelected", null, dragBox);
+      } else if(dragBox instanceof LabelDragBox) {
+        firePropertyChange("labelSelected", null, dragBox);
+      } else if(dragBox instanceof LegendDragBox) {
+        firePropertyChange("legendSelected", null, dragBox);
+      }
+      return;
+    }
+  }
+
+  public void mousePressed(MouseEvent e) {
+    // initiate object move/resize
+    PanelHolderDragBox pDragBox = null;
+    DragBox db = null;
+    dragState_ = -1;
+    Iterator iter = pDragBoxes_.values().iterator();
+    while(iter.hasNext()) {
+      pDragBox = (PanelHolderDragBox)iter.next();
+      if(pDragBox.isSelected() && pDragBox.handlesContain(e.getPoint())) {
+        dragBox_ = pDragBox;
+        dragState_ = dragBox_.getSelectedHandle();
+        inMove_ = true;
+        move_ref_ = new Point(e.getX(), e.getY());
+        break;
+      }
+      // look for DragBoxes
+      Iterator dbIter = pDragBox.getDragBoxIterator();
+      while(dbIter.hasNext()) {
+        db = (DragBox)dbIter.next();
+        if(db.isSelected() && db.handlesContain(e.getPoint())) {
+          dragBox_ = db;
+          dragState_ = dragBox_.getSelectedHandle();
+          inMove_ = true;
+          move_ref_ = new Point(e.getX(), e.getY());
+          break;
+        }
+      } // dbIter
+    } // iter
+  }
+
+  public void mouseReleased(MouseEvent e) {
+    inMove_ = false;
+    dragState_ = -1;
+  }
+  public void mouseEntered(MouseEvent e) {
+  }
+  public void mouseExited(MouseEvent e) {
+  }
+  // mouse motion listener
+  public void mouseDragged(MouseEvent e) {
+    resetSelect();
+    Point pt = null;
+    Rectangle rect = null;
+    int x = e.getX();
+    int y = e.getY();
+    if(inMove_) {
+      int dx = x - move_ref_.x;
+      int dy = y - move_ref_.y;
+      dragBox_.mouseOperation(dragState_, dx, dy);
+      repaint();
+      move_ref_ = new Point(x, y);
+    }  // inMove_
+  }
+  public void mouseMoved(MouseEvent e) {
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    size = model_.getPageSize();
+    repaint();
+  }
+
+  public String toString() {
+    return getClass().getName() + '@' + Integer.toHexString(hashCode());
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    if(evt.getPropertyName().equals("pageSize")) {
+      size = model_.getPageSize();
+      setSize(size);
+      repaint();
+    }
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DragBox.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DragBox.java
new file mode 100755
index 0000000..066662b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/DragBox.java
@@ -0,0 +1,195 @@
+/*
+ * $Id: DragBox.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.Graphics;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+abstract class DragBox implements DesignListener {
+  public static final int UPPER_LEFT = 0;
+  public static final int UPPER_RIGHT = 1;
+  public static final int LOWER_LEFT = 2;
+  public static final int LOWER_RIGHT = 3;
+  public static final int CENTER = 4;
+
+  protected static int handleSize_ = 8;
+  protected Rectangle[] handles_ = new Rectangle[5];
+  protected int selectedHandle_ = -1;
+  protected boolean selected_ = false;
+  protected Color selectedColor_ = Color.red;
+  protected Color unSelectedColor_ = Color.darkGray;
+  protected Color color_ = unSelectedColor_;
+  protected PanelHolder pHolder_;
+
+  public DragBox(PanelHolder ph) {
+    pHolder_ = ph;
+  }
+
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+    if(selected_) {
+      color_ = selectedColor_;
+    } else {
+      color_ = unSelectedColor_;
+    }
+  }
+
+  public boolean isSelected() {
+    return selected_;
+  }
+
+  public boolean handlesContain(Point pt) {
+    for(int i=0; i < handles_.length; i++) {
+      if(handles_[i].contains(pt)) {
+        selectedHandle_ = i;
+        return true;
+      }
+    }
+    selectedHandle_ = -1;
+    return false;
+  }
+
+  protected void computeHandles() {
+    Rectangle bounds = getBounds();
+    handles_[UPPER_LEFT].setBounds(bounds.x,
+                                   bounds.y,
+                                   handleSize_, handleSize_);
+    handles_[UPPER_RIGHT].setBounds(bounds.x+bounds.width-handleSize_,
+                                    bounds.y,
+                                    handleSize_, handleSize_);
+    handles_[LOWER_LEFT].setBounds(bounds.x,
+                                   bounds.y+bounds.height-handleSize_,
+                                   handleSize_, handleSize_);
+    handles_[LOWER_RIGHT].setBounds(bounds.x+bounds.width-handleSize_,
+                                    bounds.y+bounds.height-handleSize_,
+                                    handleSize_, handleSize_);
+    handles_[CENTER].setBounds(bounds.x+(bounds.width-handleSize_)/2,
+                               bounds.y+(bounds.height-handleSize_)/2,
+                               handleSize_, handleSize_);
+  }
+
+  public void mouseOperation(int op, int dx, int dy) {
+    if(op == -1) return;
+    Point pt;
+    Rectangle rect;
+    if(op == DragBox.CENTER) {
+      pt = getLocation();
+      pt.x += dx;
+      pt.y += dy;
+      setLocation(pt);
+    } else {
+      rect = getBounds();
+      int x2 = rect.x + rect.width;
+      int y2 = rect.y + rect.height;
+      switch (op) {
+        case DragBox.UPPER_LEFT:
+          rect.x += dx;
+          rect.y += dy;
+          break;
+        case DragBox.UPPER_RIGHT:
+          x2 += dx;
+          rect.y += dy;
+          break;
+        case DragBox.LOWER_LEFT:
+          rect.x += dx;
+          y2 += dy;
+          break;
+        case DragBox.LOWER_RIGHT:
+          x2 += dx;
+          y2 += dy;
+      }
+      rect.width = x2 - rect.x;
+      rect.height = y2 - rect.y;
+      setBounds(rect);
+    }
+  }
+
+  public boolean contains(Point pt) {
+    return getBounds().contains(pt);
+  }
+
+  public int getSelectedHandle() {
+    return selectedHandle_;
+  }
+
+  Point2D.Double toLocation(Point pd) {
+    return new Point2D.Double(toXLocation(pd.x),
+                              toYLocation(pd.y));
+  }
+
+  Point toLocation(Point2D.Double pp) {
+    return new Point(toXLocation(pp.x),
+                     toYLocation(pp.y));
+  }
+
+  Rectangle2D.Double toRectangle(Rectangle rd) {
+    return new Rectangle2D.Double(toXLocation(rd.x),
+                                  toYLocation(rd.y + rd.height),
+                                  transform(rd.width),
+                                  transform(rd.height));
+  }
+
+  Rectangle toRectangle(Rectangle2D.Double rp) {
+    int h = transform(rp.height);
+    return new Rectangle(toXLocation(rp.x),
+                         toYLocation(rp.y) - h,
+                         transform(rp.width),
+                         h);
+  }
+
+  double toXLocation(int xd) {
+    return (xd - pHolder_.getBounds().x)/pHolder_.getPanelModel().getDpi();
+  }
+
+  double toYLocation(int yd) {
+    return (pHolder_.getBounds().height - yd +
+            pHolder_.getBounds().y)/pHolder_.getPanelModel().getDpi();
+  }
+
+  int toXLocation(double xp) {
+    return (int)(xp*pHolder_.getPanelModel().getDpi()+0.5f) +
+        pHolder_.getBounds().x;
+  }
+
+  int toYLocation(double yp) {
+    return pHolder_.getBounds().height - (int)(yp*pHolder_.getPanelModel().getDpi()+0.5f) +
+        pHolder_.getBounds().y;
+  }
+
+  double transform(int dev) {
+    return dev/pHolder_.getPanelModel().getDpi();
+  }
+
+  int transform(double phy) {
+    return (int)(phy*pHolder_.getPanelModel().getDpi()+0.5f);
+  }
+
+  abstract public void draw(Graphics g);
+  abstract public void update(String message);
+  abstract public void setId(String id);
+  abstract public String getId();
+  abstract public void setBounds(Rectangle bounds);
+  abstract public Rectangle getBounds();
+  abstract public void setLocation(Point pt);
+  abstract public Point getLocation();
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Label.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Label.java
new file mode 100755
index 0000000..0933857
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Label.java
@@ -0,0 +1,370 @@
+/*
+ * $Id: Label.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import javax.swing.event.*;
+import java.awt.Color;
+import java.awt.Font;
+import java.util.*;
+import java.io.*;
+import java.beans.*;
+
+import gov.noaa.pmel.sgt.SGLabel;
+
+/**
+ * Encapsulates <code>SGLabel</code> properties.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+public class Label implements Serializable {
+  transient private PanelHolder pHolder_ = null;
+  private String id = "";
+  private Rectangle2D.Double boundsP = new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0);
+  transient private Vector changeListeners;
+  transient private ChangeEvent changeEvent_ = new ChangeEvent(this);
+  private String text = "";
+  private int justification = SGLabel.LEFT;
+  private boolean visible = true;
+  private boolean instantiated = false;
+
+  private boolean selectable = true;
+  private Color color = Color.black;
+  private Font font = new Font("Helvetica", Font.PLAIN, 10);
+  private int orientation = SGLabel.HORIZONTAL;
+
+  static {
+    try {
+      BeanInfo info = Introspector.getBeanInfo(Label.class);
+      PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+      for(int i=0; i < descriptors.length; i++) {
+        PropertyDescriptor pd = descriptors[i];
+        if(pd.getName().equals("instantiated")) {
+          pd.setValue("transient", Boolean.TRUE);
+        } else if(pd.getName().equals("panelHolder")) {
+          pd.setValue("transient", Boolean.TRUE);
+        }
+      }
+    } catch (IntrospectionException ie) {
+     ie.printStackTrace();
+    }
+  }
+  /**
+   * Default constructor.  Width and height are set to 0.0, name and location are
+   * <code>null</code>.
+   */
+  public Label() {
+    this(null, null, 0.0f, 0.0f);
+  }
+  /**
+   * Label constructor.
+   * @param id label identifier
+   * @param loc location in physical coordinates
+   * @param wid width in physical coordinates
+   * @param hgt height in physical coorindates.
+   */
+  public Label(String id, Point2D.Double loc, double wid, double hgt) {
+    this.id = id;
+    if(loc == null) {
+      boundsP = null;
+    } else {
+      boundsP = new Rectangle2D.Double(loc.x, loc.y, wid, hgt);
+    }
+  }
+  /**
+   * Get Label identifier.
+   * @return identification
+   */
+  public String getId() {
+    return id;
+  }
+  /**
+   * Set label identifier.
+   * @param id identifier
+   */
+  public void setId(String id) {
+    String saved = this.id;
+    this.id = id;
+    if(this.id == null || !this.id.equals(saved))
+      fireStateChanged();
+  }
+  /**
+   * Set Label bounds.
+   * @param bounds bounds in physical coordinates.
+   */
+  public void setBoundsP(Rectangle2D.Double bounds) {
+    Rectangle2D.Double saved = boundsP;
+    boundsP = bounds;
+    if(saved == null || !saved.equals(boundsP)) fireStateChanged();
+  }
+  /**
+   * Get Label bounds.
+   * @return bounds
+   */
+  public Rectangle2D.Double getBoundsP() {
+    return boundsP;
+  }
+  /**
+   * Set Label location.  Updates x and y in bounds.
+   * @param locationP location in physical coordinates.
+   */
+  public void setLocationP(Point2D.Double locationP) {
+    double x = boundsP.x;
+    double y = boundsP.y;
+
+    boundsP.x = locationP.x;
+    boundsP.y = locationP.y;
+    if(x != boundsP.x || y != boundsP.y)
+      fireStateChanged();
+  }
+  /**
+   * Get Label location
+   * @return location in physical coordinates
+   */
+  public Point2D.Double getLocationP() {
+    return new Point2D.Double(boundsP.x, boundsP.y);
+  }
+  /**
+   * Set Label height.  Updates height in bounds.
+   * @param heightP height in physical coordinates
+   */
+  public void setHeightP(double heightP) {
+    double saved = boundsP.height;
+    boundsP.height = (float)heightP;
+    if(boundsP.height != saved)
+      fireStateChanged();
+  }
+  /**
+   * Get Label height.
+   * @return height
+   */
+  public double getHeightP() {
+    return boundsP.height;
+  }
+
+  /**
+   * Set label width.  Updates width in bounds.
+   * @param widthP width in physcial coordinates
+   */
+  public void setWidthP(double widthP) {
+    double saved = boundsP.width;
+    boundsP.width = (float)widthP;
+    if(boundsP.width != saved)
+      fireStateChanged();
+  }
+  /**
+   * Get label width.
+   * @return width
+   */
+  public double getWidthP() {
+    return boundsP.width;
+  }
+  /**
+   * Remove change listener.
+   * @param l change listener.
+   */
+  public synchronized void removeChangeListener(ChangeListener l) {
+    if (changeListeners != null && changeListeners.contains(l)) {
+      Vector v = (Vector) changeListeners.clone();
+      v.removeElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Remove all change listeners.
+   */
+  public void removeAllChangeListeners() {
+    changeListeners = null;
+  }
+
+  public synchronized void addChangeListener(ChangeListener l) {
+    Vector v = changeListeners == null ? new Vector(2) : (Vector) changeListeners.clone();
+    if (!v.contains(l)) {
+      v.addElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Remove change listeners that implement <code>DesignListener</code>.
+   */
+  public synchronized void removeDesignChangeListeners() {
+    if(changeListeners != null) {
+      Vector v = (Vector) changeListeners.clone();
+      Iterator iter = v.iterator();
+      while(iter.hasNext()) {
+        Object obj = iter.next();
+        if(obj instanceof DesignListener) changeListeners.removeElement(obj);
+      }
+    }
+  }
+
+  protected void fireStateChanged() {
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(changeEvent_);
+      }
+    }
+  }
+  /**
+   * Set label text.
+   * @param text label text
+   */
+  public void setText(String text) {
+    String saved = this.text;
+    this.text = text;
+    if(this.text == null || !this.text.equals(saved))
+      fireStateChanged();
+  }
+  /**
+   * Get label text.
+   * @return text
+   */
+  public String getText() {
+    return text;
+  }
+  /**
+   * Set label visiblity.  Visible if true. Default = true.
+   * @param visible label visiblity
+   */
+  public void setVisible(boolean visible) {
+    boolean saved = this.visible;
+    this.visible = visible;
+    if(saved != this.visible) fireStateChanged();
+  }
+  /**
+   * Is Label visible?
+   * @return true, if label is visible
+   */
+  public boolean isVisible() {
+    return visible;
+  }
+  /**
+   * Set instantiation for label.  Used internally.  Set when SGLabel is instantiated
+   * from Label.
+   * @param instantiated SGLabel instantiated
+   */
+  public void setInstantiated(boolean instantiated) {
+    this.instantiated = instantiated;
+  }
+  /**
+   * Is SGLabel instatiated?
+   * @return true, if SGLabel is instantiated
+   */
+  public boolean isInstantiated() {
+    return instantiated;
+  }
+  /**
+   * Set panelholder.
+   * @param pHolder panel holder
+   */
+  public void setPanelHolder(PanelHolder pHolder) {
+    pHolder_ = pHolder;
+  }
+  /**
+   * Get panel holder.
+   * @return panel holder
+   */
+  public PanelHolder getPanelHolder() {
+    return pHolder_;
+  }
+  /**
+   * Get label justification.
+   * @return justification.
+   */
+  public int getJustification() {
+    return justification;
+  }
+  /**
+   * Set label justification.  Justification can be SGLabel.LEFT, SGLabel.RIGHT,
+   * or SGLabel.CENTER.
+   * Default = SGLabel.LEFT.
+   * @param justification label justification
+   * @see gov.noaa.pmel.sgt.SGLabel
+   */
+  public void setJustification(int justification) {
+    int saved = this.justification;
+    this.justification = justification;
+    if(saved != this.justification) fireStateChanged();
+  }
+  /**
+   * Get label color.
+   * @return color
+   */
+  public Color getColor() {
+    return color;
+  }
+  /**
+   * Get label font.
+   * @return font
+   */
+  public Font getFont() {
+    return font;
+  }
+  /**
+   * Set label color. Default = Color.black.
+   * @param color label color
+   */
+  public void setColor(Color color) {
+    Color saved = this.color;
+    this.color = color;
+    if(!saved.equals(this.color)) fireStateChanged();
+  }
+  /**
+   * Set label font. Default = Helvectia, PLAIN
+   * @param font label font
+   */
+  public void setFont(Font font) {
+    Font saved = this.font;
+    this.font = font;
+    if(!saved.equals(this.font)) fireStateChanged();
+  }
+  /**
+   * Get label orientation.
+   * @return orientation
+   */
+  public int getOrientation() {
+    return orientation;
+  }
+  /**
+   * Set label orientation.  Legal values are SGLabel.HORIZONTAL and
+   * SGLabel.VERTICAL.  Default = SGLabel.HORIZONTAL.
+   * @param orientation label orientation
+   * @see gov.noaa.pmel.sgt.SGLabel
+   */
+  public void setOrientation(int orientation) {
+    int saved = this.orientation;
+    this.orientation = orientation;
+    if(saved != this.orientation) fireStateChanged();
+  }
+  /**
+   * Is label selectable?
+   * @return true if label is selectable
+   */
+  public boolean isSelectable() {
+    return selectable;
+  }
+  /**
+   * Set label selectable.
+   * @param selectable true if label is selectable
+   */
+  public void setSelectable(boolean selectable) {
+    boolean saved = this.selectable;
+    this.selectable = selectable;
+    if(saved != this.selectable) fireStateChanged();
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LabelDragBox.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LabelDragBox.java
new file mode 100755
index 0000000..4f3e127
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LabelDragBox.java
@@ -0,0 +1,103 @@
+/*
+ * $Id: LabelDragBox.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import java.util.Iterator;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class LabelDragBox extends DragBox implements ChangeListener {
+  Label label_ = null;
+  Rectangle boundsD_ = null;
+
+  // deal with angles later
+
+  public LabelDragBox(Label label, PanelHolder pHolder) {
+    super(pHolder);
+    label_ = label;
+    label_.addChangeListener(this);
+    for(int i=0; i < handles_.length;  i++) {
+      handles_[i] = new Rectangle(0,0,0,0);
+    }
+    boundsD_ = toRectangle(label_.getBoundsP());
+    computeHandles();
+  }
+
+  public Label getLabel() {
+    return label_;
+  }
+
+  public void setBounds(Rectangle bounds) {
+    boundsD_ = bounds;
+    label_.setBoundsP(toRectangle(boundsD_));
+    computeHandles();
+  }
+
+  public void draw(Graphics g) {
+    Rectangle bounds = getBounds();
+    Color saved = g.getColor();
+    g.setColor(Color.darkGray);
+    g.drawString(getId(), bounds.x + 5, bounds.y + 12);
+    g.setColor(color_);
+    if(label_.isVisible()) g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+    if(selected_) {
+      for(int i=0; i < handles_.length; i++) {
+        Rectangle r = handles_[i];
+        g.fillRect(r.x, r.y, r.width-1, r.height-1);
+      }
+    }
+    g.setColor(saved);
+  }
+
+  public void setLocation(Point point) {
+    boundsD_.x = point.x;
+    boundsD_.y = point.y;
+    label_.setBoundsP(toRectangle(boundsD_));
+    computeHandles();
+  }
+
+  public Point getLocation() {
+    return new Point(boundsD_.x, boundsD_.y);
+  }
+
+  public Rectangle getBounds() {
+    return boundsD_;
+  }
+
+  public String getId() {
+    return label_.getId();
+  }
+
+  public void update(String message) {
+    boundsD_ = toRectangle(label_.getBoundsP());
+    computeHandles();
+   }
+
+  public void setId(String id) {
+    label_.setId(id);
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    update("LabelDragBox.stateChanged()");
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LabelPropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LabelPropertyPanel.java
new file mode 100755
index 0000000..276dbc1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LabelPropertyPanel.java
@@ -0,0 +1,278 @@
+/*
+ * $Id: LabelPropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.text.DecimalFormat;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import gov.noaa.pmel.sgt.swing.prop.ColorDialog;
+import gov.noaa.pmel.sgt.swing.prop.FontDialog;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.Point2D;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class LabelPropertyPanel extends PropertyPanel implements ActionListener, ChangeListener, FocusListener {
+  private boolean expert_ = false;
+  private Label label_;
+  private static DecimalFormat format_ = new DecimalFormat("#.###");
+  private String[] pNames_ = {"Color", "Font", "Height", "Id", "Justification",
+                              "Location", "Orientation", "Selectable", "Text", "Visible", "Width"};
+  private JComponent[] comps_ = new JComponent[pNames_.length];
+  private String[] justType = {"Left", "Center", "Right"};
+  private String[] orientType = {"Horizontal", "Vertical"};
+
+  public LabelPropertyPanel(Label label, boolean expert) {
+    super();
+    label_ = label;
+    label_.addChangeListener(this);
+    expert_ = expert;
+    create();
+  }
+
+  public void setLabel(Label label, boolean expert) {
+    if(label_ != null) label_.removeChangeListener(this);
+    label_ = label;
+    label_.addChangeListener(this);
+    expert_ = expert;
+    reset();
+  }
+
+  void update() {
+    int item = -1;
+    int i = -1;
+    updateColor((JButton)comps_[++i], label_.getColor());
+    updateFont((JButton)comps_[++i], label_.getFont());
+    ((JTextField)comps_[++i]).setText(format(label_.getHeightP(), format_));
+    ((JTextField)comps_[++i]).setText(label_.getId());
+    switch(label_.getJustification()) {
+      default:
+      case SGLabel.LEFT:
+        item = 0;
+        break;
+      case SGLabel.CENTER:
+        item = 1;
+        break;
+      case SGLabel.RIGHT:
+        item = 2;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JLabel)comps_[++i]).setText(format(label_.getLocationP(), true));
+    switch(label_.getOrientation()) {
+      default:
+      case SGLabel.HORIZONTAL:
+        item = 0;
+        break;
+      case SGLabel.VERTICAL:
+        item = 1;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JCheckBox)comps_[++i]).setSelected(label_.isSelectable());
+    ((JTextField)comps_[++i]).setText(label_.getText());
+    ((JCheckBox)comps_[++i]).setSelected(label_.isVisible());
+    ((JTextField)comps_[++i]).setText(format(label_.getWidthP(), format_));
+  }
+
+  void create() {
+    int i = -1;
+    int item = -1;
+    comps_[++i] = createColor(label_.getColor(), pNames_[i], this);
+    comps_[++i] = createFont(label_.getFont(), pNames_[i], this);
+    comps_[++i] = createTextField(format(label_.getHeightP(), format_), pNames_[i], this, true);
+    comps_[++i] = createTextField(label_.getId(), pNames_[i], this, !label_.isInstantiated());
+    switch(label_.getJustification()) {
+      default:
+      case SGLabel.LEFT:
+        item = 0;
+        break;
+      case SGLabel.CENTER:
+        item = 1;
+        break;
+      case SGLabel.RIGHT:
+        item = 2;
+        break;
+    }
+    comps_[++i] = createComboBox(justType, item, pNames_[i], this, true);
+    comps_[++i] = createLabel(format(label_.getLocationP(), true));
+    switch(label_.getOrientation()) {
+      default:
+      case SGLabel.HORIZONTAL:
+        item = 0;
+        break;
+      case SGLabel.VERTICAL:
+        item = 1;
+        break;
+    }
+    comps_[++i] = createComboBox(orientType, item, pNames_[i], this, true);
+    comps_[++i] = createCheckBox(label_.isSelectable(), pNames_[i], this);
+    comps_[++i] = createTextField(label_.getText(), pNames_[i], this, true);
+    comps_[++i] = createCheckBox(label_.isVisible(), pNames_[i], this);
+    comps_[++i] = createTextField(format(label_.getWidthP(), format_), pNames_[i], this, true);
+    for(i=0; i < comps_.length; i++) {
+      addProperty(i+1, pNames_[i], comps_[i], false);
+    }
+    addProperty(comps_.length + 1, " ", new JLabel(" "), true);
+  }
+
+  private void processEvent(Object obj, String command) {
+    if(command.equals("Id")) {
+      String oldId = label_.getId();
+      label_.getPanelHolder().getLabels().remove(oldId);
+      label_.setId(((JTextField)obj).getText());
+      label_.getPanelHolder().getLabels().put(label_.getId(), label_);
+    } else if(command.equals("Justification")) {
+      String str = (String)((JComboBox)obj).getSelectedItem();
+      int item = -1;
+      if(str.equals("Left")) {
+        item = SGLabel.LEFT;
+      } else if(str.equals("Center")) {
+        item = SGLabel.CENTER;
+      } else if(str.equals("Right")) {
+        item = SGLabel.RIGHT;
+      }
+      label_.setJustification(item);
+    } else if(command.equals("Text")) {
+      label_.setText(((JTextField)obj).getText());
+    } else if(command.equals("Location")) {
+      label_.setLocationP(parsePoint2D(((JTextField)obj).getText()));
+    } else if(command.equals("Height")) {
+      label_.setHeightP(Float.parseFloat(((JTextField)obj).getText()));
+    } else if(command.equals("Width")) {
+      label_.setWidthP(Float.parseFloat(((JTextField)obj).getText()));
+    } else if(command.equals("Visible")) {
+      label_.setVisible(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Color")) {
+      ColorDialog cd = new ColorDialog(getFrame(), "Select Label Color", true);
+      cd.setColor(label_.getColor());
+      cd.setVisible(true);
+      Color newcolor = cd.getColor();
+      if(newcolor != null) label_.setColor(newcolor);
+    } else if(command.equals("Font")) {
+      FontDialog fd = new FontDialog("Label Font");
+      int result = fd.showDialog(label_.getFont());
+      if(result == fd.OK_RESPONSE) {
+        label_.setFont(fd.getFont());
+      }
+    } else if(command.equals("Orientation")) {
+      int old = label_.getOrientation();
+      String str = (String)((JComboBox)obj).getSelectedItem();
+      int item = -1;
+      if(str.equals("Horizontal")) {
+        item = SGLabel.HORIZONTAL;
+      } else if(str.equals("Vertical")) {
+        item = SGLabel.VERTICAL;
+      }
+      label_.setOrientation(item);
+      /**
+       * if orientation has changed redefine DragBox.
+       */
+      if(old != item) {
+        Point2D.Double loc = label_.getLocationP();
+        double w = label_.getWidthP();
+        double h = label_.getHeightP();
+        double x;
+        double y;
+        label_.setWidthP(label_.getHeightP());
+        label_.setHeightP(w);
+        switch(label_.getJustification()) {
+          case SGLabel.CENTER:
+            if(item == SGLabel.VERTICAL) {
+              x = loc.x + w*0.5 - h;
+              y = loc.y - w*0.5;
+            } else {
+              x = loc.x - h*0.5 + w;
+              y = loc.y + h*0.5;
+            }
+            break;
+          default:
+          case SGLabel.LEFT:
+            if(item == SGLabel.VERTICAL) {
+              x = loc.x - h;
+              y = loc.y;
+            } else {
+              x = loc.x + w;
+              y = loc.y;
+            }
+            break;
+          case SGLabel.RIGHT:
+            if(item == SGLabel.VERTICAL) {
+              x = loc.x + w - h;
+              y = loc.y - w;
+            } else {
+              x = loc.x - h + w;
+              y = loc.y + h;
+            }
+        }
+        label_.setLocationP(new Point2D.Double(x,y));
+      }
+     } else if(command.equals("Selectable")) {
+      label_.setSelectable(((JCheckBox)obj).isSelected());
+    }
+  }
+
+  void resetFields() {
+    for(int i=0; i < comps_.length; i++) {
+      if(comps_[i] instanceof JTextField) {
+        ((JTextField)comps_[i]).removeActionListener(this);
+        ((JTextField)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JCheckBox) {
+        ((JCheckBox)comps_[i]).removeActionListener(this);
+        ((JCheckBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JComboBox) {
+        ((JComboBox)comps_[i]).removeActionListener(this);
+        ((JComboBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JButton) {
+        ((JButton)comps_[i]).removeActionListener(this);
+        ((JButton)comps_[i]).removeFocusListener(this);
+      }
+    }
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    Object obj = e.getSource();
+    String command = e.getActionCommand();
+    processEvent(obj, command);
+  }
+  public void stateChanged(ChangeEvent e) {
+    update();
+  }
+  public void focusGained(FocusEvent e) {
+  }
+  public void focusLost(FocusEvent e) {
+    Object obj = e.getSource();
+     if(obj instanceof JTextField) {
+       JTextField tf = (JTextField)obj;
+       String name = tf.getName();
+       processEvent(obj, name);
+     }
+  }
+  public void setExpert(boolean expert) {
+    expert_ = expert;
+  }
+
+  public boolean isExpert() {
+    return expert_;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Legend.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Legend.java
new file mode 100755
index 0000000..aebe6d0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Legend.java
@@ -0,0 +1,606 @@
+/*
+ * $Id: Legend.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.LayerChild;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import javax.swing.event.*;
+import java.util.*;
+import java.io.*;
+import java.beans.*;
+import java.awt.Color;
+import java.awt.Font;
+/**
+ * Encapsulates reference to <code>SGTData</code> and key.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+public class Legend implements Serializable {
+  transient private ChangeEvent changeEvent_ = new ChangeEvent(this);
+  transient private PanelHolder pHolder_ = null;
+  // properties for all keys.
+  private String id = "";
+  private Rectangle2D.Double boundsP = new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0);
+  private boolean visible = true;
+  private boolean instantiated = false;
+  // VectorKey, LineKey, PointCollectionKey specific properties
+  private double lineLength = 0.3;
+  private int columns = 1;
+  // ColorKey specific properties
+  private Color scaleColor = Color.black; //advanced
+  private double scaleLabelHeightP = 0.2;
+  private int scaleNumberSmallTics = 0; // advanced
+  private int scaleLabelInterval = 2;
+  private Font scaleLabelFont = new Font("Helvetica", Font.PLAIN, 10); //advanced
+  private double scaleLargeTicHeightP = 0.1; //advanced
+  private double scaleSmallTicHeightP = 0.05; //advanced
+  private boolean scaleVisible = true; //advanced
+  private int scaleSignificantDigits = 2;
+  private String scaleLabelFormat = ""; //advanced
+  private double keyLabelHeightP = 0.16; //advanced
+  //
+  private int borderStyle = NO_BORDER;
+  /**
+   * Plain line border style.
+   */
+  public static final int PLAIN_LINE = 0;
+  /**
+   * Raised line border style.
+   */
+  public static final int RAISED = 1;
+  /**
+   * No border line border style.
+   */
+  public static final int NO_BORDER = 2;
+
+  private int type = LINE;
+  /**
+   * LineKey legend type
+   */
+  public static final int LINE = 0;
+  /**
+   * ColorKey legend type
+   */
+  public static final int COLOR = 1;
+  /**
+   * VectorKey legend type
+   */
+  public static final int VECTOR = 2;
+  /**
+   * PointCollectionKey legend type
+   */
+  public static final int POINT = 3;
+
+  transient private Vector changeListeners;
+  static {
+    try {
+      BeanInfo info = Introspector.getBeanInfo(Legend.class);
+      PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+      for(int i=0; i < descriptors.length; i++) {
+        PropertyDescriptor pd = descriptors[i];
+        if(pd.getName().equals("instantiated")) {
+          pd.setValue("transient", Boolean.TRUE);
+        } else if(pd.getName().equals("panelHolder")) {
+          pd.setValue("transient", Boolean.TRUE);
+        }
+      }
+    } catch (IntrospectionException ie) {
+     ie.printStackTrace();
+    }
+  }
+
+  /**
+   * Default constructor.  Legend id and bounds set to <code>null</code>.
+   */
+  public Legend() {
+    this(null, null);
+  }
+  /**
+   * Legend constructor.
+   * @param id legend identifier
+   * @param boundsP bounds in physical units
+   */
+  public Legend(String id, Rectangle2D.Double boundsP) {
+    this.id = id;
+    this.boundsP = boundsP;
+  }
+
+  /**
+   * Set legend identifier.
+   * @param id identifier
+   */
+  public void setId(String id) {
+    String saved = this.id;
+    this.id = id;
+    if(saved == null || !saved.equals(this.id)) fireStateChanged();
+  }
+  /**
+   * Get legend identifier
+   * @return ident
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * Set legend bounds.
+   * @param boundsP bounds in physical coordinates
+   */
+  public void setBoundsP(Rectangle2D.Double boundsP) {
+    Rectangle2D.Double saved = this.boundsP;
+    this.boundsP = boundsP;
+    if(saved == null || !saved.equals(this.boundsP)) fireStateChanged();
+  }
+  /**
+   * Get Legend bounds.
+   * @return bounds
+   */
+  public Rectangle2D.Double getBoundsP() {
+    return boundsP;
+  }
+
+  /**
+   * Set the location of the TOP-LEFT corner
+   * @param locationP upper left corner in physical coordinates
+   */
+  public void setLocationP(Point2D.Double locationP) {
+    double x = boundsP.x;
+    double y = boundsP.y - boundsP.height;
+
+    boundsP.x = locationP.x;
+    boundsP.y = locationP.y;
+    if(x != boundsP.x || y != boundsP.y)
+      fireStateChanged();
+  }
+  /**
+   * Get the location of the upper left corner.
+   * @return upper left corner
+   */
+  public Point2D.Double getLocationP() {
+    return new Point2D.Double(boundsP.x, boundsP.y + boundsP.height);
+  }
+
+  /**
+   * Set legend height.
+   * @param heightP height on physical coordinates
+   */
+  public void setHeightP(double heightP) {
+    double saved = boundsP.height;
+    boundsP.height = (float)heightP;
+    if(boundsP.height != saved)
+      fireStateChanged();
+  }
+  /**
+   * Get legend height.
+   * @return height
+   */
+  public double getHeightP() {
+    return boundsP.height;
+  }
+
+  /**
+   * Set legend width
+   * @param widthP width in physcial coordinates
+   */
+  public void setWidthP(double widthP) {
+    double saved = boundsP.width;
+    boundsP.width = (float)widthP;
+    if(boundsP.width != saved)
+      fireStateChanged();
+  }
+  /**
+   * Get legend width
+   * @return width
+   */
+  public double getWidthP() {
+    return boundsP.width;
+  }
+
+  /**
+   * Remove change listener.
+   * @param l change listener
+   */
+  public synchronized void removeChangeListener(ChangeListener l) {
+    if (changeListeners != null && changeListeners.contains(l)) {
+      Vector v = (Vector) changeListeners.clone();
+      v.removeElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Add change listener.
+   * @param l change listener
+   */
+  public synchronized void addChangeListener(ChangeListener l) {
+    if(Page.DEBUG) System.out.println("Legend.addChangeListener(" + l + ")");
+    Vector v = changeListeners == null ? new Vector(2) : (Vector) changeListeners.clone();
+    if (!v.contains(l)) {
+      v.addElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Remove change listeners that implement <code>DesignListener</code>.
+   */
+  public synchronized void removeDesignChangeListeners() {
+    if(changeListeners != null) {
+      Vector v = (Vector) changeListeners.clone();
+      Iterator iter = v.iterator();
+      while(iter.hasNext()) {
+        Object obj = iter.next();
+        if(obj instanceof DesignListener) changeListeners.removeElement(obj);
+      }
+    }
+  }
+  /**
+   * Remove all change listeners.
+   */
+  public synchronized void removeAllChangeListeners() {
+    changeListeners = null;
+  }
+
+  protected void fireStateChanged() {
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(changeEvent_);
+      }
+    }
+  }
+
+  /**
+   * Set visibility for legend.
+   * @param visible visibility state
+   */
+  public void setVisible(boolean visible) {
+    boolean saved = this.visible;
+    this.visible = visible;
+    if(saved != this.visible) fireStateChanged();
+  }
+  /**
+   * Test if legend visible.
+   * @return true, if legend is visible
+   */
+  public boolean isVisible() {
+    return visible;
+  }
+
+  /**
+   * Set legend state to instatiated.  This is called internally when the
+   * property Key has been instatiated.
+   * @param instantiated instatiation state
+   */
+  public void setInstantiated(boolean instantiated) {
+    this.instantiated = instantiated;
+  }
+  /**
+   * Test if the key instantiated.
+   * @return true, if key has been instantiated
+   */
+  public boolean isInstantiated() {
+    return instantiated;
+  }
+  /**
+   * Test if legend of type COLOR.
+   * @return true, if legend is COLOR
+   */
+  public boolean isColor() {
+    return type == Legend.COLOR;
+  }
+
+  /**
+   * Get legend type.
+   * @return legend type.
+   */
+  public int getType() {
+    return type;
+  }
+  /**
+   * Set legend type.  Types include <code>COLOR</code>, <code>LINE</code>,
+   * <code>POINT</code>, and <code>VECTOR</code>.
+   * @param type legend type
+   */
+  public void setType(int type) {
+    this.type = type;
+  }
+
+  /**
+   * Get legend border style.
+   * @return border style
+   */
+  public int getBorderStyle() {
+    return borderStyle;
+  }
+  /**
+   * Set legend border style.  Border styles include: <code>PLAIN_LINE</code>,
+   * <code>RAISED</code>, and <code>NO_BORDER</code>.  Default = NO_BORDER.
+   * @param borderStyle border style
+   */
+  public void setBorderStyle(int borderStyle) {
+    int saved = this.borderStyle;
+    this.borderStyle = borderStyle;
+    if(saved != this.borderStyle) fireStateChanged();
+  }
+
+  /**
+   * Get number of columns. Not used with <code>COLOR</code> legends.
+   * @return number of columns
+   */
+  public int getColumns() {
+    return columns;
+  }
+  /**
+   * Set number of columns. Not used with <code>COLOR</code> legends. Default = 1.
+   * @param columns number of columns
+   */
+  public void setColumns(int columns) {
+    int saved = this.columns;
+    this.columns = columns;
+    if(saved != this.columns) fireStateChanged();
+  }
+
+  /**
+   * Get the legend line, or vector length in physical coordinages.
+   * Not used with <code>COLOR</code> legends.
+   * @return line or vector length
+   */
+  public double getLineLength() {
+    return lineLength;
+  }
+  /**
+   * Set the legend line or vector lenght in physical units.
+   * Not used with <code>COLOR</code> legends.
+   * Defautl = 0.3
+   * @param lineLength line or vector length
+   */
+  public void setLineLength(double lineLength) {
+    double saved = this.lineLength;
+    this.lineLength = lineLength;
+    if(saved != this.lineLength) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale color. Only used with <code>COLOR</code>
+   * legends.
+   * @return scale color
+   */
+  public Color getScaleColor() {
+    return scaleColor;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale color. Only used with <code>COLOR</code>
+   * legends.  Deault = black.
+   * @param scaleColor scale color
+   */
+  public void setScaleColor(Color scaleColor) {
+    Color saved = new Color(this.scaleColor.getRed(),
+                            this.scaleColor.getGreen(),
+                            this.scaleColor.getBlue(),
+                            this.scaleColor.getAlpha());
+    this.scaleColor = scaleColor;
+    if(!saved.equals(this.scaleColor)) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale font. Only used with <code>COLOR</code>
+   * legends.
+   * @return scale font
+   */
+  public Font getScaleLabelFont() {
+    return scaleLabelFont;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale font. Only used with <code>COLOR</code>
+   * legends.  Deault = ("Helvetica", PLAIN, 10).
+   * @param scaleLabelFont scale font
+   */
+  public void setScaleLabelFont(Font scaleLabelFont) {
+    Font saved = new Font(this.scaleLabelFont.getName(),
+                          this.scaleLabelFont.getStyle(),
+                          this.scaleLabelFont.getSize());
+    this.scaleLabelFont = scaleLabelFont;
+    if(!saved.equals(this.scaleLabelFont)) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale label height in physical coordinates.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale label height
+   */
+  public double getScaleLabelHeightP() {
+    return scaleLabelHeightP;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale label heigth. Only used with <code>COLOR</code>
+   * legends.  Deault = 0.2.
+   * @param scaleLabelHeightP scale label height
+   */
+  public void setScaleLabelHeightP(double scaleLabelHeightP) {
+    double saved = this.scaleLargeTicHeightP;
+    this.scaleLabelHeightP = scaleLabelHeightP;
+    if(saved != this.scaleLabelHeightP) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale label interval.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale label interval
+   */
+  public int getScaleLabelInterval() {
+    return scaleLabelInterval;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale label interval. Only used with <code>COLOR</code>
+   * legends.  Deault = 2.
+   * @param scaleLabelInterval scale label interval
+   */
+  public void setScaleLabelInterval(int scaleLabelInterval) {
+    int saved = this.scaleLabelInterval;
+    this.scaleLabelInterval = scaleLabelInterval;
+    if(saved != this.scaleLabelInterval) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale number of small tics.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale number of small tics
+   */
+  public int getScaleNumberSmallTics() {
+    return scaleNumberSmallTics;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale number of small tics. Only used with <code>COLOR</code>
+   * legends.  Deault = 0.
+   * @param scaleNumberSmallTics scale number of small tics
+   */
+  public void setScaleNumberSmallTics(int scaleNumberSmallTics) {
+    int saved = this.scaleNumberSmallTics;
+    this.scaleNumberSmallTics = scaleNumberSmallTics;
+    if(saved != this.scaleNumberSmallTics) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale label format.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale label format
+   */
+  public String getScaleLabelFormat() {
+    return scaleLabelFormat;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale label format. Only used with <code>COLOR</code>
+   * legends.  Deault = "".
+   * @param scaleLabelFormat scale label format
+   */
+  public void setScaleLabelFormat(String scaleLabelFormat) {
+    String saved = this.scaleLabelFormat;
+    this.scaleLabelFormat = scaleLabelFormat;
+    if(!saved.equals(this.scaleLabelFormat)) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale large tick height.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale large tick height
+   */
+  public double getScaleLargeTicHeightP() {
+    return scaleLargeTicHeightP;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale large tick height in physical
+   * coordinates. Only used with <code>COLOR</code>
+   * legends.  Deault = 0.1.
+   * @param scaleLargeTicHeightP scale large tick height
+   */
+  public void setScaleLargeTicHeightP(double scaleLargeTicHeightP) {
+    double saved = this.scaleLargeTicHeightP;
+    this.scaleLargeTicHeightP = scaleLargeTicHeightP;
+    if(saved != this.scaleLargeTicHeightP) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale significant digits.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale significant digits
+   */
+  public int getScaleSignificantDigits() {
+    return scaleSignificantDigits;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale significant digits. Only used with <code>COLOR</code>
+   * legends.  Deault = 2.
+   * @param scaleSignificantDigits scale significant digits
+   */
+  public void setScaleSignificantDigits(int scaleSignificantDigits) {
+    int saved = this.scaleSignificantDigits;
+    this.scaleSignificantDigits = scaleSignificantDigits;
+    if(saved != this.scaleSignificantDigits) fireStateChanged();
+  }
+
+  /**
+   * Get <code>COLOR</code> legend scale small tick height.
+   * Only used with <code>COLOR</code> legends.
+   * @return scale small tick height
+   */
+  public double getScaleSmallTicHeightP() {
+    return scaleSmallTicHeightP;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale small tick height in physical
+   * coordinates. Only used with <code>COLOR</code>
+   * legends.  Deault = 0.05.
+   * @param scaleSmallTicHeightP scale small tick height
+   */
+  public void setScaleSmallTicHeightP(double scaleSmallTicHeightP) {
+    double saved = this.scaleSmallTicHeightP;
+    this.scaleSmallTicHeightP = scaleSmallTicHeightP;
+    if(saved != this.scaleSmallTicHeightP) fireStateChanged();
+  }
+
+  /**
+   * Test if <code>COLOR</code> legend scale visible.
+   * Only used with <code>COLOR</code> legends.
+   * @return true, if scale visible
+   */
+  public boolean isScaleVisible() {
+    return scaleVisible;
+  }
+  /**
+   * Set <code>COLOR</code> legend scale visible. Only used with <code>COLOR</code>
+   * legends.  Deault = true.
+   * @param scaleVisible scale visible
+   */
+  public void setScaleVisible(boolean scaleVisible) {
+    boolean saved = this.scaleVisible;
+    this.scaleVisible = scaleVisible;
+    if(saved != this.scaleVisible) fireStateChanged();
+  }
+
+  /**
+   * Get <code>PanelHolder</code> parent.
+   * @return panelholder
+   */
+  public PanelHolder getPanelHolder() {
+    return pHolder_;
+  }
+  /**
+   * Set <code>PanelHolder</code> parent.
+   * @param pHolder panelholder
+   */
+  public void setPanelHolder(PanelHolder pHolder) {
+    pHolder_ = pHolder;
+  }
+
+  /**
+   * Get key label height.
+   * @return key label height
+   */
+  public double getKeyLabelHeightP() {
+    return keyLabelHeightP;
+  }
+  /**
+   * Set key label height in physical coordinates.
+   * Default = 0.16.
+   * @param keyLabelHeightP key label height
+   */
+  public void setKeyLabelHeightP(double keyLabelHeightP) {
+    double saved = this.keyLabelHeightP;
+    this.keyLabelHeightP = keyLabelHeightP;
+    if(saved != this.keyLabelHeightP) fireStateChanged();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LegendDragBox.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LegendDragBox.java
new file mode 100755
index 0000000..e22c493
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LegendDragBox.java
@@ -0,0 +1,100 @@
+/*
+ * $Id: LegendDragBox.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+
+import gov.noaa.pmel.util.Rectangle2D;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class LegendDragBox extends DragBox implements ChangeListener {
+  private Legend legend_ = null;
+  private Rectangle boundsD_ = null;
+
+  public LegendDragBox(Legend legend, PanelHolder pHolder) {
+    super(pHolder);
+    legend_ = legend;
+    legend_.addChangeListener(this);
+    boundsD_ = toRectangle(legend_.getBoundsP());
+    for(int i=0; i < handles_.length;  i++) {
+      handles_[i] = new Rectangle(0,0,0,0);
+    }
+    computeHandles();
+  }
+
+  public Legend getLegend() {
+    return legend_;
+  }
+
+  public void setBounds(Rectangle bounds) {
+    boundsD_ = bounds;
+    legend_.setBoundsP(toRectangle(boundsD_));
+    computeHandles();
+  }
+
+  public void draw(Graphics g) {
+    Rectangle bounds = getBounds();
+    Color saved = g.getColor();
+    g.setColor(Color.darkGray);
+    g.drawString(getId(), bounds.x + 5, bounds.y + 12);
+    g.setColor(color_);
+    if(legend_.isVisible())
+      g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+    if(selected_) {
+      for(int i=0; i < handles_.length; i++) {
+        Rectangle r = handles_[i];
+        g.fillRect(r.x, r.y, r.width-1, r.height-1);
+      }
+    }
+    g.setColor(saved);
+  }
+
+  public void setLocation(Point pt) {
+    boundsD_.x = pt.x;
+    boundsD_.y = pt.y;
+    legend_.setBoundsP(toRectangle(boundsD_));
+    computeHandles();
+  }
+
+  public Point getLocation() {
+    return new Point(boundsD_.x, boundsD_.y);
+  }
+
+  public Rectangle getBounds() {
+    return boundsD_;
+  }
+
+  public String getId() {
+    return legend_.getId();
+  }
+
+  public void update(String message) {
+//    if(Page.DEBUG) System.out.println("LegendDragBox.update(" + message + ")");
+    boundsD_ = toRectangle(legend_.getBoundsP());
+    computeHandles();
+  }
+
+  public void setId(String id) {
+    legend_.setId(id);
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    update("LegendDragBox.stateChanged()");
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LegendPropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LegendPropertyPanel.java
new file mode 100755
index 0000000..d85b290
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/LegendPropertyPanel.java
@@ -0,0 +1,337 @@
+/*
+ * $Id: LegendPropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import javax.swing.*;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.Color;
+import java.awt.Font;
+import java.text.DecimalFormat;
+
+import gov.noaa.pmel.sgt.Ruler;
+import gov.noaa.pmel.sgt.swing.prop.FontDialog;
+import gov.noaa.pmel.sgt.swing.prop.ColorDialog;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class LegendPropertyPanel extends PropertyPanel implements ActionListener, ChangeListener, FocusListener {
+  private boolean expert_ = false;
+  private Legend legend_;
+  private String[] pNames_ =
+  { "Border",                  "Columns",              "Height",
+    "Id",                      "Key Label HeightP",    "Line Length",
+    "Location",
+    "Type",                    "Scale Color",          "Scale Label Font",
+    "Scale Label Format",      "Scale Label HeightP",  "Scale Label Interval",
+    "Scale Large Tic HeightP", "Scale Num Small Tics", "Scale Significant Digits",
+    "Scale Small Tic HeightP", "Scale Visible",        "Visible",
+    "Width"};
+  private boolean[] inColor_ =
+  { true,                      false,                  true,
+    true,                      true,                   false,
+    true,
+    true,                      true,                   true,
+    true,                      true,                   true,
+    true,                      true,                   true,
+    true,                      true,                   true,
+    true};
+  private boolean[] inColorOnly_ =
+  { false,                     false,                  false,
+    false,                     false,                  false,
+    false,
+    false,                     true,                   true,
+    true,                      true,                   true,
+    true,                      true,                   true,
+    true,                      true,                   false,
+    false};
+  private boolean[] expertItem_ =
+  { false,                     false,                  false,
+    false,                     true,                   false,
+    false,
+    false,                     true,                   true,
+    true,                      true,                   false,
+    true,                      true,                   false,
+    true,                      true,                   false,
+    false};
+  private JComponent[] comps_ = new JComponent[pNames_.length];
+  private String[] keyType = {"Line", "Color", "Vector", "Point"};
+  private String[] borderType = {"Plain Line", "Raised", "No Border"};
+  private static DecimalFormat format_ = new DecimalFormat("#.###");
+
+  public LegendPropertyPanel(Legend legend, boolean expert) {
+    super();
+    legend_ = legend;
+    expert_ = expert;
+    legend_.addChangeListener(this);
+    reset();
+  }
+
+  public void setLegend(Legend legend, boolean expert) {
+    if(legend_ != null) legend_.removeChangeListener(this);
+    legend_ = legend;
+    legend_.addChangeListener(this);
+    expert_ = expert;
+//    update();
+    reset();
+  }
+
+  void update() {
+    int item = -1;
+    int i = -1;
+    switch(legend_.getBorderStyle()) {
+      default:
+      case Legend.PLAIN_LINE:
+        item = 0;
+        break;
+      case Legend.RAISED:
+        item = 1;
+        break;
+      case Legend.NO_BORDER:
+        item = 2;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JTextField)comps_[++i]).setText(Integer.toString(legend_.getColumns()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getHeightP(), format_));
+    ((JTextField)comps_[++i]).setText(legend_.getId());
+    ((JTextField)comps_[++i]).setText(format(legend_.getKeyLabelHeightP()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getLineLength()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getLocationP(), false));
+    switch(legend_.getType()) {
+      default:
+      case Legend.LINE:
+        item = 0;
+        break;
+      case Legend.COLOR:
+        item = 1;
+        break;
+      case Legend.VECTOR:
+        item = 2;
+        break;
+      case Legend.POINT:
+        item = 3;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    updateColor((JButton)comps_[++i], legend_.getScaleColor());
+    updateFont((JButton)comps_[++i], legend_.getScaleLabelFont());
+    ((JTextField)comps_[++i]).setText(legend_.getScaleLabelFormat());
+    ((JTextField)comps_[++i]).setText(format(legend_.getScaleLabelHeightP()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getScaleLabelInterval()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getScaleLargeTicHeightP()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getScaleNumberSmallTics()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getScaleSignificantDigits()));
+    ((JTextField)comps_[++i]).setText(format(legend_.getScaleSmallTicHeightP()));
+    ((JCheckBox)comps_[++i]).setSelected(legend_.isScaleVisible());
+    ((JCheckBox)comps_[++i]).setSelected(legend_.isVisible());
+    ((JTextField)comps_[++i]).setText(format(legend_.getWidthP(), format_));
+  }
+
+  void create() {
+    int item = -1;
+    int i = -1;
+    switch(legend_.getBorderStyle()) {
+      default:
+      case Legend.PLAIN_LINE:
+        item = 0;
+        break;
+      case Legend.RAISED:
+        item = 1;
+        break;
+      case Legend.NO_BORDER:
+        item = 2;
+        break;
+    }
+    comps_[++i] = createComboBox(borderType, item, pNames_[i], this, true);
+    comps_[++i] = createTextField(Integer.toString(legend_.getColumns()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getHeightP(), format_), pNames_[i], this, true);
+    comps_[++i] = createTextField(legend_.getId(), pNames_[i], this, !legend_.isInstantiated());
+    comps_[++i] = createTextField(format(legend_.getKeyLabelHeightP()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getLineLength()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getLocationP(), false), pNames_[i], this, true);
+    String[] axisPosition;
+    switch(legend_.getType()) {
+      default:
+      case Legend.LINE:
+        item = 0;
+        break;
+      case Legend.COLOR:
+        item = 1;
+        break;
+      case Legend.VECTOR:
+        item = 2;
+        break;
+      case Legend.POINT:
+        item = 3;
+        break;
+    }
+    comps_[++i] = createComboBox(keyType, item, pNames_[i], this, !legend_.isInstantiated());
+    comps_[++i] = createColor(legend_.getScaleColor(), pNames_[i], this);
+    comps_[++i] = createFont(legend_.getScaleLabelFont(), pNames_[i], this);
+    comps_[++i] = createTextField(legend_.getScaleLabelFormat(), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getScaleLabelHeightP()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getScaleLabelInterval()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getScaleLargeTicHeightP()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getScaleNumberSmallTics()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getScaleSignificantDigits()), pNames_[i], this, true);
+    comps_[++i] = createTextField(format(legend_.getScaleSmallTicHeightP()), pNames_[i], this, true);
+    comps_[++i] = createCheckBox(legend_.isScaleVisible(), pNames_[i], this);
+    comps_[++i] = createCheckBox(legend_.isVisible(), pNames_[i], this);
+    comps_[++i] = createTextField(format(legend_.getWidthP(), format_), pNames_[i], this, true);
+
+    for(i=0; i < comps_.length; i++) {
+      if(expert_ || ! expertItem_[i])
+      if(legend_.isColor()) {
+        if(inColor_[i]) {
+           addProperty(i+1, pNames_[i], comps_[i], false);
+        }
+      } else {
+        if(!inColorOnly_[i]) {
+           addProperty(i+1, pNames_[i], comps_[i], false);
+        }
+      }
+    }
+    addProperty(comps_.length + 1, " ", new JLabel(" "), true);
+  }
+
+  void resetFields() {
+    for(int i=0; i < comps_.length; i++) {
+      if(comps_[i] instanceof JTextField) {
+        ((JTextField)comps_[i]).removeActionListener(this);
+        ((JTextField)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JCheckBox) {
+        ((JCheckBox)comps_[i]).removeActionListener(this);
+        ((JCheckBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JComboBox) {
+        ((JComboBox)comps_[i]).removeActionListener(this);
+        ((JComboBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JButton) {
+        ((JButton)comps_[i]).removeActionListener(this);
+        ((JButton)comps_[i]).removeFocusListener(this);
+      }
+    }
+  }
+  private void processEvent(Object obj, String command) {
+    if(command.equals("Height")) {
+      legend_.setHeightP(Float.parseFloat(((JTextField)obj).getText()));
+    } else if(command.equals("Id")) {
+      String oldId = legend_.getId();
+      legend_.getPanelHolder().getLegends().remove(oldId);
+      legend_.setId(((JTextField)obj).getText());
+      legend_.getPanelHolder().getLegends().put(legend_.getId(), legend_);
+    } else if(command.equals("Key Label HeightP")) {
+      legend_.setKeyLabelHeightP(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Border")) {
+      String str = (String)((JComboBox)obj).getSelectedItem();
+      int item = -1;
+      if(str.equals("Plain Line")) {
+        item = Legend.PLAIN_LINE;
+      } else if(str.equals("Raised")) {
+        item = Legend.RAISED;
+      } else if(str.equals("No Border")) {
+        item = Legend.NO_BORDER;
+      }
+      legend_.setBorderStyle(item);
+    } else if(command.equals("Columns")) {
+      legend_.setColumns(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Line Length")) {
+      legend_.setLineLength(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Location")) {
+      legend_.setLocationP(parsePoint2D(((JTextField)obj).getText()));
+    } else if(command.equals("Type")) {
+      String str = (String)((JComboBox)obj).getSelectedItem();
+       int item = -1;
+       if(str.equals("Line")) {
+         item = Legend.LINE;
+       } else if(str.equals("Color")) {
+         item = Legend.COLOR;
+       } else if(str.equals("Vector")) {
+         item = Legend.VECTOR;
+       } else if(str.equals("Point")) {
+         item = Legend.POINT;
+       }
+       legend_.setType(item);
+       reset();
+    } else if(command.equals("Scale Color")) {
+      ColorDialog cd = new ColorDialog(getFrame(), "Select Axis Color", true);
+      cd.setColor(legend_.getScaleColor());
+      cd.setVisible(true);
+      Color newcolor = cd.getColor();
+      if(newcolor != null) legend_.setScaleColor(newcolor);
+    } else if(command.equals("Scale Label Font")) {
+      FontDialog fd = new FontDialog("Label Font");
+      int result = fd.showDialog(legend_.getScaleLabelFont());
+      if(result == fd.OK_RESPONSE) {
+        legend_.setScaleLabelFont(fd.getFont());
+      }
+    } else if(command.equals("Scale Label Format")) {
+      legend_.setScaleLabelFormat(((JTextField)obj).getText());
+    } else if(command.equals("Scale Label HeightP")) {
+      legend_.setScaleLabelHeightP(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Scale Label Interval")) {
+      legend_.setScaleLabelInterval(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Scale Large Tic HeightP")) {
+      legend_.setScaleLargeTicHeightP(Double.parseDouble(((JTextField)obj).getText()));
+    } else if(command.equals("Scale Num Small Tics")) {
+      legend_.setScaleNumberSmallTics(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Scale Significant Digits")) {
+      legend_.setScaleSignificantDigits(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Scale Small Tic HeightP")) {
+      legend_.setScaleSmallTicHeightP(Integer.parseInt(((JTextField)obj).getText()));
+    } else if(command.equals("Scale Visible")) {
+      legend_.setScaleVisible(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Visible")) {
+      legend_.setVisible(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Width")) {
+      legend_.setWidthP(Float.parseFloat(((JTextField)obj).getText()));
+    }
+  }
+
+ public void actionPerformed(ActionEvent e) {
+    Object obj = e.getSource();
+    String command = e.getActionCommand();
+    processEvent(obj, command);
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    update();
+  }
+  public void focusGained(FocusEvent e) {
+  }
+  public void focusLost(FocusEvent e) {
+    Object obj = e.getSource();
+    if(obj instanceof JTextField) {
+      JTextField tf = (JTextField)obj;
+      String name = tf.getName();
+      processEvent(obj, name);
+    }
+  }
+  public void setExpert(boolean expert) {
+    boolean save = expert_;
+    expert_ = expert;
+    if(expert_ != save) reset();
+  }
+
+  public boolean isExpert() {
+    return expert_;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Margin.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Margin.java
new file mode 100755
index 0000000..b534d1a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Margin.java
@@ -0,0 +1,136 @@
+/*
+ * $Id: Margin.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.io.*;
+
+/**
+ * Margin class.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+public class Margin implements Cloneable, Serializable {
+  /**
+   * Left margin.
+   */
+  public float left = Float.NaN;
+  /**
+   * Right margin.
+   */
+  public float right = Float.NaN;
+  /**
+   * Top margin.
+   */
+  public float top = Float.NaN;
+  /**
+   * Bottom margin.
+   */
+  public float bottom = Float.NaN;
+  /**
+   * Default constructor.  Sets all margin components to 0.0.
+   */
+  public Margin() {
+    this(0.0f, 0.0f, 0.0f, 0.0f);
+  }
+  /**
+   * Margin constructor.
+   * @param top top margin
+   * @param left left margin
+   * @param bottom bottom margin
+   * @param right right margin
+   */
+  public Margin(float top, float left, float bottom, float right) {
+    this.top = top;
+    this.left = left;
+    this.bottom = bottom;
+    this.right = right;
+
+  }
+  /**
+   * Copy Margin object.
+   * @return Margin
+   */
+  public Margin copy() {
+    try {
+      return (Margin)clone();
+    } catch (CloneNotSupportedException ex) {
+    }
+    return null;
+  }
+  /**
+   * Set top margin.
+   * @param top top margin
+   */
+  public void setTop(float top) {
+    this.top = top;
+  }
+  /**
+   * Get top margin.
+   * @return top margin
+   */
+  public float getTop() {
+    return top;
+  }
+  /**
+   * Set bottom margin.
+   * @param bottom bottom margin
+   */
+  public void setBottom(float bottom) {
+    this.bottom = bottom;
+  }
+  /**
+   * Get bottom margin
+   * @return bottom margin
+   */
+  public float getBottom() {
+    return bottom;
+  }
+  /**
+   * Set left margin.
+   * @param left left margin
+   */
+  public void setLeft(float left) {
+    this.left = left;
+  }
+  /**
+   * Get left margin.
+   * @return left margin
+   */
+  public float getLeft() {
+    return left;
+  }
+
+  /**
+   * Set right margin.
+   * @param right right margin
+   */
+  public void setRight(float right) {
+    this.right = right;
+  }
+  /**
+   * Get right margin.
+   * @return right margin
+   */
+  public float getRight() {
+    return right;
+  }
+  /**
+   * Get string representation of <code>Margin</code>.
+   * @return string
+   */
+  public String toString() {
+    return Float.toString(top) + ", " + Float.toString(left) +
+        ", " + Float.toString(bottom) + ", " + Float.toString(right);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Page.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Page.java
new file mode 100755
index 0000000..fb35e48
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Page.java
@@ -0,0 +1,457 @@
+/*
+ * $Id: Page.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Point2D;
+//import gov.noaa.pmel.util.SoTDomain;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+import java.util.Vector;
+import java.util.Iterator;
+import javax.swing.JComponent;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.Border;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.InputEvent;
+import java.awt.Rectangle;
+import java.awt.Point;
+
+import java.beans.*;
+import java.io.*;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterException;
+import java.awt.print.Printable;
+
+/**
+ * Main SGT JavaBean in conjunction with a <code>DataModel</code> and <code>PanelModel</code>
+ * will create a graphic.
+ *
+ * <p> Some classes have been omitted for display purposes.
+ * <P ALIGN="CENTER"><IMG SRC="images/RunTimeSimple.png" ALIGN="BOTTOM" BORDER="0">
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ * @stereotype bean
+ **/
+public class Page extends JComponent implements PropertyChangeListener, Serializable, Printable {
+  public static final boolean DEBUG = false;
+  /**
+   * @link aggregation
+   * @supplierCardinality 1
+   * @undirected
+   * @label dataModel
+   */
+  private DataModel dataModel;
+
+  /**
+   * @link aggregation
+   * @supplierCardinality 1
+   * @undirected
+   * @label panelModel
+   */
+  private PanelModel panelModel;
+
+  /**
+   *@link aggregation
+   *     @associates <{Panel}>
+   * @supplierCardinality 1..*
+   * @clientCardinality 1
+   * @undirected
+   */
+//  transient private Vector panels_;
+
+  /**
+   * @link aggregationByValue
+   * @clientCardinality 1
+   * @supplierCardinality 1
+   * @undirected
+   * @label pane
+   */
+  private JPane pane_;
+  private String name;
+  transient private boolean isDesignTime_ = Beans.isDesignTime();
+
+  /**
+   * <code>Page</code> constructor.
+   */
+  public Page() {
+    pane_ = new JPane("SGT Bean Pane", new Dimension(200, 200));
+    pane_.addPropertyChangeListener(this);
+    pane_.setBackground(Color.white);
+    pane_.setOpaque(true);
+    this.setOpaque(true);
+    this.setLayout(new BorderLayout());
+    this.setBackground(Color.white);
+    this.add(pane_, BorderLayout.CENTER);
+    pane_.addMouseListener(new PageMouse());
+  }
+
+  /**
+   * Get <code>JPane</code> associated with <code>Page</code>
+   * @return JPane
+   */
+  public JPane getJPane() {
+    return pane_;
+  }
+
+  /**
+   * Get <code>JPane</code> size.
+   * @return JPane size
+   */
+  public Dimension getJPaneSize() {
+    return pane_.getSize();
+  }
+
+  protected void paintComponent(Graphics g) {
+    super.paintComponent(g);
+  }
+
+  /**
+   * Get <code>DataModel</code>.
+   * @return DataModel
+   * @see DataModel
+   */
+  public DataModel getDataModel() {
+      return dataModel;
+  }
+
+  /**
+   * Set <code>DataModel</code>. <code>DataModel</code> is used to define the
+   * relationship between <code>SGTData</code> and the graphical representation.
+   * @param dataModel DataModel
+   * @see DataModel
+   */
+  public void setDataModel(DataModel dataModel) {
+    if(DEBUG) System.out.println("Page.setDataModel()");
+
+    DataModel saved = this.dataModel;
+    if(this.dataModel != null) this.dataModel.removePropertyChangeListener(this);
+    if(dataModel != null) dataModel.addPropertyChangeListener(this);
+
+    this.dataModel = dataModel;
+    this.dataModel.setPage(this);
+    if(isDesignTime_) repaint();
+    firePropertyChange("dataModel", saved, this.dataModel);
+  }
+
+  /**
+   * Get <code>PanelModel</code>.
+   * @return PanelModel
+   * @see PanelModel
+   */
+  public PanelModel getPanelModel(){
+    return panelModel;
+  }
+
+  /**
+   * Set <code>PanelModel</code>.  The <code>PanelModel</code> contains the information
+   * that indicates placement of <code>Panel</code>s and <code>DataGroupLayer</code>s.
+   * @param panelModel PanelModel
+   * @see PanelModel
+   */
+  public void setPanelModel(PanelModel panelModel){
+    if(DEBUG) System.out.println("Page.setPanelModel()");
+    PanelModel saved = this.panelModel;
+    setSize(panelModel.getPageSize());
+    setBackground(panelModel.getPageBackgroundColor());
+    setPreferredSize(panelModel.getPageSize());
+    this.panelModel = panelModel;
+    this.panelModel.setPage(this);
+    updatePanels();
+    if(isDesignTime_) repaint();
+    firePropertyChange("panelModel", saved, this.panelModel);
+  }
+
+  public String getName() {
+    return name;
+  }
+  public void setBackground(Color color) {
+    super.setBackground(color);
+    pane_.setBackground(color);
+  }
+  public void setName(String name) {
+    firePropertyChange("name", this.name, name);
+    this.name = name;
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    Object source = evt.getSource();
+    String property = evt.getPropertyName();
+    if(source instanceof PanelModel) {
+      if(DEBUG) System.out.println("Page.propertyChange(PanelModel): " + property);
+      updatePanels();
+    } else if(source instanceof DataModel) {
+      Object obj = evt.getNewValue();
+      if(obj instanceof DataHolder) {
+        try {
+          pane_.setBatch(true);
+          ((DataHolder)obj).notifyPanel();
+          pane_.setModified(true, "Page");
+          pane_.setBatch(false);
+        } catch (DataTargetMismatchException dtme) {
+          dtme.printStackTrace();
+        }
+      }
+      if(DEBUG) System.out.println("Page.propertyChange(DataModel): " + property);
+    } else if(source == pane_) {
+      if(property.equals("objectSelected")) {
+
+      } else if(property.equals("zoomRectangle")) {
+
+      }
+      if(DEBUG) System.out.println("Page.propertyChange(JPane): " + property);
+
+    }
+  }
+
+  private void updatePanels() {
+    // check for deleted PanelHolders
+    setSize(panelModel.getPageSize());
+    setBackground(panelModel.getPageBackgroundColor());
+    setPrintHAlign(panelModel.getPrintHAlign());
+    setPrintVAlign(panelModel.getPrintVAlign());
+    setPrintOrigin(panelModel.getPrintOrigin());
+    setPrintScaleMode(panelModel.getPrintScaleMode());
+    pane_.setBatch(true);
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Panel) {
+        Panel pnl = (Panel)comps[i];
+        if(!panelModel.hasPanelHolder(pnl.getName())) {
+          pane_.remove(pnl);
+        }
+      }
+    }
+    // check for new PanelHolders then create otherwise update
+    Panel panel = null;
+    Iterator phIter = panelModel.panelIterator();
+    while(phIter.hasNext()) {
+      PanelHolder ph = (PanelHolder)phIter.next();
+      panel = findPanel(ph);
+      if(panel == null) {
+        panel = new Panel(ph);
+        ph.setInstantiated(true);
+//        panel.setBorder(new EtchedBorder());
+        pane_.add(panel);
+      } else {
+        panel.update();
+      }
+    }
+    validate();
+    pane_.setModified(true, "Page");
+    pane_.setBatch(false);
+  }
+
+  /**
+   * Find the <code>Panel</code> associated with <code>PanelHolder</code>, a
+   * <code>PanelModel</code> component.
+   * @param pHolder PanelHolder
+   * @return Panel
+   * @see PanelModel
+   * @see PanelHolder
+   * @see Panel
+   */
+  public Panel findPanel(PanelHolder pHolder) {
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Panel) {
+        if(((Panel)comps[i]).getName().equals(pHolder.getId())) return (Panel)comps[i];
+      }
+    }
+    return null;
+  }
+
+  private void pageMousePressed(MouseEvent event) {
+    if(!event.isControlDown()) return;
+
+    pane_.setBatch(true);
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Panel) {
+        Panel pnl = (Panel)comps[i];
+        pnl.resetZoom(event.getX(), event.getY());
+      }
+    }
+    pane_.setBatch(false);
+  }
+
+  /**
+   * Reset the zoom for all <code>Panel</code>s and <code>DataGroupLayer</code>s.
+   */
+  public void resetZoom() {
+    pane_.setBatch(true);
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Panel) {
+        Panel pnl = (Panel)comps[i];
+        pnl.resetZoom();
+      }
+    }
+    pane_.setBatch(false);
+  }
+
+  private void pageMouseClicked(MouseEvent event) {
+    if(event.isControlDown()) return;  // ignore zoom resets
+    if(event.isPopupTrigger()) System.out.println("Page.pageMouseClicked(): isPopupTrigger()");
+    Object obj = pane_.getSelectedObject();
+    if((event.getModifiers()&InputEvent.BUTTON3_MASK) != 0) System.out.println("Page.pageMouseClicked(): Button3!");
+  }
+
+  private void pageMouseReleased(MouseEvent event) {
+    //
+    // continue only if button1 is pressed
+    //
+    if((event.getModifiers()&InputEvent.BUTTON1_MASK) == 0) return;
+    Rectangle zm = pane_.getZoomBounds();
+    Point zmStart = pane_.getZoomStart();
+    if(zm.width <= 1 || zm.height <= 1) return;
+
+    pane_.setBatch(true);
+    Component[] comps = pane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Panel) {
+        Panel pnl = (Panel)comps[i];
+        pnl.zoomTo(zmStart, zm);
+      }
+    }
+    pane_.setBatch(false);
+  }
+
+  class PageMouse extends MouseAdapter  {
+    public void mousePressed(MouseEvent event) {
+      if(!pane_.isMouseEventsEnabled()) return;
+      pageMousePressed(event);
+    }
+
+    public void mouseClicked(MouseEvent event) {
+      if(!pane_.isMouseEventsEnabled()) return;
+      pageMouseClicked(event);
+    }
+
+    public void mouseReleased(MouseEvent event) {
+      if(!pane_.isMouseEventsEnabled()) return;
+      pageMouseReleased(event);
+    }
+  }
+  public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
+    int result = NO_SUCH_PAGE;
+    Color saveColor = getBackground();
+    if(panelModel.isPrintWhitePage()) {
+      setBackground(Color.white);
+    }
+    result = pane_.print(g, pf, pageIndex);
+    if(result == PAGE_EXISTS && panelModel.isPrintBorders()) {
+      Component[] comps = pane_.getComponents();
+       for(int i=0; i < comps.length; i++) {
+         if(comps[i] instanceof Panel) {
+           Panel pnl = (Panel)comps[i];
+           Rectangle r = pnl.getBounds();
+           Border bdr = pnl.getBorder();
+           bdr.paintBorder(pnl, g, r.x, r.y, r.width, r.height);
+         }
+       }
+    }
+    setBackground(saveColor);
+    return result;
+  }
+  /**
+   * Set printing  scale mode.  Legal values are AbstractPane.DEFAULT_SCALE,
+   * AbstractPane.TO_FIT, and AbstractPane.SHRINK_TO_FIT.  Default =
+   * AbstractPane.DEFAULT_SCALE.
+   * @param mode scale mode
+   * @see gov.noaa.pmel.sgt.AbstractPane#DEFAULT_SCALE AbstractPane.DEFAULT_SCALE
+   * @see gov.noaa.pmel.sgt.AbstractPane#TO_FIT AbstractPane.TO_FIT
+   * @see gov.noaa.pmel.sgt.AbstractPane#SHRINK_TO_FIT AbstractPane.SHRINK_TO_FIT
+   */
+  public void setPrintScaleMode(int mode) {
+    pane_.setPageScaleMode(mode);
+  }
+  /**
+   * Get printing scale mode.
+   * @return scale mode
+   */
+  public int  getPrintScaleMode() {
+    return pane_.getPageScaleMode();
+  }
+  /**
+   * Set vertical  alignment for printing.  Legal values are AbstractPane.TOP,
+   * AbstractPane.MIDDLE, AbstractPane.BOTTOM, and AbstractPane.SPECIFIED_LOCATION.
+   * Default = AbstractPane.TOP;
+   * @param pageVAlign vertical alignment
+   * @see gov.noaa.pmel.sgt.AbstractPane#TOP AbstractPane.TOP
+   * @see gov.noaa.pmel.sgt.AbstractPane#MIDDLE AbstractPane.MIDDLE
+   * @see gov.noaa.pmel.sgt.AbstractPane#BOTTOM AbstractPane.BOTTOM
+   * @see gov.noaa.pmel.sgt.AbstractPane#SPECIFIED_LOCATION AbstractPane.SPECIFIED_LOCATION
+   */
+  public void setPrintVAlign(int vert) {
+    pane_.setPageVAlign(vert);
+  }
+  /**
+   * Set horizontal alignment for printing.  Legal values are AbstractPane.LEFT,
+   * AbstractPane.CENTER, AbstractPane.RIGHT, and AbstractPane.SPECIFIED_LOCATION.
+   * Default = AbstractPane.CENTER.
+   * @param pageHAlign horizontal alignment
+   * @see gov.noaa.pmel.sgt.AbstractPane#LEFT AbstractPane.LEFT
+   * @see gov.noaa.pmel.sgt.AbstractPane#CENTER AbstractPane.CENTER
+   * @see gov.noaa.pmel.sgt.AbstractPane#RIGHT AbstractPane.RIGHT
+   * @see gov.noaa.pmel.sgt.AbstractPane#SPECIFIED_LOCATION AbstractPane.SPECIFIED_LOCATION
+   */
+  public void setPrintHAlign(int horz) {
+    pane_.setPageHAlign(horz);
+  }
+  /**
+   * Get vertical alignment for printing.
+   * @return vertical alignment.
+   */
+  public int getPrintVAlign() {
+    return pane_.getPageVAlign();
+  }
+  /**
+   * Get horizontal alignment for printing.
+   * @return horizontal alignment
+   */
+  public int getPrintHAlign() {
+    return pane_.getPageHAlign();
+  }
+  /**
+   * Set page origin for printing.  Will be used if the horizontal or vertical alignment is
+   * AbstractPane.SPECIFIED_LOCATION.  Default = (0,0).
+   * @param pageOrigin page origin
+   * @see gov.noaa.pmel.sgt.AbstractPane AbstractPane
+   */
+  public void setPrintOrigin(Point pt) {
+    pane_.setPageOrigin(pt);
+  }
+  /**
+   * Get page origin for printing.
+   * @return page origin.
+   */
+  public Point  getPrintOrigin() {
+    return pane_.getPageOrigin();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageBeanInfo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageBeanInfo.java
new file mode 100755
index 0000000..c3f9b5a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageBeanInfo.java
@@ -0,0 +1,74 @@
+/*
+ * $Id: PageBeanInfo.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.beans.*;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+public class PageBeanInfo extends SimpleBeanInfo {
+  private Class beanClass = Page.class;
+  private String iconColor16x16Filename = "PageIcon16.gif";
+  private String iconColor32x32Filename = "PageIcon32.gif";
+  private String iconMono16x16Filename;
+  private String iconMono32x32Filename;
+
+  public PageBeanInfo() {
+  }
+  public PropertyDescriptor[] getPropertyDescriptors() {
+    try {
+      PropertyDescriptor _background = new PropertyDescriptor("background", beanClass, null, "setBackground");
+      PropertyDescriptor _dataModel = new PropertyDescriptor("dataModel", beanClass, "getDataModel", "setDataModel");
+      PropertyDescriptor _JPane = new PropertyDescriptor("JPane", beanClass, "getJPane", null);
+      PropertyDescriptor _JPaneSize = new PropertyDescriptor("JPaneSize", beanClass, "getJPaneSize", null);
+      PropertyDescriptor _name = new PropertyDescriptor("name", beanClass, "getName", "setName");
+      PropertyDescriptor _panelModel = new PropertyDescriptor("panelModel", beanClass, "getPanelModel", "setPanelModel");
+      PropertyDescriptor _printHAlign = new PropertyDescriptor("printHAlign", beanClass, "getPrintHAlign", "setPrintHAlign");
+      PropertyDescriptor _printOrigin = new PropertyDescriptor("printOrigin", beanClass, "getPrintOrigin", "setPrintOrigin");
+      PropertyDescriptor _printScaleMode = new PropertyDescriptor("printScaleMode", beanClass, "getPrintScaleMode", "setPrintScaleMode");
+      PropertyDescriptor _printVAlign = new PropertyDescriptor("printVAlign", beanClass, "getPrintVAlign", "setPrintVAlign");
+      PropertyDescriptor[] pds = new PropertyDescriptor[] {
+        _background,
+        _dataModel,
+        _JPane,
+        _JPaneSize,
+        _name,
+        _panelModel,
+        _printHAlign,
+        _printOrigin,
+        _printScaleMode,
+        _printVAlign};
+      return pds;
+    }
+    catch(IntrospectionException ex) {
+      ex.printStackTrace();
+      return null;
+    }
+  }
+  public java.awt.Image getIcon(int iconKind) {
+    switch (iconKind) {
+      case BeanInfo.ICON_COLOR_16x16:
+        return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null;
+      case BeanInfo.ICON_COLOR_32x32:
+        return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null;
+      case BeanInfo.ICON_MONO_16x16:
+        return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null;
+      case BeanInfo.ICON_MONO_32x32:
+        return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null;
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageIcon16.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageIcon16.gif
new file mode 100755
index 0000000..292709e
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageIcon32.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageIcon32.gif
new file mode 100755
index 0000000..31ec4eb
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PageIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Panel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Panel.java
new file mode 100755
index 0000000..c8acab4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/Panel.java
@@ -0,0 +1,605 @@
+/*
+ * $Id: Panel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.Graphics;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.Color;
+import java.awt.Point;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Vector;
+import java.util.Collection;
+
+import javax.swing.JComponent;
+import javax.swing.border.Border;
+
+import gov.noaa.pmel.sgt.AbstractPane;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.LayerControl;
+import gov.noaa.pmel.sgt.LayerChild;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.PaneNotFoundException;
+import gov.noaa.pmel.sgt.ChildNotFoundException;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.Attribute;
+import gov.noaa.pmel.sgt.DataKey;
+import gov.noaa.pmel.sgt.LineKey;
+import gov.noaa.pmel.sgt.ColorKey;
+import gov.noaa.pmel.sgt.VectorKey;
+import gov.noaa.pmel.sgt.PointCollectionKey;
+import gov.noaa.pmel.sgt.Ruler;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+
+/**
+ * A <code>Layer</code> container that provides a <code>StackedLayout</code> of
+ * the <code>Layer</code>s.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ * @stereotype container
+ **/
+public class Panel extends JComponent implements LayerControl  {
+  /**
+   * @label pane
+   */
+  private JPane pane_ = null;
+
+  /**
+   * @directed
+   * @label pHolder
+   */
+  private PanelHolder pHolder_ = null;
+
+  /**
+   * @label labelLayer
+   */
+  private Layer labelLayer_ = null;
+
+  /**
+   * @label legendLayer
+   */
+  private Layer legendLayer_ = null;
+  /** @link aggregation
+   * @supplierCardinality * */
+  /*#DataGroupLayer lnkDataGroupLayer; */
+  private Map dataGroupLayerList_ = new HashMap(2);
+
+  /**
+   * <code>Panel</code> constructor.  <code>PanelHolder</code> will need to be
+   * set.
+   * @param name Panel name
+   */
+  public Panel(String name) {
+    super();
+    setName(name);
+    setLayout(new StackedLayout());
+  }
+
+  /**
+   * <code>Panel</code> constructor with <code>PanelHolder</code> argument.
+   * <code>Panel</code> name set from <code>PanelHolder</code> identifier.
+   * @param ph PanelHolder
+   */
+  public Panel(PanelHolder ph) {
+    this(ph.getId());
+    pHolder_ = ph;
+    update();
+  }
+
+  /**
+   * Set <code>PanelHolder</code>.  <code>PanelHolder</code> contains the layout
+   * information and <code>DataGroup</code>s associated with the <code>Panel</code>.
+   * @param ph PanelHolder
+   */
+  public void setPanelHolder(PanelHolder ph) {
+    pHolder_ = ph;
+    setName(pHolder_.getId());
+    update();
+  }
+
+  /**
+   * Traverses the <code>PanelHolder</code> and adds any new objects and
+   * updates exisiting objects.
+   */
+  public void update() {
+    float dpi = pHolder_.getPanelModel().getDpi();
+    setBounds(pHolder_.getBounds());
+    double width = getBounds().width/dpi;
+    double height = getBounds().height/dpi;
+    Dimension2D psize = new Dimension2D(width, height);
+    if(pane_ != null) {
+      boolean batch = pane_.isBatch();
+      pane_.setBatch(true);
+      if(labelLayer_ == null) {
+        labelLayer_ = new Layer("Label Layer", psize);
+        add(labelLayer_);
+        labelLayer_.setPane(pane_);
+      } else {
+        labelLayer_.setSizeP(psize);
+      }
+      if(legendLayer_ == null) {
+        legendLayer_ = new Layer("Legend Layer", psize);
+        add(legendLayer_);
+        legendLayer_.setPane(pane_);
+      } else {
+        legendLayer_.setSizeP(psize);
+      }
+
+      this.setBorder(pHolder_.getBorder());
+
+      invalidate();
+      try {
+        updateLabels();
+        updateLegends();
+        updateDataGroups();
+      } catch (ChildNotFoundException e) {
+       e.printStackTrace();
+      }
+      pane_.setBatch(batch);
+    }
+  }
+
+  private void updateLabels() throws ChildNotFoundException {
+    Iterator lbIter = pHolder_.labelIterator();
+// remove deleted labels from layer
+    // note cant remove from an Iterator!
+    LayerChild[] children = labelLayer_.getChildren();
+    for(int i=0; i < children.length; i++) {
+      LayerChild child = children[i];
+      if(!pHolder_.hasLabel(child.getId())) {
+        labelLayer_.removeChild(child);
+      }
+    }
+// add or update labels to layer
+    while(lbIter.hasNext()) {
+      SGLabel sgl = null;
+      Label label = (Label)lbIter.next();
+      LayerChild child = labelLayer_.findChild(label.getId());
+
+      Point2D.Double loc = label.getLocationP();
+      Rectangle2D.Double bnds = label.getBoundsP();
+      double hgt;
+      if(label.getOrientation() == SGLabel.HORIZONTAL) {
+        hgt = label.getHeightP();
+        switch(label.getJustification()) {
+          case SGLabel.LEFT:
+            break;
+          case SGLabel.CENTER:
+            loc.x = loc.x + bnds.getWidth()*0.5;
+            break;
+          case SGLabel.RIGHT:
+            loc.x = loc.x + bnds.getWidth();
+            break;
+        }
+      } else {
+        hgt = label.getWidthP();
+        loc.x += bnds.getWidth();
+        switch(label.getJustification()) {
+          case SGLabel.LEFT:
+            break;
+          case SGLabel.CENTER:
+            loc.y = loc.y + bnds.getHeight()*0.5;
+            break;
+          case SGLabel.RIGHT:
+            loc.y = loc.y + bnds.getHeight();
+            break;
+        }
+      }
+      if(child == null) {
+        sgl = new SGLabel(label.getId(),
+                          label.getText(),
+                          hgt,
+                          loc,
+                          SGLabel.BOTTOM,
+                          label.getJustification());
+        sgl.setVisible(label.isVisible());
+        sgl.setSelectable(label.isSelectable());
+        sgl.setOrientation(label.getOrientation());
+        sgl.setColor(label.getColor());
+        sgl.setFont(label.getFont());
+        labelLayer_.addChild(sgl);
+        label.setInstantiated(true);
+      } else {
+        sgl = (SGLabel)child;
+        sgl.setText(label.getText());
+        sgl.setHeightP(hgt);
+        sgl.setLocationP(loc);
+        sgl.setHAlign(label.getJustification());
+        sgl.setVisible(label.isVisible());
+        sgl.setSelectable(label.isSelectable());
+        sgl.setOrientation(label.getOrientation());
+        sgl.setColor(label.getColor());
+        sgl.setFont(label.getFont());
+      }
+    }
+  }
+
+  private void updateLegends() {
+    Iterator lgIter = pHolder_.legendIterator();
+    while(lgIter.hasNext()) {
+      DataKey key = null;
+      Legend legend = (Legend)lgIter.next();
+      LayerChild child = legendLayer_.findChild(legend.getId());
+      Rectangle2D.Double boundsP = legend.getBoundsP();
+      if(child == null) {
+        switch(legend.getType()) {
+          case Legend.LINE:
+            key = new LineKey(legend.getLocationP(),
+                              LineKey.TOP, LineKey.LEFT);
+            break;
+          case Legend.COLOR:
+            key = new ColorKey(legend.getLocationP(),
+                               new Dimension2D(boundsP.width, boundsP.height),
+                               ColorKey.TOP, ColorKey.LEFT);
+            break;
+          case Legend.VECTOR:
+            key = new VectorKey(legend.getLocationP(),
+                                VectorKey.TOP, VectorKey.LEFT);
+            break;
+          case Legend.POINT:
+            key = new PointCollectionKey(legend.getLocationP(),
+                PointCollectionKey.TOP, PointCollectionKey.LEFT);
+            break;
+        }
+        key.setId(legend.getId());
+        legendLayer_.addChild(key);
+        legend.setInstantiated(true);
+      } else {
+        key = (DataKey)child;
+        key.setLocationP(legend.getLocationP());
+//        key.setBoundsP(legend.getBoundsP());
+      }
+      if(legend.isColor()) {
+        ColorKey ckey = (ColorKey)key;
+        ckey.setSizeP(new Dimension2D(boundsP.width, boundsP.height));
+        Ruler scale = ckey.getRuler();
+        scale.setLabelColor(legend.getScaleColor());
+        scale.setLineColor(legend.getScaleColor());
+        scale.setLabelFont(legend.getScaleLabelFont());
+        scale.setLabelHeightP(legend.getScaleLabelHeightP());
+        scale.setLabelInterval(legend.getScaleLabelInterval());
+        scale.setNumberSmallTics(legend.getScaleNumberSmallTics());
+        scale.setLargeTicHeightP(legend.getScaleLargeTicHeightP());
+        scale.setSmallTicHeightP(legend.getScaleSmallTicHeightP());
+        scale.setSignificantDigits(legend.getScaleSignificantDigits());
+        scale.setLabelFormat(legend.getScaleLabelFormat());
+        scale.setVisible(legend.isScaleVisible());
+        if(boundsP.width >= boundsP.height) {
+          ckey.setOrientation(ColorKey.HORIZONTAL);
+        } else {
+          ckey.setOrientation(ColorKey.VERTICAL);
+        }
+      }
+      key.setBorderStyle(legend.getBorderStyle());
+      key.setColumns(legend.getColumns());
+      key.setLineLengthP(legend.getLineLength());
+      key.setVisible(legend.isVisible());
+    }
+  }
+
+  private void updateDataGroups() {
+    float dpi = pHolder_.getPanelModel().getDpi();
+    setBounds(pHolder_.getBounds());
+    double width = getBounds().width/dpi;
+    double height = getBounds().height/dpi;
+    Dimension2D psize = new Dimension2D(width, height);
+
+    Iterator dgIter = pHolder_.dataGroupIterator();
+    // remove delete DataGroups from panel/pane
+    Component[] comps = getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        Layer ly = (Layer)comps[i];
+        if(ly != labelLayer_ && ly != legendLayer_) {
+          if(!pHolder_.hasDataGroup(ly.getId())) {
+            this.remove(ly);
+          }
+        }
+      }
+    }
+    // create/update DataGroup layers
+    while(dgIter.hasNext()) {
+      DataGroup ag = (DataGroup)dgIter.next();
+      // find DataGroupLayer
+      DataGroupLayer dgl = findDataGroupLayer(ag.getId());
+      if(dgl == null) {
+        dgl = new DataGroupLayer(this, ag);
+        add(dgl);
+        dgl.setSizeP(psize);
+        ag.setInstantiated(true);
+        dataGroupLayerList_.put(dgl.getId(), dgl);
+     } else {
+        dgl.update();
+      }
+    }
+  }
+
+  /**
+   * Find object associated with a MOUSE_DOWN event. The getObjectAt method
+   * scans through all the objects associated with the Panel to find one
+   * whose bounding box contains the mouse location.
+   *
+   * This method should not be called by a user.
+   *
+   * @param x mouse coordinate
+   * @param y mouse coordinate
+   * @param check if true requires that object isSelectable
+   * @return object at location
+   **/
+  public Object getObjectAt(int x, int y, boolean check) {
+    Object obj = null;
+
+    obj = labelLayer_.getObjectAt(x, y, check);
+    if(obj != null) return obj;
+    obj = legendLayer_.getObjectAt(x, y, check);
+    if(obj != null) return obj;
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      obj = ((DataGroupLayer)iter.next()).getObjectAt(x, y, check);
+      if(obj != null) return obj;
+    }
+    return obj;
+  }
+
+  /**
+   * Zoom <code>DataGroupLayer</code>s in <code>Panel</code>.
+   * Zoom to <code>Rectangle</code> if zoom operation started within bounds.
+   * @param start start point
+   * @param rect zoom rectangle
+   */
+  void zoomTo(Point start, Rectangle rect) {
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      ((DataGroupLayer)iter.next()).zoomTo(start, rect);
+    }
+  }
+
+  /**
+   * Reset the zoom for <code>DataGroupLayer</code>s in this <code>Panel</code>
+   * if it contains the point.
+   * @param x x device coordinate
+   * @param y y device coordinate
+   */
+  void resetZoom(int x, int y) {
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      ((DataGroupLayer)iter.next()).resetZoom(x, y);
+    }
+  }
+
+  /**
+   * Reset the zoom for all <code>DataGroupLayer</code>s in this <code>Panel</code>.
+   */
+  public void resetZoom() {
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      ((DataGroupLayer)iter.next()).resetZoom();
+    }
+  }
+  /**
+   * Set clipping for <code>DataGroupLayer</code>s in this <code>Panel</code>.
+   * @param clip if true clip data to bounds.
+   */
+  public void setClipping(boolean clip) {
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      ((DataGroupLayer)iter.next()).setClipping(clip);
+    }
+  }
+
+  /**
+   * Does this <code>Panel</code> contain this Layer?
+   * @param id layer identification
+   * @return true, if Layer is in Panel
+   */
+  public boolean hasLayer(String id) {
+    if(id.equals(labelLayer_.getId())) return true;
+    if(id.equals(legendLayer_.getId())) return true;
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      if(id.equals(((DataGroupLayer)iter.next()).getId())) return true;
+    }
+    return false;
+  }
+
+  /**
+   * Get <code>Layer</code> from this <code>Panel</code>.  Returns <code>null</code>
+   * if Layer is not found.
+   * @param id Layer identifier
+   * @return Layer
+   */
+  public Layer getLayer(String id) {
+    if(id.equals(labelLayer_.getId())) return labelLayer_;
+    if(id.equals(legendLayer_.getId())) return legendLayer_;
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      DataGroupLayer dgl = (DataGroupLayer)iter.next();
+      if(id.equals(dgl.getId())) return dgl;
+    }
+    return null;
+  }
+
+  /**
+   * Checks to see if a data id matches that data attached to the
+   * <code>Graph</code>.
+   * @param id data identifier
+   * @return true if data is in Panel
+   */
+  public boolean isDataInPanel(String id) {
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      DataGroupLayer dgl = (DataGroupLayer)iter.next();
+      if(dgl.isDataInLayer(id)) return true;
+    }
+    return false;
+  }
+
+  /**
+   * Get <code>Layer</code> from this <code>Panel</code>.  Returns <code>null</code>
+   * if Layer is not found.
+   * @param id SGTData identifier
+   * @return Layer
+   */
+  public Layer getLayerFromDataId(String id) {
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      DataGroupLayer dgl = (DataGroupLayer)iter.next();
+      if(dgl.isDataInLayer(id)) return dgl;
+    }
+    return null;
+  }
+
+  /**
+   * Find objects associated with a MOUSE_DOWN event. The getObjecstAt method
+   * scans through all the objects associated with the Panel to find those
+   * whose bounding box contains the mouse location.
+   *
+   * This method should not be called by a user.
+   *
+   * @param x mouse coordinate
+   * @param y mouse coordinate
+   * @param check if selectable
+   * @return object array
+   */
+  public Object[] getObjectsAt(int x, int y, boolean check) {
+    Object[] obj = null;
+    Vector obList = new Vector();
+
+    obj = labelLayer_.getObjectsAt(x, y, check);
+    if(obj != null) {
+      for(int i=0; i < obj.length; i++) {
+        obList.addElement(obj[i]);
+      }
+    }
+    obj = legendLayer_.getObjectsAt(x, y, check);
+    if(obj != null) {
+      for(int i=0; i < obj.length; i++) {
+        obList.addElement(obj[i]);
+      }
+    }
+    Iterator iter = dataGroupLayerList_.values().iterator();
+    while(iter.hasNext()) {
+      obj = ((DataGroupLayer)iter.next()).getObjectsAt(x, y, check);
+      if(obj != null) {
+        for(int i=0; i < obj.length; i++) {
+          obList.addElement(obj[i]);
+        }
+      }
+    }
+
+    return obList.toArray();
+  }
+
+  /**
+   * Find <code>DataGroupLayer</code> in <code>Panel</code>.
+   * @param id DataGroupLayer identifier
+   * @return DataGroupLayer
+   */
+  public DataGroupLayer findDataGroupLayer(String id) {
+    return (DataGroupLayer)dataGroupLayerList_.get(id);
+  }
+
+  /**
+   * Get the <code>JPane</code> the <code>Panel</code> is associated
+   * with.
+   *
+   * @return Refence to the <code>Pane</code>
+   **/
+  public JPane getPane() {
+    return pane_;
+  }
+
+  /**
+   * Set the <code>Pane</code> the <code>Panel</code> is associated with.
+   * This method is called by <code>Pane</code> when the
+   * <code>Pane.add</code> method is exectued.
+   *
+   * @param pane The <code>Pane</code>
+   **/
+  public void setPane(AbstractPane pane) {
+    pane_ = (JPane)pane;
+    update();
+  }
+
+  public void draw(Graphics g)  throws PaneNotFoundException {
+    if(!pHolder_.isUsePageBackground()) {
+      Color saved = g.getColor();
+      Rectangle r = pHolder_.getBounds();
+      g.setColor(pHolder_.getBackground());
+      g.fillRect(r.x, r.y, r.width, r.height);
+      g.setColor(saved);
+    }
+    Component[] comps = this.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof LayerControl) {
+        ((LayerControl)comps[i]).draw(g);
+      }
+    }
+  }
+
+  public void drawDraggableItems(Graphics g) throws PaneNotFoundException {
+    Component[] comps = this.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof LayerControl) {
+        ((LayerControl)comps[i]).drawDraggableItems(g);
+      }
+    }
+  }
+
+  /**
+   * Add data to this <code>Panel</code> and <code>DataGroup</code>.  legend can
+   * be <code>null</code>.
+   * @param data SGTData to be added
+   * @param attr Attribute
+   * @param dataGroup DataGroup to add data to
+   * @param legend Lenged for data
+   * @throws DataTargetMismatchException
+   */
+  public void addData(SGTData data, Attribute attr,
+                      DataGroup dataGroup, Legend legend)
+      throws DataTargetMismatchException {
+    DataGroupLayer agLayer = findDataGroupLayer(dataGroup.getId());
+    DataKey key = null;
+    if(legend != null) key = (DataKey)legendLayer_.findChild(legend.getId());
+
+    agLayer.addData(data, attr, key);
+  }
+
+  /**
+   * Get the identifier for the <code>Panel</code>
+   * @return identifier/name
+   */
+  public String getId() {
+    return getName();
+  }
+
+  /**
+   * Get a <code>String</code> representation of the
+   * <code>Layer</code>.
+   *
+   * @return <code>String</code> representation
+   */
+  public String toString() {
+    String name = getClass().getName();
+    return name.substring(name.lastIndexOf(".")+1) + ": " + pHolder_.getId();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolder.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolder.java
new file mode 100755
index 0000000..8c87791
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolder.java
@@ -0,0 +1,535 @@
+/*
+ * $Id: PanelHolder.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+
+import java.awt.Rectangle;
+import java.awt.Color;
+import javax.swing.event.*;
+import javax.swing.border.Border;
+import javax.swing.border.LineBorder;
+import java.util.*;
+import java.io.*;
+import java.beans.*;
+
+/**
+ * Object to hold all the objects necessary to describe a <code>Panel</code>.
+ * Associated objects include <code>Label</code>, <code>DataGroup</code>, and
+ * <code>Legend</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ * @see Label
+ * @see Panel
+ * @see PanelModel PanelModel for UML diagram
+ * @see DataGroup
+ * @see Legend
+ **/
+public class PanelHolder implements ChangeListener, Serializable {
+  private String id = "";
+  private Rectangle bounds = new Rectangle(0, 0, 100, 50);
+  /** @link aggregation
+   * @supplierCardinality *
+   * @label labels */
+  /*#Label lnkLabel; */
+  private Map labels_ = new HashMap(5);
+  /** @link aggregation
+   * @supplierCardinality 1..*
+   * @label dataGroups */
+  /*#DataGroup lnkDataGroup; */
+  private Map dataGroups_ = new HashMap(2);
+  /** @link aggregation
+   * @supplierCardinality *
+   * @label legends */
+  /*#Legend lnkLegend; */
+  private Map legends_ = new HashMap(1);
+
+  /**
+   * @label pModel
+   */
+  transient private PanelModel pModel_ = null;
+  transient private ChangeEvent changeEvent_ = new ChangeEvent(this);
+  transient private Vector changeListeners;
+  private boolean visible = true;
+  transient private boolean instantiated = false;
+  private Border border = new LineBorder(Color.gray, 2);
+  private Color background = Color.white;
+  private boolean usePageBackground = true;
+
+  static {
+    try {
+      BeanInfo info = Introspector.getBeanInfo(PanelHolder.class);
+      PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+      for(int i=0; i < descriptors.length; i++) {
+        PropertyDescriptor pd = descriptors[i];
+        if(pd.getName().equals("instantiated")) {
+          pd.setValue("transient", Boolean.TRUE);
+        } else if(pd.getName().equals("panelModel")) {
+          pd.setValue("transient", Boolean.TRUE);
+        }
+      }
+    } catch (IntrospectionException ie) {
+     ie.printStackTrace();
+    }
+  }
+  /**
+   * Default constructor.  Sets <code>PanelHolder</code> identifier and
+   * <code>PanelModel</code> parent to <code>null</code>.
+   */
+  public PanelHolder() {
+    this(null, null);
+  }
+  /**
+   * <code>PanelHolder</code> constructor.
+   * @param id PanelHolder identifier
+   * @param pModel PanelModel parent
+   */
+  public PanelHolder(String id, PanelModel pModel) {
+    this.id = id;
+    pModel_ = pModel;
+  }
+  /**
+   * <code>PanelHolder</code> constructor.  This constructor has arguments to
+   * pass <code>Map</code>s of <code>Label</code>, <code>DataGroup</code>, and
+   * <code>Legend</code> objects.  The <code>Map</code> key is the objects identifier.
+   * @param id PanelHolder identifier
+   * @param pModel PanelModel parent
+   * @param bounds bounds
+   * @param labels Map containing Labels
+   * @param dataGroups Map containing DataGroups
+   * @param legends Map contiaining Legends
+   */
+  public PanelHolder(String id, PanelModel pModel,
+                     Rectangle bounds,
+                     Map labels,
+                     Map dataGroups, Map legends) {
+    this.id = id;
+    pModel_ = pModel;
+    this.bounds = bounds;
+    if(labels != null) {
+      labels_ = new HashMap(labels);
+    }
+    if(dataGroups != null) {
+      dataGroups_ = new HashMap(dataGroups);
+    }
+    if(legends != null) {
+      legends_ = new HashMap(legends);
+    }
+  }
+  /**
+   * Set the <code>PanelModel</code> parent.
+   * @param pModel PanelModel
+   */
+  public void setPanelModel(PanelModel pModel) {
+    if(pModel_ != null) removeChangeListener(pModel_);
+    pModel_ = pModel;
+    addChangeListener(pModel_);
+  }
+  /**
+   * Get the <code>PanelModel</code>.
+   * @return PanelModel
+   */
+  public PanelModel getPanelModel() {
+    return pModel_;
+  }
+  /**
+   * Add <code>Label</code> to the <code>PanelHolder</code>.
+   * @param label Label
+   */
+  public void addLabel(Label label) {
+    label.addChangeListener(this);
+    label.setPanelHolder(this);
+    labels_.put(label.getId(), label);
+    fireStateChanged();
+  }
+  /**
+   * Remove <code>Label</code> from the <code>PanelHolder</code>.
+   * @param label Label
+   */
+  public void removeLabel(Label label) {
+    label.removeAllChangeListeners();
+    labels_.remove(label.getId());
+    fireStateChanged();
+  }
+  /**
+   * Add <code>DataGroup</code> to the <code>PanelHolder</code>.
+   * @param dataGroup DataGroup
+   */
+  public void addDataGroup(DataGroup dataGroup) {
+    dataGroup.addChangeListener(this);
+    dataGroups_.put(dataGroup.getId(), dataGroup);
+    fireStateChanged();
+  }
+  /**
+   * Remove <code>DataGroup</code> from the <code>PanelHolder</code>.
+   * @param dataGroup DataGroup
+   */
+  public void removeDataGroup(DataGroup dataGroup) {
+    dataGroup.removeAllChangeListeners();
+    dataGroup.getXAxisHolder().removeAllChangeListeners();
+    dataGroup.getYAxisHolder().removeAllChangeListeners();
+    dataGroups_.remove(dataGroup.getId());
+    fireStateChanged();
+  }
+  /**
+   * Add <code>Legend</code> to the <code>PanelHolder</code>.
+   * @param legend Legend
+   */
+  public void addLegend(Legend legend) {
+    legend.addChangeListener(this);
+    legend.setPanelHolder(this);
+    legends_.put(legend.getId(), legend);
+    fireStateChanged();
+  }
+  /**
+   * Remove <code>Legend</code> from the <code>PanelHolder</code>.
+   * @param legend Legend
+   */
+  public void removeLegend(Legend legend) {
+    legend.removeAllChangeListeners();
+    legends_.remove(legend.getId());
+    fireStateChanged();
+  }
+  /**
+   * Set <code>PanelHolder</code> identifier.
+   * @param id identifier
+   */
+  public void setId(String id) {
+    String old = this.id;
+    this.id = id;
+    if(old == null || !old.equals(this.id)) fireStateChanged();
+  }
+  /**
+   * Get <code>PanelHolder</code> identifier
+   * @return identifier
+   */
+  public String getId() {
+    return id;
+  }
+  /**
+   * Get number of <code>Label</code> objects in <code>Map</code>.
+   * @return number of Labels
+   */
+  public int getLabelSize() {
+    return labels_.size();
+  }
+  /**
+   * Get number of <code>DataGroup</code> objects in <code>Map</code>.
+   * @return number of DataGroups
+   */
+  public int getDataGroupSize() {
+    return dataGroups_.size();
+  }
+  /**
+   * Get number of <code>Legend</code> objects in <code>Map</code>.
+   * @return number of Legends
+   */
+  public int getLegendSize() {
+    return legends_.size();
+  }
+  /**
+   * Get an <code>Iterator</code> of <code>Label</code> objects.
+   * @return Iterator
+   */
+  public Iterator labelIterator() {
+    return labels_.values().iterator();
+  }
+  /**
+   * Get an <code>Iterator</code> of <code>DataGroup</code> objects.
+   * @return Iterator
+   */
+  public Iterator dataGroupIterator() {
+    return dataGroups_.values().iterator();
+  }
+  /**
+   * Get an <code>Iterator</code> of <code>Legend</code> objects.
+   * @return Iterator
+   */
+  public Iterator legendIterator() {
+    return legends_.values().iterator();
+  }
+  /**
+   * Set bounds of <code>Panel</code>.
+   * @param bounds bounds
+   */
+  public void setBounds(Rectangle bounds) {
+    Rectangle old = this.bounds;
+    this.bounds = bounds;
+    fireStateChanged();
+  }
+  /**
+   * Get bounds of <code>Panel</code>.
+   * @return bounds
+   */
+  public Rectangle getBounds() {
+    return bounds;
+    /** @todo bounds isn't  cloned should be see note */
+//    return (Rectangle)bounds.clone();  // the clone didn't work with XMLEncoder for some reason
+  }
+  /**
+   * Remove all <code>ChangeListener</code>s.
+   */
+  public void removeAllChangeListeners() {
+    changeListeners = null;
+  }
+  /**
+   * <code>ChangeListner</code> callback.
+   * @param e ChangeEvent
+   */
+  public void stateChanged(ChangeEvent e) {
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(e);
+      }
+    }
+  }
+  /**
+   * Remove changelistener.
+   * @param l changelistener
+   */
+  public synchronized void removeChangeListener(ChangeListener l) {
+    if (changeListeners != null && changeListeners.contains(l)) {
+      Vector v = (Vector) changeListeners.clone();
+      v.removeElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Add changelistener
+   * @param l changelistener
+   */
+  public synchronized void addChangeListener(ChangeListener l) {
+    Vector v = changeListeners == null ? new Vector(2) : (Vector) changeListeners.clone();
+    if (!v.contains(l)) {
+      v.addElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Remove all <code>ChangeListener</code>s that implement the
+   * <code>DesignListener</code> interface.
+   *
+   * @see DesignListener
+   */
+  public synchronized void removeDesignChangeListeners() {
+    if(changeListeners != null) {
+      Vector v = (Vector) changeListeners.clone();
+      Iterator iter = v.iterator();
+      while(iter.hasNext()) {
+        Object obj = iter.next();
+        if(obj instanceof DesignListener) changeListeners.removeElement(obj);
+      }
+    }
+  }
+
+  protected void fireStateChanged() {
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(changeEvent_);
+      }
+    }
+  }
+  /**
+   * Set <code>Panel</code> visible.
+   * @param visible true if visible
+   */
+  public void setVisible(boolean visible) {
+    boolean saved = this.visible;
+    this.visible = visible;
+    if(saved != this.visible) fireStateChanged();
+  }
+  /**
+   * Is <code>Panel</code> visible?
+   * @return true, if Panel is visible
+   */
+  public boolean isVisible() {
+    return visible;
+  }
+  /**
+   * Set instantiated.  Once associated <code>Panel</code> object has been created
+   * this property is set true.  Used internally.
+   * @param instantiated true if instantiated
+   */
+  public void setInstantiated(boolean instantiated) {
+    this.instantiated = instantiated;
+  }
+  /**
+    * Is panel instantiated?
+    * @return true, if Panel instantiated
+    */
+   public boolean isInstantiated() {
+    return instantiated;
+  }
+  /**
+   * Find a <code>DataGroup</code> by identifier.
+   * @param id identifier
+   * @return DataGroup
+   */
+  public DataGroup findDataGroup(String id) {
+    return (DataGroup)dataGroups_.get(id);
+  }
+  /**
+   * Find <code>Label</code> by identifier.
+   * @param id identifier
+   * @return Label
+   */
+  public Label findLabel(String id) {
+    return (Label)labels_.get(id);
+  }
+  /**
+   * Find <code>Legend</code> by identifier.
+   * @param id identifier
+   * @return Legend
+   */
+  public Legend findLegend(String id) {
+    return (Legend)legends_.get(id);
+  }
+  /**
+   * Does <code>PanelHolder</code> contain <code>DataGroup</code>?
+   * @param id DataGroup identifier
+   * @return true, if DataGroup exists
+   */
+  public boolean hasDataGroup(String id) {
+    return dataGroups_.containsKey(id);
+  }
+  /**
+   * Does <code>PanelHolder</code> contain <code>Label</code>?
+   * @param id Label identifier
+   * @return Label
+   */
+  public boolean hasLabel(String id) {
+    return labels_.containsKey(id);
+  }
+  /**
+   * Does <code>PanelHolder</code> contain <code>Legend</code>?
+   * @param id Legend identifier
+   * @return Legend
+   */
+  public boolean hasLegend(String id) {
+    return legends_.containsKey(id);
+  }
+  /**
+   * Return <code>Border</code> for <code>Panel</code>.
+   * @return Border
+   */
+  public Border getBorder() {
+    return border;
+  }
+  /**
+   * Set <code>Border</code> for <code>Panel</code>.  Default = LineBorder(gray, 2)
+   * @param border Border
+   */
+  public void setBorder(Border border) {
+    Border saved = this.border;
+    this.border = border;
+    if(saved == null || !saved.equals(this.border)) fireStateChanged();
+  }
+  /**
+   * Get <code>Map</code> of </code>Label</code>s.
+   * @return Map
+   */
+  public Map getLabels() {
+    return labels_;
+  }
+  /**
+   * Set <code>Map</code> of </code>Label</code>s.  Key in <code>Map</code> contains
+   * <code>Label</code> identifier.
+   * @param labels Label Map
+   */
+  public void setLabels(Map labels) {
+    labels_ = labels;
+    Iterator iter = labelIterator();
+    while(iter.hasNext()) {
+      ((Label)iter.next()).addChangeListener(this);
+    }
+    fireStateChanged();
+  }
+  /**
+   * Get <code>Map</code> containing <code>Legend</code>s.
+   * @return Map
+   */
+  public Map getLegends() {
+    return legends_;
+  }
+  /**
+   * Set <code>Map</code> of </code>Legend</code>s.  Key in <code>Map</code> contains
+   * <code>Legend</code> identifier.
+   * @param legends Legend Map
+   */
+  public void setLegends(Map legends) {
+    legends_ = legends;
+    Iterator iter = legendIterator();
+    while(iter.hasNext()) {
+      ((Legend)iter.next()).addChangeListener(this);
+    }
+    fireStateChanged();
+  }
+  /**
+   * Get <code>Map</code> containing <code>DataGroup</code>s.
+   * @return Map
+   */
+  public Map getDataGroups() {
+    return dataGroups_;
+  }
+  /**
+   * Set <code>Map</code> of </code>DataGroup</code>s.  Key in <code>Map</code> contains
+   * <code>DataGroup</code> identifier.
+   * @param dataGroups DataGroup Map
+   */
+  public void setDataGroups(Map dataGroups) {
+    dataGroups_ = dataGroups;
+    Iterator iter = dataGroupIterator();
+    while(iter.hasNext()) {
+      ((DataGroup)iter.next()).addChangeListener(this);
+    }
+    fireStateChanged();
+  }
+  /**
+   * Get background color.  Will use the page background if usePageBackground property
+   * is true.
+   * @return color
+   */
+  public Color getBackground() {
+    return background;
+  }
+  /**
+   * Set the <code>Panel</code> background color.
+   * @param background color
+   */
+  public void setBackground(Color background) {
+    Color saved = this.background;
+    this.background = background;
+    if(!saved.equals(this.background)) fireStateChanged();
+  }
+  /**
+   * Use the page background color?
+   * @return true if using page background color
+   */
+  public boolean isUsePageBackground() {
+    return usePageBackground;
+  }
+  /**
+   * Set the <code>Panel</code> to use the <code>Page</code> background color.
+   * @param pageBackground true to use page background color
+   */
+  public void setUsePageBackground(boolean pageBackground) {
+    boolean saved = this.usePageBackground;
+    this.usePageBackground = pageBackground;
+    if(saved != this.usePageBackground) fireStateChanged();
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolderDragBox.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolderDragBox.java
new file mode 100755
index 0000000..6849dea
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolderDragBox.java
@@ -0,0 +1,215 @@
+/*
+ * $Id: PanelHolderDragBox.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.Color;
+import java.awt.Insets;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class PanelHolderDragBox extends DragBox implements ChangeListener {
+  private List dragBox_ = new Vector();
+  private boolean ignoreStateChange_ = false;
+
+  public PanelHolderDragBox(PanelHolder ph) {
+    super(ph);
+//    ph.setPanelDragBox(this);
+    ignoreStateChange_ = true;
+    pHolder_.addChangeListener(this);
+    Iterator iter = pHolder_.dataGroupIterator();
+    while(iter.hasNext()) {
+      DataGroup dg = (DataGroup)iter.next();
+      DataGroupDragBox agdb = new DataGroupDragBox(dg, pHolder_);
+      AxisHolderDragBox xAxdb = new AxisHolderDragBox(dg.getXAxisHolder(), dg, pHolder_);
+      AxisHolderDragBox yAxdb = new AxisHolderDragBox(dg.getYAxisHolder(), dg, pHolder_);
+      dragBox_.add(xAxdb);
+      dragBox_.add(yAxdb);
+      dragBox_.add(agdb);
+    }
+    iter = pHolder_.labelIterator();
+    while(iter.hasNext()) {
+      LabelDragBox ldb = new LabelDragBox((Label)iter.next(),  pHolder_);
+      dragBox_.add(ldb);
+    }
+    iter = pHolder_.legendIterator();
+    while(iter.hasNext()) {
+      LegendDragBox lgdb = new LegendDragBox((Legend)iter.next(), pHolder_);
+      dragBox_.add(lgdb);
+    }
+
+    for(int i=0; i < handles_.length;  i++) {
+      handles_[i] = new Rectangle(0,0,0,0);
+    }
+    ignoreStateChange_ = false;
+    computeHandles();
+  }
+
+  public PanelHolder getPanelHolder() {
+    return pHolder_;
+  }
+
+  public DragBox[] getDragBoxArray() {
+    DragBox[] dba = new DragBox[1];
+    return (DragBox[])dragBox_.toArray(dba);
+  }
+
+  public Iterator getDragBoxIterator() {
+    return dragBox_.iterator();
+  }
+
+  public void setSelected(boolean sel) {
+    super.setSelected(sel);
+    if(!selected_) {
+      Iterator iter = dragBox_.iterator();
+      while(iter.hasNext()) {
+        ((DragBox)iter.next()).setSelected(sel);
+      }
+    }
+  }
+
+  public void update(String message) {
+//    if(Page.DEBUG) System.out.println("PanelDragBox.update(" + message + ")");
+    computeHandles();
+    Iterator iter = dragBox_.iterator();
+    while(iter.hasNext()) {
+      ((DragBox)iter.next()).update(message);
+    }
+  }
+
+  public void draw(Graphics g) {
+    Color saved = g.getColor();
+    Rectangle bounds = pHolder_.getBounds();
+    if(!pHolder_.isUsePageBackground()) {
+      g.setColor(pHolder_.getBackground());
+      g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
+    }
+    g.setColor(Color.darkGray);
+    g.drawString(pHolder_.getId(), bounds.x + 10, bounds.y + 12);
+    g.drawString("["+bounds.width+"x"+bounds.height+"]",
+                 bounds.x + 10, bounds.y + 22);
+    g.setColor(color_);
+    if(pHolder_.isVisible()) g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1);
+    if(selected_) {
+      for(int i=0; i < handles_.length; i++) {
+        Rectangle r = handles_[i];
+        g.fillRect(r.x, r.y, r.width-1, r.height-1);
+      }
+    }
+
+    if(pHolder_.isVisible()) {
+      Iterator iter = dragBox_.iterator();
+      while(iter.hasNext()) {
+        ((DragBox)iter.next()).draw(g);
+      }
+    }
+
+    g.setColor(saved);
+  }
+
+  public String getId() {
+    return pHolder_.getId();
+  }
+
+  public void setId(String id) {
+    pHolder_.setId(id);
+  }
+
+  public void setBounds(Rectangle bounds) {
+    ignoreStateChange_ = true;
+    pHolder_.setBounds(bounds);
+    update("PanelDragBox.setBounds()");
+    ignoreStateChange_ = false;
+  }
+
+  public Rectangle getBounds() {
+    return pHolder_.getBounds();
+  }
+
+  public void setLocation(Point pt) {
+    setLocation(pt.x, pt.y);
+  }
+
+  public void setLocation(int x, int y) {
+    Rectangle bounds = pHolder_.getBounds();
+    bounds.x = x;
+    bounds.y = y;
+    ignoreStateChange_ = true;
+    pHolder_.setBounds(bounds);
+    update("PanelDragBox.setLocation()");
+    ignoreStateChange_ = false;
+  }
+
+  public Point getLocation() {
+    Rectangle bounds = pHolder_.getBounds();
+    return new Point(bounds.x, bounds.y);
+  }
+
+  public void addDragBox(DataGroup ag) {
+    DataGroupDragBox agdb = new DataGroupDragBox(ag, pHolder_);
+    AxisHolderDragBox xAxdb = new AxisHolderDragBox(ag.getXAxisHolder(), ag, pHolder_);
+    AxisHolderDragBox yAxdb = new AxisHolderDragBox(ag.getYAxisHolder(), ag, pHolder_);
+    agdb.setAxisHolderDB(xAxdb, yAxdb);
+    dragBox_.add(xAxdb);
+    dragBox_.add(yAxdb);
+    dragBox_.add(agdb);
+  }
+
+  public void addDragBox(Legend legend) {
+    LegendDragBox ldb = new LegendDragBox(legend, pHolder_);
+    dragBox_.add(ldb);
+  }
+
+  public void addDragBox(Label label) {
+    LabelDragBox lbdb = new LabelDragBox(label, pHolder_);
+    dragBox_.add(lbdb);
+  }
+
+  public void removeDragBox(DataGroupDragBox ag) {
+    dragBox_.remove(ag.getXAxisHolderDB());
+    dragBox_.remove(ag.getYAxisHolderDB());
+    dragBox_.remove(ag);
+    update("PanelDragBox.removeDragBox(DataGroupDragBox)");
+  }
+
+  public void removeDragBox(LegendDragBox legend) {
+    dragBox_.remove(legend);
+    update("PanelDragBox.removeDragBox(LegendDragBox)");
+  }
+
+  public void removeDragBox(LabelDragBox label) {
+    dragBox_.remove(label);
+    update("PanelDragBox.removeDragBox(LabelDragBox)");
+  }
+
+  public void stateChanged(ChangeEvent e) {
+    if(ignoreStateChange_) return;
+    update("PanelDragBox.stateChanged");
+/*    System.out.println("PanelDragBox.stateChanged(" +
+                       e.getSource().getClass().getName() + ")"); */
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolderPropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolderPropertyPanel.java
new file mode 100755
index 0000000..c48156a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelHolderPropertyPanel.java
@@ -0,0 +1,185 @@
+/*
+ * $Id: PanelHolderPropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import gov.noaa.pmel.sgt.swing.prop.ColorDialog;
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class PanelHolderPropertyPanel extends PropertyPanel implements ActionListener, ChangeListener, FocusListener {
+  private boolean expert_ = false;
+  private PanelHolder pHolder_ = null;
+  private String[] pNames_ = {"Background", "Border", "Bounds", "Data Groups",
+    "Id", "Labels", "Legends", "Page Background", "Visible"};
+  private JComponent[] comps_ = new JComponent[pNames_.length];
+
+  public PanelHolderPropertyPanel(PanelHolder ph, boolean expert) {
+    super();
+    pHolder_ = ph;
+    pHolder_.addChangeListener(this);
+    expert_ = expert;
+    create();
+  }
+
+  public void setPanelHolder(PanelHolder ph, boolean expert) {
+    if(pHolder_ != null) pHolder_.removeChangeListener(this);
+    pHolder_ = ph;
+    pHolder_.addChangeListener(this);
+    expert_ = expert;
+    reset();
+  }
+
+  void create() {
+    int i = -1;
+    comps_[++i] = createColor(pHolder_.getBackground(), pNames_[i], this);
+    comps_[++i] = createBorder(pHolder_.getBorder(), pNames_[i], this);
+    Rectangle b = pHolder_.getBounds();
+    comps_[++i] = createLabel(b.x + ", " + b.y + ", " + b.width + ", " + b.height);
+    comps_[++i] = createLabel(pHolder_.getDataGroupSize());
+    comps_[++i] = createTextField(pHolder_.getId(), pNames_[i], this, !pHolder_.isInstantiated());
+    comps_[++i] = createLabel(pHolder_.getLabelSize());
+    comps_[++i] = createLabel(pHolder_.getLegendSize());
+    comps_[++i] = createCheckBox(pHolder_.isUsePageBackground(), pNames_[i], this);
+    comps_[++i] = createCheckBox(pHolder_.isVisible(), pNames_[i], this);
+    for(i=0; i < comps_.length; i++) {
+      addProperty(i+1, pNames_[i], comps_[i], false);
+    }
+    addProperty(comps_.length + 1, " ", new JLabel(" "), true);
+  }
+
+  void resetFields() {
+    for(int i=0; i < comps_.length; i++) {
+      if(comps_[i] instanceof JTextField) {
+        ((JTextField)comps_[i]).removeActionListener(this);
+        ((JTextField)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JCheckBox) {
+        ((JCheckBox)comps_[i]).removeActionListener(this);
+        ((JCheckBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JComboBox) {
+        ((JComboBox)comps_[i]).removeActionListener(this);
+        ((JComboBox)comps_[i]).removeFocusListener(this);
+      } else if(comps_[i] instanceof JButton) {
+        ((JButton)comps_[i]).removeActionListener(this);
+        ((JButton)comps_[i]).removeFocusListener(this);
+      }
+    }
+  }
+
+  void update() {
+    int i = -1;
+    updateColor((JButton)comps_[++i], pHolder_.getBackground());
+    updateBorder((JButton)comps_[++i], pHolder_.getBorder());
+    Rectangle b = pHolder_.getBounds();
+    ((JLabel)comps_[++i]).setText(b.x + ", " + b.y + ", " + b.width + ", " + b.height);
+    ((JLabel)comps_[++i]).setText(Integer.toString(pHolder_.getDataGroupSize()));
+    ((JTextField)comps_[++i]).setText(pHolder_.getId());
+    ((JLabel)comps_[++i]).setText(Integer.toString(pHolder_.getLabelSize()));
+    ((JLabel)comps_[++i]).setText(Integer.toString(pHolder_.getLegendSize()));
+    ((JCheckBox)comps_[++i]).setSelected(pHolder_.isUsePageBackground());
+    ((JCheckBox)comps_[++i]).setSelected(pHolder_.isVisible());
+  }
+
+  private void processEvent(Object obj, String command) {
+    if(command.equals("Border")) {
+      BorderDialog bd = new BorderDialog(null, "Select Border", true);
+      bd.setBorder(pHolder_.getBorder());
+      bd.setVisible(true);
+      pHolder_.setBorder(bd.getBorder());
+    } else if(command.equals("Id")) {
+      String oldId = pHolder_.getId();
+      pHolder_.getPanelModel().getPanelList().remove(oldId);
+      pHolder_.setId(((JTextField)obj).getText());
+      pHolder_.getPanelModel().getPanelList().put(pHolder_.getId(), pHolder_);
+    } else if(command.equals("Visible")) {
+      pHolder_.setVisible(((JCheckBox)obj).isSelected());
+    } else if(command.equals("Background")) {
+      ColorDialog cd = new ColorDialog(getFrame(), "Select Axis Color", true);
+      cd.setColor(pHolder_.getBackground());
+      cd.setVisible(true);
+      Color newcolor = cd.getColor();
+      if(newcolor != null) {
+        pHolder_.setBackground(newcolor);
+        updateColor((JButton)obj, newcolor);
+      }
+    } else if(command.equals("Page Background")) {
+      pHolder_.setUsePageBackground(((JCheckBox)obj).isSelected());
+    }
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    Object obj = e.getSource();
+    String command = e.getActionCommand();
+    processEvent(obj, command);
+  }
+  public void stateChanged(ChangeEvent e) {
+    update();
+  }
+  public void focusGained(FocusEvent e) {
+  }
+  public void focusLost(FocusEvent e) {
+    Object obj = e.getSource();
+    if(obj instanceof JTextField) {
+      JTextField tf = (JTextField)obj;
+      String name = tf.getName();
+      processEvent(obj, name);
+    }
+  }
+
+  private JButton createBorder (Border value,
+                                String action, ActionListener listen) {
+    JButton jb = new JButton(getBorderDescription(value));
+    jb.setActionCommand(action);
+    if(listen != null) jb.addActionListener(listen);
+    return jb;
+  }
+
+  private void updateBorder(JButton comp, Border value) {
+    comp.setText(getBorderDescription(value));
+  }
+
+  private String getBorderDescription(Border border) {
+    String description = "None";
+    if(border != null) {
+      if(border instanceof BevelBorder) {
+        description = "Beveled";
+      } else if(border instanceof EtchedBorder) {
+        description = "Etched";
+      } else if(border instanceof LineBorder) {
+        description = "Line";
+      } else if(border instanceof TitledBorder) {
+        description = "Titled";
+      }
+    }
+    return description;
+  }
+
+  public void setExpert(boolean expert) {
+    expert_ = expert;
+  }
+
+  public boolean isExpert() {
+    return expert_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModel.java
new file mode 100755
index 0000000..2334c68
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModel.java
@@ -0,0 +1,602 @@
+/*
+ * $Id: PanelModel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.Rectangle;
+import java.awt.Dimension;
+import java.awt.Color;
+import java.awt.Point;
+
+import java.util.List;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+
+import java.beans.*;
+
+import gov.noaa.pmel.sgt.LayerChild;
+import gov.noaa.pmel.sgt.AbstractPane;
+import java.io.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+
+/**
+ * A model that supports the <code>Panel</code> structure of a <code>Plot</code>.
+ * Information includes the <code>DataGroup</code>s and <code>LayerChild</code>ren that
+ * are included in a <code>Panel</code>.  A <code>Panel</code> consist of several
+ * <code>Layer</code>s, at least one for each <code>DataGroup</code>.
+ * <p>
+ * The layout of the <code>Panel</code>s will eventually be accomplished using the <code>SpringLayout</code>.
+ * This will provide a flexible and easy method to position the <code>Panel</code>s
+ * in arbitrary positions.  Currently the <code>Panel</code>s are positioned in
+ * absolution location.
+ * <p> Some classes have been omitted for display purposes.
+ * <P ALIGN="CENTER"><IMG SRC="images/PanelModelSimple.png" ALIGN="BOTTOM" BORDER="0">
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ * @stereotype bean
+ **/
+public class PanelModel implements Serializable, ChangeListener, ComponentListener, PropertyChangeListener{
+  transient private PropertyChangeSupport support_ = new PropertyChangeSupport(this);
+  private Map panelList = new HashMap(4);
+  private float dpi = 72.0f; // pixel to user scale (dots per inch);
+  private Dimension pageSize = new Dimension(400, 300);
+  private Color pageBackgroundColor = Color.white;
+  private int printHAlign = AbstractPane.CENTER;
+  private int printVAlign = AbstractPane.TOP;
+  private int printMode = AbstractPane.DEFAULT_SCALE;
+  private Point printOrigin = new  Point(0, 0);
+  private boolean printBorders = false;
+  private boolean printWhitePage = true;
+  transient private boolean batch = false;
+  transient private boolean modified = false;
+//
+  transient private ChangeEvent changeEvent_ = new ChangeEvent(this);
+  transient private Vector changeListeners;
+
+  /**
+   * @label page
+   */
+  transient private Page page;
+
+  /** @link aggregation
+   * @supplierCardinality 1..*
+   * @label panelList*/
+  /*#PanelHolder lnkPanelHolder;*/
+
+  /**
+   * <code>PanelModel</code> constructor.
+   */
+  public PanelModel() {
+  }
+  /**
+   * Create a new <code>PanelModel</code> from an object serialized using
+   * <code>XMLEncoder</code>.  For example,
+   *
+   * <pre>
+   *   PanelModel pModel;
+   *   Page page = new Page();
+   *       try {
+   *    pModel = PanelModel.loadFromXML(new BufferedInputStream(
+   *                       new FileInputStream(outpath)));
+   *    page.setPanelModel(pModel);
+   *  } catch (FileNotFoundException fnfe) {
+   *    JOptionPane.showMessageDialog(this, "Error openning file",
+   *                                  "File Open Error", JOptionPane.ERROR_MESSAGE);
+   *  } catch (InvalidObjectException ioe) {
+   *    JOptionPane.showMessageDialog(this, "File does not contain a PanelModel",
+   *                                  "PanelModel Not Found",
+   *                                  JOptionPane.ERROR_MESSAGE);
+   *  }
+   *
+   * </pre>
+   * @param is InputStream
+   * @return PanelModel object
+   * @throws InvalidObjectException
+   * @see java.beans.XMLEncoder
+   */
+  static public PanelModel loadFromXML(InputStream is) throws InvalidObjectException {
+    PanelModel pModel = null;
+    XMLDecoder xd = new XMLDecoder(is);
+    Object obj = xd.readObject();
+    xd.close();
+    if(obj instanceof PanelModel) {
+      pModel = (PanelModel)obj;
+      pModel.repair();
+    } else {
+      throw new InvalidObjectException("XML file does not contain a PanelModel");
+    }
+    return pModel;
+  }
+  /**
+   * Save <code>PanelModel</code> and its supporting classes as a XML stream using
+   * the <code>XMLEncoder</code>.
+   * @param os OutputStream
+   */
+  public void saveToXML(OutputStream os) {
+    XMLEncoder xe = new XMLEncoder(os);
+    xe.writeObject(this);
+    xe.close();
+   }
+   /**
+    * Create a new <code>Panel</code> and add to <code>PanelModel</code>.
+    * @param id Panel identifier
+    * @param bounds bounds of Panel
+    * @param labels Label Map
+    * @param dataGroups DataGroup Map
+    * @param legends Legend Map
+    */
+   public void addPanel(String id, Rectangle bounds, Map labels,
+                       Map dataGroups, Map legends) {
+    PanelHolder ph = new PanelHolder(id, this, bounds, labels, dataGroups, legends);
+    addPanel(ph);
+  }
+  /**
+   * Add a <code>PanelHolder</code> to <code>PanelModel</code>.
+   * @param ph PanelHolder
+   */
+  public void addPanel(PanelHolder ph) {
+    int sze = panelList.size();
+    ph.addChangeListener(this);
+    panelList.put(ph.getId(), ph);
+    firePropertyChange("panelList", sze, panelList.size());
+  }
+  /**
+   * Remove Panel from <code>PanelModel</code>.
+   * @param ph PanelHolder
+   */
+  public void removePanel(PanelHolder ph) {
+    int sze = panelList.size();
+    ph.removeChangeListener(this);
+    panelList.remove(ph.getId());
+    firePropertyChange("panelList", sze, panelList.size());
+  }
+  /**
+   * Get <code>Iterator</code> of <code>PanelHolder</code> objects.
+   * @return Iterator
+   */
+  public Iterator panelIterator() {
+    return panelList.values().iterator();
+  }
+  /**
+   * Get number of <code>PanelHolder</code> objects in <code>Map</code>.
+   * @return count
+   */
+  public int getPanelCount() {
+    return panelList.size();
+  }
+  /**
+   * Does the <code>PanelModel</code> contain this <code>PanelHolder</code>?
+   * @param id PanelHolder identifier
+   * @return true, if PanelHolder exists.
+   */
+  public boolean hasPanelHolder(String id) {
+    return findPanelHolder(id) != null;
+  }
+  /**
+   * Find the <code>PanelHolder</code> from its  identifier.
+   * @param id PanelHolder identifier
+   * @return PanelHolder
+   */
+  public PanelHolder findPanelHolder(String id) {
+    return (PanelHolder)panelList.get(id);
+  }
+  /**
+  * Add property change listener.
+  * @param l property change listener
+  */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    support_.addPropertyChangeListener(l);
+  }
+  /**
+   * Listen for specific property change.
+   * @param name property name
+   * @param l property change listner
+   */
+  public void addPropertyChangeListener(String name, PropertyChangeListener l) {
+    support_.addPropertyChangeListener(name, l);
+  }
+  /**
+   * Remove property change listener.
+   * @param l property change listener
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    support_.removePropertyChangeListener(l);
+  }
+  /**
+   * Remove specific property change listener
+   * @param name property name
+   * @param l property change listener
+   */
+  public void removePropertyChangeListener(String name, PropertyChangeListener l) {
+    support_.removePropertyChangeListener(name, l);
+  }
+  /**
+   * Get dots per inch value.
+   * @return dots per inch
+   */
+  public float getDpi() {
+    return dpi;
+  }
+
+  /**
+   * Set dots per inch.  Fires property "dpi" when changed.
+   * @param dpi dots per inch
+   */
+  public void setDpi(float dpi) {
+    float saved = this.dpi;
+    this.dpi = dpi;
+    if(saved != this.dpi) firePropertyChange("dpi", new Float(saved), new Float(this.dpi));
+  }
+  /**
+   * <code>ChangeListner</code> callback.
+   * @param e ChangeEvent
+   */
+  public void stateChanged(ChangeEvent e) {
+    Object source = e.getSource();
+    firePropertyChange("panel", null, source);
+  }
+
+  private void firePropertyChange(String name, Object oldValue, Object newValue) {
+    if(batch) {
+      modified = true;
+    } else {
+      support_.firePropertyChange(name, oldValue, newValue);
+    }
+  }
+
+  private void firePropertyChange(String name, int oldValue, int newValue) {
+    if(batch) {
+      modified = true;
+    } else {
+      support_.firePropertyChange(name, oldValue, newValue);
+    }
+  }
+  /**
+   * Set batching for changes to <code>PanelModel</code>. Fires property "batch"
+   * when <code>PanelModel</code> has changed and batch is set to false.
+   * @param batch batch value
+   */
+  public void setBatch(boolean batch) {
+    this.batch = batch;
+    if(!this.batch && modified) {
+      modified = false;
+      support_.firePropertyChange("batch", null, null);
+    }
+  }
+  /**
+   * Registers ChangeListeners and sets back references in <code>PanelModel</code> and
+   * its children.
+   */
+  private void repair() {
+    // traverse PanelModel and create all event links
+    Iterator iter = panelIterator();
+    while(iter.hasNext()) {
+      PanelHolder ph = (PanelHolder)iter.next();
+      ph.removeAllChangeListeners();
+      ph.addChangeListener(this);
+      ph.setPanelModel(this);
+      Iterator dgIter = ph.dataGroupIterator();
+      while(dgIter.hasNext()) {
+        DataGroup dg = (DataGroup)dgIter.next();
+        dg.removeAllChangeListeners();
+        dg.addChangeListener(ph);
+        dg.setPanelHolder(ph);
+        dg.getXAxisHolder().removeAllChangeListeners();
+        dg.getXAxisHolder().addChangeListener(dg);
+        dg.getXAxisHolder().setDataGroup(dg);
+        dg.getYAxisHolder().removeAllChangeListeners();
+        dg.getYAxisHolder().addChangeListener(dg);
+        dg.getYAxisHolder().setDataGroup(dg);
+      }
+      Iterator lbIter = ph.labelIterator();
+      while(lbIter.hasNext()) {
+        Label lb = (Label)lbIter.next();
+        lb.removeAllChangeListeners();
+        lb.addChangeListener(ph);
+        lb.setPanelHolder(ph);
+      }
+      Iterator lgIter = ph.legendIterator();
+      while(lgIter.hasNext()) {
+        Legend lg = (Legend)lgIter.next();
+        lg.removeAllChangeListeners();
+        lg.addChangeListener(ph);
+        lg.setPanelHolder(ph);
+      }
+    }
+  }
+  /**
+   * Is batching turned on?
+   * @return true, if batch is on
+   */
+  public boolean isBatch() {
+    return batch;
+  }
+  /**
+   * Set <code>Page</code> parent.  Called from <code>Page</code> when added to
+   * <code>Page</code> object.
+   * @param page Page
+   */
+  public void setPage(Page page) {
+    if(this.page != null) removePropertyChangeListener(this.page);
+    this.page = page;
+    addPropertyChangeListener(this.page);
+    page.addComponentListener(this);
+    page.addPropertyChangeListener(this);
+    pageSize = page.getSize();
+  }
+  /**
+   * Get Page parent
+   * @return Page
+   */
+  public Page getPage() {
+    return page;
+  }
+  /**
+   * Get <code>Map</code> containing <code>PanelHolder</code> objects.
+   * @return Map
+   */
+  public Map getPanelList() {
+    return panelList;
+  }
+  /**
+   * Set <code>PanelHolder</code> <code>Map</code>.
+   * @param panelList Map
+   */
+  public void setPanelList(Map panelList) {
+    if(Page.DEBUG) System.out.println("PanelModel.setPanelList(): size = " + panelList.size());
+    this.panelList = panelList;
+    Iterator iter = panelIterator();
+    while(iter.hasNext()) {
+      PanelHolder ph = (PanelHolder)iter.next();
+      ph.addChangeListener(this);
+    }
+    firePropertyChange("panelList", 0, panelList.size());  // should this be fired?
+  }
+  /**
+   * Get <code>Page</code> size.
+   * @return Page dimensions
+   */
+  public Dimension getPageSize() {
+    return pageSize;
+  }
+  /**
+   * Set <code>Page</code> size.
+   * @param pageSize Page dimension
+   */
+  public void setPageSize(Dimension pageSize) {
+    Dimension saved = this.pageSize;
+    this.pageSize = pageSize;
+    if(!saved.equals(this.pageSize)) {
+      firePropertyChange("pageSize", saved, pageSize);
+      fireStateChanged();
+    }
+  }
+  /**
+   * Listener to update <code>Page</code> size if it changes.
+   * @param e ComponentEvent
+   */
+  public void componentResized(ComponentEvent e) {
+    pageSize = page.getSize();
+  }
+  /**
+   * Unused.
+   */
+  public void componentMoved(ComponentEvent e) { }
+  /**
+   * Unused.
+   */
+  public void componentShown(ComponentEvent e) { }
+  /**
+   * Unused.
+   */
+  public void componentHidden(ComponentEvent e) { }
+  /**
+   * Get the background color for <code>Page</code>.
+   * @return color
+   */
+  public Color getPageBackgroundColor() {
+    return pageBackgroundColor;
+  }
+  /**
+   * Set <code>Page</code> background color.
+   * @param pageBackgroundColor background color
+   */
+  public void setPageBackgroundColor(Color pageBackgroundColor) {
+    Color saved = this.pageBackgroundColor;
+    this.pageBackgroundColor = pageBackgroundColor;
+    if(!saved.equals(this.pageBackgroundColor)) {
+      firePropertyChange("pageBackgroundColor", saved, this.pageBackgroundColor);
+      fireStateChanged();
+    }
+  }
+  /**
+   * Print borders?
+   * @return true, if borders will be printed
+   */
+  public boolean isPrintBorders() {
+    return printBorders;
+  }
+  /**
+   * Print with white background?
+   * @return true, print on white background
+   */
+  public boolean isPrintWhitePage() {
+    return printWhitePage;
+  }
+  /**
+   * Set the print borders property.  Default = false.
+   * @param printBorders true to print borders
+   */
+  public void setPrintBorders(boolean printBorders) {
+    boolean saved = this.printBorders;
+    this.printBorders = printBorders;
+    if(saved != this.printBorders)
+      firePropertyChange("printBorders", new Boolean(saved),
+                         new Boolean(this.printBorders));
+  }
+  /**
+   * Set the print  on white background property.  Default = true.
+   * @param printWhitePage true to use white for background color
+   */
+  public void setPrintWhitePage(boolean printWhitePage) {
+    boolean saved = this.printWhitePage;
+    this.printWhitePage = printWhitePage;
+    if(saved != this.printWhitePage)
+      firePropertyChange("printWhitePage", new Boolean(saved),
+                         new Boolean(this.printWhitePage));
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    if(Page.DEBUG) System.out.println("PanelModel.propertyChange("+evt.getPropertyName()+")");
+  }
+  /**
+   * Remove changelistener.
+   * @param l changelistener
+   */
+  public synchronized void removeChangeListener(ChangeListener l) {
+    if (changeListeners != null && changeListeners.contains(l)) {
+      Vector v = (Vector) changeListeners.clone();
+      v.removeElement(l);
+      changeListeners = v;
+    }
+  }
+  /**
+   * Remove all <code>ChangeListener</code>s that implement the
+   * <code>DesignListener</code> interface.
+   *
+   * @see DesignListener
+   */
+  public synchronized void removeDesignChangeListeners() {
+    if(changeListeners != null) {
+      Vector v = (Vector) changeListeners.clone();
+      Iterator iter = v.iterator();
+      while(iter.hasNext()) {
+        Object obj = iter.next();
+        if(obj instanceof DesignListener) changeListeners.removeElement(obj);
+      }
+    }
+  }
+
+  /**
+   * Add changelistener
+   * @param l changelistener
+   */
+  public synchronized void addChangeListener(ChangeListener l) {
+    Vector v = changeListeners == null ? new Vector(2) : (Vector) changeListeners.clone();
+    if (!v.contains(l)) {
+      v.addElement(l);
+      changeListeners = v;
+    }
+  }
+  protected void fireStateChanged() {
+    if (changeListeners != null) {
+      Vector listeners = changeListeners;
+      int count = listeners.size();
+      for (int i = 0; i < count; i++) {
+        ((ChangeListener) listeners.elementAt(i)).stateChanged(changeEvent_);
+      }
+    }
+  }
+  /**
+   * Get horizontal alignment for printing.
+   * @return horizontal alignment
+   */
+  public int getPrintHAlign() {
+    return printHAlign;
+  }
+  /**
+   * Set horizontal alignment for printing.  Legal values are AbstractPane.LEFT,
+   * AbstractPane.CENTER, AbstractPane.RIGHT, and AbstractPane.SPECIFIED_LOCATION.
+   * Default = AbstractPane.CENTER.
+   * @param pageHAlign horizontal alignment
+   * @see gov.noaa.pmel.sgt.AbstractPane#LEFT AbstractPane.LEFT
+   * @see gov.noaa.pmel.sgt.AbstractPane#CENTER AbstractPane.CENTER
+   * @see gov.noaa.pmel.sgt.AbstractPane#RIGHT AbstractPane.RIGHT
+   * @see gov.noaa.pmel.sgt.AbstractPane#SPECIFIED_LOCATION AbstractPane.SPECIFIED_LOCATION
+   */
+  public void setPrintHAlign(int printHAlign) {
+    int saved = this.printHAlign;
+    this.printHAlign = printHAlign;
+    if(saved != this.printHAlign)
+      firePropertyChange("printHAlign", saved, this.printHAlign);
+  }
+  /**
+   * Set page origin for printing.  Will be used if the horizontal or vertical alignment is
+   * AbstractPane.SPECIFIED_LOCATION.  Default = (0,0).
+   * @param pageOrigin page origin
+   * @see gov.noaa.pmel.sgt.AbstractPane AbstractPane
+   */
+  public void setPrintOrigin(Point printOrigin) {
+    Point saved = this.printOrigin;
+    this.printOrigin = printOrigin;
+    if(!saved.equals(this.printOrigin))
+      firePropertyChange("printOrigin", saved, this.printOrigin);
+  }
+  /**
+   * Get page origin for printing.
+   * @return page origin.
+   */
+  public Point getPrintOrigin() {
+    return printOrigin;
+  }
+  /**
+   * Get vertical alignment for printing.
+   * @return vertical alignment.
+   */
+  public int getPrintVAlign() {
+    return printVAlign;
+  }
+  /**
+   * Set vertical  alignment for printing.  Legal values are AbstractPane.TOP,
+   * AbstractPane.MIDDLE, AbstractPane.BOTTOM, and AbstractPane.SPECIFIED_LOCATION.
+   * Default = AbstractPane.TOP;
+   * @param pageVAlign vertical alignment
+   * @see gov.noaa.pmel.sgt.AbstractPane#TOP AbstractPane.TOP
+   * @see gov.noaa.pmel.sgt.AbstractPane#MIDDLE AbstractPane.MIDDLE
+   * @see gov.noaa.pmel.sgt.AbstractPane#BOTTOM AbstractPane.BOTTOM
+   * @see gov.noaa.pmel.sgt.AbstractPane#SPECIFIED_LOCATION AbstractPane.SPECIFIED_LOCATION
+   */
+  public void setPrintVAlign(int printVAlign) {
+    int saved = this.printVAlign;
+    this.printVAlign = printVAlign;
+    if(saved != this.printVAlign)
+      firePropertyChange("printVAlign", saved, this.printVAlign);
+  }
+  /**
+   * Get printing scale mode.
+   * @return scale mode
+   */
+  public int getPrintScaleMode() {
+    return printMode;
+  }
+  /**
+   * Set printing  scale mode.  Legal values are AbstractPane.DEFAULT_SCALE,
+   * AbstractPane.TO_FIT, and AbstractPane.SHRINK_TO_FIT.  Default =
+   * AbstractPane.DEFAULT_SCALE.
+   * @param mode scale mode
+   * @see gov.noaa.pmel.sgt.AbstractPane#DEFAULT_SCALE AbstractPane.DEFAULT_SCALE
+   * @see gov.noaa.pmel.sgt.AbstractPane#TO_FIT AbstractPane.TO_FIT
+   * @see gov.noaa.pmel.sgt.AbstractPane#SHRINK_TO_FIT AbstractPane.SHRINK_TO_FIT
+   */
+  public void setPrintScaleMode(int mode) {
+    int saved = this.printMode;
+    this.printMode = mode;
+    if(saved != this.printMode)
+      firePropertyChange("printScaleMode", saved, this.printMode);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelBeanInfo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelBeanInfo.java
new file mode 100755
index 0000000..1032251
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelBeanInfo.java
@@ -0,0 +1,98 @@
+/*
+ * $Id: PanelModelBeanInfo.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.beans.*;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ */
+public class PanelModelBeanInfo extends SimpleBeanInfo {
+  private Class beanClass = PanelModel.class;
+  private Class customizerClass = PanelModelCustomizer.class;
+  private String iconColor16x16Filename = "PanelModelIcon16.gif";
+  private String iconColor32x32Filename = "PanelModelIcon32.gif";
+  private String iconMono16x16Filename;
+  private String iconMono32x32Filename;
+
+  public PanelModelBeanInfo() {
+  }
+
+  public BeanDescriptor getBeanDescriptor() {
+    return new BeanDescriptor(beanClass, customizerClass);
+  }
+
+  public PropertyDescriptor[] getPropertyDescriptors() {
+    try {
+      PropertyDescriptor _batch = new PropertyDescriptor("batch", beanClass, null, null);
+      _batch.setValue("transient", Boolean.TRUE);
+      PropertyDescriptor _dpi = new PropertyDescriptor("dpi", beanClass, "getDpi", "setDpi");
+      PropertyDescriptor _modified = new PropertyDescriptor("modified", beanClass, null, null);
+      _modified.setValue("transient", Boolean.TRUE);
+      PropertyDescriptor _page = new PropertyDescriptor("page", beanClass, "getPage", "setPage");
+      _page.setValue("transient", Boolean.TRUE);
+      PropertyDescriptor _panelList = new PropertyDescriptor("panelList", beanClass, "getPanelList", "setPanelList");
+      PropertyDescriptor _panelCount = new PropertyDescriptor("panelCount", beanClass, "getPanelCount", null);
+      PropertyDescriptor _pageSize = new PropertyDescriptor("pageSize", beanClass, "getPageSize", "setPageSize");
+      PropertyDescriptor _pageBackgroundColor =
+          new PropertyDescriptor("pageBackgroundColor", beanClass, "getPageBackgroundColor", "setPageBackgroundColor");
+      PropertyDescriptor _printWhitePage =
+          new PropertyDescriptor("printWhitePage", beanClass, "isPrintWhitePage", "setPrintWhitePage");
+      PropertyDescriptor _printBorders =
+          new PropertyDescriptor("printBorders", beanClass, "isPrintBorders", "setPrintBorders");
+      PropertyDescriptor _pageHAlign =
+          new PropertyDescriptor("printHAlign", beanClass, "getPrintHAlign", "setPrintHAlign");
+      PropertyDescriptor _pageVAlign =
+          new PropertyDescriptor("printVAlign", beanClass, "getPrintVAlign", "setPrintVAlign");
+      PropertyDescriptor _printMode =
+          new PropertyDescriptor("printScaleMode", beanClass, "getPrintScaleMode", "setPrintScaleMode");
+      PropertyDescriptor _pageOrigin =
+          new PropertyDescriptor("printOrigin", beanClass, "getPrintOrigin", "setPrintOrigin");
+      PropertyDescriptor[] pds = new PropertyDescriptor[] {
+        _batch,
+        _dpi,
+        _modified,
+        _page,
+        _pageBackgroundColor,
+        _pageSize,
+        _panelList,
+        _panelCount,
+        _printWhitePage,
+        _printBorders,
+        _pageHAlign,
+        _pageVAlign,
+        _printMode,
+        _pageOrigin};
+      return pds;
+    }
+    catch(IntrospectionException ex) {
+      ex.printStackTrace();
+      return null;
+    }
+  }
+  public java.awt.Image getIcon(int iconKind) {
+    switch (iconKind) {
+      case BeanInfo.ICON_COLOR_16x16:
+        return iconColor16x16Filename != null ? loadImage(iconColor16x16Filename) : null;
+      case BeanInfo.ICON_COLOR_32x32:
+        return iconColor32x32Filename != null ? loadImage(iconColor32x32Filename) : null;
+      case BeanInfo.ICON_MONO_16x16:
+        return iconMono16x16Filename != null ? loadImage(iconMono16x16Filename) : null;
+      case BeanInfo.ICON_MONO_32x32:
+        return iconMono32x32Filename != null ? loadImage(iconMono32x32Filename) : null;
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelCustomizer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelCustomizer.java
new file mode 100755
index 0000000..c7aa1c0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelCustomizer.java
@@ -0,0 +1,679 @@
+/*
+ * $Id: PanelModelCustomizer.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.beans.Customizer;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import javax.swing.filechooser.FileFilter;
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableColumn;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.*;
+import java.util.Vector;
+import java.util.Iterator;
+import java.awt.event.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.SimpleFileFilter;
+import gov.noaa.pmel.swing.MRJUtil;
+import javax.swing.event.AncestorEvent;
+import javax.swing.event.AncestorListener;
+/**
+ * Used at design time to customize a <code>PanelModel</code>.  This class is also
+ * used by <code>PanelModelEditor</code> for run-time changes to the <code>PanelModel</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ * @see PanelModelEditor
+ * @see PanelModel
+ */
+public class PanelModelCustomizer extends JComponent implements Customizer, PropertyChangeListener {
+  /**
+   * @supplierCardinality 1
+   */
+  private PanelModel panelModel_ = null;
+  private JFileChooser fileChooser_ = null;
+  private BorderLayout borderLayout1 = new BorderLayout();
+  private JPanel messagePanel = new JPanel();
+  private JTextField message = new JTextField();
+  private BorderLayout borderLayout2 = new BorderLayout();
+  private JPanel mainPanel = new JPanel();
+  private BorderLayout borderLayout3 = new BorderLayout();
+  private JPanel layoutPanel = new JPanel();
+  private BorderLayout borderLayout4 = new BorderLayout();
+  private JPanel toolPanel = new JPanel();
+  private JButton newPanelButton = new JButton();
+
+  /**
+     *@link aggregationByValue
+     *     @associates <{PanelView}>
+     * @supplierCardinality *
+     */
+  /* private Vector lnkPanelView; */
+  private DesignPanel designPanel_ = new DesignPanel();
+  private FlowLayout flowLayout1 = new FlowLayout();
+  private JButton alignBottomButton = new JButton();
+  private JButton alignTopButton = new JButton();
+  private JButton alignLeftButton = new JButton();
+  private JButton alignRightButton = new JButton();
+  private JButton justVerticalButton = new JButton();
+  private JButton justHorizontalButton = new JButton();
+  private ImageIcon alignBottom_ = new ImageIcon(getClass().getResource("images/AlignBottom24.gif"),"Align Bottom");
+  private ImageIcon alignTop_ = new ImageIcon(getClass().getResource("images/AlignTop24.gif"),"Align Top");
+  private ImageIcon alignLeft_ = new ImageIcon(getClass().getResource("images/AlignLeft24.gif"),"Align Left");
+  private ImageIcon alignRight_ = new ImageIcon(getClass().getResource("images/AlignRight24.gif"),"Align Right");
+  private ImageIcon justifyVertical_ = new ImageIcon(getClass().getResource("images/AlignJustifyVertical24.gif"),"Justify Vertical");
+  private ImageIcon justifyHorizontal_ = new ImageIcon(getClass().getResource("images/AlignJustifyHorizontal24.gif"),"Justify Horizontal");
+  private ImageIcon newPanel_ = new ImageIcon(getClass().getResource("images/New24.gif"), "New Panel");
+  private ImageIcon newDataGroup_ = new ImageIcon(getClass().getResource("images/NewDataGroup24.gif"), "New Data Group");
+  private ImageIcon newLabel_ = new ImageIcon(getClass().getResource("images/NewLabel24.gif"), "New Label");
+  private ImageIcon newLegend_ = new ImageIcon(getClass().getResource("images/NewLegend24.gif"), "New Legend");
+  private ImageIcon removePanel_ = new ImageIcon(getClass().getResource("images/Remove24.gif"), "Remove Panel");
+  private ImageIcon saveAsPanel_ = new ImageIcon(getClass().getResource("images/SaveAs24.gif"), "Save PanelModel");
+  private ImageIcon openPanel_ = new ImageIcon(getClass().getResource("images/Open24.gif"), "Open PanelModel");
+  private Component component2;
+  private Component component3;
+  private JButton removeButton = new JButton();
+  private Component component1;
+  private JPanel propertyPanel = new JPanel();
+  private JPanel leftPanel = new JPanel();
+  private TitledBorder propertyBorder;
+  private JScrollPane jScrollPane1 = new JScrollPane();
+  private BorderLayout borderLayout5 = new BorderLayout();
+  private JButton newDataGroupButton = new JButton();
+  private JButton newLabelButton = new JButton();
+  private JButton newLegendButton = new JButton();
+  private JScrollPane designScroller = new JScrollPane();
+
+  private PanelHolderPropertyPanel phPropertyPanel_ = null;
+  private LabelPropertyPanel labelPropertyPanel_ = null;
+  private LegendPropertyPanel legendPropertyPanel_ = null;
+  private DataGroupPropertyPanel agPropertyPanel_ = null;
+  private AxisHolderPropertyPanel ahPropertyPanel_ = null;
+  private PanelModelPropertyPanel pmPropertyPanel_ = null;
+  private PropertyPanel currentPropertyPanel_ = null;
+
+  private JPanel grayPanel = new JPanel();
+  private BorderLayout borderLayout6 = new BorderLayout();
+  private BorderLayout borderLayout7 = new BorderLayout();
+  private JPanel jPanel1 = new JPanel();
+  private JCheckBox expertCB = new JCheckBox();
+  private GridBagLayout gridBagLayout2 = new GridBagLayout();
+  private JButton openPanelButton = new JButton();
+  private JButton saveAsPanelButton = new JButton();
+  private Component component5;
+
+  /**
+   * <code>PanelModelCustomizer</code> constructor.
+   */
+  public PanelModelCustomizer() {
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+    designPanel_.addPropertyChangeListener(this);
+    setPanelButtons(0);
+  }
+
+  /**
+   * Set a <code>PanelModel</code> to be customized.
+   * @param panelModel PanelModel
+   * @see PanelModel
+   */
+  public void setObject(Object panelModel) {
+    panelModel_ = (PanelModel)panelModel;
+    designPanel_.setPanelModel(panelModel_);
+    pmPropertyPanel_ = new PanelModelPropertyPanel(panelModel_);
+    setDefaultPanel();
+    if(Page.DEBUG) System.out.println("Customizer setObject()");
+  }
+
+  private void jbInit() throws Exception {
+    component2 = Box.createHorizontalStrut(8);
+    component3 = Box.createHorizontalStrut(8);
+    component1 = Box.createHorizontalStrut(8);
+    propertyBorder = new TitledBorder(BorderFactory.createLineBorder(new Color(153, 153, 153),2),"Parameter");
+    component5 = Box.createHorizontalStrut(8);
+    this.setLayout(borderLayout1);
+    message.setText("Important information will go here.");
+    messagePanel.setLayout(borderLayout2);
+    messagePanel.setBorder(BorderFactory.createLoweredBevelBorder());
+    mainPanel.setLayout(borderLayout3);
+    layoutPanel.setLayout(borderLayout4);
+    leftPanel.setLayout(borderLayout7);
+    newPanelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        newPanelButton_actionPerformed(e);
+      }
+    });
+    toolPanel.setLayout(flowLayout1);
+    toolPanel.setBorder(BorderFactory.createEtchedBorder());
+    designPanel_.setLayout(null);
+    alignBottomButton.setToolTipText("Align Bottom");
+    alignBottomButton.setIcon(alignBottom_);
+    alignBottomButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        alignBottomButton_actionPerformed(e);
+      }
+    });
+    alignLeftButton.setToolTipText("Align Left");
+    alignLeftButton.setIcon(alignLeft_);
+    alignLeftButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        alignLeftButton_actionPerformed(e);
+      }
+    });
+    alignTopButton.setToolTipText("Align Top");
+    alignTopButton.setIcon(alignTop_);
+    alignTopButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        alignTopButton_actionPerformed(e);
+      }
+    });
+    alignRightButton.setToolTipText("Align Right");
+    alignRightButton.setIcon(alignRight_);
+    alignRightButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        alignRightButton_actionPerformed(e);
+      }
+    });
+    newPanelButton.setToolTipText("New Panel");
+    newPanelButton.setIcon(newPanel_);
+    justVerticalButton.setToolTipText("Justify Vertically");
+    justVerticalButton.setIcon(justifyVertical_);
+    justVerticalButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        justVerticalButton_actionPerformed(e);
+      }
+    });
+    justHorizontalButton.setToolTipText("Justify Horizontally");
+    justHorizontalButton.setIcon(justifyHorizontal_);
+    justHorizontalButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        justHorizontalButton_actionPerformed(e);
+      }
+    });
+    removeButton.setToolTipText("Remove Panel");
+    removeButton.setIcon(removePanel_);
+    removeButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        removeButton_actionPerformed(e);
+      }
+    });
+    this.setPreferredSize(new Dimension(800, 600));
+    propertyPanel.setBorder(propertyBorder);
+    propertyPanel.setMinimumSize(new Dimension(240, 10));
+    propertyPanel.setPreferredSize(new Dimension(240, 10));
+    propertyPanel.setLayout(borderLayout5);
+    propertyBorder.setTitle("Properties");
+    newDataGroupButton.setToolTipText("New Data Group");
+    newDataGroupButton.setIcon(newDataGroup_);
+    newDataGroupButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        newDataGroupButton_actionPerformed(e);
+      }
+    });
+    newLabelButton.setToolTipText("New Label");
+    newLabelButton.setIcon(newLabel_);
+    newLabelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        newLabelButton_actionPerformed(e);
+      }
+    });
+    newLegendButton.setToolTipText("New Legend");
+    newLegendButton.setIcon(newLegend_);
+    newLegendButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        newLegendButton_actionPerformed(e);
+      }
+    });
+    grayPanel.setBackground(Color.lightGray);
+    grayPanel.setLayout(borderLayout6);
+    expertCB.setText("Expert");
+    expertCB.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        expertCB_actionPerformed(e);
+      }
+    });
+    jPanel1.setLayout(gridBagLayout2);
+    openPanelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        openPanelButton_actionPerformed(e);
+      }
+    });
+    openPanelButton.setEnabled(false);
+    openPanelButton.setToolTipText("Open Panel");
+    openPanelButton.setIcon(openPanel_);
+    saveAsPanelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        saveAsPanelButton_actionPerformed(e);
+      }
+    });
+    saveAsPanelButton.setToolTipText("Save Panel");
+    saveAsPanelButton.setIcon(saveAsPanel_);
+    this.add(messagePanel, BorderLayout.SOUTH);
+    messagePanel.add(message, BorderLayout.CENTER);
+    this.add(mainPanel, BorderLayout.CENTER);
+    mainPanel.add(layoutPanel, BorderLayout.CENTER);
+    toolPanel.add(openPanelButton, null);
+    toolPanel.add(saveAsPanelButton, null);
+    toolPanel.add(component5, null);
+    toolPanel.add(newPanelButton, null);
+    toolPanel.add(newDataGroupButton, null);
+    toolPanel.add(newLabelButton, null);
+    toolPanel.add(newLegendButton, null);
+    toolPanel.add(component3, null);
+    toolPanel.add(removeButton, null);
+    toolPanel.add(component1, null);
+    toolPanel.add(alignBottomButton, null);
+    toolPanel.add(alignTopButton, null);
+    toolPanel.add(alignLeftButton, null);
+    toolPanel.add(alignRightButton, null);
+    toolPanel.add(component2, null);
+    toolPanel.add(justVerticalButton, null);
+    toolPanel.add(justHorizontalButton, null);
+    layoutPanel.add(designScroller, BorderLayout.CENTER);
+    designScroller.getViewport().add(grayPanel, null);
+    grayPanel.add(designPanel_, BorderLayout.CENTER);
+    leftPanel.add(propertyPanel, BorderLayout.CENTER);
+    layoutPanel.add(leftPanel,  BorderLayout.WEST);
+    propertyPanel.add(jScrollPane1,  BorderLayout.CENTER);
+    leftPanel.add(jPanel1, BorderLayout.NORTH);
+    jPanel1.add(expertCB,   new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    layoutPanel.add(toolPanel, BorderLayout.NORTH);
+
+    if(!MRJUtil.isAquaLookAndFeel()) {
+      alignBottomButton.setMargin(new Insets(0, 0, 0, 0));
+      alignLeftButton.setMargin(new Insets(0, 0, 0, 0));
+      alignTopButton.setMargin(new Insets(0, 0, 0, 0));
+      alignRightButton.setMargin(new Insets(0, 0, 0, 0));
+      newPanelButton.setMargin(new Insets(0, 0, 0, 0));
+      justVerticalButton.setMargin(new Insets(0, 0, 0, 0));
+      justHorizontalButton.setMargin(new Insets(0, 0, 0, 0));
+      removeButton.setMargin(new Insets(0, 0, 0, 0));
+      newDataGroupButton.setMargin(new Insets(0, 0, 0, 0));
+      newLabelButton.setMargin(new Insets(0, 0, 0, 0));
+      newLegendButton.setMargin(new Insets(0, 0, 0, 0));
+      openPanelButton.setMargin(new Insets(0, 0, 0, 0));
+      saveAsPanelButton.setMargin(new Insets(0,0,0,0));
+    }
+    openPanelButton.setFocusable(false);
+    saveAsPanelButton.setFocusable(false);
+  }
+
+  public Dimension getMinimumSize() {
+    return new Dimension(600, 400);
+  }
+
+  public Dimension getMaximumSize() {
+    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  }
+
+  public Dimension getPreferredSize() {
+    return new Dimension(800, 600);
+  }
+
+  void newPanelButton_actionPerformed(ActionEvent e) {
+    PanelHolder ph = new PanelHolder("Panel" + panelModel_.getPanelCount(),
+                                     panelModel_,
+                                     new Rectangle(20, 20, 200, 300),
+                                     null, null, null);
+    PanelHolderDragBox pi = new PanelHolderDragBox(ph);
+    panelModel_.addPanel(ph);
+    designPanel_.addPanel(pi);
+    designPanel_.repaint();
+  }
+
+  void newDataGroupButton_actionPerformed(ActionEvent e) {
+    PanelHolder ph = designPanel_.getSelectedPanel();
+    if(ph == null) return;
+    DataGroup ag = new DataGroup("DataGroup" + ph.getDataGroupSize(), ph);
+    designPanel_.addDataGroup(ag);
+    designPanel_.repaint();
+  }
+
+  void newLabelButton_actionPerformed(ActionEvent e) {
+    PanelHolder ph = designPanel_.getSelectedPanel();
+    if(ph == null) return;
+    Label label = new Label("Label" + ph.getLabelSize(),
+                            new Point2D.Double(1.5, 1.5),
+                            0.75, 0.25);
+    designPanel_.addLabel(label);
+    designPanel_.repaint();
+  }
+
+  void newLegendButton_actionPerformed(ActionEvent e) {
+    PanelHolder ph = designPanel_.getSelectedPanel();
+    if(ph == null) return;
+    Legend legend = new Legend("Legend" + ph.getLegendSize(),
+                               new Rectangle2D.Double(1.0, 1.0, 1.5, 0.25));
+    designPanel_.addLegend(legend);
+    designPanel_.repaint();
+
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    String pName = evt.getPropertyName();
+    Object val = evt.getNewValue();
+    if(Page.DEBUG) System.out.println("PanelModelCustomizer.propertyChange: " + pName + ", " + evt.getNewValue());
+    setPanelButtons(designPanel_.getSelectedCount());
+    if(designPanel_.getSelectedCount() > 1) {
+      setDefaultPanel();
+      return;
+    }
+    if(pName.equals("message")) {
+      message.setText((String)evt.getNewValue());
+    } else if(pName.equals("allUnselected")) {
+      setDefaultPanel();
+    } else if(pName.equals("panelSelected")) {
+      if(val instanceof PanelHolderDragBox) {
+        PanelHolderDragBox pdb = (PanelHolderDragBox)val;
+        if(pdb.isSelected()) {
+          setPanelPropertyPanel(pdb.getPanelHolder());
+        } else {
+          setDefaultPanel();
+        }
+      }
+    } else if(pName.equals("dataGroupSelected")) {
+      if(val instanceof DataGroupDragBox) {
+        DataGroupDragBox ag = (DataGroupDragBox)val;
+        if(ag.isSelected()) {
+          setDataGroupPropertyPanel(ag.getDataGroup());
+        } else {
+          setDefaultPanel();
+        }
+      }
+    } else if(pName.equals("axisSelected")) {
+      if(val instanceof AxisHolderDragBox) {
+        AxisHolderDragBox ah = (AxisHolderDragBox)val;
+        if(ah.isSelected()) {
+          setAxisHolderPropertyPanel(ah.getAxisHolder());
+        } else {
+          setDefaultPanel();
+        }
+      }
+    } else if(pName.equals("labelSelected")) {
+      if(val instanceof LabelDragBox) {
+        LabelDragBox ldb = (LabelDragBox)val;
+        if(ldb.isSelected()) {
+          setLabelPropertyPanel(ldb.getLabel());
+        } else {
+          setDefaultPanel();
+        }
+      }
+    } else if(pName.equals("legendSelected")) {
+      if(val instanceof LegendDragBox) {
+        LegendDragBox ldb = (LegendDragBox)val;
+        if(ldb.isSelected()) {
+          setLegendPropertyPanel(ldb.getLegend());
+        } else {
+          setDefaultPanel();
+        }
+      }
+    } else if(pName.equals("ancestor")) {
+/*      if(Page.DEBUG) {
+        System.out.println("PanelModelCustomizer.propertyChange()");
+        System.out.println("           propertyName = " + evt.getPropertyName());
+        System.out.println("                 source = " + evt.getSource());
+        System.out.println("               oldValue = " + evt.getOldValue());
+        System.out.println("               newValue = " + evt.getNewValue());
+        System.out.println("          propagationId = " + evt.getPropagationId());
+      } */
+//      panelModel_.getPage().setBackground(panelModel_.getPageBackgroundColor());
+//      panelModel_.getPage().setSize(panelModel_.getPageSize());
+      if(evt.getNewValue() == null) {
+        // clean up ChangeListeners
+        Iterator iter;
+        if(panelModel_ == null) return;
+        Iterator pIter = panelModel_.panelIterator();
+        while(pIter.hasNext()) {
+          PanelHolder ph = (PanelHolder)pIter.next();
+          iter = ph.labelIterator();
+          while(iter.hasNext()) {
+            Label label = (Label)iter.next();
+            label.removeDesignChangeListeners();
+          }
+          iter = ph.legendIterator();
+          while(iter.hasNext()) {
+            Legend legend = (Legend)iter.next();
+            legend.removeDesignChangeListeners();
+          }
+          iter = ph.dataGroupIterator();
+          while(iter.hasNext()) {
+            DataGroup dg = (DataGroup)iter.next();
+            dg.getXAxisHolder().removeDesignChangeListeners();
+            dg.getYAxisHolder().removeDesignChangeListeners();
+            dg.removeDesignChangeListeners();
+          }
+         ph.removeDesignChangeListeners();
+        }
+        panelModel_.removeDesignChangeListeners();
+      } /* else {
+        System.out.println("change focus here?");
+        System.out.println("PanelModelCustomizer.isVisible() = " + isVisible());
+        if(newPanelButton.requestFocusInWindow()) {
+          System.out.println("focus may be granted");
+        } else {
+          System.out.println("focus wont be granted");
+        }
+        KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+//        KeyboardFocusManager.getCurrentKeyboardFocusManager().upFocusCycle();
+//        KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
+
+      } */
+    }
+  }
+
+  private void setDefaultPanel() {
+    jScrollPane1.getViewport().removeAll();
+    jScrollPane1.getViewport().add(pmPropertyPanel_, null);
+    currentPropertyPanel_ = pmPropertyPanel_;
+  }
+
+  private void setPanelPropertyPanel(PanelHolder ph) {
+    if(ph == null) {
+      setDefaultPanel();
+      return;
+    }
+    if(phPropertyPanel_ == null) {
+      phPropertyPanel_ = new PanelHolderPropertyPanel(ph, expertCB.isSelected());
+    } else {
+      phPropertyPanel_.setPanelHolder(ph, expertCB.isSelected());
+    }
+    jScrollPane1.getViewport().removeAll();
+    jScrollPane1.getViewport().add(phPropertyPanel_);
+    currentPropertyPanel_ = phPropertyPanel_;
+  }
+
+  private void setDataGroupPropertyPanel(DataGroup dg) {
+    if(dg == null) {
+      setDefaultPanel();
+      return;
+    }
+    if(agPropertyPanel_ == null) {
+      agPropertyPanel_ = new DataGroupPropertyPanel(dg, expertCB.isSelected());
+    } else {
+      agPropertyPanel_.setDataGroup(dg, expertCB.isSelected());
+    }
+    jScrollPane1.getViewport().removeAll();
+    jScrollPane1.getViewport().add(agPropertyPanel_);
+    currentPropertyPanel_ = agPropertyPanel_;
+  }
+
+  private void setAxisHolderPropertyPanel(AxisHolder ah) {
+    if(ah == null) {
+      setDefaultPanel();
+      return;
+    }
+    if(ahPropertyPanel_ == null) {
+      ahPropertyPanel_ = new AxisHolderPropertyPanel(ah, expertCB.isSelected());
+    } else {
+      ahPropertyPanel_.setAxisHolder(ah, expertCB.isSelected());
+    }
+    jScrollPane1.getViewport().removeAll();
+    jScrollPane1.getViewport().add(ahPropertyPanel_);
+    currentPropertyPanel_ = ahPropertyPanel_;
+  }
+
+  private void setLabelPropertyPanel(Label lab) {
+    if(lab == null) {
+      setDefaultPanel();
+      return;
+    }
+    if(labelPropertyPanel_ == null) {
+      labelPropertyPanel_ = new LabelPropertyPanel(lab, expertCB.isSelected());
+    } else {
+      labelPropertyPanel_.setLabel(lab, expertCB.isSelected());
+    }
+    jScrollPane1.getViewport().removeAll();
+    jScrollPane1.getViewport().add(labelPropertyPanel_);
+    currentPropertyPanel_ = labelPropertyPanel_;
+  }
+
+  private void setLegendPropertyPanel(Legend legend) {
+    if(legend == null) {
+      setDefaultPanel();
+      return;
+    }
+    if(legendPropertyPanel_ == null) {
+      legendPropertyPanel_ = new LegendPropertyPanel(legend, expertCB.isSelected());
+    } else {
+      legendPropertyPanel_.setLegend(legend, expertCB.isSelected());
+    }
+    jScrollPane1.getViewport().removeAll();
+    jScrollPane1.getViewport().add(legendPropertyPanel_);
+    currentPropertyPanel_ = legendPropertyPanel_;
+  }
+
+  private void setPanelButtons(int enabledCount) {
+    boolean enabled = enabledCount >= 2;
+
+    alignBottomButton.setEnabled(enabled);
+    alignTopButton.setEnabled(enabled);
+    alignLeftButton.setEnabled(enabled);
+    alignRightButton.setEnabled(enabled);
+
+    enabled = enabledCount >= 1;
+    justVerticalButton.setEnabled(enabled);
+    justHorizontalButton.setEnabled(enabled);
+
+    enabled = enabledCount == 1;
+    removeButton.setEnabled(enabled);
+    newDataGroupButton.setEnabled(enabled);
+    newLabelButton.setEnabled(enabled);
+    newLegendButton.setEnabled(enabled);
+
+    enabled = designPanel_.isChildDragBoxSelected();
+    if(enabled) {
+      removeButton.setEnabled(!designPanel_.isAxisHolderDragBoxSelected());
+    }
+  }
+
+  void alignBottomButton_actionPerformed(ActionEvent e) {
+    designPanel_.alignBoxes(DesignPanel.ALIGN_BOTTOM);
+  }
+
+  void alignTopButton_actionPerformed(ActionEvent e) {
+    designPanel_.alignBoxes(DesignPanel.ALIGN_TOP);
+  }
+
+  void alignLeftButton_actionPerformed(ActionEvent e) {
+    designPanel_.alignBoxes(DesignPanel.ALIGN_LEFT);
+  }
+
+  void alignRightButton_actionPerformed(ActionEvent e) {
+    designPanel_.alignBoxes(DesignPanel.ALIGN_RIGHT);
+  }
+
+  void justVerticalButton_actionPerformed(ActionEvent e) {
+    designPanel_.alignBoxes(DesignPanel.JUSTIFY_VERTICAL);
+  }
+
+  void justHorizontalButton_actionPerformed(ActionEvent e) {
+    designPanel_.alignBoxes(DesignPanel.JUSTIFY_HORIZONTAL);
+  }
+
+  void removeButton_actionPerformed(ActionEvent e) {
+    designPanel_.removeSelected();
+    setDefaultPanel();
+    setPanelButtons(0);
+  }
+
+  void expertCB_actionPerformed(ActionEvent e) {
+    currentPropertyPanel_.setExpert(expertCB.isSelected());
+  }
+
+  void openPanelButton_actionPerformed(ActionEvent e) {
+    // problem with open since PanelModelCustomizer work on the original
+    // object.  Right now there isn't a method for replacing the PanelModel
+    // inside the customizer.  However, I can save it!
+  }
+
+  void saveAsPanelButton_actionPerformed(ActionEvent e) {
+    File file;
+    FileFilter filt;
+    String ext;
+    String outpath;
+    String[] xmlFile = new String[]{".xml"};
+    SimpleFileFilter xmlFilt = new SimpleFileFilter(xmlFile, "XML Serialized Bean");
+
+    if(fileChooser_ == null) {
+      fileChooser_ = new JFileChooser();
+    }
+    fileChooser_.setFileFilter(fileChooser_.getAcceptAllFileFilter());
+    fileChooser_.resetChoosableFileFilters();
+    fileChooser_.addChoosableFileFilter(xmlFilt);
+    fileChooser_.setFileFilter(xmlFilt);
+
+    int result = fileChooser_.showSaveDialog(this);
+    if(result == JFileChooser.APPROVE_OPTION) {
+      file = fileChooser_.getSelectedFile();
+      filt = fileChooser_.getFileFilter();
+      outpath = file.getPath();
+      if(filt instanceof SimpleFileFilter) {
+        ext = ((SimpleFileFilter)filt).getExtension();
+        String name = file.getName().toLowerCase();
+        if(!name.endsWith(ext)) {
+          outpath += ext;
+        }
+      }
+      try {
+        panelModel_.saveToXML(new BufferedOutputStream(
+                                       new FileOutputStream(outpath, false)));
+      } catch (FileNotFoundException fnfe) {
+        JOptionPane.showMessageDialog(this, "Error creating file, rename and try again",
+                                      "File Save Error", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelEditor.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelEditor.java
new file mode 100755
index 0000000..48cbaf8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelEditor.java
@@ -0,0 +1,301 @@
+/*
+ * $Id: PanelModelEditor.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import java.io.InvalidObjectException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import java.awt.event.*;
+
+import gov.noaa.pmel.util.SimpleFileFilter;
+
+/**
+ * Run-time and stand-alone editor to modify a <code>PanelModel</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ * @see PanelModelCustomizer
+ **/
+public class PanelModelEditor extends JFrame {
+  private PanelModel panelModel_ = null;
+  private static boolean isApp_ = false;
+  private boolean throwClosing = true;
+  private String openPath_ = null;
+  private static String title_ = "Panel Model Editor";
+  //
+  private JFileChooser fileChooser_ = null;
+  private JPanel pmcPanel = new JPanel();
+  private JPanel buttonPanel = new JPanel();
+  private JMenuBar menuBar = new JMenuBar();
+  private JButton okButton = new JButton();
+  private PanelModelCustomizer pmc = new PanelModelCustomizer();
+  private BorderLayout borderLayout1 = new BorderLayout();
+  private JMenu fileMenu = new JMenu();
+  private JMenuItem openFileMI = new JMenuItem();
+  private JMenuItem saveFileMI = new JMenuItem();
+  private JMenuItem exitFileMI = new JMenuItem();
+  private JMenuItem saveAsFileMI = new JMenuItem();
+  private JMenuItem newFileMI = new JMenuItem();
+
+  /**
+   * <code>PanelModelEditor</code> constructor.
+   * @param pModel PanelModel
+   */
+  public PanelModelEditor(PanelModel pModel) {
+    this();
+    setPanelModel(pModel);
+  }
+
+  /**
+   * Default constructor.
+   */
+  public PanelModelEditor() {
+    try {
+      jbInit();
+      pack();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Main method for stand-alone application to create/modify <code>PanelModel</code>s
+   * that have been serialized using <code>XMLEncoder</code>.
+   * @param args Arguement String
+   * @see java.beans.XMLEncoder
+   */
+  public static void main(String[] args) {
+    isApp_ = true;
+    PanelModelEditor pme = new PanelModelEditor(new PanelModel());
+    pme.setTitle(title_);
+    pme.setVisible(true);
+  }
+
+  private void jbInit() throws Exception {
+    okButton.setText("OK");
+    okButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        okButton_actionPerformed(e);
+      }
+    });
+    pmcPanel.setLayout(borderLayout1);
+    fileMenu.setText("File");
+    openFileMI.setActionCommand("Open");
+    openFileMI.setText("Open...");
+    openFileMI.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        openFileMI_actionPerformed(e);
+      }
+    });
+    saveFileMI.setActionCommand("Save");
+    saveFileMI.setText("Save");
+    saveFileMI.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        saveFileMI_actionPerformed(e);
+      }
+    });
+    exitFileMI.setText("Exit");
+    exitFileMI.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        exitFileMI_actionPerformed(e);
+      }
+    });
+    saveAsFileMI.setActionCommand("SaveAs");
+    saveAsFileMI.setText("Save As...");
+    saveAsFileMI.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        saveAsFileMI_actionPerformed(e);
+      }
+    });
+    if(isApp_)this.setJMenuBar(menuBar);
+    newFileMI.setText("New");
+    newFileMI.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        newFileMI_actionPerformed(e);
+      }
+    });
+    this.getContentPane().add(pmcPanel, BorderLayout.CENTER);
+    if(!isApp_) this.getContentPane().add(buttonPanel,  BorderLayout.SOUTH);
+    buttonPanel.add(okButton, null);
+    pmcPanel.add(pmc,  BorderLayout.CENTER);
+    menuBar.add(fileMenu);
+    fileMenu.add(newFileMI);
+    fileMenu.addSeparator();
+    fileMenu.add(openFileMI);
+    fileMenu.add(saveFileMI);
+    fileMenu.add(saveAsFileMI);
+    fileMenu.addSeparator();
+    fileMenu.add(exitFileMI);
+
+    addWindowListener(new java.awt.event.WindowAdapter() {
+      public void windowClosing(WindowEvent e) {
+        if(throwClosing) pmf_windowClosing(e);
+      }
+    });
+    Dimension dim = pmc.getPreferredSize();
+    setSize(new Dimension(473, 354));
+    //Center the window
+    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+    Dimension frameSize = getSize();
+    if (frameSize.height > screenSize.height) {
+      frameSize.height = screenSize.height;
+    }
+    if (frameSize.width > screenSize.width) {
+      frameSize.width = screenSize.width;
+    }
+    setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
+  }
+
+  void pmf_windowClosing(WindowEvent e) {
+    if(Page.DEBUG) System.out.println("windowClosing");
+    throwClosing = false;
+    setVisible(false);
+    if(panelModel_ != null) panelModel_.setBatch(false);
+    dispose();
+    if(isApp_) System.exit(0);
+  }
+
+  void okButton_actionPerformed(ActionEvent e) {
+    throwClosing = false;
+    pmf_windowClosing(null);
+  }
+
+  /**
+   * Get <code>PanelModel</code>.
+   * @return PanelModel
+   */
+  public PanelModel getPanelModel() {
+    return panelModel_;
+  }
+
+  /**
+   * Set <code>PanelModel</code>.
+   * @param panelModel PanelModel
+   */
+  public void setPanelModel(PanelModel panelModel) {
+    panelModel_ = panelModel;
+    if(panelModel_ != null) {
+      panelModel_.setBatch(true);
+      pmc.setObject(panelModel_);
+    }
+  }
+
+  void openFileMI_actionPerformed(ActionEvent e) {
+    PanelModel pModel = null;
+    File file;
+    String ext;
+    String[] xmlFile = new String[]{".xml"};
+    SimpleFileFilter xmlFilt = new SimpleFileFilter(xmlFile, "XML Serialized Bean");
+
+    if(fileChooser_ == null) {
+      fileChooser_ = new JFileChooser();
+    }
+    fileChooser_.setFileFilter(fileChooser_.getAcceptAllFileFilter());
+    fileChooser_.resetChoosableFileFilters();
+    fileChooser_.addChoosableFileFilter(xmlFilt);
+    fileChooser_.setFileFilter(xmlFilt);
+
+    int result = fileChooser_.showOpenDialog(this);
+    if(result == JFileChooser.APPROVE_OPTION) {
+      file = fileChooser_.getSelectedFile();
+      openPath_ = file.getPath();
+      setTitle(title_ + ": " + openPath_);
+      try {
+        pModel = PanelModel.loadFromXML(new BufferedInputStream(
+                           new FileInputStream(openPath_)));
+        setPanelModel(pModel);
+       } catch (FileNotFoundException fnfe) {
+        JOptionPane.showMessageDialog(this, "Error openning file",
+                                      "File Open Error", JOptionPane.ERROR_MESSAGE);
+      } catch (InvalidObjectException ioe) {
+        JOptionPane.showMessageDialog(this, "File does not contain a PanelModel",
+                                       "PanelModel Not Found",
+                                       JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  void saveAsFileMI_actionPerformed(ActionEvent e) {
+    File file;
+    FileFilter filt;
+    String ext;
+    String outpath;
+    String[] xmlFile = new String[]{".xml"};
+    SimpleFileFilter xmlFilt = new SimpleFileFilter(xmlFile, "XML Serialized Bean");
+
+    if(fileChooser_ == null) {
+      fileChooser_ = new JFileChooser();
+    }
+    fileChooser_.setFileFilter(fileChooser_.getAcceptAllFileFilter());
+    fileChooser_.resetChoosableFileFilters();
+    fileChooser_.addChoosableFileFilter(xmlFilt);
+    fileChooser_.setFileFilter(xmlFilt);
+
+    int result = fileChooser_.showSaveDialog(this);
+    if(result == JFileChooser.APPROVE_OPTION) {
+      file = fileChooser_.getSelectedFile();
+      filt = fileChooser_.getFileFilter();
+      outpath = file.getPath();
+      if(filt instanceof SimpleFileFilter) {
+        ext = ((SimpleFileFilter)filt).getExtension();
+        String name = file.getName().toLowerCase();
+        if(!name.endsWith(ext)) {
+          outpath += ext;
+        }
+      }
+      if(new File(outpath).exists()) {
+        JOptionPane.showMessageDialog(this, "File already exists, rename and try again",
+                                      "File Save Error", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+      try {
+        panelModel_.saveToXML(new BufferedOutputStream(
+                                       new FileOutputStream(outpath, false)));
+      } catch (FileNotFoundException fnfe) {
+        JOptionPane.showMessageDialog(this, "Error creating file, rename and try again",
+                                      "File Save Error", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+  }
+
+  void saveFileMI_actionPerformed(ActionEvent e) {
+    if(openPath_ == null) return;
+    try {
+      panelModel_.saveToXML(new BufferedOutputStream(
+                                     new FileOutputStream(openPath_, false)));
+    } catch (FileNotFoundException fnfe) {
+      JOptionPane.showMessageDialog(this, "Error creating file, rename and try again",
+                                    "File Save Error", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+  }
+
+  void exitFileMI_actionPerformed(ActionEvent e) {
+    throwClosing = false;
+    pmf_windowClosing(null);
+  }
+
+  void newFileMI_actionPerformed(ActionEvent e) {
+    setPanelModel(new PanelModel());
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif
new file mode 100755
index 0000000..5fe6cc0
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelIcon16.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif
new file mode 100755
index 0000000..6dfe217
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelIcon32.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelPropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelPropertyPanel.java
new file mode 100755
index 0000000..0be71a2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PanelModelPropertyPanel.java
@@ -0,0 +1,250 @@
+/*
+ * $Id: PanelModelPropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import javax.swing.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import gov.noaa.pmel.sgt.swing.prop.ColorDialog;
+import gov.noaa.pmel.sgt.AbstractPane;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+class PanelModelPropertyPanel extends PropertyPanel implements PropertyChangeListener, ActionListener {
+  private boolean expert_ = false;
+  private PanelModel pModel_ = null;
+  private String[] pNames_ = {"DPI", "Page Color", "Page Size", "Panels",
+                              "Print Borders",
+    "Print HAlign", "Print Origin", "Print Scale Mode", "Print VAlign",
+    "Print White"};
+  private JComponent[] comps_ = new JComponent[pNames_.length];
+  private String[] vAlignItems = {"Top", "Middle", "Bottom", "Specified Location"};
+  private String[] hAlignItems = {"Left", "Center", "Right", "Specified Location"};
+  private String[] sModeItems = {"Default", "To Fit", "Shrink To Fit"};
+
+  public PanelModelPropertyPanel(PanelModel pm) {
+    super();
+    pModel_ = pm;
+    pModel_.addPropertyChangeListener(this);
+
+    create();
+  }
+
+  public void propertyChange(PropertyChangeEvent evt) {
+    update();
+  }
+
+  void create() {
+    int i = -1;
+    int item = -1;
+    comps_[++i] = createLabel(Float.toString(pModel_.getDpi()));
+    comps_[++i] = createColor(pModel_.getPageBackgroundColor(), pNames_[i], this);
+    comps_[++i] = createTextField(format(pModel_.getPageSize(), false),pNames_[i], this, true);
+    comps_[++i] = createLabel(pModel_.getPanelCount());
+    comps_[++i] = createCheckBox(pModel_.isPrintBorders(), pNames_[i], this);
+    switch(pModel_.getPrintHAlign()) {
+      case AbstractPane.LEFT:
+        item = 0;
+        break;
+      default:
+      case AbstractPane.CENTER:
+        item = 1;
+        break;
+      case AbstractPane.RIGHT:
+        item = 2;
+        break;
+      case AbstractPane.SPECIFIED_LOCATION:
+        item = 3;
+        break;
+    }
+    comps_[++i] = createComboBox(hAlignItems, item, pNames_[i], this, true);
+    comps_[++i] = createTextField(format(pModel_.getPrintOrigin(), false), pNames_[i], this, true);
+    switch(pModel_.getPrintScaleMode()) {
+      default:
+      case AbstractPane.DEFAULT_SCALE:
+        item = 0;
+        break;
+      case AbstractPane.TO_FIT:
+        item = 1;
+        break;
+      case AbstractPane.SHRINK_TO_FIT:
+        item = 2;
+        break;
+    }
+    comps_[++i] = createComboBox(sModeItems, item, pNames_[i], this, true);
+    switch(pModel_.getPrintVAlign()) {
+      default:
+      case AbstractPane.TOP:
+        item = 0;
+        break;
+      case AbstractPane.MIDDLE:
+        item = 1;
+        break;
+      case AbstractPane.BOTTOM:
+        item = 2;
+        break;
+      case AbstractPane.SPECIFIED_LOCATION:
+        item = 3;
+        break;
+    }
+    comps_[++i] = createComboBox(vAlignItems, item, pNames_[i], this, true);
+    comps_[++i] = createCheckBox(pModel_.isPrintWhitePage(), pNames_[i], this);
+    for(i=0; i < comps_.length; i++) {
+      addProperty(i+1, pNames_[i], comps_[i], false);
+    }
+    addProperty(comps_.length + 1, " ", new JLabel(" "), true);
+  }
+
+  void update() {
+    int i = -1;
+    int item = -1;
+    ((JLabel)comps_[++i]).setText(Float.toString(pModel_.getDpi()));
+    updateColor((JButton)comps_[++i], pModel_.getPageBackgroundColor());
+    ((JTextField)comps_[++i]).setText(format(pModel_.getPageSize(), false));
+    ((JLabel)comps_[++i]).setText(Integer.toString(pModel_.getPanelCount()));
+    ((JCheckBox)comps_[++i]).setSelected(pModel_.isPrintBorders());
+    switch(pModel_.getPrintHAlign()) {
+      case AbstractPane.LEFT:
+        item = 0;
+        break;
+      default:
+      case AbstractPane.CENTER:
+        item = 1;
+        break;
+      case AbstractPane.RIGHT:
+        item = 2;
+        break;
+      case AbstractPane.SPECIFIED_LOCATION:
+        item = 3;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JTextField)comps_[++i]).setText(format(pModel_.getPrintOrigin(), false));
+    switch(pModel_.getPrintScaleMode()) {
+      default:
+      case AbstractPane.DEFAULT_SCALE:
+        item = 0;
+        break;
+      case AbstractPane.TO_FIT:
+        item = 1;
+        break;
+      case AbstractPane.SHRINK_TO_FIT:
+        item = 2;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    switch(pModel_.getPrintVAlign()) {
+      default:
+      case AbstractPane.TOP:
+        item = 0;
+        break;
+      case AbstractPane.MIDDLE:
+        item = 1;
+        break;
+      case AbstractPane.BOTTOM:
+        item = 2;
+        break;
+      case AbstractPane.SPECIFIED_LOCATION:
+        item = 3;
+        break;
+    }
+    ((JComboBox)comps_[++i]).setSelectedIndex(item);
+    ((JCheckBox)comps_[++i]).setSelected(pModel_.isPrintWhitePage());
+  }
+
+  private void processEvent(Object obj, String command) {
+    String str;
+    int item = -1;
+    if(command.equals("Page Size")) {
+      Dimension size = parseDimension(((JTextField)obj).getText());
+      pModel_.setPageSize(size);
+      if(pModel_.getPage() != null) pModel_.getPage().setSize(size);
+   } else if(command.equals("Page Color")) {
+     ColorDialog cd = new ColorDialog(getFrame(), "Select Axis Color", true);
+     cd.setColor(pModel_.getPageBackgroundColor());
+     cd.setVisible(true);
+     Color newcolor = cd.getColor();
+     if(newcolor != null) {
+       pModel_.setPageBackgroundColor(newcolor);
+       updateColor((JButton)obj, newcolor);
+     }
+   } else if(command.equals("Print Borders")) {
+     pModel_.setPrintBorders(((JCheckBox)obj).isSelected());
+   } else if(command.equals("Print HAlign")) {
+     str = (String)((JComboBox)obj).getSelectedItem();
+     item = -1;
+     if(str.equals("Left")) {
+       item = AbstractPane.LEFT;
+     } else if(str.equals("Center")) {
+       item = AbstractPane.CENTER;
+     } else if(str.equals("Right")) {
+       item = AbstractPane.RIGHT;
+     } else if(str.equals("Specified Location")) {
+       item = AbstractPane.SPECIFIED_LOCATION;
+     }
+     pModel_.setPrintHAlign(item);
+   } else if(command.equals("Print Origin")) {
+     Point pt = parsePoint(((JTextField)obj).getText());
+     if(pt != null) pModel_.setPrintOrigin(pt);
+
+   } else if(command.equals("Print Scale Mode")) {
+     str = (String)((JComboBox)obj).getSelectedItem();
+     item = -1;
+     if(str.equals("Default")) {
+       item = AbstractPane.DEFAULT_SCALE;
+     } else if(str.equals("To Fit")) {
+       item = AbstractPane.TO_FIT;
+     } else if(str.equals("Shrink To Fit")) {
+       item = AbstractPane.SHRINK_TO_FIT;
+     }
+     pModel_.setPrintScaleMode(item);
+   } else if(command.equals("Print VAlign")) {
+     str = (String)((JComboBox)obj).getSelectedItem();
+     item = -1;
+     if(str.equals("Top")) {
+       item = AbstractPane.TOP;
+     } else if(str.equals("Middle")) {
+       item = AbstractPane.MIDDLE;
+     } else if(str.equals("Bottom")) {
+       item = AbstractPane.BOTTOM;
+     } else if(str.equals("Specified Location")) {
+       item = AbstractPane.SPECIFIED_LOCATION;
+     }
+     pModel_.setPrintVAlign(item);
+   } else if(command.equals("Print White")) {
+     pModel_.setPrintWhitePage(((JCheckBox)obj).isSelected());
+   }
+  }
+
+  void resetFields() {  }
+
+  public void setExpert(boolean expert) {
+    expert_ = expert;
+  }
+
+  public boolean isExpert() {
+    return expert_;
+  }
+  public void actionPerformed(ActionEvent e) {
+    Object obj = e.getSource();
+    String command = e.getActionCommand();
+    processEvent(obj, command);
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PropertyPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PropertyPanel.java
new file mode 100755
index 0000000..6968565
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/PropertyPanel.java
@@ -0,0 +1,439 @@
+/*
+ * $Id: PropertyPanel.java,v 1.1.1.1 2007/09/07 06:32:02 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.beans;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusListener;
+import java.util.EventListener;
+import java.util.Vector;
+import java.text.DecimalFormat;
+import java.util.StringTokenizer;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.sgt.swing.ColorSwatchIcon;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:02 $
+ * @since 3.0
+ **/
+abstract class PropertyPanel extends JComponent implements DesignListener {
+  private PanelHolder pHolder_ = null;
+  private JLabel jLabel1 = new JLabel();
+  private JLabel jLabel3 = new JLabel();
+  private GridBagLayout gridBagLayout1 = new GridBagLayout();
+  private Font hdrFont_ = new Font("Dialog", 1, 9);
+  private Font textFont_ = new Font("Dialog", 0, 9);
+  private Insets lInset = new Insets(2, 1, 1, 3);
+  private Insets rInset = new Insets(2, 3, 1, 1);
+  private static DecimalFormat numberFormat_ = new DecimalFormat("#.##");
+  private String dateFormat_ = "yyyy-MM-dd hh:mm";
+
+  public PropertyPanel() {
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  private void jbInit() throws Exception {
+    jLabel1.setText("Property");
+    jLabel1.setFont(hdrFont_);
+    jLabel1.setForeground(Color.black);
+    jLabel1.setHorizontalAlignment(SwingConstants.RIGHT);
+    this.setLayout(gridBagLayout1);
+    jLabel3.setText("Value");
+    jLabel3.setFont(hdrFont_);
+    jLabel3.setForeground(Color.black);
+    this.add(jLabel1,          new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, lInset, 5, 5));
+    this.add(jLabel3,       new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, rInset, 10, 5));
+  }
+
+  abstract void resetFields();
+
+  public void reset() {
+    this.removeAll();
+    resetFields();
+    try {
+      jbInit();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    create();
+    revalidate();
+  }
+
+  protected void addProperty(int row, String propertyName, JComponent component, boolean last) {
+    double weighty;
+    int left, right;
+    JLabel label = new JLabel(propertyName);
+    label.setHorizontalAlignment(SwingConstants.RIGHT);
+    label.setFont(textFont_);
+    component.setFont(textFont_);
+    if(last) {
+      weighty = 1.0;
+      left = GridBagConstraints.NORTHEAST;
+      right = GridBagConstraints.NORTHWEST;
+    } else {
+      weighty = 0.0;
+      left = GridBagConstraints.EAST;
+      right = GridBagConstraints.WEST;
+    }
+    this.add(label, new GridBagConstraints(0, row, 1, 1, 0.0, weighty,
+        left, GridBagConstraints.BOTH, lInset, 5, 5));
+    this.add(component, new GridBagConstraints(1, row, 1, 1, 1.0, weighty,
+        right, GridBagConstraints.HORIZONTAL, rInset, 5, 5));
+  }
+
+  abstract void update();
+  abstract void create();
+
+  protected JTextField createTextField(String text,
+                                       String action, EventListener listen,
+                                       boolean edit) {
+    JTextField tf = new JTextField(text);
+    tf.setActionCommand(action);
+    tf.setName(action);
+    tf.setEditable(edit);
+    if(listen != null) {
+      if(listen instanceof ActionListener) tf.addActionListener((ActionListener)listen);
+      if(listen instanceof FocusListener) tf.addFocusListener((FocusListener)listen);
+    }
+    return tf;
+  }
+
+  protected JLabel createLabel(String text) {
+    JLabel jl = new JLabel(text);
+    return jl;
+  }
+
+  protected JLabel createLabel(int value) {
+    return new JLabel(Integer.toString(value));
+  }
+
+  protected JCheckBox createCheckBox(boolean value,
+                                     String action, ActionListener listen) {
+    JCheckBox cb = new JCheckBox("", value);
+    cb.setHorizontalTextPosition(SwingConstants.LEFT);
+    cb.setActionCommand(action);
+    if(listen != null) cb.addActionListener(listen);
+    return cb;
+  }
+
+  protected JComboBox createComboBox(Vector list, int item,
+                                     String action, ActionListener listen,
+                                     boolean edit) {
+    return createComboBox(list.toArray(), item, action, listen, edit);
+  }
+
+  protected JComboBox createComboBox(Object[] list, int item,
+                                     String action, ActionListener listen,
+                                     boolean edit) {
+    JComboBox cb = new JComboBox(list);
+    cb.setSelectedIndex(item);
+    cb.setActionCommand(action);
+    cb.setEditable(edit);
+    cb.setEnabled(edit);
+    if(listen != null) cb.addActionListener(listen);
+    return cb;
+  }
+
+  protected JButton createSGLabel(SGLabel value,
+                                String action, ActionListener listen) {
+    if(value == null) return new JButton("null");
+    JButton jb = new JButton(value.getText());
+    jb.setFont(value.getFont());
+    jb.setForeground(value.getColor());
+//  jb.setHorizontalTextPosition(SwingConstants.LEFT);
+    jb.setActionCommand(action);
+    if(listen != null) jb.addActionListener(listen);
+    return jb;
+  }
+
+  protected Point2D.Double parsePoint2D(String value) {
+    StringTokenizer tok = new StringTokenizer(value, ",\t\n\r\f");
+    if(tok.countTokens() != 2) {
+      JOptionPane.showMessageDialog(this, "Four values required", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    double x = Double.parseDouble(tok.nextToken().trim());
+    double y = Double.parseDouble(tok.nextToken().trim());
+    return new Point2D.Double(x, y);
+  }
+
+  protected Point parsePoint(String value) {
+    StringTokenizer tok = new StringTokenizer(value, ",\t\n\r\f");
+    if(tok.countTokens() != 2) {
+      JOptionPane.showMessageDialog(this, "Two values required", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    int x = Integer.parseInt(tok.nextToken().trim());
+    int y = Integer.parseInt(tok.nextToken().trim());
+    return new Point(x, y);
+  }
+
+  protected Dimension parseDimension(String value) {
+    StringTokenizer tok = new StringTokenizer(value, ",\t\n\r\f");
+    if(tok.countTokens() != 2) {
+      JOptionPane.showMessageDialog(this, "Two values required", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    int width = Integer.parseInt(tok.nextToken().trim());
+    int height = Integer.parseInt(tok.nextToken().trim());
+    return new Dimension(width, height);
+  }
+
+  protected Rectangle2D parseBounds(String value) {
+    StringTokenizer tok = new StringTokenizer(value, ",\t\n\r\f");
+    if(tok.countTokens() != 4) {
+      JOptionPane.showMessageDialog(this, "Four values required", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    double x = Double.parseDouble(tok.nextToken().trim());
+    double y = Double.parseDouble(tok.nextToken().trim());
+    double width = Double.parseDouble(tok.nextToken().trim());
+    double height = Double.parseDouble(tok.nextToken().trim());
+    return new Rectangle2D.Double(x, y, width, height);
+  }
+
+  protected SoTRange parseRange(String value, boolean isTime) {
+    StringTokenizer tok = new StringTokenizer(value, ",\t\n\r\f");
+    if(tok.countTokens() != 3) {
+      JOptionPane.showMessageDialog(this, "Three values required", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    SoTRange range = null;
+    if(isTime) {
+//      String format = "yyyy-MM-dd hh:mm";
+      try {
+        GeoDate start = new GeoDate(tok.nextToken().trim(), dateFormat_);
+        GeoDate end = new GeoDate(tok.nextToken().trim(), dateFormat_);
+        long dlta = Long.parseLong(tok.nextToken().trim())*86400000;
+        GeoDate delta = new GeoDate(dlta);
+        range = new SoTRange.Time(start, end, delta);
+      } catch (IllegalTimeValue itv) {
+        JOptionPane.showMessageDialog(this, "Illegal Time Value", "Illegal Response", JOptionPane.ERROR_MESSAGE);
+        return null;
+      }
+    } else {
+      double start = Double.parseDouble(tok.nextToken().trim());
+      double end = Double.parseDouble(tok.nextToken().trim());
+      double delta  = Double.parseDouble(tok.nextToken().trim());
+      range = new SoTRange.Double(start, end, delta);
+    }
+    return range;
+  }
+
+  protected String colorString(Color value) {
+    StringBuffer sbuf = new StringBuffer("[");
+    sbuf.append(value.getRed()).append(", ");
+    sbuf.append(value.getGreen()).append(", ");
+    sbuf.append(value.getRed());
+    if(value.getAlpha() == 255) {
+      sbuf.append("]");
+    } else {
+      sbuf.append(", ").append(value.getAlpha()).append("]");
+    }
+    return sbuf.toString();
+  }
+
+  protected JButton createColor(Color value,
+                                String action, ActionListener listen) {
+    Icon icon = new ColorSwatchIcon(value, 32, 20);
+    JButton jb = new JButton(colorString(value), icon);
+    jb.setActionCommand(action);
+    if(listen != null) jb.addActionListener(listen);
+    return jb;
+  }
+
+  protected void updateColor(JButton comp, Color value) {
+    comp.setText(colorString(value));
+    Icon icon = new ColorSwatchIcon(value, 32, 20);
+    comp.setIcon(icon);
+  }
+
+  protected JButton createFont(Font value,
+                                String action, ActionListener listen) {
+    JButton jb = new JButton(value.getName());
+    jb.setFont(value);
+//  jb.setHorizontalTextPosition(SwingConstants.LEFT);
+    jb.setActionCommand(action);
+    if(listen != null) jb.addActionListener(listen);
+    return jb;
+  }
+
+  protected void updateFont(JButton comp, Font value) {
+    comp.setText(value.getName());
+    comp.setFont(value);
+  }
+  protected void updateSGLabel(JButton comp, SGLabel value) {
+    comp.setFont(value.getFont());
+    comp.setText(value.getText());
+    comp.setForeground(value.getColor());
+  }
+
+  protected String format(Point val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(format(val.x)).append(", ");
+    buf.append(format(val.y));
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(Dimension val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(format(val.width)).append(", ");
+    buf.append(format(val.height));
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(Rectangle2D.Double val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(format(val.x)).append(", ");
+    buf.append(format(val.y)).append(", ");
+    buf.append(format(val.width)).append(", ");
+    buf.append(format(val.height));
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(Point2D.Double val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(format(val.x)).append(", ");
+    buf.append(format(val.y));
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(Range2D val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(format(val.start)).append(", ");
+    buf.append(format(val.end)).append(", ");
+    buf.append(format(val.delta));
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(SoTRange.Double val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(format(val.start)).append(", ");
+    buf.append(format(val.end)).append(", ");
+    buf.append(format(val.delta));
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(SoTRange.Time val, boolean brackets) {
+    StringBuffer buf = new StringBuffer();
+    if(brackets) buf.append("[");
+    buf.append(val.getStart().toString()).append(", ");
+    buf.append(val.getEnd().toString()).append(", ");
+    buf.append(Long.toString(val.getDelta().getLongTime()/86400000)); // days
+    if(brackets) buf.append("]");
+    return buf.toString();
+  }
+
+  protected String format(SoTRange val, boolean brackets) {
+    if(val instanceof SoTRange.Float) {
+      return format((SoTRange.Float)val, brackets);
+    } else if(val instanceof SoTRange.Double) {
+      return format((SoTRange.Double)val, brackets);
+    } else if(val instanceof SoTRange.Time) {
+      return format((SoTRange.Time)val, brackets);
+    }
+    return "";
+  }
+
+  protected String format(SoTPoint val, boolean brackets) {
+    if(val == null) return "null";
+    return val.toString();
+  }
+
+  protected String format(float value) {
+    return numberFormat_.format(value);
+  }
+
+  protected String format(float value, DecimalFormat format) {
+    return format.format(value);
+  }
+
+  protected String format(double value, DecimalFormat format) {
+    return format.format(value);
+  }
+
+  protected String format(double value) {
+    DecimalFormat format = new DecimalFormat("#.##");
+    return format.format(value);
+  }
+
+  protected void paintBorder(Graphics g) {
+    int x0=0, x1=0, x2=0;
+    int y;
+    int y1=0;
+    int y0=0;
+
+    Component[] comps = getComponents();
+
+    for(int i=0;  i < comps.length;i += 2) {
+      if(i == 0) {
+        x0 = comps[0].getBounds().x - lInset.left;
+        x1 = comps[0].getBounds().x + comps[0].getBounds().width + lInset.right;
+        x2 = comps[1].getBounds().x + comps[1].getBounds().width;
+        y0 = comps[0].getBounds().y - lInset.top;
+      }
+      y = comps[i].getBounds().y - lInset.top;
+      if(i >= comps.length - 2) {
+        y1 = y;
+      }
+      g.drawLine(0, y, x2, y);
+    }
+    g.drawLine(x0, y0, x0, y1);
+    g.drawLine(x1, y0, x1, y1);
+    g.drawLine(x2, y0, x2, y1);
+  }
+
+  public String toString() {
+    return getClass().getName() + '@' + Integer.toHexString(hashCode());
+  }
+
+  Frame getFrame() {
+    Window fr = javax.swing.SwingUtilities.getWindowAncestor(this);
+    if(fr != null && fr instanceof Frame) {
+      return (Frame)fr;
+    }
+    return null;
+  }
+
+  abstract public void setExpert(boolean expert);
+  abstract public boolean isExpert();
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignBottom24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignBottom24.gif
new file mode 100755
index 0000000..62e921d
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignBottom24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignCenter24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignCenter24.gif
new file mode 100755
index 0000000..f19d8ed
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignCenter24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignJustifyHorizontal24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignJustifyHorizontal24.gif
new file mode 100755
index 0000000..32a1070
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignJustifyHorizontal24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignJustifyVertical24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignJustifyVertical24.gif
new file mode 100755
index 0000000..f5d4a00
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignJustifyVertical24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif
new file mode 100755
index 0000000..4db364c
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignLeft24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignRight24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignRight24.gif
new file mode 100755
index 0000000..9c82ad4
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignRight24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignTop24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignTop24.gif
new file mode 100755
index 0000000..8fd07a2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/AlignTop24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/DataModelSimple.png b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/DataModelSimple.png
new file mode 100755
index 0000000..dae8b72
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/DataModelSimple.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Edit24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Edit24.gif
new file mode 100755
index 0000000..a5af7d7
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Edit24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/New24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/New24.gif
new file mode 100755
index 0000000..1cc488d
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/New24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewDataGroup24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewDataGroup24.gif
new file mode 100755
index 0000000..db272f7
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewDataGroup24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewLabel24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewLabel24.gif
new file mode 100755
index 0000000..60589ed
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewLabel24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewLegend24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewLegend24.gif
new file mode 100755
index 0000000..57bfaf8
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/NewLegend24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Open24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Open24.gif
new file mode 100755
index 0000000..2086bc2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Open24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/PanelModelSimple.png b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/PanelModelSimple.png
new file mode 100755
index 0000000..b2cc5dd
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/PanelModelSimple.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Preferences24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Preferences24.gif
new file mode 100755
index 0000000..2e727b2
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Preferences24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Remove24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Remove24.gif
new file mode 100755
index 0000000..fa40604
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Remove24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/RunTimeSimple.png b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/RunTimeSimple.png
new file mode 100755
index 0000000..d90a4eb
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/RunTimeSimple.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Save24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Save24.gif
new file mode 100755
index 0000000..bfa98a8
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/Save24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/SaveAs24.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/SaveAs24.gif
new file mode 100755
index 0000000..97eb6fa
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/images/SaveAs24.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/package.html
new file mode 100755
index 0000000..6b00eda
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/beans/package.html
@@ -0,0 +1,20 @@
+<HTML>
+<BODY>
+Classes and interfaces that make up SGT Beans. The classes
+<code>Page</code>, <code>DataModel</code>, and <code>PanelModel</code>
+are the core bean classes. Classes that extend
+<code>PropertyPanel</code> or <code>DragBox</code> are used with both
+<code>PanelModelCustomizer</code> (called from IDE's) and
+<code>PanelModelEditor</code> (designed to be called from users
+code).
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Contour.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Contour.java
new file mode 100755
index 0000000..1b3ee26
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Contour.java
@@ -0,0 +1,913 @@
+/*
+ * $Id: Contour.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.contour;
+
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.ContourLineAttribute;
+import gov.noaa.pmel.sgt.DefaultContourLineAttribute;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.LayerNotFoundException;
+import gov.noaa.pmel.sgt.ContourLevels;
+import gov.noaa.pmel.sgt.ContourLevelNotFoundException;
+
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Contour constructs a set of <code>ContourLine</code> objects based on
+ * the <code>ContourLevels</code>, <code>SGTGrid</code>, and mask
+ * supplied. Used by
+ * <code>GridCartesianRenderer</code> for <code>GridAttribute</code>
+ * types of CONTOUR.
+ *
+ * @author D. W. Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ * @see ContourLine
+ * @see ContourLevels
+ * @see gov.noaa.pmel.sgt.GridCartesianRenderer
+ * @see gov.noaa.pmel.sgt.GridAttribute
+ * @see ContourLineAttribute
+ * @see DefaultContourLineAttribute
+ */
+public class Contour implements PropertyChangeListener {
+  /**
+   * @label grid 
+   */
+  private SGTGrid grid_;
+  /**
+   * A non-zero mask value will cause a point to be excluded.
+   * @label mask
+   */
+  private SGTGrid mask_;
+  private CartesianGraph cg_;
+  /**
+   * @label contourLevels 
+   */
+  private ContourLevels contourLevels_;
+  private double zmin_;
+  private double zmax_;
+  private boolean upToDate_;
+  private GeoDate tref_ = null;
+  private boolean xTime_ = false;
+  private boolean yTime_ = false;
+  private double[] px_;
+  private double[] py_;
+  private double[] z_;
+  private double[] xx_;
+  private double[] yy_;
+  private double[] zz_;
+  private boolean[] used_;
+  private int[] kabov_;
+  private int[] isin_ = {0, 1, 0, -1};
+  private double weezee_;
+  private int nx_;
+  private int ny_;
+
+  /**
+   * @associates <oiref:gov.noaa.pmel.sgt.contour.ContourLine:oiref>
+   * @link aggregation
+   * @supplierCardinality 1..* 
+   * @label contourLines
+   */
+  private Vector contourLines_;
+
+  /**
+   * @link aggregationByValue
+   * @supplierCardinality 1
+   * @label sides
+   */
+  private Sides sides_;
+
+  /**
+   * @link aggregationByValue
+   * @supplierCardinality 1 
+   * @label gridFlag
+   */
+  private GridFlag gridFlag_;
+  //
+  private static double DSLAB = 2.0;
+  private static double SLAB1F = 0.4;
+  /**
+   * Construct a <code>Contour</code> object using a range to define
+   * the <code>ContourLevels</code>.
+   */
+  public Contour(CartesianGraph cg, SGTGrid grid, Range2D range) {
+    cg_ = cg;
+    grid_ = grid;
+    contourLevels_ = ContourLevels.getDefault(range);
+    init();
+    upToDate_ = false;
+  }
+  /**
+   * Construct a <code>Contour</code> object using an array of levels to define
+   * the <code>ContourLevels</code>.
+   */
+  public Contour(CartesianGraph cg, SGTGrid grid, double[] levels) {
+    cg_ = cg;
+    grid_ = grid;
+    contourLevels_ = ContourLevels.getDefault(levels);
+    init();
+    upToDate_ = false;
+  }
+
+  /**
+   * Construct a <code>Contour</code> object using a
+   * <code>ContourLevels</code> object.
+   */
+  public Contour(CartesianGraph cg, SGTGrid grid, ContourLevels conLevels) {
+    cg_ = cg;
+    grid_ = grid;
+    contourLevels_ = conLevels;
+    contourLevels_.addPropertyChangeListener(this);
+    init();
+    upToDate_ = false;
+  }
+  /**
+   * Get a reference to the <code>ContourLevels</code> object.
+   */
+  public ContourLevels getContourLevels() {
+    return contourLevels_;
+  }
+  /**
+   * Set a <code>SGTGrid</code> object to be used to mask the data
+   * grid.  The Z values are used to determine the masking, values of
+   * NaN and non-zero are set as MISSING.
+   */
+  public void setMask(SGTGrid mask) {
+    if(mask_ == null || !mask_.equals(mask)) upToDate_ = false;
+    mask_ = mask;
+  }
+  /**
+   * Get the mask.
+   */
+  public SGTGrid getMask() {
+    return mask_;
+  }
+  /**
+   * Return the <code>Enumeration</code> of a <code>Vector</code>
+   * containing the <code>ContourLine</code> objects.
+   */
+  public Enumeration elements() {
+    if(!upToDate_) generateContourLines();
+    return contourLines_.elements();
+  }
+  /**
+   * Reponds to changes in the <code>ContourLevels</code> object.
+   */
+  public void propertyChange(PropertyChangeEvent event) {
+  }
+
+  private void init() {
+    GeoDate[] ttemp;
+    if(grid_.isXTime()) {
+      xTime_ = true;
+      ttemp = grid_.getTimeArray();
+      tref_ = ttemp[0];
+      px_ = getTimeOffsetArray(ttemp, tref_);
+      nx_ = grid_.getTSize();
+    } else {
+      px_ = grid_.getXArray();
+      nx_ = grid_.getXSize();
+    }
+    if(grid_.isYTime()) {
+      yTime_ = true;
+      ttemp = grid_.getTimeArray();
+      tref_ = ttemp[0];
+      py_ = getTimeOffsetArray(ttemp, tref_);
+      ny_ = grid_.getTSize();
+    } else {
+      py_ = grid_.getYArray();
+      ny_ = grid_.getYSize();
+    }
+    if(Debug.CONTOUR) {
+      System.out.println("nx_ = " + nx_ + ", ny_ = " + ny_);
+    }
+    /**
+     *   side definitions
+     *   ________
+     *  |   2    |
+     *  |        |
+     * 3|        |1
+     *  |        |
+     *  |________|
+     *      0
+     */
+    sides_ = new Sides(nx_, ny_);
+    //
+    // make the corner arrays index from 0 to 3
+    //
+    xx_ = new double[4];
+    yy_ = new double[4];
+    zz_ = new double[4];
+    used_ = new boolean[4];
+    kabov_ = new int[4];
+    z_ = grid_.getZArray();
+  }
+
+  private double[] getTimeOffsetArray(GeoDate[] tarray, GeoDate tref) {
+    double[] array = new double[tarray.length];
+    for(int i=0; i < tarray.length; i++) {
+      array[i] = tarray[i].offset(tref);
+    }
+    return array;
+  }
+
+  private GeoDate[] getTimeArray(double[] array, GeoDate tref) {
+    GeoDate[] tarray = new GeoDate[array.length];
+    for(int i=0; i < array.length; i++) {
+      tarray[i] = new GeoDate(tref);
+      tarray[i].increment(array[i], GeoDate.DAYS);
+    }
+    return tarray;
+  }
+  /**
+   * Given the current <code>ContourLevels</code>, mask, and
+   * <code>SGTGrid</code> generate the <code>ContourLine</code>s.
+   */
+  public void generateContourLines() {
+    double zrange;
+    double zc;
+    int kabij, kabip1, kabjp1;
+    int used0, used3;
+    int ll;
+    int i=0;
+    int j=0;
+    int ii, jj;
+    ContourLine cl;
+    int lin, k, kmax, nseg;
+    boolean reversed;
+    double xt, yt, frac;
+    double flm1, flp1;
+    int lp1, lp2, lm1;
+    int kda, kdb;
+    int exit;
+
+    if(upToDate_) return;
+
+    contourLines_ = new Vector();
+    upToDate_ = true;
+    computeMinMax();
+    //
+    // compute a small non-zero value for testing
+    //
+    zrange = (zmax_ - zmin_)*1.1;
+    if(zrange <= 0.0) return;
+    weezee_ = zrange*0.0002;
+    //
+    // loop over all contour levels
+    //
+    Enumeration lenum = contourLevels_.levelElements();
+    while(lenum.hasMoreElements()) {
+      //
+      // initialize for level
+      //
+      zc = ((Double)lenum.nextElement()).doubleValue();
+      if(Debug.CONTOUR) {
+				System.out.println("zc = " + zc);
+      }
+      if(zc <= zmin_ || zc >= zmax_) continue;
+      sides_.clear();
+      if(mask_ != null) {
+        gridFlag_ = new GridFlag(grid_, mask_, zc);
+      } else {
+        gridFlag_ = new GridFlag(grid_, zc);
+      }
+      for(ii=0; ii < nx_; ii++) {    /* 1001 */
+      loop1000:
+        for(jj=0; jj < ny_; jj++) {  /* 1000 */
+          i = ii;
+          j = jj;
+          kabij = gridFlag_.getValue(i, j);
+	  if(i < nx_-1) {
+	    kabip1 = gridFlag_.getValue(i+1, j);
+	  } else {
+	    kabip1 = 10;
+	  }
+	  if(j < ny_-1) {
+	    kabjp1 = gridFlag_.getValue(i, j+1);
+	  } else {
+	    kabjp1 = 10;
+	  }
+          used0 = sides_.getSide(i, j, 0);
+          used3 = sides_.getSide(i, j, 3);
+          ll=0;   /*  bottom side */
+          if(kabij + kabip1 + used0 == 0) {
+	    computeCorners(i, j, zc);
+	  } else if(kabij + kabjp1 + used3 == 0) {
+            ll=3;  /*  left side */
+	    computeCorners(i, j, zc);
+          } else {
+            continue;
+          }
+          //
+          // setup for new contour line
+          //
+          lin = ll;
+          k = 0;
+          nseg = 1;
+          reversed = false;
+          cl = new ContourLine();
+	  try {
+	    cl.setAttributes(contourLevels_.getDefaultContourLineAttribute(), 
+	                     contourLevels_.getContourLineAttribute(zc));
+	  } catch (ContourLevelNotFoundException e) {
+	    System.out.println(e);
+	  }
+	  cl.setLevel(zc);
+	  cl.setCartesianGraph(cg_);
+	  cl.setTime(tref_, xTime_, yTime_);
+          contourLines_.addElement(cl);  /* add to list */
+          cl.addPoint(0.0, 0.0);  /* dummy k=1 point */
+	  //
+	  // Given entrance to square(i,j) on side lin, 
+	  // record the entrance point x(k), y(k). 
+	  // Set lin to used
+	  //
+	  //    lin    lp1    lp2    lm1
+	  //   _________________________
+	  //     0      1      2      3
+	  //     1      2      3      0
+	  //     2      3      0      1
+	  //     3      0      1      2
+	  //
+	loop350:
+          while(true) {  /* 350 */
+            lp1 = lin + 1 - ((lin+1)/4)*4;
+            lp2 = lp1 + 1 - ((lp1+1)/4)*4;
+            lm1 = lp2 + 1 - ((lp2+1)/4)*4;
+            if(!reversed) {
+              k = k + 1;
+              frac = (zc - zz_[lin])/(zz_[lp1] - zz_[lin]);
+              xt = xx_[lin] + (xx_[lp1] - xx_[lin])*frac;
+              yt = yy_[lin] + (yy_[lp1] - yy_[lin])*frac;
+              cl.addPoint(xt, yt);
+              sides_.setSideUsed(i, j, lin, true);
+            }
+	    //
+	    // See if an exit exists on side l-1, l+1, or l+2.
+	    // If so choose the one closest to side l. If the
+	    // exit already used terminate x,y.
+	    //
+            reversed = false;
+            exit = lm1;
+            if(kabov_[lin] + kabov_[lm1] == 0) {
+              if(kabov_[lp1] + kabov_[lp2] == 0) {
+                flm1 = (zc - zz_[lin])/(zz_[lm1] - zc);
+                flp1 = (zc - zz_[lp1])/(zz_[lp2] - zc);
+                if(!(used_[lp1] ||
+                     (flm1 <= flp1 && !used_[lm1]))) {
+                  exit = lp1;
+                }
+              }
+            } else {
+              if(kabov_[lp1] + kabov_[lp2] == 0) {
+                exit = lp1;
+              } else {
+                exit = lp2;
+                if(kabov_[lp2] + kabov_[lm1] != 0) { /* 470 */
+                  if(kabov_[lp2] + kabov_[lm1] <= 15) {
+                    kda = lin;
+                    kdb = lp2;
+                    if(kabov_[lp2] > 5) {
+                      kda = lm1;
+                      kdb = lp1;
+                    }
+                    k = k + 1;
+                    frac = (zc - zz_[kda])/(zz_[kdb] - zz_[kda]);
+                    xt = xx_[kda] + (xx_[kdb] - xx_[kda])*frac;
+                    yt = yy_[kda] + (yy_[kdb] - yy_[kda])*frac;
+                    cl.addPoint(xt, yt);
+                  }
+                  if(nseg > 1) {
+                    kmax = k;
+		    //
+		    //       pt(1) = pt(2)
+		    //  pt(kmax+1) = pt(kmax)
+		    //
+                    cl.setElementAt((Point2D.Double)cl.elementAt(1), 0);
+                    cl.addPoint((Point2D.Double)cl.elementAt(k));
+                    cl.setClosed(false);
+		    cl.setKmax(kmax);
+		    continue loop1000;
+                  }
+                  reversed = true;
+                  nseg = 2;
+                  cl.reverseElements(k);
+                  i=ii;
+                  j=jj;
+                  exit = ll;
+		  //
+		  // Find square entered by present exit.
+		  //
+		  //    exit    i     j     lin
+		  //   _________________________
+		  //     0      i    j-1     2
+		  //     1     i+1    j      3
+		  //     2      i    j+1     0
+		  //     3     i-1    j      1
+		  //
+                  i = i + isin_[exit];
+                  j = j + isin_[3-exit];
+                  lin = exit + 2 - ((exit+2)/4)*4;
+                  computeCorners(i, j, zc);
+                  continue loop350;
+                }
+              }
+            }
+            if(used_[exit]) {
+              kmax = k + 1;
+	      //
+	      //     pt(kmax) = pt(2)
+	      //        pt(1) = pt(k)
+	      //   pt(kmax+1) = pt(3)
+	      //
+              cl.addPoint((Point2D.Double)cl.elementAt(1));
+              cl.setElementAt((Point2D.Double)cl.elementAt(k), 0);
+              cl.addPoint((Point2D.Double)cl.elementAt(2));
+              cl.setClosed(true);
+	      cl.setKmax(kmax);
+	      continue loop1000;
+            }
+            i = i + isin_[exit];
+            j = j + isin_[3-exit];
+            lin = exit + 2 - ((exit+2)/4)*4;
+            computeCorners(i, j, zc);
+          } /* 350 */
+        } /* 1000 */
+      } /* 1001 */
+    } /* levels */
+  }
+
+  private void computeCorners(int i, int j, double zc) {
+    int jl, lp1, il;
+    boolean[] used = {false, false, false, false};
+    //
+    // Get xx,yy,zz,kabov for each corner and 
+    // used for each side.
+    //
+    //   lcorner     il    jl    lp1
+    //      0        i     j      1
+    //      1       i+1    j      2
+    //      2       i+1   j+1     3
+    //      3        i    j+1     0
+    //
+    //
+    // lcorner definitions:
+    // (i,j+1) __________ (i+1,j+1)
+    //        |    2     |
+    //        |          |
+    //       3|          |1
+    //        |          |
+    //        |__________|
+    //  (i,j)      0      (i+1,j)
+    //
+    for(int lcorner=0; lcorner < 4; lcorner++) { /* 620 */
+      jl = j + lcorner/2;
+      lp1 = lcorner + 1 - ((lcorner+1)/4)*4;
+      il = i + lp1/2;
+      zz_[lcorner] = Double.NaN;
+      kabov_[lcorner] = 10;
+      if(((il+1)*(nx_-il) > 0) && ((jl+1)*(ny_-jl) > 0) &&
+         (!gridFlag_.isMissing(il, jl))) {
+	used[lcorner] = sides_.isSideUsed(i, j, lcorner);
+        zz_[lcorner] = setZ(z(il, jl), zc);
+        if(zz_[lcorner] < zc) {
+	  kabov_[lcorner] = -1;
+        } else {
+	  kabov_[lcorner] = 1;
+        }
+      }
+      xx_[lcorner] = px_[Math.max(0,Math.min(il,nx_-1))];
+      yy_[lcorner] = py_[Math.max(0,Math.min(jl,ny_-1))];
+    } /* 620 */
+    used_[0] = used[0];
+    used_[1] = used[1];
+    used_[2] = used[2];
+    used_[3] = used[3];
+  }
+
+  private double z(int i, int j) {
+    return z_[j + i*ny_];
+  }
+
+  private double setZ(double z, double zc) {
+    double diff = z - zc;
+    if(Math.abs(diff) < weezee_) {
+      return zc + weezee_ * (diff>0.0?1.0:-1.0);
+    } else {
+      return z;
+    }
+  }
+
+  private void computeMinMax() {
+    double[] grid = grid_.getZArray();
+    double[] mask = null;
+    boolean haveMask = mask_ != null;
+    if(haveMask) mask = mask_.getZArray();
+
+    zmin_ = Double.POSITIVE_INFINITY;
+    zmax_ = Double.NEGATIVE_INFINITY;
+
+    for(int i=0; i < grid.length; i++) {
+      if(!Double.isNaN(grid[i]) &&
+         !(haveMask && (mask[i] == 0.0))) {
+        zmin_ = Math.min(zmin_, grid[i]);
+        zmax_ = Math.max(zmax_, grid[i]);
+      }
+    }
+  }
+  /**
+   * Given the computed <code>ContourLine</code>s and the
+   * <code>ContourLineAttribute</code> generate the contour labels.
+   * Must be only invoked after generateConourLines().
+   */
+  public void generateContourLabels(Graphics g) {
+    int i, j, k, kk, km1, kp1;
+    int nx, ny;
+    double dx, dy, dzdx, dzdy, dzdg;
+    GeoDate tref = null;
+    GeoDate time;
+    double[] x, y, z, s;
+    double dxx, dyy, smax;
+    double space = 0.0;
+    double ark = 1.0;
+    boolean roomFound;
+    double slab1, stest;
+    double width, hgt;
+    double xa, xb, ya, yb, aa, bb, cc, zxy;
+    double xendl, yendl;
+    //    double xst, yst, xstp, ystp;
+    double xlab, ylab, hhgt, angle;
+    SGLabel label;
+    double[] px, py;
+    boolean xIncreasing, yIncreasing;
+    double dlev, cspace;
+    Enumeration elem = contourLines_.elements();
+    ContourLine cl;
+    while(elem.hasMoreElements()) {
+      cl = (ContourLine)elem.nextElement();
+      int kmax = cl.getKmax();
+      int lev = contourLevels_.getIndex(cl.getLevel());
+      if(Debug.CONTOUR) {
+	//      System.out.println("drawLabelContourLine: lev = " + lev +
+	//			 ", level = " + cl.getLevel());
+      }
+      DefaultContourLineAttribute cattr = cl.getDefaultContourLineAttribute();
+      cattr.setContourLineAttribute(cl.getContourLineAttribute());
+      if(kmax <= 1 || !cattr.isLabelEnabled()) continue;
+      //
+      // create SGLabel at a dummy location and no rotation
+      //
+      label = new SGLabel("CLevel", 
+			  cattr.getLabelText(), 
+			  cattr.getLabelHeightP(), 
+			  new Point2D.Double(0.0,0.0), 
+			  SGLabel.BOTTOM, 
+			  SGLabel.LEFT);
+      if(cattr.getLabelFont() != null) label.setFont(cattr.getLabelFont());
+      label.setColor(cattr.getLabelColor());
+      label.setLayer(cg_.getLayer());
+      //
+      // compute hgt and width from font
+      //
+      int swidth = (int)label.getStringWidth(g);
+      int sheight = (int)label.getStringHeight(g);
+      width = cg_.getLayer().getXDtoP(swidth) -	cg_.getLayer().getXDtoP(0);
+      //
+      hgt = cg_.getLayer().getYDtoP(0) - cg_.getLayer().getYDtoP(sheight);
+      //
+      hhgt = hgt*0.5;
+      width = width + hhgt;
+      if(Debug.CONTOUR) {
+	//      System.out.println("drawLabeledContourLine: hhgt,width = " +
+	//			 hhgt + ", " + width);
+      }
+      //
+      px = xArrayP();
+      py = yArrayP();
+      z = grid_.getZArray();
+      xIncreasing = px[0] < px[1];
+      yIncreasing = py[0] < py[1];
+      nx = px.length;
+      ny = py.length;
+      //
+      x = new double[kmax+1];
+      y = new double[kmax+1];
+      s = new double[kmax+1];
+      if(cl.isXTime() || cl.isYTime()) {
+	tref = cl.getReferenceTime();
+      }
+      s[1] = 0.0;
+      //
+      // convert ContourLine to physical units
+      //
+      x = cl.getXArrayP();
+      y = cl.getYArrayP();
+      //
+      // compute s[k]
+      //
+      for(k=2; k <= kmax; k++) {
+	dxx = x[k] - x[k-1];
+	dyy = y[k] - y[k-1];
+	s[k] = s[k-1] + Math.sqrt(dxx*dxx+dyy*dyy);
+      }
+      smax = s[kmax];
+      slab1 = smax*SLAB1F;
+      stest = Math.max(0.0, DSLAB - slab1);
+      k=1;
+      //
+      // check conditions for labelling
+      //
+      while(k < kmax) { /* 755 */
+	km1 = Math.max(k-1, 1);
+	stest = stest + s[k] - s[km1];
+	//
+	// Test if there is enough room for a label
+	//
+	if(stest < DSLAB || (smax - s[k]) <= 2.0*width) {
+	  //	  drawLineSegment(g, x[k], y[k], x[k+1], y[k+1]);
+	  k=k+1;
+	  continue;
+	}
+	kp1 = k + 1;
+	//
+	// gradient test
+	//
+	if(lev != 0) {
+	  try {
+	    dlev = Math.abs(contourLevels_.getLevel(lev) - 
+			    contourLevels_.getLevel(lev-1));
+	    if(xIncreasing) {
+	      for(i=0; i < nx-1; i++) {
+		if(x[k] >= px[i] && x[k] <= px[i+1]) break;
+	      }
+	    } else {
+	      for(i=0; i < nx-1; i++) {
+		if(x[k] <= px[i] && x[k] >= px[i+1]) break;
+	      }
+	    }
+	    if(yIncreasing) {
+	      for(j=0; j < ny-1; j++) {
+		if(y[k] >= py[j] && y[k] <= py[j+1]) break;
+	      }
+	    } else {
+	      for(j=0; j < ny-1; j++) {
+		if(y[k] <= py[j] && y[k] >= py[j+1]) break;
+	      }
+	    }
+	    i = Math.min(i, nx-2);
+	    j = Math.min(j, ny-2);
+	    dx = px[i+1] - px[i];
+	    dy = py[j+1] - py[j];
+	    if(Double.isNaN(z[j+(i+1)*ny])) {
+	      dzdx = 0.0;
+	    } else {
+	      dzdx = (z[j+(i+1)*ny] - z[j+i*ny])/dx;
+	    }
+	    if(Double.isNaN(z[j+1+i*ny])) {
+	      dzdy = 0.0;
+	    } else {
+	      dzdy = (z[j+1+i*ny] - z[j+i*ny])/dy;
+	    }
+	    //
+	    // dzdg = sqrt(dzdx*dzdx+dzdy*dzdy)
+	    //
+	    // replace with less prone to overflow
+	    // calculation
+	    //
+	    dzdg = Math.abs(dzdx) + Math.abs(dzdy);
+	    if(dzdg != 0.0) {
+	      cspace = dlev/dzdg;
+	      //
+	      // is there room for label height?
+	      // (was 0.75)
+	      if(cspace < hgt*1.0) {
+		//		drawLineSegment(g, x[k], y[k], x[k+1], y[k+1]);
+		k=k+1;
+		continue;
+	      }
+	    }
+	  } catch (ContourLevelNotFoundException e) {
+	    System.out.println(e);
+	  }
+	}
+	//
+	// test line arc
+	//
+	roomFound = false;
+	for(kk=kp1; kk <= kmax; kk++) {
+	  dxx = x[kk] - x[k];
+	  dyy = y[kk] - y[k];
+	  space = Math.sqrt(dxx*dxx + dyy*dyy);
+	  ark = s[kk] - s[k];
+	  if(space >= width) { 
+	    roomFound = true;
+	    break;
+	  }
+	}
+	if(space/ark < 0.80 || !roomFound) {
+	  //	  drawLineSegment(g, x[k], y[k], x[k+1], y[k+1]);
+	  k=k+1;
+	  continue;
+	} else {
+	  //
+	  // add label to contour line
+	  //
+	  cl.addLabel(k, (SGLabel)label.copy(), hgt, width);
+	  //
+	  // draw the label
+	  //
+	  stest = 0.0;   /* 810 */
+//  	  xa = x[kk-1] - x[k];
+//  	  xb = x[kk] - x[kk-1];
+//  	  ya = y[kk-1] - y[k];
+//  	  yb = y[kk] - y[kk-1];
+//  	  aa = xb*xb + yb*yb;
+//  	  bb = xa*xb + ya*yb;
+//  	  cc = xa*xa + ya*ya - width*width;
+//  	  zxy = (-bb + Math.sqrt(bb*bb - aa*cc))/aa;
+//  	  dxx = xa + xb*zxy;
+//  	  dyy = ya + yb*zxy;
+//  	  xendl = x[k] + dxx;
+//  	  yendl = y[k] + dyy;
+//  	  //
+//  	  // compute label angle
+//  	  //
+//  	  angle = 90.0;
+//  	  if(dyy < 0.0) angle = -90.0;
+//  	  if(dxx != 0.0) {
+//  	    angle = Math.atan(dyy/dxx)*180.0/Math.PI;
+//  	  }
+//  	  //
+//  	  // compute label position
+//  	  //
+//  	  if(dxx >= 0) {
+//  	    xlab = x[k] + hhgt*(0.5*dxx + dyy)/width;
+//  	    ylab = y[k] + hhgt*(0.5*dyy - dxx)/width;
+//  	  } else {
+//  	    xlab = xendl - hhgt*(0.5*dxx + dyy)/width;
+//  	    ylab = yendl - hhgt*(0.5*dyy - dxx)/width;
+//  	  }
+//  	  label.setAngle(angle);
+//  	  label.setLocationP(new Point2D.Double(xlab, ylab));
+//  	  try {
+//  	    label.draw(g);
+//  	    //	  drawRotatedRectangle(g, angle, xlab, ylab, width-hhgt, hgt);
+//  	  } catch (LayerNotFoundException e) {
+//  	    System.out.println(e);
+//  	  }
+//  	  drawLineSegment(g, xendl, yendl, x[kk], y[kk]);
+	  k = kk;
+	}
+      }
+    }
+  }
+
+  private void drawRotatedRectangle(Graphics g,
+				    double angle,
+				    double x0, double y0,
+				    double width, double height) {
+    double sinthta = Math.sin(angle*Math.PI/180.0);
+    double costhta = Math.cos(angle*Math.PI/180.0);
+    double[] x, y;
+    double xp, yp;
+    int[] xd, yd;
+    double xorig, yorig;
+    x = new double[4];
+    y = new double[4];
+    xd = new int[5];
+    yd = new int[5];
+    xorig = x0;
+    yorig = y0;
+    x[0] = x0;
+    y[0] = y0;
+    x[1] = x[0] + width;
+    y[1] = y[0];
+    x[2] = x[1];
+    y[2] = y[0] + height;
+    x[3] = x[0];
+    y[3] = y[2];
+    for(int i=0; i < 4; i++) {
+      xp = (x[i]-xorig)*costhta - (y[i]-yorig)*sinthta + xorig;
+      yp = (y[i]-yorig)*costhta + (x[i]-xorig)*sinthta + yorig;
+      xd[i] = cg_.getLayer().getXPtoD(xp);
+      yd[i] = cg_.getLayer().getYPtoD(yp);
+    }
+    xd[4] = xd[0];
+    yd[4] = yd[0];
+    g.setColor(Color.blue);
+    g.drawPolyline(xd, yd, 5);
+    g.setColor(Color.black);
+  }
+
+//    private void drawLineSegment(Graphics g, double x0, double y0,
+//  			       double x1, double y1) { /* 900 */
+//      int xd0, yd0, xd1, yd1;
+//      xd0 = cg_.getLayer().getXPtoD(x0);
+//      yd0 = cg_.getLayer().getYPtoD(y0);
+//      xd1 = cg_.getLayer().getXPtoD(x1);
+//      yd1 = cg_.getLayer().getYPtoD(y1);
+//      g.drawLine(xd0, yd0, xd1, yd1);
+//    }
+
+  private double[] xArrayP() {
+    int i;
+    double[] p;
+    if(grid_.isXTime()) {
+      GeoDate[] t = grid_.getTimeArray();
+      p = new double[t.length];
+      for(i=0; i < t.length; i++) {
+	p[i] = cg_.getXUtoP(t[i]);
+      }
+    } else {
+      double[] x = grid_.getXArray();
+      p = new double[x.length];
+      for(i=0; i < x.length; i++) {
+	p[i] = cg_.getXUtoP(x[i]);
+      }
+    }
+    return p;
+  }
+
+  private double[] yArrayP() {
+    int i;
+    double[] p;
+    if(grid_.isYTime()) {
+      GeoDate[] t = grid_.getTimeArray();
+      p = new double[t.length];
+      for(i=0; i < t.length; i++) {
+	p[i] = cg_.getYUtoP(t[i]);
+      }
+    } else {
+      double[] y = grid_.getYArray();
+      p = new double[y.length];
+      for(i=0; i < y.length; i++) {
+	p[i] = cg_.getYUtoP(y[i]);
+      }
+    }
+    return p;
+  }
+
+//    private void drawContourLine(Graphics g, ContourLine cl) {
+//      GeoDate tref, time;
+//      Point2D.Double[] pt;
+//      int i;
+//      //    int size = cl.size();
+//      int size = cl.getKmax() + 1;
+//      if(size <= 3) return;
+//      int[] xp = new int[size];
+//      int[] yp = new int[size];
+//      pt = new Point2D.Double[size];
+//      for(i=0; i < size; i++) {
+//        pt[i] = (Point2D.Double)cl.elementAt(i);
+//      }
+//      if(cl.isXTime()) {
+//        tref = cl.getReferenceTime();
+//        for(i=0; i < size; i++) {
+//  	time = (new GeoDate(tref)).increment(pt[i].x, GeoDate.DAYS);
+//  	xp[i] = cg_.getXUtoD(time);
+//        }
+//      } else {
+//        for(i=0; i < size; i++) {
+//  	xp[i] = cg_.getXUtoD(pt[i].x);
+//        }
+//      }
+//      if(cl.isYTime()) {
+//        tref = cl.getReferenceTime();
+//        for(i=0; i < size; i++) {
+//  	time = (new GeoDate(tref)).increment(pt[i].y, GeoDate.DAYS);
+//  	yp[i] = cg_.getYUtoD(time);
+//        }
+//      } else {
+//        for(i=0; i < size; i++) {
+//  	yp[i] = cg_.getYUtoD(pt[i].y);
+//        }
+//      }
+//      g.drawPolyline(xp, yp, size);
+//    }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/ContourLabel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/ContourLabel.java
new file mode 100755
index 0000000..bb821e5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/ContourLabel.java
@@ -0,0 +1,55 @@
+/*
+ * $Id: ContourLabel.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.contour;
+
+import gov.noaa.pmel.sgt.SGLabel;
+
+/**
+ * Container for information about where labels should
+ * be inserted on a ContourLine.
+ *
+ * @author D. W. Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+class ContourLabel {
+  int index;
+
+  /**
+   * @label label
+   * @link aggregationByValue 
+   * @supplierCardinality 1
+   */
+  SGLabel label;
+  double width;
+  double height;
+
+  public ContourLabel(int indx, SGLabel lab, double hgt, double wid) {
+    index = indx;
+    label = lab;
+    width = wid;
+    height = hgt;
+  }
+  public SGLabel getLabel() {
+    return label;
+  }
+  public int getIndex() {
+    return index;
+  }
+  public double getWidth() {
+    return width;
+  }
+  public double getHeight() {
+    return height;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/ContourLine.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/ContourLine.java
new file mode 100755
index 0000000..ad03cd5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/ContourLine.java
@@ -0,0 +1,434 @@
+/*
+ * $Id: ContourLine.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.contour;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+import java.awt.Graphics;
+import java.awt.Color;
+
+import gov.noaa.pmel.sgt.ContourLineAttribute;
+import gov.noaa.pmel.sgt.DefaultContourLineAttribute;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.LayerNotFoundException;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.StrokeDrawer;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.GeoDate;
+
+/**
+ * <code>ContourLine</code> contains a single closed or open contour
+ * and a list of its labels.
+ * The level, closedness, and path are properties.
+ * The path is stored as a <code>Vector</code> of <code>Point2D</code>
+ * user coordinate values. <code>ContourLine</code> objects are
+ * created by <code>Contour</code> and drawn by
+ * <code>GridCartesianRenderer</code>.  Time coordinates are stored in
+ * the <code>Point2D</code> objects releative to a reference time.
+ *
+ * @author D. W. Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ * @see Contour
+ * @see ContourLineAttribute
+ * @see DefaultContourLineAttribute
+ * @see gov.noaa.pmel.sgt.GridCartesianRenderer
+ */
+public class ContourLine extends Vector {
+  private StrokeDrawer stroke_ = null;
+
+  private boolean closed_ = false;
+  private double level_;
+  private GeoDate timeRef_ = null;
+  private boolean xTime_ = false;
+  private boolean yTime_ = false;
+  private int kmax_;
+
+  /**
+   * @label attr
+   */
+  private ContourLineAttribute attr_ = null;
+  private DefaultContourLineAttribute defaultAttr_ = null;
+  private Vector conLabels_;
+
+  /**
+   * @supplierCardinality *
+   * @link aggregationByValue
+   */
+  private ContourLabel lnkContourLabel;
+
+  private CartesianGraph cg_;
+  /**
+   * Default constructor.
+   */
+  public ContourLine() {
+    super();
+    conLabels_ = new Vector();
+    stroke_ = JPane.getStrokeDrawer();
+  }
+  /**
+   * Constructor setting initial size and extend values of coordinate
+   * <code>Vector</code>.
+   */
+  public ContourLine(int size, int extend) {
+    super(size, extend);
+    conLabels_ = new Vector();
+    stroke_ = JPane.getStrokeDrawer();
+  }
+  /**
+   * Constructor setting initial size of coordinate <code>Vector</code>.
+   */
+  public ContourLine(int size) {
+    super(size);
+    conLabels_ = new Vector();
+    stroke_ = JPane.getStrokeDrawer();
+  }
+  /**
+   * Set the parent <code>CartesianGraph</code>.  Used internally by
+   * sgt.
+   */
+  public void setCartesianGraph(CartesianGraph cg) {
+    cg_ = cg;
+  }
+  /**
+   * Set the attributes for the contour line.
+   */
+  public void setAttributes(DefaultContourLineAttribute def, ContourLineAttribute attr) {
+    defaultAttr_ = def;
+    attr_ = attr;
+  }
+  /**
+   * Set the <code>ContourLineAttribute</code>
+   */
+  public void setContourLineAttribute(ContourLineAttribute attr) {
+    attr_ = attr;
+  }
+
+  /**
+   * Get the <code>ContourLineAttribute</code>
+   */
+  public ContourLineAttribute getContourLineAttribute() {
+    return attr_;
+  }
+  /**
+   * Set the <code>DefaultContourLineAttribute</code>
+   */
+  public void setDefaultContourLineAttribute(DefaultContourLineAttribute def) {
+        defaultAttr_ = def;
+  }
+  /**
+   * Get the <code>DefaultContourLineAttribute</code>
+   */
+  public DefaultContourLineAttribute getDefaultContourLineAttribute() {
+        return defaultAttr_;
+  }
+
+  void setClosed(boolean closed){
+    closed_ = closed;
+  }
+  /**
+   * Is the contour line closed?
+   */
+  public boolean isClosed() {
+    return closed_;
+  }
+  /**
+   * The level value of the contour line.
+   */
+  public double getLevel(){
+    return level_;
+  }
+
+  void setLevel(double level){
+    level_ = level;
+  }
+
+  void addPoint(double x, double y) {
+    addElement(new Point2D.Double(x, y));
+  }
+
+  void addPoint(Point2D.Double point) {
+    addElement(point);
+  }
+
+  void setKmax(int kmax) {
+    kmax_ = kmax;
+  }
+  /**
+   * Get the number of points in the contour line.
+   */
+  public int getKmax() {
+    return kmax_;
+  }
+
+  void setTime(GeoDate tref, boolean xtime, boolean ytime) {
+    timeRef_ = tref;
+    xTime_ = xtime;
+    yTime_ = ytime;
+  }
+
+  void setReferenceTime(GeoDate tref) {
+    timeRef_ = tref;
+  }
+  /**
+   * Get reference time for the time point of the <code>Point2D</code> object.
+   */
+  public GeoDate getReferenceTime() {
+    return timeRef_;
+  }
+
+  void setXTime(boolean time) {
+    xTime_ = time;
+  }
+  /**
+   * Is the x coordinate time?
+   */
+  public boolean isXTime() {
+    return xTime_;
+  }
+
+  void setYTime(boolean time) {
+    yTime_ = time;
+  }
+  /**
+   * Is the y coordinate time?
+   */
+  public boolean isYTime() {
+    return yTime_;
+  }
+
+  void reverseElements(int k) {
+    /* k is reversal length */
+    Point2D.Double point;
+    int kkr;
+    int kh = 1 + k/2;
+    for(int kk=1; kk < kh; kk++) {
+      kkr = k+1-kk;
+      point = (Point2D.Double)elementAt(kk);
+      setElementAt(elementAt(kkr), kk);
+      setElementAt(point, kkr);
+    }
+  }
+  /**
+   * Add a label to the contour line.
+   */
+  public void addLabel(int point, SGLabel lab, double hgt, double wid) {
+    ContourLabel clab = new ContourLabel(point, lab, hgt, wid);
+    conLabels_.addElement(clab);
+  }
+  /**
+   * Remove all labels.
+   */
+  public void removeAllLabels() {
+    conLabels_.removeAllElements();
+  }
+  /**
+   * Used internally by sgt.
+   */
+  public void draw(Graphics g) {
+    int k, kk, loc, kp1;
+    double[] x = new double[kmax_+1];
+    double[] y = new double[kmax_+1];
+    ContourLabel clab;
+    double width, hhgt;
+    double dxx, dyy, space;
+    double xa, xb, ya, yb, aa, bb, cc, zxy;
+    double xendl, yendl, angle;
+    double xlab, ylab;
+    SGLabel label;
+    GeoDate time;
+    defaultAttr_.setContourLineAttribute(attr_);
+    Color lineColor = defaultAttr_.getColor();
+    //
+    // convert ContourLine to physical units
+    //
+    x = getXArrayP();
+    y = getYArrayP();
+    //
+    // loop through labels
+    //
+    k=1;
+    Enumeration cenum = conLabels_.elements();
+    while(cenum.hasMoreElements()) {
+      clab = (ContourLabel)cenum.nextElement();
+      loc = clab.getIndex();
+      width = clab.getWidth();
+      hhgt = clab.getHeight()*0.5;
+      label = clab.getLabel();
+      //
+      g.setColor(lineColor);
+      drawLine(g, x, y, k, loc);
+      //
+      k = loc;
+      kp1 = k + 1;
+      for(kk=kp1; kk <= kmax_; kk++) {
+        dxx = x[kk] - x[k];
+        dyy = y[kk] - y[k];
+        space = Math.sqrt(dxx*dxx+dyy*dyy);
+        if(space >= width) break;
+      }
+      xa = x[kk-1] - x[k];
+      xb = x[kk] - x[kk-1];
+      ya = y[kk-1] - y[k];
+      yb = y[kk] - y[kk-1];
+      aa = xb*xb + yb*yb;
+      bb = xa*xb + ya*yb;
+      cc = xa*xa + ya*ya - width*width;
+      zxy = (-bb + Math.sqrt(bb*bb - aa*cc))/aa;
+      dxx = xa + xb*zxy;
+      dyy = ya + yb*zxy;
+      xendl = x[k] + dxx;
+      yendl = y[k] + dyy;
+      //
+      // compute label angle
+      //
+      angle = 90.0;
+      if(dyy < 0.0) angle = -90.0;
+      if(dxx != 0.0) {
+        angle = Math.atan(dyy/dxx)*180.0/Math.PI;
+      }
+      //
+      // compute label position
+      //
+      if(dxx >= 0) {
+        xlab = x[k] + hhgt*(0.5*dxx + dyy)/width;
+        ylab = y[k] + hhgt*(0.5*dyy - dxx)/width;
+      } else {
+        xlab = xendl - hhgt*(0.5*dxx + dyy)/width;
+        ylab = yendl - hhgt*(0.5*dyy - dxx)/width;
+      }
+      label.setAngle(angle);
+      label.setLocationP(new Point2D.Double(xlab, ylab));
+      try {
+        label.draw(g);
+      } catch (LayerNotFoundException e) {
+        System.out.println(e);
+      }
+      g.setColor(lineColor);
+      drawLineSegment(g, xendl, yendl, x[kk], y[kk]);
+      k=kk;
+    }
+    if(k < kmax_) {
+      g.setColor(lineColor);
+      drawLine(g, x, y, k, kmax_);
+    }
+  }
+
+  private void drawLine(Graphics g, double[] x, double[] y,
+                        int kstart, int kend) {
+    int size = kend-kstart+1;
+    int[] xp = new int[size];
+    int[] yp = new int[size];
+    int i, k;
+    for(i=0, k=kstart; k <= kend; k++, i++) {
+      xp[i] = cg_.getLayer().getXPtoD(x[k]);
+      yp[i] = cg_.getLayer().getYPtoD(y[k]);
+    }
+    switch(defaultAttr_.getStyle()) {
+    case LineAttribute.HIGHLIGHT:
+      stroke_.drawHighlight(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    case LineAttribute.HEAVY:
+      stroke_.drawHeavy(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    case LineAttribute.DASHED:
+      stroke_.drawDashed(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    case LineAttribute.STROKE:
+      stroke_.drawStroke(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    default:
+    case LineAttribute.MARK:
+    case LineAttribute.MARK_LINE:
+    case LineAttribute.SOLID:
+      g.drawPolyline(xp, yp, size);
+    }
+  }
+
+  private void drawLineSegment(Graphics g, double x0, double y0,
+                               double x1, double y1) {
+    int[] xp, yp;
+    int size = 2;
+    xp = new int[2];
+    yp = new int[2];
+    xp[0] = cg_.getLayer().getXPtoD(x0);
+    yp[0] = cg_.getLayer().getYPtoD(y0);
+    xp[1] = cg_.getLayer().getXPtoD(x1);
+    yp[1] = cg_.getLayer().getYPtoD(y1);
+    switch(defaultAttr_.getStyle()) {
+    case LineAttribute.HIGHLIGHT:
+      stroke_.drawHighlight(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    case LineAttribute.HEAVY:
+      stroke_.drawHeavy(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    case LineAttribute.DASHED:
+      stroke_.drawDashed(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    case LineAttribute.STROKE:
+      stroke_.drawStroke(g, xp, yp, size, (LineAttribute)defaultAttr_);
+      break;
+    default:
+    case LineAttribute.MARK:
+    case LineAttribute.MARK_LINE:
+    case LineAttribute.SOLID:
+      g.drawPolyline(xp, yp, size);
+    }
+  }
+  /**
+   * Get x physical coordinates of the contour line.
+   */
+  public double[] getXArrayP() {
+    double[] xp = null;
+    Point2D.Double pt;
+    GeoDate time;
+    if(cg_ != null) {
+      xp = new double[kmax_+1];
+      for(int k=0; k <= kmax_; k++) {
+        pt = (Point2D.Double)elementAt(k);
+        if(isXTime()) {
+          time = (new GeoDate(timeRef_)).increment(pt.x, GeoDate.DAYS);
+          xp[k] = cg_.getXUtoP(time);
+        } else {
+          xp[k] = cg_.getXUtoP(pt.x);
+        }
+      }
+    }
+    return xp;
+  }
+  /**
+   * Get y physical coordinates of the contour line.
+   */
+  public double[] getYArrayP() {
+    double[] yp = null;
+    Point2D.Double pt;
+    GeoDate time;
+    if(cg_ != null) {
+      yp = new double[kmax_+1];
+      for(int k=0; k <= kmax_; k++) {
+        pt = (Point2D.Double)elementAt(k);
+        if(isYTime()) {
+          time = (new GeoDate(timeRef_)).increment(pt.x, GeoDate.DAYS);
+          yp[k] = cg_.getYUtoP(time);
+        } else {
+          yp[k] = cg_.getYUtoP(pt.y);
+        }
+      }
+    }
+    return yp;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/GridFlag.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/GridFlag.java
new file mode 100755
index 0000000..ad9c857
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/GridFlag.java
@@ -0,0 +1,122 @@
+/*
+ * $Id: GridFlag.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.contour;
+
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+
+/**
+ * Used to set and test whether a grid value is less than, equal, or
+ * greater than a contour level.
+ *
+ * @author D. W. Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+class GridFlag {
+  public final static int LESS_THAN_ZC = -1;
+  public final static int MISSING = 10;
+  public final static int GREATER_THAN_ZC = 1;
+
+  private double[] array_;
+  private double[] mask_ = null;
+  private byte[] value_;
+  private int nx_;
+  private int ny_;
+
+  public GridFlag(SGTGrid grid, double zc)  {
+    this(grid, null, zc);
+  }
+
+  public GridFlag(SGTGrid grid, SGTGrid mask, double zc) {
+    if(grid.isXTime()) {
+      nx_ = grid.getTSize();
+    } else {
+    nx_ = grid.getXSize();
+    }
+    if(grid.isYTime()) {
+        ny_ = grid.getTSize();
+    } else {
+    ny_ = grid.getYSize();
+    }
+    value_ = new byte[nx_*ny_];
+    array_ = grid.getZArray();
+    setLevel(zc);
+    if(mask != null) setMask(mask);
+  }
+
+  public void setMask(SGTGrid mask) {
+    mask_ = mask.getZArray();
+    applyMask();
+  }
+
+  void applyMask() {
+    if(mask_ == null) return;
+    for(int i=0; i < nx_*ny_; i++) {
+      if(Double.isNaN(mask_[i]) || mask_[i] != 0.0) {
+	value_[i] = MISSING;
+      }
+    }
+  }
+
+  public void setLevel(double zc) {
+    for(int i=0; i < nx_*ny_; i++) {
+      if(!Double.isNaN(array_[i])) {
+	if(array_[i] <= zc) {
+	  value_[i] = LESS_THAN_ZC;
+	} else {
+	  value_[i] = GREATER_THAN_ZC;
+	}
+      } else {
+	value_[i] = MISSING;
+      }
+    }
+    applyMask();
+  }
+
+  int index(int i, int j) {
+    return j + ny_*i;
+  }
+  /**
+   * True if grid(i,j) is missing.
+   */
+  public boolean isMissing(int i, int j) {
+    int ind = index(i,j);
+    if(Debug.CONTOUR) {
+      if(ind < 0 || ind >= nx_*ny_) {
+	System.out.println("GridFlag.isMissing(): (i,j) = (" + i + ", " + j + ")");
+      }
+    }
+    return (value_[ind] == MISSING);
+  }
+
+  public boolean isGreater(int i, int j ) {
+    int ind = index(i,j);
+    if(Debug.CONTOUR) {
+      if(ind < 0 || ind >= nx_*ny_) {
+	System.out.println("GridFlag.isGreater(): (i,j) = (" + i + ", " + j + ")");
+      }
+    }
+    return (value_[ind] == GREATER_THAN_ZC);
+  }
+
+  public int getValue(int i, int j) {
+    int ind = index(i,j);
+    if(Debug.CONTOUR) {
+      if(ind < 0 || ind >= nx_*ny_) {
+	System.out.println("GridFlag.getValue(): (i,j) = (" + i + ", " + j + ")");
+      }
+    }
+    return value_[ind];
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/PolygonGenerator.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/PolygonGenerator.java
new file mode 100755
index 0000000..fac5f63
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/PolygonGenerator.java
@@ -0,0 +1,8 @@
+/* Generated by Together */
+
+package gov.noaa.pmel.sgt.contour;
+/**
+ * Not implemented.
+ */
+public class PolygonGenerator {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/PolygonRenderer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/PolygonRenderer.java
new file mode 100755
index 0000000..01b6476
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/PolygonRenderer.java
@@ -0,0 +1,8 @@
+/* Generated by Together */
+
+package gov.noaa.pmel.sgt.contour;
+/**
+ * Not implemented.
+ */
+public class PolygonRenderer {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Sides.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Sides.java
new file mode 100755
index 0000000..2cd5411
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Sides.java
@@ -0,0 +1,92 @@
+/*
+ * $Id: Sides.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.contour;
+
+import gov.noaa.pmel.util.Debug;
+
+import java.util.BitSet;
+
+/**
+ * Used to keep track of which sides have been used during the contour
+ * line generation process.
+ *
+ * @author D. W. Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+class Sides {
+  BitSet sides_;
+  int nx_;
+  int ny_;
+  int ny2_;
+
+  public Sides(int nx, int ny) {
+    nx_ = nx;
+    ny_ = ny;
+    ny2_ = ny_*2;
+    sides_ = new BitSet(ny2_*nx_);
+  }
+
+  public boolean isSideUsed(int i, int j, int side) {
+    int ind = index(i,j,side);
+    if(ind < 0 || ind > ny2_*nx_-1) {
+      if(Debug.CONTOUR) {
+	System.out.println("Sides.isSideUsed(): (i,j,side) = " + i + ", " + j + ", " + side);
+      }
+      return false;
+    }
+    return sides_.get(ind);
+  }
+
+  public void setSideUsed(int i, int j, int side, boolean set) {
+    int ind = index(i,j,side);
+    if(Debug.CONTOUR) {
+      if(ind < 0 || ind > ny2_*nx_-1) {
+	System.out.println("Sides.setSideUsed(): (i,j,side) = " + i + ", " + j + ", " + side);
+      }
+    }
+    if(set) {
+      sides_.set(ind);
+    } else {
+      sides_.clear(ind);
+    }
+  }
+
+  public int getSide(int i, int j, int side) {
+    int ind = index(i,j,side);
+    if(ind < 0 || ind > ny2_*nx_-1) {
+      if(Debug.CONTOUR) {
+	System.out.println("Sides.getSide(): (i,j,side) = " + i + ", " + j + ", " + side);
+      }
+      return 0;
+    }
+    return sides_.get(ind)?1:0;
+  }
+
+  int index(int i, int j, int side) {
+    int index = -10;
+    if(side == 1) { /* i+1,j  right */
+      index = 1 + j*2 + (i+1)*ny2_;
+    } else if(side == 2) { /* i,j+1  top */
+      index = (j+1)*2 + i*ny2_;
+    } else if(side == 0) { /* i,j  bottom */
+      index = j*2 + i*ny2_;
+    } else if(side == 3) { /* i,j  left */
+      index = 1 + j*2 + i*ny2_;
+    }
+    return index;
+  }
+  public void clear() {
+    sides_ = new BitSet(ny2_*nx_);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Tree.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Tree.java
new file mode 100755
index 0000000..52cb166
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/Tree.java
@@ -0,0 +1,8 @@
+/* Generated by Together */
+
+package gov.noaa.pmel.sgt.contour;
+/**
+ * Not implemented.
+ */
+public class Tree {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/TreeEnumerator.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/TreeEnumerator.java
new file mode 100755
index 0000000..c507587
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/TreeEnumerator.java
@@ -0,0 +1,14 @@
+/* Generated by Together */
+
+package gov.noaa.pmel.sgt.contour;
+/**
+ * Not implemented.
+ */
+public class TreeEnumerator implements java.util.Enumeration {
+  public boolean hasMoreElements() {
+    return false;
+  }
+  public Object nextElement() {
+    return null;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/TreeGenerator.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/TreeGenerator.java
new file mode 100755
index 0000000..5e87bcd
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/TreeGenerator.java
@@ -0,0 +1,8 @@
+/* Generated by Together */
+
+package gov.noaa.pmel.sgt.contour;
+/**
+ * Not implemented.
+ */
+public class TreeGenerator {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/package.html
new file mode 100755
index 0000000..3be8be1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/contour/package.html
@@ -0,0 +1,14 @@
+<HTML>
+<BODY>
+Contour and polygon fill support.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/AddDataFrame.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/AddDataFrame.java
new file mode 100755
index 0000000..de388f5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/AddDataFrame.java
@@ -0,0 +1,927 @@
+/*
+ * $Id: AddDataFrame.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.*;
+import javax.swing.border.*;
+import java.util.Iterator;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SGTVector;
+import gov.noaa.pmel.sgt.Attribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.VectorAttribute;
+import gov.noaa.pmel.sgt.beans.*;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.sgt.IndexedColorMap;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.sgt.beans.Page;
+
+import javax.swing.event.*;
+
+/**
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 3.0
+ **/
+class AddDataFrame extends JFrame {
+  private BorderLayout borderLayout1 = new BorderLayout();
+  private JPanel jPanel1 = new JPanel();
+  private JPanel jPanel2 = new JPanel();
+  private JButton okButton = new JButton();
+  private JButton cancelButton = new JButton();
+  private JPanel sourcePanel = new JPanel();
+  private JPanel targetPanel = new JPanel();
+  private GridBagLayout gridBagLayout1 = new GridBagLayout();
+  private TitledBorder sourceBorder;
+  private TitledBorder targetBorder;
+  private Page page_ = null;
+  private JScrollPane jScrollPane1 = new JScrollPane();
+  private GridBagLayout gridBagLayout2 = new GridBagLayout();
+  private JScrollPane jScrollPane2 = new JScrollPane();
+  private JScrollPane jScrollPane3 = new JScrollPane();
+  private JList panelList = new JList();
+  private JList axisGroupList = new JList();
+  private JList legendList = new JList();
+  private TitledBorder panelBorder;
+  private TitledBorder axisGroupBorder;
+  private TitledBorder legendBorder;
+  private BorderLayout borderLayout2 = new BorderLayout();
+  private JPanel jPanel3 = new JPanel();
+  private JLabel jLabel1 = new JLabel();
+  private JComboBox dataTypeCB = new JComboBox();
+  private JPanel cardPanel = new JPanel();
+  private CardLayout cardLayout1 = new CardLayout();
+  private JPanel oneDSpatialPanel = new JPanel();
+  private JPanel twoDSpatialPanel = new JPanel();
+  private JPanel oneDTimePanel = new JPanel();
+  private JPanel twoDTimePanel = new JPanel();
+  private JPanel pointPanel = new JPanel();
+  private JLabel jLabel2 = new JLabel();
+  private JComboBox dir1SCB = new JComboBox();
+  private GridBagLayout gridBagLayout3 = new GridBagLayout();
+  private JLabel jLabel3 = new JLabel();
+  private JPanel jPanel5 = new JPanel();
+  private JTextField delta1STF = new JTextField();
+  private JTextField max1STF = new JTextField();
+  private JTextField min1STF = new JTextField();
+  private JLabel jLabel4 = new JLabel();
+  private JComboBox type1SCB = new JComboBox();
+  private JLabel jLabel5 = new JLabel();
+  private JTextField amp1STF = new JTextField();
+  private JLabel jLabel6 = new JLabel();
+  private JTextField off1STF = new JTextField();
+  private JLabel jLabel7 = new JLabel();
+  private JTextField per1STF = new JTextField();
+  private GridBagLayout gridBagLayout4 = new GridBagLayout();
+  private Component component1;
+  private String[] args = {"1-d Spatial", "2-d Spatial",
+      "1-d Time", "2-d Time", "Point", "Vector"};
+  private DefaultComboBoxModel dataTypeModel = new DefaultComboBoxModel(args);
+
+  private String[] dir1Sargs = {"X_SERIES", "Y_SERIES", "PROFILE", "LOG_LOG"};
+  private String[] dir2Sargs = {"XY_GRID", "XZ_GRID", "YZ_GRID"};
+  private DefaultComboBoxModel dir1SModel = new DefaultComboBoxModel(dir1Sargs);
+  private DefaultComboBoxModel dir2SModel = new DefaultComboBoxModel(dir2Sargs);
+
+  private String[] typeargs = {"SINE", "RANDOM"};
+  private DefaultComboBoxModel typeModel = new DefaultComboBoxModel(typeargs);
+  private GridBagLayout gridBagLayout5 = new GridBagLayout();
+  private JLabel jLabel8 = new JLabel();
+  private JComboBox dir2SCB = new JComboBox();
+  private JLabel jLabel9 = new JLabel();
+  private JPanel jPanel4 = new JPanel();
+  private JTextField delta12STF = new JTextField();
+  private JTextField max12STF = new JTextField();
+  private JTextField min12STF = new JTextField();
+  private JLabel jLabel10 = new JLabel();
+  private JPanel jPanel6 = new JPanel();
+  private JTextField delta22STF = new JTextField();
+  private JTextField max22STF = new JTextField();
+  private JTextField min22STF = new JTextField();
+  private JLabel jLabel11 = new JLabel();
+  private JComboBox type2SCB = new JComboBox();
+  private JLabel jLabel12 = new JLabel();
+  private JTextField amp2STF = new JTextField();
+  private JLabel jLabel13 = new JLabel();
+  private JTextField off2STF = new JTextField();
+  private JLabel jLabel14 = new JLabel();
+  private JTextField per2STF = new JTextField();
+  private GridBagLayout gridBagLayout6 = new GridBagLayout();
+  private GridBagLayout gridBagLayout7 = new GridBagLayout();
+  private Component component2;
+  private Component component3;
+  private GridBagLayout gridBagLayout8 = new GridBagLayout();
+  private JTextField amp1TTF = new JTextField();
+  private Component component4;
+  private JComboBox type1TCB = new JComboBox();
+  private GridBagLayout gridBagLayout9 = new GridBagLayout();
+  private JTextField max1TTF = new JTextField();
+  private JLabel jLabel15 = new JLabel();
+  private JTextField off1TTF = new JTextField();
+  private JLabel jLabel16 = new JLabel();
+  private JTextField per1TTF = new JTextField();
+  private JLabel jLabel17 = new JLabel();
+  private JTextField min1TTF = new JTextField();
+  private JLabel jLabel18 = new JLabel();
+  private JPanel jPanel7 = new JPanel();
+  private JLabel jLabel19 = new JLabel();
+  private JTextField delta1TTF = new JTextField();
+  private JLabel jLabel20 = new JLabel();
+  private GridBagLayout gridBagLayout10 = new GridBagLayout();
+  private JLabel jLabel110 = new JLabel();
+  private JLabel jLabel111 = new JLabel();
+  private JLabel jLabel112 = new JLabel();
+  private GridBagLayout gridBagLayout11 = new GridBagLayout();
+  private JTextField delta22TTF = new JTextField();
+  private Component component5;
+  private JTextField amp2TTF = new JTextField();
+  private JComboBox type2TCB = new JComboBox();
+  private JTextField max22TTF = new JTextField();
+  private JPanel jPanel8 = new JPanel();
+  private JTextField off2TTF = new JTextField();
+  private JLabel jLabel113 = new JLabel();
+  private JTextField min22TTF = new JTextField();
+  private JLabel jLabel114 = new JLabel();
+  private JTextField per2TTF = new JTextField();
+  private JLabel jLabel21 = new JLabel();
+  private JLabel jLabel22 = new JLabel();
+  private Component component6;
+  private GridBagLayout gridBagLayout12 = new GridBagLayout();
+  private JTextField max12TTF = new JTextField();
+  private JTextField min12TTF = new JTextField();
+  private JPanel jPanel9 = new JPanel();
+  private JTextField delta12TTF = new JTextField();
+  private GridBagLayout gridBagLayout13 = new GridBagLayout();
+  private GridBagLayout gridBagLayout14 = new GridBagLayout();
+  private JPanel jPanel10 = new JPanel();
+  private JTextField delta2PTF = new JTextField();
+  private JPanel jPanel11 = new JPanel();
+  private JTextField max2PTF = new JTextField();
+  private JLabel jLabel119 = new JLabel();
+  private JTextField min1PTF = new JTextField();
+  private JTextField delta1PTF = new JTextField();
+  private JTextField max1PTF = new JTextField();
+  private JLabel jLabel23 = new JLabel();
+  private Component component7;
+  private Component component8;
+  private JTextField min2PTF = new JTextField();
+  private GridBagLayout gridBagLayout15 = new GridBagLayout();
+  private JLabel jLabel24 = new JLabel();
+  private JTextField numPTF = new JTextField();
+  private JPanel vectorPanel = new JPanel();
+  private GridBagLayout gridBagLayout16 = new GridBagLayout();
+
+  public AddDataFrame() {
+    this(null);
+  }
+
+  public AddDataFrame(Page page) {
+    page_ = page;
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+    this.setSize(450, 600);
+    this.setLocation(200, 200);
+    ((CardLayout)cardPanel.getLayout()).show(cardPanel, "oneDSpatial");
+    init();
+  }
+
+  public Page getPage() {
+    return page_;
+  }
+
+  public void setPage(Page page) {
+    page_ = page;
+    init();
+  }
+
+  private void jbInit() throws Exception {
+    sourceBorder = new TitledBorder("");
+    targetBorder = new TitledBorder("");
+    panelBorder = new TitledBorder("");
+    axisGroupBorder = new TitledBorder("");
+    legendBorder = new TitledBorder("");
+    component1 = Box.createHorizontalStrut(8);
+    component2 = Box.createHorizontalStrut(8);
+    component3 = Box.createHorizontalStrut(8);
+    component4 = Box.createHorizontalStrut(8);
+    component5 = Box.createHorizontalStrut(8);
+    component6 = Box.createHorizontalStrut(8);
+    component7 = Box.createHorizontalStrut(8);
+    component8 = Box.createHorizontalStrut(8);
+    this.getContentPane().setLayout(borderLayout1);
+    okButton.setText("OK");
+    okButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        okButton_actionPerformed(e);
+      }
+    });
+    cancelButton.setText("Cancel");
+    cancelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        cancelButton_actionPerformed(e);
+      }
+    });
+    jPanel2.setBorder(BorderFactory.createEtchedBorder());
+    jPanel1.setLayout(gridBagLayout1);
+    sourcePanel.setBorder(sourceBorder);
+    sourcePanel.setMinimumSize(new Dimension(163, 300));
+    sourcePanel.setPreferredSize(new Dimension(167, 300));
+    sourcePanel.setLayout(borderLayout2);
+    sourceBorder.setTitle("Source");
+    targetPanel.setBorder(targetBorder);
+    targetPanel.setLayout(gridBagLayout2);
+    targetBorder.setTitle("Target");
+    this.setTitle("Add Data");
+    jScrollPane1.setBorder(panelBorder);
+    panelBorder.setTitle("Panels");
+    jScrollPane2.setBorder(axisGroupBorder);
+    axisGroupBorder.setTitle("AxisGroups");
+    jScrollPane3.setBorder(legendBorder);
+    legendBorder.setTitle("Legends");
+    jLabel1.setText("Data Type");
+    cardPanel.setLayout(cardLayout1);
+    jLabel2.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel2.setText("Direction:");
+    oneDSpatialPanel.setLayout(gridBagLayout3);
+    jLabel3.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel3.setText("Range:");
+    delta1STF.setText("0.5");
+    delta1STF.setColumns(8);
+    max1STF.setText("10.0");
+    max1STF.setColumns(8);
+    min1STF.setText("0.0");
+    min1STF.setColumns(8);
+    jLabel4.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel4.setText("Type:");
+    jLabel5.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel5.setText("Amplitude:");
+    amp1STF.setText("1.0");
+    amp1STF.setColumns(8);
+    jLabel6.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel6.setText("Offset:");
+    off1STF.setText("0.0");
+    off1STF.setColumns(8);
+    jLabel7.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel7.setText("Period:");
+    per1STF.setText("5.0");
+    per1STF.setColumns(8);
+    jPanel5.setLayout(gridBagLayout4);
+    dataTypeCB.setModel(dataTypeModel);
+    dataTypeCB.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        dataTypeCB_actionPerformed(e);
+      }
+    });
+    dir1SCB.setModel(dir1SModel);
+    type1SCB.setModel(typeModel);
+    panelList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+      public void valueChanged(ListSelectionEvent e) {
+        panelList_valueChanged(e);
+      }
+    });
+    twoDSpatialPanel.setLayout(gridBagLayout5);
+    jLabel8.setText("Direction:");
+    dir2SCB.setModel(dir2SModel);
+    jLabel9.setText("Range1:");
+    delta12STF.setText("0.02");
+    delta12STF.setColumns(8);
+    max12STF.setText("1.0");
+    max12STF.setColumns(8);
+    min12STF.setText("0.0");
+    min12STF.setColumns(8);
+    jLabel10.setText("Range2:");
+    delta22STF.setText("0.02");
+    delta22STF.setColumns(8);
+    max22STF.setText("1.0");
+    max22STF.setColumns(8);
+    min22STF.setText("0.0");
+    min22STF.setColumns(8);
+    jLabel11.setText("Type:");
+    type2SCB.setModel(typeModel);
+    jLabel12.setText("Amplitude:");
+    amp2STF.setText("0.5");
+    amp2STF.setColumns(8);
+    jLabel13.setText("Offset:");
+    off2STF.setText("0.5");
+    off2STF.setColumns(8);
+    jLabel14.setText("Period:");
+    per2STF.setText("0.2");
+    per2STF.setColumns(8);
+    jPanel4.setLayout(gridBagLayout6);
+    jPanel6.setLayout(gridBagLayout7);
+    oneDTimePanel.setLayout(gridBagLayout8);
+    amp1TTF.setColumns(8);
+    amp1TTF.setText("1.0");
+    type1TCB.setModel(typeModel);
+    max1TTF.setColumns(12);
+    max1TTF.setText("2001-06-12 00:00");
+    jLabel15.setText("Period:");
+    jLabel15.setHorizontalAlignment(SwingConstants.RIGHT);
+    off1TTF.setColumns(8);
+    off1TTF.setText("0.0");
+    jLabel16.setText("Offset:");
+    jLabel16.setHorizontalAlignment(SwingConstants.RIGHT);
+    per1TTF.setColumns(8);
+    per1TTF.setText("5.0");
+    jLabel17.setText("Amplitude:");
+    jLabel17.setHorizontalAlignment(SwingConstants.RIGHT);
+    min1TTF.setColumns(12);
+    min1TTF.setText("2001-02-11 00:00");
+    jLabel18.setText("Type:");
+    jLabel18.setHorizontalAlignment(SwingConstants.RIGHT);
+    jPanel7.setLayout(gridBagLayout9);
+    jLabel19.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel19.setText("Range:");
+    delta1TTF.setText("2");
+    delta1TTF.setColumns(4);
+    jLabel20.setText("Delta:");
+    twoDTimePanel.setLayout(gridBagLayout10);
+    jLabel110.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel110.setText("Amplitude:");
+    jLabel111.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel111.setText("Offset:");
+    jLabel112.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel112.setText("Period:");
+    delta22TTF.setColumns(4);
+    delta22TTF.setText("2");
+    amp2TTF.setText("1.0");
+    amp2TTF.setColumns(8);
+    type2TCB.setModel(typeModel);
+    max22TTF.setText("1990-06-02 00:00");
+    max22TTF.setColumns(12);
+    jPanel8.setLayout(gridBagLayout11);
+    off2TTF.setColumns(8);
+    off2TTF.setText("0.0");
+    jLabel113.setHorizontalAlignment(SwingConstants.RIGHT);
+    jLabel113.setText("Time Range:");
+    min22TTF.setColumns(12);
+    min22TTF.setText("1990-01-01 00:00");
+    jLabel114.setText("Type:");
+    jLabel114.setHorizontalAlignment(SwingConstants.RIGHT);
+    per2TTF.setColumns(8);
+    per2TTF.setText("5.0");
+    jLabel21.setText("Time Delta:");
+    jLabel22.setText("Depth Range:");
+    max12TTF.setColumns(8);
+    max12TTF.setText("10.0");
+    min12TTF.setColumns(8);
+    min12TTF.setText("0.0");
+    jPanel9.setLayout(gridBagLayout12);
+    delta12TTF.setText("0.5");
+    delta12TTF.setColumns(8);
+    pointPanel.setLayout(gridBagLayout13);
+    jPanel10.setLayout(gridBagLayout15);
+    delta2PTF.setText("0.1");
+    delta2PTF.setColumns(8);
+    jPanel11.setLayout(gridBagLayout14);
+    max2PTF.setText("1.0");
+    max2PTF.setColumns(8);
+    jLabel119.setText("Range2:");
+    min1PTF.setText("0.0");
+    min1PTF.setColumns(8);
+    delta1PTF.setText("0.1");
+    delta1PTF.setColumns(8);
+    max1PTF.setText("1.0");
+    max1PTF.setColumns(8);
+    jLabel23.setText("Range1:");
+    min2PTF.setText("0.0");
+    min2PTF.setColumns(8);
+    jLabel24.setText("Number Pts:");
+    numPTF.setText("25");
+    numPTF.setColumns(5);
+    vectorPanel.setLayout(gridBagLayout16);
+    this.getContentPane().add(jPanel1, BorderLayout.CENTER);
+    this.getContentPane().add(jPanel2,  BorderLayout.SOUTH);
+    jPanel2.add(okButton, null);
+    jPanel2.add(cancelButton, null);
+    jPanel1.add(sourcePanel,   new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
+    sourcePanel.add(jPanel3, BorderLayout.NORTH);
+    jPanel3.add(jLabel1, null);
+    jPanel3.add(dataTypeCB, null);
+    jPanel1.add(targetPanel,     new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
+    targetPanel.add(jScrollPane1,       new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
+    jScrollPane1.getViewport().add(panelList, null);
+    targetPanel.add(jScrollPane2,    new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
+    jScrollPane2.getViewport().add(axisGroupList, null);
+    targetPanel.add(jScrollPane3,   new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
+    jScrollPane3.getViewport().add(legendList, null);
+    sourcePanel.add(cardPanel, BorderLayout.CENTER);
+    cardPanel.add(oneDSpatialPanel,  "oneDSpatial");
+    cardPanel.add(twoDSpatialPanel, "twoDSpatial");
+    twoDSpatialPanel.add(jLabel8,   new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(dir2SCB,   new GridBagConstraints(1, 0, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(jLabel9,   new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(jPanel4,    new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    jPanel4.add(min12STF,      new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel4.add(max12STF,     new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel4.add(delta12STF,     new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
+    jPanel4.add(component2,   new GridBagConstraints(3, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    twoDSpatialPanel.add(jLabel10,   new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(jPanel6,    new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    jPanel6.add(min22STF,    new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel6.add(max22STF,     new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel6.add(delta22STF,    new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel6.add(component3,  new GridBagConstraints(3, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    twoDSpatialPanel.add(jLabel11,   new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(type2SCB,   new GridBagConstraints(1, 3, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(jLabel12,   new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(amp2STF,   new GridBagConstraints(1, 4, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(jLabel13,   new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(off2STF,   new GridBagConstraints(1, 5, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(jLabel14,   new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDSpatialPanel.add(per2STF,   new GridBagConstraints(1, 6, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    cardPanel.add(oneDTimePanel, "oneDTime");
+    jPanel7.add(min1TTF,  new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
+    jPanel7.add(max1TTF,  new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel7.add(component4,  new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    oneDTimePanel.add(jLabel20,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(delta1TTF,  new GridBagConstraints(1, 1, 1, 1, 0.01, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(jLabel19,               new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(amp1TTF,               new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(type1TCB,               new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(jLabel15,            new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(off1TTF,           new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(jLabel16,          new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(per1TTF,         new GridBagConstraints(1, 5, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(jLabel17,        new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(jLabel18,       new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDTimePanel.add(jPanel7,      new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    cardPanel.add(twoDTimePanel, "twoDTime");
+    jPanel8.add(min22TTF, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
+    jPanel8.add(max22TTF, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel8.add(component5, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    twoDTimePanel.add(off2TTF,                     new GridBagConstraints(1, 5, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jLabel113,                     new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jLabel114,                   new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(per2TTF,                  new GridBagConstraints(1, 6, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jLabel21,                   new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jLabel22,      new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jPanel9,     new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    jPanel9.add(min12TTF, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
+    jPanel9.add(max12TTF, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel9.add(delta12TTF, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel9.add(component6, new GridBagConstraints(3, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    twoDTimePanel.add(jLabel110,                new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jLabel111,               new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jLabel112,              new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(delta22TTF,             new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(amp2TTF,            new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(type2TCB,           new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    twoDTimePanel.add(jPanel8,           new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    cardPanel.add(pointPanel, "point");
+    jPanel10.add(min2PTF, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel10.add(max2PTF, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel10.add(delta2PTF, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel10.add(component7, new GridBagConstraints(3, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    pointPanel.add(jPanel11,                                   new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));
+    jPanel11.add(min1PTF, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel11.add(max1PTF, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel11.add(delta1PTF, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
+    jPanel11.add(component8, new GridBagConstraints(3, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    pointPanel.add(jLabel119,                             new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    pointPanel.add(jLabel23,                          new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    pointPanel.add(jPanel10,                      new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));
+    oneDSpatialPanel.add(jLabel2,     new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(dir1SCB,       new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(jLabel3,    new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(jPanel5,   new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    jPanel5.add(min1STF,        new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
+    jPanel5.add(max1STF,      new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel5.add(delta1STF,     new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    jPanel5.add(component1,   new GridBagConstraints(3, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    oneDSpatialPanel.add(jLabel4,   new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(type1SCB,   new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(jLabel5,   new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(amp1STF,   new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(jLabel6,    new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(off1STF,   new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(jLabel7,   new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
+    oneDSpatialPanel.add(per1STF,   new GridBagConstraints(1, 6, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    pointPanel.add(jLabel24,  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    pointPanel.add(numPTF,   new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    cardPanel.add(vectorPanel,   "vector");
+  }
+
+  void init() {
+    PanelModel pModel = page_.getPanelModel();
+    Iterator pItor = pModel.panelIterator();
+    String[] listData = new String[pModel.getPanelCount()];
+    int i=0;
+    while(pItor.hasNext()) {
+      PanelHolder panel = (PanelHolder)pItor.next();
+      listData[i++] = panel.getId();
+    }
+    panelList.setListData(listData);
+  }
+
+  void cancelButton_actionPerformed(ActionEvent e) {
+    setVisible(false);
+    dispose();
+  }
+
+  int getDirection(String dirValue) {
+    int dir = TestData.X_SERIES;
+    if(dirValue.equals("X_SERIES")) {
+      dir = TestData.X_SERIES;
+    } else if(dirValue.equals("Y_SERIES")) {
+      dir = TestData.Y_SERIES;
+    } else if(dirValue.equals("PROFILE")) {
+      dir = TestData.PROFILE;
+    } else if(dirValue.equals("LOG_LOG")) {
+      dir = TestData.LOG_LOG;
+    } else if(dirValue.equals("XY_GRID")) {
+      dir = TestData.XY_GRID;
+    } else if(dirValue.equals("XZ_GRID")) {
+      dir = TestData.XZ_GRID;
+    } else if(dirValue.equals("YZ_GRID")) {
+      dir = TestData.YZ_GRID;
+    } else if(dirValue.equals("TIME_SERIES")) {
+      dir = TestData.TIME_SERIES;
+    } else if(dirValue.equals("ZT_GRID")) {
+      dir = TestData.ZT_GRID;
+    }
+    return dir;
+  }
+
+  int getType(String typeValue) {
+    int type = TestData.RANDOM;
+    if(typeValue.equals("SINE")) {
+      type = TestData.SINE;
+    } else if(typeValue.equals("RANDOM")) {
+      type = TestData.RANDOM;
+    }
+    return type;
+  }
+
+  void okButton_actionPerformed(ActionEvent e) {
+    //
+    // define default colormap
+    //
+    int[] red =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  7, 23, 39, 55, 71, 87,103,
+       119,135,151,167,183,199,215,231,
+       247,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,246,228,211,193,175,158,140};
+    int[] green =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0, 11, 27, 43, 59, 75, 91,107,
+       123,139,155,171,187,203,219,235,
+       251,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0};
+    int[] blue =
+    {  0,143,159,175,191,207,223,239,
+       255,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0};
+
+    SGTData data = null;
+    Attribute attr = null;
+    String dataType = (String)dataTypeCB.getSelectedItem();
+    if(dataType.equals("1-d Spatial")) {
+      int dir = getDirection((String)dir1SCB.getSelectedItem());
+      int type = getType((String)type1SCB.getSelectedItem());
+      double min = Double.parseDouble(min1STF.getText());
+      double max = Double.parseDouble(max1STF.getText());
+      double delta = Double.parseDouble(delta1STF.getText());
+      Range2D range = new Range2D(min, max, delta);
+
+      float amp = Float.parseFloat(amp1STF.getText());
+      float off = Float.parseFloat(off1STF.getText());
+      float per = Float.parseFloat(per1STF.getText());
+
+      TestData td = new TestData(dir, range, type, amp, off, per);
+      data = td.getSGTData();
+      attr = new LineAttribute(LineAttribute.SOLID, Color.blue);
+    } else if(dataType.equals("2-d Spatial")) {
+      ColorMap cmap;
+      int dir = getDirection((String)dir2SCB.getSelectedItem());
+      int type = getType((String)type2SCB.getSelectedItem());
+      double min1 = Double.parseDouble(min12STF.getText());
+      double max1 = Double.parseDouble(max12STF.getText());
+      double delta1 = Double.parseDouble(delta12STF.getText());
+      Range2D range1 = new Range2D(min1, max1, delta1);
+
+      double min2 = Double.parseDouble(min22STF.getText());
+      double max2 = Double.parseDouble(max22STF.getText());
+      double delta2 = Double.parseDouble(delta22STF.getText());
+      Range2D range2 = new Range2D(min2, max2, delta2);
+
+      float amp = Float.parseFloat(amp2STF.getText());
+      float off = Float.parseFloat(off2STF.getText());
+      float per = Float.parseFloat(per2STF.getText());
+
+      TestData td = new TestData(dir, range1, range2, type, amp, off, per);
+      data = td.getSGTData();
+      cmap = new IndexedColorMap(red, green, blue);
+      LinearTransform ctrans =
+        new LinearTransform(0.0, (double)red.length, 0.0, 1.0);
+      ((IndexedColorMap)cmap).setTransform(ctrans);
+      attr = new GridAttribute(GridAttribute.RASTER, cmap);
+//      attr = new GridAttribute();
+    }else if(dataType.equals("1-d Time")) {
+      int dir = TestData.TIME_SERIES;
+      int type = getType((String)type1TCB.getSelectedItem());
+
+      GeoDate start = null;
+      GeoDate end = null;
+      String format = "yyyy-MM-dd HH:mm";
+      String min1 = min1TTF.getText();
+      String max1 = max1TTF.getText();
+      try {
+        start = new GeoDate(min1, format);
+        end = new GeoDate(max1, format);
+      } catch (IllegalTimeValue itf) {
+        String message = "Illegal time string " + "'" + min1 + "' or '" + max1 + "'" +
+                         "\nshould be of the form " + format;
+        JOptionPane.showMessageDialog(this, message,
+                                      "Error in Time Value", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+
+      float delta = Float.parseFloat(delta1TTF.getText());
+
+      float amp = Float.parseFloat(amp1TTF.getText());
+      float off = Float.parseFloat(off1TTF.getText());
+      float per = Float.parseFloat(per1TTF.getText());
+      TestData td = new TestData(dir, new TimeRange(start, end), delta,
+                                 type, amp, off, per);
+      data = td.getSGTData();
+      attr = new LineAttribute(LineAttribute.SOLID, Color.blue.brighter());
+    } else if(dataType.equals("2-d Time")) {
+      ColorMap cmap;
+      int dir = TestData.ZT_GRID;
+      int type = getType((String)type2TCB.getSelectedItem());
+
+      double smin1 = Double.parseDouble(min12TTF.getText());
+      double smax1 = Double.parseDouble(max12TTF.getText());
+      double sdelta1 = Double.parseDouble(delta12TTF.getText());
+      Range2D range1 = new Range2D(smin1, smax1, sdelta1);
+
+      GeoDate start = null;
+      GeoDate end = null;
+      String format = "yyyy-MM-dd HH:mm";
+      String min1 = min22TTF.getText();
+      String max1 = max22TTF.getText();
+      try {
+        start = new GeoDate(min1, format);
+        end = new GeoDate(max1, format);
+      } catch (IllegalTimeValue itf) {
+        String message = "Illegal time string " + "'" + min1 + "' or '" + max1 + "'" +
+                         "\nshould be of the form " + format;
+        JOptionPane.showMessageDialog(this, message,
+                                      "Error in Time Value", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+
+      float delta = Float.parseFloat(delta22TTF.getText());
+
+      float amp = Float.parseFloat(amp2TTF.getText());
+      float off = Float.parseFloat(off2TTF.getText());
+      float per = Float.parseFloat(per2TTF.getText());
+
+      TestData td = new TestData(dir, range1, new TimeRange(start, end), delta,
+                                 type, amp, off, per);
+      data = td.getSGTData();
+      cmap = new IndexedColorMap(red, green, blue);
+      LinearTransform ctrans =
+        new LinearTransform(0.0, (double)red.length, 0.0, 1.0);
+      ((IndexedColorMap)cmap).setTransform(ctrans);
+      attr = new GridAttribute(GridAttribute.RASTER, cmap);
+    } else if(dataType.equals("Point")) {
+      double min1 = Double.parseDouble(min1PTF.getText());
+      double max1 = Double.parseDouble(max1PTF.getText());
+      double delta1 = Double.parseDouble(delta1PTF.getText());
+      Range2D range1 = new Range2D(min1, max1, delta1);
+
+      double min2 = Double.parseDouble(min2PTF.getText());
+      double max2 = Double.parseDouble(max2PTF.getText());
+      double delta2 = Double.parseDouble(delta2PTF.getText());
+      Range2D range2 = new Range2D(min2, max2, delta2);
+
+      int num = Integer.parseInt(numPTF.getText());
+
+      TestData td = new TestData(range1, range2, num);
+      data = td.getCollection();
+      attr = new PointAttribute(10, Color.red);
+      ((PointAttribute)attr).setMarkHeightP(0.20);
+    } else if(dataType.equals("Vector")) {
+      SGTGrid uComp;
+      SGTGrid vComp;
+//      SGTVector vector;
+      TestData td;
+      /*
+       * Create a test grid with sinasoidal-ramp data.
+       */
+      Range2D xr = new Range2D(190.0f, 250.0f, 3.0f);
+      Range2D yr = new Range2D(0.0f, 45.0f, 3.0f);
+      td = new TestData(TestData.XY_GRID, xr, yr,
+                        TestData.SINE_RAMP, 20.0f, 10.f, 5.0f);
+      uComp = (SGTGrid)td.getSGTData();
+      td = new TestData(TestData.XY_GRID, xr, yr,
+                        TestData.SINE_RAMP, 20.0f, 0.f, 3.0f);
+      vComp = (SGTGrid)td.getSGTData();
+      data = new SGTVector(uComp, vComp);
+      attr = new VectorAttribute(0.0075, Color.red);
+      ((VectorAttribute)attr).setHeadScale(0.5);
+    }
+    PanelHolder pHolder = null;
+    if(!panelList.isSelectionEmpty())
+      pHolder = page_.getPanelModel().findPanelHolder((String)panelList.getSelectedValue());
+    DataGroup axisGroup = null;
+    if(!axisGroupList.isSelectionEmpty())
+      axisGroup = pHolder.findDataGroup((String)axisGroupList.getSelectedValue());
+    Legend legend = null;
+    if(!legendList.isSelectionEmpty())
+      legend = pHolder.findLegend((String)legendList.getSelectedValue());
+    //
+    if((pHolder == null) || (axisGroup == null)) {
+      JOptionPane.showMessageDialog(this, "A Panel and DataGroup must be selected.\n\n" +
+                                    "Please select a Panel and DataGroup.",
+                                    "Panel/DataGroup Selection Error",
+                                    JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    page_.getDataModel().addData(data, attr, pHolder, axisGroup, legend);
+    setVisible(false);
+    dispose();
+  }
+
+  void dataTypeCB_actionPerformed(ActionEvent e) {
+    if(Page.DEBUG) System.out.println("ActionPerformed: new value = " + dataTypeCB.getSelectedItem());
+    int index = dataTypeCB.getSelectedIndex();
+    switch(index) {
+      case 0:   // oneDSpatial
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "oneDSpatial");
+        break;
+      case 1:   // twoDSpatial
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "twoDSpatial");
+        break;
+      case 2:   // oneDTime
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "oneDTime");
+        break;
+      case 3:   // twoDTime
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "twoDTime");
+        break;
+      case 4:  //Point
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "point");
+        break;
+      case 5:  //Vector
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "vector");
+        break;
+      default:
+        JOptionPane.showMessageDialog(this, "Selection Not Yet Implemented",
+                                      "Not Implemented", JOptionPane.ERROR_MESSAGE);
+        dataTypeCB.setSelectedIndex(0);
+        ((CardLayout)cardPanel.getLayout()).show(cardPanel, "oneDSpatial");
+    }
+  }
+
+  void panelList_valueChanged(ListSelectionEvent e) {
+    String pid = (String)panelList.getSelectedValue();
+    PanelHolder pHolder = page_.getPanelModel().findPanelHolder(pid);
+    Iterator agItor = pHolder.dataGroupIterator();
+    String[] agData = new String[pHolder.getDataGroupSize()];
+    int i=0;
+    while(agItor.hasNext()) {
+      agData[i++] = ((DataGroup)agItor.next()).getId();
+    }
+    axisGroupList.setListData(agData);
+    Iterator lgItor = pHolder.legendIterator();
+    String[] lgData = new String[pHolder.getLegendSize()];
+    i=0;
+    while(lgItor.hasNext()) {
+      lgData[i++] = ((Legend)lgItor.next()).getId();
+    }
+    legendList.setListData(lgData);
+  }
+
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemo.java
new file mode 100755
index 0000000..314a2b1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemo.java
@@ -0,0 +1,62 @@
+/*
+ * $Id: BeanDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import javax.swing.UIManager;
+import java.awt.*;
+
+/**
+ * Example demonstrating the use of the SGT Bean classes.  This application
+ * looks for the BeanDemoPanelModel.xml file in the same directory as
+ * gov.noaa.pmel.sgt.beans.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 3.0
+ **/
+public class BeanDemo {
+  private boolean packFrame = false;
+
+  //Construct the application
+  public BeanDemo() {
+    BeanDemoFrame frame = new BeanDemoFrame();
+    //Validate frames that have preset sizes
+    //Pack frames that have useful preferred size info, e.g. from their layout
+    if (packFrame) {
+      frame.pack();
+    }
+    else {
+      frame.validate();
+    }
+    //Center the window
+    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+    Dimension frameSize = frame.getSize();
+    if (frameSize.height > screenSize.height) {
+      frameSize.height = screenSize.height;
+    }
+    if (frameSize.width > screenSize.width) {
+      frameSize.width = screenSize.width;
+    }
+    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
+    frame.setVisible(true);
+  }
+  //Main method
+  public static void main(String[] args) {
+    try {
+      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+    new BeanDemo();
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemoFrame.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemoFrame.java
new file mode 100755
index 0000000..58d2edb
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemoFrame.java
@@ -0,0 +1,368 @@
+/*
+ * $Id: BeanDemoFrame.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import java.awt.*;
+import java.awt.print.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+
+import gov.noaa.pmel.sgt.beans.*;
+import gov.noaa.pmel.sgt.dm.*;
+import gov.noaa.pmel.sgt.AbstractPane;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.sgt.IndexedColorMap;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.Attribute;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.util.*;
+import gov.noaa.pmel.swing.JSystemPropertiesDialog;
+
+/**
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 3.0
+ **/
+class BeanDemoFrame extends JFrame {
+  private Page page = new Page();
+  private PanelModel panelModel = new PanelModel();
+  private DataModel dataModel = new DataModel();
+  private SGTData timeSeries;
+  private Attribute timeSeriesAttr;
+  private SGTData grid;
+  private Attribute gridAttr;
+  private SGTData line;
+  private Attribute lineAttr;
+
+  private JPanel contentPane;
+  private JMenuBar jMenuBar1 = new JMenuBar();
+  private JMenu jMenuFile = new JMenu();
+  private JMenuItem jMenuFileExit = new JMenuItem();
+  private JMenu jMenuHelp = new JMenu();
+  private JMenuItem jMenuHelpAbout = new JMenuItem();
+  private BorderLayout borderLayout1 = new BorderLayout();
+  private JMenu jMenuView = new JMenu();
+  private JMenuItem jMenuViewReset = new JMenuItem();
+  private JMenuItem jMenuViewTree = new JMenuItem();
+  private JPanel pagePanel = new JPanel();
+  private BorderLayout borderLayout2 = new BorderLayout();
+  private JMenuItem jMenuHelpProps = new JMenuItem();
+  private JMenu jMenuEdit = new JMenu();
+  private JMenuItem jMenuEditData = new JMenuItem();
+  private JMenuItem jMenuEditPM = new JMenuItem();
+  private JMenuItem jMenuFilePrint = new JMenuItem();
+  private JMenuItem jMenuFilePage = new JMenuItem();
+
+  private PageFormat pageFormat = PrinterJob.getPrinterJob().defaultPage();
+
+  //Construct the frame
+  public BeanDemoFrame() {
+    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
+    page.getJPane().setBackground(Color.lightGray);
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+    createGraphic();
+    pack();
+  }
+  //Component initialization
+  private void jbInit() throws Exception  {
+    //setIconImage(Toolkit.getDefaultToolkit().createImage(BeanDemoFrame.class.getResource("[Your Icon]")));
+    contentPane = (JPanel) this.getContentPane();
+    contentPane.setLayout(borderLayout1);
+//    this.setSize(new Dimension(501, 450));
+    this.setTitle("SGT Bean Demo");
+    jMenuFile.setText("File");
+    jMenuFileExit.setText("Exit");
+    jMenuFileExit.addActionListener(new ActionListener()  {
+      public void actionPerformed(ActionEvent e) {
+        jMenuFileExit_actionPerformed(e);
+      }
+    });
+    jMenuHelp.setText("Help");
+    jMenuHelpAbout.setText("About");
+    jMenuHelpAbout.addActionListener(new ActionListener()  {
+      public void actionPerformed(ActionEvent e) {
+        jMenuHelpAbout_actionPerformed(e);
+      }
+    });
+    jMenuView.setText("View");
+    jMenuViewReset.setText("Reset All Zoom");
+    jMenuViewReset.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuViewReset_actionPerformed(e);
+      }
+    });
+    jMenuViewTree.setText("Class Tree...");
+    jMenuViewTree.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuViewTree_actionPerformed(e);
+      }
+    });
+    pagePanel.setLayout(borderLayout2);
+    jMenuHelpProps.setText("System Properties...");
+    jMenuHelpProps.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuHelpProps_actionPerformed(e);
+      }
+    });
+    jMenuEdit.setText("Edit");
+    jMenuEditData.setText("Add Data...");
+    jMenuEditData.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuEditData_actionPerformed(e);
+      }
+    });
+    jMenuEditPM.setText("PanelModel");
+    jMenuEditPM.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuEditPM_actionPerformed(e);
+      }
+    });
+    jMenuFilePrint.setText("Print...");
+    jMenuFilePrint.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuFilePrint_actionPerformed(e);
+      }
+    });
+    jMenuFilePage.setText("Page Layout...");
+    jMenuFilePage.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        jMenuFilePage_actionPerformed(e);
+      }
+    });
+    jMenuFile.add(jMenuFilePage);
+    jMenuFile.add(jMenuFilePrint);
+    jMenuFile.addSeparator();
+    jMenuFile.add(jMenuFileExit);
+    jMenuHelp.add(jMenuHelpProps);
+    jMenuHelp.add(jMenuHelpAbout);
+    jMenuBar1.add(jMenuFile);
+    jMenuBar1.add(jMenuEdit);
+    jMenuBar1.add(jMenuView);
+    jMenuBar1.add(jMenuHelp);
+    jMenuView.add(jMenuViewReset);
+    jMenuView.add(jMenuViewTree);
+    contentPane.add(pagePanel, BorderLayout.CENTER);
+    jMenuEdit.add(jMenuEditData);
+    jMenuEdit.add(jMenuEditPM);
+    this.setJMenuBar(jMenuBar1);
+  }
+  //File | Exit action performed
+  private void jMenuFileExit_actionPerformed(ActionEvent e) {
+    System.exit(0);
+  }
+  //Help | About action performed
+  private void jMenuHelpAbout_actionPerformed(ActionEvent e) {
+    JOptionPane.showMessageDialog(this, "BeanDemo: SGT version 3.0",
+                                  "About BeanDemo",
+                                  JOptionPane.INFORMATION_MESSAGE);
+  }
+  //Overridden so we can exit when window is closed
+  protected void processWindowEvent(WindowEvent e) {
+    super.processWindowEvent(e);
+    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
+      jMenuFileExit_actionPerformed(null);
+    }
+  }
+
+  private void createGraphic() {
+    pagePanel.add(page, BorderLayout.CENTER);
+    page.setDataModel(dataModel);
+    try {
+      panelModel = PanelModel.loadFromXML(getClass().getResource("BeanDemoPanelModel.xml").openStream());
+    } catch (Exception e) {
+      e.printStackTrace();
+      System.exit(1);
+    }
+    page.setPanelModel(panelModel);
+    PanelHolder ul = panelModel.findPanelHolder("UpperLeft");
+    DataGroup uldg = ul.findDataGroup("Grid");
+    Legend ullg = ul.findLegend("ColorKey");
+    createGrid();
+    dataModel.addData(grid, gridAttr, ul, uldg, ullg);
+
+    PanelHolder ur = panelModel.findPanelHolder("UpperRight");
+    DataGroup urdg = ur.findDataGroup("Random");
+    createLine();
+    dataModel.addData(line, lineAttr, ur, urdg, null);
+
+    PanelHolder bt = panelModel.findPanelHolder("Bottom");
+    DataGroup btdg = bt.findDataGroup("TimeSeries");
+    createTimeSeries();
+    dataModel.addData(timeSeries, timeSeriesAttr, bt, btdg, null);
+    // get datasets
+
+  }
+
+  private void createTimeSeries() {
+    int dir = TestData.TIME_SERIES;
+    int type = TestData.RANDOM;
+
+    GeoDate start = null;
+    GeoDate end = null;
+    String format = "yyyy-MM-dd HH:mm";
+    String min1 = "2001-02-12 00:00";
+    String max1 = "2001-06-10 00:00";
+    try {
+      start = new GeoDate(min1, format);
+      end = new GeoDate(max1, format);
+    } catch (IllegalTimeValue itf) {
+      String message = "Illegal time string " + "'" + min1 + "' or '" + max1 + "'" +
+                       "\nshould be of the form " + format;
+      JOptionPane.showMessageDialog(this, message,
+                                    "Error in Time Value", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+
+    float delta = 2.0f;
+
+    float amp = 1.0f;
+    float off = 0.0f;
+    float per = 5.0f;
+    TestData td = new TestData(dir, new TimeRange(start, end), delta,
+                               type, amp, off, per);
+    timeSeries = td.getSGTData();
+    timeSeriesAttr = new LineAttribute(LineAttribute.SOLID, Color.blue.brighter());
+  }
+
+  void createLine() {
+    int dir = TestData.X_SERIES;
+    int type = TestData.RANDOM;
+    double min = 0.0;
+    double max = 10.0;
+    double delta = 0.5;
+    Range2D range = new Range2D(min, max, delta);
+
+    float amp = 1.0f;
+    float off = 0.0f;
+    float per = 5.0f;
+
+    TestData td = new TestData(dir, range, type, amp, off, per);
+    line = td.getSGTData();
+    lineAttr = new LineAttribute(LineAttribute.SOLID, Color.blue);
+  }
+
+  void createGrid() {
+    ColorMap cmap;
+    int[] red =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  7, 23, 39, 55, 71, 87,103,
+       119,135,151,167,183,199,215,231,
+       247,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,246,228,211,193,175,158,140};
+    int[] green =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0, 11, 27, 43, 59, 75, 91,107,
+       123,139,155,171,187,203,219,235,
+       251,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0};
+    int[] blue =
+    {  0,143,159,175,191,207,223,239,
+       255,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0};
+
+    int dir = TestData.XY_GRID;
+    int type = TestData.SINE;
+    double min1 = 0.0;
+    double max1 = 1.0;
+    double delta1 = 0.02;
+    Range2D range1 = new Range2D(min1, max1, delta1);
+
+    double min2 = 0.0;
+    double max2 = 1.0;
+    double delta2 = 0.02;
+    Range2D range2 = new Range2D(min2, max2, delta2);
+
+    float amp = 0.5f;
+    float off = 0.5f;
+    float per = 0.2f;
+
+    TestData td = new TestData(dir, range1, range2, type, amp, off, per);
+    grid = td.getSGTData();
+    cmap = new IndexedColorMap(red, green, blue);
+    LinearTransform ctrans =
+      new LinearTransform(0.0, (double)red.length, 0.0, 1.0);
+    ((IndexedColorMap)cmap).setTransform(ctrans);
+    gridAttr = new GridAttribute(GridAttribute.RASTER, cmap);
+  }
+
+  void jMenuViewReset_actionPerformed(ActionEvent e) {
+    page.resetZoom();
+  }
+
+  void jMenuViewTree_actionPerformed(ActionEvent e) {
+    JClassTree ct = new JClassTree();
+    ct.setModal(false);
+    ct.setJPane(page.getJPane());
+    ct.show();
+  }
+
+  void jMenuEditData_actionPerformed(ActionEvent e) {
+    AddDataFrame adf = new AddDataFrame(page);
+    adf.setVisible(true);
+  }
+
+  void jMenuEditPM_actionPerformed(ActionEvent e) {
+    PanelModelEditor pme = new PanelModelEditor(panelModel);
+    pme.setVisible(true);
+  }
+
+  void jMenuHelpProps_actionPerformed(ActionEvent e) {
+    JSystemPropertiesDialog sysProps =
+      new JSystemPropertiesDialog(this, "System Properties", false);
+    sysProps.show();
+  }
+
+  void jMenuFilePrint_actionPerformed(ActionEvent e) {
+    Color saveColor;
+    JPane pane = page.getJPane();
+
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+    printJob.setPrintable(page, pageFormat);
+    printJob.setJobName("BeanDemo");
+    if(printJob.printDialog()) {
+      try {
+        RepaintManager currentManager = RepaintManager.currentManager(pane);
+        currentManager.setDoubleBufferingEnabled(false);
+        printJob.print();
+        currentManager.setDoubleBufferingEnabled(true);
+      } catch (PrinterException pe) {
+        System.out.println("Error printing: " + pe);
+      }
+    }
+  }
+
+  void jMenuFilePage_actionPerformed(ActionEvent e) {
+    PrinterJob pj = PrinterJob.getPrinterJob();
+    pageFormat = pj.pageDialog(pageFormat);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml
new file mode 100755
index 0000000..e36330c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/BeanDemoPanelModel.xml
@@ -0,0 +1,695 @@
+<?xml version="1.0" encoding="UTF-8"?> 
+<java version="1.4.1_01" class="java.beans.XMLDecoder"> 
+ <object class="gov.noaa.pmel.sgt.beans.PanelModel"> 
+  <void property="printScaleMode"> 
+   <int>0</int> 
+  </void> 
+  <void property="pageSize"> 
+   <object class="java.awt.Dimension"> 
+    <int>501</int> 
+    <int>400</int> 
+   </object> 
+  </void> 
+  <void property="panelList"> 
+   <void method="put"> 
+    <string>UpperRight</string> 
+    <object class="gov.noaa.pmel.sgt.beans.PanelHolder"> 
+     <void property="border"> 
+      <object class="javax.swing.border.BevelBorder"> 
+       <int>0</int> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>255</int> 
+       </object> 
+      </object> 
+     </void> 
+     <void property="bounds"> 
+      <object class="java.awt.Rectangle"> 
+       <int>300</int> 
+       <int>0</int> 
+       <int>200</int> 
+       <int>293</int> 
+      </object> 
+     </void> 
+     <void property="dataGroups"> 
+      <void method="put"> 
+       <string>Random</string> 
+       <object class="gov.noaa.pmel.sgt.beans.DataGroup"> 
+        <void property="XAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="width"> 
+           <double>2.097222328186035</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.5</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="VAlign"> 
+           <int>0</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>394</int> 
+            <int>278</int> 
+            <int>34</int> 
+            <int>10</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>12</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>411</int> 
+            <int>276</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Random</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double0" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double0"/> 
+          </void> 
+          <void id="SoTValue$Double1" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double1"/> 
+          </void> 
+          <void id="SoTValue$Double2" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double2"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="YAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>3.125</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.5</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>308</int> 
+            <int>128</int> 
+            <int>10</int> 
+            <int>34</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>12</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>316</int> 
+            <int>145</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+          <void property="orientation"> 
+           <int>1</int> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Random</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double3" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double3"/> 
+          </void> 
+          <void id="SoTValue$Double4" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double4"/> 
+          </void> 
+          <void id="SoTValue$Double5" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double5"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="ZRangeU"> 
+         <void id="SoTValue$Double6" property="delta"/> 
+         <void property="delta"> 
+          <object idref="SoTValue$Double6"/> 
+         </void> 
+         <void id="SoTValue$Double7" property="end"/> 
+         <void property="end"> 
+          <object idref="SoTValue$Double7"/> 
+         </void> 
+         <void id="SoTValue$Double8" property="start"/> 
+         <void property="start"> 
+          <object idref="SoTValue$Double8"/> 
+         </void> 
+        </void> 
+        <void property="id"> 
+         <string>Random</string> 
+        </void> 
+        <void id="Margin0" property="margin"> 
+         <void property="right"> 
+          <float>0.18055555</float> 
+         </void> 
+         <void property="top"> 
+          <float>0.44444445</float> 
+         </void> 
+        </void> 
+        <void property="margin"> 
+         <object idref="Margin0"/> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+     <void property="id"> 
+      <string>UpperRight</string> 
+     </void> 
+     <void property="labels"> 
+      <void method="put"> 
+       <string>Label0</string> 
+       <object class="gov.noaa.pmel.sgt.beans.Label"> 
+        <void property="boundsP"> 
+         <object class="gov.noaa.pmel.util.Rectangle2D$Double"> 
+          <void property="height"> 
+           <double>0.25</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.75</double> 
+          </void> 
+          <void property="x"> 
+           <double>1.0138888359069824</double> 
+          </void> 
+          <void property="y"> 
+           <double>3.75</double> 
+          </void> 
+         </object> 
+        </void> 
+        <void property="id"> 
+         <string>Label0</string> 
+        </void> 
+        <void property="text"> 
+         <string>Bean Demo</string> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+    </object> 
+   </void> 
+   <void method="put"> 
+    <string>UpperLeft</string> 
+    <object class="gov.noaa.pmel.sgt.beans.PanelHolder"> 
+     <void property="border"> 
+      <object class="javax.swing.border.BevelBorder"> 
+       <int>0</int> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>255</int> 
+       </object> 
+      </object> 
+     </void> 
+     <void property="bounds"> 
+      <object class="java.awt.Rectangle"> 
+       <int>0</int> 
+       <int>0</int> 
+       <int>300</int> 
+       <int>293</int> 
+      </object> 
+     </void> 
+     <void property="dataGroups"> 
+      <void method="put"> 
+       <string>Grid</string> 
+       <object class="gov.noaa.pmel.sgt.beans.DataGroup"> 
+        <void property="XAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="width"> 
+           <double>2.375</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.5</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="VAlign"> 
+           <int>0</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>102</int> 
+            <int>279</int> 
+            <int>38</int> 
+            <int>11</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>13</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>121</int> 
+            <int>277</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Grid</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double9" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double9"/> 
+          </void> 
+          <void id="SoTValue$Double10" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double10"/> 
+          </void> 
+          <void id="SoTValue$Double11" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double11"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="YAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>3.277777671813965</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.5</double> 
+          </void> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>7</int> 
+            <int>121</int> 
+            <int>11</int> 
+            <int>38</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>13</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>16</int> 
+            <int>140</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+          <void property="orientation"> 
+           <int>1</int> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>Grid</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double12" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double12"/> 
+          </void> 
+          <void id="SoTValue$Double13" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double13"/> 
+          </void> 
+          <void id="SoTValue$Double14" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double14"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="ZRangeU"> 
+         <void id="SoTValue$Double15" property="delta"/> 
+         <void property="delta"> 
+          <object idref="SoTValue$Double15"/> 
+         </void> 
+         <void id="SoTValue$Double16" property="end"/> 
+         <void property="end"> 
+          <object idref="SoTValue$Double16"/> 
+         </void> 
+         <void id="SoTValue$Double17" property="start"/> 
+         <void property="start"> 
+          <object idref="SoTValue$Double17"/> 
+         </void> 
+        </void> 
+        <void property="id"> 
+         <string>Grid</string> 
+        </void> 
+        <void id="Margin1" property="margin"> 
+         <void property="right"> 
+          <float>1.2916666</float> 
+         </void> 
+         <void property="top"> 
+          <float>0.29166666</float> 
+         </void> 
+        </void> 
+        <void property="margin"> 
+         <object idref="Margin1"/> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+     <void property="id"> 
+      <string>UpperLeft</string> 
+     </void> 
+     <void property="legends"> 
+      <void method="put"> 
+       <string>ColorKey</string> 
+       <object class="gov.noaa.pmel.sgt.beans.Legend"> 
+        <void property="boundsP"> 
+         <object class="gov.noaa.pmel.util.Rectangle2D$Double"> 
+          <void property="height"> 
+           <double>3.2916667461395264</double> 
+          </void> 
+          <void property="width"> 
+           <double>1.125</double> 
+          </void> 
+          <void property="x"> 
+           <double>2.930555582046509</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.4861111044883728</double> 
+          </void> 
+         </object> 
+        </void> 
+        <void property="id"> 
+         <string>ColorKey</string> 
+        </void> 
+        <void property="scaleSignificantDigits"> 
+         <int>1</int> 
+        </void> 
+        <void property="type"> 
+         <int>1</int> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+    </object> 
+   </void> 
+   <void method="put"> 
+    <string>Bottom</string> 
+    <object class="gov.noaa.pmel.sgt.beans.PanelHolder"> 
+     <void property="border"> 
+      <object class="javax.swing.border.BevelBorder"> 
+       <int>0</int> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>124</int> 
+        <int>255</int> 
+       </object> 
+       <object class="java.awt.Color"> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>178</int> 
+        <int>255</int> 
+       </object> 
+      </object> 
+     </void> 
+     <void property="bounds"> 
+      <object class="java.awt.Rectangle"> 
+       <int>0</int> 
+       <int>293</int> 
+       <int>500</int> 
+       <int>107</int> 
+      </object> 
+     </void> 
+     <void property="dataGroups"> 
+      <void method="put"> 
+       <string>TimeSeries</string> 
+       <object class="gov.noaa.pmel.sgt.beans.DataGroup"> 
+        <void property="XAxisHolder"> 
+         <void property="axisType"> 
+          <int>3</int> 
+         </void> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="width"> 
+           <double>6.291666507720947</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.5</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>TimeSeries</string> 
+         </void> 
+         <void property="userRange"> 
+          <object class="gov.noaa.pmel.util.SoTRange$Time"> 
+           <void id="SoTValue$Time0" property="delta"> 
+            <void property="value"> 
+             <long>172800000</long> 
+            </void> 
+           </void> 
+           <void property="delta"> 
+            <object idref="SoTValue$Time0"/> 
+           </void> 
+           <void id="SoTValue$Time1" property="end"> 
+            <void property="value"> 
+             <long>978307200000</long> 
+            </void> 
+           </void> 
+           <void property="end"> 
+            <object idref="SoTValue$Time1"/> 
+           </void> 
+           <void id="SoTValue$Time2" property="start"> 
+            <void property="value"> 
+             <long>946684800000</long> 
+            </void> 
+           </void> 
+           <void property="start"> 
+            <object idref="SoTValue$Time2"/> 
+           </void> 
+          </object> 
+         </void> 
+        </void> 
+        <void property="YAxisHolder"> 
+         <void property="boundsP"> 
+          <void property="height"> 
+           <double>0.875</double> 
+          </void> 
+          <void property="width"> 
+           <double>0.4166666567325592</double> 
+          </void> 
+          <void property="x"> 
+           <double>0.0833333358168602</double> 
+          </void> 
+          <void property="y"> 
+           <double>0.5</double> 
+          </void> 
+         </void> 
+         <void property="labelInterval"> 
+          <int>4</int> 
+         </void> 
+         <void property="title"> 
+          <void property="HAlign"> 
+           <int>1</int> 
+          </void> 
+          <void property="bounds"> 
+           <object class="java.awt.Rectangle"> 
+            <int>15</int> 
+            <int>317</int> 
+            <int>10</int> 
+            <int>34</int> 
+           </object> 
+          </void> 
+          <void property="font"> 
+           <object class="java.awt.Font"> 
+            <string>Helvetica</string> 
+            <int>0</int> 
+            <int>12</int> 
+           </object> 
+          </void> 
+          <void property="location"> 
+           <object class="java.awt.Point"> 
+            <int>23</int> 
+            <int>334</int> 
+           </object> 
+          </void> 
+          <void property="moveable"> 
+           <boolean>false</boolean> 
+          </void> 
+          <void property="orientation"> 
+           <int>1</int> 
+          </void> 
+         </void> 
+         <void property="transformGroup"> 
+          <string>TimeSeries</string> 
+         </void> 
+         <void property="userRange"> 
+          <void id="SoTValue$Double18" property="delta"/> 
+          <void property="delta"> 
+           <object idref="SoTValue$Double18"/> 
+          </void> 
+          <void id="SoTValue$Double19" property="end"/> 
+          <void property="end"> 
+           <object idref="SoTValue$Double19"/> 
+          </void> 
+          <void id="SoTValue$Double20" property="start"/> 
+          <void property="start"> 
+           <object idref="SoTValue$Double20"/> 
+          </void> 
+         </void> 
+        </void> 
+        <void property="ZRangeU"> 
+         <void id="SoTValue$Double21" property="delta"/> 
+         <void property="delta"> 
+          <object idref="SoTValue$Double21"/> 
+         </void> 
+         <void id="SoTValue$Double22" property="end"/> 
+         <void property="end"> 
+          <object idref="SoTValue$Double22"/> 
+         </void> 
+         <void id="SoTValue$Double23" property="start"/> 
+         <void property="start"> 
+          <object idref="SoTValue$Double23"/> 
+         </void> 
+        </void> 
+        <void property="id"> 
+         <string>TimeSeries</string> 
+        </void> 
+        <void id="Margin2" property="margin"> 
+         <void property="right"> 
+          <float>0.15277778</float> 
+         </void> 
+         <void property="top"> 
+          <float>0.11111111</float> 
+         </void> 
+        </void> 
+        <void property="margin"> 
+         <object idref="Margin2"/> 
+        </void> 
+       </object> 
+      </void> 
+     </void> 
+     <void property="id"> 
+      <string>Bottom</string> 
+     </void> 
+    </object> 
+   </void> 
+  </void> 
+ </object> 
+</java> 
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JDesktopDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JDesktopDemo.java
new file mode 100755
index 0000000..f1f5eb6
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JDesktopDemo.java
@@ -0,0 +1,300 @@
+/*
+ * $Id: JDesktopDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+import javax.swing.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import gov.noaa.pmel.sgt.*;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Dimension2D;
+
+/**
+ * Example demonstrating the use of <code>PropertyChangeEvents</code>
+ * in the datamodel.  <code>JDesktopDemo</code> constructs the plot
+ * from basic <code>sgt</code> objects. 
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.1
+ */
+
+public class JDesktopDemo extends JApplet implements PropertyChangeListener {
+  PseudoRealTimeData rtData_;
+  JPane pane_;
+  Layer layer_;
+  TimeAxis xbot_;
+  PlainAxis yleft_;
+  LinearTransform xt_, yt_;
+  boolean isStandalone = false;
+  BorderLayout borderLayout1 = new BorderLayout();
+  JPanel buttonPanel = new JPanel();
+  JButton startButton = new JButton();
+  JButton stopButton = new JButton();
+  JButton resetButton = new JButton();
+
+  /**Construct the applet*/
+  public JDesktopDemo() {
+  }
+  /**Initialize the applet*/
+  public void init() {
+    /*
+     * Create the data source
+     */
+    rtData_ = new PseudoRealTimeData("rtDataSource", "Sea Level");
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+    /*
+     * add listener for data source.  JDesktopDemo is listening
+     * for rangeModified events
+     */
+    rtData_.addPropertyChangeListener(this);
+  }
+  /**Component initialization*/
+  private void jbInit() throws Exception {
+    this.setSize(new Dimension(800, 440));
+    this.getContentPane().setLayout(borderLayout1);
+    startButton.setText("start");
+    startButton.addActionListener(new JDesktopDemo_startButton_actionAdapter(this));
+    stopButton.setText("stop");
+    stopButton.addActionListener(new JDesktopDemo_stopButton_actionAdapter(this));
+    resetButton.setText("reset");
+    resetButton.addActionListener(new JDesktopDemo_resetButton_actionAdapter(this));
+    buttonPanel.setBorder(BorderFactory.createEtchedBorder());
+    this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+    buttonPanel.add(startButton, null);
+    buttonPanel.add(stopButton, null);
+    buttonPanel.add(resetButton, null);
+    //
+    // construct JPane
+    //
+    pane_ = new JPane("Real Time Data Demo", new Dimension(800, 400));
+    pane_.setBatch(true);
+    pane_.setLayout(new StackedLayout());
+    pane_.setBackground(Color.white);
+    /*
+     * xsize, ysize are the width and height in physical units
+     * of the Layer graphics region.
+     *
+     * xstart, xend are the start and end points for the X axis
+     * ystart, yend are the start and end points for the Y axis
+     */
+    double xsize = 6.0;
+    double xstart = 0.6;
+    double xend = 5.5;
+    double ysize = 3.0;
+    double ystart = 0.6;
+    double yend = 2.75;
+    /*
+     * Create the layer and add it to the Pane.
+     */
+    CartesianGraph graph;
+    /*
+     * Get x and y ranges from data source.
+     */
+    SoTRange.GeoDate xrange = (SoTRange.GeoDate)rtData_.getXRange();
+    SoTRange.Double yrange = (SoTRange.Double)rtData_.getYRange();
+
+    xt_ = new LinearTransform(xstart, xend, xrange.start, xrange.end);
+    yt_ = new LinearTransform(ystart, yend, yrange.start, yrange.end);
+
+    layer_ = new Layer("Layer 1", new Dimension2D(xsize, ysize));
+    pane_.add(layer_);
+
+    SGLabel title = new SGLabel("title",
+				"Real Time Demo",
+				new Point2D.Double((xstart+xend)/2.0,
+						   ysize-0.05));
+    title.setAlign(SGLabel.TOP, SGLabel.CENTER);
+    title.setFont(new Font("Serif", Font.PLAIN, 14));
+    title.setHeightP(0.25);
+    title.setColor(Color.blue.darker());
+    layer_.addChild(title);
+    /*
+     * Create a CartesianGraph and set transforms.
+     */
+    graph = new CartesianGraph("Time Graph");
+    layer_.setGraph(graph);
+    graph.setXTransform(xt_);
+    graph.setYTransform(yt_);
+    /*
+     * Create the bottom axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    SoTPoint origin = new SoTPoint(xrange.start, yrange.start);
+    xbot_ = new TimeAxis("Botton Axis", TimeAxis.AUTO);
+    xbot_.setRangeU(xrange);
+    xbot_.setLocationU(origin);
+    Font xbfont = new Font("Helvetica", Font.PLAIN, 14);
+    xbot_.setLabelFont(xbfont);
+    graph.addXAxis(xbot_);
+    /*
+     * Create the left axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    String yLabel = "Latitude";
+
+    yleft_ = new PlainAxis("Left Axis");
+    yleft_.setRangeU(yrange);
+    yleft_.setLocationU(origin);
+    yleft_.setLabelFont(xbfont);
+    SGLabel ytitle = new SGLabel("yaxis title", yLabel,
+                                 new Point2D.Double(0.0, 0.0));
+    Font ytfont = new Font("Helvetica", Font.PLAIN, 14);
+    ytitle.setFont(ytfont);
+    ytitle.setHeightP(0.2);
+    yleft_.setTitle(ytitle);
+    graph.addYAxis(yleft_);
+
+    LineAttribute attr = new LineAttribute();
+    graph.setData(rtData_, attr);
+
+    this.getContentPane().add(pane_, BorderLayout.CENTER);
+    if(!isStandalone) pane_.setBatch(false);
+  }
+  /**Start the applet*/
+  public void start() {
+  }
+  /**Stop the applet*/
+  public void stop() {
+    rtData_.stopData();
+  }
+  /**Destroy the applet*/
+  public void destroy() {
+    rtData_.stopData();
+  }
+  /**Get Applet information*/
+  public String getAppletInfo() {
+    return "Applet Information";
+  }
+  /**Main method*/
+  public static void main(String[] args) {
+    JFrame desk = new JFrame("Desktop Demo");
+    //EXIT_ON_CLOSE == 3
+    desk.setDefaultCloseOperation(3);
+    desk.getContentPane().setLayout(new BorderLayout());
+    desk.setSize(850, 500);
+    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+    desk.setLocation((d.width - desk.getSize().width) / 2, 
+		     (d.height - desk.getSize().height) / 2);
+    JDesktopPane desktop = new JDesktopPane();
+    desk.getContentPane().add(desktop, BorderLayout.CENTER);
+    JDesktopDemo applet = new JDesktopDemo();
+    applet.isStandalone = true;
+    JInternalFrame frame = new JInternalFrame("Real Time Data Demo",
+					      false, false, false, true);
+    frame.getContentPane().add(applet, BorderLayout.CENTER);
+    applet.init();
+    applet.start();
+    frame.setSize(800,440);
+    desktop.add(frame);
+    applet.pane_.setBatch(false);
+    desk.setVisible(true);
+    frame.setVisible(true);
+  }
+
+  //static initializer for setting look & feel
+  static {
+    try {
+      //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+      //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+    }
+    catch(Exception e) {
+    }
+  }
+
+  void startButton_actionPerformed(ActionEvent e) {
+    rtData_.startData();
+  }
+
+  void stopButton_actionPerformed(ActionEvent e) {
+    rtData_.stopData();
+  }
+
+  void resetButton_actionPerformed(ActionEvent e) {
+    rtData_.stopData();
+    rtData_.resetData();
+    resetRange();
+  }
+  private void resetRange() {
+    /*
+     * A change in the range has occured. Get new range
+     * and set transforms, axes, and origin appropriately.
+     */
+    pane_.setBatch(true);
+    SoTRange.GeoDate xrange = (SoTRange.GeoDate)rtData_.getXRange();
+    SoTRange.Double yrange = (SoTRange.Double)rtData_.getYRange();
+    SoTPoint origin = new SoTPoint(xrange.start, yrange.start);
+    xt_.setRangeU(xrange);
+    yt_.setRangeU(yrange);
+    xbot_.setRangeU(xrange);
+    xbot_.setLocationU(origin);
+    yleft_.setRangeU(yrange);
+    yleft_.setLocationU(origin);
+    pane_.setBatch(false);
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    /**
+     * dataModified property is handled by CartesianGraph
+     * only need to look for rangeModified here to make sure
+     * range is properly updated
+     */
+    if("rangeModified".equals(evt.getPropertyName())) {
+      resetRange();
+    }
+  }
+}
+/*
+ * wrappers for button events created by JBuilder
+ */
+class JDesktopDemo_startButton_actionAdapter implements ActionListener {
+  JDesktopDemo adaptee;
+
+  JDesktopDemo_startButton_actionAdapter(JDesktopDemo adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.startButton_actionPerformed(e);
+  }
+}
+
+class JDesktopDemo_stopButton_actionAdapter implements ActionListener {
+  JDesktopDemo adaptee;
+
+  JDesktopDemo_stopButton_actionAdapter(JDesktopDemo adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.stopButton_actionPerformed(e);
+  }
+}
+
+class JDesktopDemo_resetButton_actionAdapter implements ActionListener {
+  JDesktopDemo adaptee;
+
+  JDesktopDemo_resetButton_actionAdapter(JDesktopDemo adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.resetButton_actionPerformed(e);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JGridDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JGridDemo.java
new file mode 100755
index 0000000..297ec5f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JGridDemo.java
@@ -0,0 +1,377 @@
+/*
+ * $Id: JGridDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.swing.JPlotLayout;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.sgt.swing.prop.GridAttributeDialog;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.AbstractPane;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.ContourLevels;
+import gov.noaa.pmel.sgt.CartesianRenderer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.GridCartesianRenderer;
+import gov.noaa.pmel.sgt.IndexedColorMap;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.util.Debug;
+
+import java.awt.*;
+import java.awt.print.*;
+import java.awt.event.*;
+import javax.swing.*;
+/**
+ * Example demonstrating how to use <code>JPlotLayout</code>
+ * to create a raster-contour plot.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+public class JGridDemo extends JApplet {
+  static JPlotLayout rpl_;
+  private GridAttribute gridAttr_;
+  JButton edit_;
+  JButton space_ = null;
+  JButton tree_;
+  JButton print_;
+  JButton layout_;
+  PageFormat pageFormat = PrinterJob.getPrinterJob().defaultPage();
+
+  public void init() {
+    /*
+    * Create the demo in the JApplet environment.
+     */
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setBackground(java.awt.Color.white);
+    setSize(600,550);
+    JPanel main = new JPanel();
+    rpl_ = makeGraph();
+    JPanel button = makeButtonPanel(false);
+    rpl_.setBatch(true);
+    main.add(rpl_, BorderLayout.CENTER);
+    JPane gridKeyPane = rpl_.getKeyPane();
+    gridKeyPane.setSize(new Dimension(600,100));
+    main.add(gridKeyPane, BorderLayout.SOUTH);
+    getContentPane().add(main, "Center");
+    getContentPane().add(button, "South");
+    rpl_.setBatch(false);
+
+  }
+
+  JPanel makeButtonPanel(boolean mark) {
+    MyAction myAction = new MyAction();
+    JPanel button = new JPanel();
+    button.setLayout(new FlowLayout());
+    print_ = new JButton("Print...");
+    print_.addActionListener(myAction);
+    button.add(print_);
+    layout_ = new JButton("Page Layout...");
+    layout_.addActionListener(myAction);
+    button.add(layout_);
+    tree_ = new JButton("Tree View");
+    tree_.addActionListener(myAction);
+    button.add(tree_);
+    edit_ = new JButton("Edit GridAttribute");
+    edit_.addActionListener(myAction);
+    button.add(edit_);
+    /*
+    * Optionally leave the "mark" button out of the button panel
+     */
+    if(mark) {
+      space_ = new JButton("Add Mark");
+      space_.addActionListener(myAction);
+      button.add(space_);
+    }
+    return button;
+  }
+  public static void main(String[] args) {
+    /*
+    * Create the demo as an application
+     */
+    JGridDemo gd = new JGridDemo();
+    /*
+    * Create a new JFrame to contain the demo.
+     */
+    JFrame frame = new JFrame("Grid Demo");
+    JPanel main = new JPanel();
+    main.setLayout(new BorderLayout());
+    frame.setSize(600,500);
+    frame.getContentPane().setLayout(new BorderLayout());
+    /*
+    * Listen for windowClosing events and dispose of JFrame
+     */
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+      public void windowClosing(java.awt.event.WindowEvent event) {
+        JFrame fr = (JFrame)event.getSource();
+        fr.setVisible(false);
+        fr.dispose();
+        System.exit(0);
+      }
+      public void windowOpened(java.awt.event.WindowEvent event) {
+        rpl_.getKeyPane().draw();
+      }
+    });
+    /*
+    * Create button panel with "mark" button
+     */
+    JPanel button = gd.makeButtonPanel(true);
+    /*
+    * Create JPlotLayout and turn batching on.  With batching on the
+    * plot will not be updated as components are modified or added to
+    * the plot tree.
+     */
+    rpl_ = gd.makeGraph();
+    rpl_.setBatch(true);
+    /*
+    * Layout the plot, key, and buttons.
+     */
+    main.add(rpl_, BorderLayout.CENTER);
+    JPane gridKeyPane = rpl_.getKeyPane();
+    gridKeyPane.setBatch(true); // new line
+    gridKeyPane.setSize(new Dimension(600,100));
+    rpl_.setKeyLayerSizeP(new Dimension2D(6.0, 1.0));
+    rpl_.setKeyBoundsP(new Rectangle2D.Double(0.0, 1.0, 6.0, 1.0));
+    main.add(gridKeyPane, BorderLayout.SOUTH);
+    frame.getContentPane().add(main, BorderLayout.CENTER);
+    frame.getContentPane().add(button, BorderLayout.SOUTH);
+
+    JPanel foo = null;
+    JPanel bar = null;
+    JButton foobutton = null;
+    JButton barbutton = null;
+
+/*    JPanel foo = new JPanel();
+    foo.setLayout(new BorderLayout());
+    JButton foobutton = new JButton("my foo button");
+    foo.add(foobutton, BorderLayout.CENTER);
+    foo.setMaximumSize(new Dimension(700, 100));
+    foo.setMinimumSize(new Dimension(600, 100));
+    foo.setPreferredSize(new Dimension(600, 100));
+    frame.getContentPane().add(foo, BorderLayout.NORTH);
+    JPanel bar = new JPanel();
+    bar.setLayout(new BorderLayout());
+    JButton barbutton = new JButton("my bar button");
+    bar.add(barbutton, BorderLayout.CENTER);
+    bar.setMaximumSize(new Dimension(150, 2000));
+    bar.setMinimumSize(new Dimension(150, 100));
+    bar.setPreferredSize(new Dimension(150, 200));
+    frame.getContentPane().add(bar, BorderLayout.WEST); */
+
+    frame.pack();
+    frame.setVisible(true);
+    /*
+    * Turn batching off. JPlotLayout will redraw if it has been
+    * modified since batching was turned on.
+     */
+    gridKeyPane.setBatch(false); // new line
+    rpl_.setBatch(false);
+
+    if(Debug.DEBUG) {
+      System.out.println("Locations:");
+      System.out.println("           foo = " + foo.getLocation());
+      System.out.println("     foobutton = " + foobutton.getLocation());
+      System.out.println("           bar = " + bar.getLocation());
+      System.out.println("     barbutton = " + barbutton.getLocation());
+      System.out.println("          main = " + main.getLocation());
+      System.out.println("          rpl_ = " + rpl_.getLocation());
+      System.out.println("   gridKeyPane = " + gridKeyPane.getLocation());
+      System.out.println("        button = " + button.getLocation());
+      System.out.println("        print_ = " + gd.print_.getLocation());
+      System.out.println("        space_ = " + gd.space_.getLocation());
+      System.out.println("         tree_ = " + gd.tree_.getLocation());
+      System.out.println("         edit_ = " + gd.edit_.getLocation());
+    }
+  }
+
+  void edit_actionPerformed(java.awt.event.ActionEvent e) {
+    /*
+    * Create a GridAttributeDialog and set the renderer.
+     */
+    GridAttributeDialog gad = new GridAttributeDialog();
+    gad.setJPane(rpl_);
+    CartesianRenderer rend = ((CartesianGraph)rpl_.getFirstLayer().getGraph()).getRenderer();
+    gad.setGridCartesianRenderer((GridCartesianRenderer)rend);
+    //        gad.setGridAttribute(gridAttr_);
+    gad.setVisible(true);
+  }
+
+  void tree_actionPerformed(java.awt.event.ActionEvent e) {
+      /*
+    * Create a JClassTree for the JPlotLayout objects
+       */
+    JClassTree ct = new JClassTree();
+    ct.setModal(false);
+    ct.setJPane(rpl_);
+    ct.show();
+  }
+
+  void print_actionPerformed(ActionEvent e) {
+    Color saveColor;
+
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+    printJob.setPrintable(rpl_, pageFormat);
+    printJob.setJobName("Grid Demo");
+    if(printJob.printDialog()) {
+      try {
+        saveColor = rpl_.getBackground();
+        if(!saveColor.equals(Color.white)) {
+          rpl_.setBackground(Color.white);
+        }
+        rpl_.setPageAlign(AbstractPane.TOP,
+                          AbstractPane.CENTER);
+        RepaintManager currentManager = RepaintManager.currentManager(rpl_);
+        currentManager.setDoubleBufferingEnabled(false);
+        printJob.print();
+        currentManager.setDoubleBufferingEnabled(true);
+        rpl_.setBackground(saveColor);
+      } catch (PrinterException pe) {
+        System.out.println("Error printing: " + pe);
+      }
+    }
+
+  }
+
+  void layout_actionPerformed(ActionEvent e) {
+    PrinterJob pj = PrinterJob.getPrinterJob();
+    pageFormat = pj.pageDialog(pageFormat);
+  }
+
+  JPlotLayout makeGraph() {
+    /*
+    * This example uses a pre-created "Layout" for raster time
+    * series to simplify the construction of a plot. The
+    * JPlotLayout can plot a single grid with
+    * a ColorKey, time series with a LineKey, point collection with a
+    * PointCollectionKey, and general X-Y plots with a
+    * LineKey. JPlotLayout supports zooming, object selection, and
+    * object editing.
+     */
+    SGTData newData;
+    TestData td;
+    JPlotLayout rpl;
+    ContourLevels clevels;
+    /*
+    * Create a test grid with sinasoidal-ramp data.
+     */
+    Range2D xr = new Range2D(190.0f, 250.0f, 1.0f);
+    Range2D yr = new Range2D(0.0f, 45.0f, 1.0f);
+    td = new TestData(TestData.XY_GRID, xr, yr,
+                      TestData.SINE_RAMP, 12.0f, 30.f, 5.0f);
+    newData = td.getSGTData();
+    /*
+    * Create the layout without a Logo image and with the
+    * ColorKey on a separate Pane object.
+     */
+    rpl = new JPlotLayout(true, false, false, "JGridDemo Pane", null, true);
+    rpl.setEditClasses(false);
+    /*
+    * Create a GridAttribute for CONTOUR style.
+     */
+    Range2D datar = new Range2D(-20.0f, 45.0f, 5.0f);
+    clevels = ContourLevels.getDefault(datar);
+    gridAttr_ = new GridAttribute(clevels);
+    /*
+    * Create a ColorMap and change the style to RASTER_CONTOUR.
+     */
+    ColorMap cmap = createColorMap(datar);
+    gridAttr_.setColorMap(cmap);
+    gridAttr_.setStyle(GridAttribute.RASTER_CONTOUR);
+    /*
+    * Add the grid to the layout and give a label for
+    * the ColorKey.
+     */
+    rpl.addData(newData, gridAttr_, "First Data");
+    /*
+    * Change the layout's three title lines.
+     */
+    rpl.setTitles("Raster Plot Demo",
+                  "using a JPlotLayout",
+                  "");
+    /*
+    * Resize the graph  and place in the "Center" of the frame.
+     */
+    rpl.setSize(new Dimension(600, 400));
+    /*
+    * Resize the key Pane, both the device size and the physical
+    * size. Set the size of the key in physical units and place
+    * the key pane at the "South" of the frame.
+     */
+//    rpl.setKeyLayerSizeP(new Dimension2D(6.0, 1.02));
+//    rpl.setKeyBoundsP(new Rectangle2D.Double(0.01, 1.01, 5.98, 1.0));
+
+    return rpl;
+  }
+
+  ColorMap createColorMap(Range2D datar) {
+    int[] red =
+    {   0,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0,
+        0,  7, 23, 39, 55, 71, 87,103,
+      119,135,151,167,183,199,215,231,
+      247,255,255,255,255,255,255,255,
+      255,255,255,255,255,255,255,255,
+      255,246,228,211,193,175,158,140};
+    int[] green =
+    {   0,  0,  0,  0,  0,  0,  0,  0,
+        0, 11, 27, 43, 59, 75, 91,107,
+      123,139,155,171,187,203,219,235,
+      251,255,255,255,255,255,255,255,
+      255,255,255,255,255,255,255,255,
+      255,247,231,215,199,183,167,151,
+      135,119,103, 87, 71, 55, 39, 23,
+        7,  0,  0,  0,  0,  0,  0,  0};
+    int[] blue =
+    {   0,143,159,175,191,207,223,239,
+      255,255,255,255,255,255,255,255,
+      255,255,255,255,255,255,255,255,
+      255,247,231,215,199,183,167,151,
+      135,119,103, 87, 71, 55, 39, 23,
+        7,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0};
+
+    IndexedColorMap cmap = new IndexedColorMap(red, green, blue);
+    cmap.setTransform(new LinearTransform(0.0, (double)red.length,
+        datar.start, datar.end));
+    return cmap;
+  }
+
+  class MyAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object obj = event.getSource();
+      if(obj == edit_) {
+        edit_actionPerformed(event);
+      } else if(obj == space_) {
+        System.out.println("  <<Mark>>");
+      } else if(obj == tree_) {
+        tree_actionPerformed(event);
+      } else if(obj == print_) {
+        print_actionPerformed(event);
+      } else if(obj == layout_) {
+        layout_actionPerformed(event);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JLayoutDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JLayoutDemo.java
new file mode 100755
index 0000000..c46317a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JLayoutDemo.java
@@ -0,0 +1,507 @@
+/*
+ * $Id: JLayoutDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.LineKey;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.Axis;
+
+import gov.noaa.pmel.sgt.dm.SimpleLine;
+
+import gov.noaa.pmel.sgt.swing.JClassTree;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.TimePoint;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTPoint;
+
+import java.util.Enumeration;
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+
+/**
+ * Example demonstrating how to use <code>setLayout()</code> with
+ * <code>JPane</code> to change how <code>Layer</code>s are placed on
+ * a <code>JPane</code>.  <code>JLayoutDemo</code> constructs the
+ * plots from basic <code>sgt</code> objects.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+public class JLayoutDemo extends JApplet {
+  JPane mainPane_;
+  JClassTree tree_ = null;
+  boolean isApplet_ = true;
+  JFrame frame = null;
+
+  public void init() {
+    /*
+     * Create a JLayoutDemo within a JApplet
+     */
+    setLayout(new BorderLayout(0,0));
+    setBackground(Color.white);
+    setSize(426,712);
+
+    makeControlPanel();
+    add(controlPanel, BorderLayout.SOUTH);
+
+    makeGraph();
+    add(mainPane_, BorderLayout.CENTER);
+  }
+
+  public static void main(String[] args) {
+    /*
+     * Create a JLayoutDemo as an application.
+     */
+    JLayoutDemo ld = new JLayoutDemo();
+    ld.isApplet_ = false;
+    ld.frame = new JFrame("Layout Demo");
+    ld.frame.setSize(426,712);
+    ld.frame.getContentPane().setLayout(new BorderLayout());
+    ld.frame.addWindowListener(new java.awt.event.WindowAdapter() {
+  public void windowClosing(java.awt.event.WindowEvent event) {
+    JFrame fr = (JFrame)event.getSource();
+    fr.setVisible(false);
+    fr.dispose();
+    System.exit(0);
+  }
+      });
+
+    ld. makeControlPanel();
+    ld.frame.getContentPane().add(ld.controlPanel, BorderLayout.SOUTH);
+
+    ld.makeGraph();
+    ld.mainPane_.setBackground(Color.white);
+    ld.mainPane_.setBatch(true);
+    ld.frame.getContentPane().add(ld.mainPane_, BorderLayout.CENTER);
+
+    ld.frame.setVisible(true);
+    ld.mainPane_.setBatch(false);
+  }
+
+  void makeControlPanel() {
+    controlPanel.setLayout(new GridBagLayout());
+//    controlPanel.setBackground(new java.awt.Color(200,200,200));
+    controlPanel.setBounds(0,679,426,33);
+    controlPanel.setBorder(new EtchedBorder());
+    gridtype.add(stacked);
+    stacked.setSelected(true);
+    stacked.setText("Overlayed");
+
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.gridx = 0;
+    gbc.gridy = 0;
+    gbc.gridwidth = 1;
+    gbc.gridheight = 1;
+    gbc.weightx = 0.0;
+    gbc.weighty = 1.0;
+    gbc.anchor = GridBagConstraints.EAST;
+    gbc.fill = GridBagConstraints.BOTH;
+    gbc.insets = new Insets(5,15,5,5);
+    gbc.ipadx = 0;
+    gbc.ipady = 0;
+    controlPanel.add(stacked, gbc);
+    stacked.setBounds(15,5,84,23);
+    gridtype.add(grid);
+    grid.setText("Grid");
+
+    gbc.gridx = 1;
+    gbc.gridy = 0;
+    gbc.gridwidth = 1;
+    gbc.gridheight = 1;
+    gbc.weightx = 0.5;
+    gbc.weighty = 1.0;
+    gbc.anchor = GridBagConstraints.WEST;
+    gbc.fill = GridBagConstraints.VERTICAL;
+    gbc.insets = new Insets(5,5,5,0);
+    gbc.ipadx = 0;
+    gbc.ipady = 0;
+    controlPanel.add(grid, gbc);
+    grid.setBounds(109,5,53,23);
+    showTree.setText("Show Class Tree");
+
+    gbc.gridx = 2;
+    gbc.gridy = 0;
+    gbc.gridwidth = 1;
+    gbc.gridheight = 1;
+    gbc.weightx = 1.0;
+    gbc.weighty = 1.0;
+    gbc.anchor = GridBagConstraints.EAST;
+    gbc.fill = GridBagConstraints.VERTICAL;
+    gbc.insets = new Insets(5,5,5,15);
+    gbc.ipadx = 0;
+    gbc.ipady = 0;
+    controlPanel.add(showTree, gbc);
+    showTree.setBackground(Color.yellow.brighter());
+    showTree.setBounds(302,5,109,23);
+
+    SymItem lSymItem = new SymItem();
+    stacked.addItemListener(lSymItem);
+    grid.addItemListener(lSymItem);
+    SymAction lSymAction = new SymAction();
+    showTree.addActionListener(lSymAction);
+  }
+
+  void makeGraph() {
+    /*
+     * This example explicitly creates the JPane, Layers, Axes, and SGLabels.
+     */
+    /*
+     * Create JPane, place in the center of the frame
+     * and set the layout to use the StackedLayout.  StackedLayout is
+     * a custom layout manager designed to place Components directly
+     * over one another.
+     */
+    mainPane_ = new JPane("Layout Demo", new Dimension(426, 400));
+    mainPane_.setLayout(new StackedLayout());
+    /*
+     * Create the two random time series using the TestData class and
+     * the SimpleLine classes from sgt.dm
+     */
+    SimpleLine line;
+    SimpleLine line2;
+    GeoDate start = null;
+    GeoDate stop = null;
+    TimeRange tr;
+    TestData td;
+    try {
+      start = new GeoDate("1992-11-01", "yyyy-MM-dd");
+      stop  = new GeoDate("1993-02-20", "yyyy-MM-dd");
+    } catch (IllegalTimeValue e) {}
+    tr = new TimeRange(start, stop);
+    td = new TestData(TestData.TIME_SERIES, tr, 1.0f,
+                      TestData.RANDOM, 1.2f, 0.0f, 20.0f);
+    line = (SimpleLine)td.getSGTData();
+    //
+    try {
+      start = new GeoDate("1992-11-01", "yyyy-MM-dd");
+      stop  = new GeoDate("1993-02-20", "yyyy-MM-dd");
+    } catch (IllegalTimeValue e) {}
+    tr = new TimeRange(start, stop);
+    td = new TestData(TestData.TIME_SERIES, tr, 1.0f,
+                      TestData.RANDOM, 1.2f, 0.5f, 30.0f);
+    line2 = (SimpleLine)td.getSGTData();
+    /*
+     * Get the axis ranges from SGTLine
+     */
+    SoTRange ynRange, yRange;
+    SoTRange tnRange;
+    String yLabel;
+    yRange = line.getYRange();
+    yRange.add(line2.getYRange());
+    tnRange = line.getXRange();
+    /*
+     * compute the range for the y and time axes
+     * and get the y axis label from line's metadata
+     */
+    ynRange = Graph.computeRange(yRange, 6);
+    yLabel = line.getYMetaData().getName();
+    /*
+     * LayoutDemo will have two layers.
+     * One layer for each line to be drawn.
+     * The first layer will contain the axes and labels
+     * and the first set of data. The second layer will
+     * contain the second set of data.
+     */
+    /*
+     * xsize, ysize are the width and height in physical units
+     * of the Layer graphics region.
+     *
+     * xstart, xend are the start and end points for the TimeAxis
+     * ystart, yend are the start and end points for the Y axis
+     */
+    double xsize  = 4.0;
+    double xstart = 0.6;
+    double xend   = 3.25;
+    double ysize  = 3.0;
+    double ystart = 0.6;
+    double yend   = 2.50;
+
+    Layer layer, layer2;
+    SGLabel label, title, ytitle;
+    CartesianGraph graph, graph2;
+    LinearTransform xt, yt;
+    PlainAxis yleft;
+    TimeAxis xbot;
+    LineKey lkey;
+    GeoDate stime;
+    /*
+     * create the first layer
+     */
+    layer = new Layer("First Layer", new Dimension2D(xsize, ysize));
+    /*
+     * create a time stamp label for the plot
+     * position the label at the lower left corner
+     * and add to the first layer
+     * (NOTE: the time will be displayed for the GMT time zone)
+     */
+    stime = new GeoDate();
+    label = new SGLabel("Date Stamp", stime.toString(),
+                        new Point2D.Double(0.05, 0.05));
+    label.setAlign(SGLabel.BOTTOM, SGLabel.LEFT);
+    label.setColor(Color.magenta);
+    label.setHeightP(0.15);
+    label.setFont(new Font("Dialog", Font.PLAIN, 10));
+    layer.addChild(label);
+    /*
+     * create a title for the plot
+     * position the label centered on the graph
+     * and add to the first layer
+     */
+    title = new SGLabel("Title", "Layout Demo",
+                        new Point2D.Double(xsize/2.0, ysize));
+    title.setAlign(SGLabel.TOP, SGLabel.CENTER);
+    title.setHeightP(0.20);
+    title.setFont(new Font("Helvetica", Font.BOLD, 14));
+    layer.addChild(title);
+    /*
+     * create a LineKey
+     * the LineKey will be a legend for the two lines created
+     * position the key in the upper right corner
+     * and add to the first layer
+     */
+    lkey = new LineKey();
+    lkey.setId("Legend");
+    lkey.setLocationP(new Point2D.Double(xsize - 0.01, ysize));
+    lkey.setVAlign(LineKey.TOP);
+    lkey.setHAlign(LineKey.RIGHT);
+    layer.addChild(lkey);
+    /*
+     * add the first layer to the Pane
+     */
+    mainPane_.add(layer);
+    /*
+     * create first CartesianGraph and transforms
+     */
+    graph = new CartesianGraph("First Graph");
+    xt = new LinearTransform(new Range2D(xstart, xend), tnRange);
+    graph.setXTransform(xt);
+    yt = new LinearTransform(new Range2D(ystart, yend), ynRange);
+    graph.setYTransform(yt);
+    /*
+     * Create the time axis, set its range in user units
+     * and its origin. Add the axis to the first graph.
+     */
+    SoTPoint point = new SoTPoint(ynRange.getStart(), tnRange.getStart());
+    xbot = new TimeAxis("Bottom Axis", TimeAxis.MONTH_YEAR);
+    xbot.setRangeU(tnRange);
+    xbot.setLocationU(point);
+    Font xbfont = new Font("Helvetica", Font.ITALIC, 14);
+    xbot.setLabelFont(xbfont);
+    xbot.setMinorLabelInterval(1);
+    graph.addXAxis(xbot);
+    /*
+     * Create the vertical axis, set its range in user units
+     * and its origin.  Create the axis title and add the
+     * axis to the first graph.
+     */
+    yleft = new PlainAxis("Left Axis");
+    yleft.setRangeU(ynRange);
+    yleft.setLocationU(point);
+    yleft.setLabelFont(xbfont);
+    ytitle = new SGLabel("Y-Axis Title", yLabel,
+                         new Point2D.Double(0.0, 0.0));
+    Font ytfont = new Font("Helvetica", Font.PLAIN, 14);
+    ytitle.setFont(ytfont);
+    ytitle.setHeightP(0.2);
+    yleft.setTitle(ytitle);
+    graph.addYAxis(yleft);
+    /*
+     * Add the first graph to the first layer.
+     */
+    layer.setGraph(graph);
+    /*
+     * Create a LineAttribute for the display of the first
+     * line. Associate the attribute and the line with the
+     * first graph.  Add the line to the LineKey.
+     */
+    LineAttribute attr;
+
+    attr = new LineAttribute(LineAttribute.MARK, 20, Color.red);
+    attr.setMarkHeightP(0.1);
+    graph.setData(line, attr);
+    lkey.addLineGraph((LineCartesianRenderer)graph.getRenderer(),
+                      new SGLabel("1st line", "Red Data",
+                                  new Point2D.Double(0.0, 0.0)));
+    /*
+     * Create the second layer and add it the the Pane.
+     * Create the second graph and associate it with the
+     * second layer.
+     */
+    layer2 = new Layer("Second Layer", new Dimension2D(xsize, ysize));
+    mainPane_.add(layer2);
+    graph2 = new CartesianGraph("Second Graph", xt, yt);
+    layer2.setGraph(graph2);
+    /*
+     * Create a LineAttribute for the display of the second
+     * line. Associate the attribute and the line with the
+     * second graph.  Add the line to the LineKey.
+     */
+    LineAttribute attr2;
+    attr2 = new LineAttribute(LineAttribute.MARK, 2, Color.blue);
+    attr2.setMarkHeightP(0.1);
+    graph2.setData(line2, attr2);
+    lkey.addLineGraph((LineCartesianRenderer)graph2.getRenderer(),
+                      new SGLabel("2nd line", "Blue Data",
+                                  new Point2D.Double(0.0, 0.0)));
+
+  }
+
+  JPanel controlPanel = new JPanel();
+  JCheckBox stacked = new JCheckBox();
+  ButtonGroup gridtype = new ButtonGroup();
+  JCheckBox grid = new JCheckBox();
+  JButton showTree = new JButton();
+
+  class SymItem implements java.awt.event.ItemListener {
+    public void itemStateChanged(java.awt.event.ItemEvent event) {
+      Object object = event.getSource();
+      if (object == stacked)
+        stacked_itemStateChanged(event);
+      else if (object == grid)
+        grid_itemStateChanged(event);
+    }
+  }
+
+  /**
+   * Change the Pane layout to StackedLayout.
+   *
+   * @param event
+   */
+
+  void stacked_itemStateChanged(java.awt.event.ItemEvent event) {
+    /*
+     * Get the component list for mainPane_ and change
+     * the layout to StackedLayout.
+     */
+    Component[] comps = mainPane_.getComponents();
+    mainPane_.setBatch(true);
+    mainPane_.setLayout(new StackedLayout());
+    /*
+     * Remove any axes that have been associated with
+     * the second graph.  With the layers overlayed it
+     * is not necessary to have duplicate axes.
+     */
+    Graph gr2 = ((Layer)comps[1]).getGraph();
+    ((CartesianGraph)gr2).removeAllXAxes();
+    ((CartesianGraph)gr2).removeAllYAxes();
+    /*
+     * Tell the Applet that the mainPane_ needs to
+     * be layed out and re-draw the mainPane_.
+     */
+    if(isApplet_) {
+      validate();
+    } else {
+      frame.validate();
+    }
+    mainPane_.setBatch(false);
+    if(tree_ != null) {
+      if(tree_.isVisible()) {
+        tree_.setJPane(mainPane_);
+        tree_.expandTree();
+      }
+    }
+  }
+
+  /**
+   * Change the Pane layout to GridLayout.
+   *
+   * @param event
+   */
+
+  void grid_itemStateChanged(java.awt.event.ItemEvent event) {
+    /*
+     * Get the component list for mainPane_ and change
+     * the layout to GridLayout.
+     */
+    Component[] comps = mainPane_.getComponents();
+    mainPane_.setBatch(true);
+    mainPane_.setLayout(new GridLayout(2,0));
+    /*
+     * Get the first and second graphs from the first
+     * and second layers, respectively.
+     */
+    Graph gr = ((Layer)comps[0]).getGraph();
+    Graph gr2 = ((Layer)comps[1]).getGraph();
+    /*
+     * Create copies of all X-Axes associated with the first
+     * graph for the second graph. If the axes are not copied then
+     * the second graph will have the second line plotted, but without
+     * any axes.
+     */
+    for(Enumeration xa = ((CartesianGraph)gr).xAxisElements(); xa.hasMoreElements();) {
+      ((CartesianGraph)gr2).addXAxis(((Axis)xa.nextElement()).copy());
+    }
+    /*
+     * Create copies of all Y-Axes associated with the first
+     * graph for the second graph.
+     */
+    for(Enumeration ya = ((CartesianGraph)gr).yAxisElements(); ya.hasMoreElements();) {
+      ((CartesianGraph)gr2).addYAxis(((Axis)ya.nextElement()).copy());
+    }
+    /*
+     * Tell the Applet that the mainPane_ needs to
+     * be layed out and re-draw the mainPane_.
+     */
+    if(isApplet_) {
+      validate();
+    } else {
+      frame.validate();
+    }
+    //    mainPane_.draw();
+    mainPane_.setBatch(false);
+    if(tree_ != null) {
+      if(tree_.isVisible()) {
+        tree_.setJPane(mainPane_);
+        tree_.expandTree();
+      }
+    }
+  }
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == showTree)
+        showTree_ActionPerformed(event);
+    }
+  }
+
+  void showTree_ActionPerformed(java.awt.event.ActionEvent event) {
+    /*
+     * Create the ClassTree dialog to display the classes used
+     * in the mainPane_ and allow editing.
+     */
+    if(tree_ == null) {
+      tree_ = new JClassTree("Classes for LayoutDemo");
+    }
+    tree_.setJPane(mainPane_);
+    tree_.show();
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JLogLogDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JLogLogDemo.java
new file mode 100755
index 0000000..f0f6841
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JLogLogDemo.java
@@ -0,0 +1,224 @@
+/*
+ * $Id: JLogLogDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Layer;
+//import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.LogAxis;
+import gov.noaa.pmel.sgt.LineKey;
+//import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.LogTransform;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.SGLabel;
+//import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+//import gov.noaa.pmel.sgt.Logo;
+
+//import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.Dimension2D;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * Example demonstrating the creation of a simple
+ * graph using LogAxis.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 3.0
+ */
+
+public class JLogLogDemo extends JApplet {
+    JButton tree_;
+    JButton space_;
+    JPane mainPane_;
+
+  public void init() {
+    setLayout(new BorderLayout(0,0));
+    setSize(553,438);
+
+    add(makeGraph(), BorderLayout.CENTER);
+  }
+
+  public static void main(String[] args) {
+    JLogLogDemo pd = new JLogLogDemo();
+    JFrame frame = new JFrame("Log-Log Demo");
+    JPanel button = new JPanel();
+    JPane graph;
+    button.setLayout(new FlowLayout());
+    pd.tree_ = new JButton("Tree View");
+    MyAction myAction = pd. new MyAction();
+    pd.tree_.addActionListener(myAction);
+    button.add(pd.tree_);
+    pd.space_ = new JButton("Add Mark");
+    pd.space_.addActionListener(myAction);
+    button.add(pd.space_);
+    frame.getContentPane().setLayout(new BorderLayout());
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+      public void windowClosing(java.awt.event.WindowEvent event) {
+	JFrame fr = (JFrame)event.getSource();
+	fr.setVisible(false);
+	fr.dispose();
+	System.exit(0);
+      }
+    });
+    frame.setSize(553,438);
+    graph = pd.makeGraph();
+    graph.setBatch(true);
+    frame.getContentPane().add(graph, BorderLayout.CENTER);
+    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    frame.pack();
+    frame.setVisible(true);
+    graph.setBatch(false);
+  }
+
+  JPane makeGraph() {
+    /*
+     * This example creates a very simple plot from
+     * scratch (not using one of the sgt.awt classes)
+     * to display log-log line.
+     */
+    /*
+     * Create a Pane, place in the center of the Applet
+     * and set the layout to be StackedLayout.
+     */
+    mainPane_ = new JPane("Point Plot Demo", new Dimension(553,438));
+    mainPane_.setLayout(new StackedLayout());
+    mainPane_.setBackground(Color.white);
+    /*
+     * Create a line using the TestData class.
+     */
+    Range2D xrange;
+    SoTRange yrange;
+    TestData td;
+    SGTData data;
+    xrange = new Range2D(50.0, 150000., 1.25);
+    td = new TestData(TestData.LOG_LOG, xrange, TestData.RANDOM, 10000.0f, 1.0f, 10.0f);
+    data = td.getSGTData();
+    yrange = data.getYRange();
+    /*
+     * xsize, ysize are the width and height in physical units
+     * of the Layer graphics region.
+     *
+     * xstart, xend are the start and end points for the X axis
+     * ystart, yend are the start and end points for the Y axis
+     */
+    double xsize = 4.0;
+    double xstart = 0.6;
+    double xend = 3.5;
+    double ysize = 3.0;
+    double ystart = 0.6;
+    double yend = 2.75;
+    /*
+     * Create the layer and add it to the Pane.
+     */
+    Layer layer;
+
+    layer = new Layer("Layer 1", new Dimension2D(xsize, ysize));
+    mainPane_.add(layer);
+    /*
+     * Create a CartesianGraph and transforms.
+     */
+    CartesianGraph graph;
+    LogTransform xt, yt;
+
+    graph = new CartesianGraph("Log-Log Graph");
+    layer.setGraph(graph);
+    xt = new LogTransform(xstart, xend, xrange.start, xrange.end);
+    yt = new LogTransform(new Range2D(ystart, yend), yrange);
+    graph.setXTransform(xt);
+    graph.setYTransform(yt);
+    /*
+     * Create the bottom axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    LogAxis xbot;
+    String xLabel = "X Label";
+
+    xbot = new LogAxis("Botton Axis");
+    xbot.setRangeU(xrange);
+    xbot.setLocationU(new SoTPoint(new SoTValue.Double(xrange.start), yrange.getStart()));
+    Font xbfont = new Font("Helvetica", Font.ITALIC, 14);
+    xbot.setLabelFont(xbfont);
+    SGLabel xtitle = new SGLabel("xaxis title", xLabel,
+                                 new Point2D.Double(0.0, 0.0));
+    Font xtfont = new Font("Helvetica", Font.PLAIN, 14);
+    xtitle.setFont(xtfont);
+    xtitle.setHeightP(0.2);
+    xbot.setTitle(xtitle);
+    graph.addXAxis(xbot);
+    /*
+     * Create the left axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    LogAxis yleft;
+    String yLabel = "Y Label";
+
+    yleft = new LogAxis("Left Axis");
+    yleft.setRangeU(yrange);
+    yleft.setLocationU(new SoTPoint(new SoTValue.Double(xrange.start), yrange.getStart()));
+    yleft.setLabelFont(xbfont);
+    SGLabel ytitle = new SGLabel("yaxis title", yLabel,
+                                 new Point2D.Double(0.0, 0.0));
+    Font ytfont = new Font("Helvetica", Font.PLAIN, 14);
+    ytitle.setFont(ytfont);
+    ytitle.setHeightP(0.2);
+    yleft.setTitle(ytitle);
+    graph.addYAxis(yleft);
+    /*
+     * Create a LineAttribute for the display of the
+     * line.
+     */
+    LineAttribute lattr;
+    lattr = new LineAttribute(LineAttribute.SOLID, Color.red);
+    /*
+     * Associate the attribute and the line
+     * with the graph.
+     */
+    graph.setData(data, lattr);
+
+    return mainPane_;
+  }
+
+    void tree_actionPerformed(java.awt.event.ActionEvent e) {
+        JClassTree ct = new JClassTree();
+        ct.setModal(false);
+        ct.setJPane(mainPane_);
+        ct.show();
+    }
+
+  class MyAction implements java.awt.event.ActionListener {
+        public void actionPerformed(java.awt.event.ActionEvent event) {
+           Object obj = event.getSource();
+	   if(obj == space_) {
+	     System.out.println("  <<Mark>>");
+	   }
+	   if(obj == tree_)
+	       tree_actionPerformed(event);
+        }
+    }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JPointDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JPointDemo.java
new file mode 100755
index 0000000..fd1ab09
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JPointDemo.java
@@ -0,0 +1,244 @@
+/*
+ * $Id: JPointDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.LineKey;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.sgt.Logo;
+
+import gov.noaa.pmel.sgt.dm.Collection;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * Example demonstrating the creation of a simple 
+ * graph of many points.
+ * 
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+
+public class JPointDemo extends JApplet {
+    JButton tree_;
+    JButton space_;
+    JPane mainPane_;
+  
+  public void init() {
+    setLayout(new BorderLayout(0,0));
+    setSize(553,438);
+
+    add(makeGraph(), BorderLayout.CENTER);
+  }
+
+  public static void main(String[] args) {
+    JPointDemo pd = new JPointDemo();
+    JFrame frame = new JFrame("Point Demo");
+    JPanel button = new JPanel();
+    JPane graph;
+    button.setLayout(new FlowLayout());
+    pd.tree_ = new JButton("Tree View");
+    MyAction myAction = pd. new MyAction();
+    pd.tree_.addActionListener(myAction);
+    button.add(pd.tree_);
+    pd.space_ = new JButton("Add Mark");
+    pd.space_.addActionListener(myAction);
+    button.add(pd.space_);
+    frame.getContentPane().setLayout(new BorderLayout());
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+      public void windowClosing(java.awt.event.WindowEvent event) {
+	JFrame fr = (JFrame)event.getSource();
+	fr.setVisible(false);
+	fr.dispose();
+	System.exit(0);
+      }
+    });
+    frame.setSize(553,438);
+    graph = pd.makeGraph();
+    graph.setBatch(true);
+    frame.getContentPane().add(graph, BorderLayout.CENTER);
+    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    frame.pack();
+    frame.setVisible(true);
+    graph.setBatch(false);
+  }
+
+  JPane makeGraph() {
+    /*
+     * This example creates a very simple plot from
+     * scratch (not using one of the sgt.awt classes)
+     * to display a Collection of points.
+     */
+    /*
+     * Create a Pane, place in the center of the Applet
+     * and set the layout to be StackedLayout.
+     */
+    mainPane_ = new JPane("Point Plot Demo", new Dimension(553,438));
+    mainPane_.setLayout(new StackedLayout());
+    mainPane_.setBackground(Color.white);
+    /*
+     * Create a Collection of points using the TestData class.
+     */
+    Range2D xrange, yrange;
+    TestData td;
+    Collection col;
+    xrange = new Range2D(50.0, 150., 10.0);
+    yrange = new Range2D(-20.0, 20.0, 5.0);
+    td = new TestData(xrange, yrange, 50);
+    col = td.getCollection();
+    /*
+     * xsize, ysize are the width and height in physical units
+     * of the Layer graphics region.
+     *
+     * xstart, xend are the start and end points for the X axis
+     * ystart, yend are the start and end points for the Y axis
+     */
+    double xsize = 4.0;
+    double xstart = 0.6;
+    double xend = 3.5;
+    double ysize = 3.0;
+    double ystart = 0.6;
+    double yend = 2.75;
+    /*
+     * Create the layer and add it to the Pane.
+     */
+    Layer layer;
+
+    layer = new Layer("Layer 1", new Dimension2D(xsize, ysize));
+    mainPane_.add(layer);
+    /*
+    * create and add image as a Logo to the layer
+    */
+    Image img = this.getToolkit().getImage(getClass().getResource("ncBrowse48.gif"));
+    //
+    // wait for image to be loaded
+    //
+    if(img != null) {
+      MediaTracker mt = new MediaTracker(this);
+      try {
+	mt.addImage(img, 0);
+	mt.waitForAll();
+	if(mt.isErrorAny())
+	  System.err.println("JPointDemo: Error loading image");
+      } catch (InterruptedException e) {}
+    }
+    Logo logo = new Logo(new Point2D.Double(0.0, 0.0), Logo.BOTTOM, Logo.LEFT);
+    logo.setId("ncBrowse logo");
+    logo.setImage(img);
+    layer.addChild(logo);
+    /*
+     * Create a CartesianGraph and transforms.
+     */
+    CartesianGraph graph;
+    LinearTransform xt, yt;
+
+    graph = new CartesianGraph("Point Graph");
+    layer.setGraph(graph);
+    xt = new LinearTransform(xstart, xend, xrange.start, xrange.end);
+    yt = new LinearTransform(ystart, yend, yrange.start, yrange.end);
+    graph.setXTransform(xt);
+    graph.setYTransform(yt);
+    /*
+     * Create the bottom axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    PlainAxis xbot;
+    String xLabel = "X Label";
+
+    xbot = new PlainAxis("Botton Axis");
+    xbot.setRangeU(xrange);
+    xbot.setLocationU(new Point2D.Double(xrange.start, yrange.start));
+    Font xbfont = new Font("Helvetica", Font.ITALIC, 14);
+    xbot.setLabelFont(xbfont);
+    SGLabel xtitle = new SGLabel("xaxis title", xLabel, 
+                                 new Point2D.Double(0.0, 0.0));
+    Font xtfont = new Font("Helvetica", Font.PLAIN, 14);
+    xtitle.setFont(xtfont);
+    xtitle.setHeightP(0.2);
+    xbot.setTitle(xtitle);
+    graph.addXAxis(xbot);
+    /*
+     * Create the left axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    PlainAxis yleft;
+    String yLabel = "Y Label";
+
+    yleft = new PlainAxis("Left Axis");
+    yleft.setRangeU(yrange);
+    yleft.setLocationU(new Point2D.Double(xrange.start, yrange.start));
+    yleft.setLabelFont(xbfont);
+    SGLabel ytitle = new SGLabel("yaxis title", yLabel, 
+                                 new Point2D.Double(0.0, 0.0));
+    Font ytfont = new Font("Helvetica", Font.PLAIN, 14);
+    ytitle.setFont(ytfont);
+    ytitle.setHeightP(0.2);
+    yleft.setTitle(ytitle);
+    graph.addYAxis(yleft);
+    /*
+     * Create a PointAttribute for the display of the
+     * Collection of points. The points will be red with
+     * the label at the NE corner and in blue.
+     */
+    PointAttribute pattr;
+
+    pattr = new PointAttribute(20, Color.red);
+    pattr.setLabelPosition(PointAttribute.NE);
+    Font pfont = new Font("Helvetica", Font.PLAIN, 12);
+    pattr.setLabelFont(pfont);
+    pattr.setLabelColor(Color.blue);
+    pattr.setLabelHeightP(0.1);
+    pattr.setDrawLabel(true);
+    /*
+     * Associate the attribute and the point Collection
+     * with the graph.
+     */
+    graph.setData(col, pattr);
+    
+    return mainPane_;
+  }
+  
+    void tree_actionPerformed(java.awt.event.ActionEvent e) {
+        JClassTree ct = new JClassTree();
+        ct.setModal(false);
+        ct.setJPane(mainPane_);
+        ct.show();
+    }
+
+  class MyAction implements java.awt.event.ActionListener {
+        public void actionPerformed(java.awt.event.ActionEvent event) {
+           Object obj = event.getSource();
+	   if(obj == space_) {
+	     System.out.println("  <<Mark>>");
+	   }
+	   if(obj == tree_)
+	       tree_actionPerformed(event);
+        }
+    }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JProfileDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JProfileDemo.java
new file mode 100755
index 0000000..88f6446
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JProfileDemo.java
@@ -0,0 +1,111 @@
+/*
+ * $Id: JProfileDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.swing.JPlotLayout;
+import gov.noaa.pmel.sgt.dm.SGTData;
+
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Point2D;
+
+import java.awt.*;
+import javax.swing.*;
+/**
+ * Example demonstrating how to use <code>JPlotLayout</code> to create
+ * a profile plot. 
+ * 
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+
+
+public class JProfileDemo extends JApplet {
+  public void init() {
+    setLayout(null);
+    setSize(450,600);
+    add("Center", makeGraph());
+  }
+
+  public static void main(String[] args) {
+    JProfileDemo pd = new JProfileDemo();
+    JFrame frame = new JFrame("Profile Demo");
+    JPane graph;
+    frame.getContentPane().setLayout(new BorderLayout());
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+      public void windowClosing(java.awt.event.WindowEvent event) {
+	JFrame fr = (JFrame)event.getSource();
+	fr.setVisible(false);
+	fr.dispose();
+	System.exit(0);
+      }
+    });
+    frame.setSize(450, 600);
+    graph = pd.makeGraph();
+    graph.setBatch(true);
+    frame.getContentPane().add(graph, BorderLayout.CENTER);
+    frame.pack();
+    frame.setVisible(true);
+    graph.setBatch(false);
+  }
+
+  JPlotLayout makeGraph() {
+    /*
+     * This example uses a pre-created "Layout" for profile
+     * data to simplify the construction of a plot. The
+     * LineProfileLayout can plot multiple lines, with
+     * a legend and provides zooming and line hi-lighting
+     * capabilities.
+     */
+    SGTData newData;
+    TestData td;
+    JPlotLayout lpl;
+    /*
+     * Create a test profile with random data.
+     */
+    Range2D zrange = new Range2D(0.0, 495.0, 10.0);
+    td = new TestData(TestData.PROFILE, zrange,
+                      TestData.RANDOM, 1.2f, 0.5f, 30.0f);
+    newData = td.getSGTData();
+    /*
+     * Create the layout without a Logo image and with the
+     * LineKey on the main Pane object.  Data object is used
+     * to automatically determine the type of plot to create.
+     */
+    lpl = new JPlotLayout(newData, "Profile Demo", null, false);
+    /*
+     * Add first profile.
+     */
+    lpl.addData(newData, "First Line");
+    /*
+     * Create a second profile.
+     */
+    td = new TestData(TestData.PROFILE, zrange,
+                      TestData.RANDOM, 2.0f, 0.25f, 30.0f);
+    lpl.addData(td.getSGTData(), "Second Line");
+    /*
+     * Change the layout's three title lines and place the Pane
+     * on the Applet.
+     */
+    lpl.setTitles("Profile Demo", 
+                  "using a sgt.swing class", 
+                  "JPlotLayout");
+                  
+    lpl.setSize(new Dimension(450,600));
+    lpl.setLayerSizeP(new Dimension2D(6.0, 8.0));
+    lpl.setKeyLocationP(new Point2D.Double(6.0, 8.0));
+    return lpl;
+  }
+        
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JRealTimeDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JRealTimeDemo.java
new file mode 100755
index 0000000..aa81189
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JRealTimeDemo.java
@@ -0,0 +1,294 @@
+/*
+ * $Id: JRealTimeDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+import javax.swing.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import gov.noaa.pmel.sgt.*;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Point2D;
+//import gov.noaa.pmel.util.*;
+
+/**
+ * Example demonstrating the use of <code>PropertyChangeEvents</code>
+ * in the datamodel.  <code>JRealTimeDemo</code> constructs the plot
+ * from basic <code>sgt</code> objects. 
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+
+public class JRealTimeDemo extends JApplet implements PropertyChangeListener {
+  PseudoRealTimeData rtData_;
+  JPane pane_;
+  Layer layer_;
+  TimeAxis xbot_;
+  PlainAxis yleft_;
+  LinearTransform xt_, yt_;
+  boolean isStandalone = false;
+  BorderLayout borderLayout1 = new BorderLayout();
+  JPanel buttonPanel = new JPanel();
+  JButton startButton = new JButton();
+  JButton stopButton = new JButton();
+  JButton resetButton = new JButton();
+
+  /**Construct the applet*/
+  public JRealTimeDemo() {
+  }
+  /**Initialize the applet*/
+  public void init() {
+    /*
+     * Create the data source
+     */
+    rtData_ = new PseudoRealTimeData("rtDataSource", "Sea Level");
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+    /*
+     * add listener for data source.  JRealTimeDemo is listening
+     * for rangeModified events
+     */
+    rtData_.addPropertyChangeListener(this);
+  }
+  /**Component initialization*/
+  private void jbInit() throws Exception {
+    this.setSize(new Dimension(800, 440));
+    this.getContentPane().setLayout(borderLayout1);
+    startButton.setText("start");
+    startButton.addActionListener(new JRealTimeDemo_startButton_actionAdapter(this));
+    stopButton.setText("stop");
+    stopButton.addActionListener(new JRealTimeDemo_stopButton_actionAdapter(this));
+    resetButton.setText("reset");
+    resetButton.addActionListener(new JRealTimeDemo_resetButton_actionAdapter(this));
+    buttonPanel.setBorder(BorderFactory.createEtchedBorder());
+    this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+    buttonPanel.add(startButton, null);
+    buttonPanel.add(stopButton, null);
+    buttonPanel.add(resetButton, null);
+    //
+    // construct JPane
+    //
+    pane_ = new JPane("Real Time Data Demo", new Dimension(800, 400));
+    pane_.setBatch(true);
+    pane_.setLayout(new StackedLayout());
+    pane_.setBackground(Color.white);
+    /*
+     * xsize, ysize are the width and height in physical units
+     * of the Layer graphics region.
+     *
+     * xstart, xend are the start and end points for the X axis
+     * ystart, yend are the start and end points for the Y axis
+     */
+    double xsize = 6.0;
+    double xstart = 0.6;
+    double xend = 5.5;
+    double ysize = 3.0;
+    double ystart = 0.6;
+    double yend = 2.75;
+    /*
+     * Create the layer and add it to the Pane.
+     */
+    CartesianGraph graph;
+    /*
+     * Get x and y ranges from data source.
+     */
+    SoTRange.GeoDate xrange = (SoTRange.GeoDate)rtData_.getXRange();
+    SoTRange.Double yrange = (SoTRange.Double)rtData_.getYRange();
+
+    xt_ = new LinearTransform(xstart, xend, xrange.start, xrange.end);
+    yt_ = new LinearTransform(ystart, yend, yrange.start, yrange.end);
+
+    layer_ = new Layer("Layer 1", new Dimension2D(xsize, ysize));
+    pane_.add(layer_);
+
+    SGLabel title = new SGLabel("title",
+				"Real Time Demo",
+				new Point2D.Double((xstart+xend)/2.0,
+						   ysize-0.05));
+    title.setAlign(SGLabel.TOP, SGLabel.CENTER);
+    title.setFont(new Font("Serif", Font.PLAIN, 14));
+    title.setHeightP(0.25);
+    title.setColor(Color.blue.darker());
+    layer_.addChild(title);
+    /*
+     * Create a CartesianGraph and set transforms.
+     */
+    graph = new CartesianGraph("Time Graph");
+    layer_.setGraph(graph);
+    graph.setXTransform(xt_);
+    graph.setYTransform(yt_);
+    /*
+     * Create the bottom axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    SoTPoint origin = new SoTPoint(xrange.start, yrange.start);
+    xbot_ = new TimeAxis("Botton Axis", TimeAxis.AUTO);
+    xbot_.setRangeU(xrange);
+    xbot_.setLocationU(origin);
+    Font xbfont = new Font("Helvetica", Font.PLAIN, 14);
+    xbot_.setLabelFont(xbfont);
+    graph.addXAxis(xbot_);
+    /*
+     * Create the left axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    String yLabel = "Latitude";
+
+    yleft_ = new PlainAxis("Left Axis");
+    yleft_.setRangeU(yrange);
+    yleft_.setLocationU(origin);
+    yleft_.setLabelFont(xbfont);
+    SGLabel ytitle = new SGLabel("yaxis title", yLabel,
+                                 new Point2D.Double(0.0, 0.0));
+    Font ytfont = new Font("Helvetica", Font.PLAIN, 14);
+    ytitle.setFont(ytfont);
+    ytitle.setHeightP(0.2);
+    yleft_.setTitle(ytitle);
+    graph.addYAxis(yleft_);
+
+    LineAttribute attr = new LineAttribute();
+    graph.setData(rtData_, attr);
+
+    this.getContentPane().add(pane_, BorderLayout.CENTER);
+    if(!isStandalone) pane_.setBatch(false);
+  }
+  /**Start the applet*/
+  public void start() {
+  }
+  /**Stop the applet*/
+  public void stop() {
+    rtData_.stopData();
+  }
+  /**Destroy the applet*/
+  public void destroy() {
+    rtData_.stopData();
+  }
+  /**Get Applet information*/
+  public String getAppletInfo() {
+    return "Applet Information";
+  }
+  /**Main method*/
+  public static void main(String[] args) {
+    JRealTimeDemo applet = new JRealTimeDemo();
+    applet.isStandalone = true;
+    JFrame frame = new JFrame();
+    //EXIT_ON_CLOSE == 3
+    frame.setDefaultCloseOperation(3);
+    frame.setTitle("Real Time Data Demo");
+    frame.getContentPane().add(applet, BorderLayout.CENTER);
+    applet.init();
+    applet.start();
+    frame.setSize(800,440);
+    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+    frame.setLocation((d.width - frame.getSize().width) / 2, 
+		      (d.height - frame.getSize().height) / 2);
+    frame.setVisible(true);
+    applet.pane_.setBatch(false);
+  }
+
+  //static initializer for setting look & feel
+  static {
+    try {
+      //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+      //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+    }
+    catch(Exception e) {
+    }
+  }
+
+  void startButton_actionPerformed(ActionEvent e) {
+    rtData_.startData();
+  }
+
+  void stopButton_actionPerformed(ActionEvent e) {
+    rtData_.stopData();
+  }
+
+  void resetButton_actionPerformed(ActionEvent e) {
+    rtData_.stopData();
+    rtData_.resetData();
+    resetRange();
+  }
+  private void resetRange() {
+    /*
+     * A change in the range has occured. Get new range
+     * and set transforms, axes, and origin appropriately.
+     */
+    pane_.setBatch(true);
+    SoTRange.GeoDate xrange = (SoTRange.GeoDate)rtData_.getXRange();
+    SoTRange.Double yrange = (SoTRange.Double)rtData_.getYRange();
+    SoTPoint origin = new SoTPoint(xrange.start, yrange.start);
+    xt_.setRangeU(xrange);
+    yt_.setRangeU(yrange);
+    xbot_.setRangeU(xrange);
+    xbot_.setLocationU(origin);
+    yleft_.setRangeU(yrange);
+    yleft_.setLocationU(origin);
+    pane_.setBatch(false);
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    /**
+     * dataModified property is handled by CartesianGraph
+     * only need to look for rangeModified here to make sure
+     * range is properly updated
+     */
+    if("rangeModified".equals(evt.getPropertyName())) {
+      resetRange();
+    }
+  }
+}
+/*
+ * wrappers for button events created by JBuilder
+ */
+class JRealTimeDemo_startButton_actionAdapter implements ActionListener {
+  JRealTimeDemo adaptee;
+
+  JRealTimeDemo_startButton_actionAdapter(JRealTimeDemo adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.startButton_actionPerformed(e);
+  }
+}
+
+class JRealTimeDemo_stopButton_actionAdapter implements ActionListener {
+  JRealTimeDemo adaptee;
+
+  JRealTimeDemo_stopButton_actionAdapter(JRealTimeDemo adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.stopButton_actionPerformed(e);
+  }
+}
+
+class JRealTimeDemo_resetButton_actionAdapter implements ActionListener {
+  JRealTimeDemo adaptee;
+
+  JRealTimeDemo_resetButton_actionAdapter(JRealTimeDemo adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.resetButton_actionPerformed(e);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JTimeSeriesDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JTimeSeriesDemo.java
new file mode 100755
index 0000000..9da96b8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JTimeSeriesDemo.java
@@ -0,0 +1,205 @@
+/*
+ * $Id: JTimeSeriesDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.swing.JPlotLayout;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.sgt.swing.prop.LineAttributeDialog;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.LineAttribute;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+/**
+ * Example demonstrating how to use <code>JPlotLayout</code>
+ * to create a time series plot.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+
+public class JTimeSeriesDemo extends JApplet {
+  JButton tree_;
+  JButton space_ = null;
+  JPane pane_;
+  MyMouse myMouse_;
+  LineAttributeDialog lad_;
+
+  public void init() {
+    /*
+     * init is used when run as an JApplet
+     */
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(600,500);
+    pane_ = makeGraph();
+    pane_.setBatch(true);
+    JPanel button = makeButtonPanel(false);
+    getContentPane().add(pane_, BorderLayout.CENTER);
+    getContentPane().add(button, "South");
+    pane_.setBatch(false);
+  }
+
+  JPanel makeButtonPanel(boolean mark) {
+    JPanel button = new JPanel();
+    button.setLayout(new FlowLayout());
+    tree_ = new JButton("Tree View");
+    MyAction myAction = new MyAction();
+    tree_.addActionListener(myAction);
+    button.add(tree_);
+    /*
+     * optionally include "mark" button
+     */
+    if(mark) {
+      space_ = new JButton("Add Mark");
+      space_.addActionListener(myAction);
+      button.add(space_);
+    }
+    return button;
+  }
+
+  public static void main(String[] args) {
+    /*
+     * main() is used when run as an application
+     */
+    JTimeSeriesDemo tsd = new JTimeSeriesDemo();
+    /*
+     * Create a JFrame to run JTimeSeriesDemo in.
+     */
+    JFrame frame = new JFrame("Time Series Demo");
+    JPanel button = tsd.makeButtonPanel(true);
+    frame.getContentPane().setLayout(new BorderLayout());
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+        public void windowClosing(java.awt.event.WindowEvent event) {
+          JFrame fr = (JFrame)event.getSource();
+          fr.setVisible(false);
+          fr.dispose();
+          System.exit(0);
+        }
+      });
+    tsd.pane_ = tsd.makeGraph();
+    tsd.pane_.setBatch(true);
+    frame.setSize(600, 500);
+    frame.getContentPane().add(tsd.pane_, BorderLayout.CENTER);
+    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    frame.setVisible(true);
+    tsd.pane_.setBatch(false);
+  }
+
+  JPlotLayout makeGraph() {
+    /*
+     * This example uses a pre-created "Layout" for time
+     * series to simplify the construction of a plot. The
+     * LineTimeSeriesLayout can plot multiple lines, with
+     * a legend and provides zooming and line hi-lighting
+     * capabilities.
+     */
+    SGTData newData;
+    TestData td;
+    JPlotLayout ltsl;
+    /*
+     * Create a test time series with random data.
+     */
+    GeoDate start = new GeoDate();
+    GeoDate stop = new GeoDate();
+    try {
+      start = new GeoDate("1968-11-01", "yyyy-MM-dd");
+      stop  = new GeoDate("2001-02-20", "yyyy-MM-dd");
+    } catch (IllegalTimeValue e) {}
+    TimeRange tr = new TimeRange(start, stop);
+    td = new TestData(TestData.TIME_SERIES, tr, 10.0f,
+                      TestData.RANDOM, 1.2f, 0.5f, 30.0f);
+    newData = td.getSGTData();
+    System.out.println("series length = " + ((SGTLine)newData).getYArray().length);
+    /*
+     * Create the layout without a Logo image and with the
+     * LineKey on the main Pane object.
+     */
+    ltsl = new JPlotLayout(newData, "Time Series Demo", null, false);
+    /*
+     * Add the time series to the layout and give a label for
+     * the legend.
+     */
+    ltsl.addData(newData, "Random Data");
+    /*
+     * Change the layout's three title lines and place the Pane
+     * on the Applet.
+     */
+    ltsl.setTitles("Time Series Demo",
+                   "using JPlotLayout",
+                   "");
+
+    myMouse_ = new MyMouse();
+    ltsl.addMouseListener(myMouse_);
+
+    return ltsl;
+  }
+
+  void tree_actionPerformed(java.awt.event.ActionEvent e) {
+    /*
+     * Create JClassTree showing object tree.
+     */
+    JClassTree ct = new JClassTree();
+    ct.setModal(false);
+    ct.setJPane(pane_);
+    ct.show();
+  }
+
+  class MyAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object obj = event.getSource();
+      if(obj == space_) {
+        System.out.println("  <<Mark>>");
+      }
+      if(obj == tree_)
+        tree_actionPerformed(event);
+    }
+  }
+
+  class MyMouse extends MouseAdapter {
+    /*
+     * process mouse events.
+     */
+    public void mouseReleased(MouseEvent event) {
+      Object object = event.getSource();
+      if(object == pane_)
+        maybeShowLineAttributeDialog(event);
+    }
+
+    void maybeShowLineAttributeDialog(MouseEvent e) {
+      if(e.isPopupTrigger() || e.getClickCount() == 2) {
+        Object obj = pane_.getObjectAt(e.getX(), e.getY());
+        pane_.setSelectedObject(obj);
+        if(obj instanceof LineCartesianRenderer) {
+          LineAttribute attr = ((LineCartesianRenderer)obj).getLineAttribute();
+          if(lad_ == null) {
+            lad_ = new LineAttributeDialog();
+          }
+          lad_.setLineAttribute(attr);
+          if(!lad_.isShowing())
+            lad_.setVisible(true);
+        }
+      }
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JVectorDemo.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JVectorDemo.java
new file mode 100755
index 0000000..a129685
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/JVectorDemo.java
@@ -0,0 +1,268 @@
+/*
+ * $Id: JVectorDemo.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.swing.JPlotLayout;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.AbstractPane;
+import gov.noaa.pmel.sgt.VectorAttribute;
+import gov.noaa.pmel.sgt.CartesianRenderer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SGTVector;
+import gov.noaa.pmel.sgt.swing.prop.VectorAttributeDialog;
+
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.IllegalTimeValue;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+import java.awt.event.ActionEvent;
+
+import java.awt.print.PrinterJob;
+import java.awt.print.PrinterException;
+
+/**
+ * Example demonstrating how to use <code>JPlotLayout</code>
+ * to create a raster-contour plot.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.1
+ */
+public class JVectorDemo extends JApplet {
+  static JPlotLayout rpl_;
+  private VectorAttribute vectorAttr_;
+  JButton edit_;
+  JButton space_ = null;
+  JButton tree_;
+  JButton print_ = null;
+
+  public void init() {
+    /*
+     * Create the demo in the JApplet environment.
+     */
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setBackground(java.awt.Color.white);
+    setSize(600,430);
+    JPanel main = new JPanel();
+    rpl_ = makeGraph();
+    JPanel button = makeButtonPanel(false);
+    rpl_.setBatch(true);
+    main.add(rpl_, BorderLayout.CENTER);
+    getContentPane().add(main, "Center");
+    getContentPane().add(button, "South");
+    rpl_.setBatch(false);
+  }
+
+  JPanel makeButtonPanel(boolean app) {
+    JPanel button = new JPanel();
+    button.setLayout(new FlowLayout());
+    MyAction myAction = new MyAction();
+    if(app) {
+      print_ = new JButton("Print...");
+      print_.addActionListener(myAction);
+      button.add(print_);
+    }
+    tree_ = new JButton("Tree View");
+    tree_.addActionListener(myAction);
+    button.add(tree_);
+    edit_ = new JButton("Edit VectorAttribute");
+    edit_.addActionListener(myAction);
+    button.add(edit_);
+    /*
+     * Optionally leave the "mark" button out of the button panel
+     */
+    if(app) {
+      space_ = new JButton("Add Mark");
+      space_.addActionListener(myAction);
+      button.add(space_);
+    }
+    return button;
+  }
+  public static void main(String[] args) {
+    /*
+     * Create the demo as an application
+     */
+    JVectorDemo vd = new JVectorDemo();
+    /*
+     * Create a new JFrame to contain the demo.
+     */
+    JFrame frame = new JFrame("Vector Demo");
+    JPanel main = new JPanel();
+    main.setLayout(new BorderLayout());
+    frame.setSize(600,400);
+    frame.getContentPane().setLayout(new BorderLayout());
+    /*
+     * Listen for windowClosing events and dispose of JFrame
+     */
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+      public void windowClosing(java.awt.event.WindowEvent event) {
+        JFrame fr = (JFrame)event.getSource();
+        fr.setVisible(false);
+        fr.dispose();
+        System.exit(0);
+      }
+    });
+    /*
+     * Create button panel with "mark" button
+     */
+    JPanel button = vd.makeButtonPanel(true);
+    /*
+     * Create JPlotLayout and turn batching on.  With batching on the
+     * plot will not be updated as components are modified or added to
+     * the plot tree.
+     */
+    rpl_ = vd.makeGraph();
+    rpl_.setBatch(true);
+    /*
+     * Layout the plot and buttons.
+     */
+    main.add(rpl_, BorderLayout.CENTER);
+    frame.getContentPane().add(main, BorderLayout.CENTER);
+    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    frame.pack();
+    /*
+     * Turn batching off. JPlotLayout will redraw if it has been
+     * modified since batching was turned on.
+     */
+    rpl_.setBatch(false);
+
+    frame.setVisible(true);
+  }
+
+  void print_actionPerformed(ActionEvent e) {
+    Color saveColor;
+
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+    printJob.setPrintable(rpl_);
+    printJob.setJobName("Vector Demo");
+    if(printJob.printDialog()) {
+      try {
+        saveColor = rpl_.getBackground();
+        if(!saveColor.equals(Color.white)) {
+          rpl_.setBackground(Color.white);
+        }
+        rpl_.setPageAlign(AbstractPane.TOP,
+                          AbstractPane.CENTER);
+        RepaintManager currentManager = RepaintManager.currentManager(rpl_);
+        currentManager.setDoubleBufferingEnabled(false);
+        printJob.print();
+        currentManager.setDoubleBufferingEnabled(true);
+        rpl_.setBackground(saveColor);
+      } catch (PrinterException pe) {
+        System.out.println("Error printing: " + pe);
+      }
+    }
+
+  }
+
+  void edit_actionPerformed(ActionEvent e) {
+    /*
+     * Create a GridAttributeDialog and set the renderer.
+     */
+     VectorAttributeDialog vad = new VectorAttributeDialog();
+     vad.setJPane(rpl_);
+     vad.setVectorAttribute(vectorAttr_);
+     vad.setVisible(true);
+  }
+
+    void tree_actionPerformed(ActionEvent e) {
+      /*
+       * Create a JClassTree for the JPlotLayout objects
+       */
+        JClassTree ct = new JClassTree();
+        ct.setModal(false);
+        ct.setJPane(rpl_);
+        ct.show();
+    }
+
+  JPlotLayout makeGraph() {
+    /*
+     * This example uses a pre-created "Layout" for raster time
+     * series to simplify the construction of a plot. The
+     * JPlotLayout can plot a single grid with
+     * a ColorKey, time series with a LineKey, point collection with a
+     * PointCollectionKey, and general X-Y plots with a
+     * LineKey. JPlotLayout supports zooming, object selection, and
+     * object editing.
+     */
+    SGTGrid uComp;
+    SGTGrid vComp;
+    SGTVector vector;
+    TestData td;
+    JPlotLayout rpl;
+    /*
+     * Create a test grid with sinasoidal-ramp data.
+     */
+    Range2D xr = new Range2D(190.0f, 250.0f, 3.0f);
+    Range2D yr = new Range2D(0.0f, 45.0f, 3.0f);
+    td = new TestData(TestData.XY_GRID, xr, yr,
+                      TestData.SINE_RAMP, 20.0f, 10.f, 5.0f);
+    uComp = (SGTGrid)td.getSGTData();
+    td = new TestData(TestData.XY_GRID, xr, yr,
+                      TestData.SINE_RAMP, 20.0f, 0.f, 3.0f);
+    vComp = (SGTGrid)td.getSGTData();
+    vector = new SGTVector(uComp, vComp);
+    /*
+     * Create the layout without a Logo image and with the
+     * VectorKey on the graph Pane.
+     */
+    rpl = new JPlotLayout(JPlotLayout.VECTOR,
+                          false, false, "test layout", null, false);
+    rpl.setEditClasses(false);
+    vectorAttr_ = new VectorAttribute(0.0075, Color.red);
+    vectorAttr_.setHeadScale(0.5);
+    /*
+     * Add the grid to the layout and give a label for
+     * the VectorKey.
+     */
+    rpl.addData(vector, vectorAttr_, "First Data");
+    /*
+     * Change the layout's three title lines.
+     */
+    rpl.setTitles("Vector Plot Demo",
+                  "using a JPlotLayout",
+                  "");
+    /*
+     * Resize the graph  and place in the "Center" of the frame.
+     */
+    rpl.setSize(new Dimension(600, 400));
+    return rpl;
+  }
+
+  class MyAction implements java.awt.event.ActionListener {
+        public void actionPerformed(java.awt.event.ActionEvent event) {
+           Object obj = event.getSource();
+           if(obj == edit_) {
+             edit_actionPerformed(event);
+           } else if(obj == space_) {
+             System.out.println("  <<Mark>>");
+           } else if(obj == tree_) {
+               tree_actionPerformed(event);
+           } else if(obj == print_) {
+               print_actionPerformed(event);
+           }
+        }
+    }
+}
+
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/PseudoRealTimeData.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/PseudoRealTimeData.java
new file mode 100755
index 0000000..d7a15db
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/PseudoRealTimeData.java
@@ -0,0 +1,239 @@
+/*
+ * $Id: PseudoRealTimeData.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTMetaData;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Timer;
+
+/**
+ * Generates a real-time data stream using <code>SGTLine</code> and
+ * <code>javax.swing.Timer</code>. <code>PseudoRealTimeData</code>
+ * generates <code>PropertyCchangeEvent</code>s
+ * whenever data is added "dataModified" or the data range changes
+ * "rangeModified". The "dataModified" event is directly handled by
+ * <code>sgt</code> and the "rangeModified" event needs to be handled
+ * by the graphics application.
+ *
+ * <p> <code>PseudoRealTimeData</code> demonstrates how a class that
+ * implements the <code>SGTLine</code> interface can use the
+ * <code>getXRange()</code> and <code>getYRange()</code> methods to
+ * produce "nice" plots.  This class updates the data each time step,
+ * but updates the range only after a day has passed.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+
+public class PseudoRealTimeData implements SGTLine, ActionListener {
+  private SGTMetaData xMeta_;
+  private SGTMetaData yMeta_;
+  private SoTRange.GeoDate xRange_;
+  private SoTRange.Double yRange_;
+  private GeoDate[] xData_;
+  private double[] yData_;
+  private GeoDate tend_;
+  private int count_;
+  private String title_;
+  private SGLabel keyTitle_ = null;
+  private String id_;
+  private Timer timer_;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private GeoDate ref_ = null;
+  // bufsize should be integral multiple of majorIncrement plus 1
+  private int bufsize_ = 241;
+  private int offset_;
+  // offsetIncrement should be same as majorIncrement
+  private int offsetIncrement_ = 24;
+
+  private double minorIncrement_ = 1.0;
+  private double majorIncrement_ = 24.0;
+  private int units_ = GeoDate.HOURS;
+
+  private double A0_ = 1.0;
+  private double A1_ = 0.375;
+  private double A2_ = 0.2;
+  private double omega0_ = 0.251327412;
+  private double omega1_ = 0.3;
+  /**
+   * Constructor.
+   */
+  public PseudoRealTimeData(String id, String title) {
+    xMeta_ = new SGTMetaData("Time", "");
+    yMeta_ = new SGTMetaData("PseudoData", "Ps/day");
+    title_ = title;
+    id_ = id;
+    timer_ = new Timer(250, this);
+    resetData();
+  }
+  /**
+   * Get x data array.  Always returns <code>null</code>.
+   */
+  public double[] getXArray() {
+    return null;
+  }
+  /**
+   * Get y data values. Creates a copy of the buffer array.
+   */
+  public double[] getYArray() {
+    if(count_ > 0) {
+      double[] temp = new double[count_+offset_];
+      for(int i=0; i < count_+offset_; i++) {
+        temp[i] = yData_[i];
+      }
+      return temp;
+    } else {
+      return null;
+    }
+  }
+  public GeoDate[] getTimeArray() {
+    if(count_ > 0) {
+      GeoDate[] temp = new GeoDate[count_+offset_];
+      for(int i=0; i < count_+offset_; i++) {
+        temp[i] = xData_[i];
+      }
+      return temp;
+    } else {
+      return null;
+    }
+  }
+  /**
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArray() {
+    return new GeoDateArray(getTimeArray());
+  }
+  public SGTLine getAssociatedData() {
+    return null;
+  }
+  public boolean hasAssociatedData() {
+    return false;
+  }
+  public String getTitle() {
+    return title_;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  public String getId() {
+    return id_;
+  }
+  public SGTData copy() {
+    return null;
+  }
+  public boolean isXTime() {
+    return true;
+  }
+  public boolean isYTime() {
+    return false;
+  }
+  public SGTMetaData getXMetaData() {
+    return xMeta_;
+  }
+  public SGTMetaData getYMetaData() {
+    return yMeta_;
+  }
+  public SoTRange getXRange() {
+    return xRange_.copy();
+  }
+  public SoTRange getYRange() {
+    return yRange_.copy();
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+  /**
+   * Start the timer and begin/continue generating property change events.
+   */
+  public void startData() {
+    timer_.start();
+  }
+  /**
+   * Stop the timer.
+   */
+  public void stopData() {
+    timer_.stop();
+  }
+  /**
+   * Reset the demonstration to the begining.
+   */
+  public void resetData() {
+    xData_ = new GeoDate[bufsize_];
+    yData_ = new double[bufsize_];
+    try {
+      ref_ = new GeoDate("1999-01-01 00:00", "yyyy-MM-dd HH:mm");
+    } catch (IllegalTimeValue e) {
+      e.printStackTrace();
+    }
+    tend_ = new GeoDate(ref_);
+    // Add a little fudge to get last tic on the axis
+    tend_.increment(10.0, GeoDate.SECONDS);
+    yRange_ = new SoTRange.Double(-1.5, 1.5);
+    xRange_ = new SoTRange.GeoDate(new GeoDate(ref_),
+                                    tend_.increment(majorIncrement_, units_));
+    xData_[0] = new GeoDate(ref_);
+    yData_[0] = 0.0;
+    count_ = 1;
+    offset_ = 0;
+  }
+
+  /**
+   * Handle timer ActionEvents
+   * <BR><B>Property Change:</B> <code>rangeModified</code> and
+   * <code>DataModified</code>
+   */
+  public void actionPerformed(ActionEvent e) {
+    if((count_+offset_) >= bufsize_) {
+      offset_ = offset_ - offsetIncrement_;
+      for(int i=0; i < bufsize_-offsetIncrement_; i++) {
+        xData_[i] = xData_[i+offsetIncrement_];
+        yData_[i] = yData_[i+offsetIncrement_];
+      }
+      xRange_.start = xData_[0];
+    }
+    xData_[count_+offset_] = new GeoDate(ref_.increment(minorIncrement_, units_));
+    yData_[count_+offset_] = tSeries(count_);
+    if(xData_[count_+offset_].after(tend_)) {
+      SoTRange.GeoDate oldRange = (SoTRange.GeoDate)xRange_.copy();
+      /**
+       * compute new range
+       */
+      tend_.increment(majorIncrement_, units_);
+      xRange_.end = tend_;
+      changes_.firePropertyChange("rangeModified", oldRange, xRange_);
+    } else {
+      changes_.firePropertyChange("dataModified",
+                                  new Integer(count_),
+                                  new Integer(count_+1));
+    }
+    count_++;
+  }
+
+  private double tSeries(int val) {
+    return A0_*Math.sin(omega0_*val)+A1_*Math.sin(omega1_*val)+A2_*Math.random();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAO.dat b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAO.dat
new file mode 100755
index 0000000..e7a9736
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAO.dat
@@ -0,0 +1,59 @@
+0;-95;0N 95W
+2;-95;2N 95W
+4;-95;4N 95W
+5;-95;5N 95W
+8;-95;8N 95W
+-2;-95;2S 95W
+-5;-95;5S 95W
+-8;-95;8S 95W
+10;-95;10N 95W
+12;-95;12N 95W
+0;-110;0N 110W
+2;-110;2N 110W
+5;-110;5N 110W
+8;-110;8N 110W
+-2;-110;2S 110W
+-5;-110;5S 110W
+-8;-110;8S 110W
+0;-125;0N 125W
+2;-125;2N 125W
+5;-125;5N 125W
+8;-125;8N 125W
+-2;-125;2S 125W
+-5;-125;5S 125W
+-8;-125;8S 125W
+0;-140;0N 140W
+2;-140;2N 140W
+5;-140;5N 140W
+7;-140;7N 140W
+9;-140;9N 140W
+-2;-140;2S 140W
+-5;-140;5S 140W
+0;-155;0N 155W
+2;-155;2N 155W
+5;-155;5N 155W
+8;-155;8N 155W
+-2;-155;2S 155W
+-5;-155;5S 155W
+-8;-155;8S 155W
+0;-170;0N 170W
+2;-170;2N 170W
+5;-170;5N 170W
+8;-170;8N 170W
+-2;-170;2S 170W
+-5;-170;5S 170W
+-8;-170;8S 170W
+0;-180;0N 180W
+2;-180;2N 180W
+5;-180;5N 180W
+8;-180;8N 180W
+-2;-180;2S 180W
+-5;-180;5S 180W
+-8;-180;8S 180W
+0;165;0N 165E
+2;165;2N 165E
+5;165;5N 165E
+8;165;8N 165E
+-2;165;2S 165E
+-5;165;5S 165E
+-8;165;8S 165E
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAOMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAOMap.java
new file mode 100755
index 0000000..c0656ee
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TAOMap.java
@@ -0,0 +1,680 @@
+/*
+ * $Id: TAOMap.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.PointCollectionKey;
+import gov.noaa.pmel.sgt.PointCartesianRenderer;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.swing.JClassTree;
+import gov.noaa.pmel.sgt.Logo;
+
+import gov.noaa.pmel.sgt.swing.ValueIcon;
+import gov.noaa.pmel.sgt.swing.ValueIconFormat;
+import gov.noaa.pmel.sgt.swing.prop.PointAttributeDialog;
+
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.SimplePoint;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.dm.SimpleLine;
+import gov.noaa.pmel.sgt.dm.SGTMetaData;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.SoTPoint;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import javax.swing.*;
+import java.io.*;
+import java.text.DecimalFormat;
+import java.util.StringTokenizer;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Example demonstrating the creation of a graph that displays point
+ * data from files and includes a coastline.  <code>TAOMap</code>
+ * constructs the plot from basic <code>sgt</code> objects and uses
+ * the <code>JPane</code> <code>PropertyChangeEvent</code>s to notify
+ * <code>TAOMap</code> of zoom requests and object selections.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 2.0
+ */
+public class TAOMap extends JApplet implements PropertyChangeListener {
+  JButton tree_;
+  JButton space_ = null;
+  JButton reset_;
+  JPane mainPane_;
+  SGTLine coastLine_ = null;
+  CartesianGraph graph_;
+  LinearTransform xt_, yt_;
+  Layer layer_;
+  PlainAxis xbot_;
+  PlainAxis yleft_;
+  Range2D xrange_, yrange_;
+  PointAttributeDialog pAttrDialog_ = null;
+
+  public void init() {
+    /*
+     * init() is called when TAOMap is run as an JApplet.
+     */
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(553,438);
+    JPane graph = makeGraph();
+    graph.setBatch(true);
+
+    getContentPane().add(graph, "Center");
+    getContentPane().add(makeButtonPanel(false), "South");
+    addValueIcon();
+    graph.setBatch(false);
+  }
+
+  JPanel makeButtonPanel(boolean mark) {
+    /*
+     * Create the buttonPanel.  Leave the "mark" button off when
+     * creating the panel for a JApplet.  The mark button is used for
+     * debugging events.
+     */
+    JPanel button = new JPanel();
+    button.setLayout(new FlowLayout());
+    /*
+     * Create button to open a JClassTree dialog
+     */
+    tree_ = new JButton("Tree View");
+    MyAction myAction = new MyAction();
+    tree_.addActionListener(myAction);
+    button.add(tree_);
+    if(mark) {
+      /*
+       * Create the <<mark>> button
+       */
+      space_ = new JButton("Add Mark");
+      space_.addActionListener(myAction);
+      button.add(space_);
+    }
+    /*
+     * Create the zoom reset button.
+     */
+    reset_ = new JButton("Reset Zoom");
+    reset_.addActionListener(myAction);
+    button.add(reset_);
+    return button;
+  }
+
+  public static void main(String[] args) {
+    /*
+     * main(String[] args) is called when TAOMap is run as an
+     * application
+     */
+    TAOMap pd = new TAOMap();
+    /*
+     * Create a JFrame to place TAOMap into.
+     */
+    JFrame frame = new JFrame("TAO Mooring Map");
+    JPane graph;
+    JPanel button;
+    frame.getContentPane().setLayout(new BorderLayout());
+    /*
+     * Add listener to properly dispose of window when closed.
+     */
+    frame.addWindowListener(new java.awt.event.WindowAdapter() {
+        public void windowClosing(java.awt.event.WindowEvent event) {
+          JFrame fr = (JFrame)event.getSource();
+          fr.setVisible(false);
+          fr.dispose();
+          System.exit(0);
+        }
+      });
+    frame.setSize(553,438);
+    graph = pd.makeGraph();
+    /*
+     * make buttonPanel with "mark" button.
+     */
+    button = pd.makeButtonPanel(true);
+    /*
+     * set batch to true.  Changes to graph will not cause updates of
+     * the display.
+     */
+    graph.setBatch(true);
+    frame.getContentPane().add(graph, BorderLayout.CENTER);
+    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    frame.pack();
+    frame.setVisible(true);
+    pd.addValueIcon();
+    /*
+     * set batch to false. Any changes to graph will now cause graph
+     * to redraw.
+     */
+    graph.setBatch(false);
+
+  }
+
+  JPane makeGraph() {
+    /*
+     * This example creates a very simple plot from
+     * scratch (not using one of the gov.noaa.pmel.sgt.swing classes)
+     * to display a Collection of points.
+     */
+    coastLine_ = getCoastLine("finerezcoast.bin", 50200);
+    /*
+     * Create a Pane, place in the center of the Applet
+     * and set the layout to be StackedLayout.
+     */
+    mainPane_ = new JPane("Point Plot Demo", new Dimension(553,438));
+    mainPane_.setLayout(new StackedLayout());
+    mainPane_.setBackground(Color.white);
+    /*
+     * Read two point collections, TAO.dat and TRITON.dat.  These
+     * files contain coordinate and labelling information.
+     *
+     */
+    Collection TAO;
+    Collection TRITON;
+    TAO = readPointCollection("TAO.dat");
+    TRITON = readPointCollection("TRITON.dat");
+    /*
+     * Although Collection has methods to query the x and y range of
+     * the coordinates we set the range to produce a "nice" graph.
+     */
+    xrange_ = new Range2D(130.0, 270., 20.0);
+    yrange_ = new Range2D(-10.0, 14.0, 2.0);
+    /*
+     * xsize, ysize are the width and height in physical units
+     * of the Layer graphics region.
+     *
+     * xstart, xend are the start and end points for the X axis
+     * ystart, yend are the start and end points for the Y axis
+     */
+    double xsize = 4.0;
+    double xstart = 0.45;
+    double xend = 3.75;
+    double ysize = 3.0;
+    double ystart = 0.45;
+    double yend = 2.95;
+
+    /*
+     * Create the transforms that will be used for all layers
+     */
+    xt_ = new LinearTransform(xstart, xend, xrange_.start, xrange_.end);
+    yt_ = new LinearTransform(ystart, yend, yrange_.start, yrange_.end);
+
+    if(coastLine_ != null) {
+      /*
+       * Create the layer that will hold the coastline and add to the
+       * JPane.
+       */
+      Layer layer = new Layer("CoastLine", new Dimension2D(xsize, ysize));
+      mainPane_.add(layer);
+      /*
+       * Create the CartesianGraph, attach to the layer, set the
+       * transforms and add the coastline data.
+       */
+      CartesianGraph cstgraph = new CartesianGraph("CoastLine Graph");
+      layer.setGraph(cstgraph);
+      cstgraph.setXTransform(xt_);
+      cstgraph.setYTransform(yt_);
+      LineAttribute lattr = new LineAttribute();
+      lattr.setColor(new Color(165, 42, 42));
+      cstgraph.setData(coastLine_, lattr);
+      /*
+       * Since the coastline is for the entire world we clip the
+       * display to the current axes.
+       */
+      cstgraph.setClip(xrange_.start, xrange_.end,
+                      yrange_.start, yrange_.end);
+      cstgraph.setClipping(true);
+    }
+    /*
+     * Create the first "data" layer.  This object reference is made
+     * class wide for convience later.
+     */
+    layer_ = new Layer("Layer 1", new Dimension2D(xsize, ysize));
+    mainPane_.add(layer_);
+    /*
+     * Create a CartesianGraph and set the transforms.
+     */
+    graph_ = new CartesianGraph("Point Graph");
+    layer_.setGraph(graph_);
+    graph_.setXTransform(xt_);
+    graph_.setYTransform(yt_);
+    /*
+     * This Graph contain the plots axes.
+     * Create the bottom axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    String xLabel = "Longitude";
+
+    xbot_ = new PlainAxis("Botton Axis");
+    xbot_.setRangeU(xrange_);
+    xbot_.setLocationU(new Point2D.Double(xrange_.start, yrange_.start));
+    Font xbfont = new Font("Helvetica", Font.ITALIC, 14);
+    xbot_.setLabelFont(xbfont);
+    SGLabel xtitle = new SGLabel("xaxis title", xLabel,
+                                 new Point2D.Double(0.0, 0.0));
+    Font xtfont = new Font("Helvetica", Font.PLAIN, 14);
+    xtitle.setFont(xtfont);
+    xtitle.setHeightP(0.2);
+    xbot_.setTitle(xtitle);
+    graph_.addXAxis(xbot_);
+    /*
+     * Create the left axis, set its range in user units
+     * and its origin. Add the axis to the graph.
+     */
+    String yLabel = "Latitude";
+
+    yleft_ = new PlainAxis("Left Axis");
+    yleft_.setRangeU(yrange_);
+    yleft_.setLocationU(new Point2D.Double(xrange_.start, yrange_.start));
+    yleft_.setLabelFont(xbfont);
+    SGLabel ytitle = new SGLabel("yaxis title", yLabel,
+                                 new Point2D.Double(0.0, 0.0));
+    Font ytfont = new Font("Helvetica", Font.PLAIN, 14);
+    ytitle.setFont(ytfont);
+    ytitle.setHeightP(0.2);
+    yleft_.setTitle(ytitle);
+    graph_.addYAxis(yleft_);
+    /*
+     * create the point collection key
+     */
+    PointCollectionKey key = new PointCollectionKey();
+    key.setId("Mooring Key");
+    key.setVAlign(PointCollectionKey.TOP);
+    key.setHAlign(PointCollectionKey.LEFT);
+    key.setBorderStyle(PointCollectionKey.PLAIN_LINE);
+    key.setLocationP(new Point2D.Double(xstart+0.1, yend));
+    layer_.addChild(key);
+    /*
+     * Create a PointAttribute for the display of the
+     * Collection of points. The points will have a color or rgb
+     * (200,0,255) with the label at the NE corner and in a dark red.
+     */
+    PointAttribute pattr;
+    Color markColor = new Color(200, 0, 255);
+    pattr = new PointAttribute(44, markColor);
+    pattr.setLabelPosition(PointAttribute.NE);
+    Font pfont = new Font("Helvetica", Font.PLAIN, 12);
+    pattr.setLabelFont(pfont);
+    pattr.setLabelColor(Color.red.darker());
+    pattr.setLabelHeightP(0.08);
+    pattr.setDrawLabel(true);
+    /*
+     * Associate the attribute and the point Collection
+     * with the graph.
+     */
+    graph_.setData(TAO, pattr);
+    SGLabel pointTitle = new SGLabel("TAO title",
+                                     "TAO Moorings",
+                                     new Point2D.Double(0.0, 0.0));
+    pointTitle.setHeightP(0.16);
+    key.addPointGraph((PointCartesianRenderer)graph_.getRenderer(),
+                      pointTitle);
+    /*
+     * create second layer for second file
+     */
+    Layer layer2 = new Layer("Layer 2", new Dimension2D(xsize, ysize));
+    mainPane_.add(layer2);
+    /*
+     * Create the graph and set the shared transforms.  NOTE: this
+     * graph will not contain any axes.
+     */
+    CartesianGraph graph2 = new CartesianGraph("Point Graph2");
+    layer2.setGraph(graph2);
+    graph2.setXTransform(xt_);
+    graph2.setYTransform(yt_);
+
+    PointAttribute pattr2;
+    pattr2 = new PointAttribute(13, markColor);
+    pattr2.setLabelPosition(PointAttribute.NE);
+    pattr2.setLabelFont(pfont);
+    pattr2.setLabelColor(Color.blue.darker());
+    pattr2.setLabelHeightP(0.08);
+    pattr2.setDrawLabel(true);
+
+    graph2.setData(TRITON, pattr2);
+    SGLabel pointTitle2 = new SGLabel("TRITON title",
+                                      "TRITON Moorings",
+                                      new Point2D.Double(0.0, 0.0));
+    pointTitle2.setHeightP(0.16);
+    key.addPointGraph((PointCartesianRenderer)graph2.getRenderer(),
+                      pointTitle2);
+    mainPane_.addPropertyChangeListener(this);
+
+    return mainPane_;
+  }
+
+  private void addValueIcon() {
+    /*
+     * add a ValueIcon.  The value icon is used to show the current
+     * value for the user coordinates.
+     */
+    ValueIcon vi = new ValueIcon(getClass().getResource("query.gif"), "value");
+
+    layer_.addChild(vi);
+    vi.setId("local query");
+    try {
+      vi.setLocationU(new SoTPoint(220.0, -5.0));
+    } catch (java.beans.PropertyVetoException e) {
+      e.printStackTrace();
+    }
+    vi.setVisible(true);
+    vi.setSelectable(true);
+    vi.setValueFormat(new GeoFormat());
+
+  }
+
+  void tree_actionPerformed(ActionEvent e) {
+    /*
+     * Create a JClassTree to display a graph of the sgt objects
+     */
+    JClassTree ct = new JClassTree();
+    ct.setModal(false);
+    ct.setJPane(mainPane_);
+    ct.show();
+  }
+
+  class MyAction implements java.awt.event.ActionListener {
+    public void actionPerformed(ActionEvent event) {
+      Object obj = event.getSource();
+      if(obj == space_) {
+        System.out.println("  <<Mark>>");
+      }
+      if(obj == tree_)
+        tree_actionPerformed(event);
+      if(obj == reset_)
+        reset_actionPerformed(event);
+    }
+  }
+
+  Collection readPointCollection(String file) {
+    /*
+     * method used to parse the station information.
+     * The file format is
+     * lat;lon;label
+     */
+    SimplePoint sp = null;
+    BufferedReader in = null;
+    String line = null;
+    String title;
+    int lat, lon;
+    Collection pc = new Collection(file);
+    /*
+     * Get data file.  The getResourceAsStream enables java to find
+     * the data inside of a jar file.
+     */
+    InputStream is = getClass().getResourceAsStream(file);
+    /*
+     * Open reader and get first line
+     */
+    try {
+      in = new BufferedReader(new InputStreamReader(is));
+      line = in.readLine();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    while(line != null) {
+      StringTokenizer st = new StringTokenizer(line, ";");
+      String token1 = st.nextToken();
+      String token2 = st.nextToken();
+      title = st.nextToken();
+      lat = Integer.parseInt(token1);
+      lon = Integer.parseInt(token2);
+      if(lon < 0) lon = lon + 360;
+      lon = lon%360;
+      /*
+       * Create new SimplePoint with coordinates and title and
+       * add to Collection.
+       */
+      sp = new SimplePoint((double)lon, (double)lat, title);
+      pc.addElement(sp);
+      /*
+       * Read the next line
+       */
+      try {
+        line = in.readLine();
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+
+    return pc;
+  }
+  SGTLine getCoastLine(String coastFileName, int bufsize) {
+    /*
+     * Read coastline file
+     */
+    SimpleLine line;
+    if(coastFileName.length() == 0) return null;
+
+    double[] lat = new double[bufsize];
+    double[] lon = new double[bufsize];
+    int cpt = 0;
+    int cpt_save = 0;
+    int cut_count = 0;
+    InputStream is = getClass().getResourceAsStream(coastFileName);
+    try {
+      BufferedInputStream bis;
+      bis = new BufferedInputStream(is, 1000000);
+      DataInputStream inData = new DataInputStream(bis);
+      while (true) {
+        // get the number of entries
+        int numEntries = inData.readShort();
+        if (numEntries == -1)
+          break;
+
+        // get the lats and lons for this segment
+        cpt_save = cpt;
+        for (int i=0; i<numEntries; i++) {
+          lat[cpt] = inData.readDouble();
+          cpt++;
+        }
+
+        cpt = cpt_save;
+        for (int i=0; i<numEntries; i++) {
+          lon[cpt] = (inData.readDouble() + 360)%360.0;
+          if(cpt > 0 && Math.abs(lon[cpt] - lon[cpt-1]) > 50.0) {
+            cut_count++;
+          }
+          cpt++;
+        }
+
+        lat[cpt] = Double.NaN;
+        lon[cpt] = Double.NaN;
+        cpt++;
+      }
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    System.out.println(cpt + " points read");
+    System.out.println(cut_count + " cuts added");
+    /*
+     * The coastline file is setup for +180/-180 range for
+     * longitudes.  Since TAO and TRITON span the pacific we
+     * need to remap longitude to 0-360. Additional points need
+     * to be added so that lines don't wrap strangely.
+     */
+    int length = cpt;
+    double[] latVal = new double[cpt + cut_count];
+    double[] lonVal = new double[cpt + cut_count];
+    cpt = 0;
+    for(int i=0; i < length; i++) {
+      if(i > 0 && Math.abs(lon[i] - lon[i-1]) > 50.0) {
+        latVal[cpt] = Double.NaN;
+        lonVal[cpt] = Double.NaN;
+        cpt++;
+      }
+      latVal[cpt] = lat[i];
+      lonVal[cpt] = lon[i];
+      cpt++;
+    }
+
+    line = new SimpleLine(lonVal, latVal, "CoastLine");
+    SGTMetaData yMeta = new SGTMetaData("Latitude", "degrees_N",
+                                        false, false);
+    SGTMetaData xMeta = new SGTMetaData("Longitude", "degrees_E",
+                                        false, true);
+    line.setXMetaData(xMeta);
+    line.setYMetaData(yMeta);
+
+    return line;
+  }
+
+  public void propertyChange(PropertyChangeEvent event) {
+    /*
+     * Listen for propery change events from JPane.
+     */
+    String name = event.getPropertyName();
+    if(name.equals("zoomRectangle")) {
+      /*
+       * compute zoom rectangle in user units
+       */
+      Range2D xr = new Range2D();
+      Range2D yr = new Range2D();
+      Rectangle zm = (Rectangle)event.getNewValue();
+      if(zm.width <= 1 || zm.height <= 1) return;
+      xr.start = graph_.getXPtoU(layer_.getXDtoP(zm.x));
+      xr.end = graph_.getXPtoU(layer_.getXDtoP(zm.x + zm.width));
+      if(xr.start > xr.end) {
+        double temp = xr.start;
+        xr.start = xr.end;
+        xr.end = temp;
+      }
+      yr.start = graph_.getYPtoU(layer_.getYDtoP(zm.y));
+      yr.end = graph_.getYPtoU(layer_.getYDtoP(zm.y + zm.height));
+      if(yr.start > yr.end) {
+        double temp = yr.start;
+        yr.start = yr.end;
+        yr.end = temp;
+      }
+      mainPane_.setBatch(true);
+      /*
+       * set range for transforms
+       */
+      xt_.setRangeU(xr);
+      yt_.setRangeU(yr);
+      /*
+       * set range and origin for axes
+       */
+      Point2D.Double orig = new Point2D.Double(xr.start, yr.start);
+      xbot_.setRangeU(xr);
+      xbot_.setLocationU(orig);
+
+      yleft_.setRangeU(yr);
+      yleft_.setLocationU(orig);
+      /*
+       * set clipping on all graphs
+       */
+      Component[] comps = mainPane_.getComponents();
+      Layer ly;
+      for(int i=0; i < comps.length; i++) {
+        if(comps[i] instanceof Layer) {
+          ly = (Layer)comps[i];
+          ((CartesianGraph)ly.getGraph()).setClip(xr.start, xr.end,
+                                                  yr.start, yr.end);
+        }
+      }
+      mainPane_.setBatch(false);
+    } else if(name.equals("objectSelected")) {
+      /*
+       * An sgt object has been selected.
+       * If it is a PointCartesianRenderer that means the key has been
+       * selected and so open a dialog to modified the PointAttribute.
+       */
+      if(event.getNewValue() instanceof PointCartesianRenderer) {
+        PointAttribute pattr =
+          ((PointCartesianRenderer)event.getNewValue()).getPointAttribute();
+        if(pAttrDialog_ == null) {
+          pAttrDialog_ = new PointAttributeDialog();
+        }
+        pAttrDialog_.setPointAttribute(pattr, mainPane_);
+        pAttrDialog_.setVisible(true);
+      } else {
+        /*
+         * Print the name of the object selected.
+         */
+        System.out.println("objectSelected = " + event.getNewValue());
+      }
+    }
+  }
+
+  void reset_actionPerformed(ActionEvent e) {
+    mainPane_.setBatch(true);
+    Layer ly;
+    /*
+     * clear clipping on all graphs but coast line.
+     */
+    Component[] comps = mainPane_.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ly = (Layer)comps[i];
+        if(ly.getId().equals("CoastLine")) {
+          ((CartesianGraph)ly.getGraph()).setClip(xrange_.start,
+                                                  xrange_.end,
+                                                  yrange_.start,
+                                                  yrange_.end);
+        } else {
+          ((CartesianGraph)ly.getGraph()).setClipping(false);
+        }
+      }
+    }
+    /*
+     * reset range for transform
+     */
+    xt_.setRangeU(xrange_);
+    yt_.setRangeU(yrange_);
+    /*
+     * reset range for axes and origin
+     */
+    Point2D.Double orig = new Point2D.Double(xrange_.start,
+                                             yrange_.start);
+    xbot_.setRangeU(xrange_);
+    xbot_.setLocationU(orig);
+    yleft_.setRangeU(yrange_);
+    yleft_.setLocationU(orig);
+
+    mainPane_.setBatch(false);
+  }
+
+  class GeoFormat extends ValueIconFormat {
+    /*
+     * Create a specialized format for ValueIcon so that it handles
+     * longitude wrapping properly and hemisphere labelling.
+     */
+    public GeoFormat() {
+      super("#####.##;#####.##W", "#####.##N;#####.##S");
+      xfrm_.setPositiveSuffix("E");
+    }
+    public String format(double x, double y) {
+      double xt = (x + 360.0) % 360.0;
+      if(x > 180.0) x = x - 360.0;
+      return "(" + xfrm_.format(x) + ", " + yfrm_.format(y) + ")";
+    }
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TRITON.dat b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TRITON.dat
new file mode 100755
index 0000000..63e856e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TRITON.dat
@@ -0,0 +1,13 @@
+0;156;0N 156E
+2;156;2N 156E
+5;156;5N 156E
+8;156;8N 156E
+-2;156;2S 156E
+-5;156;5S 156E
+0;147;0N 147E
+2;147;2N 147E
+5;147;5N 147E
+0;137;0N 137E
+2;137;2N 137E
+5;137;5N 137E
+7;137;7N 137E
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TestData.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TestData.java
new file mode 100755
index 0000000..ec64ad8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/TestData.java
@@ -0,0 +1,586 @@
+/*
+ * $Id: TestData.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.demo;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.GeoDateArray;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTPoint;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SGTMetaData;
+import gov.noaa.pmel.sgt.dm.SimplePoint;
+import gov.noaa.pmel.sgt.dm.SimpleLine;
+import gov.noaa.pmel.sgt.dm.SimpleGrid;
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.SGLabel;
+
+/**
+ * Create <code>SGTData</code> objects containing test data.
+ * These objects can be used for
+ * graphics and analysis testing purposes.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:03 $
+ * @since 1.0
+ */
+public class TestData {
+  /**
+   * create profile data
+   **/
+  public final static int PROFILE = 1;
+  /**
+   * create longitude track data
+   **/
+  public final static int X_SERIES = 2;
+  /**
+   * create latitude track data
+   **/
+  public final static int Y_SERIES = 3;
+  /**
+   * create time series data
+   **/
+  public final static int TIME_SERIES = 4;
+  /**
+   * create X-Y grid
+   */
+  public final static int XY_GRID = 5;
+  /**
+   * create X-Y grid
+   */
+  public final static int XZ_GRID = 6;
+  /**
+   * create X-Y grid
+   */
+  public final static int YZ_GRID = 7;
+  /**
+   * create Z-T grid
+   */
+  public final static int ZT_GRID = 10;
+  /**
+   * create log-log line
+   */
+  public final static int LOG_LOG = 11;
+  /**
+   * create sine wave
+   **/
+  public final static int SINE = 1;
+  /**
+   * create random data
+   **/
+  public final static int RANDOM = 2;
+  /**
+   * create sine wave with a ramp
+   */
+  public final static int SINE_RAMP = 3;
+  //
+  private int dataType_;
+  private SGTData data_;
+  private Collection coll_;
+  /**
+   * Create default test data. Will create profile (z) data with sine shape.
+   **/
+  public TestData() {
+    this(PROFILE, new Range2D(0.0f, 100.0f, 10.0f), SINE, 1.0f, 0.0f, 25.0f);
+  }
+  /**
+   * Create one-dimensional spatial test data.
+   *
+   * @param dir direction of test data, TestData.X_SERIES,
+   * TestData.Y_SERIES, TestData.PROFILE, TestData.LOG_LOG
+   * @param range minimum and maximum overwhich to create
+   * @param type type of series, TestData.SINE or TestData.RANDOM
+   * @param amp amplitude
+   * @param off offset
+   * @param per period
+   * @see #PROFILE
+   * @see #X_SERIES
+   * @see #Y_SERIES
+   * @see #LOG_LOG
+   * @see #SINE
+   * @see #RANDOM
+   **/
+  public TestData(int dir, Range2D range,
+                  int type, float amp, float off, float per) {
+    SimpleLine sl;
+    SGTMetaData xMeta;
+    SGTMetaData yMeta;
+
+    double[] axis;
+    double[] values;
+    double[] zero;
+    GeoDate tzero[] = new GeoDate[1];
+    int count;
+
+    zero = new double[1];
+    tzero[0] = new GeoDate();
+    zero[0] = 0;
+    tzero[0].now();
+    if(dir != LOG_LOG) {
+      int num = (int)((range.end - range.start)/range.delta) + 1;
+      axis = new double[num];
+
+      for(count=0; count < num; count++) {
+        axis[count] = range.start + count*range.delta;
+      }
+
+      values = getValues(axis, num, type, amp, off, per);
+    } else {
+      double log10 = Math.log(10.0);
+      double end10 = Math.log(range.end)/log10;
+      double start10 = Math.log(range.start)/log10;
+      double delta10 = Math.log(range.delta)/log10;
+      float amp10 = (float)(Math.log(amp)/log10);
+      float off10 = (float)(Math.log(off)/log10);
+      float per10 = (float)(Math.log(per)/log10);
+      int num = (int)((end10 - start10)/delta10) + 1;
+      axis = new double[num];
+
+      for(count=0; count < num; count++) {
+        axis[count] = start10 + count*delta10;
+      }
+
+      // create values in log space
+      values = getValues(axis, num, type, amp10, off10, per10);
+
+      // convert back ...
+      for(count=0; count < num; count++) {
+        axis[count] = Math.pow(10.0, axis[count]);
+        values[count] = Math.pow(10.0, values[count]);
+      }
+    }
+    SGLabel keyLabel = new SGLabel("Key Label", "", new Point2D.Double(0.0, 0.0));
+    keyLabel.setHeightP(0.16);
+    //
+    // create SimpleLine object
+    //
+    switch(dir) {
+    case X_SERIES:
+      keyLabel.setText("X series ts data");
+      xMeta = new SGTMetaData("lon", "degE");
+      yMeta = new SGTMetaData("ts", "m s-1");
+      sl = new SimpleLine(axis, values, "Test Series");
+      break;
+    case Y_SERIES:
+      keyLabel.setText("Y series ts data");
+      xMeta = new SGTMetaData("lat", "deg");
+      yMeta = new SGTMetaData("ts", "m s-1");
+      sl = new SimpleLine(axis, values, "Test Series");
+      break;
+    default:
+    case PROFILE:
+      keyLabel.setText("Profile ts data");
+      xMeta = new SGTMetaData("ts", "m s-1");
+      yMeta = new SGTMetaData("depth", "m");
+      sl = new SimpleLine(values, axis, "Test Series");
+      break;
+    case LOG_LOG:
+      keyLabel.setText("Log/Log diameters");
+      xMeta = new SGTMetaData("diameter", "m");
+      yMeta = new SGTMetaData("count", "");
+      sl = new SimpleLine(axis, values, "Test Log-Log Series");
+    }
+    sl.setXMetaData(xMeta);
+    sl.setYMetaData(yMeta);
+    sl.setKeyTitle(keyLabel);
+    data_ = sl;
+  }
+  /**
+   * Create two-dimensional spatial test data.
+   *
+   * @param dir direction of test data, TestData.XY_GRID, TestData.XZ_GRID, TestData.YZ_GRID
+   * @param range1 minimum and maximum overwhich to create for first axis
+   * @param range2 minimum and maximum overwhich to create for second axis
+   * @param type type of series, TestData.SINE or TestData.RANDOM
+   * @param amp amplitude
+   * @param off offset
+   * @param per period
+   * @see #PROFILE
+   * @see #X_SERIES
+   * @see #Y_SERIES
+   * @see #SINE
+   * @see #RANDOM
+   **/
+  public TestData(int dir, Range2D range1, Range2D range2,
+                  int type, float amp, float off, float per) {
+    SimpleGrid sg;
+    SGTMetaData xMeta;
+    SGTMetaData yMeta;
+    SGTMetaData zMeta;
+
+    double[] axis1, axis2;
+    double[] values;
+    double[] zero;
+    GeoDate tzero[] = new GeoDate[1];
+    int count;
+
+    zero = new double[1];
+    tzero[0] = new GeoDate();
+    zero[0] = 0;
+    tzero[0].now();
+    int num1 = (int)((range1.end - range1.start)/range1.delta) + 1;
+    axis1 = new double[num1];
+    int num2 = (int)((range2.end - range2.start)/range2.delta) + 1;
+    axis2 = new double[num2];
+
+    for(count=0; count < num1; count++) {
+      axis1[count] = range1.start + count*range1.delta;
+    }
+    for(count=0; count < num2; count++) {
+      axis2[count] = range2.start + count*range2.delta;
+    }
+
+    values = getValues(axis1, num1, axis2, num2, type, amp, off, per);
+
+    SGLabel keyLabel = new SGLabel("Key Label", "", new Point2D.Double(0.0, 0.0));
+    keyLabel.setHeightP(0.16);
+    //
+    // create SimpleGrid
+    //
+    zMeta = new SGTMetaData("ts", "m s-1");
+    switch(dir) {
+    case XY_GRID:
+      keyLabel.setText("XY test grid");
+      xMeta = new SGTMetaData("lon", "degE");
+      yMeta = new SGTMetaData("lat", "deg");
+      sg = new SimpleGrid(values, axis1, axis2, "Test Series");
+      break;
+    case XZ_GRID:
+      keyLabel.setText("XZ test grid");
+      xMeta = new SGTMetaData("lon", "degE");
+      yMeta = new SGTMetaData("depth", "m");
+      sg = new SimpleGrid(values, axis1, axis2, "Test Series");
+      break;
+    default:
+    case YZ_GRID:
+      keyLabel.setText("YZ test grid");
+      xMeta = new SGTMetaData("lat", "deg");
+      yMeta = new SGTMetaData("depth", "m");
+      sg = new SimpleGrid(values, axis1, axis2, "Test Series");
+    }
+    sg.setXMetaData(xMeta);
+    sg.setYMetaData(yMeta);
+    sg.setZMetaData(zMeta);
+    sg.setKeyTitle(keyLabel);
+    data_ = sg;
+  }
+  /**
+   * Create time series test data.
+   *
+   * @param dir direction of test data, TestData.TIME_SERIES
+   * @param range minimum and maximum overwhich to create
+   * @param delta space between points in days
+   * @param type type of series, TestData.SINE or TestData.RANDOM
+   * @param amp amplitude
+   * @param off offset
+   * @param per period
+   * @see #PROFILE
+   * @see #X_SERIES
+   * @see #Y_SERIES
+   * @see #SINE
+   * @see #RANDOM
+   **/
+  public TestData(int dir, TimeRange range, float delta,
+                  int type, float amp, float off, float per) {
+    SimpleLine sl;
+    SGTMetaData xMeta;
+    SGTMetaData yMeta;
+
+    GeoDateArray taxis;
+    long[] tvalues;
+    double[] values;
+    double[] zero;
+    double totalTime;
+    int count, num;
+
+    zero = new double[1];
+    zero[0] = 0;
+
+    totalTime = range.end.offset(range.start);
+    num = (int)(totalTime/(double)delta) + 1;
+
+    tvalues = new long[num];
+    long ref = range.start.getTime();
+    long ldelta = ((long)delta)*86400000;
+//    taxis = new GeoDate[num];
+    for(count=0; count < num; count++) {
+      tvalues[count] = ref + count*ldelta;
+//      taxis[count] = new GeoDate(range.start);
+//      taxis[count].increment(delta*count, GeoDate.DAYS);
+    }
+    taxis = new GeoDateArray(tvalues);
+    values = getValues(taxis, num, type, amp, off, per);
+
+    SGLabel keyLabel = new SGLabel("Key Label", "", new Point2D.Double(0.0, 0.0));
+    keyLabel.setHeightP(0.16);
+    //
+    // create SimpleLine
+    //
+    keyLabel.setText("Time series ts");
+    xMeta = new SGTMetaData("time", "");
+    yMeta = new SGTMetaData("ts", "m s-1");
+    sl = new SimpleLine(taxis, values, "Test Series");
+    sl.setXMetaData(xMeta);
+    sl.setYMetaData(yMeta);
+    sl.setKeyTitle(keyLabel);
+    data_ = sl;
+  }
+  /**
+   * Create time series test grid data.
+   *
+   * @param dir direction of test data, TestData.ZT_SERIES
+   * @param range minimum and maximum for space axis
+   * @param trange minimum and maximum overwhich to create
+   * @param delta space between points in days
+   * @param type type of series, TestData.SINE or TestData.RANDOM
+   * @param amp amplitude
+   * @param off offset
+   * @param per period
+   * @see #PROFILE
+   * @see #X_SERIES
+   * @see #Y_SERIES
+   * @see #SINE
+   * @see #RANDOM
+   **/
+  public TestData(int dir, Range2D range,
+                  TimeRange trange, float delta,
+                  int type, float amp, float off, float per) {
+    SimpleGrid sg;
+    SGTMetaData xMeta;
+    SGTMetaData yMeta;
+    SGTMetaData zMeta;
+
+    GeoDate[] taxis;
+    double[] values, axis;
+    double[] zero;
+    double totalTime;
+    int count, tnum, snum;
+
+    zero = new double[1];
+    zero[0] = 0;
+
+    totalTime = trange.end.offset(trange.start);
+    tnum = (int)(totalTime/(double)delta) + 1;
+
+    taxis = new GeoDate[tnum];
+    for(count=0; count < tnum; count++) {
+      taxis[count] = new GeoDate(trange.start);
+      taxis[count].increment(delta*count, GeoDate.DAYS);
+    }
+
+    snum = (int)((range.end - range.start)/range.delta) + 1;
+    axis = new double[snum];
+
+    for(count=0; count < snum; count++) {
+      axis[count] = range.start + count*range.delta;
+    }
+
+    values = getValues(axis, snum, taxis, tnum, type, amp, off, per);
+    SGLabel keyLabel = new SGLabel("Key Label", "", new Point2D.Double(0.0, 0.0));
+    keyLabel.setHeightP(0.16);
+    //
+    // create SimpleGrid
+    //
+    keyLabel.setText("time-depth grid");
+    xMeta = new SGTMetaData("time", "");
+    yMeta = new SGTMetaData("depth", "m");
+    zMeta = new SGTMetaData("ts", "m s-1");
+    sg = new SimpleGrid(values, taxis, axis, "Test Series");
+    sg.setXMetaData(xMeta);
+    sg.setYMetaData(yMeta);
+    sg.setZMetaData(zMeta);
+    sg.setKeyTitle(keyLabel);
+    data_ = sg;
+  }
+  /**
+   * Create a Collection of points.
+   *
+   * @param xrnge range of values in x
+   * @param yrnge range of values in y
+   * @param num number of values to create
+   */
+  public TestData(Range2D xrnge, Range2D yrnge, int num) {
+    SimplePoint sp;
+    double xamp, yamp, xoff, yoff;
+    double xp, yp;
+    String title;
+    coll_ = new Collection("Test Points", num);
+    xamp = xrnge.end - xrnge.start;
+    xoff = xrnge.start;
+    yamp = yrnge.end - yrnge.start;
+    yoff = yrnge.start;
+    for(int i=0; i < num; i++) {
+      xp = xamp*Math.random() + xoff;
+      yp = yamp*Math.random() + yoff;
+      title = "point"+i;
+      sp = new SimplePoint(xp, yp, title);
+      coll_.addElement((Object)sp);
+    }
+  }
+
+  /**
+   * Get the Collection of points created with the point constructor.
+   *
+   * @return Collection of points
+   */
+  public Collection getCollection() {
+    return coll_;
+  }
+
+  /**
+   * Get a SGTGrid or SGTLine object depending on type of constructor
+   * used.
+   *
+   * @return SGTData object.
+   */
+  public SGTData getSGTData() {
+    return data_;
+  }
+  private double[] getValues(double[] axis, int num, int type,
+                             float amp, float off, float per) {
+    double[] values;
+    int count;
+    values = new double[num];
+    switch(type) {
+    default:
+    case TestData.RANDOM:
+      for(count=0; count < num; count++) {
+        values[count] = amp*Math.random()+off;
+      }
+      break;
+    case TestData.SINE:
+      for(count=0; count < num; count++) {
+        values[count] = amp*Math.sin(axis[count]/per) + off;
+      }
+    }
+    return values;
+  }
+
+  private double[] getValues(double[] axis1, int num1, double[] axis2, int num2,
+                             int type, float amp, float off, float per) {
+    double[] values;
+    int count1, count2, count;
+    values = new double[num1*num2];
+    switch(type) {
+    default:
+    case TestData.RANDOM:
+      for(count=0; count < num1*num2; count++) {
+        values[count] = amp*Math.random()+off;
+      }
+      break;
+    case TestData.SINE:
+      count=0;
+      for(count1=0; count1 < num1; count1++) {
+        for(count2=0; count2 < num2; count2++) {
+          values[count] = amp*Math.sin(axis1[count1]/per)*
+            Math.sin(axis2[count2]/per) + off;
+          count++;
+        }
+      }
+      break;
+    case TestData.SINE_RAMP:
+      count=0;
+      double ax1factr = 0.08*Math.abs(axis1[0]-axis1[num1-1])/
+  Math.max(Math.abs(axis1[0]),Math.abs(axis1[num1-1]));
+      double ax2factr = 0.08*Math.abs(axis2[0]-axis2[num2-1])/
+  Math.max(Math.abs(axis2[0]),Math.abs(axis2[num2-1]));
+      for(count1=0; count1 < num1; count1++) {
+        for(count2=0; count2 < num2; count2++) {
+          values[count] = amp*Math.sin(axis1[count1]/per)*
+            Math.sin(axis2[count2]/per) + off +
+      amp*(ax1factr*count1 - ax2factr*count2);
+          count++;
+        }
+      }
+
+    }
+    return values;
+  }
+
+  private double[] getValues(GeoDate[] axis, int num, int type,
+                             float amp, float off, float per) {
+    double[] values;
+    double theta;
+    int count;
+    values = new double[num];
+    switch(type) {
+    default:
+    case TestData.RANDOM:
+      for(count=0; count < num; count++) {
+        values[count] = amp*Math.random() + off;
+      }
+      break;
+    case TestData.SINE:
+      for(count=0; count < num; count++) {
+        theta = axis[count].offset(axis[0])/per;
+        values[count] = amp*Math.sin(theta) + off;
+      }
+    }
+    return values;
+  }
+
+  private double[] getValues(GeoDateArray axis, int num, int type,
+                             float amp, float off, float per) {
+    double[] values;
+    double theta;
+    float lper = per*86400000;
+    long[] tvalues = axis.getTime();
+    int count;
+    values = new double[num];
+    switch(type) {
+    default:
+    case TestData.RANDOM:
+      for(count=0; count < num; count++) {
+        values[count] = amp*Math.random() + off;
+      }
+      break;
+    case TestData.SINE:
+      for(count=0; count < num; count++) {
+        theta = (tvalues[count] - tvalues[0])/lper;
+ //       theta = axis[count].offset(axis[0])/per;
+        values[count] = amp*Math.sin(theta) + off;
+      }
+    }
+    return values;
+  }
+
+  private double[] getValues(double[] axis, int snum, GeoDate[] taxis, int tnum,
+                             int type, float amp, float off, float per) {
+    double[] values;
+    double theta;
+    int tcount, scount, count;
+    values = new double[tnum*snum];
+    switch(type) {
+    default:
+    case TestData.RANDOM:
+      for(count=0; count < tnum*snum; count++) {
+        values[count] = amp*Math.random() + off;
+      }
+      break;
+    case TestData.SINE:
+      count=0;
+      for(tcount=0; tcount < tnum; tcount++) {
+        theta = taxis[tcount].offset(taxis[0])/per;
+        for(scount=0; scount < snum; scount++) {
+          values[count] = amp*Math.sin(theta)*Math.sin(axis[scount]/per) + off;
+          count++;
+        }
+      }
+    }
+    return values;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/coarserezcoast.bin b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/coarserezcoast.bin
new file mode 100755
index 0000000..0af3323
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/coarserezcoast.bin differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/finerezcoast.bin b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/finerezcoast.bin
new file mode 100755
index 0000000..c9491a5
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/finerezcoast.bin differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/ncBrowse48.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/ncBrowse48.gif
new file mode 100755
index 0000000..35b8d68
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/ncBrowse48.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/ncBrowse96.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/ncBrowse96.gif
new file mode 100755
index 0000000..a476dcd
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/ncBrowse96.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/package.html
new file mode 100755
index 0000000..eeec276
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/package.html
@@ -0,0 +1,17 @@
+<HTML>
+<BODY>
+<code>JApplets</code> and applications that demonstrate the use of
+</code>sgt</code>.  Some of these examples use the
+<code>gov.noaa.pmel.sgt.swing</code> and
+<code>gov.noaa.pmel.sgt.swing.prop</code> classes.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/query.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/query.gif
new file mode 100755
index 0000000..3f98ed1
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/demo/query.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Annotation.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Annotation.java
new file mode 100755
index 0000000..a21a8a7
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Annotation.java
@@ -0,0 +1,402 @@
+/*
+ * $Id: Annotation.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.SGException;
+
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTPoint;
+
+import java.util.List;
+import java.util.Vector;
+import java.util.Iterator;
+import java.awt.Color;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * A container to hold <code>Annote</code> objects.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+public class Annotation implements SGTData, PropertyChangeListener {
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private String title_ = null;
+  private String id_ = null;
+
+  /**
+   * @label x
+   * @link aggregation 
+   */
+  private SGTMetaData xMeta_ = null;
+
+  /**
+   * @link aggregation
+   * @label y 
+   */
+  private SGTMetaData yMeta_ = null;
+  private List text_ = new Vector();
+  private List line_ = new Vector();
+  private List point_ = new Vector();
+  private List oval_ = new Vector();
+  private List rect_ = new Vector();
+
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private boolean xTime_ = false;
+  private boolean yTime_ = false;
+
+  public Annotation() {
+    this(null, false, false);
+  }
+
+  public Annotation(String title) {
+    this(title, false, false);
+  }
+
+  public Annotation(String title, boolean xTime, boolean yTime) {
+    title_ = title;
+    xTime_ = xTime;
+    yTime_ = yTime;
+  }
+
+  public boolean remove(String id) {
+    Annote ann = findAnnote(id);
+    if(ann == null) return false;
+    return remove(ann);
+  }
+
+  public boolean remove(Annote ann) {
+    if(ann instanceof Annote.Line) {
+      return removeLine(ann);
+    } else if(ann instanceof Annote.Oval) {
+      return removeOval(ann);
+    } else if(ann instanceof Annote.Point) {
+      return removePoint(ann);
+    } else if(ann instanceof Annote.Rect) {
+      return removeRect(ann);
+    } else if(ann instanceof Annote.Text) {
+      return removeText(ann);
+    }
+    return false;
+  }
+
+  public void add(Annote ann) throws SGException {
+    if(ann instanceof Annote.Line) {
+      SGTLine line = ((Annote.Line)ann).getLine();
+      if(xTime_ != line.isXTime() || yTime_ != line.isYTime())
+        throw new SGException("Time axes do not match");
+      ann.addPropertyChangeListener(this);
+      line_.add(ann);
+      changes_.firePropertyChange("lineAdded", true, false);
+    } else if(ann instanceof Annote.Oval) {
+      SoTPoint pt1 = ((Annote.Oval)ann).getUpperLeft();
+      if(xTime_ != pt1.isXTime() || yTime_ != pt1.isYTime())
+        throw new SGException("Time axes do not match");
+      ann.addPropertyChangeListener(this);
+      oval_.add(ann);
+      changes_.firePropertyChange("ovalAdded", true, false);
+    } else if(ann instanceof Annote.Point) {
+      SGTPoint point = ((Annote.Point)ann).getPoint();
+      if(xTime_ != point.isXTime() || yTime_ != point.isYTime())
+        throw new SGException("Time axes do not match");
+      ann.addPropertyChangeListener(this);
+      point_.add(ann);
+      changes_.firePropertyChange("pointAdded", true, false);
+    } else if(ann instanceof Annote.Rect) {
+      SoTPoint pt1 = ((Annote.Rect)ann).getUpperLeft();
+      if(xTime_ != pt1.isXTime() || yTime_ != pt1.isYTime())
+        throw new SGException("Time axes do not match");
+      ann.addPropertyChangeListener(this);
+      rect_.add(ann);
+      changes_.firePropertyChange("rectAdded", true, false);
+    } else if(ann instanceof Annote.Text) {
+      SoTPoint loc = ((Annote.Text)ann).getLocation();
+      if(xTime_ != loc.isXTime() || yTime_ != loc.isYTime())
+        throw new SGException("Time axes do not match");
+      ann.addPropertyChangeListener(this);
+      text_.add(ann);
+      changes_.firePropertyChange("textAdded", true, false);
+    }
+  }
+
+  public Annote addLine(String id, SGTLine line, LineAttribute attr)
+                      throws SGException {
+    if(xTime_ != line.isXTime() || yTime_ != line.isYTime())
+      throw new SGException("Time axes do not match");
+    Annote.Line aLine = new Annote.Line(id, line, attr);
+    aLine.addPropertyChangeListener(this);
+    line_.add(aLine);
+
+    changes_.firePropertyChange("lineAdded", true, false);
+    return aLine;
+  }
+
+  private boolean removeLine(Annote line) {
+    boolean result = false;
+    if(line instanceof Annote.Line) {
+      line.removePropertyChangeListener(this);
+      result = line_.remove(line);
+      if(result) changes_.firePropertyChange("lineRemoved", true, false);
+    }
+    return result;
+  }
+
+  public Iterator getLineIterator() {
+    return line_.iterator();
+  }
+
+  public boolean hasLine() {
+    return !line_.isEmpty();
+  }
+
+  public Annote addPoint(String id, SGTPoint point, PointAttribute attr)
+                       throws SGException {
+    if(xTime_ != point.isXTime() || yTime_ != point.isYTime())
+      throw new SGException("Time axes do not match");
+    Annote.Point aPoint = new Annote.Point(id, point, attr);
+    aPoint.addPropertyChangeListener(this);
+    point_.add(aPoint);
+
+    changes_.firePropertyChange("pointAdded", true, false);
+    return aPoint;
+  }
+
+  private boolean removePoint(Annote point) {
+    boolean result = false;
+    if(point instanceof Annote.Point) {
+      point.removePropertyChangeListener(this);
+      result = point_.remove(point);
+      if(result) changes_.firePropertyChange("pointRemoved", true, false);
+    }
+    return result;
+  }
+
+  public Iterator getPointIterator() {
+    return point_.iterator();
+  }
+
+  public boolean hasPoint() {
+    return !point_.isEmpty();
+  }
+
+  public Annote addText(String id, SoTPoint loc, SGLabel text)
+                      throws SGException {
+    if(xTime_ != loc.isXTime() || yTime_ != loc.isYTime())
+      throw new SGException("Time axes do not match");
+    Annote.Text aText = new Annote.Text(id, loc, text);
+    aText.addPropertyChangeListener(this);
+    text_.add(aText);
+
+    changes_.firePropertyChange("textAdded", true, false);
+    return aText;
+  }
+
+  private boolean removeText(Annote text) {
+    boolean result = false;
+    if(text instanceof Annote.Text) {
+      text.removePropertyChangeListener(this);
+      result = text_.remove(text);
+      if(result) changes_.firePropertyChange("textRemoved", true, false);
+    }
+    return result;
+  }
+
+  public Iterator getTextIterator() {
+    return text_.iterator();
+  }
+
+  public boolean hasText() {
+    return !text_.isEmpty();
+  }
+/**
+ * Add an oval to the <code>Annotation</code>. If attr is non-null an oval
+ * outline will be drawn, if color is non-null it will be filled.
+ */
+  public Annote addOval(String id, SoTPoint pt1, SoTPoint pt2,
+                      LineAttribute attr, Color color) throws SGException {
+    if(xTime_ != pt1.isXTime() || yTime_ != pt1.isYTime())
+      throw new SGException("Time axes do not match");
+    Annote.Oval aOval = new Annote.Oval(id, pt1, pt2, attr, color);
+    aOval.addPropertyChangeListener(this);
+    oval_.add(aOval);
+
+    changes_.firePropertyChange("ovalAdded", true, false);
+    return aOval;
+  }
+
+  private boolean removeOval(Annote oval) {
+    boolean result = false;
+    if(oval instanceof Annote.Oval) {
+      oval.removePropertyChangeListener(this);
+      result = oval_.remove(oval);
+      if(result) changes_.firePropertyChange("ovalRemoved", true, false);
+    }
+    return result;
+  }
+
+  public Iterator getOvalIterator() {
+    return oval_.iterator();
+  }
+
+  public boolean hasOval() {
+    return !oval_.isEmpty();
+  }
+/**
+ * Add an rectangle to the <code>Annotation</code>. If attr is non-null an rectangle
+ * outline will be drawn, if color is non-null it will be filled.
+ */
+  public Annote addRect(String id, SoTPoint pt1, SoTPoint pt2,
+                      LineAttribute attr, Color color) throws SGException {
+    if(xTime_ != pt1.isXTime() || yTime_ != pt1.isYTime())
+      throw new SGException("Time axes do not match");
+    Annote.Rect aRect = new Annote.Rect(id, pt1, pt2, attr, color);
+    aRect.addPropertyChangeListener(this);
+    rect_.add(aRect);
+
+    changes_.firePropertyChange("rectAdded", true, false);
+    return aRect;
+  }
+
+  private boolean removeRect(Annote rect) {
+    boolean result = false;
+    if(rect instanceof Annote.Rect) {
+    rect.removePropertyChangeListener(this);
+      result = rect_.remove(rect);
+      if(result) changes_.firePropertyChange("rectRemoved", true, false);
+    }
+    return result;
+  }
+
+  public Iterator getRectIterator() {
+    return rect_.iterator();
+  }
+
+  public boolean hasRect() {
+    return !rect_.isEmpty();
+  }
+
+  public Annote findAnnote(String id) {
+    Annote tmp = null;
+    Iterator iter;
+    if(!line_.isEmpty()) {
+      iter = line_.iterator();
+      while(iter.hasNext()) {
+        tmp = (Annote)iter.next();
+        if(tmp.getAnnoteId().equals(id)) return tmp;
+      }
+    }
+    if(!point_.isEmpty()) {
+      iter = point_.iterator();
+      while(iter.hasNext()) {
+        tmp = (Annote)iter.next();
+        if(tmp.getAnnoteId().equals(id)) return tmp;
+      }
+    }
+    if(!oval_.isEmpty()) {
+      iter = oval_.iterator();
+      while(iter.hasNext()) {
+        tmp = (Annote)iter.next();
+        if(tmp.getAnnoteId().equals(id)) return tmp;
+      }
+    }
+    if(!rect_.isEmpty()) {
+      iter = rect_.iterator();
+      while(iter.hasNext()) {
+        tmp = (Annote)iter.next();
+        if(tmp.getAnnoteId().equals(id)) return tmp;
+      }
+    }
+    if(!text_.isEmpty()) {
+      iter = text_.iterator();
+      while(iter.hasNext()) {
+        tmp = (Annote)iter.next();
+        if(tmp.getAnnoteId().equals(id)) return tmp;
+      }
+    }
+    return null;
+  }
+
+  public void setTitle(String title) {
+    title_ = title;
+  }
+
+  public String getTitle() {
+    return title_;
+  }
+
+  public SGLabel getKeyTitle() {
+    return null;
+  }
+
+  public void setId(String id) {
+    id_ = id;
+  }
+
+  public String getId() {
+    return id_;
+  }
+
+  public SGTData copy() {
+    /**@todo: Implement this gov.noaa.pmel.sgt.dm.SGTData method*/
+    throw new java.lang.UnsupportedOperationException("Method copy() not yet implemented.");
+  }
+
+  public boolean isXTime() {
+    return xTime_;
+  }
+
+  public boolean isYTime() {
+    return yTime_;
+  }
+
+  public void setXMetaData(SGTMetaData meta) {
+    xMeta_ = meta;
+  }
+
+  public SGTMetaData getXMetaData() {
+    return xMeta_;
+  }
+
+  public void setYMetaData(SGTMetaData meta) {
+    yMeta_ = meta;
+  }
+
+  public SGTMetaData getYMetaData() {
+    return yMeta_;
+  }
+
+  public SoTRange getXRange() {
+    return xRange_;
+  }
+
+  public SoTRange getYRange() {
+    return yRange_;
+  }
+
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+  public void propertyChange(PropertyChangeEvent evt) {
+    changes_.firePropertyChange(evt);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Annote.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Annote.java
new file mode 100755
index 0000000..ed13c9f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Annote.java
@@ -0,0 +1,708 @@
+/*
+ *  $Id: Annote.java,v 1.1.1.1 2007/09/07 06:32:03 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.SGLabel;
+
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTDomain;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+
+import java.io.Serializable;
+import java.awt.Color;
+import java.awt.Rectangle;
+
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+/**
+ * Abstract class for annotations.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+public abstract class Annote implements SGTData, Serializable, PropertyChangeListener {
+  protected transient PropertyChangeSupport changes_;
+  // serial version ref 1.7.2.5
+  private static final long serialVersionUID = 7305616377566581275L;
+  protected String id_ = null;
+
+/**
+ * Class for line annotations.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+  public static class Line extends Annote {
+    SGTLine line;
+    LineAttribute attr;
+
+    public Line(String id, SGTLine line, LineAttribute attr) {
+      id_ = id;
+      this.line = line;
+      this.attr = attr;
+      init();
+    }
+    public void init() {
+      if(attr != null) attr.addPropertyChangeListener(this);
+      changes_ = new PropertyChangeSupport(this);
+    }
+    public SGTLine getLine() {
+      return line;
+    }
+    public LineAttribute getAttribute() {
+      return attr;
+    }
+    public SoTDomain getDomain() {
+      return new SoTDomain(line.getXRange(), line.getYRange());
+    }
+    public Rectangle getBounds(Graph graph) {
+      return computeBounds(graph, this.getDomain());
+    }
+    public void moveBy(SoTPoint point) {
+      double[] xu = null;
+      double[] yu = null;
+      long[] tu = null;
+      double delta;
+      long tdelta;
+      if(!(line instanceof SimpleLine)) return;
+      if(line.isXTime()) {
+        tu = line.getGeoDateArray().getTime();
+        tdelta = point.getX().getLongTime();
+        for(int i=0; i < tu.length; i++) {
+          tu[i] += tdelta;
+        }
+        ((SimpleLine)line).setTimeArray(new GeoDateArray(tu));
+      } else {
+        xu = line.getXArray();
+        delta = ((Number)point.getX().getObjectValue()).doubleValue();
+        for(int i=0; i < xu.length; i++) {
+          xu[i] += delta;
+        }
+        ((SimpleLine)line).setXArray(xu);
+      }
+      if(line.isYTime()) {
+        tu = line.getGeoDateArray().getTime();
+        tdelta = point.getY().getLongTime();
+        for(int i=0; i < tu.length; i++) {
+          tu[i] += tdelta;
+        }
+        ((SimpleLine)line).setTimeArray(new GeoDateArray(tu));
+      } else {
+        yu = line.getYArray();
+        delta = ((Number)point.getY().getObjectValue()).doubleValue();
+        for(int i=0; i < yu.length; i++) {
+          yu[i] += delta;
+        }
+        ((SimpleLine)line).setYArray(yu);
+      }
+      changes_.firePropertyChange("lineMoved", true, false);
+    }
+    public void setXArray(double[] xa) {
+    }
+    public void setYArray(double[] ya) {
+    }
+    public void setTimeArray(GeoDateArray gda) {
+    }
+    public void propertyChange(PropertyChangeEvent evt) {
+      changes_.firePropertyChange(evt);
+    }
+    /* SGTData required methods */
+    public SGTData copy() {
+      SGTData copy = null;
+      try {
+        copy = (SGTData)this.clone();
+      } catch (CloneNotSupportedException ex) {
+        ex.printStackTrace();
+      }
+      return copy;
+    }
+    public String getId() {
+      return line.getId();
+    }
+    public SGLabel getKeyTitle() {
+      return line.getKeyTitle();
+    }
+    public String getTitle() {
+      return line.getTitle();
+    }
+    public SGTMetaData getXMetaData() {
+      return line.getXMetaData();
+    }
+    public SoTRange getXRange() {
+      return line.getXRange();
+    }
+    public SGTMetaData getYMetaData() {
+      return line.getYMetaData();
+    }
+    public SoTRange getYRange() {
+      return line.getYRange();
+    }
+    public boolean isXTime() {
+      return line.isXTime();
+    }
+    public boolean isYTime() {
+      return line.isYTime();
+    }
+  }
+
+/**
+ * Class for point annotations.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+  public static class Point extends Annote {
+    SGTPoint point;
+    PointAttribute attr;
+
+    public Point(String id, SGTPoint point, PointAttribute attr) {
+      id_ = id;
+      this.point = point;
+      this.attr = attr;
+      init();
+    }
+    public void init() {
+      if(attr != null) attr.addPropertyChangeListener(this);
+      changes_ = new PropertyChangeSupport(this);
+    }
+    public SGTPoint getPoint() {
+      return point;
+    }
+    public PointAttribute getAttribute() {
+      return attr;
+    }
+
+    public SoTDomain getDomain() {
+      return new SoTDomain(point.getXRange(), point.getYRange());
+    }
+
+    public Rectangle getBounds(Graph graph) {
+      /** @todo add text bounds */
+      Rectangle rect = computeBounds(graph, this.getDomain());
+      double hgt = attr.getMarkHeightP();
+      int ihgt = graph.getLayer().getXPtoD(hgt);
+      rect.setBounds(rect.x-ihgt/2,
+                     rect.y-ihgt/2,
+                     ihgt, ihgt);
+      return rect;
+    }
+
+    public void moveBy(SoTPoint pnt) {
+      double xu = 0.0;
+      double yu = 0.0;
+      long tu = 0;
+      double delta;
+      long tdelta;
+      if(!(point instanceof SimplePoint)) return;
+      if(point.isXTime()) {
+        tu = point.getLongTime();
+        tdelta = pnt.getX().getLongTime();
+        tu += tdelta;
+        ((SimplePoint)point).setTime(tu);
+      } else {
+        xu = point.getX();
+        delta = ((Number)pnt.getX().getObjectValue()).doubleValue();
+        xu += delta;
+        ((SimplePoint)point).setX(xu);
+      }
+      if(point.isYTime()) {
+        tu = point.getLongTime();
+        tdelta = pnt.getY().getLongTime();
+        tu += tdelta;
+        ((SimplePoint)point).setTime(tu);
+      } else {
+        yu = point.getY();
+        delta = ((Number)pnt.getY().getObjectValue()).doubleValue();
+        yu += delta;
+        ((SimplePoint)point).setY(yu);
+      }
+      changes_.firePropertyChange("pointMoved", true, false);
+    }
+    public void propertyChange(PropertyChangeEvent evt) {
+      changes_.firePropertyChange(evt);
+    }
+    /* SGTData required methods */
+    public SGTData copy() {
+      SGTData copy = null;
+      try {
+        copy = (SGTData)this.clone();
+      } catch (CloneNotSupportedException ex) {
+        ex.printStackTrace();
+      }
+      return copy;
+    }
+    public String getId() {
+      return point.getId();
+    }
+    public SGLabel getKeyTitle() {
+      return point.getKeyTitle();
+    }
+    public String getTitle() {
+      return point.getTitle();
+    }
+    public SGTMetaData getXMetaData() {
+      return point.getXMetaData();
+    }
+    public SoTRange getXRange() {
+      return point.getXRange();
+    }
+    public SGTMetaData getYMetaData() {
+      return point.getYMetaData();
+    }
+    public SoTRange getYRange() {
+      return point.getYRange();
+    }
+    public boolean isXTime() {
+      return point.isXTime();
+    }
+    public boolean isYTime() {
+      return point.isYTime();
+    }
+  }
+
+/**
+ * Class for text annotations.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+  public static class Text extends Annote {
+    SoTPoint location;
+    SGLabel text;
+
+    public Text(String id, SoTPoint location, SGLabel text) {
+      id_ = id;
+      this.location = location;
+      this.text = text;
+      init();
+    }
+    public void init() {
+      if(text != null) text.addPropertyChangeListener(this);
+      changes_ = new PropertyChangeSupport(this);
+    }
+    public SoTPoint getLocation() {
+      return location;
+    }
+    public SGLabel getText() {
+      return text;
+    }
+    public SoTDomain getDomain() {
+
+      return null;
+    }
+    private SoTDomain getDomain(Graph graph) {
+      CartesianGraph cg = (CartesianGraph)graph;
+      SoTRange xRange = null;
+      SoTRange yRange = null;
+      Rectangle2D.Double bnds = text.getBoundsP();
+/** @todo rewrite to go directly to device units */
+      double xloc = cg.getXUtoP(location.getX());
+      double yloc = cg.getYUtoP(location.getY());
+      double width = bnds.width;
+      double height = bnds.height;
+      if(location.isXTime()) {
+        long min = cg.getXPtoLongTime(xloc);
+        long max = cg.getXPtoLongTime(xloc + width);
+        xRange = new SoTRange.Time(min, max);
+      } else {
+        double min = cg.getXPtoU(xloc);
+        double max = cg.getXPtoU(xloc + width);
+        xRange = new SoTRange.Double(min, max);
+      }
+      if(location.isYTime()) {
+        long min = cg.getYPtoLongTime(yloc);
+        long max = cg.getYPtoLongTime(yloc + height);
+        yRange = new SoTRange.Time(min, max);
+      } else {
+        double min = cg.getYPtoU(yloc);
+        double max = cg.getYPtoU(yloc + height);
+        yRange = new SoTRange.Double(min, max);
+      }
+      return new SoTDomain(xRange, yRange);
+    }
+    public Rectangle getBounds(Graph graph) {
+      return computeBounds(graph, this.getDomain(graph));
+    }
+    public void moveBy(SoTPoint point) {
+      location.add(point);
+      changes_.firePropertyChange("textMoved", true, false);
+    }
+    public void propertyChange(PropertyChangeEvent evt) {
+      changes_.firePropertyChange(evt);
+    }
+    /* SGTData required methods */
+    public SGTData copy() {
+      SGTData copy = null;
+      try {
+        copy = (SGTData)this.clone();
+      } catch (CloneNotSupportedException ex) {
+        ex.printStackTrace();
+      }
+      return copy;
+    }
+    public String getId() {
+      return text.getId();
+    }
+    public SGLabel getKeyTitle() {
+      return null;
+    }
+    public String getTitle() {
+      return null;
+    }
+    public SGTMetaData getXMetaData() {
+      return null;
+    }
+    public SoTRange getXRange() {
+      return null;
+    }
+    public SGTMetaData getYMetaData() {
+      return null;
+    }
+    public SoTRange getYRange() {
+      return null;
+    }
+    public boolean isXTime() {
+      return location.isXTime();
+    }
+    public boolean isYTime() {
+      return location.isYTime();
+    }
+  }
+
+/**
+ * Class for oval annotations.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+  public static class Oval extends Annote {
+    SoTPoint upperLeft;
+    SoTPoint lowerRight;
+    LineAttribute attr;
+    Color color;
+    SoTRange xRange_ = null;
+    SoTRange yRange_ = null;
+
+    public Oval(String id, SoTPoint upperLeft, SoTPoint lowerRight,
+                LineAttribute attr, Color color) {
+      id_ = id;
+      this.upperLeft = upperLeft;
+      this.lowerRight = lowerRight;
+      this.attr = attr;
+      this.color = color;
+      init();
+      computeRange();
+    }
+    public void init() {
+      if(attr != null) attr.addPropertyChangeListener(this);
+      changes_ = new PropertyChangeSupport(this);
+    }
+    public SoTPoint getUpperLeft() {
+      return upperLeft;
+    }
+    public void setUpperLeft(SoTPoint ul) {
+      upperLeft = ul;
+      computeRange();
+      changes_.firePropertyChange("ovalMoved", true, false);
+    }
+    public SoTPoint getLowerRight() {
+      return lowerRight;
+    }
+    public void setLowerRight(SoTPoint lr) {
+      lowerRight = lr;
+      computeRange();
+      changes_.firePropertyChange("ovalMoved", true, false);
+    }
+    public void setLocation(SoTPoint ul, SoTPoint lr) {
+      upperLeft = ul;
+      lowerRight = lr;
+      computeRange();
+      changes_.firePropertyChange("ovalMoved", true, false);
+    }
+    public LineAttribute getLineAttribute() {
+      return attr;
+    }
+    public Color getFillColor() {
+      return color;
+    }
+    public void setFillColor(Color color) {
+      this.color = color;
+      changes_.firePropertyChange("colorChanged", true, false);
+    }
+    public SoTDomain getDomain() {
+      return new SoTDomain(xRange_, yRange_);
+    }
+    public Rectangle getBounds(Graph graph) {
+      return computeBounds(graph, this.getDomain());
+    }
+    public void moveBy(SoTPoint point) {
+      upperLeft.add(point);
+      lowerRight.add(point);
+      computeRange();
+      changes_.firePropertyChange("ovalMoved", true, false);
+    }
+    private void computeRange() {
+      if(upperLeft.getX().isTime()) {
+        xRange_ = new SoTRange.Time(upperLeft.getX().getLongTime(),
+                                    lowerRight.getX().getLongTime());
+      } else {
+        double xmin = ((Number)upperLeft.getX().getObjectValue()).doubleValue();
+        double xmax = ((Number)lowerRight.getX().getObjectValue()).doubleValue();
+        xRange_ = new SoTRange.Double(xmin, xmax);
+      }
+      if(upperLeft.getY().isTime()) {
+        yRange_ = new SoTRange.Time(lowerRight.getY().getLongTime(),
+                                    upperLeft.getY().getLongTime());
+      } else {
+        double ymin = ((Number)lowerRight.getY().getObjectValue()).doubleValue();
+        double ymax = ((Number)upperLeft.getY().getObjectValue()).doubleValue();
+        yRange_ = new SoTRange.Double(ymin, ymax);
+      }
+    }
+    public void propertyChange(PropertyChangeEvent evt) {
+      changes_.firePropertyChange(evt);
+    }
+    /* SGTData required methods */
+    public SGTData copy() {
+      SGTData copy = null;
+      try {
+        copy = (SGTData)this.clone();
+      } catch (CloneNotSupportedException ex) {
+        ex.printStackTrace();
+      }
+      return copy;
+    }
+    public String getId() {
+      return null;
+    }
+    public SGLabel getKeyTitle() {
+      return null;
+    }
+    public String getTitle() {
+      return null;
+    }
+    public SGTMetaData getXMetaData() {
+      return null;
+    }
+    public SoTRange getXRange() {
+      return xRange_;
+    }
+    public SGTMetaData getYMetaData() {
+      return null;
+    }
+    public SoTRange getYRange() {
+      return yRange_;
+    }
+    public boolean isXTime() {
+      return upperLeft.isXTime();
+    }
+    public boolean isYTime() {
+      return upperLeft.isYTime();
+    }
+  }
+
+/**
+ * Class for rectangle annotations.
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+  public static class Rect extends Annote {
+    SoTPoint upperLeft;
+    SoTPoint lowerRight;
+    LineAttribute attr;
+    Color color;
+    SoTRange xRange_ = null;
+    SoTRange yRange_ = null;
+
+    public Rect(String id, SoTPoint upperLeft, SoTPoint lowerRight,
+                LineAttribute attr, Color color) {
+      id_ = id;
+      this.upperLeft = upperLeft;
+      this.lowerRight = lowerRight;
+      this.attr = attr;
+      this.color = color;
+      init();
+      computeRange();
+    }
+    public void init() {
+      if(attr != null) attr.addPropertyChangeListener(this);
+      changes_ = new PropertyChangeSupport(this);
+    }
+    public SoTPoint getUpperLeft() {
+      return upperLeft;
+    }
+    public void setUpperLeft(SoTPoint ul) {
+      upperLeft = ul;
+      computeRange();
+      changes_.firePropertyChange("rectMoved", true, false);
+    }
+    public SoTPoint getLowerRight() {
+      return lowerRight;
+    }
+    public void setLowerRight(SoTPoint lr) {
+      lowerRight = lr;
+      computeRange();
+      changes_.firePropertyChange("rectMoved", true, false);
+    }
+    public void setLocation(SoTPoint ul, SoTPoint lr) {
+      upperLeft = ul;
+      lowerRight = lr;
+      computeRange();
+      changes_.firePropertyChange("rectMoved", true, false);
+    }
+    public LineAttribute getLineAttribute() {
+      return attr;
+    }
+    public Color getFillColor() {
+      return color;
+    }
+    public void setFillColor(Color color) {
+      this.color = color;
+      changes_.firePropertyChange("colorChanged", true, false);
+    }
+    public SoTDomain getDomain() {
+      return new SoTDomain(xRange_, yRange_);
+    }
+    public Rectangle getBounds(Graph graph) {
+      return computeBounds(graph, this.getDomain());
+    }
+    public void moveBy(SoTPoint point) {
+      upperLeft.add(point);
+      lowerRight.add(point);
+      computeRange();
+      changes_.firePropertyChange("rectMoved", true, false);
+    }
+    private void computeRange() {
+      if(upperLeft.getX().isTime()) {
+        xRange_ = new SoTRange.Time(upperLeft.getX().getLongTime(),
+                                    lowerRight.getX().getLongTime());
+      } else {
+        double xmin = ((Number)upperLeft.getX().getObjectValue()).doubleValue();
+        double xmax = ((Number)lowerRight.getX().getObjectValue()).doubleValue();
+        xRange_ = new SoTRange.Double(xmin, xmax);
+      }
+      if(upperLeft.getY().isTime()) {
+        yRange_ = new SoTRange.Time(lowerRight.getY().getLongTime(),
+                                    upperLeft.getY().getLongTime());
+      } else {
+        double ymin = ((Number)lowerRight.getY().getObjectValue()).doubleValue();
+        double ymax = ((Number)upperLeft.getY().getObjectValue()).doubleValue();
+        yRange_ = new SoTRange.Double(ymin, ymax);
+      }
+    }
+    public void propertyChange(PropertyChangeEvent evt) {
+      changes_.firePropertyChange(evt);
+    }
+    /* SGTData required methods */
+    public SGTData copy() {
+      SGTData copy = null;
+      try {
+        copy = (SGTData)this.clone();
+      } catch (CloneNotSupportedException ex) {
+        ex.printStackTrace();
+      }
+      return copy;
+    }
+    public String getId() {
+      return null;
+    }
+    public SGLabel getKeyTitle() {
+      return null;
+    }
+    public String getTitle() {
+      return null;
+    }
+    public SGTMetaData getXMetaData() {
+      return null;
+    }
+    public SoTRange getXRange() {
+      return xRange_;
+    }
+    public SGTMetaData getYMetaData() {
+      return null;
+    }
+    public SoTRange getYRange() {
+      return yRange_;
+    }
+    public boolean isXTime() {
+      return upperLeft.isXTime();
+    }
+    public boolean isYTime() {
+      return upperLeft.isYTime();
+    }
+  }
+
+  protected Annote() {
+  }
+
+  protected Rectangle computeBounds(Graph graph, SoTDomain domain) {
+    Rectangle rect = null;
+    if(domain == null || !(graph instanceof CartesianGraph)) return rect;
+    CartesianGraph cg = (CartesianGraph)graph;
+    int xd, yd;
+    int width, height;
+
+    int xd1 = cg.getXUtoD(domain.getXRange().getStart());
+    int yd1 = cg.getYUtoD(domain.getYRange().getStart());
+    int xd2 = cg.getXUtoD(domain.getXRange().getEnd());
+    int yd2 = cg.getYUtoD(domain.getYRange().getEnd());
+    if(xd1 < xd2) {
+      xd = xd1;
+      width = xd2 - xd1;
+    } else {
+      xd = xd2;
+      width = xd1 - xd2;
+    }
+    if(yd1 < yd2) {
+      yd = yd1;
+      height = yd2 - yd1;
+    } else {
+      yd = yd2;
+      height = yd1 - yd2;
+    }
+    rect = new Rectangle(xd, yd, width, height);
+    return rect;
+  }
+
+  public abstract Rectangle getBounds(Graph graph);
+  public abstract SoTDomain getDomain();
+  public abstract void moveBy(SoTPoint point);
+  public abstract void propertyChange(PropertyChangeEvent evt);
+
+  public String getAnnoteId() {
+    return id_;
+  }
+  /**
+   * Init method used to setup serialized object.
+   */
+  public abstract void init();
+
+  /* SGTData required methods */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    if(changes_ == null) changes_ = new PropertyChangeSupport(this);
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Cartesian.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Cartesian.java
new file mode 100755
index 0000000..35fedbd
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Cartesian.java
@@ -0,0 +1,27 @@
+/*
+ * $Id: Cartesian.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+/**
+ * The <code>Cartesian</code> interface indicates to the
+ * <code>sgt</code> classes that
+ * X and Y coordinates are to be interpreted as Cartesian
+ * coordinates.  X or Y can optionally, when independent, a time
+ * axis.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ */
+public interface Cartesian extends CoordinateSystem {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Collection.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Collection.java
new file mode 100755
index 0000000..ad48473
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Collection.java
@@ -0,0 +1,149 @@
+/*
+ * $Id: Collection.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+
+/**
+ * <code>Collection</code> is an extension to <code>Vector</code>
+ * designed to hold <code>SGTData</code> objects. These objects must
+ * have consistent x and y coordinate types.  Otherwise, the
+ * <code>isXTime()</code>, <code>isYTime()</code>,
+ * <code>getXMetaData()</code>, <code>getYMetaData()</code>, and
+ * <code>get?Ranges()</code> methods will fail.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see SGTPoint
+ * @see SGTLine
+ * @see SGTGrid
+ * @see SGTVector
+ */
+public class Collection extends Vector implements SGTData, Cloneable {
+  private String title_;
+  private SGLabel keyTitle_ = null;
+  private String id_ = null;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private int colLen_ = 0;
+
+  public Collection() {
+    this("");
+  }
+  public Collection(String title) {
+    super();
+    title_ = title;
+  }
+  public Collection(String title, int initialCapacity) {
+    super(initialCapacity);
+    title_ = title;
+  }
+  public Collection(String title, int initialCapacity, int increment) {
+    super(initialCapacity, increment);
+    title_ = title;
+  }
+  /**
+   * Create a copy.
+   *
+   * @see SGTData
+   */
+  public SGTData copy() {
+    Collection newCollection;
+    newCollection = (Collection)clone();
+    return (SGTData)newCollection;
+  }
+  /**
+   * Get the title.
+   */
+  public String getTitle() {
+    return title_;
+  }
+  /**
+   * Set the title.
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  public boolean isXTime() {
+    return ((SGTData)firstElement()).isXTime();
+  }
+  public boolean isYTime() {
+    return ((SGTData)firstElement()).isYTime();
+  }
+  public SGTMetaData getXMetaData() {
+    return ((SGTData)firstElement()).getXMetaData();
+  }
+  public SGTMetaData getYMetaData() {
+    return ((SGTData)firstElement()).getYMetaData();
+  }
+  public SoTRange getXRange() {
+    computeRange();
+    return xRange_.copy();
+  }
+  public SoTRange getYRange() {
+    computeRange();
+    return yRange_.copy();
+  }
+  private void computeRange() {
+    if(colLen_ == size()) return;
+    colLen_ = size();
+    xRange_ = ((SGTData)firstElement()).getXRange();
+    yRange_ = ((SGTData)firstElement()).getYRange();
+
+    Enumeration enume = elements();
+    while(enume.hasMoreElements()) {
+      SGTData data = (SGTData)enume.nextElement();
+      xRange_.add(data.getXRange());
+      yRange_.add(data.getYRange());
+    }
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/CoordinateSystem.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/CoordinateSystem.java
new file mode 100755
index 0000000..d75c31f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/CoordinateSystem.java
@@ -0,0 +1,25 @@
+/*
+ * $Id: CoordinateSystem.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+/**
+ * Base class for coordinate system information
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see Cartesian
+ * @see Polar
+ */
+public interface CoordinateSystem {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Geographic.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Geographic.java
new file mode 100755
index 0000000..392e296
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Geographic.java
@@ -0,0 +1,27 @@
+/*
+ * $Id: Geographic.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+/**
+ * The <code>Geographic</code> interface indicates to the
+ * <code>sgt</code> classes that
+ * X and Y coordinates are to be interpreted as longitude
+ * and latitude, respectively. The <code>Geographic</code> interface does not
+ * support X or Y being a time coordinate.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ */
+public interface Geographic extends CoordinateSystem {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/PointCollection.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/PointCollection.java
new file mode 100755
index 0000000..02154c1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/PointCollection.java
@@ -0,0 +1,138 @@
+/*
+ * $Id: PointCollection.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+import gov.noaa.pmel.util.SoTRange;
+ 
+/**
+ * <code>PointCollection</code> is an extension to <code>Vector</code>
+ * designed to hold <code>SGTPoint</code> objects.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see SGTData
+ * @see SGTPoint
+ * @see SGTLine
+ * @see SGTGrid
+ * @see SGTVector
+ */
+public class PointCollection extends Collection {
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private int colLen_ = 0;
+
+  /**
+   * @link aggregation
+   * @clientRole x 
+   */
+  private SGTMetaData xMetaData_;
+
+  /**
+   * @link aggregation
+   * @clientRole y 
+   */
+  private SGTMetaData yMetaData_;
+  /**
+   * Default consturctor
+   */
+  public PointCollection() {
+    this("");
+  }
+  public PointCollection(String title) {
+    super(title);
+  }
+  public PointCollection(String title, int initialCapacity) {
+    super(title, initialCapacity);
+  }
+  public PointCollection(String title, int initialCapacity, int increment) {
+    super(title, initialCapacity, increment);
+  }
+  /**
+   * Create a copy.
+   *
+   * @see SGTData
+   */
+  public SGTData copy() {
+    PointCollection newCollection;
+    newCollection = (PointCollection)clone();
+    return (SGTData)newCollection;
+  }
+  public SoTRange getXRange() {
+    computeRange();
+    return xRange_.copy();
+  }
+
+  public SoTRange getYRange() {
+    computeRange();
+    return yRange_.copy();
+  }
+
+  private void computeRange() {
+    if(colLen_ == size()) return;
+    colLen_ = size();
+    double xmin = Double.POSITIVE_INFINITY;
+    double xmax = Double.NEGATIVE_INFINITY;
+    double ymin = xmin;
+    double ymax = xmax;
+    double ptx, pty;
+
+    int count = 0;
+    Enumeration e = elements();
+    while(e.hasMoreElements()) {
+      Object obj = e.nextElement();
+      if(obj instanceof SGTPoint) {
+	SGTPoint pt = (SGTPoint)obj;
+	ptx = pt.getX();
+	pty = pt.getY();
+	if(!(Double.isNaN(ptx) || Double.isNaN(pty))) {
+	  xmin = Math.min(xmin, ptx);
+	  xmax = Math.max(xmax, ptx);
+	  ymin = Math.min(ymin, pty);
+	  ymax = Math.max(ymax, pty);
+	  count++;
+	}
+      }
+    }
+    if(count == 0) {
+      xRange_ = new SoTRange.Double(Double.NaN, Double.NaN);
+      yRange_ = new SoTRange.Double(Double.NaN, Double.NaN);
+    } else {
+      xRange_ = new SoTRange.Double(xmin, xmax);
+      yRange_ = new SoTRange.Double(ymin, ymax);
+    }
+  }
+
+  public SGTMetaData getXMetaData(){ 
+    return xMetaData_; 
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the x axis.
+   */
+  public void setXMetaData(SGTMetaData xMetaData){ 
+    xMetaData_ = xMetaData; 
+  }
+
+  public SGTMetaData getYMetaData(){ 
+    return yMetaData_; 
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the y axis.
+   */
+  public void setYMetaData(SGTMetaData yMetaData){ 
+    yMetaData_ = yMetaData; 
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Polar.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Polar.java
new file mode 100755
index 0000000..043e40d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/Polar.java
@@ -0,0 +1,28 @@
+/*
+ * $Id: Polar.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+/**
+ * The <code>Polar</code> interface indicates to the <code>sgt</code> graphics
+ * toolkit that the X and Y coordinates are to be
+ * interpreted as R (radius) and Theta (angle), 
+ * respectively.  Neither X nor Y can be a time axis 
+ * when using the <code>Polar</code> interface.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see CoordinateSystem
+ */
+public interface Polar extends CoordinateSystem {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGT3DGrid.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGT3DGrid.java
new file mode 100755
index 0000000..da37d47
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGT3DGrid.java
@@ -0,0 +1,74 @@
+/*
+ * $Id: SGT3DGrid.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.SoTRange;
+ 
+/**
+ * Defines a data object to be of Grid type. Interpretation 
+ * of X and Y is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, X and Y are the Cartesian coordinates. For
+ * <code>Polar</code>, X and Y are R (radius) and Theta (angle), respectively.
+ *
+ * The <code>SGTGrid</code> interface only specifies the methods required
+ * to access information. The methods used to construct an
+ * object that implements <code>SGTGrid</code> is left to the developer.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ * @see Cartesian
+ * @see Polar
+ * @see SimpleGrid
+ */
+public interface SGT3DGrid extends SGTData {
+	// additions to SGTData stuff
+
+  /**
+   * Returns true if the Z coordinate is Time.
+   */
+  public boolean isZTime();
+
+  /**
+   * Get the length of Z value array.
+   */
+  public int getZSize();
+  /**
+   * Get the range of measured values on this 3D grid.
+   */
+  public Range2D getValRange();
+  /**
+   * Get the array of temporal values.
+   */
+  /**
+   * Get the Value SGTMetaData.
+   */
+  public SGTMetaData getValMetaData();
+  /**
+   * Z edges available?
+   */
+  public boolean hasZEdges();
+  /**
+   * Get the Y coordinate edges. The YEdge length will
+   * be one greater than the YArray length.
+   */
+  public double[] getZEdges();
+  /**
+   * Get the range of Y coordinate edges.
+   */
+  public SoTRange getZEdgesRange();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGT3DVector.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGT3DVector.java
new file mode 100755
index 0000000..0379356
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGT3DVector.java
@@ -0,0 +1,132 @@
+/*
+ * $Id: SGT3DVector.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+
+/**
+ * Defines a data object to be a Vector. Interpretation
+ * of U and V is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, U and V are the Cartesian vector
+ * components. For <code>Polar</code> ,
+ * U and V are R (radius) and Theta (angle) vector components,
+ * respectively.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ */
+public class SGT3DVector extends SGTVector {
+    /**@shapeType AggregationLink
+  * @clientRole w comp*/
+    SGTGrid wComp_;
+  /**
+   * Default constructor.
+   */
+  public SGT3DVector() {
+  }
+  /**
+   * Construct a SGTVector from two components. The two components
+   * must match in both SGTData and CoordinateSystem Interfaces.
+   * Both components must be the same shape.
+   *
+   * @param uComp U component of the vector
+   * @param vComp V component of the vector
+   * @param vComp W component of the vector
+   */
+  public SGT3DVector(SGTGrid uComp,SGTGrid vComp, SGTGrid wComp) {
+    uComp_ = uComp;
+    vComp_ = vComp;
+    wComp_ = wComp;
+  }
+  /**
+   * Create a copy. Creates a shallow copy.
+   *
+   * @see SGTData
+   */
+  public SGTData copy() {
+    SGT3DVector newSGTVector;
+    try {
+      newSGTVector = (SGT3DVector)clone();
+    } catch (CloneNotSupportedException e) {
+      newSGTVector = new SGT3DVector(this.uComp_, this.vComp_, this.wComp_);
+    }
+    return (SGTData)newSGTVector;
+  }
+  /**
+   * Get the W component.
+   *
+   * @return W component
+   */
+  public SGTGrid getW() {
+    return wComp_;
+  }
+
+  /**
+   * Set the W component.
+   *
+   * @param uComp W component
+   */
+  public void setU(SGTGrid wComp) {
+    wComp_ = wComp;
+  }
+
+  /**
+   * Set the vector components.
+   *
+   * @param uComp U component
+   * @param vComp V component
+   */
+  public void setComponents(SGTGrid uComp, SGTGrid vComp, SGTGrid wComp) {
+    uComp_ = uComp;
+    vComp_ = vComp;
+    wComp_ = wComp;
+  }
+
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+
+
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    uComp_.addPropertyChangeListener(l);
+    vComp_.addPropertyChangeListener(l);
+    wComp_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    uComp_.removePropertyChangeListener(l);
+    vComp_.removePropertyChangeListener(l);
+    wComp_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTData.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTData.java
new file mode 100755
index 0000000..758d419
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTData.java
@@ -0,0 +1,134 @@
+/*
+ * $Id: SGTData.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.beans.PropertyChangeListener;
+
+/**
+ * Base class for sgt datamodel rank information.
+ * The <code>SGTData</code> class and its children are used by sgt
+ * to determine the rank (point, line, grid) of the
+ * data. Data values can be either <code>double</code> or
+ * <code>GeoDate</code>, which extends <code>Date</code>.  Missing
+ * values are indicated by <code>Double.NaN</code> for type
+ * <code>double</code> and by <code>null</code> or by
+ * <code>Long.MIN_VALUE</code> milliseconds after (before) January 1,
+ * 1970 00:00:00 GMT for <code>GeoDate</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTPoint
+ * @see SGTLine
+ * @see SGTGrid
+ */
+public interface SGTData {
+  /**
+   * Get the title.
+   */
+  public String getTitle();
+  /**
+   * Get a title formatted for a Key. <code>JPlotLayout</code> will use this
+   * if an explicit Key title is not given in the <code>addData</code> method.
+   *
+   * @see gov.noaa.pmel.sgt.SGLabel
+   * @see gov.noaa.pmel.sgt.ColorKey
+   * @see gov.noaa.pmel.sgt.LineKey
+   * @see gov.noaa.pmel.sgt.PointCollectionKey
+   * @see gov.noaa.pmel.sgt.VectorKey
+   */
+   public SGLabel getKeyTitle();
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId();
+  /**
+   * Create a shallow copy. User should implement using the clone()
+   * method, which requires the Cloneable interface be inherited.
+   * If clone() is used, then references to objects are copied NOT
+   * the object itself.
+   *
+   * <p>For example, </p>
+   * <pre>
+   * public SGTData copy() {
+   *   SGTData newData;
+   *   try {
+   *     newData = (SGTData)clone();
+   *   } catch (CloneNotSupportedException e) {
+   *     newData = null;
+   *   }
+   *   return newData;
+   * }
+   * </pre>
+   *
+   * @return shallow copy
+   * @see java.lang.Object
+   */
+  public SGTData copy();
+
+  /**
+   * Returns true if the X coordinate is Time.
+   */
+  public boolean isXTime();
+
+  /**
+   * Returns true if the Y coordinate is Time.
+   */
+  public boolean isYTime();
+
+  /**
+   * Returns the X SGTMetaData.
+   */
+  public SGTMetaData getXMetaData();
+
+  /**
+   * Returns the Y SGTMetaData.
+   */
+  public SGTMetaData getYMetaData();
+
+  /**
+   * Returns the range of the X coordinates.  If all the data in the
+   * array is missing, this method will return <code>Double.NaN</code>
+   * as the start and end values for data of type <code>double</code>
+   * and return <code>GeoDate(Long.MIN_VALUE)</code> for data of type
+   * <code>GeoDate</code>.
+   *
+   * @see gov.noaa.pmel.util.GeoDate#isMissing()
+   */
+  public SoTRange getXRange();
+
+  /**
+   * Returns the range of the Y coordinates.
+   * @see #getXRange()
+   */
+  public SoTRange getYRange();
+
+  /**
+   * Add a PropertyChangeListener to the listener list.
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l);
+
+  /**
+   * Remove a PropertyChangeListener from the listener list.
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTFull3DVector.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTFull3DVector.java
new file mode 100755
index 0000000..27ffc70
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTFull3DVector.java
@@ -0,0 +1,219 @@
+/*
+ * $Id: SGTFull3DVector.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+
+/**
+ * Defines a data object to be a Vector. Interpretation
+ * of U and V is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, U and V are the Cartesian vector
+ * components. For <code>Polar</code> ,
+ * U and V are R (radius) and Theta (angle) vector components,
+ * respectively.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ */
+public class SGTFull3DVector implements SGTData, Cloneable, Serializable {
+  String title_;
+  SGLabel keyTitle_ = null;
+  String id_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole u comp*/
+    ThreeDGrid uComp_;
+    /**@shapeType AggregationLink
+  * @clientRole v comp*/
+    ThreeDGrid vComp_;
+    /**@shapeType AggregationLink
+  * @clientRole w comp*/
+    ThreeDGrid wComp_;
+    
+  /**
+   * Default constructor.
+   */
+  public SGTFull3DVector() {
+  }
+  /**
+   * Construct a SGT3DVector from three components. The three components
+   * must match in both SGTData and CoordinateSystem Interfaces.
+   * All components must be the same shape.
+   *
+   * @param uComp U component of the vector
+   * @param vComp V component of the vector
+   * @param wComp W component of the vector
+   */
+  public SGTFull3DVector(ThreeDGrid uComp, ThreeDGrid vComp, ThreeDGrid wComp) {
+    uComp_ = uComp;
+    vComp_ = vComp;
+    wComp_ = wComp;
+  }
+  /**
+   * Create a copy. Creates a shallow copy.
+   *
+   * @see SGTData
+   */
+  public SGTData copy() {
+    SGTFull3DVector newSGTVector;
+    try {
+      newSGTVector = (SGTFull3DVector)clone();
+    } catch (CloneNotSupportedException e) {
+      newSGTVector = new SGTFull3DVector(this.uComp_, this.vComp_, this.wComp_);
+    }
+    return newSGTVector;
+  }
+  /**
+   * Get the U component.
+   *
+   * @return U component
+   */
+  public ThreeDGrid getU() {
+    return uComp_;
+  }
+  /**
+   * Get the V component.
+   *
+   * @return V component
+   */
+  public ThreeDGrid getV() {
+    return vComp_;
+  }
+  /**
+   * Get the W component.
+   *
+   * @return W component
+   */
+  public ThreeDGrid getW() {
+    return wComp_;
+  }
+  /**
+   * Set the U component.
+   *
+   * @param uComp U component
+   */
+  public void setU(ThreeDGrid uComp) {
+    uComp_ = uComp;
+  }
+  /**
+   * Set the V component.
+   *
+   * @param vComp V component
+   */
+  public void setV(ThreeDGrid vComp) {
+    vComp_ = vComp;
+  }
+  /**
+   * Set the W component.
+   *
+   * @param vComp W component
+   */
+  public void setW(ThreeDGrid wComp) {
+    wComp_ = wComp;
+  }
+  /**
+   * Set the vector components.
+   *
+   * @param uComp U component
+   * @param vComp V component
+   */
+  public void setComponents(ThreeDGrid uComp, ThreeDGrid vComp, ThreeDGrid wComp) {
+    uComp_ = uComp;
+    vComp_ = vComp;
+    wComp_ = wComp;
+  }
+  /**
+   * Set the vector's title.
+   *
+   * @param title
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  /** Set the title formatted for the <code>VectorKey</code>. */
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  /**
+   * Get the vector's title.
+   *
+   * @return the title
+   */
+  public String getTitle() {
+    return title_;
+  }
+  public boolean isXTime() {
+    return uComp_.isXTime();
+  }
+  public boolean isYTime() {
+    return uComp_.isYTime();
+  }
+  public boolean isZTime() {
+    return uComp_.isZTime();
+  }
+  public SGTMetaData getXMetaData() {
+    return uComp_.getXMetaData();
+  }
+  public SGTMetaData getYMetaData() {
+    return uComp_.getYMetaData();
+  }
+  public SGTMetaData getZMetaData() {
+    return uComp_.getZMetaData();
+  }
+  public SoTRange getXRange() {
+    return uComp_.getXRange();
+  }
+  public SoTRange getYRange() {
+    return uComp_.getYRange();
+  }
+  public SoTRange getZRange() {
+    return uComp_.getZRange();
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    uComp_.addPropertyChangeListener(l);
+    vComp_.addPropertyChangeListener(l);
+    wComp_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    uComp_.removePropertyChangeListener(l);
+    vComp_.removePropertyChangeListener(l);
+    wComp_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTGrid.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTGrid.java
new file mode 100755
index 0000000..138e095
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTGrid.java
@@ -0,0 +1,128 @@
+/*
+ * $Id: SGTGrid.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.SoTRange;
+
+/**
+ * Defines a data object to be of Grid type. Interpretation
+ * of X and Y is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, X and Y are the Cartesian coordinates. For
+ * <code>Polar</code>, X and Y are R (radius) and Theta (angle), respectively.
+ *
+ * The <code>SGTGrid</code> interface only specifies the methods required
+ * to access information. The methods used to construct an
+ * object that implements <code>SGTGrid</code> is left to the developer.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ * @see Cartesian
+ * @see Polar
+ * @see SimpleGrid
+ */
+public interface SGTGrid extends SGTData {
+  /**
+   * Get the array of X values.
+   */
+  public double[] getXArray();
+  /**
+   * Get the length of X value array.
+   */
+  public int getXSize();
+  /**
+   * Get the array of Y values.
+   */
+  public double[] getYArray();
+  /**
+   * Get the length of Y value array.
+   */
+  public int getYSize();
+  /**
+   * Get the array of Z values.
+   */
+  public double[] getZArray();
+  /**
+   * Get the range of Z values.
+   */
+  public Range2D getZRange();
+  /**
+   * Get the array of temporal values.
+   */
+  public GeoDate[] getTimeArray();
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   *
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArray();
+  /**
+   * Get the length of temporal value array.
+   */
+  public int getTSize();
+  /**
+   * Get the Z SGTMetaData.
+   */
+  public SGTMetaData getZMetaData();
+  /**
+   * Get the associated data. The associated data must
+   * be of the same type (SGTGrid) and shape.
+   */
+  public SGTGrid getAssociatedData();
+  /**
+   * Is there associated data available?
+   */
+  public boolean hasAssociatedData();
+  /**
+   * Are X edges available?
+   */
+  public boolean hasXEdges();
+  /**
+   * Get the X coordinate edges. The XEdge length will
+   * be one greater than the XArray length.
+   */
+  public double[] getXEdges();
+  /**
+   * Get the range of X coordinate edges.
+   */
+  public SoTRange getXEdgesRange();
+  /**
+   * Are Y edges available?
+   */
+  public boolean hasYEdges();
+  /**
+   * Get the Y coordinate edges. The YEdge length will
+   * be one greater than the YArray length.
+   */
+  public double[] getYEdges();
+  /**
+   * Get the range of Y coordinate edges.
+   */
+  public SoTRange getYEdgesRange();
+  /**
+   * Get the Time edges. The TimeEdge length will
+   * be one greater than the TimeArray length.
+   */
+  public GeoDate[] getTimeEdges();
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   *
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArrayEdges();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTImage.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTImage.java
new file mode 100755
index 0000000..ddbf983
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTImage.java
@@ -0,0 +1,62 @@
+/*
+ * $Id: SGTImage.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+import java.awt.Image;
+ 
+/**
+ * Defines a data object to be of <code>Image</code> type. Interpretation 
+ * of X and Y is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, X and Y are the Cartesian coordinates. For
+ * <code>Polar</code>,
+ * X and Y are R (radius) and Theta (angle), respectively.
+ *
+ * The </code>SGTImage</code> interface only specifies the methods required
+ * to access information. The methods used to construct an
+ * object that implements <code>SGTImage</code> is left to the developer.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ * @see Cartesian
+ * @see Polar
+ */
+public interface SGTImage extends SGTData {
+  /**
+   * Get the X coordinate edges.
+   */
+  public double[] getXEdges();
+  /**
+   * Get the Y coordinate edges.
+   */
+  public double[] getYEdges();
+  /**
+   * Get the image.
+   */
+  public Image getImage();
+  /**
+   * Get the X coordinate SGTMetaData.
+   */
+  public SGTMetaData getXMetaData();
+  /**
+   * Get the Y coordinate SGTMetaData.
+   */
+  public SGTMetaData getYMetaData();
+  /**
+   * Get the pixel SGTMetaData.
+   */
+  public SGTMetaData getZMetaData();
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTLine.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTLine.java
new file mode 100755
index 0000000..af85e9d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTLine.java
@@ -0,0 +1,67 @@
+/*
+ * $Id: SGTLine.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+
+/**
+ * Defines a data object to be of Line type. Interpretation
+ * of X and Y is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, X and Y are the Cartesian coordinates. For
+ * <code>Polar</code>,
+ * X and Y are R (radius) and Theta (angle), respectively.
+ *
+ * The <code>SGTLine</code> interfaces only specifies the methods required
+ * to access information. The methods used to construct an
+ * object that implements <code>SGTLine</code> is left to the developer.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ * @see Cartesian
+ * @see Polar
+ * @see SimpleLine
+ */
+public interface SGTLine extends SGTData {
+  /**
+   * Get the array of X values.
+   */
+  public double[] getXArray();
+  /**
+   * Get the array of Y values.
+   */
+  public double[] getYArray();
+  /**
+   * Get the array of Time values.
+   */
+  public GeoDate[] getTimeArray();
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   *
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArray();
+  /**
+   * Get the associated data. The associated data must
+   * be of the same type (SGTLine) and length. The Y
+   * array will be used.
+   */
+  public SGTLine getAssociatedData();
+  /**
+   * Is there associated data available?
+   */
+  public boolean hasAssociatedData();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTMetaData.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTMetaData.java
new file mode 100755
index 0000000..1b81095
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTMetaData.java
@@ -0,0 +1,155 @@
+/**
+ * $Id: SGTMetaData.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.dm;
+ 
+import gov.noaa.pmel.util.GeoDate;
+import java.util.Properties;
+/**
+ * MetaData container for the sgt datamodel.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ */
+public class SGTMetaData implements java.io.Serializable {
+  private String name_;
+  private String units_;
+  private boolean modulo_;
+  private double moduloValue_ = 0.0;
+  private GeoDate moduloTime_ = null;
+  private boolean reversed_;
+  private Properties props_ = null;
+  /**
+   * Default constructor.
+   */
+  public SGTMetaData() {
+    this("", "");
+  }
+  /**
+   * SGTMetaData constructor.
+   *
+   * @param name variable name
+   * @param units units of variable
+   */
+  public SGTMetaData(String name,String units) {
+    this(name, units, false, false);
+  }
+  public SGTMetaData(String name, String units, boolean rev, boolean mod) {
+    name_ = name;
+    units_ = units;
+    reversed_ = rev;
+    modulo_ = mod;
+  }
+  /**
+   * Get the name associated with the variable or coordinate.
+   */
+  public String getName() {
+    return name_;
+  }
+  /**
+   * Axis values are reversed.  This axis defines a left-hand
+   * coordinate system.  For example, northward, eastward, downward,
+   * is left-handed.
+   */
+  public boolean isReversed() {
+    return reversed_;
+  }
+  /**
+   * Axis values are modulo.  For example, 0 and 360 longitude are
+   * equivalent values.
+   */
+  public boolean isModulo() {
+    return modulo_;
+  }
+  /**
+   * Set the modulo value.  For example, 360 for longitude.
+   */
+  public void setModuloValue(double val) {
+    moduloValue_ = val;
+  }
+  /**
+   * Set temporal modulo value.  For example, 365 days, for yearly
+   * climatologies.
+   */
+  public void setModuloTime(GeoDate val) {
+    moduloTime_ = val;
+  }
+  /**
+   * Get modulo value.
+   */
+  public double getModuloValue() {
+    return moduloValue_;
+  }
+  /**
+   * Get temporal modulo value
+   */
+  public GeoDate getModuloTime() {
+    return moduloTime_;
+  }
+  /**
+   * Set name of coordinate or variable
+   */
+  public void setName(String name) {
+    name_ = name;
+  }
+  /**
+   * Set units of coordinate or variable
+   */
+  public void setUnits(String units) {
+    units_ = units;
+  }
+  /**
+   * Set additional properties for the coordinate or variable.
+   */
+  public void setProperties(Properties props) {
+    props_ = props;
+  }
+  /**
+   * Get variable or coordinate additional properties.
+   */
+  public Properties getProperties() {
+    return props_;
+  }
+  /**
+   * Get property value given the key.
+   */
+  public String getProperty(String key) {
+    return getProperty(key, "");
+  }
+  /**
+   * Get property value given the key, if key is not defined use the
+   * default value.
+   */
+  public String getProperty(String key,String defValue) {
+    if(props_ != null) {
+      return props_.getProperty(key, defValue);
+    } else {
+      return null;
+    }
+  }
+  /**
+   * Set a property for the variable or coordinate.
+   */
+  public void setProperty(String key,String value) {
+    if(props_ == null) {
+      props_ = new Properties();
+    }
+    props_.put(key, value);
+  }
+  /**
+   * Get variable or coordinate units.
+   */
+  public String getUnits() {
+    return units_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTPoint.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTPoint.java
new file mode 100755
index 0000000..5790f63
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTPoint.java
@@ -0,0 +1,68 @@
+/*
+ * $Id: SGTPoint.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.util.GeoDate;
+
+/**
+ * Defines a data object to be of Point type. Interpretation
+ * of X and Y is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, X and Y are the Cartesian coordinates. For
+ * <code>Polar</code>,
+ * X and Y are R (radius) and Theta (angle), respectively.
+ *
+ * The <code>SGTPoint</code> interface only defines data access, not how
+ * the data will be constructed or set.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ * @see Cartesian
+ * @see Polar
+ * @see SimplePoint
+ */
+public interface SGTPoint extends SGTData {
+  /**
+   * Get the x coordinate.
+   */
+  public double getX();
+  /**
+   * Get the y coordinate.
+   */
+  public double getY();
+  /**
+   * Test if a value is associated with the SGTPoint.
+   */
+  public boolean hasValue();
+  /**
+   * Get the associated value.
+   */
+  public double getValue();
+  /**
+   * Get the SGTMetaData object associated with the value.
+   */
+  public SGTMetaData getValueMetaData();
+  /**
+   * Get the Time value.
+   */
+  public GeoDate getTime();
+  /**
+   * Get the time as <code>long</code> referenced from
+   * 1970-01-01.
+   *
+   * @since 3.0
+   */
+  public long getLongTime();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTTuple.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTTuple.java
new file mode 100755
index 0000000..051ce1c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTTuple.java
@@ -0,0 +1,41 @@
+/*
+ * $Id: SGTTuple.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+import gov.noaa.pmel.util.Range2D;
+
+/**
+ * Provides access to tuple organized data of either 2 or 3 dimensions.
+ * All arrays that are provided must be of equal length.
+ * Tuples can be used to provide un-structured 3-D data that can then
+ * be trianglulated to enable area fill or contouring.  3-d tuples
+ * are also useful in the construction of vectors.
+ * @since 2.x
+ */
+public interface SGTTuple extends SGTData {
+    public double[] getXArray();
+    public double[] getYArray();
+    public double[] getZArray();
+    public int getSize();
+    public GeoDate[] getTimeArray();
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   */
+    public GeoDateArray getGeoDateArray();
+    public double[] getAssociatedData();
+    public boolean hasAssociatedData();
+    public SGTMetaData getZMetaData();
+    public Range2D getZRange();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTVector.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTVector.java
new file mode 100755
index 0000000..c763153
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SGTVector.java
@@ -0,0 +1,185 @@
+/*
+ * $Id: SGTVector.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+
+/**
+ * Defines a data object to be a Vector. Interpretation
+ * of U and V is determined by the <code>CoordinateSystem</code>.  For
+ * <code>Cartesian</code>, U and V are the Cartesian vector
+ * components. For <code>Polar</code> ,
+ * U and V are R (radius) and Theta (angle) vector components,
+ * respectively.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTData
+ * @see CoordinateSystem
+ */
+public class SGTVector implements SGTData, Cloneable, Serializable {
+  String title_;
+  SGLabel keyTitle_ = null;
+  String id_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole u comp*/
+    SGTGrid uComp_;
+    /**@shapeType AggregationLink
+  * @clientRole v comp*/
+    SGTGrid vComp_;
+  /**
+   * Default constructor.
+   */
+  public SGTVector() {
+  }
+  /**
+   * Construct a SGTVector from two components. The two components
+   * must match in both SGTData and CoordinateSystem Interfaces.
+   * Both components must be the same shape.
+   *
+   * @param uComp U component of the vector
+   * @param vComp V component of the vector
+   */
+  public SGTVector(SGTGrid uComp,SGTGrid vComp) {
+    uComp_ = uComp;
+    vComp_ = vComp;
+  }
+  /**
+   * Create a copy. Creates a shallow copy.
+   *
+   * @see SGTData
+   */
+  public SGTData copy() {
+    SGTVector newSGTVector;
+    try {
+      newSGTVector = (SGTVector)clone();
+    } catch (CloneNotSupportedException e) {
+      newSGTVector = new SGTVector(this.uComp_, this.vComp_);
+    }
+    return (SGTData)newSGTVector;
+  }
+  /**
+   * Get the U component.
+   *
+   * @return U component
+   */
+  public SGTGrid getU() {
+    return uComp_;
+  }
+  /**
+   * Get the V component.
+   *
+   * @return V component
+   */
+  public SGTGrid getV() {
+    return vComp_;
+  }
+  /**
+   * Set the U component.
+   *
+   * @param uComp U component
+   */
+  public void setU(SGTGrid uComp) {
+    uComp_ = uComp;
+  }
+  /**
+   * Set the V component.
+   *
+   * @param vComp V component
+   */
+  public void setV(SGTGrid vComp) {
+    vComp_ = vComp;
+  }
+  /**
+   * Set the vector components.
+   *
+   * @param uComp U component
+   * @param vComp V component
+   */
+  public void setComponents(SGTGrid uComp, SGTGrid vComp) {
+    uComp_ = uComp;
+    vComp_ = vComp;
+  }
+  /**
+   * Set the vector's title.
+   *
+   * @param title
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  /** Set the title formatted for the <code>VectorKey</code>. */
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  /**
+   * Get the vector's title.
+   *
+   * @return the title
+   */
+  public String getTitle() {
+    return title_;
+  }
+  public boolean isXTime() {
+    return uComp_.isXTime();
+  }
+  public boolean isYTime() {
+    return uComp_.isYTime();
+  }
+  public SGTMetaData getXMetaData() {
+    return uComp_.getXMetaData();
+  }
+  public SGTMetaData getYMetaData() {
+    return uComp_.getYMetaData();
+  }
+  public SoTRange getXRange() {
+    return uComp_.getXRange();
+  }
+  public SoTRange getYRange() {
+    return uComp_.getYRange();
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    uComp_.addPropertyChangeListener(l);
+    vComp_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    uComp_.removePropertyChangeListener(l);
+    vComp_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleGrid.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleGrid.java
new file mode 100755
index 0000000..007d994
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleGrid.java
@@ -0,0 +1,488 @@
+/**
+ * $Id: SimpleGrid.java,v 1.1.1.2 2008/12/19 13:29:38 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+
+/**
+ * <code>SimpleGrid</code> provides an implementation of the
+ * <code>SGTGrid</code> and <code>Cartesian</code> interfaces.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:38 $
+ * @since 1.0
+ * @see SGTGrid
+ * @see Cartesian
+ */
+public class SimpleGrid implements SGTGrid, Cartesian, Cloneable, Serializable {
+protected double[] xloc_;
+  protected double[] yloc_;
+//  protected GeoDate[] tloc_;
+  protected GeoDateArray tloc_;
+  protected double[] grid_;
+  protected double[] xEdges_;
+  protected double[] yEdges_;
+//  protected GeoDate[] tEdges_;
+  protected GeoDateArray tEdges_;
+  protected boolean hasXEdges_;
+  protected boolean hasYEdges_;
+  protected String title_;
+  protected SGLabel keyTitle_ = null;
+  protected String id_ = null;
+  protected boolean xTime_;
+  protected boolean yTime_;
+    /**@shapeType AggregationLink
+  * @clientRole x*/
+    protected SGTMetaData xMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole y*/
+    protected SGTMetaData yMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole z*/
+    protected SGTMetaData zMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole associated data*/
+    protected SGTGrid associatedData_;
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private SoTRange xEdgesRange_ = null;
+  private SoTRange yEdgesRange_ = null;
+  private Range2D zRange_ = null;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+
+  /**
+   * Default constructor.
+   */
+  public SimpleGrid() {
+    this(null, (double[])null, (double[])null, "");
+  }
+  /**
+   * Constructor for X and Y coordinates as double.
+   *
+   * @param grid Z values
+   * @param xloc X coordinates
+   * @param yloc Y coordinates
+   * @param title the title
+   */
+  public SimpleGrid(double[] grid, double[] xloc,
+                    double[] yloc, String title) {
+    grid_ = grid;
+    xloc_ = xloc;
+    yloc_ = yloc;
+    title_ = title;
+    xTime_ = false;
+    yTime_ = false;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(yloc);
+    zRange_ = computeRange2D(grid);
+  }
+  /**
+   * Constructor for X time and Y double.
+   *
+   * @param grid Z values
+   * @param tloc Time coordinates
+   * @param yloc Y coordinates
+   * @param title the title
+   */
+  public SimpleGrid(double[] grid, GeoDate[] tloc,
+                    double[] yloc,String title) {
+    grid_ = grid;
+    tloc_ = new GeoDateArray(tloc);
+    yloc_ = yloc;
+    title_ = title;
+    xTime_ = true;
+    yTime_ = false;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    xRange_ = computeSoTRange(tloc_);
+    yRange_ = computeSoTRange(yloc);
+    zRange_ = computeRange2D(grid);
+  }
+  /**
+   * Constructor for X double and Y time.
+   *
+   * @param grid Z values
+   * @param xloc X coordinates
+   * @param tloc Time coordinates
+   * @param title the title
+   */
+  public SimpleGrid(double[] grid, double[] xloc,
+                    GeoDate[] tloc,String title) {
+    grid_ = grid;
+    xloc_ = xloc;
+    tloc_ = new GeoDateArray(tloc);
+    title_ = title;
+    xTime_ = false;
+    yTime_ = true;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(tloc_);
+    zRange_ = computeRange2D(grid);
+  }
+  /**
+   * Create a copy of the grid.
+   *
+   * @since 2.0
+   * @see SGTData
+   */
+  public SGTData copy() {
+    SGTGrid newGrid;
+    try {
+      newGrid = (SGTGrid)clone();
+    } catch (CloneNotSupportedException e) {
+      newGrid = new SimpleGrid();
+    }
+    return (SGTData)newGrid;
+  }
+  public double[] getXArray() {
+    return xloc_;
+  }
+  /**
+   * Get the length of the x axis
+   *
+   * @since 2.0
+   */
+  public int getXSize() {
+    return xloc_.length;
+  }
+  public double[] getYArray() {
+    return yloc_;
+  }
+  /**
+   * Get the length of the y axis
+   *
+   * @since 2.0
+   */
+  public int getYSize() {
+    return yloc_.length;
+  }
+  public double[] getZArray() {
+    return grid_;
+  }
+  public GeoDate[] getTimeArray() {
+    return tloc_.getGeoDate();
+  }
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   *
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArray() {
+    return tloc_;
+  }
+  /**
+   * Get the length of the Time axis
+   *
+   * @since 2.0
+   */
+  public int getTSize() {
+    return tloc_.getLength();
+  }
+  public boolean isXTime() {
+    return xTime_;
+  }
+  public boolean isYTime() {
+    return yTime_;
+  }
+  public SGTMetaData getXMetaData() {
+    return xMetaData_;
+  }
+  public SGTMetaData getYMetaData() {
+    return yMetaData_;
+  }
+  public SGTMetaData getZMetaData() {
+    return zMetaData_;
+  }
+  public String getTitle() {
+    return title_;
+  }
+  /**
+   * Set the associated data grid.
+   * <BR><B>Property Change:</B> <code>associatedDataModified</code>.
+   *
+   * @since 2.0
+   */
+  public void setAssociatedData(SGTGrid assoc) {
+    associatedData_ = assoc;
+    changes_.firePropertyChange("associatedDataModified",
+                                null,
+                                assoc);
+  }
+  public SGTGrid getAssociatedData() {
+    return associatedData_;
+  }
+  public boolean hasAssociatedData() {
+    return (associatedData_ != null);
+  }
+  public boolean hasXEdges() {
+    return hasXEdges_;
+  }
+  public double[] getXEdges() {
+    return xEdges_;
+  }
+  /**
+   * Set the values for the x grid edges.
+   */
+  public void setXEdges(double[] edge) {
+    xEdges_ = edge;
+    hasXEdges_ = true;
+    xEdgesRange_ = computeSoTRange(edge);
+  }
+  public boolean hasYEdges() {
+    return hasYEdges_;
+  }
+  public double[] getYEdges() {
+    return yEdges_;
+  }
+  /**
+   * Set the values for the y grid edges.
+   */
+  public void setYEdges(double[] edge) {
+    yEdges_ = edge;
+    hasYEdges_ = true;
+    yEdgesRange_ = computeSoTRange(edge);
+  }
+  public GeoDate[] getTimeEdges() {
+    return tEdges_.getGeoDate();
+  }
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   *
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArrayEdges() {
+    return tEdges_;
+  }
+  /**
+   * Set the values for the temporal grid edges.
+   */
+  public void setTimeEdges(GeoDate[] edge) {
+    setTimeEdges(new GeoDateArray(edge));
+  }
+  /**
+   * @since 3.0
+   */
+  public void setTimeEdges(GeoDateArray tarray) {
+    tEdges_ = tarray;
+    if(xTime_) {
+      hasXEdges_ = true;
+      xEdgesRange_ = computeSoTRange(tarray);
+    } else if(yTime_){
+      hasYEdges_ = true;
+      yEdgesRange_ = computeSoTRange(tarray);
+    }
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the x
+   * coordinate.
+   */
+  public void setXMetaData(SGTMetaData md) {
+    xMetaData_ = md;
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the y
+   * coordinate.
+   */
+  public void setYMetaData(SGTMetaData md) {
+    yMetaData_ = md;
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the z
+   * coordinate.
+   */
+  public void setZMetaData(SGTMetaData md) {
+    zMetaData_ = md;
+  }
+  /**
+   * Set the grid title
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  /** Set the title formatted for the <code>VectorKey</code>. */
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @since 2.0
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  /**
+   * Set the x coordinate grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setXArray(double[] xloc) {
+    xloc_ = xloc;
+    xTime_ = false;
+    xRange_ = computeSoTRange(xloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(xloc.length));
+  }
+  /**
+   * Set the y coordinate grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setYArray(double[] yloc) {
+    yloc_ = yloc;
+    yTime_ = false;
+    yRange_ = computeSoTRange(yloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(yloc.length));
+  }
+  /**
+   * Set the z grid values.
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setZArray(double[] grid) {
+    grid_ = grid;
+    zRange_ = computeRange2D(grid);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(grid.length));
+  }
+  /**
+   * set the temporal grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setTimeArray(GeoDate[] tloc) {
+    setTimeArray(new GeoDateArray(tloc));
+  }
+  /**
+   * @since 3.0
+   */
+  public void setTimeArray(GeoDateArray tarray) {
+    tloc_ = tarray;
+    if(xTime_) {
+      xRange_ = computeSoTRange(tarray);
+    } else if(yTime_) {
+      yRange_ = computeSoTRange(tarray);
+    }
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(tarray.getLength()));
+  }
+  public SoTRange getXRange() {
+    return xRange_.copy();
+  }
+  public SoTRange getYRange() {
+    return yRange_.copy();
+  }
+  public Range2D getZRange() {
+    return zRange_;
+  }
+  /**
+   * Return the range of the x edges
+   *
+   * @since 2.0
+   */
+  public SoTRange getXEdgesRange() {
+    return xEdgesRange_;
+  }
+  /**
+   * Return the range of the y edges
+   *
+   * @since 2.0
+   */
+  public SoTRange getYEdgesRange() {
+    return yEdgesRange_;
+  }
+
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+
+  private SoTRange computeSoTRange(double[] array) {
+    Range2D range = computeRange2D(array);
+    return new SoTRange.Double(range.start, range.end);
+  }
+  private SoTRange computeSoTRange(GeoDateArray tarray) {
+    long start = Long.MAX_VALUE;
+    long end = Long.MIN_VALUE;
+    long[] tar = tarray.getTime();
+    int count = 0;
+    for(int i=0; i < tar.length; i++) {
+      if(!(tar[i] == Long.MAX_VALUE)) {
+        start = Math.min(start, tar[i]);
+        end = Math.max(end, tar[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new SoTRange.Time(Long.MAX_VALUE,
+                               Long.MAX_VALUE);
+    } else {
+      return new SoTRange.Time(start, end);
+    }
+  }
+  private Range2D computeRange2D(double[] array) {
+    double start = Double.POSITIVE_INFINITY;
+    double end = Double.NEGATIVE_INFINITY;
+    int count = 0;
+    for(int i=0; i < array.length; i++) {
+      if(!Double.isNaN(array[i])) {
+        start = Math.min(start, array[i]);
+        end = Math.max(end, array[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new Range2D(Double.NaN, Double.NaN);
+    } else {
+      return new Range2D(start, end);
+    }
+  }
+  public void finalize() throws Throwable {
+		super.finalize();
+		xloc_ = null;
+		yloc_ = null;
+		grid_ = null;
+		xEdges_ = null;
+		yEdges_ = null;
+		changes_ = null;
+	}
+ 
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleLine.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleLine.java
new file mode 100755
index 0000000..171195c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleLine.java
@@ -0,0 +1,377 @@
+/**
+ * $Id: SimpleLine.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.io.Serializable;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+
+/**
+ * <code>SimpleLine</code> provides an implementation of the
+ * <code>SGTLine</code> and <code>Cartesian</code> interfaces.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTLine
+ * @see Cartesian
+ */
+public class SimpleLine implements SGTLine, Cartesian,
+                                   Serializable, Cloneable {
+  protected double[] xloc_;
+  protected double[] yloc_;
+//  protected GeoDate[] tloc_;
+  protected GeoDateArray tloc_;
+  protected boolean xTime_;
+  protected boolean yTime_;
+  protected String title_;
+  protected SGLabel keyTitle_ = null;
+  protected String id_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole x*/
+    protected SGTMetaData xMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole y*/
+    protected SGTMetaData yMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole associated data*/
+  protected SGTLine associatedData_ = null;
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  /**
+   * Default constuctor.
+   */
+  public SimpleLine() {
+    this((double[])null, (double[])null, "");
+  }
+  /**
+   * Constructor for X and Y double.
+   *
+   * @param xloc X coordinates
+   * @param yloc Y coordinates
+   * @param title the Title
+   */
+  public SimpleLine(double[] xloc,double[] yloc,String title) {
+    xloc_ = xloc;
+    yloc_ = yloc;
+    title_ = title;
+    xTime_ = false;
+    yTime_ = false;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(yloc);
+  }
+  /**
+   * Constructor for X Time and Y double.
+   *
+   * @param tloc Time coordinates
+   * @param yloc Y coordinates
+   * @param title the Title
+   */
+  public SimpleLine(GeoDate[] tloc, double[] yloc, String title) {
+    tloc_ = new GeoDateArray(tloc);
+    yloc_ = yloc;
+    title_ = title;
+    xTime_ = true;
+    yTime_ = false;
+    xRange_ = computeSoTRange(tloc_);
+    yRange_ = computeSoTRange(yloc);
+  }
+  /**
+   * Constructor for X Time and Y double.
+   *
+   * @since 3.0
+   * @param tloc Time coordinates
+   * @param yloc Y coordinates
+   * @param title the Title
+   */
+  public SimpleLine(GeoDateArray tloc, double[] yloc, String title) {
+    tloc_ = tloc;
+    yloc_ = yloc;
+    title_ = title;
+    xTime_ = true;
+    yTime_ = false;
+    xRange_ = computeSoTRange(tloc_);
+    yRange_ = computeSoTRange(yloc);
+  }
+  /**
+   * Constructor for X double and Y Time.
+   *
+   * @since 3.0
+   * @param xloc X coordinates
+   * @param tloc Time coordinates
+   * @param title the Title
+   */
+  public SimpleLine(double[] xloc, GeoDateArray tloc, String title) {
+    xloc_ = xloc;
+    tloc_ = tloc;
+    title_ = title;
+    xTime_ = false;
+    yTime_ = true;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(tloc_);
+  }
+  /**
+   * Constructor for X double and Y Time.
+   *
+   * @param xloc X coordinates
+   * @param tloc Time coordinates
+   * @param title the Title
+   */
+  public SimpleLine(double[] xloc, GeoDate[] tloc, String title) {
+    xloc_ = xloc;
+    tloc_ = new GeoDateArray(tloc);
+    title_ = title;
+    xTime_ = false;
+    yTime_ = true;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(tloc_);
+  }
+  /**
+   * Create a shallow copy.
+   *
+   * @since 2.0
+   * @see SGTData
+   */
+  public SGTData copy(){
+    SGTLine newLine;
+    try {
+      newLine = (SGTLine)clone();
+    } catch (CloneNotSupportedException e) {
+      newLine = new SimpleLine();
+    }
+    return (SGTData)newLine;
+  }
+  /**
+   * Get the X coordinate array.
+   */
+  public double[] getXArray() {
+    return xloc_;
+  }
+  /**
+   * Get the Y coordinate array.
+   */
+  public double[] getYArray() {
+    return yloc_;
+  }
+  /**
+   * Get the Time coordinate array.
+   */
+  public GeoDate[] getTimeArray() {
+    return tloc_.getGeoDate();
+  }
+  /**
+   * Get the <code>GeoDateArray</code> object.
+   *
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArray() {
+    return tloc_;
+  }
+  /**
+   * Is the X coordinate Time?
+   */
+  public boolean isXTime() {
+    return xTime_;
+  }
+  /**
+   * Is the Y coordinate Time?
+   */
+  public boolean isYTime() {
+    return yTime_;
+  }
+  /**
+   * Get the X coordinate metadata.
+   */
+  public SGTMetaData getXMetaData() {
+    return xMetaData_;
+  }
+  /**
+   * Get the Y coordinate metadata
+   */
+  public SGTMetaData getYMetaData() {
+    return yMetaData_;
+  }
+  /**
+   * Get the Title.
+   */
+  public String getTitle() {
+    return title_;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @since 2.0
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.JPane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  /**
+   * Set the data that will be associated with <code>SGTLine</code>
+   * <BR><B>Property Change:</B> <code>associatedDataModified</code>.
+   *
+   * @since 2.0
+   */
+  public void setAssociatedData(SGTLine assoc) {
+    associatedData_ = assoc;
+    changes_.firePropertyChange("associatedDataModified",
+                                null,
+                                assoc);
+  }
+  /**
+   * Get the associated data.
+   */
+  public SGTLine getAssociatedData() {
+    return associatedData_;
+  }
+  /**
+   * Is there associated data?
+   */
+  public boolean hasAssociatedData() {
+    return (associatedData_ != null);
+  }
+  /**
+   * Set the X coordinate metadata.
+   */
+  public void setXMetaData(SGTMetaData md) {
+    xMetaData_ = md;
+  }
+  /**
+   * Set the Y coordinate metadata.
+   */
+  public void setYMetaData(SGTMetaData md) {
+    yMetaData_ = md;
+  }
+  /**
+   * Set the title.
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  /** Set the title formatted for the <code>VectorKey</code>. */
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Set the X coordinate array.
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setXArray(double[] xloc) {
+    xloc_ = xloc;
+    xTime_ = false;
+    xRange_ = computeSoTRange(xloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(xloc.length));
+  }
+  /**
+   * Set the Y coordinate array
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setYArray(double[] yloc) {
+    yloc_ = yloc;
+    yTime_ = false;
+    yRange_ = computeSoTRange(yloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(yloc.length));
+  }
+  /**
+   * Set the Time coordinate array
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setTimeArray(GeoDate[] tloc) {
+    setTimeArray(new GeoDateArray(tloc));
+  }
+  /**
+   * @since 3.0
+   */
+  public void setTimeArray(GeoDateArray tarray) {
+    tloc_ = tarray;
+    if(xTime_) {
+      xRange_ = computeSoTRange(tarray);
+    } else if(yTime_) {
+      yRange_ = computeSoTRange(tarray);
+    }
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(tarray.getLength()));
+  }
+  public SoTRange getXRange() {
+    return xRange_.copy();
+  }
+  public SoTRange getYRange() {
+    return yRange_.copy();
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+  private SoTRange computeSoTRange(double[] array) {
+    double dstart = Double.POSITIVE_INFINITY;
+    double dend = Double.NEGATIVE_INFINITY;
+    int count = 0;
+    for(int i=0; i < array.length; i++) {
+      if(!Double.isNaN(array[i])) {
+        dstart = Math.min(dstart, array[i]);
+        dend = Math.max(dend, array[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new SoTRange.Double(Double.NaN, Double.NaN);
+    } else {
+      return new SoTRange.Double(dstart, dend);
+    }
+  }
+  private SoTRange computeSoTRange(GeoDateArray tarray) {
+    long tstart = Long.MAX_VALUE;
+    long tend = Long.MIN_VALUE;
+    long[] tar = tarray.getTime();
+    int count = 0;
+    for(int i=0; i < tar.length; i++) {
+      if(!(tar[i] == Long.MAX_VALUE)) {
+        tstart = Math.min(tstart, tar[i]);
+        tend = Math.max(tend, tar[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new SoTRange.Time(Long.MAX_VALUE,
+                               Long.MAX_VALUE);
+    } else {
+      return new SoTRange.Time(tstart, tend);
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimplePoint.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimplePoint.java
new file mode 100755
index 0000000..503d7bd
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimplePoint.java
@@ -0,0 +1,313 @@
+/**
+ * $Id: SimplePoint.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.InvalidMethodError;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTValue;
+
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+
+/**
+ * <code>SimplePoint</code> provides an implementation of the
+ * <code>SGTPoint</code> and <code>Cartesian</code> interfaces.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTPoint
+ * @see Cartesian
+*/
+public class SimplePoint implements SGTPoint, Cartesian, Cloneable, Serializable {
+  protected double xloc_ = Double.NaN;
+  protected double yloc_ = Double.NaN;
+  protected long tloc_;
+  protected boolean xTime_ = false;
+  protected boolean yTime_ = false;
+  protected double value_;
+  protected String title_;
+  protected SGLabel keyTitle_ = null;
+  protected String id_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole value*/
+    protected SGTMetaData valueMetaData_;
+
+  /**
+   * @link aggregation
+   * @clientRole x
+   */
+  protected SGTMetaData xMetaData_;
+
+  /**
+   * @link aggregation
+   * @clientRole y*/
+  protected SGTMetaData yMetaData_;
+  protected boolean hasValue_ = false;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  /**
+   * Default constructor.
+   */
+  public SimplePoint() {
+  }
+  /**
+   * Simple Point constructor.
+   *
+   * @param xloc X coordinate
+   * @param yloc Y coordinate
+   * @param title the title
+   */
+  public SimplePoint(double xloc,double yloc,String title) {
+    xloc_ = xloc;
+    yloc_ = yloc;
+    title_ = title;
+  }
+  /**
+   * Simple Point constructor.
+   *
+   * @since 3.0
+   *
+   * @param loc SoTPoint
+   * @param title the title
+   */
+  public SimplePoint(SoTPoint loc, String title) {
+    xTime_ = loc.isXTime();
+    yTime_ = loc.isYTime();
+    if(xTime_) {
+      tloc_ = loc.getX().getLongTime();
+    } else {
+      xloc_ = ((Number)loc.getX().getObjectValue()).doubleValue();
+    }
+    if(yTime_) {
+      tloc_ = loc.getY().getLongTime();
+    } else {
+      yloc_ = ((Number)loc.getY().getObjectValue()).doubleValue();
+    }
+    title_ = title;
+  }
+  /**
+   * Create a copy.
+   *
+   * @since 2.0
+   * @see SGTData
+   */
+  public SGTData copy() {
+    SGTPoint newPoint;
+    try {
+      newPoint = (SGTPoint)clone();
+    } catch (CloneNotSupportedException e) {
+      newPoint = new SimplePoint();
+    }
+    return (SGTData)newPoint;
+  }
+  /**
+   * Get the X coordinate.
+   */
+  public double getX() {
+    return xloc_;
+  }
+  /**
+   * Get the Y coordinate
+   */
+  public double getY() {
+    return yloc_;
+  }
+  /**
+   * Get the associated value.
+   */
+  public double getValue() {
+    return value_;
+  }
+  /**
+   * Is there an associated value?
+   */
+  public boolean hasValue() {
+    return hasValue_;
+  }
+  /**
+   * Get the time coordinate.
+   */
+  public GeoDate getTime() {
+    return new GeoDate(tloc_);
+  }
+  /**
+   * Get the time in <code>long</code> referenced
+   * to 1970-01-01
+   *
+   * @since 3.0
+   */
+  public long getLongTime() {
+    return tloc_;
+  }
+  /**
+   * Set the time coordinate
+   *
+   * @since 3.0
+   */
+  public void setTime(GeoDate date) {
+    setTime(date.getTime());
+  }
+  /**
+   * @since 3.0
+   */
+  public void setTime(long t) {
+    long old = tloc_;
+    tloc_ = t;
+    changes_.firePropertyChange("dataModified",
+                                new Long(old),
+                                new Long(tloc_));
+  }
+  /**
+   * Is the X coordinate Time?
+   */
+  public boolean isXTime() {
+    return xTime_;
+  }
+  /**
+   * Is the Y coordinate Time?
+   */
+  public boolean isYTime() {
+    return yTime_;
+  }
+  /**
+   * Get the title.
+   */
+  public String getTitle() {
+    return title_;
+  }
+  /**
+   * Set the title.
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  /** Set the title formatted for the <code>VectorKey</code>. */
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @since 2.0
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  /**
+   * Get the associated value SGTMetaData.
+   */
+  public SGTMetaData getValueMetaData() {
+    return valueMetaData_;
+  }
+  /**
+   * Set the X coordinate.
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setX(double xloc) {
+    double old = xloc_;
+    xloc_ = xloc;
+    changes_.firePropertyChange("dataModified",
+                                new Double(old),
+                                new Double(xloc_));
+  }
+  /**
+   * Set the Y coordinate.
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setY(double yloc) {
+    double old = yloc_;
+    yloc_ = yloc;
+    changes_.firePropertyChange("dataModified",
+                                new Double(old),
+                                new Double(yloc_));
+  }
+  /**
+   * The the associated value and basic metadata.
+   * <BR><B>Property Change:</B> <code>associatedDataModified</code>.
+   *
+   * @param value associated data
+   * @param name values name
+   * @param units values units
+   */
+  public void setValue(double value,String name,String units) {
+    double old = value_;
+    value_ = value;
+    valueMetaData_ = new SGTMetaData(name, units);
+    hasValue_ = true;
+    changes_.firePropertyChange("associatedDataModified",
+                                new Double(old),
+                                new Double(value_));
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the x
+   * coordinate
+   *
+   * @since 2.0
+   */
+  public void setXMetaData(SGTMetaData md) {
+    xMetaData_ = md;
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the y
+   * coordinate
+   *
+   * @since 2.0
+   */
+  public void setYMetaData(SGTMetaData md) {
+    yMetaData_ = md;
+  }
+  public SGTMetaData getXMetaData() {
+    return xMetaData_;
+  }
+  public SGTMetaData getYMetaData() {
+    return yMetaData_;
+  }
+  public SoTRange getXRange() {
+    if(xTime_) {
+      return new SoTRange.Time(tloc_, tloc_);
+    } else {
+      return new SoTRange.Double(xloc_, xloc_);
+    }
+  }
+  public SoTRange getYRange() {
+    if(yTime_) {
+      return new SoTRange.Time(tloc_, tloc_);
+    } else {
+      return new SoTRange.Double(yloc_, yloc_);
+    }
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleTuple.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleTuple.java
new file mode 100755
index 0000000..1b9a5d8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/SimpleTuple.java
@@ -0,0 +1,370 @@
+/*
+ * $Id: SimpleTuple.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.GeoDateArray;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.Range2D;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.Serializable;
+/**
+ * <code>SimpleTuple</code> provides an implementation of the
+ * <code>SGTTuple</code> and <code>Cartesian</code> interfaces.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.x
+ * @see SGTTuple
+ * @see Cartesian
+ */
+public class SimpleTuple implements Cloneable, SGTTuple, Cartesian, Serializable {
+  private boolean xTime_ = false;
+  private boolean yTime_ = false;
+  private String title_ = null;
+  private SGLabel keyTitle_ = null;
+  private String id_ = null;
+  private double[] xArray_ = null;
+  private double[] yArray_ = null;
+//  private GeoDate[] tArray_ = null;
+  private GeoDateArray tArray_ = null;
+  private double[] zArray_ = null;
+  private double[] assocArray_ = null;
+
+  /**
+   * @link aggregation
+   * @clientRole x
+   */
+  protected SGTMetaData xMetaData_ = null;
+
+  /**
+   * @link aggregation
+   * @clientRole y
+   */
+  protected SGTMetaData yMetaData_ = null;
+
+  /**
+   * @link aggregation
+   * @clientRole z*/
+  protected SGTMetaData zMetaData_ = null;
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private Range2D zRange_ = null;
+
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+
+    public SimpleTuple(double[] xArray, double[] yArray, String title) {
+      xArray_ = xArray;
+      yArray_ = yArray;
+      xTime_ = false;
+      yTime_ = false;
+      title_ = title;
+      xRange_ = computeSoTRange(xArray);
+      yRange_ = computeSoTRange(yArray);
+    }
+
+    public SimpleTuple(GeoDate[] xArray, double[] yArray, String title) {
+      tArray_ = new GeoDateArray(xArray);
+      yArray_ = yArray;
+      xTime_ = true;
+      yTime_ = false;
+      title_ = title;
+      xRange_ = computeSoTRange(tArray_);
+      yRange_ = computeSoTRange(yArray);
+    }
+
+    public SimpleTuple(double[] xArray, GeoDate[] yArray, String title) {
+      xArray_ = xArray;
+      tArray_ = new GeoDateArray(yArray);
+      xTime_ = false;
+      yTime_ = true;
+      title_ = title;
+      xRange_ = computeSoTRange(xArray);
+      yRange_ = computeSoTRange(tArray_);
+    }
+
+    public SimpleTuple(double[] xArray, double[] yArray,
+                       double[] zArray, String title) {
+      xArray_ = xArray;
+      yArray_ = yArray;
+      zArray_ = zArray;
+      xTime_ = false;
+      yTime_ = false;
+      title_ = title;
+      xRange_ = computeSoTRange(xArray);
+      yRange_ = computeSoTRange(yArray);
+      zRange_ = computeRange2D(zArray);
+    }
+
+    public SimpleTuple(GeoDate[] xArray, double[] yArray,
+                       double[] zArray, String title) {
+      tArray_ = new GeoDateArray(xArray);
+      yArray_ = yArray;
+      zArray_ = zArray;
+      xTime_ = true;
+      yTime_ = false;
+      title_ = title;
+      xRange_ = computeSoTRange(tArray_);
+      yRange_ = computeSoTRange(yArray);
+      zRange_ = computeRange2D(zArray);
+    }
+
+    public SimpleTuple(double[] xArray, GeoDate[] yArray,
+                       double[] zArray, String title) {
+      xArray_ = xArray;
+      tArray_ = new GeoDateArray(yArray);
+      zArray_ = zArray;
+      xTime_ = false;
+      yTime_ = true;
+      title_ = title;
+      xRange_ = computeSoTRange(xArray);
+      yRange_ = computeSoTRange(tArray_);
+      zRange_ = computeRange2D(zArray);
+    }
+
+  public SimpleTuple() {
+    xTime_ = false;
+    yTime_ = false;
+  }
+
+  public double[] getXArray() {
+    return xArray_;
+  }
+
+  public void setXArray(double[] xArray) {
+    xArray_ = xArray;
+    xTime_ = false;
+    xRange_ = computeSoTRange(xArray);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(xArray.length));
+  }
+
+  public void setXArray(GeoDate[] tArray) {
+    setXArray(new GeoDateArray(tArray));
+  }
+  /**
+   * @since 3.0
+   */
+  public void setXArray(GeoDateArray tArray) {
+    tArray_ = tArray;
+    xTime_ = true;
+    xArray_ = null;
+    xRange_ = computeSoTRange(tArray);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(tArray.getLength()));
+  }
+
+  public double[] getYArray() {
+    return yArray_;
+  }
+
+  public void setYArray(double[] yArray) {
+    yArray_ = yArray;
+    yTime_ = false;
+    yRange_ = computeSoTRange(yArray);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(yArray.length));
+  }
+
+  public void setYArray(GeoDate[] tArray) {
+    setYArray(new GeoDateArray(tArray));
+  }
+  /**
+   * @since 3.0
+   */
+  public void setYArray(GeoDateArray tArray) {
+    tArray_ = tArray;
+    yTime_ = true;
+    yArray_ = null;
+    yRange_ = computeSoTRange(tArray);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(tArray.getLength()));
+  }
+  public double[] getZArray() {
+    return zArray_;
+  }
+
+  public void setZArray(double[] zArray) {
+    zArray_ = zArray;
+    zRange_ = computeRange2D(zArray);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(zArray.length));
+  }
+
+  public int getSize() {
+    if(xTime_) {
+      return tArray_.getLength();
+    } else {
+      return xArray_.length;
+    }
+  }
+
+  public GeoDate[] getTimeArray() {
+    return tArray_.getGeoDate();
+  }
+  /**
+   * @since 3.0
+   */
+  public GeoDateArray getGeoDateArray() {
+    return tArray_;
+  }
+
+  public double[] getAssociatedData() {
+    return assocArray_;
+  }
+
+  public void setAssociatedData(double[] assocArray) {
+    assocArray_ = assocArray;
+  }
+
+  public boolean hasAssociatedData() {
+    return (assocArray_ != null);
+  }
+
+  public SGTMetaData getZMetaData() {
+    return zMetaData_;
+  }
+
+  public void setZMetaData(SGTMetaData zMeta) {
+    zMetaData_ = zMeta;
+  }
+
+  public String getTitle() {
+    return title_;
+  }
+
+  public void setTitle(String title) {
+    title_ = title;
+  }
+
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+
+  public String getId() {
+    return id_;
+  }
+
+  public void setId(String id) {
+    id_ = id;
+  }
+
+  public SGTData copy() {
+    SGTTuple newTuple;
+    try {
+      newTuple = (SGTTuple)clone();
+    } catch (CloneNotSupportedException e) {
+      newTuple = new SimpleTuple();
+    }
+    return (SGTData)newTuple;
+  }
+
+  public boolean isXTime() {
+    return xTime_;
+  }
+
+  public boolean isYTime() {
+    return yTime_;
+  }
+
+  public SGTMetaData getXMetaData() {
+    return xMetaData_;
+  }
+
+  public void setXMetaData(SGTMetaData xMeta) {
+    xMetaData_ = xMeta;
+  }
+
+  public SGTMetaData getYMetaData() {
+    return yMetaData_;
+  }
+
+  public void setYMetaData(SGTMetaData yMeta) {
+    yMetaData_ = yMeta;
+  }
+
+  public SoTRange getXRange() {
+    return xRange_;
+  }
+
+  public SoTRange getYRange() {
+    return yRange_;
+  }
+
+  public Range2D getZRange() {
+    return zRange_;
+  }
+
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+
+  private SoTRange computeSoTRange(double[] array) {
+    Range2D range = computeRange2D(array);
+    return new SoTRange.Double(range.start, range.end);
+  }
+
+  private SoTRange computeSoTRange(GeoDateArray tarray) {
+    long start = Long.MAX_VALUE;
+    long end = Long.MIN_VALUE;
+    long[] tar = tarray.getTime();
+    int count = 0;
+    for(int i=0; i < tar.length; i++) {
+      if(!(tar[i] == Long.MAX_VALUE)) {
+        start = Math.min(start, tar[i]);
+        end = Math.max(end, tar[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new SoTRange.Time(Long.MAX_VALUE,
+                               Long.MAX_VALUE);
+    } else {
+      return new SoTRange.Time(start, end);
+    }
+  }
+
+  private Range2D computeRange2D(double[] array) {
+    double start = Double.POSITIVE_INFINITY;
+    double end = Double.NEGATIVE_INFINITY;
+    int count = 0;
+    for(int i=0; i < array.length; i++) {
+      if(!Double.isNaN(array[i])) {
+        start = Math.min(start, array[i]);
+        end = Math.max(end, array[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new Range2D(Double.NaN, Double.NaN);
+    } else {
+      return new Range2D(start, end);
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/ThreeDGrid.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/ThreeDGrid.java
new file mode 100755
index 0000000..083d52a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/ThreeDGrid.java
@@ -0,0 +1,584 @@
+/**
+ * $Id: ThreeDGrid.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.dm;
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.SoTRange;
+
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+
+/**
+ * <code>ThreeDGrid</code> provides an implementation of the
+ * <code>SGT3DGrid</code> and <code>Cartesian</code> interfaces.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 1.0
+ * @see SGTGrid
+ * @see Cartesian
+ */
+public class ThreeDGrid implements SGT3DGrid, Cartesian, Cloneable, Serializable {
+  protected double[] xloc_;
+  protected double[] yloc_;
+  protected double[] zloc_;
+  protected GeoDate[] tloc_;
+  protected double[] grid_;
+  protected double[] xEdges_;
+  protected double[] yEdges_;
+  protected double[] zEdges_;
+  protected GeoDate[] tEdges_;
+  protected boolean hasXEdges_;
+  protected boolean hasYEdges_;
+  protected boolean hasZEdges_;
+  protected String title_;
+  protected SGLabel keyTitle_ = null;
+  protected String id_ = null;
+  protected boolean xTime_;
+  protected boolean yTime_;
+  protected boolean zTime_;
+    /**@shapeType AggregationLink
+  * @clientRole x*/
+    protected SGTMetaData xMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole y*/
+    protected SGTMetaData yMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole z*/
+    protected SGTMetaData zMetaData_ = null;
+    /**@shapeType AggregationLink
+  * @clientRole associated data*/
+    protected SGTMetaData valMetaData_ = null;
+    protected SGTGrid associatedData_;
+  private SoTRange xRange_ = null;
+  private SoTRange yRange_ = null;
+  private SoTRange zRange_ = null;
+  private SoTRange xEdgesRange_ = null;
+  private SoTRange yEdgesRange_ = null; 
+  private SoTRange zEdgesRange_ = null;
+  private Range2D valRange_ = null;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+
+  /**
+   * Default constructor.
+   */
+  public ThreeDGrid() {
+    //this(null, (double[])null, (double[])null, (double[])null, "");
+  }
+  
+  /**
+   * Constructor for X, Y, and Z coordinates as double.
+   *
+   * @param grid Z values
+   * @param xloc X coordinates
+   * @param yloc Y coordinates
+   * @param zloc Z coordinates
+   * @param title the title
+   */
+  public ThreeDGrid(double[] grid, double[] xloc,
+                    double[] yloc, double[] zloc, String title) {
+    grid_ = grid;
+    xloc_ = xloc;
+    yloc_ = yloc;
+    zloc_ = zloc;
+    title_ = title;
+    xTime_ = false;
+    yTime_ = false;
+    zTime_ = false;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    hasZEdges_ = false;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(yloc);
+    zRange_ = computeSoTRange(yloc);
+    valRange_ = computeRange2D(grid);
+  }
+  
+  /**
+   * Constructor for X time and Y, Z double.
+   *
+   * @param grid values
+   * @param tloc Time coordinates
+   * @param yloc Y coordinates
+   * @param zloc Z coordinates
+   * @param title the title
+   */
+  public ThreeDGrid(double[] grid, GeoDate[] tloc,
+                    double[] yloc, double[] zloc, String title) {
+    grid_ = grid;
+    tloc_ = tloc;
+    yloc_ = yloc;
+    zloc_ = zloc;
+    title_ = title;
+    xTime_ = true;
+    yTime_ = false;
+    zTime_ = false;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    hasZEdges_ = false;
+    xRange_ = computeSoTRange(tloc);
+    yRange_ = computeSoTRange(yloc);
+    zRange_ = computeSoTRange(zloc);
+    valRange_ = computeRange2D(grid);
+  }
+  /**
+   * Constructor for X, Z double and Y time.
+   *
+   * @param grid values
+   * @param xloc X coordinates
+   * @param xloc Z coordinates
+   * @param tloc Time coordinates
+   * @param title the title
+   */
+  public ThreeDGrid(double[] grid, double[] xloc,
+                    GeoDate[] tloc,double[] zloc, String title) {
+    grid_ = grid;
+    xloc_ = xloc;
+    tloc_ = tloc;
+    zloc_ = zloc;
+    title_ = title;
+    xTime_ = false;
+    yTime_ = true;
+    zTime_ = false;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    hasZEdges_ = false;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(tloc);
+    zRange_ = computeSoTRange(zloc);
+    valRange_ = computeRange2D(grid);
+  }
+  
+  /**
+   * Constructor for X double and Y double, and Z time.
+   *
+   * @param grid Z values
+   * @param xloc X coordinates
+   * @param tloc Time coordinates
+   * @param title the title
+   */
+  public ThreeDGrid(double[] grid, double[] xloc,
+                    double[] yloc, GeoDate[] tloc, String title) {
+    grid_ = grid;
+    xloc_ = xloc;
+    yloc_ = yloc;
+    tloc_ = tloc;
+    title_ = title;
+    xTime_ = false;
+    yTime_ = false;
+    zTime_ = true;
+    hasXEdges_ = false;
+    hasYEdges_ = false;
+    hasZEdges_ = false;
+    xRange_ = computeSoTRange(xloc);
+    yRange_ = computeSoTRange(yloc);
+    zRange_ = computeSoTRange(tloc);
+    valRange_ = computeRange2D(grid);
+  }
+  
+  /**
+   * Create a copy of the grid.
+   *
+   * @since 2.0
+   * @see SGTData
+   */
+  public SGTData copy() {
+    SGT3DGrid newGrid;
+    try {
+      newGrid = (SGT3DGrid)clone();
+    } catch (CloneNotSupportedException e) {
+      newGrid = new ThreeDGrid();
+    }
+    return (SGTData)newGrid;
+  }
+  
+  public double[] getXArray() {
+    return xloc_;
+  }
+  
+  /**
+   * Get the length of the x axis
+   *
+   * @since 2.0
+   */
+  public int getXSize() {
+    return xloc_.length;
+  }
+  
+  public double[] getYArray() {
+    return yloc_;
+  }
+  /**
+   * Get the length of the y axis
+   *
+   * @since 2.0
+   */
+   
+  public int getYSize() {
+    return yloc_.length;
+  }
+  
+  public double[] getZArray() {
+    return zloc_;
+  }
+  
+  public int getZSize() {
+    return zloc_.length;
+  }
+  
+  public double[] getValArray() {
+    return grid_;
+  }
+  
+  public int getValArraySize() {
+    return grid_.length;
+  }
+  
+  public GeoDate[] getTimeArray() {
+    return tloc_;
+  }
+  /**
+   * Get the length of the Time axis
+   *
+   * @since 2.0
+   */
+  public int getTSize() {
+    return tloc_.length;
+  }
+  public boolean isXTime() {
+    return xTime_;
+  }
+  public boolean isYTime() {
+    return yTime_;
+  }
+  public boolean isZTime() {
+    return zTime_;
+  }
+  public void setXTime(boolean flag) {
+    xTime_ = flag;
+  }
+  public void setYTime(boolean flag) {
+    yTime_= flag;
+  }
+  public void setZTime(boolean flag) {
+    zTime_= flag;
+  }
+  public SGTMetaData getXMetaData() {
+    return xMetaData_;
+  }
+  public SGTMetaData getYMetaData() {
+    return yMetaData_;
+  }
+  public SGTMetaData getZMetaData() {
+    return zMetaData_;
+  }
+  public SGTMetaData getValMetaData() {
+    return valMetaData_;
+  }
+  public String getTitle() {
+    return title_;
+  }
+  /**
+   * Set the associated data grid.
+   * <BR><B>Property Change:</B> <code>associatedDataModified</code>.
+   *
+   * @since 2.0
+   */
+  public void setAssociatedData(SGTGrid assoc) {
+    associatedData_ = assoc;
+    changes_.firePropertyChange("associatedDataModified",
+                                null,
+                                assoc);
+  }
+  public SGTGrid getAssociatedData() {
+    return associatedData_;
+  }
+  public boolean hasAssociatedData() {
+    return (associatedData_ != null);
+  }
+  public boolean hasXEdges() {
+    return hasXEdges_;
+  }
+  public double[] getXEdges() {
+    return xEdges_;
+  }
+  
+  public boolean hasZEdges() {
+    return hasZEdges_;
+  }
+  /**
+   * Set the values for the z grid edges.
+   */
+  public void setZEdges(double[] edge) {
+    zEdges_ = edge;
+    hasZEdges_ = true;
+    zEdgesRange_ = computeSoTRange(edge);
+  }
+  
+  public double[] getZEdges() {
+    return zEdges_;
+  }
+  /**
+   * Set the values for the x grid edges.
+   */
+  public void setXEdges(double[] edge) {
+    xEdges_ = edge;
+    hasXEdges_ = true;
+    xEdgesRange_ = computeSoTRange(edge);
+  }
+  public boolean hasYEdges() {
+    return hasYEdges_;
+  }
+  public double[] getYEdges() {
+    return yEdges_;
+  }
+  /**
+   * Set the values for the y grid edges.
+   */
+  public void setYEdges(double[] edge) {
+    yEdges_ = edge;
+    hasYEdges_ = true;
+    yEdgesRange_ = computeSoTRange(edge);
+  }
+  public GeoDate[] getTimeEdges() {
+    return tEdges_;
+  }
+  /**
+   * Set the values for the temporal grid edges.
+   */
+  public void setTimeEdges(GeoDate[] edge) {
+    tEdges_ = edge;
+    if (xTime_) {
+      hasXEdges_ = true;
+      xEdgesRange_ = computeSoTRange(edge);
+    } 
+    else if(yTime_){
+      hasYEdges_ = true;
+      yEdgesRange_ = computeSoTRange(edge);
+    }
+    else if(zTime_){
+      hasZEdges_ = true;
+      zEdgesRange_ = computeSoTRange(edge);
+    }
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the x
+   * coordinate.
+   */
+  public void setXMetaData(SGTMetaData md) {
+    xMetaData_ = md;
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the y
+   * coordinate.
+   */
+  public void setYMetaData(SGTMetaData md) {
+    yMetaData_ = md;
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the z
+   * coordinate.
+   */
+  public void setZMetaData(SGTMetaData md) {
+    zMetaData_ = md;
+  }
+  /**
+   * Set the <code>SGTMetaData</code> associated with the z
+   * coordinate.
+   */
+  public void setValMetaData(SGTMetaData md) {
+    valMetaData_ = md;
+  }
+  /**
+   * Set the grid title
+   */
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public SGLabel getKeyTitle() {
+    return keyTitle_;
+  }
+  /** Set the title formatted for the <code>VectorKey</code>. */
+  public void setKeyTitle(SGLabel title) {
+    keyTitle_ = title;
+  }
+  /**
+   * Get the unique identifier.  The presence of the identifier
+   * is optional, but if it is present it should be unique.  This
+   * field is used to search for the layer that contains the data.
+   *
+   * @since 2.0
+   * @return unique identifier
+   * @see gov.noaa.pmel.sgt.Pane
+   * @see gov.noaa.pmel.sgt.Layer
+   */
+  public String getId() {
+    return id_;
+  }
+  /**
+   * Set the unique identifier.
+   */
+  public void setId(String ident) {
+    id_ = ident;
+  }
+  /**
+   * Set the x coordinate grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setXArray(double[] xloc) {
+    xloc_ = xloc;
+    xTime_ = false;
+    xRange_ = computeSoTRange(xloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(xloc.length));
+  }
+  /**
+   * Set the y coordinate grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setYArray(double[] yloc) {
+    yloc_ = yloc;
+    yTime_ = false;
+    yRange_ = computeSoTRange(yloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(yloc.length));
+  }
+  /**
+   * Set the z coordinate grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setZArray(double[] zloc) {
+    zloc_ = zloc;
+    zTime_ = false;
+    zRange_ = computeSoTRange(zloc);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(zloc.length));
+  }
+  /**
+   * Set the z grid values.
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setValArray(double[] grid) {
+    grid_ = grid;
+    valRange_ = computeRange2D(grid);
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(grid.length));
+  }
+  /**
+   * set the temporal grid centers
+   * <BR><B>Property Change:</B> <code>dataModified</code>.
+   */
+  public void setTimeArray(GeoDate[] tloc) {
+    tloc_ = tloc;
+    if (xTime_) {
+      xRange_ = computeSoTRange(tloc);
+    } 
+    else if(yTime_) {
+      yRange_ = computeSoTRange(tloc);
+    }
+    else if(zTime_) {
+      zRange_ = computeSoTRange(tloc);
+    }
+    changes_.firePropertyChange("dataModified",
+                                new Integer(0),
+                                new Integer(tloc.length));
+  }
+  public SoTRange getXRange() {
+    return xRange_.copy();
+  }
+  public SoTRange getYRange() {
+    return yRange_.copy();
+  }
+  public SoTRange getZRange() {
+    return zRange_.copy();
+  }
+  public Range2D getValRange() {
+    return valRange_;
+  }
+  /**
+   * Return the range of the x edges
+   *
+   * @since 2.0
+   */
+  public SoTRange getXEdgesRange() {
+    return xEdgesRange_;
+  }
+  /**
+   * Return the range of the y edges
+   *
+   * @since 2.0
+   */
+  public SoTRange getYEdgesRange() {
+    return yEdgesRange_;
+  }
+  
+  public SoTRange getZEdgesRange() {
+    return zEdgesRange_;
+  }
+
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+
+  private SoTRange computeSoTRange(double[] array) {
+    Range2D range = computeRange2D(array);
+    return new SoTRange.Double(range.start, range.end);
+  }
+  private SoTRange computeSoTRange(GeoDate[] tarray) {
+    long start = Long.MAX_VALUE;
+    long end = Long.MIN_VALUE;
+    long value;
+    int count = 0;
+    for(int i=0; i < tarray.length; i++) {
+      if(!(tarray[i] == null || tarray[i].isMissing())) {
+        value = tarray[i].getTime();
+        start = Math.min(start, value);
+        end = Math.max(end, value);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new SoTRange.GeoDate(new GeoDate(Long.MIN_VALUE),
+                                  new GeoDate(Long.MAX_VALUE));
+    } else {
+      return new SoTRange.GeoDate(new GeoDate(start), new GeoDate(end));
+    }
+  }
+  private Range2D computeRange2D(double[] array) {
+    double start = Double.POSITIVE_INFINITY;
+    double end = Double.NEGATIVE_INFINITY;
+    int count = 0;
+    for(int i=0; i < array.length; i++) {
+      if(!Double.isNaN(array[i])) {
+        start = Math.min(start, array[i]);
+        end = Math.max(end, array[i]);
+        count++;
+      }
+    }
+    if(count == 0) {
+      return new Range2D(Double.NaN, Double.NaN);
+    } else {
+      return new Range2D(start, end);
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/package.html
new file mode 100755
index 0000000..660d1e4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/dm/package.html
@@ -0,0 +1,14 @@
+<HTML>
+<BODY>
+Classes and interfaces that define the sgt datamodel.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/overview.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/overview.html
new file mode 100755
index 0000000..54fde6d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/overview.html
@@ -0,0 +1,46 @@
+<HTML>
+<BODY>
+<P>The Scientific Graphics Toolkit (<b>SGT</b>) is designed
+to allow a graphics client developer a great deal of flexibility and
+freedom. <CODE>sgt</CODE> is a package that greatly aids a developer
+in creating graphics applets. <CODE>sgt</CODE> is not a general
+purpose graphics package, but provides the tools to enable scientific
+graphics to be easily incorporated into applications or 
+<code>Applets</code>.</P>
+
+<P>SGT has three main components, the {@link gov.noaa.pmel.sgt.JPane JPane}, 
+on which all graphics are drawn. The 
+{@link gov.noaa.pmel.sgt.Layer Layer}, of which several can be
+associated with a single <CODE>JPane</CODE>, that insulates the
+developer from device coordinates.  And the 
+{@link gov.noaa.pmel.sgt.Graph Graph}, of
+which a single instance can be associated with a <CODE>Layer</CODE>,
+that transforms form user coordinates (e.g. cm/sec, time, etc) to the
+layer coordinate system (physical coordinates).
+
+<P>Examples demonstrating the use of SGT are available in the {@link
+gov.noaa.pmel.sgt.demo demo} package.  These examples show how to
+create SGT applications from scratch and how to use the {@link
+gov.noaa.pmel.sgt.swing.JPlotLayout JPlotLayout} utility class.  A <A
+href="http://www.epic.noaa.gov/talks/dwd/noaatech2002/SGT_Tutorial_files/v3_document.htm">tutorial
+</A> on using SGT to develop interactive graphics is now available.
+
+<P>The gov.noaa.pmel.sgt.awt and gov.noaa.pmel.sgt.util packages have
+been deprecated.  The functionality in gov.noaa.pmel.sgt.swing and
+gov.noaa.pmel.sgt.swing.prop completely replaces the deprecated
+classes. 
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+
+ at see gov.noaa.pmel.sgt.JPane
+ at see gov.noaa.pmel.sgt.Layer 
+ at see gov.noaa.pmel.sgt.Graph
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/package.html
new file mode 100755
index 0000000..dbd23de
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/package.html
@@ -0,0 +1,43 @@
+<HTML>
+<BODY>
+Core classes for the Scientific Graphics Toolkit.
+
+<P>The Java Scientific Graphics Toolkit (<CODE>sgt</CODE>) is designed
+to allow a graphics client developer a great deal of flexibility and
+freedom. <CODE>sgt</CODE> is a package that greatly aids a developer
+in creating graphics applets. <CODE>sgt</CODE> is not a general
+purpose graphics package, but provides the tools to enable scientific
+graphics to be easily incorporated into applications or
+<code>Applets</code>.</P>
+
+<P>SGT has three main components, the <CODE>JPane</CODE>, on which all
+graphics are drawn. The <CODE>Layer</CODE>, of which several can be
+associated with a single <CODE>JPane</CODE>, that insulates the
+developer from device coordinates.  And the <CODE>Graph</CODE>, of
+which a single instance can be associated with a <CODE>Layer</CODE>,
+that transforms form user coordinates (e.g. cm/sec, time, etc) to the
+layer coordinate system (physical coordinates).
+
+<P>Examples demonstrating the use of SGT are available in the {@link
+gov.noaa.pmel.sgt.demo demo} package.  These examples show how to
+create SGT applications from scratch and how to use the {@link
+gov.noaa.pmel.sgt.swing.JPlotLayout JPlotLayout} utility class.  A <A
+href="http://www.epic.noaa.gov/talks/dwd/noaatech2002/SGT_Tutorial_files/v3_document.htm">tutorial
+</A> on using SGT to develop interactive graphics is now available.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+
+ at see gov.noaa.pmel.sgt.Pane
+ at see gov.noaa.pmel.sgt.JPane
+ at see gov.noaa.pmel.sgt.Layer 
+ at see gov.noaa.pmel.sgt.Graph
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/DragNDropManager.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/DragNDropManager.java
new file mode 100755
index 0000000..234b767
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/DragNDropManager.java
@@ -0,0 +1,19 @@
+/*
+ * $Id: DragNDropManager.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.plot;
+
+/**
+ * @since 2.x
+ */
+public class DragNDropManager {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/JPlotPane.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/JPlotPane.java
new file mode 100755
index 0000000..4e68d92
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/JPlotPane.java
@@ -0,0 +1,59 @@
+/*
+ * $Id: JPlotPane.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.plot;
+
+import gov.noaa.pmel.sgt.JPane;
+import java.util.Vector;
+import gov.noaa.pmel.sgt.LayerStack;
+
+/**
+ * @since 2.x
+ */
+public class JPlotPane extends JPane {
+  /**
+   * @undirected
+   * @link aggregation 
+   * @label currentMode
+   */
+  private PlotPaneMode currentMode_;
+
+  /**
+   * @link aggregationByValue
+   * @undirected
+   * @label layerManager 
+   */
+  private PlotLayerManager layerManager_;
+
+  /**
+   * @link aggregationByValue
+   * @undirected
+   * @label printManager 
+   */
+  private PrintManager printManager_;
+
+  /**
+   * @link aggregationByValue
+   * @undirected
+   * @label dragNDropManager 
+   */
+  private DragNDropManager dragNDropManager_;
+
+  /**
+   *@link aggregation
+   *     @associates <{LayerStack}>
+   * @undirected
+   * @supplierCardinality 1..*
+   * @label layerStack
+   */
+  private Vector layerStack_;
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/Notes.txt b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/Notes.txt
new file mode 100755
index 0000000..032994c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/Notes.txt
@@ -0,0 +1,51 @@
+			   JPlotPane Notes
+
+			      11/30/2000
+
+* Create JPlotPane
+  1) create and initealizes managers. (Print, DnD, Layer, ...)
+  2) other initialization efforts.
+  3) clear pane?
+
+* addData(SGTData, PlotLayerHints) to JPlotPane
+  1) create PlotLayer (data, hints)
+     - create Graph
+     - create Renderer and bind data
+  2) invoke PlotLayerManager
+      as newLayer(PlotLayer) or reLayout() <-  is this needed?
+
+      - if newLayer
+	+ get X-Y types (space/time, units)
+	+ using hints match with existing LayerStack
+	+ if needed create new LayerStack & add to JPlotPane
+	  else find stack to add layer to...
+	+ create new transform if needed or bind to existing transform
+	+ create new axes if needed
+
+      - if modified Layer
+	+ check for X-Y axes owner
+	+ check for transforms
+	+ update Key
+	  (once a PlotLayer is assigned to a LayerStack it
+	   stays there unless explictly moved)
+
+* hints (should hints include values?)
+  1) Keys  (location- on layer, new layer, table, popup; position)
+  2) Transforms (scale/offset, share, new)
+  3) Axes (share, new, location)
+  4) PlotLayer ...
+
+* modes
+  1) Zoom
+  2) Object Select
+  3) Data Select
+  4) Layer DnD (LayerStack is DnD client/server?)
+  5) Default (none? Zoom?)
+
+
+* LayerManager
+  1) LayerManager should have its rules about what can be overlayed!
+     For example, raster grid should not be over a contour grid! 
+  2) LayerManager should be able to re-order the Layers in a
+     LayerStack?
+ 
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayer.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayer.java
new file mode 100755
index 0000000..b7d3f42
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayer.java
@@ -0,0 +1,34 @@
+/*
+ * $Id: PlotLayer.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.plot;
+
+import gov.noaa.pmel.sgt.Layer;
+/**
+ * @since 2.x
+ */
+public class PlotLayer extends Layer {
+  public PlotLayerHints getPlotLayerHints(){
+      return plotLayerHints_;
+    }
+
+  public void setPlotLayerHints(PlotLayerHints plotLayerHints){
+      this.plotLayerHints_ = plotLayerHints;
+    }
+
+  /**
+   * @link aggregation
+   * @undirected
+   * @label plotLayerHints 
+   */
+  private PlotLayerHints plotLayerHints_;
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayerHints.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayerHints.java
new file mode 100755
index 0000000..0898c6c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayerHints.java
@@ -0,0 +1,287 @@
+/*
+ * $Id: PlotLayerHints.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.plot;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * @since 2.x
+ */
+public class PlotLayerHints implements Map, Cloneable {
+  HashMap hintmap = new HashMap(5);
+
+  /**
+   * PlotKey Type hint key
+   */
+  public static final String KEY_PLOTKEY_TYPE = "PlotKeyType";
+  /**
+   * PlotKey Type hint values -- on layer
+   */
+  public static final String VALUE_PLOTKEY_ON_LAYER = "OnLayer";
+  /**
+   * PlotKey Type hint values -- on seperate layer
+   */
+  public static final String VALUE_PLOTKEY_ON_SEPERATE_LAYER = "OnSeperateLayer";
+  /**
+   * PlotKey Type hint values -- in pop-up window
+   */
+  public static final String VALUE_PLOTKEY_IN_POPUP = "InPopUp";
+  /**
+   * PlotKey Type hint values -- in JTable
+   */
+  public static final String VALUE_PLOTKEY_IN_TABLE = "InTable";
+  /**
+   * PlotKey Type hint values -- no key
+   */
+  public static final String VALUE_PLOTKEY_NONE = "None";
+
+  /**
+   * PlotKey location hint key
+   */
+  public static final String KEY_PLOTKEY_LOCATION = "PlotKeyLocation";
+
+  /**
+   * Layer Placement hint key
+   */
+  public static final String KEY_LAYER_PLACEMENT = "LayerPlacement";
+  /**
+   * Layer Placement hint values -- overlay
+   */
+  public static final String VALUE_LAYER_PLACEMENT_OVERLAY = "Overlay";
+
+  /**
+   * AspectRatio hint key
+   */
+  public static final String KEY_ASPECT_RATIO = "AspectRatio";
+  /**
+   * AspecRatio hint values -- lock X and Y scales
+   */
+  public static final String VALUE_ASPECT_RATIO_LOCK = "Lock";
+  /**
+   * AspecRatio hint values -- dont lock X and Y scales (during resize)
+   */
+  public static final String VALUE_ASPECT_RATIO_NO_LOCK = "NoLock";
+
+  /**
+   * Axis location should actually go through a series of steps
+   *
+   * X Axis Location
+   * 1) bottom of plot region
+   * 2) top of plot region
+   * 3) below bottom axis (increase border if needed)
+   * 4) above top axis (increase border if needed)
+   *
+   * Y Axis Locations
+   * 1) left of plot region
+   * 2) right of plot region
+   * 3) outside left axis (increase border if needed)
+   * 4) outside right axis (increase border if needed)
+   *
+   *
+   * X Axis Location hint key
+   */
+  public static final String KEY_X_AXIS_LOCATION = "XAxisLocation";
+  /**
+   * X Axis Location hint values -- default
+   * First try bottom, top, below bottom, then above top
+   */
+  public static final String VALUE_X_AXIS_LOCATION_DEFAULT = "Default";
+  /**
+   * X Axis Location hint values -- bottom
+   */
+  public static final String VALUE_X_AXIS_LOCATION_BOTTOM = "Bottom";
+  /**
+   * X Axis Location hint values -- top
+   */
+  public static final String VALUE_X_AXIS_LOCATION_TOP = "Top";
+
+  /**
+   * Y Axis Location hint key
+   */
+  public static final String KEY_Y_AXIS_LOCATION = "YAxis Location";
+  /**
+   * Y Axis Location hint values -- default
+   * First try left, right, outside right, then outside left
+   */
+  public static final String VALUE_Y_AXIS_LOCATION_DEFAULT = "Default";
+  /**
+   * Y Axis Location hint values -- left
+   */
+  public static final String VALUE_Y_AXIS_LOCATION_LEFT = "Left";
+  /**
+   * Y Axis Location hint values -- right
+   */
+  public static final String VALUE_Y_AXIS_LOCATION_RIGHT = "Right";
+
+  /**
+   * Decision to create a new transform or re-use an existing
+   * transform should follow the following steps
+   *
+   * 1) Use transform from same LayerStack
+   * 2) Use transform from same JPlotPane
+   * 3) Create a new transform
+   *
+   * to use existing transform
+   * 1) both must be space or both time (test cant be defeated)
+   * 2) must have units that are convertable to existing transform
+   * 3) must have identical units
+   *
+   *
+   * X Transform hint key
+   */
+  public static final String KEY_X_TRANSFORM = "XTransform";
+  /**
+   * X Transform hint values -- default
+   * First try LayerStack, JPlotPane, then create new transform
+   */
+  public static final String VALUE_X_TRANSFORM_DEFAULT = "Default";
+  /**
+   * X Transform hint values -- new
+   */
+  public static final String VALUE_X_TRANSFORM_NEW = "New";
+  /**
+   * X Transform hint values -- use JPlotPane
+   */
+  public static final String VALUE_X_TRANSFORM_USEPLOTPANE = "UsePlotPane";
+
+  /**
+   * Y Transform hint key
+   */
+  public static final String KEY_Y_TRANSFORM = "YTransform";
+  /**
+   * Y Transform hint values -- default
+   * First try LayerStack, JPlotPane, then create new transform
+   */
+  public static final String VALUE_Y_TRANSFORM_DEFAULT = "Default";
+  /**
+   * Y Transform hint values -- new
+   */
+  public static final String VALUE_Y_TRANSFORM_NEW = "New";
+  /**
+   * Y Transform hint values -- use JPlotPane
+   */
+  public static final String VALUE_Y_TRANSFORM_USEPLOTPANE = "UsePlotPane";
+
+  public PlotLayerHints(Map init) {
+    if(init != null) {
+      hintmap.putAll(init);
+    }
+  }
+
+  public PlotLayerHints(String key, String value) {
+    hintmap.put(key, value);
+  }
+
+  public int size() {
+    return hintmap.size();
+  }
+
+  public boolean isEmpty() {
+    return hintmap.isEmpty();
+  }
+
+  public boolean containsKey(Object key) {
+    return hintmap.containsKey((String)key);
+  }
+
+  public boolean containsValue(Object value) {
+    return hintmap.containsValue((String)value);
+  }
+
+  public Object get(Object key) {
+    return hintmap.get((String)key);
+  }
+
+  public Object put(Object key, Object value) {
+    return hintmap.put((String) key, (String)value);
+  }
+
+  public void add(PlotLayerHints hints) {
+    hintmap.putAll(hints.hintmap);
+  }
+
+  public void clear() {
+    hintmap.clear();
+  }
+
+  public Object remove(Object key) {
+    return hintmap.remove((String)key);
+  }
+
+  public void putAll(Map m) {
+    if(m instanceof PlotLayerHints) {
+      hintmap.putAll(((PlotLayerHints)m).hintmap);
+    } else {
+      // Funnel each key/value pair though our method
+      Iterator iter = m.entrySet().iterator();
+      while(iter.hasNext()) {
+        Map.Entry entry = (Map.Entry) iter.next();
+        put(entry.getKey(), entry.getValue());
+      }
+    }
+  }
+
+  public Set keySet() {
+    return hintmap.keySet();
+  }
+
+  public Collection values() {
+    return hintmap.values();
+  }
+
+  public Set entrySet() {
+    return Collections.unmodifiableMap(hintmap).entrySet();
+  }
+
+  public boolean equals(Object o) {
+    if(o instanceof PlotLayerHints) {
+      return hintmap.equals(((PlotLayerHints)o).hintmap);
+    } else if(o instanceof Map) {
+      return hintmap.equals(o);
+    }
+    return false;
+  }
+
+  public int hashCode() {
+    return hintmap.hashCode();
+  }
+
+  public Object clone() {
+    PlotLayerHints plh;
+    try {
+      plh = (PlotLayerHints) super.clone();
+      if(hintmap != null) {
+        plh.hintmap = (HashMap) hintmap.clone();
+      }
+    } catch (CloneNotSupportedException e) {
+      // this shouldnt happend since we are Cloneable
+      throw new InternalError();
+    }
+    return plh;
+  }
+
+  public String toString() {
+    if(hintmap == null) {
+      return getClass().getName() +
+          "@" +
+          Integer.toHexString(hashCode()) +
+          " (0 hints)";
+    }
+    return hintmap.toString();
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayerManager.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayerManager.java
new file mode 100755
index 0000000..a00aa4f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotLayerManager.java
@@ -0,0 +1,57 @@
+/*
+ * $Id: PlotLayerManager.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.plot;
+
+import gov.noaa.pmel.sgt.AxisTransform;
+import gov.noaa.pmel.sgt.LayerStack;
+import gov.noaa.pmel.sgt.LayerNotFoundException;
+/**
+ * @since 2.x
+ */
+public class PlotLayerManager {
+    public PlotLayerManager(JPlotPane plotPane) {
+        plotPane_ = plotPane;
+    }
+
+  /**
+   *
+   */
+  public void addLayer(PlotLayer layer) {
+  }
+
+  public void removeLayer(int index) throws LayerNotFoundException {
+  }
+
+  public void removeLayer(PlotLayer layer) throws LayerNotFoundException {
+  }
+
+  public void update() {
+  }
+
+  /** @link dependency */
+  /*#LayerStack lnkLayerStack;*/
+
+  /** @link dependency */
+  /*#PlotLayer lnkPlotLayer;*/
+
+  /** @link dependency */
+  /*#AxisTransform lnkAxisTransform;*/
+
+  /** @link dependency */
+  /*#PlotLayerHints lnkPlotLayerHints;*/
+
+  /**
+   * @label plotPane 
+   */
+  private JPlotPane plotPane_;
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotPaneMode.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotPaneMode.java
new file mode 100755
index 0000000..8e566ed
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PlotPaneMode.java
@@ -0,0 +1,43 @@
+/*
+ * $Id: PlotPaneMode.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.plot;
+
+/**
+ * @since 2.x
+ */
+final public class PlotPaneMode {
+  /**
+   * @supplierCardinality
+   */
+  private static PlotPaneMode[] values_ = new PlotPaneMode[4];
+  private int value_;
+    public final static int _ZOOM_DOMAIN = 0;
+    public final static PlotPaneMode ZOOM_DOMAIN = new PlotPaneMode(_ZOOM_DOMAIN);
+    public final static int _SELECT_OBJECT = 1;
+    public final static PlotPaneMode SELECT_OBJECT = new PlotPaneMode(_SELECT_OBJECT);
+    public final static int _SELECT_DATA = 2;
+    public final static PlotPaneMode SELECT_DATA = new PlotPaneMode(_SELECT_DATA);
+    public final static int _DRAG_AND_DROP = 3;
+    public final static PlotPaneMode DRAG_AND_DROP = new PlotPaneMode(_DRAG_AND_DROP);
+
+  protected PlotPaneMode(int value) {
+    values_[value] = this;
+    value_ = value;
+  }
+  public int getValue() {
+    return value_;
+  }
+  public PlotPaneMode from_int(int value) {
+    return values_[value];
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PrintManager.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PrintManager.java
new file mode 100755
index 0000000..61d45ff
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/PrintManager.java
@@ -0,0 +1,19 @@
+/*
+ * $Id: PrintManager.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.sgt.plot;
+
+/**
+ * @since 2.x
+ */
+public class PrintManager {
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/package.html
new file mode 100755
index 0000000..5068b35
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plot/package.html
@@ -0,0 +1,23 @@
+<HTML>
+<BODY>
+Classes for the automatic layout of multiple <code>Layer</code>s.
+
+<P>The classes in this package are designed to work together to create
+an automated system for plot layout.  Eventually, I hope to include
+managers for printing, Drag-and-Drop, and plot layout.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+
+ at see gov.noaa.pmel.sgt.JPane
+ at see gov.noaa.pmel.sgt.Layer 
+ at see gov.noaa.pmel.sgt.Graph
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plotmarkcodes.gif b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plotmarkcodes.gif
new file mode 100755
index 0000000..6b2fbce
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/plotmarkcodes.gif differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ColorSwatchIcon.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ColorSwatchIcon.java
new file mode 100755
index 0000000..638c59e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ColorSwatchIcon.java
@@ -0,0 +1,142 @@
+/*
+ * $Id: ColorSwatchIcon.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.IndexedColor;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.util.Debug;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+import javax.swing.Icon;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Color;
+/**
+ * <code>ColorSwatchIcon</code> implements <code>Icon</code> to create a
+ * icon that displays a small square of
+ * color. <code>ColorSwatchIcon</code> is used with property dialogs
+ * to display/edit colors from an <code>IndexedColor</code> map.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see Icon
+ */
+public class ColorSwatchIcon implements Icon, PropertyChangeListener {
+  private int width_;
+  private int height_;
+//  private int size_;
+  private IndexedColor cmap_;
+  private int index_;
+  private Color color_ = null;
+  /**
+   * Construct a <code>ColorSwatchIcon</code>.
+   *
+   * @param cmap indexed color map
+   * @param index color index
+   * @param size swatch size in pixels
+   */
+  public ColorSwatchIcon(IndexedColor cmap, int index, int size) {
+    setSize(size);
+    cmap_ = cmap;
+    index_ = index;
+    ((ColorMap)cmap_).addPropertyChangeListener(this);
+    color_ = cmap_.getColorByIndex(index_);
+  }
+
+  /**
+   * @since version 1.3
+   * @param color
+   * @param size
+   */
+  public ColorSwatchIcon(Color color, int width, int height) {
+    index_ = -1;
+    cmap_ = null;
+    color_ = color;
+    width_ = width;
+    height_ = height;
+  }
+  /**
+   * Get color index.
+   */
+  public int getIndex() {
+    return index_;
+  }
+  /**
+   * Get icon color.
+   */
+  public Color getColor() {
+    return color_;
+  }
+  /**
+   * Change the size of the swatch.
+   */
+  public void setSize(int size) {
+    width_ = size;
+    height_ = size;
+  }
+  /**
+   * Get the size of the icon.
+   */
+//  public int getSize() {
+//    return size_;
+//  }
+  /**
+   * Paint the icon at the specified location
+   */
+  public void paintIcon(Component c, Graphics g, int x, int y) {
+    g.setColor(color_);
+    g.fillRect(x, y, width_, height_);
+  }
+  /**
+   * Get the icon width.
+   */
+  public int getIconWidth() {
+    return width_;
+  }
+  /**
+   * Get the icon heigth.
+   */
+  public int getIconHeight() {
+    return height_;
+  }
+
+  public String toString() {
+    return "ColorSwatchIcon: ";
+  }
+  /**
+   * <code>ColorSwatchIcon</code> listens for changes to the
+   * <code>IndexedColor</code> color map. If changes occur the swatch
+   * is updated.
+   */
+  public void propertyChange(PropertyChangeEvent event) {
+    if(Debug.EVENT) {
+      System.out.println("ColorSwatchIcon: " + event);
+      System.out.println("                 " + event.getPropertyName());
+    }
+    if(event.getPropertyName().equals("color")) {
+      //
+      // color has changed
+      //
+      Color ncolor = cmap_.getColorByIndex(index_);
+      if(!ncolor.equals(color_)) {
+        color_ = ncolor;
+        // notify here?
+      }
+    }
+  }
+}
+
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/Draggable.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/Draggable.java
new file mode 100755
index 0000000..8a58ea8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/Draggable.java
@@ -0,0 +1,43 @@
+/*
+ * $Id: Draggable.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing;
+
+import java.awt.Point;
+/**
+ * <code>Draggable</code> defines an interface to allow classes to be
+ *  imaged separately in a <code>Layer</code> from other classes.
+ *  The interface is sufficient to allow dragging in a
+ * <code>JLayeredPane</code>  (<code>JPane</code>).
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ */
+public interface Draggable {
+  /**
+   * Set the location of the <code>Draggable</code> object. Change in
+   * location will not be vetoed.
+   */
+  public void setLocationNoVeto(int x, int y);
+  /**
+   * Set the location of the <code>Draggable</code> object.
+   */
+  public void setLocation(Point loc);
+  /**
+   * Set the location of the <code>Draggable</code> object and optionally don't
+   * fire a <code>PropertyChangeEvent</code>
+   *
+   * @since 3.0
+   */
+   public void setLocation(Point loc, boolean fireEvent);
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JClassTree.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JClassTree.java
new file mode 100755
index 0000000..7d44f41
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JClassTree.java
@@ -0,0 +1,619 @@
+/*
+ * $Id: JClassTree.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing;
+
+import javax.swing.*;
+import javax.swing.tree.*;
+import java.awt.*;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.InputEvent;
+import java.util.Enumeration;
+import java.util.List;
+
+import gov.noaa.pmel.util.Debug;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.LayerChild;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.CartesianRenderer;
+import gov.noaa.pmel.sgt.PointCartesianRenderer;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.GridCartesianRenderer;
+import gov.noaa.pmel.sgt.VectorCartesianRenderer;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.SpaceAxis;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.Transform;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.VectorAttribute;
+import gov.noaa.pmel.sgt.Logo;
+
+import gov.noaa.pmel.sgt.beans.Panel;
+import gov.noaa.pmel.sgt.beans.DataGroupLayer;
+
+import gov.noaa.pmel.sgt.swing.prop.LineAttributeDialog;
+import gov.noaa.pmel.sgt.swing.prop.GridAttributeDialog;
+import gov.noaa.pmel.sgt.swing.prop.SGLabelDialog;
+import gov.noaa.pmel.sgt.swing.prop.TimeAxisDialog;
+import gov.noaa.pmel.sgt.swing.prop.SpaceAxisDialog;
+import gov.noaa.pmel.sgt.swing.prop.PointAttributeDialog;
+import gov.noaa.pmel.sgt.swing.prop.LogoDialog;
+import gov.noaa.pmel.sgt.swing.prop.VectorAttributeDialog;
+
+/**
+ * <code>JClassTree</code> displays the <code>sgt</code> object tree
+ * in a <code>JDialog</code> using a <code>JTree</code>.  Many
+ * <code>sgt</code> classes can be selected from the
+ * <code>JTree</code> to edit their properties.  They include:
+ * {@link gov.noaa.pmel.sgt.SGLabel SGLabel},
+ * {@link gov.noaa.pmel.sgt.LineAttribute LineAttribute},
+ * {@link gov.noaa.pmel.sgt.GridAttribute GridAttribute},
+ * {@link gov.noaa.pmel.sgt.CartesianGraph CartesianGraph},
+ * {@link gov.noaa.pmel.sgt.TimeAxis TimeAxis},
+ * {@link gov.noaa.pmel.sgt.SpaceAxis SpaceAxis},
+ * {@link gov.noaa.pmel.sgt.PointAttribute PointAttribute}, and
+ * {@link gov.noaa.pmel.sgt.Logo Logo}.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see SGLabelDialog
+ * @see LineAttributeDialog
+ * @see GridAttributeDialog
+ * @see TimeAxisDialog
+ * @see SpaceAxisDialog
+ * @see PointAttributeDialog
+ * @see LogoDialog
+ */
+public class JClassTree extends javax.swing.JDialog {
+  private JPane pane_;
+
+  private static SGLabelDialog sg_;
+  private static LineAttributeDialog la_;
+  private static GridAttributeDialog ga_;
+  private static VectorAttributeDialog va_;
+  private static TimeAxisDialog ta_;
+  private static SpaceAxisDialog pa_;
+  private static PointAttributeDialog pta_;
+  private static LogoDialog lg_;
+  /**
+   * Default constructor.
+   */
+  public JClassTree() {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setVisible(false);
+    setSize(405,362);
+    jScrollPane1 = new javax.swing.JScrollPane();
+    jScrollPane1.setOpaque(true);
+    getContentPane().add(BorderLayout.CENTER, jScrollPane1);
+    treeView_ = new javax.swing.JTree();
+    treeView_.setBounds(0,0,402,324);
+    treeView_.setFont(new Font("Dialog", Font.PLAIN, 12));
+    treeView_.setBackground(java.awt.Color.white);
+    jScrollPane1.getViewport().add(treeView_);
+    treeControlsPanel = new javax.swing.JPanel();
+    treeControlsPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    treeControlsPanel.setFont(new Font("Dialog", Font.PLAIN, 12));
+    treeControlsPanel.setForeground(java.awt.Color.black);
+    treeControlsPanel.setBackground(new java.awt.Color(204,204,204));
+    getContentPane().add(BorderLayout.SOUTH, treeControlsPanel);
+    expandButton = new javax.swing.JButton();
+    expandButton.setText("Expand All");
+    expandButton.setActionCommand("Expand All");
+    expandButton.setFont(new Font("Dialog", Font.BOLD, 12));
+    expandButton.setBackground(new java.awt.Color(204,204,204));
+    treeControlsPanel.add(expandButton);
+    collapseButton = new javax.swing.JButton();
+    collapseButton.setText("Collapse All");
+    collapseButton.setActionCommand("Collapse All");
+    collapseButton.setFont(new Font("Dialog", Font.BOLD, 12));
+    collapseButton.setBackground(new java.awt.Color(204,204,204));
+    treeControlsPanel.add(collapseButton);
+    editButton = new javax.swing.JButton();
+    editButton.setText("Edit Selected");
+    editButton.setActionCommand("Edit Selected");
+    editButton.setFont(new Font("Dialog", Font.BOLD, 12));
+    editButton.setBackground(new java.awt.Color(204,204,204));
+    treeControlsPanel.add(editButton);
+    cancelButton = new javax.swing.JButton();
+    cancelButton.setText("Close");
+    cancelButton.setActionCommand("Close");
+    cancelButton.setFont(new Font("Dialog", Font.BOLD, 12));
+    cancelButton.setBackground(new java.awt.Color(204,204,204));
+    treeControlsPanel.add(cancelButton);
+    setTitle("Class View");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    expandButton.addActionListener(lSymAction);
+    collapseButton.addActionListener(lSymAction);
+    editButton.addActionListener(lSymAction);
+    cancelButton.addActionListener(lSymAction);
+
+    MouseListener ml = new MouseAdapter() {
+        public void mouseClicked(MouseEvent e) {
+          int selRow = treeView_.getRowForLocation(e.getX(),
+                                                   e.getY());
+          TreePath selPath = treeView_.getPathForLocation(e.getX(),
+                                                          e.getY());
+          if(selRow != -1) {
+            if((e.getClickCount() == 2) ||
+               ((e.getModifiers()&InputEvent.BUTTON3_MASK) != 0)) {
+              doubleClick(selRow, selPath);
+            }
+          }
+        }
+      };
+    treeView_.addMouseListener(ml);
+    //
+
+    if(System.getProperty("mrj.version") == null ||
+       !UIManager.getSystemLookAndFeelClassName().equals(UIManager.getLookAndFeel().getClass().getName())) {
+      Insets inset = new Insets(0,5,0,5);
+      expandButton.setMargin(inset);
+      collapseButton.setMargin(inset);
+      editButton.setMargin(inset);
+      cancelButton.setMargin(inset);
+    }
+  }
+
+  void doubleClick(int selRow, TreePath selPath) {
+    if(Debug.DEBUG) System.out.println("row " + selRow + " selected");
+    Object[] objs = selPath.getPath();
+    Object thing = ((DefaultMutableTreeNode)objs[objs.length-1]).getUserObject();
+    showProperties(thing);
+  }
+
+  public JClassTree(String sTitle) {
+    this();
+    setTitle(sTitle);
+  }
+  /**
+   * Make the dialog visible.
+   */
+  public void setVisible(boolean b) {
+    if (b)
+      setLocation(50, 50);
+    super.setVisible(b);
+  }
+
+  static public void main(String[] args) {
+    (new JClassTree()).setVisible(true);
+  }
+
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+    Insets in = getInsets();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+    // Adjust components according to the insets
+    setSize(in.left + in.right + d.width, in.top + in.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++)
+      {
+        Point p = components[i].getLocation();
+        p.translate(in.left, in.top);
+        components[i].setLocation(p);
+      }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  private boolean fComponentsAdjusted = false;
+
+  javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
+  javax.swing.JTree treeView_ = new javax.swing.JTree();
+  javax.swing.JPanel treeControlsPanel = new javax.swing.JPanel();
+  javax.swing.JButton expandButton = new javax.swing.JButton();
+  javax.swing.JButton collapseButton = new javax.swing.JButton();
+  javax.swing.JButton editButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == JClassTree.this)
+        JClassTree_WindowClosing(event);
+    }
+  }
+
+  void JClassTree_WindowClosing(java.awt.event.WindowEvent event) {
+    setVisible(false); // hide the Frame
+    //          dispose();           // free the system resources
+    //          System.exit(0);    // close the application
+  }
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == expandButton)
+        expandButton_actionPerformed(event);
+      else if (object == collapseButton)
+        collapseButton_actionPerformed(event);
+      else if (object == editButton)
+        editButton_actionPerformed(event);
+      else if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+    }
+  }
+
+  void expandButton_actionPerformed(java.awt.event.ActionEvent event) {
+    expandTree();
+  }
+  /**
+   * Expand the tree to show all nodes.
+   */
+  public void expandTree() {
+    int row=0;
+    while(row < treeView_.getRowCount()) {
+      if(treeView_.isCollapsed(row)) {
+        treeView_.expandRow(row);
+      }
+      row++;
+    }
+  }
+
+  void collapseButton_actionPerformed(java.awt.event.ActionEvent event) {
+    treeView_.collapseRow(0);
+  }
+
+  void editButton_actionPerformed(java.awt.event.ActionEvent event) {
+    Object[] objs = treeView_.getSelectionPath().getPath();
+    showProperties(((DefaultMutableTreeNode)objs[objs.length-1]).getUserObject());
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    setVisible(false);
+  }
+  /**
+   * Set the <code>JPane</code> for which the <code>JTree</code> is to
+   * be built.
+   */
+  public void setJPane(JPane pane) {
+    Layer ly;
+    //
+    DefaultTreeModel treeModel;
+    DefaultMutableTreeNode paneNode;
+    DefaultMutableTreeNode panelNode;
+    DefaultMutableTreeNode layerNode;
+    DefaultMutableTreeNode dataGroupNode;
+
+    pane_ = pane;
+    paneNode = new DefaultMutableTreeNode(pane_);
+    treeModel = new DefaultTreeModel(paneNode);
+    treeView_.setModel(treeModel);
+    //
+    Component[] comps = pane_.getComponents();
+    for(int il=0; il < comps.length; il++) {
+      if(comps[il] instanceof DataGroupLayer) {
+        ly = (Layer)comps[il];
+        dataGroupNode = new DefaultMutableTreeNode(ly);
+        treeModel.insertNodeInto(dataGroupNode,
+                                 paneNode,
+                                 treeModel.getChildCount(paneNode));
+        List lyList = ((DataGroupLayer)ly).getLayerList();
+        for(int i=1; i < lyList.size(); i++) {
+          ly = (Layer)lyList.get(i);
+          layerNode = new DefaultMutableTreeNode(ly);
+          treeModel.insertNodeInto(layerNode,
+                                   dataGroupNode,
+                                   treeModel.getChildCount(dataGroupNode));
+          expandLayer(ly, dataGroupNode, treeModel);
+        }
+      } else if(comps[il] instanceof Layer) {
+        ly = (Layer)comps[il];
+        layerNode = new DefaultMutableTreeNode(ly);
+        treeModel.insertNodeInto(layerNode,
+                                 paneNode,
+                                 treeModel.getChildCount(paneNode));
+        expandLayer(ly, layerNode, treeModel);
+      } else if(comps[il] instanceof Panel) {
+        panelNode = new DefaultMutableTreeNode(comps[il]);
+        treeModel.insertNodeInto(panelNode,
+                                 paneNode,
+                                 treeModel.getChildCount(paneNode));
+        Component[] pcomps = ((Panel)comps[il]).getComponents();
+        for(int pl=0; pl < pcomps.length; pl++) {
+          if(pcomps[pl] instanceof DataGroupLayer) {
+            ly = (Layer)pcomps[pl];
+            dataGroupNode = new DefaultMutableTreeNode(ly);
+            treeModel.insertNodeInto(dataGroupNode,
+                                     paneNode,
+                                     treeModel.getChildCount(paneNode));
+            expandLayer(ly, dataGroupNode, treeModel);
+            List lyList = ((DataGroupLayer)ly).getLayerList();
+            for(int i=1; i < lyList.size(); i++) {
+              ly = (Layer)lyList.get(i);
+              layerNode = new DefaultMutableTreeNode(ly);
+              treeModel.insertNodeInto(layerNode,
+                                       dataGroupNode,
+                                       treeModel.getChildCount(dataGroupNode));
+              expandLayer(ly, layerNode, treeModel);
+            }
+          } else if(pcomps[pl] instanceof Layer) {
+            ly = (Layer)pcomps[pl];
+            layerNode = new DefaultMutableTreeNode(ly);
+            treeModel.insertNodeInto(layerNode,
+                                     panelNode,
+                                     treeModel.getChildCount(panelNode));
+            expandLayer(ly, layerNode, treeModel);
+          }
+        }
+       } else {
+        continue;
+      }
+
+      int row=0;
+      while(row < treeView_.getRowCount()) {
+        if(treeView_.isCollapsed(row)) {
+          treeView_.expandRow(row);
+        }
+        row++;
+      }
+    }
+  }
+
+  private void expandLayer(Layer ly,
+                           DefaultMutableTreeNode layerNode,
+                           DefaultTreeModel treeModel) {
+    LayerChild child;
+    Graph graph;
+    Axis axis;
+    CartesianRenderer rend;
+    LineAttribute attr;
+    GridAttribute gattr;
+    PointAttribute pattr;
+    VectorAttribute vattr;
+    //
+    DefaultMutableTreeNode node;
+    DefaultMutableTreeNode paneNode;
+    DefaultMutableTreeNode childNode;
+    DefaultMutableTreeNode graphNode;
+    DefaultMutableTreeNode attrNode;
+    DefaultMutableTreeNode gattrNode;
+    DefaultMutableTreeNode pattrNode;
+    DefaultMutableTreeNode axisNode;
+    DefaultMutableTreeNode titleNode;
+
+      String name, className;
+      for(Enumeration childs = ly.childElements(); childs.hasMoreElements();) {
+        child = (LayerChild)childs.nextElement();
+        className = child.getClass().getName();
+        name = className.substring(className.lastIndexOf(".")+1);
+        childNode = new DefaultMutableTreeNode(child);
+        treeModel.insertNodeInto(childNode,
+                                 layerNode,
+                                 treeModel.getChildCount(layerNode));
+      }
+      graph = ly.getGraph();
+      if(graph == null) return;
+      className = graph.getClass().getName();
+      name = className.substring(className.lastIndexOf(".")+1);
+      if(graph instanceof CartesianGraph) {
+        graphNode = new DefaultMutableTreeNode(graph);
+        treeModel.insertNodeInto(graphNode,
+                                 layerNode,
+                                 treeModel.getChildCount(layerNode));
+        rend = ((CartesianGraph)graph).getRenderer();
+        if(rend instanceof LineCartesianRenderer) {
+          attr = (LineAttribute)((LineCartesianRenderer)rend).getAttribute();
+          if(attr != null) {
+            className = attr.getClass().getName();
+            name = className.substring(className.lastIndexOf(".")+1);
+            attrNode = new DefaultMutableTreeNode(attr);
+            treeModel.insertNodeInto(attrNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+          }
+        } else if(rend instanceof VectorCartesianRenderer) {
+          vattr = (VectorAttribute)((VectorCartesianRenderer)rend).getAttribute();
+          if(vattr != null) {
+            className = vattr.getClass().getName();
+            name = className.substring(className.lastIndexOf(".")+1);
+            attrNode = new DefaultMutableTreeNode(vattr);
+            treeModel.insertNodeInto(attrNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+          }
+        } else if(rend instanceof GridCartesianRenderer) {
+          gattr = (GridAttribute)((GridCartesianRenderer)rend).getAttribute();
+          if(gattr != null) {
+            className = gattr.getClass().getName();
+            name = className.substring(className.lastIndexOf(".")+1);
+            gattrNode = new DefaultMutableTreeNode(gattr);
+            treeModel.insertNodeInto(gattrNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+          }
+        } else if(rend instanceof PointCartesianRenderer) {
+          pattr = (PointAttribute)((PointCartesianRenderer)rend).getAttribute();
+          if(pattr != null) {
+            className = pattr.getClass().getName();
+            name = className.substring(className.lastIndexOf(".")+1);
+            pattrNode = new DefaultMutableTreeNode(pattr);
+            treeModel.insertNodeInto(pattrNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+          }
+        }
+        for(Enumeration axes = ((CartesianGraph)graph).xAxisElements();
+            axes.hasMoreElements();) {
+          axis = (Axis)axes.nextElement();
+          className = axis.getClass().getName();
+          name = className.substring(className.lastIndexOf(".")+1);
+          if(axis instanceof SpaceAxis) {
+            axisNode = new DefaultMutableTreeNode(axis);
+            treeModel.insertNodeInto(axisNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+            SGLabel title = axis.getTitle();
+            if(title != null) {
+              titleNode = new DefaultMutableTreeNode(title);
+              treeModel.insertNodeInto(titleNode,
+                                       axisNode,
+                                       treeModel.getChildCount(axisNode));
+            }
+          } else { // not a SpaceAxis
+            axisNode = new DefaultMutableTreeNode(axis);
+            treeModel.insertNodeInto(axisNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+          }
+        }
+        for(Enumeration axes = ((CartesianGraph)graph).yAxisElements();
+            axes.hasMoreElements();) {
+          axis = (Axis)axes.nextElement();
+          className = axis.getClass().getName();
+          name = className.substring(className.lastIndexOf(".")+1);
+          if(axis instanceof SpaceAxis) {
+            axisNode = new DefaultMutableTreeNode(axis);
+            treeModel.insertNodeInto(axisNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+            SGLabel title = axis.getTitle();
+            if(title != null) {
+              titleNode = new DefaultMutableTreeNode(title);
+              treeModel.insertNodeInto(titleNode,
+                                       axisNode,
+                                       treeModel.getChildCount(axisNode));
+            }
+          } else { // not a SpaceAxis
+            axisNode = new DefaultMutableTreeNode(axis);
+            treeModel.insertNodeInto(axisNode,
+                                     graphNode,
+                                     treeModel.getChildCount(graphNode));
+          }
+        }
+      } else {  // not a CartesianGraph
+        graphNode = new DefaultMutableTreeNode(graph);
+        treeModel.insertNodeInto(graphNode,
+                                 layerNode,
+                                 treeModel.getChildCount(layerNode));
+      }
+    }
+
+  void showProperties(Object obj) {
+    if(obj instanceof SGLabel) {
+      if(sg_ == (SGLabelDialog) null) {
+        //
+        // create the SGLabel  dialog
+        //
+        sg_ = new SGLabelDialog();
+      }
+      sg_.setSGLabel((SGLabel) obj, pane_);
+      if(!sg_.isShowing())
+        sg_.setVisible(true);
+    } else if(obj instanceof Logo) {
+      if(lg_ == null) {
+        //
+        // create logo dialog
+        //
+        lg_ = new LogoDialog();
+      }
+      lg_.setLogo((Logo) obj, pane_);
+      if(!lg_.isShowing())
+        lg_.setVisible(true);
+    } else if(obj instanceof PlainAxis) {
+      if(pa_ == (SpaceAxisDialog) null) {
+        //
+        // create the PlainAxis  dialog
+        //
+        pa_ = new SpaceAxisDialog();
+      }
+      pa_.setSpaceAxis((PlainAxis) obj, pane_);
+      if(!pa_.isShowing())
+        pa_.show();
+    } else if(obj instanceof TimeAxis) {
+      if(ta_ == (TimeAxisDialog) null) {
+        //
+        // create the TimeAxis  dialog
+        //
+        ta_ = new TimeAxisDialog();
+      }
+      ta_.setTimeAxis((TimeAxis) obj, pane_);
+      if(!ta_.isShowing())
+        ta_.show();
+    } else if(obj instanceof LineAttribute) {
+      if(la_ == (LineAttributeDialog) null) {
+        //
+        // create the LineAttr  dialog
+        //
+        la_ = new LineAttributeDialog();
+        la_.setJPane(pane_);
+      }
+      la_.setLineAttribute((LineAttribute)obj);
+      if(!la_.isShowing())
+        la_.setVisible(true);
+    } else if(obj instanceof VectorAttribute) {
+      if(va_ == (VectorAttributeDialog) null) {
+        //
+        // create the LineAttr  dialog
+        //
+        va_ = new VectorAttributeDialog();
+        va_.setJPane(pane_);
+      }
+      va_.setVectorAttribute((VectorAttribute)obj);
+      if(!va_.isShowing())
+        va_.setVisible(true);
+    } else if (obj instanceof GridAttribute) {
+      if(ga_ == null) {
+        //
+        // create a new dialog
+        //
+        ga_ = new GridAttributeDialog();
+      }
+      ga_.setGridAttribute((GridAttribute)obj);
+      if(!ga_.isShowing())
+        ga_.setVisible(true);
+    } else if (obj instanceof CartesianGraph) {
+      CartesianRenderer rend = ((CartesianGraph)obj).getRenderer();
+      if( rend instanceof GridCartesianRenderer) {
+        if(ga_ == null) {
+          ga_ = new GridAttributeDialog();
+        }
+        ga_.setGridCartesianRenderer((GridCartesianRenderer)rend);
+        if(!ga_.isShowing())
+          ga_.setVisible(true);
+      }
+    } else if (obj instanceof PointAttribute) {
+      if(pta_ == (PointAttributeDialog) null) {
+        pta_ = new PointAttributeDialog();
+      }
+      pta_.setPointAttribute((PointAttribute) obj, pane_);
+      if(!pta_.isShowing())
+        pta_.show();
+    }
+  }
+  private Frame getFrame() {
+    Container theFrame = this;
+    do {
+      theFrame = theFrame.getParent();
+    } while ((theFrame != null) && !(theFrame instanceof Frame));
+    if (theFrame == null)
+      theFrame = new Frame();
+    return (Frame)theFrame;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JGraphicLayout.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JGraphicLayout.java
new file mode 100755
index 0000000..ccb1cc5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JGraphicLayout.java
@@ -0,0 +1,1131 @@
+/*
+ * $Id: JGraphicLayout.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.Pane;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.AxisTransform;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.Attribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.Logo;
+import gov.noaa.pmel.sgt.DataNotFoundException;
+
+import gov.noaa.pmel.util.Domain;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Units;
+import gov.noaa.pmel.util.SoTRange;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTPoint;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.SGTVector;
+
+import gov.noaa.pmel.sgt.swing.prop.SGLabelDialog;
+import gov.noaa.pmel.sgt.swing.prop.TimeAxisDialog;
+import gov.noaa.pmel.sgt.swing.prop.SpaceAxisDialog;
+import gov.noaa.pmel.sgt.swing.prop.LogoDialog;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.net.URL;
+import java.awt.Image;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.event.InputEvent;
+import java.text.DecimalFormat;
+
+import java.beans.PropertyVetoException;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.beans.VetoableChangeSupport;
+import java.beans.VetoableChangeListener;
+
+/**
+ * <code>JGraphicLayout</code> is a abstract class that provides
+ * the basis for pre-defined layouts using the
+ * <code>CartesianGraph</code> class. <code>JGraphicLayout</code>
+ * extends <code>JPane</code>.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see CartesianGraph
+ * @see JPlotLayout
+**/
+public abstract class JGraphicLayout extends JPane {
+  /**
+   * Use X array from <code>SGTData</code>.
+   */
+  public static final int X_AXIS = 1;
+  /**
+   * Use Y array from <code>SGTData</code>.
+   */
+  public static final int Y_AXIS = 2;
+  /**
+   * Use Z array from <code>SGTData</code>.
+   */
+  public static final int Z_AXIS = 3;
+  /** Width of graph in physical units */
+  protected static double XSIZE_ = 6.00;
+  /** Start of X axis in physical units */
+  protected static double XMIN_  = 0.60;
+  /** End of X axis in physical units */
+  protected static double XMAX_  = 5.40;
+  /** Height of graph in physical units */
+  protected static double YSIZE_ = 4.50;
+  /** Start of Y axis in physical units */
+  protected static double YMIN_  = 0.75;
+  /** End of Y axis in physical units */
+  protected static double YMAX_  = 3.30;
+  //
+  /** Height of main title in physical units */
+  protected static double MAIN_TITLE_HEIGHT_ = 0.25;
+  /** Height of axis title in physical units */
+  protected static double TITLE_HEIGHT_ = 0.22;
+  /** Height of axis labels in physical units */
+  protected static double LABEL_HEIGHT_ = 0.18;
+  /** Height of 2nd and 3rd main titles */
+  protected static double WARN_HEIGHT_ = 0.15;
+  /** Height of line or color key labels */
+  protected static double KEY_HEIGHT_ = 0.16;
+  //  protected static double KEY_HEIGHT_ = 0.20;
+  //
+  /** Width of key if in separate pane */
+  protected static double XKEYSIZE_ =  6.00;
+  /** Height of key if in separate pane */
+  protected static double YKEYSIZE_ = 12.00;
+  //
+  /** Main pane color */
+  protected static Color PANE_COLOR = Color.white;
+  /** Key pane color */
+  protected static Color KEYPANE_COLOR = Color.white;
+  //
+  /** Base units of data */
+  protected int base_units_ = Units.NONE;
+  private JGraphicLayout me_;
+  /** Key pane reference */
+  protected JPane keyPane_;
+  /** <code>SGTData</code> storage */
+  protected Vector data_;
+  /** Mapping of data to attributes */
+  protected Hashtable dataAttrMap_ = new Hashtable();
+  /** Identification of graph */
+  protected String ident_;
+  /** Layers are overlayed */
+  protected boolean overlayed_;
+  /** Data is clipped to axes */
+  protected boolean clipping_ = false;
+  /** Optional image */
+  protected Image iconImage_ = null;
+
+  /**
+   * Titles for graph
+   * @link aggregation
+   * @undirected
+   * @label titles
+   */
+  protected SGLabel mainTitle_, title2_, title3_;
+  /** Reference to Mouse event handler */
+  protected SymMouse aSymMouse_;
+  //
+  /** Allow editing of <code>sgt</code> object properties */
+  protected boolean editClasses_ = true;
+  /** Reference to <code>SGLabelDialog</code> */
+  protected SGLabelDialog sg_props_;
+  /** Reference to <code>SpaceAxisDialog</code> */
+  protected SpaceAxisDialog pa_props_;
+  /** Reference to <code>TimeAxisDialog</code> */
+  protected TimeAxisDialog ta_props_;
+  /** Reference to <code>LogoDialog</code> */
+  protected LogoDialog lo_props_;
+  //
+  /** Reference to <code>PropertyChangeSupport</code> */
+  protected PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  /** Reference to <code>VetoableChangeSupport</code> */
+  protected VetoableChangeSupport vetos_ = new VetoableChangeSupport(this);
+  /**
+   * Default constructor
+   */
+  public JGraphicLayout() {
+    this("", null, new Dimension(50,50));
+  }
+  /**
+   * <code>JGraphicLayout</code> constructor.
+   *
+   * @param id identifier
+   * @param img icon image
+   * @see JPlotLayout
+   */
+  public JGraphicLayout(String id, Image img) {
+    this(id, img, new Dimension(50,50));
+  }
+  /**
+   * <code>JGraphicLayout</code> constructor.
+   *
+   * @param id identifier
+   * @param img icon image
+   * @param size graph size in device units
+   * @see JPlotLayout
+   */
+  public JGraphicLayout(String id, Image img, Dimension size) {
+    super(id, size);
+    ident_ = id;
+    overlayed_ = true;
+    data_ = new Vector(10);
+    iconImage_ = img;
+    mainTitle_ = null;
+    title2_ = null;
+    title3_ = null;
+    me_ = this;
+    if(aSymMouse_ == null) aSymMouse_ = new SymMouse();
+    addMouseListener(aSymMouse_);
+  }
+  /**
+   * Set the identifier
+   *
+   * @param id layout identifier
+   */
+  public void setId(String id) {
+    ident_ = id;
+  }
+  /**
+   * Get the identifier
+   *
+   * @return layout identifier
+   */
+  public String getId() {
+    return ident_;
+  }
+  /**
+   * Set the plot titles.
+   *
+   * @param title main plot title
+   * @param title2 secondary plot title
+   * @param title3 tertiary plot title
+   */
+  public void setTitles(String title, String title2, String title3) {
+    if(mainTitle_ != null) mainTitle_.setText(title);
+    if(title2_ != null) title2_.setText(title2);
+    if(title3_ != null) title3_.setText(title3);
+  }
+  /**
+   * Set the base units. The base units are set automatically based
+   * on the first <code>SGTData</code> added to the list. Other
+   * <code>SGTData</code> objects added
+   * thereafter will be converted to the standard display units for each
+   * base unit type.  (TEMPERATURE, default units are "degC"; VELOCITY,
+   * default units are "m/s"; DISTANCE, default unis are "m"). NOTE: Presently
+   * the units supported are very limited.
+   *
+   * @see gov.noaa.pmel.util.Units#NONE
+   * @see gov.noaa.pmel.util.Units#TEMPERATURE
+   * @see gov.noaa.pmel.util.Units#VELOCITY
+   * @see gov.noaa.pmel.util.Units#DISTANCE
+   */
+  public void setBaseUnit(int base) {
+    base_units_ = base;
+  }
+  /**
+   * Get the base units
+   *
+   * @return the current base units for the layout
+   */
+  public int getBaseUnit() {
+    return base_units_;
+  }
+  /**
+   * Set flag to overlay the layers.
+   *
+   * @param over if true overlay layers if false stack
+   */
+  public void setOverlayed(boolean over) {
+    overlayed_ = over;
+  }
+  /**
+   * Layer overlay flag.
+   *
+   * @return true if layers will be overlayed
+   */
+  public boolean isOverlayed() {
+    return overlayed_;
+  }
+  /**
+   * Get icon image
+   *
+   * @return icon image
+   */
+  public Image getIconImage() {
+    return iconImage_;
+  }
+  /**
+   * Get KeyPane object
+   *
+   * @return pane
+   */
+  public JPane getKeyPane() {
+    return keyPane_;
+  }
+  /**
+   * Is there a key pane?
+   */
+  public boolean isKeyPane() {
+    return (keyPane_ != null);
+  }
+  /**
+   * Add data to the layout.  Where data is added is dependent on the
+   * specific layout. Additional layers will be created as required.
+   *
+   * @param data data to be added
+   */
+  public void addData(SGTData data) {
+    data_.addElement(data);
+  }
+  /**
+   * Associate <code>SGTData</code> with an
+   * <code>Attribute</code>. The associations are managed by a
+   * <code>Hashtable</code> object.
+   */
+  public void addAttribute(SGTData data, Attribute attr) {
+    dataAttrMap_.put(data, attr);
+  }
+  /**
+   * Find an <code>Attribute</code> given a <code>SGTData</code>
+   * object.
+   */
+  public Attribute getAttribute(SGTData data)
+    throws DataNotFoundException {
+    Attribute attr = (Attribute)dataAttrMap_.get(data);
+    if(attr == null) {
+      throw new DataNotFoundException();
+    }
+    return attr;
+  }
+  /**
+   * Find an <code>Attribute</code> given an id.
+   *
+   * @since 3.0
+   */
+  public Attribute findAttribute(String id) {
+    Attribute attr = null;
+    Enumeration e = dataAttrMap_.elements();
+    while(e.hasMoreElements()) {
+      attr = (Attribute)e.nextElement();
+      if(attr.getId().equals(id)) return attr;
+    }
+    return attr;
+  }
+  /**
+   * Add data to the plot
+   */
+  public abstract void addData(SGTData data, String label);
+  /**
+   * Construct a string that summarizes the location of the data.
+   */
+  public abstract String getLocationSummary(SGTData grid);
+  /**
+   * Find the range of the <code>SGTLine</code> object in the specific
+   * direction.
+   *
+   * @param data SGTLine object
+   * @param dir direction
+   * @see CartesianGraph
+   */
+  public Range2D findRange(SGTLine data, int dir) {
+    int num, i, first=0;
+    double amin=0.0, amax=0.0;
+    double[] values;
+    boolean good = false;
+
+    switch(dir) {
+    case X_AXIS:
+      values = data.getXArray();
+      num = values.length;
+      break;
+    default:
+    case Y_AXIS:
+      values = data.getYArray();
+      num = values.length;
+    }
+    for(i=0; i < num; i++) {
+      if(!Double.isNaN(values[i])) {
+        amin = (double)values[i];
+        amax = (double)values[i];
+        good = true;
+        first = i+1;
+        break;
+      }
+    }
+    if(!good) {
+      return new Range2D(Double.NaN, Double.NaN);
+    } else {
+      for(i=first; i < num; i++) {
+        if(!Double.isNaN(values[i])) {
+          amin = Math.min(amin, (double)values[i]);
+          amax = Math.max(amax, (double)values[i]);
+        }
+      }
+    }
+    return new Range2D(amin, amax);
+  }
+  /**
+   * Find the range of the <code>SGTLine</code> object in the specific
+   * direction.
+   *
+   * @param data SGTLine object
+   * @param dir direction
+   * @return range as an <code>SoTRange</code> object
+   * @see CartesianGraph
+   */
+  public SoTRange findSoTRange(SGTLine line, int dir) {
+    switch(dir) {
+    case X_AXIS:
+      return line.getXRange();
+    case Y_AXIS:
+      return line.getYRange();
+    default:
+      return null;
+    }
+  }
+  /**
+   * Find the range of the <code>SGTVector</code> object in the
+   * specified direction.  Uses the U component to find X, Y ranges.
+   *
+   * @param data the data vector
+   * @param dir the direction
+   * @return range as an <code>SoTRange</code> object
+   */
+  public SoTRange findSoTRange(SGTVector data, int dir) {
+    double[] veclen;
+    int num, i, first = 0;
+    double amin = 0.0, amax = 0.0;
+    boolean good = false;
+
+    switch(dir) {
+    case X_AXIS:
+      return data.getU().getXRange();
+    case Y_AXIS:
+      return data.getU().getYRange();
+    default:
+    case Z_AXIS:
+      double[] ucomp = data.getU().getZArray();
+      double[] vcomp = data.getV().getZArray();
+      veclen = new double[ucomp.length];
+      for(i=0; i < veclen.length; i++) {
+        veclen[i] = Math.sqrt(ucomp[i]*ucomp[i] + vcomp[i]*vcomp[i]);
+      }
+      num = veclen.length;
+    }
+    for(i=0; i < num; i++) {
+      if(!Double.isNaN(veclen[i])) {
+        amin = (double)veclen[i];
+        amax = (double)veclen[i];
+        good = true;
+        first = i+1;
+        break;
+      }
+    }
+    if(!good) {
+      return new SoTRange.Double(Double.NaN, Double.NaN);
+    } else {
+      for(i=first; i < num; i++) {
+        if(!Double.isNaN(veclen[i])) {
+          amin = Math.min(amin, (double)veclen[i]);
+          amax = Math.max(amax, (double)veclen[i]);
+        }
+      }
+    }
+    return new SoTRange.Double(amin, amax);
+  }
+  /**
+   * Find the range of the <code>SGTGrid</code> object in the
+   * specified direction.
+   *
+   * @param data the data grid
+   * @param attr the grid attribute
+   * @param dir the direction
+   * @return range as an <code>SoTRange</code> object
+   */
+  public SoTRange findSoTRange(SGTGrid data, GridAttribute attr, int dir) {
+    int num, onum, i, first=0;
+    double amin=0.0, amax=0.0;
+    GeoDate tmin, tmax;
+    double[] values, orig;
+    GeoDate[] taxis, torig;
+    boolean good = false;
+
+    if(attr.isRaster() &&
+       ((data.isXTime() && (dir == X_AXIS) && !data.hasXEdges()) ||
+            (data.isYTime() && (dir == Y_AXIS) && !data.hasYEdges()))) {
+        torig = data.getTimeArray();
+        onum = torig.length;
+        taxis = new GeoDate[onum+1];
+        taxis[0] = torig[0].subtract(
+                   (torig[1].subtract(torig[0])).divide(2.0));
+        for(i=1; i < onum; i++) {
+          taxis[i] = (torig[i-1].add(torig[i])).divide(2.0);
+        }
+        taxis[onum] = torig[onum-1].add(
+                      (torig[onum-1].subtract(torig[onum-2])).divide(2.0));
+        num = taxis.length;
+        return new SoTRange.Time(taxis[0].getTime(),
+                                 taxis[num-1].getTime());
+    }
+
+    switch(dir) {
+    case X_AXIS:
+      if(attr.isRaster()) {
+        if(data.hasXEdges()) {
+          return data.getXEdgesRange();
+        } else {
+          orig = data.getXArray();
+          onum = orig.length;
+          values = new double[onum+1];
+          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
+          for(i=1; i < onum; i++) {
+            values[i] = (orig[i-1]+orig[i])*0.5;
+          }
+          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
+          num = values.length;
+        }
+      } else {
+        return data.getXRange();
+      }
+      break;
+    case Y_AXIS:
+      if(attr.isRaster()) {
+        if(data.hasYEdges()) {
+          return data.getYEdgesRange();
+        } else {
+          orig = data.getYArray();
+          onum = orig.length;
+          values = new double[onum+1];
+          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
+          for(i=1; i < onum; i++) {
+            values[i] = (orig[i-1]+orig[i])*0.5;
+          }
+          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
+          num = values.length;
+        }
+      } else {
+        return data.getYRange();
+      }
+      break;
+    default:
+    case Z_AXIS:
+      values = data.getZArray();
+      num = values.length;
+    }
+    for(i=0; i < num; i++) {
+      if(!Double.isNaN(values[i])) {
+        amin = (double)values[i];
+        amax = (double)values[i];
+        good = true;
+        first = i+1;
+        break;
+      }
+    }
+    if(!good) {
+      return new SoTRange.Double(Double.NaN, Double.NaN);
+    } else {
+      for(i=first; i < num; i++) {
+        if(!Double.isNaN(values[i])) {
+          amin = Math.min(amin, (double)values[i]);
+          amax = Math.max(amax, (double)values[i]);
+        }
+      }
+    }
+    return new SoTRange.Double(amin, amax);
+  }
+  /**
+   * Find the range of the <code>SGTGrid</code> object in the
+   * specified direction.
+   *
+   * @param data the data grid
+   * @param attr the grid attribute
+   * @param dir the direction
+   */
+  public Range2D findRange(SGTGrid data, GridAttribute attr, int dir) {
+    int num, onum, i, first=0;
+    double amin=0.0, amax=0.0;
+    double[] values, orig;
+    boolean good = false;
+
+    switch(dir) {
+    case X_AXIS:
+      if(attr.isRaster()) {
+        if(data.hasXEdges()) {
+          values = data.getXEdges();
+          num = values.length;
+        } else {
+          orig = data.getXArray();
+          onum = orig.length;
+          values = new double[onum+1];
+          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
+          for(i=1; i < onum; i++) {
+            values[i] = (orig[i-1]+orig[i])*0.5;
+          }
+          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
+          num = values.length;
+        }
+      } else {
+        values = data.getXArray();
+        num = values.length;
+      }
+      break;
+    case Y_AXIS:
+      if(attr.isRaster()) {
+        if(data.hasYEdges()) {
+          values = data.getYEdges();
+          num = values.length;
+        } else {
+          orig = data.getYArray();
+          onum = orig.length;
+          values = new double[onum+1];
+          values[0] = orig[0]-(orig[1]-orig[0])*0.5;
+          for(i=1; i < onum; i++) {
+            values[i] = (orig[i-1]+orig[i])*0.5;
+          }
+          values[onum] = orig[onum-1]+(orig[onum-1]-orig[onum-2])*0.5;
+          num = values.length;
+        }
+      } else {
+        values = data.getYArray();
+        num = values.length;
+      }
+      break;
+    default:
+    case Z_AXIS:
+      values = data.getZArray();
+      num = values.length;
+    }
+    for(i=0; i < num; i++) {
+      if(!Double.isNaN(values[i])) {
+        amin = (double)values[i];
+        amax = (double)values[i];
+        good = true;
+        first = i+1;
+        break;
+      }
+    }
+    if(!good) {
+      return new Range2D(Double.NaN, Double.NaN);
+    } else {
+      for(i=first; i < num; i++) {
+        if(!Double.isNaN(values[i])) {
+          amin = Math.min(amin, (double)values[i]);
+          amax = Math.max(amax, (double)values[i]);
+        }
+      }
+    }
+    return new Range2D(amin, amax);
+  }
+  /**
+   * Find the time range of the <code>SGTLine</code> object.
+   *
+   * @param data SGTLine object
+   * @see CartesianGraph
+   */
+  public TimeRange findTimeRange(SGTLine data) {
+    long taxis[];
+    int num;
+
+    taxis = data.getGeoDateArray().getTime();
+    num = taxis.length;
+    return new TimeRange(taxis[0], taxis[num-1]);
+  }
+  /**
+   * Find the <code>TimeRange</code> of the <code>SGTGrid</code> object.
+   *
+   * @param data the data grid
+   * @param attr the grid attribute
+   * @param dir the direction
+   */
+  public TimeRange findTimeRange(SGTGrid data, GridAttribute attr) {
+    long tmin, tmax;
+    long taxis[], orig[];
+    int num, onum, i;
+
+    if(attr.isRaster() && (data.isXTime() || data.isYTime())) {
+      if(data.hasXEdges() || data.hasYEdges()) {
+        taxis = data.getGeoDateArrayEdges().getTime();
+      } else {
+        orig = data.getGeoDateArray().getTime();
+        onum = orig.length;
+        taxis = new long[onum+1];
+        taxis[0] = orig[0] - (orig[1]-orig[0])/2;
+        for(i=1; i < onum; i++) {
+          taxis[i] = (orig[i-1] + orig[i])/2;
+        }
+        taxis[onum] = orig[onum-1] + (orig[onum-1] - orig[onum-2])/2;
+      }
+    } else {
+      taxis = data.getGeoDateArray().getTime();
+    }
+    num = taxis.length;
+    return new TimeRange(taxis[0], taxis[num-1]);
+  }
+  /**
+   * Set clipping on or off. If clipping is on, clip to the
+   * axes range.
+   *
+   * @param clip true if clipping is on
+   */
+  public void setClipping(boolean clip) {
+    clipping_ = clip;
+  }
+  /**
+   * Returns true if clipping is on.
+   *
+   * @return true if clipping is on
+   */
+  public boolean isClipping() {
+    return clipping_;
+  }
+  /**
+   * Set the axes to the range of the <code>SGTData</code> objects.
+   */
+  abstract public void resetZoom();
+  /**
+   * Set the axes to to range specified by the <code>Domain</code>
+   * object.
+   */
+  abstract public void setRange(Domain domain) throws PropertyVetoException;
+  /**
+   * Get the current <code>Domain</code>
+   */
+  public Domain getRange() {
+    Domain domain = new Domain();
+    Range2D xr = new Range2D();
+    Range2D yr = new Range2D();
+//    TimeRange tr = new TimeRange();
+    Layer layer = getFirstLayer();
+    Graph graph = layer.getGraph();
+    if(graph instanceof CartesianGraph) {
+      CartesianGraph cg = (CartesianGraph)graph;
+      AxisTransform xt = cg.getXTransform();
+      AxisTransform yt = cg.getYTransform();
+      if(xt.isTime()) {
+        domain.setXRange(xt.getTimeRangeU());
+      } else {
+        domain.setXRange(xt.getRangeU());
+      }
+      if(yt.isTime()) {
+        domain.setYRange(yt.getTimeRangeU());
+      } else {
+        domain.setYRange(yt.getRangeU());
+      }
+    }
+    return domain;
+  }
+  /**
+   * Get the zoom bounds in user units
+   */
+  public Domain getZoomBoundsU() {
+    Domain domain = new Domain();
+    Range2D xr = new Range2D();
+    Range2D yr = new Range2D();
+    long start, end;
+
+    Rectangle zoom = getZoomBounds();
+    Layer layer = getFirstLayer();
+    Graph graph = layer.getGraph();
+
+    if(graph instanceof CartesianGraph) {
+      CartesianGraph cg = (CartesianGraph)graph;
+      AxisTransform xt = cg.getXTransform();
+      AxisTransform yt = cg.getYTransform();
+      if(xt.isSpace()) {
+        xr.start = cg.getXPtoU(layer.getXDtoP(zoom.x));
+        xr.end = cg.getXPtoU(layer.getXDtoP(zoom.x + zoom.width));
+        if(xr.start > xr.end) {
+          double temp = xr.start;
+          xr.start = xr.end;
+          xr.end = temp;
+        }
+        domain.setXRange(xr);
+      } else {
+        start = cg.getXPtoLongTime(layer.getXDtoP(zoom.x));
+        end = cg.getXPtoLongTime(layer.getXDtoP(zoom.x + zoom.width));
+        if(start > end) {
+          long tmp = start;
+          start = end;
+          end = tmp;
+        }
+        domain.setXRange(new TimeRange(new GeoDate(start), new GeoDate(end)));
+      }
+      if(yt.isSpace()) {
+        yr.start = cg.getYPtoU(layer.getYDtoP(zoom.y));
+        yr.end = cg.getYPtoU(layer.getYDtoP(zoom.y + zoom.height));
+        if(yr.start > yr.end) {
+          double temp = yr.start;
+          yr.start = yr.end;
+          yr.end = temp;
+        }
+        domain.setYRange(yr);
+      } else {
+        start = cg.getYPtoLongTime(layer.getYDtoP(zoom.y));
+        end = cg.getYPtoLongTime(layer.getYDtoP(zoom.y + zoom.height));
+        if(start > end) {
+          long tmp = start;
+          start = end;
+          end = tmp;
+        }
+        domain.setYRange(new TimeRange(new GeoDate(start), new GeoDate(end)));
+      }
+    }
+    return domain;
+  }
+  /**
+   * return a formated string summarizing the latitude
+   */
+  protected String getLatString(double lat) {
+    if(lat == 0.0) return "Eq";
+    DecimalFormat dfLat = new DecimalFormat("##.##N;##.##S");
+    return dfLat.format(lat);
+  }
+  /**
+   * return a formated string summarizing the longitude
+   */
+  protected String getLonString(double lond) {
+    /* positive west */
+    String str;
+    DecimalFormat dfLon = new DecimalFormat("###.##W;###.##");
+    double lon = (lond + 360.0) % 360.0;
+    dfLon.setNegativeSuffix("E");
+    if(lon > 180.0) {
+      lon = 360.0 - lon;
+    }
+    return dfLon.format(lon);
+  }
+  /**
+   * Return data associated with the plot.
+   *
+   * @return data in a <code>Collection</code>
+   */
+  public Collection getData() {
+    Collection col = new Collection(ident_ + " Data Collection",
+                                    data_.size());
+    for(Enumeration e = data_.elements(); e.hasMoreElements(); ) {
+      col.addElement(e.nextElement());
+    }
+    return col;
+  }
+
+  class SymMouse extends java.awt.event.MouseAdapter  {
+    public void mousePressed(java.awt.event.MouseEvent event) {
+      if(!isMouseEventsEnabled()) return;
+      Object object = event.getSource();
+      if (object == me_)
+        Layout_MousePress(event);
+      else if (object == keyPane_)
+        KeyPane_MousePress(event);
+    }
+
+    public void mouseClicked(java.awt.event.MouseEvent event) {
+      if(!isMouseEventsEnabled()) return;
+      Object object = event.getSource();
+      if (object == me_)
+        Layout_MouseClicked(event);
+      else if (object == keyPane_)
+        KeyPane_MouseClicked(event);
+    }
+
+    public void mouseReleased(java.awt.event.MouseEvent event) {
+      if(!isMouseEventsEnabled()) return;
+      Object object = event.getSource();
+      if (object == me_)
+        Layout_MouseRelease(event);
+    }
+  }
+
+  void Layout_MouseRelease(java.awt.event.MouseEvent event) {
+    //
+    // continue only if button1 is pressed
+    //
+    if((event.getModifiers()&InputEvent.BUTTON1_MASK) == 0) return;
+
+    Rectangle zm = getZoomBounds();
+    if(zm.width <= 1 || zm.height <= 1) return;
+
+    Domain zoom = getZoomBoundsU();
+
+    setClipping(true);
+
+    if(getFirstLayer().getGraph() instanceof CartesianGraph) {
+      try {
+        setRange(zoom);
+      } catch (PropertyVetoException e) {
+        System.out.println("Zoom denied! " + e);
+      }
+    }
+    //    draw();
+  }
+
+  void Layout_MousePress(java.awt.event.MouseEvent event) {
+    if(event.isControlDown()) {
+      resetZoom();
+      setClipping(false);
+      //      draw();
+    }
+  }
+
+  void Layout_MouseClicked(java.awt.event.MouseEvent event) {
+    if(event.isControlDown()) return;
+    Object obj = getSelectedObject();
+    if(obj instanceof LineCartesianRenderer) {
+      LineCartesianRenderer line = (LineCartesianRenderer)obj;
+      LineAttribute attr = line.getLineAttribute();
+      if(attr.getStyle() == LineAttribute.SOLID) {
+        attr.setStyle(LineAttribute.HIGHLIGHT);
+      } else if(attr.getStyle() == LineAttribute.HIGHLIGHT) {
+        attr.setStyle(LineAttribute.SOLID);
+      }
+      //      draw();
+    }
+
+    if(((event.getModifiers()&InputEvent.BUTTON3_MASK) != 0) &&
+       editClasses_) {
+      showProperties(obj);
+    }
+  }
+
+  void KeyPane_MousePress(java.awt.event.MouseEvent event) {
+  }
+
+  void KeyPane_MouseClicked(java.awt.event.MouseEvent event) {
+    if(keyPane_ == null) return;
+    Object obj = keyPane_.getSelectedObject();
+    if(obj instanceof LineCartesianRenderer) {
+      LineCartesianRenderer line = (LineCartesianRenderer)obj;
+      LineAttribute attr = line.getLineAttribute();
+      if(attr.getStyle() == LineAttribute.SOLID) {
+        attr.setStyle(LineAttribute.HIGHLIGHT);
+      } else if(attr.getStyle() == LineAttribute.HIGHLIGHT) {
+        attr.setStyle(LineAttribute.SOLID);
+      }
+      //      draw();
+      //      keyPane_.draw();
+    }
+    if(editClasses_) {
+      showProperties(obj);
+    }
+  }
+  /**
+   * Enable <code>sgt</code> object property editing
+   */
+  public void setEditClasses(boolean b) {
+    editClasses_ = b;
+  }
+  /**
+   * Are <code>sgt</code> objects editable?
+   */
+  public boolean isEditClasses() {
+    return editClasses_;
+  }
+  /**
+   * Determine if the object selected is an SGLabel, PlainAxis, or
+   * TimeAxis. Depending on the answer create the appropriate dialog.
+   */
+  void showProperties(Object obj) {
+    if(obj instanceof SGLabel) {
+      if(sg_props_ == (SGLabelDialog) null) {
+        //
+        // create the SGLabelDialog
+        //
+        sg_props_ = new SGLabelDialog();
+      }
+      sg_props_.setSGLabel((SGLabel) obj, this);
+      if(!sg_props_.isShowing())
+        sg_props_.show();
+    } else if(obj instanceof PlainAxis) {
+      if(pa_props_ == (SpaceAxisDialog) null) {
+        //
+        // create the PlainAxis dialog
+        //
+        pa_props_ = new SpaceAxisDialog();
+      }
+      pa_props_.setSpaceAxis((PlainAxis) obj, this);
+      if(!pa_props_.isShowing())
+        pa_props_.show();
+    } else if(obj instanceof TimeAxis) {
+      if(ta_props_ == (TimeAxisDialog) null) {
+        //
+        // create the TimeAxis Dialog
+        //
+        ta_props_ = new TimeAxisDialog();
+      }
+      ta_props_.setTimeAxis((TimeAxis) obj, this);
+      if(!ta_props_.isShowing())
+        ta_props_.show();
+    } else if (obj instanceof Logo) {
+      if(lo_props_ == (LogoDialog) null) {
+        //
+        // create the LogoProperties dialog
+        //
+        lo_props_ = new LogoDialog();
+      }
+      lo_props_.setLogo((Logo) obj, this);
+      if(!lo_props_.isShowing())
+        lo_props_.show();
+    }
+  }
+
+  private Frame getFrame() {
+    Container theFrame = this;
+    do {
+      theFrame = theFrame.getParent();
+    } while ((theFrame != null) && !(theFrame instanceof Frame));
+    if (theFrame == null)
+      theFrame = new Frame();
+    return (Frame) theFrame;
+  }
+  /**
+   * Set the clip range for all <code>Layer</code>s.
+   */
+  protected void setAllClip(SoTRange xr, SoTRange yr) {
+    if(yr.isTime()) {
+      setAllClip(yr.getStart().getLongTime(),
+                 yr.getEnd().getLongTime(),
+                 ((SoTRange.Double)xr).start,
+                 ((SoTRange.Double)xr).end);
+    } else {
+      if(xr.isTime()) {
+        setAllClip(xr.getStart().getLongTime(),
+                   xr.getEnd().getLongTime(),
+                   ((SoTRange.Double)yr).start,
+                   ((SoTRange.Double)yr).end);
+      } else {
+        setAllClip(((SoTRange.Double)xr).start,
+                   ((SoTRange.Double)xr).end,
+                   ((SoTRange.Double)yr).start,
+                   ((SoTRange.Double)yr).end);
+      }
+    }
+  }
+
+  /**
+   * Set the clip range for all <code>Layer</code>s.
+   */
+  protected void setAllClip(double xmin, double xmax, double ymin, double ymax) {
+    Layer ly;
+    Component[] comps = getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ly = (Layer)comps[i];
+        ((CartesianGraph)ly.getGraph()).setClip(xmin, xmax, ymin, ymax);
+      }
+    }
+  }
+  /**
+   * Set the clip range for all <code>Layer</code>s.
+   */
+  protected void setAllClip(GeoDate tmin, GeoDate tmax, double min, double max) {
+//    System.out.println("setAllClip(" + tmin + ", " + tmax + ", " + min + ", " + max + ")");
+    setAllClip(tmin.getTime(), tmax.getTime(), min, max);
+/*    Layer ly;
+    Component[] comps = getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ly = (Layer)comps[i];
+        ((CartesianGraph)ly.getGraph()).setClip(tmin, tmax, min, max);
+      }
+    } */
+  }
+  /**
+   * @since 3.0
+   */
+  protected void setAllClip(long tmin, long tmax, double min, double max) {
+//    System.out.println("setAllClip(" + tmin + ", " + tmax + ", " + min + ", " + max + ")");
+    Layer ly;
+    Component[] comps = getComponents();
+    for(int i=0; i < comps.length; i++) {
+      ly = (Layer)comps[i];
+      ((CartesianGraph)ly.getGraph()).setClip(tmin, tmax, min, max);
+    }
+  }
+  /**
+   * Turn on clipping for all <code>Layer</code>s.
+   */
+  protected void setAllClipping(boolean clip) {
+    Layer ly;
+    Component[] comps = getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ly = (Layer)comps[i];
+        ((CartesianGraph)ly.getGraph()).setClipping(clip);
+      }
+    }
+  }
+  /**
+   * Get the bounds for the line or color key.
+   */
+  public abstract Rectangle2D.Double getKeyBoundsP();
+  /**
+   * Set the bounds for the line or color key.
+   */
+  public abstract void setKeyBoundsP(Rectangle2D.Double r);
+  /**
+   * Get the size of the key layer in physical coordinates.
+   */
+  public Dimension2D getKeyLayerSizeP() {
+    if(keyPane_ != null) {
+      return keyPane_.getFirstLayer().getSizeP();
+    }
+    return null;
+  }
+  /**
+   * Set the size of the key layer in physical coordinates.
+   */
+  public void setKeyLayerSizeP(Dimension2D d) {
+    if(keyPane_ != null) {
+      keyPane_.getFirstLayer().setSizeP(d);
+    }
+  }
+  public void addVetoableChangeListener(VetoableChangeListener l) {
+    vetos_.addVetoableChangeListener(l);
+  }
+  public void removeVetoableChangeListener(VetoableChangeListener l) {
+    vetos_.removeVetoableChangeListener(l);
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+  public void finalize(){
+	  changes_ = null;
+	  vetos_ = null;
+	  data_ = null;
+	  dataAttrMap_ = null;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JLineProfileLayout.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JLineProfileLayout.java
new file mode 100755
index 0000000..49199a4
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JLineProfileLayout.java
@@ -0,0 +1,884 @@
+/*
+ * $Id: JLineProfileLayout.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.LineKey;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Logo;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.LayerNotFoundException;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.AxisNotFoundException;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.SGException;
+import gov.noaa.pmel.sgt.StackedLayout;
+
+import gov.noaa.pmel.util.Domain;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Range2D;
+//import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.Units;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SimpleLine;
+import gov.noaa.pmel.sgt.dm.SGTMetaData;
+import gov.noaa.pmel.sgt.dm.Collection;
+
+
+import java.util.Enumeration;
+import java.util.Vector;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Color;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Component;
+
+import java.beans.PropertyVetoException;
+
+/**
+ * JLineProfileLayout creates a pre-defined graphics layout for
+ * profile data using LineCartesianGraph. This layout is application specific.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @see LineCartesianRenderer
+ * @deprecated As of v2.0, replaced by {@link gov.noaa.pmel.sgt.swing.JPlotLayout}
+**/
+/*oodE***********************************************/
+public class JLineProfileLayout extends JGraphicLayout {
+  //
+  // save handles to unique components
+  //
+  Logo logo_;
+  LineKey lineKey_;
+  int layerCount_;
+  boolean zUp_ = true;
+  Layer firstLayer_;
+  boolean inZoom_ = false;
+  //
+  // constants
+  //
+  double xSize_ = XSIZE_;
+  double xMin_ = XMIN_;
+  double xMax_ = XMAX_;
+  double ySize_ = YSIZE_;
+  double yMin_ = YMIN_;
+  double yMax_ = YMAX_;
+  //
+  double mainTitleHeight_ = MAIN_TITLE_HEIGHT_;
+  double titleHeight_ = TITLE_HEIGHT_;
+  double labelHeight_ = LABEL_HEIGHT_;
+  double warnHeight_ = WARN_HEIGHT_;
+  double keyHeight_ = KEY_HEIGHT_;
+  //
+  double xKeySize_ = XKEYSIZE_;
+  double yKeySize_ = YKEYSIZE_;
+  //
+  Color paneColor_ = PANE_COLOR;
+  Color keyPaneColor_ = KEYPANE_COLOR;
+
+  //
+  private static final Color[] colorList_ =
+  { Color.blue, Color.cyan, Color.green, Color.orange.darker(),
+    Color.red, Color.magenta, Color.black, Color.gray};
+  //  {Color.red, Color.green, Color.blue, Color.cyan,
+  //   Color.magenta, Color.yellow, Color.orange, Color.pink};
+  private static final int[] markList_ =
+  {1, 2, 9, 15, 10, 24, 11, 44};
+  /**
+   * Default constructor. No Logo image is used and the LineKey
+   * will be in the same Pane.
+   */
+  public JLineProfileLayout() {
+    this("", null, false);
+  }
+  /**
+   * JLineProfileLayout constructor.
+   *
+   * @param id identifier
+   * @param img Logo image
+   * @param is_key_pane if true LineKey is in separate pane
+   */
+  public JLineProfileLayout(String id, Image img, boolean is_key_pane) {
+    super(id, img, new Dimension(400,300));
+    Layer layer, key_layer;
+    CartesianGraph graph;
+    LinearTransform xt, yt;
+    PlainAxis xbot, yleft;
+    double xpos, ypos;
+    int halign;
+    //
+    // create Pane and descendants for the LineProfile layout
+    //
+    setOpaque(true);
+    setLayout(new StackedLayout());
+    setBackground(paneColor_);
+    layer = new Layer("Layer 1", new Dimension2D(xSize_, ySize_));
+    firstLayer_ = layer;
+    add(layer,0);
+    //
+    lineKey_ = new LineKey();
+    lineKey_.setSelectable(false);
+    lineKey_.setId("Line Key");
+    lineKey_.setVAlign(LineKey.TOP);
+    if(is_key_pane) {
+      lineKey_.setHAlign(LineKey.LEFT);
+      lineKey_.setBorderStyle(LineKey.NO_BORDER);
+      lineKey_.setLocationP(new Point2D.Double(0.0, yKeySize_));
+      int xdim = 400;
+      int ydim = (int)((double)xdim/xKeySize_*yKeySize_);
+      keyPane_ = new JPane("KeyPane", new Dimension(xdim,ydim));
+      keyPane_.setOpaque(true);
+      keyPane_.setLayout(new StackedLayout());
+      keyPane_.setBackground(keyPaneColor_);
+      key_layer = new Layer("Key Layer", new Dimension2D(xKeySize_, yKeySize_));
+      keyPane_.add(key_layer);
+      key_layer.addChild(lineKey_);
+    } else {
+      lineKey_.setHAlign(LineKey.RIGHT);
+      lineKey_.setLocationP(new Point2D.Double(xSize_ - 0.01, ySize_));
+      layer.addChild(lineKey_);
+    }
+    //
+    // add Icon
+    //
+    if(iconImage_ != null) {
+      logo_ = new Logo(new Point2D.Double(0.0, ySize_), Logo.TOP, Logo.LEFT);
+      logo_.setImage(iconImage_);
+      layer.addChild(logo_);
+      Rectangle bnds = logo_.getBounds();
+      xpos = layer.getXDtoP(bnds.x + bnds.width) + 0.05;
+      halign = SGLabel.LEFT;
+    } else {
+      xpos = (xMin_ + xMax_)*0.5;
+      halign = SGLabel.CENTER;
+    }
+    //
+    // title
+    //
+    ypos = ySize_ - 1.2f*mainTitleHeight_;
+    Font titleFont = new Font("Helvetica", Font.BOLD, 14);
+    mainTitle_ = new SGLabel("Line Profile Title",
+                             "Profile Plot",
+                             mainTitleHeight_,
+                             new Point2D.Double(xpos, ypos),
+                             SGLabel.BOTTOM,
+                             halign);
+    mainTitle_.setFont(titleFont);
+    layer.addChild(mainTitle_);
+    ypos = ypos - 1.2f*warnHeight_;
+    Font title2Font = new Font("Helvetica", Font.PLAIN, 10);
+    title2_ = new SGLabel("Warning",
+                          "Warning: Browse image only",
+                          warnHeight_,
+                          new Point2D.Double(xpos, ypos),
+                          SGLabel.BOTTOM,
+                          halign);
+    title2_.setFont(title2Font);
+    layer.addChild(title2_);
+    ypos = ypos - 1.1f*warnHeight_;
+    title3_ = new SGLabel("Warning 2",
+                          "Verify accuracy of plot before research use",
+                          warnHeight_,
+                          new Point2D.Double(xpos, ypos),
+                          SGLabel.BOTTOM,
+                          halign);
+    title3_.setFont(title2Font);
+    layer.addChild(title3_);
+    //
+    title3_.setSelectable(false);
+
+    layerCount_ = 0;
+    //
+    // create LineCartesianGraph and transforms
+    //
+    graph = new CartesianGraph("Profile Graph 1");
+    xt = new LinearTransform(xMin_, xMax_, 10.0, 20.0);
+    yt = new LinearTransform(yMin_, yMax_, 400.0, 0.0);
+    graph.setXTransform(xt);
+    graph.setYTransform(yt);
+    //
+    // create axes
+    //
+    Font axfont = new Font("Helvetica", Font.ITALIC, 14);
+    xbot = new PlainAxis("Bottom Axis");
+    xbot.setRangeU(new Range2D(10.0, 20.0));
+    xbot.setDeltaU(2.0);
+    xbot.setNumberSmallTics(0);
+    xbot.setLabelHeightP(labelHeight_);
+    xbot.setLocationU(new Point2D.Double(10.0, 400.0));
+    xbot.setLabelFont(axfont);
+    graph.addXAxis(xbot);
+    //
+    yleft = new PlainAxis("Left Axis");
+    yleft.setRangeU(new Range2D(400.0, 0.0));
+    yleft.setDeltaU(-50.0);
+    yleft.setNumberSmallTics(0);
+    yleft.setLabelHeightP(labelHeight_);
+    yleft.setLocationU(new Point2D.Double(10.0, 400.0));
+    yleft.setLabelFont(axfont);
+    graph.addYAxis(yleft);
+    //
+    layer.setGraph(graph);
+  }
+  public String getLocationSummary(SGTData grid) {
+    return "";
+  }
+  public void addData(Collection lines) {
+    addData(lines, null);
+  }
+  public void addData(Collection lines, String descrip) {
+    //    System.out.println("addData(Collection) called");
+    for(int i=0; i < lines.size(); i++) {
+      SGTLine line = (SGTLine)lines.elementAt(i);
+      addData(line, line.getTitle());
+    }
+  }
+  /**
+   * Add data to the layout. LineKey descriptor will be
+   * taken from the dependent variable name.
+   *
+   * @param data datum data to be added
+   */
+  public void addData(SGTData datum) {
+    addData(datum, null);
+  }
+  /**
+   * Add data to the layout.  Data will be added to X axis and Z_AXIS will be
+   * assigned to Y axis. If this is not the first invocation of addData a new Layer
+   * will be created. If overlayed, the transforms from the first layer will be
+   * attached and <B>no</B> axes will be created. If not overlayed, new transforms
+   * and axes will be created and adjusted so that the data is horizontally stacked.
+   *
+   * @param datum data to be added
+   * @param descrip LineKey description for datum
+   */
+  public void addData(SGTData datum, String descrip) {
+    //
+    Layer layer, newLayer;
+    CartesianGraph graph, newGraph;
+    PlainAxis xbot = null;
+    PlainAxis yleft = null;
+    LinearTransform xt, yt;
+    SGLabel xtitle, ytitle, lineTitle;
+    SGTData data;
+    LineAttribute lineAttr;
+    String xLabel, yLabel;
+    Range2D xRange, yRange;
+    Range2D xnRange = null, ynRange = null;
+    Point2D.Double origin = null;
+    boolean data_good = true;
+    double save;
+    //
+    if(data_.size() == 0) setBaseUnit(Units.getBaseUnit(((SGTLine)datum).getXMetaData()));
+    datum = Units.convertToBaseUnit(datum, getBaseUnit(), Units.X_AXIS);
+    //
+    if(data_.size() == 0) {
+      super.addData(datum);
+      //
+      // only one data set...
+      // determine range and titles from data
+      //
+      data = (SGTData)data_.firstElement();
+      xRange = findRange((SGTLine)data, X_AXIS);
+      yRange = findRange((SGTLine)data, Y_AXIS);
+      zUp_ = ((SGTLine)data).getYMetaData().isReversed();
+
+      if(Double.isNaN(xRange.start) || Double.isNaN(yRange.start)) data_good = false;
+
+      if(data_good) {
+        if(!zUp_) {
+          save = yRange.end;
+          yRange.end = yRange.start;
+          yRange.start = save;
+        }
+        //
+        xnRange = Graph.computeRange(xRange, 6);
+        ynRange = Graph.computeRange(yRange, 6);
+        //
+        origin = new Point2D.Double(xnRange.start, ynRange.start);
+      }
+      //
+      xLabel =  " (" + ((SGTLine)data).getXMetaData().getUnits() + ")";
+      yLabel =  " (" + ((SGTLine)data).getYMetaData().getUnits() + ")";
+      //
+      // attach information to pane and descendents
+      //
+      try {
+        layer = getLayer("Layer 1");
+      } catch (LayerNotFoundException e) {
+        return;
+      }
+      graph = (CartesianGraph)layer.getGraph();
+      //
+      // axes
+      //
+      try {
+        Font tfont = new Font("Helvetica", Font.PLAIN, 14);
+        xbot = (PlainAxis)graph.getXAxis("Bottom Axis");
+        if(data_good) {
+          xbot.setRangeU(xnRange);
+          xbot.setDeltaU(xnRange.delta);
+          xbot.setLocationU(origin);
+        }
+        xtitle = new SGLabel("xaxis title", xLabel, new Point2D.Double(0.0, 0.0));
+        xtitle.setFont(tfont);
+        xtitle.setHeightP(titleHeight_);
+        xbot.setTitle(xtitle);
+        //
+        yleft = (PlainAxis)graph.getYAxis("Left Axis");
+        if(data_good) {
+          yleft.setRangeU(ynRange);
+          yleft.setDeltaU(ynRange.delta);
+          yleft.setLocationU(origin);
+        }
+        ytitle = new SGLabel("yaxis title", yLabel, new Point2D.Double(0.0, 0.0));
+        ytitle.setFont(tfont);
+        ytitle.setHeightP(titleHeight_);
+        yleft.setTitle(ytitle);
+      } catch (AxisNotFoundException e) {}
+      if(data_good) {
+        //
+        // transforms
+        //
+        xt = (LinearTransform)graph.getXTransform();
+        xt.setRangeU(xnRange);
+        //
+        yt = (LinearTransform)graph.getYTransform();
+        yt.setRangeU(ynRange);
+      }
+      //
+      // attach data
+      //
+      if(((SGTLine)data).getYArray().length >= 2) {
+        lineAttr = new LineAttribute(LineAttribute.SOLID,
+                                     markList_[layerCount_%8],
+                                     colorList_[layerCount_%8]);
+      } else {
+        lineAttr = new LineAttribute(LineAttribute.MARK,
+                                     markList_[layerCount_%8],
+                                     colorList_[layerCount_%8]);
+      }
+      graph.setData(data, lineAttr);
+      //
+      // add to lineKey
+      //
+      if(descrip == null) {
+        lineTitle = new SGLabel("line title", xLabel, new Point2D.Double(0.0, 0.0));
+      } else {
+        lineTitle = new SGLabel("line title", descrip, new Point2D.Double(0.0, 0.0));
+      }
+      lineTitle.setHeightP(keyHeight_);
+      lineKey_.addLineGraph((LineCartesianRenderer)graph.getRenderer(), lineTitle);
+      if(keyPane_ != null) {
+        Rectangle vRect = keyPane_.getVisibleRect();
+        int nrow = vRect.height/lineKey_.getRowHeight();
+        keyPane_.setScrollableUnitIncrement(1, lineKey_.getRowHeight());
+        keyPane_.setScrollableBlockIncrement(vRect.width,
+                                             lineKey_.getRowHeight()*nrow);
+      }
+    } else {
+      //
+      // more than one data set...
+      // add new layer
+      //
+      if(((SGTLine)datum).getYMetaData().isReversed() != zUp_) {
+        //        System.out.println("New datum has reversed ZUp!");
+        SGTData modified = flipZ(datum);
+        datum = modified;
+      }
+      super.addData(datum);
+
+      data_good = false;
+      layerCount_++;
+      if(isOverlayed()) {
+        try {
+          layer = getLayer("Layer 1");
+        } catch (LayerNotFoundException e) {
+          return;
+        }
+        graph = (CartesianGraph)layer.getGraph();
+        //
+        // transforms
+        //
+        xt = (LinearTransform)graph.getXTransform();
+        yt = (LinearTransform)graph.getYTransform();
+        try {
+          xbot = (PlainAxis)graph.getXAxis("Bottom Axis");
+          yleft = (PlainAxis)graph.getYAxis("Left Axis");
+        } catch (AxisNotFoundException e) {}
+
+        if(!inZoom_) {
+          //
+          // loop over data sets, getting ranges
+          //
+          Range2D xTotalRange = new Range2D();
+          Range2D yTotalRange = new Range2D();
+
+          boolean first = true;
+          for (Enumeration e = data_.elements() ; e.hasMoreElements() ;) {
+            data = (SGTData)e.nextElement();
+            xRange = findRange((SGTLine)data, X_AXIS);
+            yRange = findRange((SGTLine)data, Y_AXIS);
+            if(!((SGTLine)data).getYMetaData().isReversed()) {
+              save = yRange.start;
+              yRange.start = yRange.end;
+              yRange.end = save;
+            }
+            if(first) {
+              if(Double.isNaN(xRange.start) || Double.isNaN(yRange.start)) {
+                first = true;
+              } else {
+                first = false;
+                data_good = true;
+                xTotalRange = new Range2D(xRange.start, xRange.end);
+                yTotalRange = new Range2D(yRange.start, yRange.end);
+              }
+            } else {
+              if(!Double.isNaN(xRange.start) && !Double.isNaN(yRange.start)) {
+                data_good = true;
+                xTotalRange.start = Math.min(xTotalRange.start, xRange.start);
+                xTotalRange.end = Math.max(xTotalRange.end, xRange.end);
+                if(!((SGTLine)data).getYMetaData().isReversed()) {
+                  yTotalRange.start = Math.max(yTotalRange.start, yRange.start);
+                  yTotalRange.end = Math.min(yTotalRange.end, yRange.end);
+                } else {
+                  yTotalRange.start = Math.min(yTotalRange.start, yRange.start);
+                  yTotalRange.end = Math.max(yTotalRange.end, yRange.end);
+                }
+              }
+            }
+          }
+          if(data_good) {
+            xnRange = Graph.computeRange(xTotalRange, 6);
+            ynRange = Graph.computeRange(yTotalRange, 6);
+            origin = new Point2D.Double(xnRange.start, ynRange.start);
+            //
+            // axes
+            //
+            xbot.setRangeU(xnRange);
+            xbot.setDeltaU(xnRange.delta);
+            xbot.setLocationU(origin);
+            //
+            yleft.setRangeU(ynRange);
+            yleft.setDeltaU(ynRange.delta);
+            yleft.setLocationU(origin);
+          }
+          //
+          if(data_good) {
+            xt.setRangeU(xnRange);
+            yt.setRangeU(ynRange);
+          }
+        }
+        //
+        // create new layer and graph
+        //
+        newLayer = new Layer("Layer " + (layerCount_+1), new Dimension2D(xSize_, ySize_));
+        newGraph = new CartesianGraph("Graph " + (layerCount_+1), xt, yt);
+        if(inZoom_) {
+          Range2D xr, yr;
+          xr = xbot.getRangeU();
+          yr = yleft.getRangeU();
+          newGraph.setClip(xr.start, xr.end, yr.start, yr.end);
+          newGraph.setClipping(true);
+        }
+        add(newLayer,0);
+        newLayer.setGraph(newGraph);
+        newLayer.invalidate();
+        validate();
+        //
+        // attach data
+        //
+        if(((SGTLine)datum).getXArray().length >= 2) {
+          lineAttr = new LineAttribute(LineAttribute.SOLID,
+                                       markList_[layerCount_%8],
+                                       colorList_[layerCount_%8]);
+        } else {
+          lineAttr = new LineAttribute(LineAttribute.MARK,
+                                       markList_[layerCount_%8],
+                                       colorList_[layerCount_%8]);
+        }
+        newGraph.setData(datum, lineAttr);
+        //
+        // add to lineKey
+        //
+        if(descrip == null) {
+          xLabel = ((SGTLine)datum).getXMetaData().getName();
+          lineTitle = new SGLabel("line title", xLabel, new Point2D.Double(0.0, 0.0));
+        } else {
+          lineTitle = new SGLabel("line title", descrip, new Point2D.Double(0.0, 0.0));
+        }
+        lineTitle.setHeightP(keyHeight_);
+        lineKey_.addLineGraph((LineCartesianRenderer)newGraph.getRenderer(), lineTitle);
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          int nrow = vRect.height/lineKey_.getRowHeight();
+          keyPane_.setScrollableUnitIncrement(1, lineKey_.getRowHeight());
+          keyPane_.setScrollableBlockIncrement(vRect.width,
+                                               lineKey_.getRowHeight()*nrow);
+        }
+      }
+    }
+  }
+  /**
+   * Flip the zaxis.  Reverse the direction of the z axis by changing the sign
+   * of the axis values and isBackward flag.
+   */
+  private SGTData flipZ(SGTData in) {
+    SGTMetaData zmetaout;
+    SGTMetaData zmetain;
+    SimpleLine out = null;
+    SGTLine line = (SGTLine) in;
+    double[] values;
+    double[] newValues;
+    values = line.getYArray();
+    newValues = new double[values.length];
+    for(int i=0; i < values.length; i++) {
+      newValues[i] = -values[i];
+    }
+    out = new SimpleLine(line.getXArray(), newValues, line.getTitle());
+    zmetain = line.getYMetaData();
+    zmetaout = new SGTMetaData(zmetain.getName(), zmetain.getUnits(),
+                               !zmetain.isReversed(), zmetain.isModulo());
+    zmetaout.setModuloValue(zmetain.getModuloValue());
+    zmetaout.setModuloTime(zmetain.getModuloTime());
+    out.setXMetaData(line.getXMetaData());
+    out.setYMetaData(zmetaout);
+    return (SGTData)out;
+  }
+  /**
+   * Clear the current zoom.
+   */
+  public void resetZoom() {
+    SGTData data;
+    Range2D xRange, yRange;
+    boolean data_good = false;
+    double save;
+
+    inZoom_ = false;
+    //
+    // loop over data sets, getting ranges
+    //
+    Range2D xTotalRange = new Range2D();
+    Range2D yTotalRange = new Range2D();
+
+    boolean first = true;
+
+    for (Enumeration e = data_.elements() ; e.hasMoreElements() ;) {
+      data = (SGTData)e.nextElement();
+      xRange = findRange((SGTLine)data, X_AXIS);
+      yRange = findRange((SGTLine)data, Y_AXIS);
+      if(!((SGTLine)data).getYMetaData().isReversed()) {
+        save = yRange.start;
+        yRange.start = yRange.end;
+        yRange.end = save;
+      }
+      if(first) {
+        if(Double.isNaN(xRange.start) || Double.isNaN(yRange.start)) {
+          first = true;
+        } else {
+          first = false;
+          data_good = true;
+          xTotalRange = new Range2D(xRange.start, xRange.end);
+          yTotalRange = new Range2D(yRange.start, yRange.end);
+        }
+      } else {
+        if(!Double.isNaN(xRange.start) && !Double.isNaN(yRange.start)) {
+          data_good = true;
+          xTotalRange.start = Math.min(xTotalRange.start, xRange.start);
+          xTotalRange.end = Math.max(xTotalRange.end, xRange.end);
+          if(!((SGTLine)data).getYMetaData().isReversed()) {
+            yTotalRange.start = Math.max(yTotalRange.start, yRange.start);
+            yTotalRange.end = Math.min(yTotalRange.end, yRange.end);
+          } else {
+            yTotalRange.start = Math.min(yTotalRange.start, yRange.start);
+            yTotalRange.end = Math.max(yTotalRange.end, yRange.end);
+          }
+        }
+      }
+    }
+    if(data_good) {
+      try {
+        setRange(new Domain(xTotalRange, yTotalRange), false);
+      } catch (PropertyVetoException e) {
+        System.out.println("zoom reset denied! " + e);
+      }
+    }
+  }
+  /**
+   * Set the x and y range of the domain.
+   *
+   * @param range new domain
+   */
+  public void setRange(Domain domain) throws PropertyVetoException {
+    setRange(domain, true);
+  }
+  public void setRange(Domain domain, boolean testZUp)
+    throws PropertyVetoException {
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    Domain oldRange = new Domain(xt.getRangeU(),
+                                           yt.getRangeU());
+    if(!domain.equals(oldRange)) {
+      setBatch(true, "JLineProfileLayout: setRange");
+      vetos_.fireVetoableChange("domainRange", oldRange, domain);
+
+      inZoom_ = true;
+
+      if(!domain.isXTime()) {
+        setXRange(domain.getXRange());
+      }
+      if(!domain.isYTime()) {
+        setYRange(domain.getYRange(), testZUp);
+      }
+      changes_.firePropertyChange("domainRange", oldRange, domain);
+      setBatch(false, "JLineProfileLayout: setRange");
+    }
+  }
+  public void setRangeNoVeto(Domain domain) {
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    Domain oldRange = new Domain(xt.getRangeU(),
+                                           yt.getRangeU());
+    //
+    // clipping?  hack fix.  how should clipping be done for
+    // external range sets?
+    //
+    setBatch(true, "JLineProfileLayout: setRangeNoVeto");
+    inZoom_ = true;
+    setClipping(true);
+
+    if(!domain.isXTime()) {
+      setXRange(domain.getXRange());
+    }
+    if(!domain.isYTime()) {
+      setYRange(domain.getYRange(),false);
+    }
+    setBatch(false, "JLineProfileLayout: setRangeNoVeto");
+    //    changes_.firePropertyChange("domainRange", oldRange, domain);
+  }
+  /**
+   * Reset the x range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param rnge new x range
+   */
+  void setXRange(Range2D rnge) {
+    Point2D.Double origin;
+    PlainAxis xbot, yleft;
+    Range2D xr, yr, xnRange;
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    xnRange = Graph.computeRange(rnge, 6);
+    xt.setRangeU(xnRange);
+    try {
+      xbot = (PlainAxis)graph.getXAxis("Bottom Axis");
+      yleft = (PlainAxis)graph.getYAxis("Left Axis");
+
+      xbot.setRangeU(xnRange);
+      xbot.setDeltaU(xnRange.delta);
+
+      xr = xbot.getRangeU();
+      yr = yleft.getRangeU();
+      origin = new Point2D.Double(xr.start, yr.start);
+      xbot.setLocationU(origin);
+
+      yleft.setLocationU(origin);
+      //
+      // set clipping
+      //
+      if(clipping_) {
+        setAllClip(xr.start, xr.end, yr.start, yr.end);
+      } else {
+        setAllClipping(false);
+      }
+    } catch (AxisNotFoundException e) {}
+  }
+  /**
+   * Reset the y range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param rnge new y range
+   */
+  void setYRange(Range2D rnge) {
+    setYRange(rnge, true);
+  }
+
+  /**
+   * Reset the y range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param rnge new y range
+   * @param testZUp test to see if Z is Up
+   */
+  void setYRange(Range2D rnge, boolean testZUp) {
+    SGTData grid;
+    Point2D.Double origin;
+    PlainAxis xbot, yleft;
+    Range2D xr, yr, ynRange;
+    double save;
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    if(testZUp && data_.size() > 0) {
+      grid = (SGTData)data_.elements().nextElement();
+      if(!((SGTLine)grid).getYMetaData().isReversed()) {
+        save = rnge.end;
+        rnge.end = rnge.start;
+        rnge.start = save;
+      }
+    }
+    ynRange = Graph.computeRange(rnge, 6);
+    yt.setRangeU(ynRange);
+    try {
+      xbot = (PlainAxis)graph.getXAxis("Bottom Axis");
+      yleft = (PlainAxis)graph.getYAxis("Left Axis");
+
+      yleft.setRangeU(ynRange);
+      yleft.setDeltaU(ynRange.delta);
+
+      xr = xbot.getRangeU();
+      yr = yleft.getRangeU();
+      origin = new Point2D.Double(xr.start, yr.start);
+      yleft.setLocationU(origin);
+
+      xbot.setLocationU(origin);
+      //
+      // set clipping
+      //
+      if(clipping_) {
+        setAllClip(xr.start, xr.end, yr.start, yr.end);
+      } else {
+        setAllClipping(false);
+      }
+    } catch (AxisNotFoundException e) {}
+  }
+  private void setAllClip(JPane pane, double xmin, double xmax, double ymin, double ymax) {
+    Layer ly;
+    Component[] comps = pane.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ly = (Layer)comps[i];
+        ((CartesianGraph)ly.getGraph()).setClip(xmin, xmax, ymin, ymax);
+      }
+    }
+  }
+  private void setAllClipping(JPane pane, boolean clip) {
+    Layer ly;
+    Component[] comps = pane.getComponents();
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ly = (Layer)comps[i];
+        ((CartesianGraph)ly.getGraph()).setClipping(clip);
+      }
+    }
+  }
+  public void clear() {
+    data_.removeAllElements();
+    ((CartesianGraph)firstLayer_.getGraph()).setRenderer(null);
+    removeAll();
+    add(firstLayer_,0);   // restore first layer
+    lineKey_.clearAll();
+    //    draw();
+    //    if(keyPane_ != null)keyPane_.draw();
+    inZoom_ = false;
+  }
+
+  public void clear(String data_id) {
+    Layer ly = null;
+    SGTData dat;
+    try {
+      ly = getLayerFromDataId(data_id);
+      remove(ly);
+    } catch (LayerNotFoundException e) {}
+    for(Enumeration it=data_.elements(); it.hasMoreElements();) {
+      dat = (SGTData)it.nextElement();
+      if(dat.getId().equals(data_id)) {
+        data_.removeElement(dat);
+      }
+    }
+    lineKey_.clear(data_id);
+    if(getComponentCount() <= 0 || ly.equals(firstLayer_)) {
+      ((CartesianGraph)firstLayer_.getGraph()).setRenderer(null);
+      add(firstLayer_,0);  // restore first layer
+    }
+    //    draw();
+    //    if(keyPane_ != null)keyPane_.draw();
+  }
+
+  public void setKeyBoundsP(Rectangle2D.Double bounds){
+    if(lineKey_ != null) {
+      lineKey_.setBoundsP(bounds);
+    }
+  }
+  public Rectangle2D.Double getKeyBoundsP() {
+    if(lineKey_ == null) {
+      return null;
+    } else {
+      return lineKey_.getBoundsP();
+    }
+  }
+
+  public Dimension2D getLayerSizeP() {
+    return new Dimension2D(xSize_, ySize_);
+  }
+  public Layer getFirstLayer() {
+    return firstLayer_;
+  }
+  public void setLayerSizeP(Dimension2D d) {
+    Component[] comps = getComponents();
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    xMax_ = d.width - (xSize_ - xMax_);
+    yMax_ = d.height - (ySize_ - yMax_);
+    xSize_ = d.width;
+    ySize_ = d.height;
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ((Layer)comps[i]).setSizeP(d);
+      }
+    }
+    yt.setRangeP(new Range2D(yMin_, yMax_));
+    xt.setRangeP(new Range2D(xMin_, xMax_));
+    //
+    double xpos;
+    if(iconImage_ != null) {
+      Rectangle bnds = logo_.getBounds();
+      xpos = firstLayer_.getXDtoP(bnds.x + bnds.width) + 0.05;
+    } else {
+      xpos = (xMin_ + xMax_)*0.5;
+    }
+    double ypos = ySize_ - 1.2f*mainTitleHeight_;
+    mainTitle_.setLocationP(new Point2D.Double(xpos, ypos));
+    ypos = ypos - 1.2f*warnHeight_;
+    title2_.setLocationP(new Point2D.Double(xpos, ypos));
+    ypos = ypos - 1.1f*warnHeight_;
+    title3_.setLocationP(new Point2D.Double(xpos, ypos));
+    if(keyPane_ == null) {
+      lineKey_.setLocationP(new Point2D.Double(xSize_ - 0.01, ySize_));
+    }
+
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JPlotLayout.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JPlotLayout.java
new file mode 100755
index 0000000..488afcd
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/JPlotLayout.java
@@ -0,0 +1,2293 @@
+/*
+ * $Id: JPlotLayout.java,v 1.1.1.2 2008/12/19 13:29:38 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.LineKey;
+import gov.noaa.pmel.sgt.PointCollectionKey;
+import gov.noaa.pmel.sgt.ColorKey;
+import gov.noaa.pmel.sgt.VectorKey;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.CartesianRenderer;
+import gov.noaa.pmel.sgt.LineCartesianRenderer;
+import gov.noaa.pmel.sgt.PointCartesianRenderer;
+import gov.noaa.pmel.sgt.GridCartesianRenderer;
+import gov.noaa.pmel.sgt.VectorCartesianRenderer;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.PlainAxis;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.Logo;
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.LayerNotFoundException;
+import gov.noaa.pmel.sgt.Attribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.VectorAttribute;
+import gov.noaa.pmel.sgt.Graph;
+import gov.noaa.pmel.sgt.AxisNotFoundException;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.SGException;
+import gov.noaa.pmel.sgt.StackedLayout;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.sgt.IndexedColorMap;
+import gov.noaa.pmel.sgt.TransformAccess;
+import gov.noaa.pmel.sgt.DataNotFoundException;
+import gov.noaa.pmel.sgt.AttributeChangeEvent;
+
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.util.SoTValue;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTRange;
+import gov.noaa.pmel.util.SoTDomain;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.Domain;
+import gov.noaa.pmel.util.Dimension2D;
+import gov.noaa.pmel.util.Rectangle2D;
+import gov.noaa.pmel.util.Units;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimeRange;
+
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SimpleLine;
+import gov.noaa.pmel.sgt.dm.SGTMetaData;
+import gov.noaa.pmel.sgt.dm.Collection;
+import gov.noaa.pmel.sgt.dm.PointCollection;
+import gov.noaa.pmel.sgt.dm.SGTVector;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Color;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Component;
+import java.awt.geom.AffineTransform;
+
+import java.awt.Point;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.print.*;
+
+import java.beans.PropertyVetoException;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * <code>JPlotLayout</code> creates a pre-defined graphics layout for
+ * <code>SGTLine</code>, <code>SGTGrid</code>,
+ * <code>Collection</code>, <code>SGTVector</code>,
+ * and <code>PointCollection</code> data.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.2 $, $Date: 2008/12/19 13:29:38 $
+ * @since 2.0
+ * @see LineCartesianRenderer
+ * @see PointCartesianRenderer
+ * @see GridCartesianRenderer
+ * @see VectorCartesianRenderer
+**/
+public class JPlotLayout extends JGraphicLayout
+  implements PropertyChangeListener {
+  //
+  // save handles to unique components
+  //
+
+
+  /**
+   * @label coastline
+   * @link aggregation
+   * @undirected
+   */
+  CartesianGraph coastLine_ = null;
+  Layer coastLayer_ = null;
+  Logo logo_;
+
+  /**
+   * @label lineKey
+   * @link aggregation
+   * @undirected
+   */
+  LineKey lineKey_;
+
+  /**
+   * @label colorKey
+   * @link aggregation
+   * @undirected
+   */
+  ColorKey colorKey_;
+
+  /**
+   * @label pointKey
+   * @link aggregation
+   * @undirected
+   */
+  PointCollectionKey pointKey_;
+
+  VectorKey vectorKey_;
+
+  private boolean computeScroll_ = false;
+  int layerCount_;
+  boolean revXAxis_ = false;
+  boolean revYAxis_ = false;
+  Layer firstLayer_;
+  boolean inZoom_ = false;
+  GridAttribute gAttr_ = null;
+  //
+  private boolean isXTime_ = false;
+  private boolean isYTime_ = false;
+  //
+  // constants
+  //
+  double xSize_ = XSIZE_;
+  double xMin_ = XMIN_;
+  double xMax_ = XMAX_;
+  double ySize_ = YSIZE_;
+  double yMin_ = YMIN_;
+  double yMax_ = YSIZE_ - 1.0*MAIN_TITLE_HEIGHT_
+                        - 2.0*WARN_HEIGHT_
+                        - 0.5*WARN_HEIGHT_;
+  //
+  double mainTitleHeight_ = MAIN_TITLE_HEIGHT_;
+  double titleHeight_ = TITLE_HEIGHT_;
+  double labelHeight_ = LABEL_HEIGHT_;
+  double warnHeight_ = WARN_HEIGHT_;
+  double keyHeight_ = KEY_HEIGHT_;
+  //
+  double xKeySize_ = XKEYSIZE_;
+  double yKeySize_ = YKEYSIZE_;
+  //
+  Color paneColor_ = PANE_COLOR;
+  Color keyPaneColor_ = KEYPANE_COLOR;
+  //
+  boolean autoRangeX_ = false;
+  boolean autoRangeY_ = false;
+  int autoXIntervals_ = 10;
+  int autoYIntervals_ = 10;
+  //
+  public static final int POINTS = 0;
+  public static final int LINE = 1;
+  public static final int GRID = 2;
+  public static final int VECTOR = 3;
+  //
+  private int plotType_ = -1;
+  //
+  private static final Color[] colorList_ =
+  { Color.blue, Color.cyan.darker(), Color.green, Color.orange.darker(),
+    Color.red, Color.magenta, Color.black, Color.gray};
+  //  {Color.red, Color.green, Color.blue, Color.cyan,
+  //   Color.magenta, Color.yellow, Color.orange, Color.pink};
+  private static final int[] markList_ =
+  {1, 2, 9, 15, 10, 24, 11, 44};
+
+  private static String LEFT_AXIS = "Left Axis";
+  private static String BOTTOM_AXIS = "Bottom Axis";
+
+  //  public JPlotLayout(SGTData dataset, String dataKey) {
+  //    this(dataset, "", null, false);
+  //  }
+  /**
+   * Default constructor. No Logo image is used and the <code>LineKey</code>
+   * will be in the same <code>JPane</code>.
+   */
+  public JPlotLayout(SGTData dataset) {
+    this(dataset, "", null, false);
+  }
+  /**
+   * <code>JPlotLayout</code> constructor.  Whether the data is GRID,
+   * POINTS, LINE, or VECTOR, isXtime, and isYTime is determined from the dataset.
+   *
+   * @param dataset the template data
+   * @param id identifier
+   * @param img Logo image
+   * @param is_key_pane if true LineKey is in separate pane
+   */
+  public JPlotLayout(SGTData dataset, String id, Image img,
+                     boolean is_key_pane) {
+    this(dataset instanceof SGTGrid? GRID:
+         (dataset instanceof PointCollection? POINTS: (dataset instanceof SGTVector? VECTOR: LINE)),
+         dataset.isXTime(), dataset.isYTime(), id, img, is_key_pane);
+  }
+  /**
+   * <code>JPlotLayout</code> constructor.  This constructor is
+   * retained for backward compatability.
+   *
+   * @param isGrid if true data is grid
+   * @param isXtime if true x coordinate is time
+   * @param isYTime if true y coordinate is time
+   * @param id identifier
+   * @param img Logo image
+   * @param is_key_pane if true LineKey is in separate pane
+   */
+  public JPlotLayout(boolean isGrid, boolean isXTime,
+                     boolean isYTime, String id, Image img,
+                     boolean is_key_pane) {
+    this(isGrid? GRID: LINE,
+         isXTime, isYTime, id, img, is_key_pane);
+  }
+  /**
+   * <code>JPlotLayout</code> constructor.  All other constructors
+   * call this one. Data is not plotted during construction of the
+   * <code>JPlotLayout</code> object and the <code>addData</code>
+   * method must be called to associated data with this object.
+   *
+   * @param isGrid if true data is grid
+   * @param isPoints if true data is points
+   * @param isXtime if true x coordinate is time
+   * @param isYTime if true y coordinate is time
+   * @param id identifier
+   * @param img Logo image
+   * @param is_key_pane if true LineKey is in separate pane
+   */
+  public JPlotLayout(boolean isGrid,
+                     boolean isPoints,
+                     boolean isXTime,
+                     boolean isYTime,
+                     String id,
+                     Image img,
+                     boolean is_key_pane) {
+    this(isGrid? GRID:(isPoints? POINTS: LINE),
+         isXTime, isYTime, id, img, is_key_pane);
+  }
+  /**
+   * <code>JPlotLayout</code> constructor.  All other constructors
+   * call this one. Data is not plotted during construction of the
+   * <code>JPlotLayout</code> object and the <code>addData</code>
+   * method must be called to associated data with this object.
+   *
+   * @param type type of plot , POINT, GRID, LINE, or VECTOR
+   * @param isXtime if true x coordinate is time
+   * @param isYTime if true y coordinate is time
+   * @param id identifier
+   * @param img Logo image
+   * @param is_key_pane if true LineKey is in separate pane
+   */
+  public JPlotLayout(int type,
+                     boolean isXTime,
+                     boolean isYTime,
+                     String id,
+                     Image img,
+                     boolean is_key_pane) {
+    super(id, img, new Dimension(400,300));
+    Layer layer, key_layer;
+    CartesianGraph graph;
+    LinearTransform xt, yt;
+    PlainAxis xbot = null;
+    PlainAxis yleft = null;
+    TimeAxis tbot = null;
+    TimeAxis tleft = null;
+    double xpos, ypos;
+    int halign;
+    ColorMap cmap;
+    //
+    //
+    // define default colormap
+    //
+    int[] red =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  7, 23, 39, 55, 71, 87,103,
+       119,135,151,167,183,199,215,231,
+       247,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,246,228,211,193,175,158,140};
+    int[] green =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0, 11, 27, 43, 59, 75, 91,107,
+       123,139,155,171,187,203,219,235,
+       251,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0};
+    int[] blue =
+    {  0,143,159,175,191,207,223,239,
+       255,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0};
+    //
+    isXTime_ = isXTime;
+    isYTime_ = isYTime;
+    plotType_ = type;
+    //
+    // create Pane and descendants for the LineProfile layout
+    //
+    setOpaque(true);
+    setLayout(new StackedLayout());
+    setBackground(paneColor_);
+    layer = new Layer("Layer 1", new Dimension2D(xSize_, ySize_));
+    firstLayer_ = layer;
+    if(coastLine_ == null) {
+      add(layer,0);
+    } else {
+      add(layer,1);
+    }
+    //
+    if(plotType_ == GRID) {
+      // SGTGrid
+      colorKey_ = new ColorKey(new Rectangle2D.Double(0.01, 0.01,
+                                                      xKeySize_ - 0.01, 1.0),
+                               ColorKey.BOTTOM, ColorKey.LEFT);
+      colorKey_.setId("Color Key");
+      colorKey_.setVisible(false);
+      if(is_key_pane) {
+        colorKey_.setVAlign(ColorKey.TOP);
+        colorKey_.setBorderStyle(ColorKey.NO_BORDER);
+//        colorKey_.setBorderStyle(ColorKey.PLAIN_LINE);
+        colorKey_.setLocationP(new Point2D.Double(0.0, yKeySize_));
+        int xdim = 500;
+        int ydim = (int)((double)xdim/xKeySize_*yKeySize_);
+        keyPane_ = new JPane("KeyPane", new Dimension(xdim,ydim));
+        keyPane_.setOpaque(true);
+        keyPane_.setLayout(new StackedLayout());
+        keyPane_.setBackground(keyPaneColor_);
+        key_layer = new Layer("Key Layer", new Dimension2D(xKeySize_, yKeySize_));
+        keyPane_.add(key_layer);
+        key_layer.addChild(colorKey_);
+      } else {
+        colorKey_.setHAlign(ColorKey.CENTER);
+        colorKey_.setLocationP(new Point2D.Double(xSize_*0.5, 0.01));
+        layer.addChild(colorKey_);
+      }
+    } else if(plotType_ == POINTS){
+      // SGTPoint
+      pointKey_ = new PointCollectionKey();
+      pointKey_.setSelectable(false);
+      pointKey_.setId("Point Key");
+      pointKey_.setVAlign(LineKey.TOP);
+      if(is_key_pane) {
+        pointKey_.setHAlign(PointCollectionKey.LEFT);
+        pointKey_.setBorderStyle(PointCollectionKey.NO_BORDER);
+        pointKey_.setLocationP(new Point2D.Double(0.0, yKeySize_));
+        int xdim = 500;
+        int ydim = (int)((double)xdim/xKeySize_*yKeySize_);
+        keyPane_ = new JPane("KeyPane", new Dimension(xdim,ydim));
+        keyPane_.setOpaque(true);
+        keyPane_.setLayout(new StackedLayout());
+        keyPane_.setBackground(keyPaneColor_);
+        key_layer = new Layer("Key Layer", new Dimension2D(xKeySize_, yKeySize_));
+        keyPane_.add(key_layer);
+        key_layer.addChild(pointKey_);
+      } else {
+        pointKey_.setVAlign(PointCollectionKey.TOP);
+        pointKey_.setHAlign(PointCollectionKey.RIGHT);
+        pointKey_.setLocationP(new Point2D.Double(xSize_-0.02, ySize_-0.1));
+        layer.addChild(pointKey_);
+      }
+    } else if(plotType_ == LINE) {
+      // SGTLine
+      lineKey_ = new LineKey();
+      lineKey_.setSelectable(false);
+      lineKey_.setId("Line Key");
+      lineKey_.setVAlign(LineKey.TOP);
+      if(is_key_pane) {
+        lineKey_.setHAlign(LineKey.LEFT);
+        lineKey_.setBorderStyle(LineKey.NO_BORDER);
+        lineKey_.setLocationP(new Point2D.Double(0.0, yKeySize_));
+        int xdim = 500;
+        int ydim = (int)((double)xdim/xKeySize_*yKeySize_);
+        keyPane_ = new JPane("KeyPane", new Dimension(xdim,ydim));
+        keyPane_.setOpaque(true);
+        keyPane_.setLayout(new StackedLayout());
+        keyPane_.setBackground(keyPaneColor_);
+        key_layer = new Layer("Key Layer", new Dimension2D(xKeySize_, yKeySize_));
+        keyPane_.add(key_layer);
+        key_layer.addChild(lineKey_);
+      } else {
+        lineKey_.setVAlign(LineKey.TOP);
+        lineKey_.setHAlign(LineKey.RIGHT);
+        lineKey_.setLocationP(new Point2D.Double(xSize_-0.02, ySize_-0.1));
+        layer.addChild(lineKey_);
+      }
+    } else if(plotType_ == VECTOR) {
+      // SGTVector
+      vectorKey_ = new VectorKey();
+      vectorKey_.setSelectable(false);
+      vectorKey_.setId("Vector Key");
+      vectorKey_.setVAlign(VectorKey.TOP);
+      if(is_key_pane) {
+        vectorKey_.setHAlign(VectorKey.LEFT);
+        vectorKey_.setBorderStyle(VectorKey.NO_BORDER);
+        vectorKey_.setLocationP(new Point2D.Double(0.0, yKeySize_));
+        int xdim = 500;
+        int ydim = (int)((double)xdim/xKeySize_*yKeySize_);
+        keyPane_ = new JPane("KeyPane", new Dimension(xdim,ydim));
+        keyPane_.setOpaque(true);
+        keyPane_.setLayout(new StackedLayout());
+        keyPane_.setBackground(keyPaneColor_);
+        key_layer = new Layer("Key Layer", new Dimension2D(xKeySize_, yKeySize_));
+        keyPane_.add(key_layer);
+        key_layer.addChild(vectorKey_);
+      } else {
+        vectorKey_.setVAlign(VectorKey.TOP);
+        vectorKey_.setHAlign(VectorKey.RIGHT);
+        vectorKey_.setLocationP(new Point2D.Double(xSize_-0.02, ySize_-0.1));
+        vectorKey_.setSelectable(true);
+        layer.addChild(vectorKey_);
+      }
+    }
+    //
+    // add Icon
+    //
+    if(iconImage_ != null) {
+      logo_ = new Logo(new Point2D.Double(0.0, ySize_), Logo.TOP, Logo.LEFT);
+      logo_.setImage(iconImage_);
+      layer.addChild(logo_);
+      Rectangle bnds = logo_.getBounds();
+      xpos = layer.getXDtoP(bnds.x + bnds.width) + 0.05;
+      halign = SGLabel.LEFT;
+    } else {
+        xpos = (xMin_ + xMax_)*0.5;
+        halign = SGLabel.CENTER;
+    }
+    //
+    // title
+    //
+    ypos = ySize_ - 1.0f*mainTitleHeight_;
+    Font titleFont = new Font("Helvetica", Font.BOLD, 14);
+    mainTitle_ = new SGLabel("Line Profile Title",
+                             "Profile Plot",
+                             mainTitleHeight_,
+                             new Point2D.Double(xpos, ypos),
+                             SGLabel.BOTTOM,
+                             halign);
+    mainTitle_.setFont(titleFont);
+    layer.addChild(mainTitle_);
+    ypos = ypos - 1.0f*warnHeight_;
+    Font title2Font = new Font("Helvetica", Font.PLAIN, 10);
+    title2_ = new SGLabel("Second Title",
+                          "Warning: Browse image only",
+                          warnHeight_,
+                          new Point2D.Double(xpos, ypos),
+                          SGLabel.BOTTOM,
+                          halign);
+    title2_.setFont(title2Font);
+    layer.addChild(title2_);
+    ypos = ypos - 1.0f*warnHeight_;
+    title3_ = new SGLabel("Warning 2",
+                          "Verify accuracy of plot before research use",
+                          warnHeight_,
+                          new Point2D.Double(xpos, ypos),
+                          SGLabel.BOTTOM,
+                          halign);
+    title3_.setFont(title2Font);
+    layer.addChild(title3_);
+
+    layerCount_ = 0;
+    //
+    // create LineCartesianGraph and transforms
+    //
+    graph = new CartesianGraph("Profile Graph 1");
+    GeoDate start = null;
+    GeoDate end = null;
+    try {
+      start = new GeoDate("1992-11-01", "yyyy-MM-dd");
+      end = new GeoDate("1993-02-20", "yyyy-MM-dd");
+    } catch (IllegalTimeValue e) {}
+    SoTRange xRange, yRange;
+    if(isXTime_) {
+      xRange = new SoTRange.Time(start.getTime(), end.getTime());
+    } else {
+      xRange = new SoTRange.Double(10.0, 20.0, 2.0);
+    }
+    if(isYTime_) {
+      yRange = new SoTRange.Time(start.getTime(), end.getTime());
+    } else {
+      yRange = new SoTRange.Double(400.0, 0.0, -50.0);
+    }
+    SoTPoint origin;
+
+    xt = new LinearTransform(new Range2D(xMin_, xMax_), xRange);
+    yt = new LinearTransform(new Range2D(yMin_, yMax_), yRange);
+    origin = new SoTPoint(xRange.getStart(), yRange.getStart());
+
+    graph.setXTransform(xt);
+    graph.setYTransform(yt);
+    //
+    // create axes
+    //
+    Font axfont = new Font("Helvetica", Font.ITALIC, 14);
+    if(isXTime_) {
+      tbot = new TimeAxis(BOTTOM_AXIS, TimeAxis.AUTO);
+      tbot.setRangeU(xRange);
+      tbot.setLabelHeightP(labelHeight_);
+      tbot.setLocationU(origin);
+      tbot.setLabelFont(axfont);
+      graph.addXAxis(tbot);
+      // graph.addXAxis("Time",tbot);
+    } else {
+      xbot = new PlainAxis(BOTTOM_AXIS);
+      xbot.setRangeU(xRange);
+      xbot.setNumberSmallTics(0);
+      xbot.setLocationU(origin);
+      xbot.setLabelHeightP(labelHeight_);
+      xbot.setLabelFont(axfont);
+      graph.addXAxis(xbot);
+    }
+    if(isYTime_) {
+      tleft = new TimeAxis(LEFT_AXIS, TimeAxis.AUTO);
+      tleft.setRangeU(yRange);
+      tleft.setLabelHeightP(labelHeight_);
+      tleft.setLocationU(origin);
+      tleft.setLabelFont(axfont);
+      graph.addYAxis(tleft);
+    } else {
+      yleft = new PlainAxis(LEFT_AXIS);
+      yleft.setRangeU(yRange);
+      yleft.setNumberSmallTics(0);
+      yleft.setLabelHeightP(labelHeight_);
+      yleft.setLocationU(origin);
+      yleft.setLabelFont(axfont);
+      graph.addYAxis(yleft);
+    }
+    if(plotType_ == GRID) {
+      //
+      // create default GridAttribute, and ColorMap
+      //
+      cmap = new IndexedColorMap(red, green, blue);
+      LinearTransform ctrans =
+        new LinearTransform(0.0, (double)red.length, 0.0, 1.0);
+      ((IndexedColorMap)cmap).setTransform(ctrans);
+      gAttr_ = new GridAttribute(GridAttribute.RASTER, cmap);
+      gAttr_.addPropertyChangeListener(this);
+      colorKey_.setColorMap(cmap);
+    }
+    //
+    layer.setGraph(graph);
+  }
+  /**
+   * @todo implement getLocationSummary
+   */
+  public String getLocationSummary(SGTData grid) {
+    return "";
+  }
+  /**
+   * Add a <code>Collection</code> of lines using the default
+   * attributes and description.  The description will be taken from
+   * the dependent variable name
+   */
+  public void addData(Collection lines) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(Collection)");
+    addData(lines, null, null);
+  }
+  /**
+   * Add a <code>Collection</code> of lines using the default
+   * description.  The description will be taken from
+   * the dependent variable name
+   */
+  public void addData(Collection lines, Attribute attr) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(Collection, Attribute)");
+    addData(lines, attr, null);
+  }
+
+  /**
+   * Add a <code>PointCollection</code>.
+   */
+  public void addData(PointCollection points, String descrip) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(PointCollection, String)");
+    addData((SGTData)points, descrip);
+  }
+
+  /**
+   * Add a <code>Collection</code> of lines using the default
+   * attributes.
+   */
+  public void addData(Collection lines, String descrip) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(Collection, String)");
+    addData(lines, null, descrip);
+  }
+  /**
+   * Add a <code>Collecdtion</code> of lines.
+   */
+  public void addData(Collection lines, Attribute attr, String descrip) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(Collection, Attribute, String)");
+    //    System.out.println("addData(Collection) called");
+    for(int i=0; i < lines.size(); i++) {
+      SGTLine line = (SGTLine)lines.elementAt(i);
+      addData(line, attr, line.getTitle());
+    }
+  }
+  /**
+   * Add data to the layout. LineKey descriptor will be
+   * taken from the dependent variable name.
+   *
+   * @param data datum data to be added
+   */
+  public void addData(SGTData datum) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(SGTData)");
+    addData(datum, null, null);
+  }
+  /**
+   * Add data to the layout. LineKey descriptor will be
+   * taken from the dependent variable name.
+   *
+   * @param data datum data to be added
+   * @param attr attribute for graphics
+   */
+  public void addData(SGTData datum, Attribute attr) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(SGTData, Attribute)");
+    addData(datum, attr, null);
+  }
+  /**
+   * Add data to the layout.  <code>JPlotLayout</code> will use a
+   * default attribute.
+   */
+  public void addData(SGTData datum, String descrip) {
+    if(Debug.DEBUG) System.out.println("JPlotLayout.addData(SGTData, String)");
+    addData(datum, null, descrip);
+  }
+  /**
+   * Add data to the layout.  Data will be added to X axis and
+   * <code>Z_AXIS</code> will be assigned to Y axis. If this is
+   * not the first invocation of <code>addData</code> a new
+   * <code>Layer</code> will be created. If overlayed, the
+   * <code>Transform</code>s from the first <code>Layer</code>
+   * will be attached and <B>no</B> axes will be created. If not
+   * overlayed, new transforms and axes will be created and
+   * adjusted so that the data is horizontally stacked.
+   *
+   * @param datum data to be added
+   * @param descrip LineKey description for datum
+   */
+  public void addData(SGTData datum, Attribute attr, String descrip) {
+    if(Debug.DEBUG) {
+      System.out.println("JPlotLayout.addData(SGTData, Attribute, String)");
+      if(attr != null && attr instanceof LineAttribute) {
+        System.out.println("attr = LineAttribute");
+      } else {
+        System.out.println("attr = new LineAttribute");
+      }
+    }
+    //
+    Layer layer, newLayer;
+    CartesianGraph graph, newGraph;
+    Axis bottom = null;
+    Axis left = null;
+    LinearTransform xt, yt;
+    SGLabel xtitle, ytitle, lineTitle;
+    SGTData data;
+    SGTGrid grid = null;
+    SGTLine line = null;
+    SGTVector vector = null;
+    PointCollection points = null;
+    LineAttribute lineAttr = null;
+    GridAttribute gridAttr = null;
+    PointAttribute pointAttr = null;
+    VectorAttribute vectorAttr = null;
+    String xLabel, yLabel;
+    SoTRange xRange = null;
+    SoTRange yRange = null;
+    SoTRange xnRange = null;
+    SoTRange ynRange = null;
+    SoTPoint origin = null;
+    Range2D vRange = null;
+    boolean data_good = true;
+    boolean flipX = false;
+    boolean flipY = false;
+    double save;
+    GeoDate savet;
+    int len;
+    boolean showColorKey = false;
+    //
+    //      if(!isXTime_ && !(plotType_ == GRID)) {
+    //        if(data_.size() == 0) setBaseUnit(Units.getBaseUnit(datum.getXMetaData()));
+    //        datum = Units.convertToBaseUnit(datum, getBaseUnit(),
+    //                                        Units.X_AXIS);
+    //      }
+    //
+    if(data_.size() == 0) {
+      super.addData(datum);
+      //
+      // only one data set...
+      // determine range and titles from data
+      //
+      data = (SGTData)data_.firstElement();
+      if(plotType_ == GRID) {
+        // SGTGrid
+        grid = (SGTGrid)data;
+      } else if(plotType_ == POINTS){
+        // SGTPoint
+        points = (PointCollection)data;
+      } else if(plotType_ == LINE){
+        // SGTLine
+        line = (SGTLine)data;
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        vector = (SGTVector)data;
+      }
+      //
+      // find range of datum (grid, points, or line)
+      //
+      if(plotType_ == GRID) {
+        // SGTGrid
+        if(attr != null && attr instanceof GridAttribute) {
+          gridAttr = (GridAttribute)attr;
+          gridAttr.addPropertyChangeListener(this);
+        } else {
+          gridAttr = gAttr_;
+        }
+        addAttribute(datum, gridAttr);
+        showColorKey = gridAttr.isRaster();
+        vRange = findRange(grid, gridAttr, Z_AXIS);
+        if(gridAttr.isRaster()) {
+          ColorMap cmap = gridAttr.getColorMap();
+          if(cmap instanceof TransformAccess) {
+            ((TransformAccess)cmap).setRange(vRange);
+          }
+        }
+        xRange = findSoTRange(grid, gridAttr, X_AXIS);
+        yRange = findSoTRange(grid, gridAttr, Y_AXIS);
+      } else if((plotType_ == LINE) || (plotType_ == POINTS)){
+        // SGTPoint or SGTLine
+        xRange = data.getXRange();
+        yRange = data.getYRange();
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        xRange = findSoTRange(vector, X_AXIS);
+        yRange = findSoTRange(vector, Y_AXIS);
+      }
+      flipX = data.getXMetaData().isReversed();
+      flipY = data.getYMetaData().isReversed();
+      //
+      // check for good points
+      //
+      data_good = !(xRange.isStartOrEndMissing() ||
+                    yRange.isStartOrEndMissing());
+
+      revXAxis_ = flipX;
+      revYAxis_ = flipY;
+
+      if(data_good) {
+        //
+        // flip range if data_good and flipped
+        //
+        if(flipX) {
+          xRange.flipStartAndEnd();
+        }
+        if(flipY) {
+          yRange.flipStartAndEnd();
+        }
+        //
+        // compute "Nice" range
+        //
+        if(isXTime_) {
+          xnRange = xRange;
+        } else {
+          if(autoRangeX_) {
+            xnRange = Graph.computeRange(xRange, autoXIntervals_);
+          } else {
+            xnRange = xRange;
+            ((SoTRange.Double)xnRange).delta = ((SoTRange.Double)Graph.computeRange(xRange, autoXIntervals_)).delta;
+          }
+        }
+        if(isYTime_) {
+          ynRange = yRange;
+        } else {
+          if(autoRangeY_) {
+            ynRange = Graph.computeRange(yRange, autoYIntervals_);
+          } else {
+            ynRange = yRange;
+            ((SoTRange.Double)ynRange).delta = ((SoTRange.Double)Graph.computeRange(yRange, autoYIntervals_)).delta;
+          }
+        }
+        //
+        // test xnRange and ynRange
+        //
+        adjustRange(xnRange);
+        adjustRange(ynRange);
+        origin = new SoTPoint(xnRange.getStart(), ynRange.getStart());
+      } // data_good
+      //
+      // create labels
+      //
+      xLabel =  data.getXMetaData().getName() +
+        " (" + data.getXMetaData().getUnits() + ")";
+      yLabel =  data.getYMetaData().getName() +
+        " (" + data.getYMetaData().getUnits() + ")";
+      //
+      // attach information to pane and descendents
+      //
+      try {
+        layer = getLayer("Layer 1");
+      } catch (LayerNotFoundException e) {
+        return;
+      }
+      graph = (CartesianGraph)layer.getGraph();
+      //
+      // create axes
+      //
+      try {
+        Font tfont = new Font("Helvetica", Font.PLAIN, 14);
+        xtitle = new SGLabel("xaxis title", xLabel, new Point2D.Double(0.0, 0.0));
+        xtitle.setFont(tfont);
+        xtitle.setHeightP(titleHeight_);
+
+        bottom = graph.getXAxis(BOTTOM_AXIS);
+        bottom.setRangeU(xRange);
+        bottom.setLocationU(origin);
+        bottom.setTitle(xtitle);
+
+        ytitle = new SGLabel("yaxis title", yLabel, new Point2D.Double(0.0, 0.0));
+        ytitle.setFont(tfont);
+        ytitle.setHeightP(titleHeight_);
+
+        left = graph.getYAxis(LEFT_AXIS);
+        left.setRangeU(ynRange);
+        left.setLocationU(origin);
+        left.setTitle(ytitle);
+      } catch (AxisNotFoundException e) {}
+      if(data_good) {
+        //
+        // transforms
+        //
+        xt = (LinearTransform)graph.getXTransform();
+        xt.setRangeU(xnRange);
+        //
+        yt = (LinearTransform)graph.getYTransform();
+        yt.setRangeU(ynRange);
+      }
+      //
+      // attach data
+      //
+      if(plotType_ == GRID) {
+        // SGTGrid
+        graph.setData(grid, gridAttr);
+      } else if(plotType_ == POINTS) {
+        // SGTPoint
+        if(attr != null && attr instanceof PointAttribute) {
+          pointAttr = (PointAttribute)attr;
+        } else {
+          pointAttr = new PointAttribute(markList_[layerCount_%8],
+                                         colorList_[layerCount_%8]);
+          pointAttr.setMarkHeightP(0.15);
+          pointAttr.setLabelHeightP(0.15);
+          pointAttr.setDrawLabel(false);
+          pointAttr.setLabelColor(Color.red);
+          pointAttr.setLabelPosition(PointAttribute.NE);
+        }
+        pointAttr.addPropertyChangeListener(this);
+        addAttribute(datum, pointAttr);
+        graph.setData(points, pointAttr);
+      } else if(plotType_ == LINE) {
+        // SGTLine
+        if(isYTime_) {
+          len = line.getXArray().length;
+        } else {
+          len = line.getYArray().length;
+        }
+        if(attr != null && attr instanceof LineAttribute) {
+          lineAttr = (LineAttribute)attr;
+        } else {
+          if(len >= 2) {
+            lineAttr = new LineAttribute(LineAttribute.SOLID,
+                                         markList_[layerCount_%8],
+                                         colorList_[layerCount_%8]);
+          } else {
+            lineAttr = new LineAttribute(LineAttribute.MARK,
+                                         markList_[layerCount_%8],
+                                         colorList_[layerCount_%8]);
+          }
+        }
+        lineAttr.addPropertyChangeListener(this);
+        addAttribute(datum, lineAttr);
+        graph.setData(line, lineAttr);
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        if(attr != null && attr instanceof VectorAttribute) {
+          vectorAttr = (VectorAttribute)attr;
+        } else {
+          vectorAttr = new VectorAttribute(VectorAttribute.SCALED_HEAD,
+                                           0.10,
+                                           Color.black,
+                                           0.10);
+        }
+        vectorAttr.addPropertyChangeListener(this);
+        addAttribute(datum, vectorAttr);
+        graph.setData(vector, vectorAttr);
+      }
+      //
+      // add to lineKey
+      //
+      if(descrip == null) {
+        lineTitle = datum.getKeyTitle();
+        if(lineTitle == null) {
+          lineTitle = new SGLabel("line title",
+                                  xLabel,
+                                  new Point2D.Double(0.0, 0.0));
+        }
+      } else {
+        lineTitle = new SGLabel("line title",
+                                descrip,
+                                new Point2D.Double(0.0, 0.0));
+      }
+      lineTitle.setHeightP(keyHeight_);
+      int rowHeight = 1;
+      if(!isShowing()) computeScroll_ = true;
+      if(plotType_ == GRID) {
+        // SGTGrid
+        colorKey_.setTitle(lineTitle);
+        colorKey_.setColorMap(gridAttr.getColorMap());
+        colorKey_.setVisible(showColorKey);
+      } else if(plotType_ == POINTS) {
+        // SGTPoint
+        pointKey_.addPointGraph((PointCartesianRenderer)graph.getRenderer(), lineTitle);
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          if(isShowing()) rowHeight = pointKey_.getRowHeight();
+          int nrow = vRect.height/rowHeight;
+          keyPane_.setScrollableUnitIncrement(1, rowHeight);
+          keyPane_.setScrollableBlockIncrement(vRect.width, rowHeight*nrow);
+        }
+      } else if(plotType_ == LINE) {
+        // SGTLine
+        lineKey_.addLineGraph((LineCartesianRenderer)graph.getRenderer(), lineTitle);
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          if(isShowing()) rowHeight = lineKey_.getRowHeight();
+          int nrow = vRect.height/rowHeight;
+          keyPane_.setScrollableUnitIncrement(1, rowHeight);
+          keyPane_.setScrollableBlockIncrement(vRect.width, rowHeight*nrow);
+        }
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        vectorKey_.addVectorGraph((VectorCartesianRenderer)graph.getRenderer(),
+                                  lineTitle);
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          if(isShowing()) rowHeight = vectorKey_.getRowHeight();
+          int nrow = vRect.height/rowHeight;
+          keyPane_.setScrollableUnitIncrement(1, rowHeight);
+          keyPane_.setScrollableBlockIncrement(vRect.width, rowHeight*nrow);
+        }
+      }
+      //
+      // update coast
+      //
+      updateCoastLine();
+    } else {     // #of datasets
+      //
+      // grid can't have more than one data set!!!!
+      // more than one data set...
+      // add new layer
+      //
+      if(plotType_ == GRID) return;
+
+      if(datum instanceof SGTLine) {
+        if(datum.getYMetaData().isReversed() != revYAxis_) {
+          if(Debug.DEBUG) System.out.println("New datum has reversed ZUp!");
+          SGTData modified = flipY(datum);
+          datum = modified;
+        }
+      }
+      super.addData(datum);
+
+      data_good = false;
+      layerCount_++;
+      if(isOverlayed()) {
+        try {
+          layer = getLayer("Layer 1");
+        } catch (LayerNotFoundException e) {
+          return;
+        }
+        graph = (CartesianGraph)layer.getGraph();
+        //
+        // transforms
+        //
+        xt = (LinearTransform)graph.getXTransform();
+        yt = (LinearTransform)graph.getYTransform();
+        try {
+          bottom = graph.getXAxis(BOTTOM_AXIS);
+          left = graph.getYAxis(LEFT_AXIS);
+        } catch (AxisNotFoundException e) {}
+
+        if(!inZoom_) {
+          //
+          // loop over data sets, getting ranges
+          //
+          SoTRange xTotalRange = null;
+          SoTRange yTotalRange = null;
+
+          boolean first = true;
+
+          for (Enumeration e = data_.elements() ; e.hasMoreElements() ;) {
+            data = (SGTData)e.nextElement();
+            xRange = data.getXRange();
+            yRange = data.getYRange();
+            flipX = data.getXMetaData().isReversed();
+            flipY = data.getYMetaData().isReversed();
+
+            revXAxis_ = flipX;
+            revYAxis_ = flipY;
+
+            if(flipX) {
+              xRange.flipStartAndEnd();
+            }
+            if(flipY) {
+              yRange.flipStartAndEnd();
+            }
+            if(first) {
+              data_good = !(xRange.isStartOrEndMissing() ||
+                            yRange.isStartOrEndMissing());
+
+              if(!data_good) {
+                first = true;
+              } else {
+                first = false;
+                data_good = true;
+                xTotalRange = xRange;
+                yTotalRange = yRange;
+              }
+            } else {
+              //
+              // not first
+              //
+              data_good = !(xRange.isStartOrEndMissing() ||
+                            yRange.isStartOrEndMissing());
+              if(data_good) {
+                xTotalRange.add(xRange);
+                yTotalRange.add(yRange);
+              } // data_good
+            } // first
+          } // loop over data elements
+
+          if(data_good) {
+            if(isXTime_) {
+              xnRange = xTotalRange;
+            } else {
+              if(autoRangeX_) {
+                xnRange = Graph.computeRange(xTotalRange, autoXIntervals_);
+              } else {
+                xnRange = xTotalRange;
+                ((SoTRange.Double)xnRange).delta =
+                  ((SoTRange.Double)Graph.computeRange(xTotalRange, autoXIntervals_)).delta;
+              }
+            }
+            if(isYTime_) {
+              ynRange = yTotalRange;
+            } else {
+              if(autoRangeY_) {
+                ynRange = Graph.computeRange(yTotalRange, autoYIntervals_);
+              } else {
+                ynRange = yTotalRange;
+                ((SoTRange.Double)ynRange).delta =
+                  ((SoTRange.Double)Graph.computeRange(yTotalRange, autoYIntervals_)).delta;
+              }
+            }
+            //
+            // fix xnRange and ynRange
+            //
+            adjustRange(xnRange);
+            adjustRange(ynRange);
+            origin = new SoTPoint(xnRange.getStart(), ynRange.getStart());
+            //
+            // axes
+            //
+            bottom.setRangeU(xnRange);
+            bottom.setLocationU(origin);
+            //
+            left.setRangeU(ynRange);
+            left.setLocationU(origin);
+            //
+            xt.setRangeU(xnRange);
+            yt.setRangeU(ynRange);
+            updateCoastLine();
+          } // data_good
+        } // end of !inZoom_
+        //
+        // create new layer and graph
+        //
+        newLayer = new Layer("Layer " + (layerCount_+1), new Dimension2D(xSize_, ySize_));
+        newGraph = new CartesianGraph("Graph " + (layerCount_+1), xt, yt);
+        if(inZoom_) {
+          SoTRange xr = null;
+          SoTRange yr = null;
+          xr = bottom.getSoTRangeU();
+          yr = left.getSoTRangeU();
+          newGraph.setClip(xr, yr);
+          newGraph.setClipping(true);
+        } // inZoom_
+        if(coastLine_ == null) {
+          add(newLayer,0);
+        } else {
+          add(newLayer,1);
+        }
+        newLayer.setGraph(newGraph);
+        newLayer.invalidate();
+        validate();
+        //
+        // attach data
+        //
+        if(plotType_ == POINTS) {
+          // SGTPoint
+          if(attr != null && attr instanceof PointAttribute) {
+            pointAttr = (PointAttribute)attr;
+          } else {
+            pointAttr = new PointAttribute(markList_[layerCount_%8],
+                                           colorList_[layerCount_%8]);
+            pointAttr.setMarkHeightP(0.15);
+            pointAttr.setLabelHeightP(0.15);
+            pointAttr.setDrawLabel(false);
+            pointAttr.setLabelColor(Color.red);
+            pointAttr.setLabelPosition(PointAttribute.NE);
+          }
+          pointAttr.addPropertyChangeListener(this);
+          addAttribute(datum, pointAttr);
+          newGraph.setData(datum, pointAttr);
+        } else if(plotType_ == LINE) {
+          // SGTLine
+          if(isYTime_) {
+            len = ((SGTLine)datum).getXArray().length;
+          } else {
+            len = ((SGTLine)datum).getYArray().length;
+          }
+          if(attr != null && attr instanceof LineAttribute) {
+            lineAttr = (LineAttribute)attr;
+          } else {
+            if(Debug.DEBUG) System.out.println("Create new LineAttribute");
+            if(len >= 2) {
+              lineAttr = new LineAttribute(LineAttribute.SOLID,
+                                           markList_[layerCount_%8],
+                                           colorList_[layerCount_%8]);
+            } else {
+              lineAttr = new LineAttribute(LineAttribute.MARK,
+                                           markList_[layerCount_%8],
+                                           colorList_[layerCount_%8]);
+            }
+          }
+          lineAttr.addPropertyChangeListener(this);
+          addAttribute(datum, lineAttr);
+          newGraph.setData(datum, lineAttr);
+        } else if(plotType_ == VECTOR) {
+          // SGTVector
+          /**
+           * @todo add vector data to graph
+           */
+        }
+        //
+        // add to lineKey
+        //
+        if(pointKey_ != null) {
+          if(descrip == null) {
+            xLabel = datum.getXMetaData().getName();
+            lineTitle = new SGLabel("line title", xLabel, new Point2D.Double(0.0, 0.0));
+          } else {
+            lineTitle = new SGLabel("line title", descrip, new Point2D.Double(0.0, 0.0));
+          }
+          lineTitle.setHeightP(keyHeight_);
+          pointKey_.addPointGraph((PointCartesianRenderer)newGraph.getRenderer(), lineTitle);
+          if(keyPane_ != null) {
+            Rectangle vRect = keyPane_.getVisibleRect();
+            int nrow = vRect.height/pointKey_.getRowHeight();
+            keyPane_.setScrollableUnitIncrement(1, pointKey_.getRowHeight());
+            keyPane_.setScrollableBlockIncrement(vRect.width,
+                                                 pointKey_.getRowHeight()*nrow);
+          }
+        }
+        if(lineKey_ != null) {
+          if(descrip == null) {
+            xLabel = datum.getXMetaData().getName();
+            lineTitle = new SGLabel("line title", xLabel, new Point2D.Double(0.0, 0.0));
+          } else {
+            lineTitle = new SGLabel("line title", descrip, new Point2D.Double(0.0, 0.0));
+          }
+          lineTitle.setHeightP(keyHeight_);
+          lineKey_.addLineGraph((LineCartesianRenderer)newGraph.getRenderer(), lineTitle);
+          if(keyPane_ != null) {
+            Rectangle vRect = keyPane_.getVisibleRect();
+            int nrow = vRect.height/lineKey_.getRowHeight();
+            keyPane_.setScrollableUnitIncrement(1, lineKey_.getRowHeight());
+            keyPane_.setScrollableBlockIncrement(vRect.width,
+                                                 lineKey_.getRowHeight()*nrow);
+          }
+        }
+      } // overlayed
+    } // # of datasets
+  }
+  /**
+   * If start == end fix
+   */
+  private void adjustRange(SoTRange range) {
+    if(range.isTime()) {
+      long end = range.getEnd().getLongTime();
+      long st = range.getStart().getLongTime();
+      if(end == st) {
+        end += 30*86400000;  // add 30 days
+        st  -= 30*86400000;  // substract 30 days
+        if(range instanceof SoTRange.Time) {
+          ((SoTRange.Time)range).end = end;
+          ((SoTRange.Time)range).start = st;
+        } else {
+          ((SoTRange.GeoDate)range).end = new GeoDate(end);
+          ((SoTRange.GeoDate)range).start = new GeoDate(st);
+        }
+      }
+    } else {
+      double end = ((SoTRange.Double)range).end;
+      double st = ((SoTRange.Double)range).start;
+      double dlt = ((SoTRange.Double)range).delta;
+      if(dlt == 0) { // delta computation failed
+        end = st;
+      }
+      if(end == st) {
+        if(end == 0.0) {
+          st = -1.0;
+          end =  1.0;
+        } else {
+          if(end > 0.0) {
+            end = 1.1*end;
+          } else {
+            end = 0.9*end;
+          }
+          if(st > 0.0) {
+            st = 0.9*st;
+          } else {
+            st = 1.1*st;
+          }
+        }
+        ((SoTRange.Double)range).end = end;
+        ((SoTRange.Double)range).start = st;
+        ((SoTRange.Double)range).delta =
+          ((SoTRange.Double)Graph.computeRange(range, 10)).delta;
+      } // end == st
+    } // isTime()
+  }
+  /**
+   * Flip the yaxis.  Reverse the direction of the y axis by changing the sign
+   * of the axis values and isReversed flag.
+   */
+  private SGTData flipY(SGTData in) {
+    SGTMetaData zmetaout;
+    SGTMetaData zmetain;
+    SimpleLine out = null;
+    SGTLine line = (SGTLine) in;
+    double[] values;
+    double[] newValues;
+    values = line.getYArray();
+    newValues = new double[values.length];
+    for(int i=0; i < values.length; i++) {
+      newValues[i] = -values[i];
+    }
+    out = new SimpleLine(line.getXArray(), newValues, line.getTitle());
+    zmetain = line.getYMetaData();
+    zmetaout = new SGTMetaData(zmetain.getName(), zmetain.getUnits(),
+                               zmetain.isReversed(), zmetain.isModulo());
+    zmetaout.setModuloValue(zmetain.getModuloValue());
+    zmetaout.setModuloTime(zmetain.getModuloTime());
+    out.setXMetaData(line.getXMetaData());
+    out.setYMetaData(zmetaout);
+    return (SGTData)out;
+  }
+
+  public void resetZoom() {
+    Attribute attr;
+    GridAttribute gridAttr = null;
+    SGTData data;
+    SoTRange xRange = null;
+    SoTRange yRange = null;
+    SoTRange xTotalRange = null;
+    SoTRange yTotalRange = null;
+    boolean data_good = false;
+    boolean flipY = false;
+    boolean flipX = false;
+    double save;
+    GeoDate savet;
+    boolean batch = isBatch();
+
+    setBatch(true, "JPlotLayout: resetZoom");
+    inZoom_ = false;
+    setAllClipping(false);
+    setClipping(false);
+    //
+    // loop over data sets, getting ranges
+    //
+    boolean first = true;
+    Enumeration e = data_.elements();
+    while (e.hasMoreElements()) {
+      data = (SGTData)e.nextElement();
+      try {
+        attr = getAttribute(data);
+      } catch(DataNotFoundException except) {
+        System.out.println(except);
+        attr = null;
+      }
+      if(plotType_ == GRID) {
+        // SGTGrid
+        if(attr != null && attr instanceof GridAttribute) {
+          gridAttr = (GridAttribute)attr;
+        } else {
+          gridAttr = gAttr_;
+        }
+
+        xRange = findSoTRange((SGTGrid)data, gridAttr, X_AXIS);
+        yRange = findSoTRange((SGTGrid)data, gridAttr, Y_AXIS);
+      } else if((plotType_ == POINTS) || (plotType_ == LINE)) {
+        // SGTPoint or SGTLine
+        xRange = data.getXRange();
+        yRange = data.getYRange();
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        xRange = findSoTRange((SGTVector)data, X_AXIS);
+        yRange = findSoTRange((SGTVector)data, Y_AXIS);
+      }
+      flipX = data.getXMetaData().isReversed();
+      flipY = data.getYMetaData().isReversed();
+
+      revXAxis_ = flipX;
+      revYAxis_ = flipY;
+
+      if(flipX) {
+        xRange.flipStartAndEnd();
+      }
+      if(flipY) {
+        yRange.flipStartAndEnd();
+      }
+      if(first) {
+        data_good = !(xRange.isStartOrEndMissing() ||
+                      yRange.isStartOrEndMissing());
+
+        if(!data_good) {
+          first = true;
+        } else {
+          first = false;
+          data_good = true;
+          xTotalRange = xRange;
+          yTotalRange = yRange;
+        }
+      } else {
+        data_good = !(xRange.isStartOrEndMissing() ||
+                      yRange.isStartOrEndMissing());
+        if(data_good) {
+          xTotalRange.add(xRange);
+          yTotalRange.add(yRange);
+        } // data_good
+      } // first
+    } // for loop
+    //
+    // fix ranges
+    //
+    if(xTotalRange != null && yTotalRange != null) {
+      adjustRange(xTotalRange);
+      adjustRange(yTotalRange);
+      if(data_good) {
+        try {
+          setRange(new SoTDomain(xTotalRange, yTotalRange, flipX, flipY));
+        } catch (PropertyVetoException ve) {
+          System.out.println("zoom reset denied! " + ve);
+        }
+      }
+    }
+    // turn off clipping and clip coastline
+    //
+    inZoom_ = false;
+    updateCoastLine();
+    if(!batch) setBatch(false, "JPlotLayout: resetZoom");
+  }
+
+  public Domain getRange() {
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    Range2D xr = null;
+    Range2D yr = null;
+    TimeRange tr = null;
+    if(xt.isTime()) {
+      tr = xt.getTimeRangeU();
+    } else {
+      xr = xt.getRangeU();
+    }
+    if(yt.isTime()) {
+      tr = yt.getTimeRangeU();
+    } else {
+      yr = yt.getRangeU();
+    }
+    if(xt.isTime()) {
+      return new Domain(tr, yr);
+    } else if(yt.isTime()) {
+      return new Domain(xr, tr);
+    } else {
+      return new Domain(xr, yr);
+    }
+  }
+  /**
+   * Set the x and y range of the domain.
+   *
+   * @param reversed the y axis data is reversed
+   */
+  public void setRange(SoTDomain std)
+    throws PropertyVetoException {
+    Domain domain = new Domain();
+    if(std.isXTime()) {
+      SoTRange range = std.getXRange();
+      if(range instanceof SoTRange.Time) {
+        SoTRange.Time tgeo = (SoTRange.Time)range;
+        domain.setXRange(new TimeRange(tgeo.start, tgeo.end));
+      } else {
+        SoTRange.GeoDate geo = (SoTRange.GeoDate)range;
+        domain.setXRange(new TimeRange(geo.start, geo.end));
+      }
+    } else {
+      SoTRange.Double dbl = (SoTRange.Double)std.getXRange();
+      domain.setXRange(new Range2D(dbl.start, dbl.end, dbl.delta));
+    }
+    if(std.isYTime()) {
+      SoTRange range = std.getYRange();
+      if(range instanceof SoTRange.Time) {
+        SoTRange.Time tgeo = (SoTRange.Time)range;
+        domain.setYRange(new TimeRange(tgeo.start, tgeo.end));
+      } else {
+        SoTRange.GeoDate geo = (SoTRange.GeoDate)range;
+        domain.setYRange(new TimeRange(geo.start, geo.end));
+      }
+    } else {
+      SoTRange.Double dbl = (SoTRange.Double)std.getYRange();
+      domain.setYRange(new Range2D(dbl.start, dbl.end, dbl.delta));
+    }
+    domain.setXReversed(std.isXReversed());
+    domain.setYReversed(std.isYReversed());
+    setRange(domain);
+  }
+
+  /**
+   * Set the x and y range of the domain.
+   * <BR><B>Property Change:</B> <code>domainRange</code>.
+   *
+   * @param reversed y axis data is reversed
+   */
+  public void setRange(Domain domain) throws PropertyVetoException {
+    Domain oldRange = getRange();
+    if(!domain.equals(oldRange)) {
+      boolean batch = isBatch();
+      setBatch(true, "JPlotLayout: setRange");
+      vetos_.fireVetoableChange("domainRange", oldRange, domain);
+
+      inZoom_ = true;
+
+      if(!domain.isXTime()) {
+        setXRange(domain.getXRange());
+      } else {
+        setXRange(domain.getTimeRange());
+      }
+      if(!domain.isYTime()) {
+        setYRange(domain.getYRange(), domain.isYReversed());
+      } else {
+        setYRange(domain.getTimeRange());
+      }
+      changes_.firePropertyChange("domainRange", oldRange, domain);
+      if(!batch) setBatch(false, "JPlotLayout: setRange");
+      updateCoastLine();
+    }
+  }
+
+  /**
+   * Set the x and y range of the domain.
+   */
+  public void setRangeNoVeto(Domain domain) {
+    //
+    // clipping?  hack fix.  how should clipping be done for
+    // external range sets?
+    //
+    if(Debug.DEBUG) System.out.println("setRangeNoVeto: " + domain.toString());
+    boolean batch = isBatch();
+    setBatch(true, "JPlotLayout: setRangeNoVeto");
+    inZoom_ = true;
+    setClipping(true);
+
+    if(!domain.isXTime()) {
+      setXRange(domain.getXRange());
+    } else {
+      setXRange(domain.getTimeRange());
+    }
+    if(!domain.isYTime()) {
+      setYRange(domain.getYRange(), domain.isYReversed());
+    } else {
+      setYRange(domain.getTimeRange());
+    }
+    if(!batch) setBatch(false, "JPlotLayout: setRangeNoVeto");
+    updateCoastLine();
+    //    changes_.firePropertyChange("domainRange", oldRange, domain);
+  }
+  /**
+   * Reset the x range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param trnge new x range
+   */
+  void setXRange(TimeRange trnge) {
+    Axis bottom;
+    Axis left;
+    SoTRange yr;
+    SoTRange xr = new SoTRange.Time(trnge);
+    SoTPoint origin;
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    xt.setRangeU(xr);
+    try {
+      bottom = graph.getXAxis(BOTTOM_AXIS);
+      left = graph.getYAxis(LEFT_AXIS);
+      bottom.setRangeU(xr);
+
+      yr = left.getSoTRangeU();
+      origin = new SoTPoint(xr.getStart(), yr.getStart());
+
+      bottom.setLocationU(origin);
+      left.setLocationU(origin);
+
+      //
+      // set clipping
+      //
+      if(clipping_) {
+        setAllClip(xr, yr);
+      } else {
+        setAllClipping(false);
+      }
+    } catch (AxisNotFoundException e) {}
+  }
+  /**
+   * Reset the x range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param rnge new x range
+   */
+  void setXRange(Range2D rnge) {
+    Axis bottom;
+    Axis left;
+    SoTRange xr = new SoTRange.Double(rnge);
+    SoTRange yr;
+    SoTPoint origin;
+    SoTRange xnRange;
+    double save;
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    if(Debug.DEBUG) System.out.println("setXRange start, end, delta = " +
+                                       rnge.start + ", " + rnge.end + ", " + rnge.delta);
+    if(autoRangeX_) {
+      xnRange = Graph.computeRange(xr, autoXIntervals_);
+    } else {
+      xnRange = xr;
+      ((SoTRange.Double)xnRange).delta =
+        ((SoTRange.Double)Graph.computeRange(xr, autoXIntervals_)).delta;
+    }
+    xt.setRangeU(xnRange);
+    try {
+      bottom = graph.getXAxis(BOTTOM_AXIS);
+      left = graph.getYAxis(LEFT_AXIS);
+      yr = left.getSoTRangeU();
+
+      bottom.setRangeU(xnRange);
+
+      xr = bottom.getSoTRangeU();
+      origin = new SoTPoint(xr.getStart(), yr.getStart());
+      bottom.setLocationU(origin);
+      left.setLocationU(origin);
+      //
+      // set clipping
+      //
+      if(clipping_) {
+        setAllClip(xr, yr);
+      } else {
+        setAllClipping(false);
+      }
+    } catch (AxisNotFoundException e) {}
+  }
+  /**
+   * Reset the y range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param trnge new x range
+   */
+  void setYRange(TimeRange trnge) {
+    Axis bottom;
+    Axis left;
+    SoTRange xr;
+    SoTRange yr = new SoTRange.Time(trnge);
+    SoTPoint origin;
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    yt.setRangeU(yr);
+    try {
+      bottom = graph.getXAxis(BOTTOM_AXIS);
+      left = graph.getYAxis(LEFT_AXIS);
+      left.setRangeU(yr);
+
+      xr = bottom.getSoTRangeU();
+      origin = new SoTPoint(xr.getStart(), yr.getStart());
+      left.setLocationU(origin);
+
+      bottom.setLocationU(origin);
+      //
+      // set clipping
+      //
+      if(clipping_) {
+        setAllClip(xr, yr);
+      } else {
+        setAllClipping(false);
+      }
+    } catch (AxisNotFoundException e) {}
+  }
+  /**
+   * Reset the y range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param rnge new y range
+   */
+  void setYRange(Range2D rnge) {
+    setYRange(rnge, true);
+  }
+
+  /**
+   * Reset the y range. This method is designed to provide
+   * zooming functionality.
+   *
+   * @param rnge new y range
+   * @param reversed data is reversed
+   */
+  void setYRange(Range2D rnge, boolean reversed) {
+    SGTData grid;
+    Axis bottom;
+    Axis left;
+    SoTRange xr;
+    SoTRange yr = new SoTRange.Double(rnge);
+    SoTRange ynRange;
+    SoTPoint origin;
+    double save;
+    boolean flip;
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+/*    if(testZUp && data_.size() > 0) {
+      grid = (SGTData)data_.elements().nextElement();
+      if(grid.getYMetaData().isReversed()) {
+        yr.flipStartAndEnd();
+      }
+    } */
+    if(!data_.isEmpty()) {
+      grid = (SGTData)data_.elements().nextElement();
+      if(data_.size() > 0 && (reversed != grid.getYMetaData().isReversed())) {
+        yr.flipStartAndEnd();
+      }
+    }
+    if(autoRangeY_) {
+      ynRange = Graph.computeRange(yr, autoYIntervals_);
+    } else {
+      ynRange = yr;
+      ((SoTRange.Double)ynRange).delta =
+        ((SoTRange.Double)Graph.computeRange(yr, autoYIntervals_)).delta;
+    }
+    //      if(revYAxis_) {
+    //        save = ynRange.end;
+    //        ynRange.end = ynRange.start;
+    //        ynRange.start = save;
+    //        ynRange.delta = -ynRange.delta;
+    //      }
+    yt.setRangeU(ynRange);
+    try {
+      bottom = graph.getXAxis(BOTTOM_AXIS);
+      left = graph.getYAxis(LEFT_AXIS);
+      xr = bottom.getSoTRangeU();
+      left.setRangeU(ynRange);
+
+      yr = left.getSoTRangeU();
+      origin = new SoTPoint(xr.getStart(), yr.getStart());
+      left.setLocationU(origin);
+      bottom.setLocationU(origin);
+
+      //
+      // set clipping
+      //
+      if(clipping_) {
+        setAllClip(xr, yr);
+      } else {
+        setAllClipping(false);
+      }
+    } catch (AxisNotFoundException e) {}
+  }
+  /**
+   * Find a dataset from the data's id.
+   *
+   * @param data_id the id
+   * @return <code>SGTData</code>
+   */
+  public SGTData getData(String data_id) {
+    try {
+      Layer ly = getLayerFromDataId(data_id);
+      if(ly != null) {
+        CartesianRenderer rend = ((CartesianGraph)ly.getGraph()).getRenderer();
+        if(rend != null) {
+          if(rend instanceof LineCartesianRenderer) {
+            return (SGTData)((LineCartesianRenderer)rend).getLine();
+          } else if(rend instanceof GridCartesianRenderer) {
+            return (SGTData)((GridCartesianRenderer)rend).getGrid();
+          }
+        }
+      }
+    } catch (LayerNotFoundException e) {}
+    return null;
+  }
+  /**
+   * Find a dataset from the renderer.
+   *
+   * @param rend the renderer
+   * @return <code>SGTData</code>
+   */
+  public SGTData getData(CartesianRenderer rend) {
+    if(rend instanceof LineCartesianRenderer) {
+      return (SGTData)((LineCartesianRenderer)rend).getLine();
+    } else if(rend instanceof GridCartesianRenderer) {
+      return (SGTData)((GridCartesianRenderer)rend).getGrid();
+    }
+    return null;
+  }
+  /**
+   * Remove all data from the <code>JPlotLayout</code>
+   */
+  public void clear() {
+    data_.removeAllElements();
+    ((CartesianGraph)firstLayer_.getGraph()).setRenderer(null);
+    removeAll();
+    add(firstLayer_,0);   // restore first layer
+    if(coastLine_ != null) add(coastLayer_, 0);
+    if(lineKey_ != null)
+      lineKey_.clearAll();
+    if(pointKey_ != null)
+      pointKey_.clearAll();
+    inZoom_ = false;
+  }
+  /**
+   * Remove a specific dataset from the <code>JPlotLayout</code>
+   *
+   * @param data_id the data id
+   */
+  public void clear(String data_id) {
+    Layer ly = null;
+    SGTData dat;
+    try {
+      ly = getLayerFromDataId(data_id);
+      remove(ly);
+    } catch (LayerNotFoundException e) {}
+    for(Enumeration it=data_.elements(); it.hasMoreElements();) {
+      dat = (SGTData)it.nextElement();
+      if(dat.getId().equals(data_id)) {
+        data_.removeElement(dat);
+      }
+    }
+    if(lineKey_ != null)
+      lineKey_.clear(data_id);
+    if(pointKey_ != null)
+      pointKey_.clear(data_id);
+    if(getComponentCount() <= 0 || ly.equals(firstLayer_)) {
+      ((CartesianGraph)firstLayer_.getGraph()).setRenderer(null);
+      add(firstLayer_,0);  // restore first layer
+    }
+  }
+  /**
+   * Get the <code>JPlotLayout</code> layer size in physical
+   * coordinates.
+   */
+  public Dimension2D getLayerSizeP() {
+    return new Dimension2D(xSize_, ySize_);
+  }
+
+  public Layer getFirstLayer() {
+    return firstLayer_;
+  }
+  /**
+   * Set the axes origin in physical units
+   */
+  public void setAxesOriginP(Point2D.Double pt) {
+    xMin_ = pt.x;
+    yMin_ = pt.y;
+  }
+  /**
+   * @since 3.0
+   */
+  public SoTDomain getGraphDomain() {
+    SoTRange xRange = null;
+    SoTRange yRange = null;
+    CartesianGraph graph = null;
+    try {
+      Layer layer = getLayer("Layer 1");
+      graph = (CartesianGraph)layer.getGraph();
+    } catch (LayerNotFoundException e) {
+      return null;
+    }
+    try {
+      Axis bottom = graph.getXAxis(BOTTOM_AXIS);
+      Axis left = graph.getYAxis(LEFT_AXIS);
+      xRange = bottom.getSoTRangeU();
+      yRange = left.getSoTRangeU();
+    } catch (AxisNotFoundException e) {
+      return null;
+    }
+    return new SoTDomain(xRange, yRange);
+  }
+  /**
+   * Set the layer size in physical units
+   */
+  public void setLayerSizeP(Dimension2D d) {
+    Component[] comps = getComponents();
+    CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+    LinearTransform yt = (LinearTransform)graph.getYTransform();
+    LinearTransform xt = (LinearTransform)graph.getXTransform();
+    xMax_ = d.width - (xSize_ - xMax_);
+    yMax_ = d.height - (ySize_ - yMax_);
+    xSize_ = d.width;
+    ySize_ = d.height;
+    for(int i=0; i < comps.length; i++) {
+      if(comps[i] instanceof Layer) {
+        ((Layer)comps[i]).setSizeP(d);
+      }
+    }
+    yt.setRangeP(new Range2D(yMin_, yMax_));
+    xt.setRangeP(new Range2D(xMin_, xMax_));
+    //
+    double xpos;
+    if(iconImage_ != null) {
+      Rectangle bnds = logo_.getBounds();
+      xpos = firstLayer_.getXDtoP(bnds.x + bnds.width) + 0.05;
+    } else {
+      xpos = (xMin_ + xMax_)*0.5;
+    }
+    double ypos = ySize_ - 1.0f*mainTitleHeight_;
+    mainTitle_.setLocationP(new Point2D.Double(xpos, ypos));
+    ypos = ypos - 1.0f*warnHeight_;
+    title2_.setLocationP(new Point2D.Double(xpos, ypos));
+    ypos = ypos - 1.0f*warnHeight_;
+    title3_.setLocationP(new Point2D.Double(xpos, ypos));
+    //      if(plotType_ == GRID) {
+    //        if(keyPane_ == null) {
+    //          colorKey_.setLocationP(new Point2D.Double(xSize_*0.5, 0.0));
+    //        }
+    //      } else {
+    //        if(keyPane_ == null) {
+    //          lineKey_.setLocationP(new Point2D.Double(xSize_*0.5, 0.01));
+    //        }
+    //      }
+  }
+  /**
+   * Set the main and secondary label heights in physical units
+   *
+   * @param main main label height
+   * @param second second and third label height
+   */
+  public void setTitleHeightP(double main, double second) {
+//    mainTitleHeight_ = main;
+//    warnHeight_ = second;
+    //
+    // title
+    //
+    double ypos = ySize_ - 1.0f*main;
+    double xpos = mainTitle_.getLocationP().x;
+    boolean batch = isBatch();
+    setBatch(true, "JPlotLayout: setTitleHeightP");
+    if(main != mainTitleHeight_) {
+      mainTitleHeight_ = main;
+      mainTitle_.setHeightP(main);
+      mainTitle_.setLocationP(new Point2D.Double(xpos, ypos));
+    }
+    if(second != warnHeight_) {
+      warnHeight_ = second;
+      ypos = ypos - 1.0f*second;
+      title2_.setHeightP(second);
+      title2_.setLocationP(new Point2D.Double(xpos, ypos));
+      ypos = ypos - 1.0f*warnHeight_;
+      title3_.setHeightP(second);
+      title3_.setLocationP(new Point2D.Double(xpos, ypos));
+    }
+    if(!batch) setBatch(false, "JPlotLayout: setTitleHeightP");
+  }
+  /**
+   * Get main label height in physical units
+   */
+  public double getMainTitleHeightP() {
+    return mainTitleHeight_;
+  }
+  /**
+   * Get second and third label heights in physical units
+   */
+  public double getSecondaryTitleHeightP() {
+    return warnHeight_;
+  }
+  /**
+   * Set the key size in physical units
+   */
+  public void setKeyBoundsP(Rectangle2D.Double bounds){
+    if((plotType_ == GRID) && (colorKey_ != null)) {
+      // SGTGrid
+      colorKey_.setBoundsP(bounds);
+    } else if((plotType_ == POINTS) && (pointKey_ != null)) {
+      // SGTPoint
+      pointKey_.setBoundsP(bounds);
+    } else if((plotType_ == LINE) && (lineKey_ != null)) {
+      // SGTLine
+      lineKey_.setBoundsP(bounds);
+    } else if((plotType_ == VECTOR) && (vectorKey_ != null)) {
+      // SGTVector
+      vectorKey_.setBoundsP(bounds);
+    }
+  }
+  /**
+   * Get the key size in physical units
+   */
+  public Rectangle2D.Double getKeyBoundsP() {
+   if((plotType_ == GRID) && (colorKey_ != null)) {
+      // SGTGrid
+      return colorKey_.getBoundsP();
+    } else if((plotType_ == POINTS) && (pointKey_ != null)) {
+      // SGTPoint
+      return pointKey_.getBoundsP();
+    } else if((plotType_ == LINE) && (lineKey_ != null)) {
+      // SGTLine
+      return lineKey_.getBoundsP();
+    } else if((plotType_ == VECTOR) && (vectorKey_ != null)) {
+      // SGTVector
+      return vectorKey_.getBoundsP();
+    }
+    return null;
+  }
+  /**
+   * Set the key alignment
+   *
+   * @param vert vertical alignment
+   * @param horz horizontal alignment
+   *
+   * @see ColorKey
+   * @see LineKey
+   * @see PointCollectionKey
+   */
+  public void setKeyAlignment(int vert, int horz) {
+    if((plotType_ == GRID) && (colorKey_ != null)) {
+      // SGTGrid
+      colorKey_.setAlign(vert, horz);
+    } else if((plotType_ == POINTS) && (pointKey_ != null)) {
+      // SGTPoint
+      pointKey_.setAlign(vert, horz);
+    } else if((plotType_ == LINE) && (lineKey_ != null)) {
+      // SGTLine
+      lineKey_.setAlign(vert, horz);
+    } else if((plotType_ == VECTOR) && (vectorKey_ != null)) {
+      // SGTVector
+      vectorKey_.setAlign(vert, horz);
+    }
+  }
+  /**
+   * Get the key position in physical units
+   */
+  public Point2D.Double getKeyPositionP() {
+    Rectangle2D.Double bnds = getKeyBoundsP();
+    double xp = bnds.x;
+    double yp = bnds.y;
+    return new Point2D.Double(xp, yp);
+  }
+  /**
+   * Set the key position in physical units
+   */
+  public void setKeyLocationP(Point2D.Double loc) {
+    if(keyPane_ == null) {
+      if(plotType_ == GRID) {
+        // SGTGrid
+        colorKey_.setLocationP(loc);
+      } else if(plotType_ == POINTS) {
+        // SGTPoint
+        pointKey_.setLocationP(loc);
+      } else if(plotType_ == LINE) {
+        // SGTLine
+        lineKey_.setLocationP(loc);
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        vectorKey_.setLocationP(loc);
+      }
+    }
+  }
+
+  /* reversable axes not yet fully implemented */
+  //  public boolean isXAxisReversed() {
+  //    return revXAxis_;
+  //  }
+
+  //  public boolean isYAxisReversed() {
+  //    return revYAxis_;
+  //  }
+
+  //  public void setXAxisReversed(boolean rev) {
+  //    revXAxis_ = rev;
+    //      resetAxes();
+  //  }
+
+  //  public void setYAxisReversed(boolean rev) {
+  //    revYAxis_ = rev;
+    //      resetAxes();
+  //  }
+
+  private void resetAxes() {
+    Domain domain = getRange();
+    if(domain.isXTime()) {
+      setXRange(domain.getTimeRange());
+    } else {
+      setXRange(domain.getXRange());
+    }
+    if(domain.isYTime()) {
+      setYRange(domain.getTimeRange());
+    } else {
+      setYRange(domain.getYRange());
+    }
+    //    draw();
+  }
+  /**
+   * Used by <code>JPlotLayout</code> to listen for changes in line,
+   * grid, vector, and point attributes.
+   */
+  public void propertyChange(PropertyChangeEvent evt) {
+    if(Debug.EVENT) {
+      System.out.println("JPlotLayout: " + evt);
+      System.out.println("                " + evt.getPropertyName());
+    }
+    if(evt.getSource() instanceof GridAttribute &&
+       evt.getPropertyName() == "style" && (plotType_ == GRID)) {
+      // SGTGrid
+      SGTGrid grid = (SGTGrid)data_.firstElement();
+      try{
+        GridAttribute gridAttr = (GridAttribute)getAttribute(grid);
+        Range2D vRange = findRange(grid, gridAttr, Z_AXIS);
+        if(gridAttr.isRaster()) {
+          ColorMap cmap = gridAttr.getColorMap();
+          if(cmap instanceof TransformAccess) {
+            ((TransformAccess)cmap).setRange(vRange);
+          }
+          colorKey_.setColorMap(cmap);
+          colorKey_.setVisible(true);
+        } else {
+          colorKey_.setVisible(false);
+        }
+      } catch (DataNotFoundException e) {
+        System.out.println(e);
+      }
+      if(keyPane_ != null) {
+        keyPane_.setModified(true, "JPlotLayout: forced setModified");
+        keyPane_.setBatch(false, "JPlotLayout: propertyChange");
+      }
+    }
+    if(evt.getSource() instanceof Attribute) {
+      boolean local = true;
+      if(evt instanceof AttributeChangeEvent) {
+        local = ((AttributeChangeEvent)evt).isLocal();
+      }
+      if(Debug.EVENT) System.out.println("JPlotLayout: Attribute change: " + evt.getPropertyName());
+      changes_.firePropertyChange(new AttributeChangeEvent(this,
+                                                           "attribute",
+                                                           null,
+                                                           evt.getSource(),
+                                                           local));
+    }
+  }
+  /**
+   * Set the coastline.
+   */
+  public void setCoastLine(SGTLine coast) {
+    if(coastLine_ == null) {
+      CartesianGraph graph = (CartesianGraph)firstLayer_.getGraph();
+      LinearTransform xt = (LinearTransform)graph.getXTransform();
+      LinearTransform yt = (LinearTransform)graph.getYTransform();
+      Range2D xrange = xt.getRangeU();
+      Range2D yrange = yt.getRangeU();
+      coastLayer_ = new Layer("CoastLine", new Dimension2D(xSize_, ySize_));
+      add(coastLayer_, 0);
+      coastLine_ = new CartesianGraph("CoastLine Graph");
+      coastLayer_.setGraph(coastLine_);
+      coastLine_.setXTransform(xt);
+      coastLine_.setYTransform(yt);
+      LineAttribute lattr = new LineAttribute();
+      lattr.setColor(new Color(244,164, 96));
+      lattr.addPropertyChangeListener(this);
+      coastLine_.setData(coast, lattr);
+      coastLine_.setClip(xrange.start, xrange.end, yrange.start, yrange.end);
+      coastLine_.setClipping(true);
+      //
+      coastLayer_.invalidate();
+      validate();
+    }
+  }
+
+  void updateCoastLine() {
+    if(coastLine_ != null) {
+      CartesianGraph graph = (CartesianGraph)coastLayer_.getGraph();
+      LinearTransform xt = (LinearTransform)graph.getXTransform();
+      LinearTransform yt = (LinearTransform)graph.getYTransform();
+      Range2D xrange = xt.getRangeU();
+      Range2D yrange = yt.getRangeU();
+      coastLine_.setClip(xrange.start, xrange.end, yrange.start, yrange.end);
+      coastLine_.setClipping(true);
+      coastLayer_.invalidate();
+      validate();
+    }
+  }
+  /**
+   * Implements the <code>print</code> method in
+   * <code>java.awt.print.Printable</code>.  Overrides <code>JPane</code> behavior.
+   */
+  public int print(Graphics g, PageFormat pf, int pageIndex) {
+    if(pageIndex > 0) {
+      return NO_SUCH_PAGE;
+    } else {
+      if(Debug.DEBUG) {
+        System.out.println("Imageable(X,Y): " + pf.getImageableX() +
+                           ", " + pf.getImageableY());
+        System.out.println("Imageable(h,w): " + pf.getImageableHeight() +
+                           ", " + pf.getImageableWidth());
+        System.out.println("Paper(h,w): " + pf.getHeight() +
+                           ", " + pf.getWidth());
+      }
+      Graphics2D g2 = (Graphics2D)g;
+      drawPage(g2, pf);
+      if(keyPane_ != null) {
+        g2.setTransform(new AffineTransform());
+        Point pt = keyPane_.getLocation();
+        double scale = 72.0;
+        double margin = 0.5; // 0.5 inches
+        int layoutHeight = (int)((getLayerSizeP().getHeight() + margin)*scale)
+                              - pt.y;
+        int xoff = -pt.x;
+        Point offset = new Point(xoff, layoutHeight);
+        keyPane_.setPageOrigin(offset);
+        keyPane_.setPageVAlign(SPECIFIED_LOCATION);
+        keyPane_.setPageHAlign(CENTER);
+        g2.setClip(-1000, -1000, 5000, 5000);
+        keyPane_.drawPage(g2, pf, true);
+      }
+      return PAGE_EXISTS;
+    }
+  }
+  /**
+   * Turn on/off the auto range feature for the x axis. Auto range creates a
+   * "nice" range with a delta of 1., 2., 5. or 10^n of these.  The start
+   * and end of the range is extended to the next full delta.
+   */
+  public void setXAutoRange(boolean xauto) {
+    autoRangeX_ = xauto;
+  }
+  /**
+   * Turn on/off the auto range feature for the y axis. Auto range creates a
+   * "nice" range with a delta of 1., 2., 5. or 10^n of these.  The start
+   * and end of the range is extended to the next full delta.
+   */
+  public void setYAutoRange(boolean yauto) {
+    autoRangeY_ = yauto;
+  }
+  /**
+   * Turn on/off the auto range feature for the x and y axes. Auto range
+   * creates a "nice" range with a delta of 1., 2., 5. or 10^n of these.
+   * The start and end of the range is extended to the next full delta.
+   */
+  public void setAutoRange(boolean xauto, boolean yauto) {
+    autoRangeX_ = xauto;
+    autoRangeY_ = yauto;
+  }
+  /**
+   * Tests if the auto range feature is enabled for the x axis.
+   */
+  public boolean isXAutoRange() {
+    return autoRangeX_;
+  }
+  /**
+   * Tests if the auto range feature is enabled for the y axis.
+   */
+  public boolean isYAutoRange() {
+    return autoRangeY_;
+  }
+  /**
+   * Set the approximate number of x axis intervals for auto range.
+   */
+  public void setXAutoIntervals(int xint) {
+    autoXIntervals_ = xint;
+  }
+  /**
+   * Set the approximate number of y axis intervals for auto range.
+   */
+  public void setYAutoIntervals(int yint) {
+    autoYIntervals_ = yint;
+  }
+  /**
+   * Set the approximate number of x and y axes intervals for auto range.
+   */
+  public void setAutoIntervals(int xint, int yint) {
+    autoXIntervals_ = xint;
+    autoYIntervals_ = yint;
+  }
+  /**
+   * Return the number of intervals for the x axis.
+   */
+  public int getXAutoIntervals() {
+    return autoXIntervals_;
+  }
+  /**
+   * Return the number of intervals for the y axis.
+   */
+  public int getYAutoIntervals() {
+    return autoYIntervals_;
+  }
+  /**
+   * Override JPane init method.  The scrolling list parameters are computed
+   * here if necessary.
+   */
+  public void init() {
+    if(Debug.DEBUG) System.out.println("JPLotLayout: init()");
+    if(computeScroll_) {
+      computeScroll_ = false;
+      int rowHeight = 1;
+      if(plotType_ == GRID) {
+        // SGTGrid
+      } else if(plotType_ == POINTS) {
+        // SGTPoint
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          rowHeight = pointKey_.getRowHeight();
+          int nrow = vRect.height/rowHeight;
+          keyPane_.setScrollableUnitIncrement(1, rowHeight);
+          keyPane_.setScrollableBlockIncrement(vRect.width, rowHeight*nrow);
+        }
+      } else if(plotType_ == LINE) {
+        // SGTLine
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          rowHeight = lineKey_.getRowHeight();
+          int nrow = vRect.height/rowHeight;
+          keyPane_.setScrollableUnitIncrement(1, rowHeight);
+          keyPane_.setScrollableBlockIncrement(vRect.width, rowHeight*nrow);
+        }
+      } else if(plotType_ == VECTOR) {
+        // SGTVector
+        if(keyPane_ != null) {
+          Rectangle vRect = keyPane_.getVisibleRect();
+          rowHeight = vectorKey_.getRowHeight();
+          int nrow = vRect.height/rowHeight;
+          keyPane_.setScrollableUnitIncrement(1, rowHeight);
+          keyPane_.setScrollableBlockIncrement(vRect.width, rowHeight*nrow);
+        }
+      }
+    }
+  }
+  public void finalize(){
+	  gAttr_ = null;
+	  super.finalize();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/PlotMarkIcon.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/PlotMarkIcon.java
new file mode 100755
index 0000000..ca43f2f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/PlotMarkIcon.java
@@ -0,0 +1,145 @@
+/*
+ * $Id: PlotMarkIcon.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.PlotMark;
+
+import javax.swing.Icon;
+import java.awt.Component;
+import java.awt.Graphics;
+
+/**
+ * <code>PlotMarkIcon</code> extends <code>PlotMark</code> to create a
+ * icon than displays the <code>sgt</code> plot marks.  The
+ * <code>PlotMarkIcon</code> can be used with buttons, e.g. selecting
+ * a plot mark for a line, or labels.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see PlotMark
+ * @see Icon
+ */
+public class PlotMarkIcon extends PlotMark implements Icon {
+  private int size_;
+  private double scale_;
+  /**
+   * Construct a <code>PlotMarkIcon</code>.
+   *
+   * @param mark the plot mark code
+   * @param size plot mark size in device units
+   */
+  public PlotMarkIcon(int mark, int size) {
+    super(mark);
+    setSize(size);
+  }
+  /**
+   * Construct a <code>PlotMarkIcon</code>.
+   *
+   * @param mark the plot mark code
+   */
+  public PlotMarkIcon(int mark) {
+    this(mark, 16);
+  }
+  /**
+   * Set the size of the plot mark in device units.
+   */
+  public void setSize(int size) {
+    size_ = size;
+    scale_ = (double)size_/8.0;
+  }
+  /**
+   * Get the size of the plot mark
+   */
+  public int getSize() {
+    return size_;
+  }
+  /**
+   * Paint the icon at the specified location
+   */
+  public void paintIcon(Component c, Graphics g, int x, int y) {
+    int ib;
+    boolean penf;
+    int movex, movey;
+    int xt, yt;
+    int xtOld, ytOld;
+
+    g.setColor(c.getForeground());
+
+    if(circle_) {
+      xt = (int)(scale_*2.0) + x;
+      yt = (int)(scale_*2.0) + y;
+      int w = (int)(scale_*4.0);
+      if(fill_) {
+        g.fillOval(xt, yt, w, w);
+      } else {
+        g.drawOval(xt, yt, w, w);
+      }
+      return;
+    }
+
+    int[] xl = new int[lastPoint_-firstPoint_];
+    int[] yl = new int[lastPoint_-firstPoint_];
+
+    double scale;
+
+    xtOld = x;
+    ytOld = y;
+
+    penf = false;
+    int i=0;
+    for(int count=firstPoint_; count < lastPoint_; count++) {
+      ib = table[count];
+      if(ib == 0) {
+        penf=false;
+      } else {
+        movex = (ib>>3);
+        movey = 7 - (ib&7);
+        xt = (int)(scale_*(double)movex) + x;
+        yt = (int)(scale_*(double)movey) + y;
+        if(penf) {
+          if(fill_) {
+            xl[i] = xt;
+            yl[i] = yt;
+            i++;
+          } else {
+            g.drawLine(xtOld, ytOld, xt, yt);
+          }
+        }
+        penf = true;
+        xtOld = xt;
+        ytOld = yt;
+      }
+    }
+    if(fill_) g.fillPolygon(xl, yl, i);
+  }
+  /**
+   * Get the icon with
+   */
+  public int getIconWidth() {
+    return size_;
+  }
+  /**
+   * Set the icon height
+   */
+  public int getIconHeight() {
+    return size_;
+  }
+
+  public String toString() {
+    return "PlotMarkIcon: " + mark_;
+  }
+}
+
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/UserIcon.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/UserIcon.java
new file mode 100755
index 0000000..9254f29
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/UserIcon.java
@@ -0,0 +1,354 @@
+/*
+ * $Id: UserIcon.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.LayerChild;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.AbstractPane;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.util.SoTPoint;
+
+import javax.swing.ImageIcon;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.Image;
+import java.net.URL;
+import java.awt.Graphics;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeSupport;
+import java.beans.VetoableChangeListener;
+
+/**
+ * <code>UserIcon</code> extends <code>ImageIcon</code> to create a
+ * icon than can be dragged on a <code>sgt</code> plot displaying a
+ * user defined text string along with the image.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see ValueIcon
+ */
+public class UserIcon extends ImageIcon implements LayerChild, Draggable {
+  private boolean selected_ = false;
+  private boolean selectable_ = true;
+  protected boolean moved_ = false;
+  protected Layer layer_ = null;
+  private String id_ = null;
+  private boolean visible_ = true;
+  protected Rectangle bounds_ = new Rectangle();
+  protected Point2D.Double loc_ = new Point2D.Double();
+  protected SoTPoint uLoc_ = new SoTPoint(0.0, 0.0);
+  private Font font_ = new Font("Dialog", Font.PLAIN, 10);
+  private Color textColor_ = Color.black;
+  protected PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  protected VetoableChangeSupport vetos_ = new VetoableChangeSupport(this);
+
+  /**
+   * Construct a <code>UserIcon</code> using an image from a
+   * specified file.
+   *
+   * @param filename name of image file
+   * @param description brief textual description of the image
+   */
+  public UserIcon(String filename, String description) {
+    super(filename, description);
+  }
+  /**
+   * Construct a <code>UserIcon</code> using an image from a
+   * specified <code>URL</code>.
+   *
+   * @param location URL of image file
+   * @param description brief textual description of the image
+   */
+  public UserIcon(URL location, String description) {
+    super(location, description);
+  }
+  /**
+   * Construct a <code>UserIcon</code> using an <code>Image</code>.
+   *
+   * @param image the image
+   * @param description brief textual description of the image
+   */
+  public UserIcon(Image image, String description) {
+    super(image, description);
+  }
+  /**
+   * Paint the icon at the specified location.
+   */
+  public void paintIcon(Component c, Graphics g, int x, int y) {
+    computeBounds(g);
+    bounds_.x = x;
+    bounds_.y = y;
+    if(visible_) {
+    g.drawImage(getImage(), bounds_.x, bounds_.y, layer_.getPane().getComponent());
+    int xl = bounds_.x + super.getIconWidth();
+    int yl = bounds_.y + super.getIconHeight();
+    g.setFont(font_);
+    g.setColor(textColor_);
+    g.drawString(getDescription(), xl, yl);
+    }
+  }
+  /**
+   * Set the font for the value label.
+   *
+   * @param font the font
+   */
+  public void setFont(Font font) {
+    font_ = font;
+  }
+  /**
+   * Get the value label font
+   */
+  public Font getFont() {
+    return font_;
+  }
+  /**
+   * Get the total width, icon + label.
+   */
+  public int getIconWidth() {
+    return bounds_.width;
+  }
+  /**
+   * Get the total heigth.
+   */
+  public int getIconHeight() {
+    return bounds_.height;
+  }
+  private void computeBounds(Graphics g) {
+    int wid = super.getIconWidth();
+    int hgt = super.getIconHeight();
+    g.setFont(font_);
+    FontMetrics fmet = g.getFontMetrics();
+    bounds_.width = wid + fmet.stringWidth(getDescription());
+    bounds_.height = hgt;
+  }
+
+  public LayerChild copy() {
+    return null;
+  }
+
+  public void setVisible(boolean vis) {
+    if(visible_ != vis) {
+      visible_ = vis;
+//        modified("UserIcon: setVisible(" + vis + ")");
+    }
+  }
+
+  public boolean isVisible() {
+    return visible_;
+  }
+
+  public void draw(Graphics g) {
+    int x = ((CartesianGraph)layer_.getGraph()).getXUtoD(uLoc_.getX());
+    int y = ((CartesianGraph)layer_.getGraph()).getYUtoD(uLoc_.getY());
+    paintIcon(layer_.getPane().getComponent(), g, x, y);
+  }
+
+  public String getId() {
+    return id_;
+  }
+
+  public Layer getLayer() {
+    return layer_;
+  }
+
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+
+  public void modified(String mess) {
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+
+  public void setId(String id) {
+    id_ = id;
+  }
+
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  public String toString() {
+    return "UserIcon: " + id_;
+  }
+
+  public Rectangle getBounds() {
+    return bounds_;
+  }
+
+  public boolean isSelected() {
+    return selected_;
+  }
+
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+
+  public boolean isSelectable() {
+    return selectable_;
+  }
+
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  /**
+   * Get the icon location in physical units.
+   */
+  public Point2D.Double getLocationP() {
+    return loc_;
+  }
+  /**
+   * Set the icon location in physical units.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setLocationP(Point2D.Double loc) {
+    SoTPoint pt;
+    loc_ = loc;
+    bounds_.x = layer_.getXPtoD(loc_.x);
+    bounds_.y = layer_.getYPtoD(loc_.y);
+    pt = ((CartesianGraph)layer_.getGraph()).getPtoU(loc_);
+    if(!pt.equals(uLoc_) || moved_) {
+      changes_.firePropertyChange("location",
+                                  uLoc_,
+                                  pt);
+      uLoc_ = pt;
+      moved_ = false;
+    }
+  }
+  /**
+   * Get the icon location in user units.
+   *
+   * @since 3.0
+   */
+  public SoTPoint getLocationU() {
+    return uLoc_;
+  }
+  /**
+   * Set the icon location in user units.  Location change can't be
+   * vetoed.
+   *
+   * @since 3.0
+   */
+  public void setLocationUNoVeto(SoTPoint loc) {
+    moved_ = moved_ || !loc.equals(uLoc_);
+    uLoc_ = loc;
+    loc_.x = ((CartesianGraph)layer_.getGraph()).getXUtoP(uLoc_.getX());
+    loc_.y = ((CartesianGraph)layer_.getGraph()).getYUtoP(uLoc_.getY());
+    bounds_.x = layer_.getXPtoD(loc_.x);
+    bounds_.y = layer_.getYPtoD(loc_.y);
+  }
+  /**
+   * Set the icon location in user units.  Location change can be
+   * vetoed.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   *
+   * @since 3.0
+   */
+  public void setLocationU(SoTPoint loc) throws PropertyVetoException {
+    if(!loc.equals(uLoc_) || moved_) {
+      vetos_.fireVetoableChange("location", uLoc_, loc);
+
+      changes_.firePropertyChange("location",
+                                   uLoc_,
+                                   loc);
+      uLoc_ = loc;
+      moved_ = false;
+      loc_.x = ((CartesianGraph)layer_.getGraph()).getXUtoP(uLoc_.getX());
+      loc_.y = ((CartesianGraph)layer_.getGraph()).getYUtoP(uLoc_.getY());
+      bounds_.x = layer_.getXPtoD(loc_.x);
+      bounds_.y = layer_.getYPtoD(loc_.y);
+    }
+  }
+  /**
+   * Set icon location in device coordinates. Locatoin change can't be
+   * vetoed.
+   */
+  public void setLocationNoVeto(int x, int y) {
+    SoTPoint pt;
+    bounds_.x = x;
+    bounds_.y = y;
+    loc_.x = layer_.getXDtoP(x);
+    loc_.y = layer_.getYDtoP(y);
+    pt = ((CartesianGraph)layer_.getGraph()).getPtoU(loc_);
+    moved_ = moved_ || !pt.equals(uLoc_);
+    uLoc_ = pt;
+  }
+  /**
+   * Set icon location in device units
+   */
+  public void setLocation(Point loc) {
+    setLocation(loc, true);
+  }
+  /**
+   * Set icon location in device units and optionally fire a
+   * <code>PropertyChangeEvent</code>.
+   */
+  public void setLocation(Point loc, boolean fireEvent) {
+    setBounds(loc.x, loc.y, 0, 0, fireEvent);
+  }
+  /**
+   * Set icon bounds.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    setBounds(x, y, width, height, true);
+  }
+
+  protected void setBounds(int x, int y, int width, int height, boolean fireEvent) {
+    SoTPoint pt;
+    bounds_.x = x;
+    bounds_.y = y;
+    loc_.x = layer_.getXDtoP(x);
+    loc_.y = layer_.getYDtoP(y);
+    pt = ((CartesianGraph)layer_.getGraph()).getPtoU(loc_);
+    moved_ = moved_ || !pt.equals(uLoc_);
+    if(moved_) {
+      SoTPoint temp = new SoTPoint(pt);
+      if(fireEvent) {
+        changes_.firePropertyChange("location",
+                                    uLoc_,
+                                    temp);
+        moved_ = false;
+      }
+      uLoc_ = temp;
+    }
+  }
+  /**
+   * Set icon bounds.
+   */
+  public void setBounds(Rectangle bounds) {
+    setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
+  }
+  public void addVetoableChangeListener(VetoableChangeListener l) {
+    vetos_.addVetoableChangeListener(l);
+  }
+  public void removeVetoableChangeListener(VetoableChangeListener l) {
+    vetos_.removeVetoableChangeListener(l);
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ValueIcon.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ValueIcon.java
new file mode 100755
index 0000000..42b9397
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ValueIcon.java
@@ -0,0 +1,373 @@
+/*
+ * $Id: ValueIcon.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing;
+
+import gov.noaa.pmel.sgt.LayerChild;
+import gov.noaa.pmel.sgt.Layer;
+import gov.noaa.pmel.sgt.CartesianGraph;
+import gov.noaa.pmel.sgt.AbstractPane;
+
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.Debug;
+
+import javax.swing.ImageIcon;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.Image;
+import java.net.URL;
+import java.awt.Graphics;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeSupport;
+import java.beans.VetoableChangeListener;
+/**
+ * <code>ValueIcon</code> extends <code>ImageIcon</code> to create a
+ * icon than can be dragged on a <code>sgt</code> plot displaying the
+ * local coordinates along with the image.  Typically a cross-hairs
+ * image is used, but others can be substituted.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see UserIcon
+ * @see ValueIconFormat
+ */
+public class ValueIcon extends ImageIcon implements LayerChild, Draggable {
+  private int iWidth_ = 0;
+  private int iHeight_ = 0;
+  private boolean selected_ = false;
+  private boolean selectable_ = true;
+  private boolean moved_ = false;
+  private Layer layer_ = null;
+  private String id_ = null;
+  private boolean visible_ = true;
+  private Rectangle bounds_ = new Rectangle();
+  private Point2D.Double loc_ = new Point2D.Double();
+  private SoTPoint uLoc_ = new SoTPoint(0.0, 0.0);
+  private Font font_ = new Font("Dialog", Font.PLAIN, 12);
+  private Color textColor_ = Color.black;
+  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
+  private VetoableChangeSupport vetos_ = new VetoableChangeSupport(this);
+  private ValueIconFormat frmt_ = new ValueIconFormat("#####.##", "#.#");
+  private final static String defTFrmt = "yyyy-MM-dd";
+  /**
+   * Construct a <code>ValueIcon</code> using an image from a
+   * specified file.
+   *
+   * @param filename name of image file
+   * @param description brief textual description of the image
+   */
+  public ValueIcon(String filename, String description) {
+    super(filename, description);
+    getImageSize();
+    frmt_.setTimeFormat(defTFrmt);
+  }
+  /**
+   * Construct a <code>ValueIcon</code> using an image from a
+   * specified <code>URL</code>.
+   *
+   * @param location URL of image file
+   * @param description brief textual description of the image
+   */
+  public ValueIcon(URL location, String description) {
+    super(location, description);
+    getImageSize();
+    frmt_.setTimeFormat(defTFrmt);
+  }
+  /**
+   * Construct a <code>ValueIcon</code> using an <code>Image</code>.
+   *
+   * @param image the image
+   * @param description brief textual description of the image
+   */
+  public ValueIcon(Image image, String description) {
+    super(image, description);
+    getImageSize();
+    frmt_.setTimeFormat(defTFrmt);
+  }
+  /**
+   * Set format to be used to create the value string.  Default format
+   * is <code>new ValueIconFormat("#####.##", "#")</code>.
+   *
+   * @param the value format
+   */
+  public void setValueFormat(ValueIconFormat vf) {
+    frmt_ = vf;
+  }
+  /**
+   * Paint the icon at the specified location.
+   */
+  public void paintIcon(Component c, Graphics g, int x, int y) {
+    String text;
+    double xu, yu;
+    double xt, yt;
+    //
+    // compute bounds
+    //
+    text = frmt_.format(uLoc_);
+    FontMetrics fmet = g.getFontMetrics();
+    int wid = fmet.stringWidth(text);
+    int hgt = fmet.getMaxAscent() + fmet.getMaxDescent();
+    bounds_.x = x;
+    bounds_.y = y;
+    bounds_.width = iWidth_ + wid;
+    bounds_.height = iHeight_ + fmet.getMaxDescent();
+    //
+    if(visible_) {
+      g.drawImage(getImage(), bounds_.x, bounds_.y, layer_.getPane().getComponent());
+      int xl = bounds_.x + iWidth_;
+      int yl = bounds_.y + iHeight_;
+      g.setFont(font_);
+      g.setColor(layer_.getPane().getComponent().getBackground());
+      g.fillRect(xl,yl-fmet.getMaxAscent(),wid,hgt);
+      g.setColor(textColor_);
+      g.drawString(text, xl, yl);
+    }
+  }
+  /**
+   * Set the font for the value label.
+   *
+   * @param font the font
+   */
+  public void setFont(Font font) {
+    font_ = font;
+  }
+  /**
+   * Get the value label font
+   */
+  public Font getFont() {
+    return font_;
+  }
+  private void getImageSize() {
+    iWidth_ = super.getIconWidth();
+    iHeight_ = super.getIconHeight();
+  }
+  /**
+   * Get the total width, icon + label.
+   */
+  public int getIconWidth() {
+    return bounds_.width;
+  }
+  /**
+   * Get the total heigth.
+   */
+  public int getIconHeight() {
+    return bounds_.height;
+  }
+  public LayerChild copy() {
+    return null;
+  }
+  public void setVisible(boolean vis) {
+    if(visible_ != vis) {
+      visible_ = vis;
+    }
+  }
+  public boolean isVisible() {
+    return visible_;
+  }
+
+  public void draw(Graphics g) {
+    int x = ((CartesianGraph)layer_.getGraph()).getXUtoD(uLoc_.getX()) -
+      iWidth_/2;
+    int y = ((CartesianGraph)layer_.getGraph()).getYUtoD(uLoc_.getY()) -
+      iHeight_/2;
+    paintIcon(layer_.getPane().getComponent(), g, x, y);
+  }
+  public String getId() {
+    return id_;
+  }
+  public Layer getLayer() {
+    return layer_;
+  }
+  public AbstractPane getPane() {
+    return layer_.getPane();
+  }
+  public void modified(String mess) {
+    if(layer_ != null)
+      layer_.modified(mess);
+  }
+  public void setId(String id) {
+    id_ = id;
+  }
+  public void setLayer(Layer l) {
+    layer_ = l;
+  }
+  public String toString() {
+    return "ValueIcon: " + id_;
+  }
+  public Rectangle getBounds() {
+    return bounds_;
+  }
+  public boolean isSelected() {
+    return selected_;
+  }
+  public void setSelected(boolean sel) {
+    selected_ = sel;
+  }
+  public boolean isSelectable() {
+    return selectable_;
+  }
+  public void setSelectable(boolean select) {
+    selectable_ = select;
+  }
+  /**
+   * Get the icon location in physical units.
+   */
+  public Point2D.Double getLocationP() {
+    return loc_;
+  }
+  /**
+   * Set the icon location in physical units.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setLocationP(Point2D.Double loc) {
+    SoTPoint pt;
+    loc_ = loc;
+    bounds_.x = layer_.getXPtoD(loc_.x) - iWidth_/2;
+    bounds_.y = layer_.getYPtoD(loc_.y) - iHeight_/2;
+    pt = ((CartesianGraph)layer_.getGraph()).getPtoU(loc_);
+    if(!pt.equals(uLoc_) || moved_) {
+      SoTPoint temp = new SoTPoint(pt);
+      changes_.firePropertyChange("location",
+          uLoc_,
+          temp);
+      uLoc_ = temp;
+      moved_ = false;
+    }
+  }
+  /**
+   * Get the icon location in user units.
+   *
+   * @since 3.0
+   */
+  public SoTPoint getLocationU() {
+    return uLoc_;
+  }
+  /**
+   * Set the icon location in user units.  Location change can't be
+   * vetoed.
+   *
+   * @since 3.0
+   */
+  public void setLocationUNoVeto(SoTPoint loc) {
+    moved_ = moved_ || !loc.equals(uLoc_);
+    uLoc_ = loc;
+    loc_.x = ((CartesianGraph)layer_.getGraph()).getXUtoP(uLoc_.getX());
+    loc_.y = ((CartesianGraph)layer_.getGraph()).getYUtoP(uLoc_.getY());
+    bounds_.x = layer_.getXPtoD(loc_.x);
+    bounds_.y = layer_.getYPtoD(loc_.y);
+  }
+  /**
+   * Set the icon location in user units.  Location change can be
+   * vetoed.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   * @since 3.0
+   */
+  public void setLocationU(SoTPoint loc) throws PropertyVetoException {
+    if(!loc.equals(uLoc_) || moved_) {
+      vetos_.fireVetoableChange("location", uLoc_, loc);
+
+      changes_.firePropertyChange("location",
+          uLoc_,
+          loc);
+      uLoc_ = loc;
+      moved_ = false;
+      loc_.x = ((CartesianGraph)layer_.getGraph()).getXUtoP(uLoc_.getX());
+      loc_.y = ((CartesianGraph)layer_.getGraph()).getYUtoP(uLoc_.getY());
+      bounds_.x = layer_.getXPtoD(loc_.x) - iWidth_/2;
+      bounds_.y = layer_.getYPtoD(loc_.y) - iHeight_/2;
+    }
+  }
+  /**
+   * Set icon location in device coordinates. Locatoin change can't be
+   * vetoed.
+   */
+  public void setLocationNoVeto(int x, int y) {
+    SoTPoint pt;
+    bounds_.x = x;
+    bounds_.y = y;
+    loc_.x = layer_.getXDtoP(x);
+    loc_.y = layer_.getYDtoP(y);
+    pt = ((CartesianGraph)layer_.getGraph()).getPtoU(loc_);
+    moved_ = moved_ || !pt.equals(uLoc_);
+    uLoc_ = new SoTPoint(pt);
+  }
+  /**
+   * Set icon location in device units
+   */
+  public void setLocation(Point loc) {
+    setLocation(loc, true);
+  }
+  /**
+   * Set icon location in device units and optionally fire a
+   * <code>PropertyChangeEvent</code>.
+   *
+   * @since 3.0
+   */
+  public void setLocation(Point loc, boolean fireEvent) {
+    setBounds(loc.x, loc.y, 0, 0, fireEvent);
+  }
+  /**
+   * Set icon bounds.
+   * <BR><B>Property Change:</B> <code>location</code>.
+   */
+  public void setBounds(int x, int y, int width, int height) {
+    setBounds(x, y, width, height, true);
+  }
+
+  private void setBounds(int x, int y, int width, int height, boolean fireEvent) {
+    SoTPoint pt;
+    bounds_.x = x;
+    bounds_.y = y;
+    loc_.x = layer_.getXDtoP(x + iWidth_/2);
+    loc_.y = layer_.getYDtoP(y + iHeight_/2);
+    pt = ((CartesianGraph)layer_.getGraph()).getPtoU(loc_);
+    moved_ = moved_ || !pt.equals(uLoc_);
+    if(moved_) {
+      SoTPoint temp = new SoTPoint(pt);
+      if(fireEvent) {
+        changes_.firePropertyChange("location",
+                                    uLoc_,
+                                    temp);
+        moved_ = false;
+      }
+      uLoc_ = temp;
+    }
+
+  }
+  /**
+   * Set icon bounds.
+   */
+  public void setBounds(Rectangle bounds) {
+    setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
+  }
+  public void addVetoableChangeListener(VetoableChangeListener l) {
+    vetos_.addVetoableChangeListener(l);
+  }
+  public void removeVetoableChangeListener(VetoableChangeListener l) {
+    vetos_.removeVetoableChangeListener(l);
+  }
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes_.addPropertyChangeListener(l);
+  }
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes_.removePropertyChangeListener(l);
+  }
+
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ValueIconFormat.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ValueIconFormat.java
new file mode 100755
index 0000000..0a4993b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/ValueIconFormat.java
@@ -0,0 +1,80 @@
+/*
+ * $Id: ValueIconFormat.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing;
+
+import java.text.DecimalFormat;
+
+import gov.noaa.pmel.util.SoTPoint;
+import gov.noaa.pmel.util.SoTValue;
+
+/**
+ * <code>ValueIconFormat</code> is used to create the value string for
+ * <code>ValueIcon</code>. This class can be extended to create more
+ * sophisticated formatting.  For example, handling the modulo 360 of
+ * longitude coordinates.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @see DecimalFormat
+ * @see ValueIcon
+ */
+public class ValueIconFormat {
+  protected DecimalFormat xfrm_;
+  protected DecimalFormat yfrm_;
+  protected String tfrm_ = "yyyy-MM-dd HH:mm:ss z";
+  /**
+   * Construct <code>ValueIconFormat</code> from x and y coordinate
+   * <code>DeciamalFormat</code>s.
+   */
+  public ValueIconFormat(String xfrmt, String yfrmt) {
+    xfrm_ = new DecimalFormat(xfrmt);
+    yfrm_ = new DecimalFormat(yfrmt);
+  }
+  /**
+   * Format a string using <code>DecimalFormat</code> for x and y
+   * coordinates.
+   */
+  public String format(double x, double y) {
+    return "(" + xfrm_.format(x) + ", " + yfrm_.format(y) + ")";
+  }
+  /**
+   * Define the time format.
+   *
+   * @since 3.0
+   */
+   public void setTimeFormat(String tfrmt) {
+    tfrm_ = tfrmt;
+   }
+  /**
+   * Format a string using <code>DecimalFormat</code> for x and y
+   * coordinates or <code>GeoDate</code> formatting for time.
+   *
+   * @since 3.0
+   */
+  public String format(SoTPoint pt) {
+    StringBuffer sbuf = new StringBuffer("(");
+    if(pt.isXTime()) {
+      sbuf.append(pt.getX().getGeoDate().toString(tfrm_));
+    } else {
+      sbuf.append(xfrm_.format(((SoTValue.Double)pt.getX()).getValue()));
+    }
+    sbuf.append(", ");
+    if(pt.isYTime()) {
+      sbuf.append(pt.getY().getGeoDate().toString(tfrm_));
+    } else {
+      sbuf.append(yfrm_.format(((SoTValue.Double)pt.getY()).getValue()));
+    }
+    sbuf.append(")");
+    return sbuf.toString();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/package.html
new file mode 100755
index 0000000..ec2d722
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/package.html
@@ -0,0 +1,14 @@
+<HTML>
+<BODY>
+Components that use the package <code>javax.swing</code>.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/plotmarkcodes.png b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/plotmarkcodes.png
new file mode 100755
index 0000000..16d181a
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/plotmarkcodes.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ArrayEditDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ArrayEditDialog.java
new file mode 100755
index 0000000..df9ea57
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ArrayEditDialog.java
@@ -0,0 +1,338 @@
+/*
+ * $Id: ArrayEditDialog.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.util.Enumeration;
+/**
+ * This dialog accepts an array of float's then via a graphical
+ * interface allows this array to be modified.  For example, this
+ * dialog is used to edit the dash array of the <code>LineAttribute</code>.
+ *
+ * <p> Example of <code>ArrayEditDialog</code> use:
+ * <pre>
+ *
+ * public float[] editArray(float[] inArray) {
+ *   ArrayEditDialog aed = new ArrayEditDialog();
+ *   aed.setTitle("ArrayEdit");
+ *   aed.setArray(inArray);
+ *   if(aed.showDialog() == ArrayEditDialog.CANCEL_RESPONSE) {
+ *     return inArray;
+ *   } else {
+ *     return aed.getFloatArray();
+ *   }
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ * @LineAttribute
+ */
+public class ArrayEditDialog extends JDialog implements ListSelectionListener {
+  private DefaultListModel model_;
+  private int result_;
+  /** OK button was selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button was selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Constructor.
+   */
+  public ArrayEditDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(322,349);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(48,396);
+    mainPanel.setLayout(new GridBagLayout());
+    getContentPane().add(mainPanel, "Center");
+    mainPanel.add(JScrollPane1, new GridBagConstraints(0,0,1,3,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,5,5,5),155,0));
+    arrayList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+    JScrollPane1.getViewport().add(arrayList);
+    arrayList.setBounds(0,0,173,295);
+    JPanel2.setBorder(titledBorder2);
+    JPanel2.setLayout(new GridBagLayout());
+    mainPanel.add(JPanel2, new GridBagConstraints(1,0,1,1,0.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,5),0,0));
+    JPanel2.add(editTextField,new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    editButton.setToolTipText("Change value of selected element.");
+    editButton.setText("Change Value");
+    JPanel2.add(editButton,new GridBagConstraints(0,1,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0));
+    JPanel3.setBorder(titledBorder3);
+    JPanel3.setLayout(new GridBagLayout());
+    mainPanel.add(JPanel3, new GridBagConstraints(1,2,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,0,0,0),0,0));
+    deleteButton.setToolTipText("Delete selected element.");
+    deleteButton.setText("Delete");
+    JPanel3.add(deleteButton,new GridBagConstraints(0,0,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0));
+    JPanel1.setBorder(titledBorder1);
+    JPanel1.setLayout(new GridBagLayout());
+    mainPanel.add(JPanel1, new GridBagConstraints(1,1,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,0,0,0),0,0));
+    JPanel1.add(insertTextField, new GridBagConstraints(0,0,1,1,1.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    beforeButton.setToolTipText("Insert new item before selected element.");
+    beforeButton.setText("Before");
+    JPanel1.add(beforeButton, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    afterButton.setToolTipText("Insert new item after selected element.");
+    afterButton.setText("After");
+    JPanel1.add(afterButton, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    setTitle("Edit Array");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    editButton.addActionListener(lSymAction);
+    beforeButton.addActionListener(lSymAction);
+    afterButton.addActionListener(lSymAction);
+    deleteButton.addActionListener(lSymAction);
+
+    arrayList.addListSelectionListener(this);
+  }
+  /**
+   * Used internally.
+   */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public ArrayEditDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /** Default constructor */
+  public ArrayEditDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible.
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == ArrayEditDialog.this)
+  ArrayEditDialog_WindowClosing(event);
+    }
+  }
+
+  void ArrayEditDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+  javax.swing.JScrollPane JScrollPane1 = new javax.swing.JScrollPane();
+  javax.swing.JList arrayList = new javax.swing.JList();
+  javax.swing.JPanel JPanel2 = new javax.swing.JPanel();
+  javax.swing.JTextField editTextField = new javax.swing.JTextField();
+  javax.swing.JButton editButton = new javax.swing.JButton();
+  javax.swing.JPanel JPanel3 = new javax.swing.JPanel();
+  javax.swing.JButton deleteButton = new javax.swing.JButton();
+  javax.swing.JPanel JPanel1 = new javax.swing.JPanel();
+  javax.swing.JTextField insertTextField = new javax.swing.JTextField();
+  javax.swing.JButton beforeButton = new javax.swing.JButton();
+  javax.swing.JButton afterButton = new javax.swing.JButton();
+  javax.swing.border.TitledBorder titledBorder1 = new javax.swing.border.TitledBorder("Insert Element");
+  javax.swing.border.TitledBorder titledBorder2 = new javax.swing.border.TitledBorder("Edit Element");
+  javax.swing.border.TitledBorder titledBorder3 = new javax.swing.border.TitledBorder("Delete Element");
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+  cancelButton_actionPerformed(event);
+      else if (object == okButton)
+  okButton_actionPerformed(event);
+      else if (object == editButton)
+  editButton_actionPerformed(event);
+      else if (object == beforeButton)
+  beforeButton_actionPerformed(event);
+      else if (object == afterButton)
+  afterButton_actionPerformed(event);
+      if (object == deleteButton)
+  deleteButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    this.setVisible(false);
+  }
+  /**
+   * Test entry point.
+   */
+  public static void main(String[] args) {
+    float[] array = {0.0f, 2.0f, 2.5f, 3.0f, 4.5f};
+    ArrayEditDialog aed = new ArrayEditDialog();
+    aed.setTitle("Test ArrayEdit Dialog");
+    aed.setArray(array);
+    if(aed.showDialog() == CANCEL_RESPONSE) {
+      System.out.println("Dialog Cancelled");
+    } else {
+      float[] out = aed.getFloatArray();
+      for(int i=0; i < out.length; i++) {
+	System.out.println("x["+i+"] = " + out[i]);
+      }
+    }
+    aed.setVisible(false);
+    aed.dispose();
+    System.exit(0);
+  }
+  /**
+   * Show the dialog and wait for a response.
+   *
+   * @return CANCEL_RESPONSE or OK_RESPONSE
+   */
+  public int showDialog() {
+    result_ = CANCEL_RESPONSE;
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+  /**
+   * Initialize the array.
+   */
+  public void setArray(float[] array) {
+    model_ = new DefaultListModel();
+    for(int i=0; i < array.length; i++) {
+      model_.addElement(Float.toString(array[i]));
+    }
+    arrayList.setModel(model_);
+  }
+  /**
+   * Get the edited array.
+   */
+  public float[] getFloatArray() {
+    float[] array = new float[model_.size()];
+    Enumeration e = model_.elements();
+    int index = 0;
+    while(e.hasMoreElements()) {
+      array[index] = new Float((String)e.nextElement()).floatValue();
+      index++;
+    }
+    return array;
+  }
+
+  void editButton_actionPerformed(java.awt.event.ActionEvent event) {
+    for(int i=0; i < model_.size(); i++) {
+      if(arrayList.isSelectedIndex(i)) {
+  model_.set(i, editTextField.getText());
+  return;
+      }
+    }
+  }
+
+  void beforeButton_actionPerformed(java.awt.event.ActionEvent event) {
+    for(int i=0; i < model_.size(); i++) {
+      if(arrayList.isSelectedIndex(i)) {
+  model_.insertElementAt(insertTextField.getText(), i);
+  return;
+      }
+    }
+  }
+
+  void afterButton_actionPerformed(java.awt.event.ActionEvent event) {
+    for(int i=0; i < model_.size(); i++) {
+      if(arrayList.isSelectedIndex(i)) {
+  model_.insertElementAt(insertTextField.getText(), i+1);
+  return;
+      }
+    }
+  }
+  /**
+   * Internal event listener
+   */
+  public void valueChanged(ListSelectionEvent e) {
+    if(e.getValueIsAdjusting()) return;
+    int first = e.getFirstIndex();
+    int last = e.getLastIndex();
+    for(int i=first; i <= last; i++) {
+      if(arrayList.isSelectedIndex(i))
+  editTextField.setText((String)model_.get(i));
+    }
+  }
+
+  void deleteButton_actionPerformed(java.awt.event.ActionEvent event) {
+    for(int i=0; i < model_.size(); i++) {
+      if(arrayList.isSelectedIndex(i)) {
+  model_.removeElementAt(i);
+  return;
+      }
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ColorDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ColorDialog.java
new file mode 100755
index 0000000..00cb5b8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ColorDialog.java
@@ -0,0 +1,132 @@
+/*
+ * $Id: ColorDialog.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing.prop;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.*;
+import javax.swing.border.*;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 3.0
+ **/
+public class ColorDialog extends JDialog {
+  private JPanel panel1 = new JPanel();
+  private JColorChooser colorChooserPanel = new JColorChooser();
+  private JPanel alphaPanel = new JPanel();
+  private JPanel buttonPanel = new JPanel();
+  private JButton cancelButton = new JButton();
+  private JButton okButton = new JButton();
+  private TitledBorder titledBorder1;
+  private JLabel jLabel1 = new JLabel();
+  private Border border1;
+  private GridBagLayout gridBagLayout1 = new GridBagLayout();
+  private JTextField alphaTF = new JTextField();
+  private GridBagLayout gridBagLayout2 = new GridBagLayout();
+
+  private Color color_ = null;
+
+  public ColorDialog(Dialog dialog,  String title, boolean modal) {
+    super(dialog, title, modal);
+    init(dialog);
+  }
+
+  public ColorDialog(Frame frame, String title, boolean modal) {
+    super(frame, title, modal);
+    init(frame);
+  }
+
+  private void init(Window win) {
+    try {
+      jbInit();
+      pack();
+    }
+    catch(Exception ex) {
+      ex.printStackTrace();
+    }
+    if(win != null) {
+      Rectangle fBounds = win.getBounds();
+      Point fLoc = win.getLocationOnScreen();
+      Rectangle bounds = getBounds();
+      int x = fLoc.x + fBounds.width/2 - bounds.width/2;
+      int y = fLoc.y + fBounds.height/2 - bounds.height/2;
+      setLocation(x, y);
+    }
+  }
+
+  public ColorDialog() {
+    this((Frame)null, "", false);
+  }
+
+  private void jbInit() throws Exception {
+    titledBorder1 = new TitledBorder("");
+    border1 = BorderFactory.createLineBorder(Color.gray,1);
+    panel1.setLayout(gridBagLayout1);
+    buttonPanel.setBorder(BorderFactory.createEtchedBorder());
+    cancelButton.setText("Cancel");
+    cancelButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        cancelButton_actionPerformed(e);
+      }
+    });
+    okButton.setText("OK");
+    okButton.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        okButton_actionPerformed(e);
+      }
+    });
+    alphaPanel.setBorder(titledBorder1);
+    alphaPanel.setLayout(gridBagLayout2);
+    titledBorder1.setTitle("Alpha Channel");
+    titledBorder1.setBorder(border1);
+    jLabel1.setText("Alpha");
+    alphaTF.setText("0");
+    alphaTF.setColumns(5);
+    getContentPane().add(panel1);
+    panel1.add(colorChooserPanel,    new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
+    panel1.add(alphaPanel,    new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0));
+    alphaPanel.add(jLabel1,   new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 10, 5, 5), 0, 0));
+    alphaPanel.add(alphaTF,    new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 15), 0, 0));
+    panel1.add(buttonPanel,     new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0));
+    buttonPanel.add(okButton, null);
+    buttonPanel.add(cancelButton, null);
+  }
+
+  void cancelButton_actionPerformed(ActionEvent e) {
+    setVisible(false);
+  }
+
+  void okButton_actionPerformed(ActionEvent e) {
+    Color temp = colorChooserPanel.getColor();
+    int alpha = Integer.parseInt(alphaTF.getText());
+    color_ = new Color(temp.getRed(), temp.getGreen(), temp.getBlue(), alpha);
+    setVisible(false);
+  }
+
+  public void setColor(Color color) {
+    color_ = color;
+    colorChooserPanel.setColor(color_);
+    alphaTF.setText(Integer.toString(color_.getAlpha()));
+  }
+
+  public Color getColor() {
+    return color_;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ColorEntryPanel.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ColorEntryPanel.java
new file mode 100755
index 0000000..d2a9f21
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ColorEntryPanel.java
@@ -0,0 +1,146 @@
+/*
+ * $Id: ColorEntryPanel.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.event.*;
+import java.awt.*;
+
+import gov.noaa.pmel.swing.ThreeDotsButton;
+
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 3.0
+ **/
+public class ColorEntryPanel extends JComponent {
+//  private ThreeDotsIcon dotsIcon_ = new ThreeDotsIcon(Color.black);
+  private JLabel redLabel = new JLabel();
+  private JLabel greenLabel = new JLabel();
+  private JLabel blueLabel = new JLabel();
+  private JLabel alphaLabel = new JLabel();
+  private JTextField redTF = new JTextField();
+  private JTextField greenTF = new JTextField();
+  private JTextField blueTF = new JTextField();
+  private JTextField alphaTF = new JTextField();
+  private ThreeDotsButton button = new ThreeDotsButton();
+  private FlowLayout fLayout = new FlowLayout();
+
+  private Color color_ = Color.black;
+  private String title_ = "Set Color";
+
+  public ColorEntryPanel(String title, Color color) {
+    super();
+    setColor(color);
+    setTitle(title);
+  }
+
+  public ColorEntryPanel() {
+    try {
+      jbInit();
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  private void jbInit() throws Exception {
+    setLayout(fLayout);
+    redLabel.setText("red");
+    greenLabel.setText("green");
+    blueLabel.setText("blue");
+    alphaLabel.setText("alpha");
+    redTF.setText("0");
+    redTF.setColumns(3);
+    greenTF.setText("0");
+    greenTF.setColumns(3);
+    blueTF.setText("0");
+    blueTF.setColumns(3);
+    alphaTF.setText("0");
+    alphaTF.setColumns(3);
+    button.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        button_actionPerformed(e);
+      }
+    });
+    button.setToolTipText("Edit color.");
+    button.setActionCommand("...");
+    add(redLabel);
+    add(redTF);
+    add(greenLabel);
+    add(greenTF);
+    add(blueLabel);
+    add(blueTF);
+    add(alphaLabel);
+    add(alphaTF);
+    add(button);
+    boolean enabled = isEnabled();
+    redTF.setEnabled(enabled);
+    greenTF.setEnabled(enabled);
+    blueTF.setEnabled(enabled);
+    alphaTF.setEnabled(enabled);
+    button.setEnabled(enabled);
+  }
+
+  public void setEnabled(boolean enabled) {
+    super.setEnabled(enabled);
+    redTF.setEnabled(enabled);
+    greenTF.setEnabled(enabled);
+    blueTF.setEnabled(enabled);
+    alphaTF.setEnabled(enabled);
+    button.setEnabled(enabled);
+  }
+
+  void button_actionPerformed(ActionEvent e) {
+    Window win = javax.swing.SwingUtilities.getWindowAncestor(this);
+    ColorDialog cd = null;
+    if(win instanceof Frame) {
+      cd = new ColorDialog((Frame)win, title_, true);
+    } else if(win instanceof Dialog) {
+      cd = new ColorDialog((Dialog)win, title_, true);
+    } else {
+      cd = new ColorDialog((Frame)null, title_, true);
+    }
+    cd.setColor(getColorFromTF());
+    cd.setVisible(true);
+    setColor(cd.getColor());
+  }
+
+  public void setColor(Color color) {
+    color_ = color;
+    redTF.setText(Integer.toString(color_.getRed()));
+    greenTF.setText(Integer.toString(color_.getGreen()));
+    blueTF.setText(Integer.toString(color_.getBlue()));
+    alphaTF.setText(Integer.toString(color_.getAlpha()));
+  }
+
+  public Color getColor() {
+    return getColorFromTF();
+  }
+
+  private Color getColorFromTF() {
+    int red = Integer.parseInt(redTF.getText());
+    int green = Integer.parseInt(greenTF.getText());
+    int blue = Integer.parseInt(blueTF.getText());
+    int alpha = Integer.parseInt(alphaTF.getText());
+    return new Color(red, green, blue, alpha);
+  }
+
+  public void setTitle(String title) {
+    title_ = title;
+  }
+  public String getTitle() {
+    return title_;
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ContourLevelsDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ContourLevelsDialog.java
new file mode 100755
index 0000000..3027710
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ContourLevelsDialog.java
@@ -0,0 +1,479 @@
+/*
+ * $Id: ContourLevelsDialog.java,v 1.1.1.1 2007/09/07 06:32:04 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.TableColumn;
+import javax.swing.table.AbstractTableModel;
+import java.awt.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import gov.noaa.pmel.sgt.ContourLevels;
+import gov.noaa.pmel.sgt.ContourLevelNotFoundException;
+import gov.noaa.pmel.sgt.ContourLineAttribute;
+import gov.noaa.pmel.sgt.DefaultContourLineAttribute;
+
+/**
+ * This dialog edits a <code>ContourLevels</code> object. This dialog
+ * has the standalone functionality found in the      
+ * <code>GridAttributeDialog</code> to edit <code>ContourLevels</code>
+ * objects. 
+ *
+ * <p> Example of <code>ContourLevelsDialog</code> use:
+ * <pre>
+ *
+ * public ContourLevels editLevels(ContourLevels inLevels) {
+ *   ContourLevelsDialog cld = new ContourLevelsDialog(inLevels);
+ *   if(cld.showDialog() == ContourLevelsDialog.CANCEL_RESPONSE) {
+ *     return inLevels;
+ *   } else {
+ *     return cld.getContourLevels();
+ *   }
+ * }
+ *
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:04 $
+ * @since 2.0
+ */
+public class ContourLevelsDialog extends JDialog {
+  private ContourLevels conLevels_;
+  private JTable table_;
+  private ConLevelTableModel model_;
+  private int result_;
+  /** OK button was selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button was selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Constructor.
+   */
+  public ContourLevelsDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(529,307);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5,5));
+    gridScrollPane.setMinimumSize(new Dimension(350, 283));
+    gridScrollPane.setPreferredSize(new Dimension(350, 283));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    controlPanel.setLayout(new GridBagLayout());
+    getContentPane().add(controlPanel, "East");
+    JPanel1.setBorder(titledBorder1);
+    JPanel1.setLayout(new GridBagLayout());
+    controlPanel.add(JPanel1, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0
+						     ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
+    editButton.setToolTipText("Edit attribute of selected level.");
+    editButton.setText("Edit Attribute");
+    editButton.setActionCommand("Change Value");
+    JPanel1.add(editButton, new GridBagConstraints(0,0,1,1,1.0,1.0,
+						   GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    aboveButton.setToolTipText("Insert level above selected level.");
+    aboveButton.setText("Insert Level Above");
+    aboveButton.setActionCommand("Before Item");
+    JPanel1.add(aboveButton, new GridBagConstraints(0,1,1,1,1.0,1.0,
+						    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    belowButton.setToolTipText("Insert level below selected level.");
+    belowButton.setText("Insert Level Below");
+    belowButton.setActionCommand("After Item");
+    JPanel1.add(belowButton, new GridBagConstraints(0,2,1,1,1.0,1.0,
+						    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    deleteButton.setToolTipText("Delete the selected level.");
+    deleteButton.setText("Delete Level");
+    deleteButton.setActionCommand("Delete Item");
+    JPanel1.add(deleteButton, new GridBagConstraints(0,3,1,1,1.0,1.0,
+						     GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0));
+    JPanel4.setBorder(titledBorder4);
+    JPanel4.setLayout(new GridBagLayout());
+    controlPanel.add(JPanel4, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+						     ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 0, 0, 0), 0, 0));
+    defaultButton.setToolTipText("Edit default attributes.");
+    defaultButton.setText("Edit Default Attributes");
+    JPanel4.add(defaultButton,new GridBagConstraints(0,0,1,1,1.0,1.0,
+						     GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,5,5,5),0,0));
+    sortButton.setToolTipText("Sort levels by value.");
+    sortButton.setText("Sort Levels");
+    sortButton.setActionCommand("Sort");
+    controlPanel.add(sortButton, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+							,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 10, 5), 0, 0));
+    gridScrollPane.setBorder(compoundBorder1);
+    getContentPane().add(gridScrollPane, "Center");
+    setTitle("Edit Contour Levels");
+
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    editButton.addActionListener(lSymAction);
+    aboveButton.addActionListener(lSymAction);
+    belowButton.addActionListener(lSymAction);
+    deleteButton.addActionListener(lSymAction);
+    sortButton.addActionListener(lSymAction);
+    defaultButton.addActionListener(lSymAction);
+
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public ContourLevelsDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public ContourLevelsDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == ContourLevelsDialog.this)
+	ContourLevelsDialog_WindowClosing(event);
+    }
+  }
+
+  void ContourLevelsDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.JPanel controlPanel = new javax.swing.JPanel();
+  javax.swing.JPanel JPanel1 = new javax.swing.JPanel();
+  javax.swing.JButton editButton = new javax.swing.JButton();
+  javax.swing.JButton aboveButton = new javax.swing.JButton();
+  javax.swing.JButton belowButton = new javax.swing.JButton();
+  javax.swing.JButton deleteButton = new javax.swing.JButton();
+  javax.swing.JPanel JPanel4 = new javax.swing.JPanel();
+  javax.swing.JButton defaultButton = new javax.swing.JButton();
+  javax.swing.JButton sortButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JScrollPane gridScrollPane = new javax.swing.JScrollPane();
+  javax.swing.border.TitledBorder titledBorder1 = new javax.swing.border.TitledBorder("Contour Levels");
+  javax.swing.border.EmptyBorder emptyBorder1 = new javax.swing.border.EmptyBorder(5,0,0,0);
+  javax.swing.border.CompoundBorder compoundBorder1 = new
+    javax.swing.border.CompoundBorder(emptyBorder1, etchedBorder1);
+  javax.swing.border.TitledBorder titledBorder4 = new javax.swing.border.TitledBorder("Default Attributes");
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+	cancelButton_actionPerformed(event);
+      else if (object == okButton)
+	okButton_actionPerformed(event);
+      else if (object == editButton)
+	editButton_actionPerformed(event);
+      else if (object == aboveButton)
+	aboveButton_actionPerformed(event);
+      else if (object == belowButton)
+	belowButton_actionPerformed(event);
+      if (object == deleteButton)
+	deleteButton_actionPerformed(event);
+      else if (object == sortButton)
+	sortButton_actionPerformed(event);
+      else if (object == defaultButton)
+        defaultButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    update();
+    result_ = OK_RESPONSE;
+    this.setVisible(false);
+  }
+
+  private void update() {
+    ContourLevels cl = new ContourLevels();
+    Double val;
+    ContourLineAttribute attr;
+    int size = model_.getRowCount();
+    for(int i=0; i < size; i++) {
+      val = (Double)model_.getValueAt(i,0);
+      attr = (ContourLineAttribute)model_.getValueAt(i,1);
+      cl.addLevel(val.doubleValue(), attr);
+    }
+    cl.setDefaultContourLineAttribute(conLevels_.getDefaultContourLineAttribute());
+    conLevels_ = cl;
+  }
+  /**
+   * Dialog test entry point.
+   */
+  public static void main(String[] args) {
+    ContourLevelsDialog cla = new ContourLevelsDialog();
+    cla.setTitle("Test ContourLevels Dialog");
+    cla.setVisible(true);
+  }
+  /**
+   * Show the dialog and wait for a response.
+   *
+   * @param cl <code>ContourLevels</code> object to be edited
+   * @return return code
+   */
+  public int showDialog(ContourLevels cl) {
+    conLevels_ = cl;
+    result_ = CANCEL_RESPONSE;
+    createTable();
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+
+  void createTable() {
+    Double val;
+    ContourLineAttribute attr;
+    int size = conLevels_.size();
+    model_ = new ConLevelTableModel();
+    for(int i=0; i < size; i++) {
+      try {
+	val = new Double(conLevels_.getLevel(i));
+	attr = conLevels_.getContourLineAttribute(i);
+	model_.add(val, attr);
+      } catch (ContourLevelNotFoundException e) {
+	System.out.println(e);
+      }
+    }
+    table_ = new JTable(model_);
+    table_.setSize(1000,1000);
+    ListSelectionModel lsm = table_.getSelectionModel();
+    lsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+    TableColumn tc;
+    tc = table_.getColumnModel().getColumn(0);
+    tc.setPreferredWidth(250);
+    tc = table_.getColumnModel().getColumn(1);
+    tc.setPreferredWidth(750);
+    gridScrollPane.getViewport().add(table_);
+  }
+  /**
+   * Get the edited <code>ContourLevels</code>.
+   */
+  public ContourLevels getContourLevels() {
+    return conLevels_;
+  }
+
+  void editButton_actionPerformed(java.awt.event.ActionEvent event) {
+    ContourLineAttribute attr;
+    int index = table_.getSelectedRow();
+    if(index < 0) return;
+    ContourLineAttributeDialog clad = new ContourLineAttributeDialog();
+    attr = (ContourLineAttribute)
+      ((ContourLineAttribute)model_.getValueAt(index,1)).copy();
+    int result = clad.showDialog(attr);
+    if(result == ContourLineAttributeDialog.OK_RESPONSE) {
+      attr = clad.getContourLineAttribute();
+      model_.setValueAt(attr, index, 1);
+    }
+  }
+
+  void aboveButton_actionPerformed(java.awt.event.ActionEvent event) {
+    int index = table_.getSelectedRow();
+    if(index < 0) return;
+    model_.insert(index,
+		  new Double(0.0),
+		  new ContourLineAttribute(ContourLineAttribute.SOLID));
+  }
+
+  void belowButton_actionPerformed(java.awt.event.ActionEvent event) {
+    int index = table_.getSelectedRow();
+    if(index < 0) return;
+    model_.insert(index + 1,
+		  new Double(0.0),
+		  new ContourLineAttribute(ContourLineAttribute.SOLID));
+  }
+
+
+  void deleteButton_actionPerformed(java.awt.event.ActionEvent event) {
+    int index = table_.getSelectedRow();
+    if(index < 0) return;
+    model_.remove(index);
+  }
+
+  void sortButton_actionPerformed(java.awt.event.ActionEvent event) {
+    model_.sort();
+  }
+
+  void defaultButton_actionPerformed(java.awt.event.ActionEvent event) {
+    DefaultContourLineAttribute attr;
+    DefaultContourLineAttributeDialog dclad = new DefaultContourLineAttributeDialog();
+    attr = conLevels_.getDefaultContourLineAttribute();
+    int result = dclad.showDialog((DefaultContourLineAttribute)attr.copy());
+    if(result == DefaultContourLineAttributeDialog.OK_RESPONSE) {
+      attr = dclad.getDefaultContourLineAttribute();
+      conLevels_.setDefaultContourLineAttribute(attr);
+    }
+  }
+
+  class ConLevelTableModel extends AbstractTableModel {
+    Vector values = new Vector();
+    Vector attr = new Vector();
+    String[] titles = {"Value", "Attribute"};
+
+    public void add(Double val, ContourLineAttribute cla) {
+      values.addElement(val);
+      attr.addElement(cla);
+    }
+
+    public void insert(int row, Double val, ContourLineAttribute cla) {
+      values.insertElementAt(val, row);
+      attr.insertElementAt(cla, row);
+      fireTableChanged(new TableModelEvent(this, row, row,
+					   TableModelEvent.ALL_COLUMNS,
+					   TableModelEvent.INSERT));
+    }
+
+    public void remove(int row) {
+      values.removeElementAt(row);
+      attr.removeElementAt(row);
+      fireTableChanged(new TableModelEvent(this, row, row,
+					   TableModelEvent.ALL_COLUMNS,
+					   TableModelEvent.DELETE));
+    }
+
+    public void sort() {
+      //
+      // use brain-dead bubble sort (there will be few lines)
+      //
+      int i, temp;
+      int size = values.size();
+      Double a, b;
+      int[] index = new int[size];
+      boolean flipped = true;
+      for(i=0; i < size; i++) {
+	index[i] = i;
+      }
+      while(flipped) {
+	flipped = false;
+	for(i=0; i < size-1; i++) {
+	  a = (Double)values.elementAt(index[i]);
+	  b = (Double)values.elementAt(index[i+1]);
+	  if(a.doubleValue() > b.doubleValue()) {
+	    //	  if(a.compareTo(b) > 0) {  // jdk1.2
+	    temp = index[i];
+	    index[i] = index[i+1];
+	    index[i+1] = temp;
+	    flipped = true;
+	  }
+	}
+      }
+      Vector oldValues = values;
+      Vector oldAttr = attr;
+      values = new Vector(size);
+      attr = new Vector(size);
+      for(i=0; i < size; i++) {
+	values.addElement(oldValues.elementAt(index[i]));
+	attr.addElement(oldAttr.elementAt(index[i]));
+      }
+      fireTableChanged(new TableModelEvent(this));
+    }
+
+    public Object getValueAt(int row, int col) {
+      if(col == 0) {
+	return values.elementAt(row);
+      } else {
+	return attr.elementAt(row);
+      }
+    }
+
+    public void setValueAt(Object obj, int row, int col) {
+      if(col == 0) {
+	if(obj instanceof Double) {
+	  values.setElementAt(obj, row);
+	} else if(obj instanceof String) {
+	  values.setElementAt(new Double((String)obj), row);
+	}
+      } else {
+	attr.setElementAt(obj, row);
+      }
+      fireTableCellUpdated(row, col);
+    }
+
+    public int getRowCount() {
+      return values.size();
+    }
+
+    public int getColumnCount() {
+      return 2;
+    }
+
+    public String getColumnName(int col) {
+      return titles[col];
+    }
+
+    public boolean isCellEditable(int row, int col) {
+      return col == 0;
+    }
+
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ContourLineAttributeDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ContourLineAttributeDialog.java
new file mode 100755
index 0000000..967a2f9
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/ContourLineAttributeDialog.java
@@ -0,0 +1,923 @@
+/*
+ * $Id: ContourLineAttributeDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.StringTokenizer;
+
+import gov.noaa.pmel.sgt.ContourLineAttribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import javax.swing.border.*;
+import java.awt.event.*;
+
+/**
+ * Edits a <code>ContourLineAttribute</code>.  This dialog does not
+ * make a copy of the attribute so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties unless
+ * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching}
+ * has been turned on.
+ *
+ * <p> Example of <code>ContourLineAttributeDialog</code> use:
+ * <pre>
+ * public void editCLAttribute(ContourLineAttribute cla) {
+ *   ContourLineAttributeDialog clad = new ContourLineAttributeDialog();
+ *   clad.showDialog(cla);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class ContourLineAttributeDialog extends JDialog {
+  private ContourLineAttribute attr_;
+  private Font labelFont_;
+  private int result_;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  /** OK button was selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button was selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Constructor.
+   */
+  public ContourLineAttributeDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    {
+      String[] tempString = new String[7];
+      tempString[0] = "SOLID";
+      tempString[1] = "DASHED";
+      tempString[2] = "HEAVY";
+      tempString[3] = "HIGHLIGHT";
+      tempString[4] = "MARK";
+      tempString[5] = "MARK & SOLID";
+      tempString[6] = "STROKE";
+      for(int i=0; i < tempString.length; i++) {
+        lineStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "BUTT";
+      tempString[1] = "ROUND";
+      tempString[2] = "SQUARE";
+      for(int i=0; i < tempString.length; i++) {
+        capStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "MITER";
+      tempString[1] = "ROUND";
+      tempString[2] = "BEVEL";
+      for(int i=0; i < tempString.length; i++) {
+        miterStyleCBM.addElement(tempString[i]);
+      }
+    }
+    titledBorder1 = new TitledBorder(BorderFactory.createEtchedBorder(Color.white,new Color(142, 142, 142)),"Stroke Line Attributes");
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(new Dimension(587, 410));
+    setVisible(false);
+    strokePanel.setBorder(titledBorder1);
+    strokePanel.setLayout(gridBagLayout1);
+    dashArrayUseDefault.setActionCommand("dashArray");
+    JLabel110.setText(" Width:");
+    dashPhaseTextField.setColumns(10);
+    JLabel27.setText("Dash Phase:");
+    JLabel28.setText("Dash Array:");
+    widthTextField.setColumns(10);
+    arrayEditor.setActionCommand("...");
+    arrayEditor.setToolTipText("Edit dash array.");
+    dashArrayPanel.setLayout(new GridBagLayout());
+    dashPhaseUseDefault.setActionCommand("dashPhase");
+    widthUseDefault.setActionCommand("width");
+    jLabel1.setText("Cap Style:");
+    jLabel2.setText("Miter Style:");
+    jLabel3.setText("Miter Limit:");
+    miterLimitTextField.setColumns(10);
+    capStyleComboBox.setModel(capStyleCBM);
+    miterStyleComboBox.setModel(miterStyleCBM);
+    lineStyleComboBox.addActionListener(new ContourLineAttributeDialog_lineStyleComboBox_actionAdapter(this));
+    capStyleUseDefault.setActionCommand("capStyle");
+    miterStyleUseDefault.setActionCommand("miterStyle");
+    miterLimitUseDefault.setActionCommand("miterLimit");
+    getContentPane().add(TabbedPane, "Center");
+    linePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(linePanel, "linePanel");
+    labelPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(labelPanel, "labelPanel");
+    labelPanel.setBounds(2,27,476,260);
+    labelPanel.setVisible(false);
+    JLabel23.setText("Property");
+    labelPanel.add(JLabel23, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.SOUTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    JLabel23.setForeground(java.awt.Color.darkGray);
+    JPanel3.setLayout(new GridBagLayout());
+    labelPanel.add(JPanel3, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.SOUTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    JLabel24.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+    JLabel24.setText("Use");
+    JPanel3.add(JLabel24, new GridBagConstraints(0,0,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,0,0,0),0,0));
+    JLabel24.setForeground(java.awt.Color.darkGray);
+    JLabel25.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+    JLabel25.setText("Default");
+    JPanel3.add(JLabel25, new GridBagConstraints(0,1,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    JLabel25.setForeground(java.awt.Color.darkGray);
+    JLabel26.setText("Value");
+    labelPanel.add(JLabel26, new GridBagConstraints(2,0,1,1,0.0,0.0,
+    GridBagConstraints.SOUTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    JLabel26.setForeground(java.awt.Color.darkGray);
+    JPanel4.setBorder(etchedBorder1);
+    JPanel4.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(JPanel4, new GridBagConstraints(0,1,3,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(2,5,7,5),0,-12));
+    JLabel11.setText("Color:");
+    labelPanel.add(JLabel11, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelColorUseDefault.setActionCommand("labelColor");
+    labelPanel.add(labelColorUseDefault, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    textColorPanel.setBorder(etchedBorder1);
+    textColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(textColorPanel, new GridBagConstraints(2,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    JLabel15.setText("Font:");
+    labelPanel.add(JLabel15, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelFontUseDefault.setActionCommand("labelFont");
+    labelPanel.add(labelFontUseDefault, new GridBagConstraints(1,3,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    fontPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(fontPanel, new GridBagConstraints(2,3,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor);
+    JLabel16.setText("HeightP:");
+    labelPanel.add(JLabel16, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    heightPUseDefault.setActionCommand("heightP");
+    labelPanel.add(heightPUseDefault, new GridBagConstraints(1,4,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    heightTextField.setColumns(10);
+    labelPanel.add(heightTextField, new GridBagConstraints(2,4,1,1,1.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel6.setText("Text:");
+    labelPanel.add(JLabel6, new GridBagConstraints(0,6,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelPanel.add(textTextField, new GridBagConstraints(2,6,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,5,2,5),0,0));
+    JLabel22.setText("Format:");
+    labelPanel.add(JLabel22, new GridBagConstraints(0,7,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelFormatUseDefault.setActionCommand("labelFormat");
+    labelPanel.add(labelFormatUseDefault, new GridBagConstraints(1,7,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    labelFormatTextField.setColumns(10);
+    labelPanel.add(labelFormatTextField, new GridBagConstraints(2,7,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel17.setText("Auto Label:");
+    labelPanel.add(JLabel17, new GridBagConstraints(0,5,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelPanel.add(autoLabelCheckBox, new GridBagConstraints(2,5,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    JLabel7.setText("Enabled:");
+    labelPanel.add(JLabel7, new GridBagConstraints(0,8,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(5,5,0,5),0,0));
+    labelEnabledUseDefault.setActionCommand("labelEnabled");
+    labelPanel.add(labelEnabledUseDefault, new GridBagConstraints(1,8,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    labelEnabledCheckBox.setSelected(true);
+    labelPanel.add(labelEnabledCheckBox, new GridBagConstraints(2,8,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    TabbedPane.setSelectedComponent(linePanel);
+    TabbedPane.setSelectedIndex(0);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,384);
+    linePanel.setBounds(2,27,476,260);
+    linePanel.setVisible(false);
+    JLabel1.setText("Color:");
+    linePanel.add(JLabel1, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    colorUseDefault.setActionCommand("color");
+    linePanel.add(colorUseDefault, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    lineColorPanel.setBorder(etchedBorder1);
+    lineColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    linePanel.add(lineColorPanel, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel5.setText("Line Style:");
+    linePanel.add(JLabel5, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 28, 0, 5), 0, 0));
+    styleUseDefault.setActionCommand("style");
+    linePanel.add(styleUseDefault, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    lineStyleComboBox.setModel(lineStyleCBM);
+    linePanel.add(lineStyleComboBox, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel18.setText("Property");
+    linePanel.add(JLabel18, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.SOUTH, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    JLabel18.setForeground(java.awt.Color.darkGray);
+    JPanel1.setLayout(new GridBagLayout());
+    linePanel.add(JPanel1, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.SOUTH, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    JLabel19.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+    JLabel19.setText("Use");
+    JPanel1.add(JLabel19, new GridBagConstraints(0,0,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,0,0,0),0,0));
+    JLabel19.setForeground(java.awt.Color.darkGray);
+    JLabel20.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+    JLabel20.setText("Default");
+    JPanel1.add(JLabel20, new GridBagConstraints(0,1,1,1,1.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    JLabel20.setForeground(java.awt.Color.darkGray);
+    JLabel21.setText("Value");
+    linePanel.add(JLabel21, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.SOUTH, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    JLabel21.setForeground(java.awt.Color.darkGray);
+    JPanel2.setBorder(etchedBorder1);
+    JPanel2.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    linePanel.add(JPanel2, new GridBagConstraints(0, 1, 3, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 0, 7, 0), 0, -12));
+    linePanel.add(strokePanel, new GridBagConstraints(0, 5, 3, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(dashArrayUseDefault, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    strokePanel.add(JLabel110, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(dashPhaseTextField, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(JLabel27, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(JLabel28, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(widthTextField, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(dashArrayPanel, new GridBagConstraints(2, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 5, 5), 0, 0));
+    dashArrayPanel.add(dashArrayTextField, new GridBagConstraints(0,0,1,1,1.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    dashArrayPanel.add(arrayEditor, new GridBagConstraints(1,0,1,1,0.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.VERTICAL,new Insets(0,0,0,0),0,0));
+    strokePanel.add(dashPhaseUseDefault, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    strokePanel.add(widthUseDefault, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    strokePanel.add(jLabel1, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel2, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel3, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(capStyleUseDefault, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    strokePanel.add(miterStyleUseDefault, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    strokePanel.add(miterLimitUseDefault, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 15, 0, 10), 0, 0));
+    strokePanel.add(capStyleComboBox, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(miterStyleComboBox, new GridBagConstraints(2, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(miterLimitTextField, new GridBagConstraints(2, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    TabbedPane.setTitleAt(0,"Line");
+    TabbedPane.setTitleAt(1,"Label");
+    //$$ stringComboBoxModel1.move(24,384);
+    lineStyleComboBox.setSelectedIndex(0);
+    setTitle("ContourLineAttribute Properties");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    autoLabelCheckBox.addActionListener(lSymAction);
+    labelEnabledCheckBox.addActionListener(lSymAction);
+    arrayEditor.addActionListener(lSymAction);
+
+    //
+    // Use Default checkbox's have their own action listener
+    //
+    CBAction cbAction = new CBAction();
+    colorUseDefault.addActionListener(cbAction);
+    styleUseDefault.addActionListener(cbAction);
+    labelColorUseDefault.addActionListener(cbAction);
+    labelFontUseDefault.addActionListener(cbAction);
+    heightPUseDefault.addActionListener(cbAction);
+    labelFormatUseDefault.addActionListener(cbAction);
+    labelEnabledUseDefault.addActionListener(cbAction);
+    dashArrayUseDefault.addActionListener(cbAction);
+    dashPhaseUseDefault.addActionListener(cbAction);
+    widthUseDefault.addActionListener(cbAction);
+    capStyleUseDefault.addActionListener(cbAction);
+    miterStyleUseDefault.addActionListener(cbAction);
+    miterLimitUseDefault.addActionListener(cbAction);
+
+//    Insets pup = new Insets(0, 0, 0, 0);
+//    fontEditor.setMargin(pup);
+//    arrayEditor.setMargin(pup);
+  }
+  /** Used internally. */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public ContourLineAttributeDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public ContourLineAttributeDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible.
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == ContourLineAttributeDialog.this)
+  ContourLineAttributeDialog_WindowClosing(event);
+    }
+  }
+
+  void ContourLineAttributeDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel linePanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JCheckBox colorUseDefault = new javax.swing.JCheckBox();
+  ColorEntryPanel lineColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JCheckBox styleUseDefault = new javax.swing.JCheckBox();
+  javax.swing.JComboBox lineStyleComboBox = new javax.swing.JComboBox();
+  javax.swing.JLabel JLabel18 = new javax.swing.JLabel();
+  javax.swing.JPanel JPanel1 = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel19 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel20 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel21 = new javax.swing.JLabel();
+  javax.swing.JPanel JPanel2 = new javax.swing.JPanel();
+  javax.swing.JPanel labelPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel23 = new javax.swing.JLabel();
+  javax.swing.JPanel JPanel3 = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel24 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel25 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel26 = new javax.swing.JLabel();
+  javax.swing.JPanel JPanel4 = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel11 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelColorUseDefault = new javax.swing.JCheckBox();
+  ColorEntryPanel textColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel15 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelFontUseDefault = new javax.swing.JCheckBox();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel16 = new javax.swing.JLabel();
+  javax.swing.JCheckBox heightPUseDefault = new javax.swing.JCheckBox();
+  javax.swing.JTextField heightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JTextField textTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel22 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelFormatUseDefault = new javax.swing.JCheckBox();
+  javax.swing.JTextField labelFormatTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel17 = new javax.swing.JLabel();
+  javax.swing.JCheckBox autoLabelCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelEnabledUseDefault = new javax.swing.JCheckBox();
+  javax.swing.JCheckBox labelEnabledCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  DefaultComboBoxModel lineStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel capStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel miterStyleCBM = new DefaultComboBoxModel();
+  JPanel strokePanel = new JPanel();
+  TitledBorder titledBorder1;
+  GridBagLayout gridBagLayout1 = new GridBagLayout();
+  JCheckBox dashArrayUseDefault = new javax.swing.JCheckBox();
+  JLabel JLabel110 = new javax.swing.JLabel();
+  JTextField dashPhaseTextField = new javax.swing.JTextField();
+  JLabel JLabel27 = new javax.swing.JLabel();
+  JLabel JLabel28 = new javax.swing.JLabel();
+  JTextField dashArrayTextField = new javax.swing.JTextField();
+  JTextField widthTextField = new javax.swing.JTextField();
+  ThreeDotsButton arrayEditor = new ThreeDotsButton();
+  JPanel dashArrayPanel = new javax.swing.JPanel();
+  JCheckBox dashPhaseUseDefault = new javax.swing.JCheckBox();
+  JCheckBox widthUseDefault = new javax.swing.JCheckBox();
+  JLabel jLabel1 = new JLabel();
+  JLabel jLabel2 = new JLabel();
+  JLabel jLabel3 = new JLabel();
+  JCheckBox capStyleUseDefault = new JCheckBox();
+  JCheckBox miterStyleUseDefault = new JCheckBox();
+  JCheckBox miterLimitUseDefault = new JCheckBox();
+  JComboBox capStyleComboBox = new JComboBox();
+  JComboBox miterStyleComboBox = new JComboBox();
+  JTextField miterLimitTextField = new JTextField();
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+      else if (object == autoLabelCheckBox)
+        autoLabelCheckBox_actionPerformed(event);
+      else if (object == labelEnabledCheckBox)
+        labelEnabledCheckBox_actionPerformed(event);
+      else if (object == arrayEditor)
+        arrayEditor_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    updateContourLineAttribute();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    updateContourLineAttribute();
+  }
+
+  class CBAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if(object instanceof JCheckBox)
+  checkBox_actionPerformed(event);
+    }
+  }
+
+  void checkBox_actionPerformed(java.awt.event.ActionEvent event) {
+    String action = event.getActionCommand();
+    useDefault(action);
+  }
+
+  private void useDefault(String action) {
+    boolean enable;
+    boolean stroke = lineStyleComboBox.getSelectedIndex() == LineAttribute.STROKE;
+    if(action.equals("color")) {
+      enable = !colorUseDefault.isSelected();
+      lineColorPanel.setEnabled(enable);
+    } else if(action.equals("style")) {
+      lineStyleComboBox.setEnabled(!styleUseDefault.isSelected());
+    } else if(action.equals("width")) {
+      widthTextField.setEnabled(!widthUseDefault.isSelected() && stroke);
+    } else if(action.equals("dashArray")) {
+      enable = !dashArrayUseDefault.isSelected() && stroke;
+      dashArrayTextField.setEnabled(enable);
+      arrayEditor.setEnabled(enable);
+    } else if(action.equals("dashPhase")) {
+      dashPhaseTextField.setEnabled(!dashPhaseUseDefault.isSelected() && stroke);
+    } else if(action.equals("capStyle")) {
+      capStyleComboBox.setEnabled(!capStyleUseDefault.isSelected() && stroke);
+    } else if(action.equals("miterStyle")) {
+      miterStyleComboBox.setEnabled(!miterStyleUseDefault.isSelected() && stroke);
+    } else if(action.equals("miterLimit")) {
+      miterLimitTextField.setEnabled(!miterLimitUseDefault.isSelected() && stroke);
+    } else if(action.equals("labelColor")) {
+      enable = !labelColorUseDefault.isSelected();
+      textColorPanel.setEnabled(enable);
+    } else if(action.equals("labelFont")) {
+      enable = !labelFontUseDefault.isSelected();
+      fontLabel.setEnabled(enable);
+      fontEditor.setEnabled(enable);
+    } else if(action.equals("heightP")) {
+      heightTextField.setEnabled(!heightPUseDefault.isSelected());
+    } else if(action.equals("labelFormat")) {
+      labelFormatTextField.setEnabled(!labelFormatUseDefault.isSelected());
+    } else if(action.equals("labelEnabled")) {
+      labelEnabledCheckBox.setEnabled(!labelEnabledUseDefault.isSelected());
+    } else {
+      System.out.println("Action " + action + " not found.");
+    }
+  }
+
+  private void useDefaultAll() {
+    useDefault("color");
+    useDefault("style");
+    useDefault("width");
+    useDefault("dashArray");
+    useDefault("dashPhase");
+    useDefault("capStyle");
+    useDefault("miterStyle");
+    useDefault("miterLimit");
+    useDefault("labelColor");
+    useDefault("labelFont");
+    useDefault("heightP");
+    useDefault("labelFormat");
+    useDefault("labelEnabled");
+  }
+  /**
+   * Show the dialog and wait for a response
+   *
+   * @return result, either CANCE_RESPONSE or OK_RESPONSE
+   */
+  public int showDialog(ContourLineAttribute attr) {
+    setContourLineAttribute(attr);
+    result_ = CANCEL_RESPONSE;
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+  /**
+   * Set the <code>ContourLineAttribute</code> for editing.
+   */
+  public void setContourLineAttribute(ContourLineAttribute attr) {
+    attr_ = attr;
+    //
+    // Line attributes
+    //
+    // Color
+    //
+    lineColorPanel.setColor(attr_.getColor());
+    colorUseDefault.setSelected(!attr_.isColorOverridden());
+    //
+    // style
+    //
+    lineStyleComboBox.setSelectedIndex(attr_.getStyle());
+    styleUseDefault.setSelected(!attr_.isStyleOverridden());
+    strokePanelEnabled(attr_.getStyle() == LineAttribute.STROKE);
+    //
+    // width
+    //
+    widthTextField.setText(Float.toString(attr_.getWidth()));
+    widthUseDefault.setSelected(!attr_.isWidthOverridden());
+    //
+    // dash Array
+    //
+    float[] da = attr_.getDashArray();
+    dashArrayTextField.setText(dashArrayString(da));
+    dashArrayUseDefault.setSelected(!attr_.isDashArrayOverridden());
+    //
+    // dash phase
+    //
+    dashPhaseTextField.setText(Float.toString(attr_.getDashPhase()));
+    dashPhaseUseDefault.setSelected(!attr_.isDashPhaseOverridden());
+    //
+    // cap style
+    //
+    capStyleComboBox.setSelectedIndex(attr_.getCapStyle());
+    capStyleUseDefault.setSelected(!attr_.isCapStyleOverridden());
+    //
+    // miter style
+    //
+    miterStyleComboBox.setSelectedIndex(attr_.getMiterStyle());
+    miterStyleUseDefault.setSelected(!attr_.isMiterStyleOverridden());
+    //
+    // miter limit
+    //
+    miterLimitTextField.setText(Float.toString(attr_.getMiterLimit()));
+    miterLimitUseDefault.setSelected(!attr_.isMiterLimitOverridden());
+    //
+    // Label attributes
+    //
+    // color
+    //
+    textColorPanel.setColor(attr_.getLabelColor());
+    labelColorUseDefault.setSelected(!attr_.isLabelColorOverridden());
+    //
+    // font
+    //
+    labelFont_ = attr_.getLabelFont();
+    if(labelFont_ == null) {
+      fontLabel.setText("Default Font");
+    } else {
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+    labelFontUseDefault.setSelected(!attr_.isLabelFontOverridden());
+    //
+    // heightP
+    //
+    heightTextField.setText(Double.toString(attr_.getLabelHeightP()));
+    heightPUseDefault.setSelected(!attr_.isLabelHeightPOverridden());
+    //
+    // autoLabel
+    //
+    autoLabelCheckBox.setSelected(attr_.isAutoLabel());
+    autoLabel();
+    //
+    // text
+    //
+    textTextField.setText(attr_.getLabelText());
+    //
+    // label format
+    labelFormatTextField.setText(attr_.getLabelFormat());
+    labelFormatUseDefault.setSelected(!attr_.isLabelFormatOverridden());
+    //
+    // enabled
+    //
+    labelEnabledCheckBox.setSelected(attr_.isLabelEnabled());
+    labelEnabledUseDefault.setSelected(!attr_.isLabelEnabledOverridden());
+    labelEnabled();
+    //
+    useDefaultAll();
+  }
+
+  private void autoLabel() {
+    textTextField.setEnabled(!autoLabelCheckBox.isSelected());
+  }
+
+  private void labelEnabled() {
+    boolean enabled = labelEnabledCheckBox.isSelected();
+    textTextField.setEnabled(enabled);
+    textColorPanel.setEnabled(enabled);
+    fontLabel.setEnabled(enabled);
+    labelFontUseDefault.setEnabled(enabled);
+    fontEditor.setEnabled(enabled);
+    heightTextField.setEnabled(enabled);
+    heightPUseDefault.setEnabled(enabled);
+    autoLabelCheckBox.setEnabled(enabled);
+    labelFormatTextField.setEnabled(enabled);
+    labelFormatUseDefault.setEnabled(enabled);
+    //
+    useDefaultAll();
+  }
+
+  private String dashArrayString(float[] da) {
+    if(da == null) {
+      return "null";
+    }
+    StringBuffer sbuf = new StringBuffer("{");
+    for(int i=0; i < da.length; i++) {
+      sbuf.append(Float.toString(da[i]) + ", ");
+    }
+    sbuf.setLength(sbuf.length()-2);
+    sbuf.append("}");
+    return sbuf.toString();
+  }
+
+  private float[] dashArray() {
+    String arrayString = dashArrayTextField.getText();
+    int start = arrayString.indexOf("{");
+    int stop = arrayString.indexOf("}");
+    String sub = arrayString.substring(start+1,stop);
+    //
+    // parse array
+    //
+    StringTokenizer token = new StringTokenizer(sub, ",");
+    int index = 0;
+    float[] array = new float[token.countTokens()];
+    while(token.hasMoreTokens()) {
+      array[index] = new Float(token.nextToken()).floatValue();
+      index++;
+    }
+    return array;
+  }
+
+  void updateContourLineAttribute() {
+    //
+    // Line attributes
+    //
+    // Color
+    //
+    attr_.setColor(lineColorPanel.getColor());
+    attr_.setColorOverridden(!colorUseDefault.isSelected());
+    //
+    // style
+    //
+    attr_.setStyle(lineStyleComboBox.getSelectedIndex());
+    attr_.setStyleOverridden(!styleUseDefault.isSelected());
+    //
+    // width
+    //
+    attr_.setWidth(new Float(widthTextField.getText()).floatValue());
+    attr_.setWidthOverridden(!widthUseDefault.isSelected());
+    //
+    // dash array
+    //
+    attr_.setDashArray(dashArray());
+    attr_.setDashArrayOverridden(!dashArrayUseDefault.isSelected());
+    //
+    // dash phase
+    //
+    attr_.setDashPhase(new Float(dashPhaseTextField.getText()).floatValue());
+    attr_.setDashPhaseOverridden(!dashPhaseUseDefault.isSelected());
+    //
+    // cap style
+    //
+    attr_.setCapStyle(capStyleComboBox.getSelectedIndex());
+    attr_.setCapStyleOverridden(!capStyleUseDefault.isSelected());
+    //
+    // miter style
+    //
+    attr_.setMiterStyle(miterStyleComboBox.getSelectedIndex());
+    attr_.setMiterStyleOverridden(!miterStyleUseDefault.isSelected());
+    //
+    // miter limit
+    //
+    attr_.setMiterLimit(new Float(miterLimitTextField.getText()).floatValue());
+    attr_.setMiterLimitOverridden(!miterLimitUseDefault.isSelected());
+    //
+    // Label attributes
+    //
+    // color
+    //
+    attr_.setLabelColor(textColorPanel.getColor());
+    attr_.setLabelColorOverridden(!labelColorUseDefault.isSelected());
+    //
+    // font
+    //
+    if(labelFont_ != null) attr_.setLabelFont(labelFont_);
+    attr_.setLabelFontOverridden(!labelFontUseDefault.isSelected());
+    //
+    // heightP
+    //
+    attr_.setLabelHeightP(new Double(heightTextField.getText()).doubleValue());
+    attr_.setLabelHeightPOverridden(!heightPUseDefault.isSelected());
+    //
+    // autoLabel
+    //
+    attr_.setAutoLabel(autoLabelCheckBox.isSelected());
+    //
+    // text
+    //
+    attr_.setLabelText(textTextField.getText());
+    //
+    // label format
+    //
+    attr_.setLabelFormat(labelFormatTextField.getText());
+    attr_.setLabelFormatOverridden(!labelFormatUseDefault.isSelected());
+    //
+    // enabled
+    //
+    attr_.setLabelEnabled(labelEnabledCheckBox.isSelected());
+    attr_.setLabelEnabledOverridden(!labelEnabledUseDefault.isSelected());
+  }
+  /**
+   * Get the modified attribute
+   */
+  public ContourLineAttribute getContourLineAttribute() {
+    return attr_;
+  }
+  /**
+   * Dialog test.
+   */
+  public static void main(String[] args) {
+    ContourLineAttribute attr = new ContourLineAttribute();
+    ContourLineAttributeDialog la = new ContourLineAttributeDialog();
+    la.setContourLineAttribute(attr);
+    la.setTitle("Test ContourLineAttribute Dialog");
+    la.setVisible(true);
+  }
+
+  void arrayEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    ArrayEditDialog aed = new ArrayEditDialog();
+    Point loc = arrayEditor.getLocationOnScreen();
+    aed.setLocation(loc.x, loc.y);
+    aed.setArray(dashArray());
+    int result = aed.showDialog();
+    if(result == ArrayEditDialog.OK_RESPONSE) {
+      dashArrayTextField.setText(dashArrayString(aed.getFloatArray()));
+    }
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+
+  void autoLabelCheckBox_actionPerformed(java.awt.event.ActionEvent event) {
+    autoLabel();
+  }
+
+  void labelEnabledCheckBox_actionPerformed(java.awt.event.ActionEvent event) {
+    labelEnabled();
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+
+  void lineStyleComboBox_actionPerformed(ActionEvent e) {
+    int index = lineStyleComboBox.getSelectedIndex();
+    strokePanelEnabled(index == LineAttribute.STROKE);
+    if(index == LineAttribute.MARK || index == LineAttribute.MARK_LINE) {
+      JOptionPane.showMessageDialog(this,
+      "Line stytle MARK or MARK & SOLID not valid for ContourLine",
+      "Illegal Line Style", JOptionPane.ERROR_MESSAGE);
+      lineStyleComboBox.setSelectedIndex(attr_.getStyle());
+    }
+  }
+
+  public void strokePanelEnabled(boolean enabled) {
+    widthUseDefault.setEnabled(enabled);
+    dashArrayUseDefault.setEnabled(enabled);
+    dashArrayUseDefault.setEnabled(enabled);
+    dashPhaseUseDefault.setEnabled(enabled);
+    capStyleUseDefault.setEnabled(enabled);
+    miterStyleUseDefault.setEnabled(enabled);
+    miterLimitUseDefault.setEnabled(enabled);
+    useDefault("width");
+    useDefault("dashArray");
+    useDefault("dashPhase");
+    useDefault("capStyle");
+    useDefault("miterStyle");
+    useDefault("miterLimit");
+  }
+}
+
+class ContourLineAttributeDialog_lineStyleComboBox_actionAdapter implements java.awt.event.ActionListener {
+  ContourLineAttributeDialog adaptee;
+
+  ContourLineAttributeDialog_lineStyleComboBox_actionAdapter(ContourLineAttributeDialog adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.lineStyleComboBox_actionPerformed(e);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/DefaultContourLineAttributeDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/DefaultContourLineAttributeDialog.java
new file mode 100755
index 0000000..1614a3a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/DefaultContourLineAttributeDialog.java
@@ -0,0 +1,655 @@
+/*
+ * $Id: DefaultContourLineAttributeDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.StringTokenizer;
+
+import gov.noaa.pmel.sgt.DefaultContourLineAttribute;
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import javax.swing.border.*;
+import java.awt.event.*;
+
+/**
+ * Edits a <code>DefaultContourLineAttribute</code>.  This dialog does not
+ * make a copy of the attribute so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties unless
+ * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching}
+ * has been turned on.
+ *
+ * <p> Example of <code>DefaultContourLineAttributeDialog</code> use:
+ * <pre>
+ * public void editCLAttribute(DefaultContourLineAttribute cla) {
+ *   DefaultContourLineAttributeDialog clad =
+ *                        new DefaultContourLineAttributeDialog();
+ *   clad.showDialog(cla);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class DefaultContourLineAttributeDialog extends JDialog {
+  private DefaultContourLineAttribute attr_;
+  private Font labelFont_;
+  private int result_;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  /** OK button was selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button was selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Construtor.
+   */
+  public DefaultContourLineAttributeDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    {
+      String[] tempString = new String[7];
+      tempString[0] = "SOLID";
+      tempString[1] = "DASHED";
+      tempString[2] = "HEAVY";
+      tempString[3] = "HIGHLIGHT";
+      tempString[4] = "MARK";
+      tempString[5] = "MARK & SOLID";
+      tempString[6] = "STROKE";
+      for(int i=0; i < tempString.length; i++) {
+        lineStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "BUTT";
+      tempString[1] = "ROUND";
+      tempString[2] = "SQUARE";
+      for(int i=0; i < tempString.length; i++) {
+        capStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "MITER";
+      tempString[1] = "ROUND";
+      tempString[2] = "BEVEL";
+      for(int i=0; i < tempString.length; i++) {
+        miterStyleCBM.addElement(tempString[i]);
+      }
+    }
+    titledBorder1 = new TitledBorder(BorderFactory.createEtchedBorder(Color.white,new Color(142, 142, 142)),"Stroke Line Attributes");
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(new Dimension(526, 362));
+    setVisible(false);
+    miterLimitTextField.setColumns(10);
+    dashArrayPanel.setLayout(new GridBagLayout());
+    strokePanel.setLayout(gridBagLayout1);
+    arrayEditor.setActionCommand("...");
+    arrayEditor.setToolTipText("Edit dash array.");
+    JLabel28.setText("Dash Array:");
+    JLabel27.setText("Dash Phase:");
+    dashPhaseTextField.setColumns(10);
+    jLabel3.setText("Miter Limit:");
+    jLabel2.setText("Miter Style:");
+    jLabel1.setText("Cap Style:");
+    JLabel110.setText(" Width:");
+    widthTextField.setColumns(10);
+    strokePanel.setBorder(titledBorder1);
+    lineStyleComboBox.addActionListener(new DefaultContourLineAttributeDialog_lineStyleComboBox_actionAdapter(this));
+    capStyleComboBox.setModel(capStyleCBM);
+    miterStyleComboBox.setModel(miterStyleCBM);
+    getContentPane().add(TabbedPane, "Center");
+    linePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(linePanel, "linePanel");
+    JLabel1.setText("Color:");
+    linePanel.add(JLabel1, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    lineColorPanel.setBorder(etchedBorder1);
+    lineColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    linePanel.add(lineColorPanel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel5.setText("Line Style:");
+    linePanel.add(JLabel5, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 25, 0, 5), 0, 0));
+    lineStyleComboBox.setModel(lineStyleCBM);
+    linePanel.add(lineStyleComboBox, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    linePanel.add(strokePanel, new GridBagConstraints(0, 2, 2, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+    strokePanel.add(JLabel110, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(dashPhaseTextField, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(JLabel27, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(JLabel28, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(widthTextField, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(dashArrayPanel, new GridBagConstraints(2, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 5, 5), 0, 0));
+    dashArrayPanel.add(dashArrayTextField, new GridBagConstraints(0,0,1,1,1.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    dashArrayPanel.add(arrayEditor, new GridBagConstraints(1,0,1,1,0.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.VERTICAL,new Insets(0,0,0,0),0,0));
+    strokePanel.add(jLabel1, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel2, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel3, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(capStyleComboBox, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(miterStyleComboBox, new GridBagConstraints(2, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(miterLimitTextField, new GridBagConstraints(2, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    labelPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(labelPanel, "labelPanel");
+    labelPanel.setBounds(2,27,425,258);
+    labelPanel.setVisible(false);
+    JLabel7.setText("Enabled:");
+    labelPanel.add(JLabel7, new GridBagConstraints(0,6,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelEnabledCheckBox.setSelected(true);
+    labelPanel.add(labelEnabledCheckBox, new GridBagConstraints(1,6,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    JLabel11.setText("Color:");
+    labelPanel.add(JLabel11, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    textColorPanel.setBorder(etchedBorder1);
+    textColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(textColorPanel, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    JLabel15.setText("Font:");
+    labelPanel.add(JLabel15, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(fontPanel, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor);
+    JLabel16.setText("HeightP:");
+    labelPanel.add(JLabel16, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    heightTextField.setColumns(10);
+    labelPanel.add(heightTextField, new GridBagConstraints(1,3,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel6.setText("Significant Digits:");
+    labelPanel.add(JLabel6, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    sigDigitsTextField.setColumns(10);
+    labelPanel.add(sigDigitsTextField, new GridBagConstraints(1,4,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel17.setText("Format:");
+    labelPanel.add(JLabel17, new GridBagConstraints(0,5,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelFormatTextField.setColumns(10);
+    labelPanel.add(labelFormatTextField, new GridBagConstraints(1,5,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    TabbedPane.setSelectedComponent(linePanel);
+    TabbedPane.setSelectedIndex(0);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,324);
+    linePanel.setBounds(2,27,425,258);
+    linePanel.setVisible(false);
+    TabbedPane.setTitleAt(0,"Line");
+    TabbedPane.setTitleAt(1,"Label");
+
+    lineStyleComboBox.setSelectedIndex(0);
+    setTitle("DefaultContourLineAttribute Properties");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    labelEnabledCheckBox.addActionListener(lSymAction);
+    arrayEditor.addActionListener(lSymAction);
+
+//    Insets pup = new Insets(0, 0, 0, 0);
+//    fontEditor.setMargin(pup);
+//    arrayEditor.setMargin(pup);
+
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public DefaultContourLineAttributeDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor
+   */
+  public DefaultContourLineAttributeDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == DefaultContourLineAttributeDialog.this)
+  DefaultContourLineAttributeDialog_WindowClosing(event);
+    }
+  }
+
+  void DefaultContourLineAttributeDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel linePanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  ColorEntryPanel lineColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JComboBox lineStyleComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel labelPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelEnabledCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel11 = new javax.swing.JLabel();
+  ColorEntryPanel textColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel15 = new javax.swing.JLabel();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel16 = new javax.swing.JLabel();
+  javax.swing.JTextField heightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JTextField sigDigitsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel17 = new javax.swing.JLabel();
+  javax.swing.JTextField labelFormatTextField = new javax.swing.JTextField();
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  DefaultComboBoxModel lineStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel capStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel miterStyleCBM = new DefaultComboBoxModel();
+  GridBagLayout gridBagLayout1 = new GridBagLayout();
+  JTextField miterLimitTextField = new JTextField();
+  JPanel dashArrayPanel = new javax.swing.JPanel();
+  JPanel strokePanel = new JPanel();
+  ThreeDotsButton arrayEditor = new ThreeDotsButton();
+  JLabel JLabel28 = new javax.swing.JLabel();
+  JLabel JLabel27 = new javax.swing.JLabel();
+  JTextField dashArrayTextField = new javax.swing.JTextField();
+  JTextField dashPhaseTextField = new javax.swing.JTextField();
+  JComboBox miterStyleComboBox = new JComboBox();
+  JLabel jLabel3 = new JLabel();
+  JLabel jLabel2 = new JLabel();
+  JLabel jLabel1 = new JLabel();
+  JLabel JLabel110 = new javax.swing.JLabel();
+  JComboBox capStyleComboBox = new JComboBox();
+  JTextField widthTextField = new javax.swing.JTextField();
+  TitledBorder titledBorder1;
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == arrayEditor)
+        arrayEditor_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+      else if (object == labelEnabledCheckBox)
+        labelEnabledCheckBox_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    updateDefaultContourLineAttribute();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    updateDefaultContourLineAttribute();
+  }
+  /**
+   * Show the dialog and wait for a response
+   */
+  public int showDialog(DefaultContourLineAttribute attr) {
+    setDefaultContourLineAttribute(attr);
+    result_ = CANCEL_RESPONSE;
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+  /**
+   * Set the <code>DefaultContourLineAttribute</code> to be edited.
+   */
+  public void setDefaultContourLineAttribute(DefaultContourLineAttribute attr) {
+    attr_ = attr;
+    attr_.setContourLineAttribute(null);
+    //
+    // Line attributes
+    //
+    // Color
+    //
+    lineColorPanel.setColor(attr_.getColor());
+    //
+    // style
+    //
+    lineStyleComboBox.setSelectedIndex(attr_.getStyle());
+    //
+    // width
+    //
+    widthTextField.setText(Float.toString(attr_.getWidth()));
+    //
+    // dash Array
+    //
+    float[] da = attr_.getDashArray();
+    dashArrayTextField.setText(dashArrayString(da));
+    //
+    // dash phase
+    //
+    dashPhaseTextField.setText(Float.toString(attr_.getDashPhase()));
+    //
+    // cap style
+    //
+    capStyleComboBox.setSelectedIndex(attr_.getCapStyle());
+    //
+    // miter style
+    //
+    miterStyleComboBox.setSelectedIndex(attr_.getMiterStyle());
+    //
+    // miter limit
+    //
+    miterLimitTextField.setText(Float.toString(attr_.getMiterLimit()));
+    //
+    // Label attributes
+    //
+    // color
+    //
+    textColorPanel.setColor(attr_.getLabelColor());
+    //
+    // font
+    //
+    labelFont_ = attr_.getLabelFont();
+    if(labelFont_ == null) {
+      fontLabel.setText("Default Font");
+    } else {
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+    //
+    // heightP
+    //
+    heightTextField.setText(Double.toString(attr_.getLabelHeightP()));
+    //
+    // Significant Digits
+    //
+    sigDigitsTextField.setText(Integer.toString(attr_.getSignificantDigits()));
+    //
+    // format
+    //
+    labelFormatTextField.setText(attr_.getLabelFormat());
+    //
+    // enabled
+    //
+    labelEnabledCheckBox.setSelected(attr_.isLabelEnabled());
+    labelEnabled();
+  }
+
+  private void labelEnabled() {
+    boolean enabled = labelEnabledCheckBox.isSelected();
+    textColorPanel.setEnabled(enabled);
+    fontLabel.setEnabled(enabled);
+    heightTextField.setEnabled(enabled);
+    labelFormatTextField.setEnabled(enabled);
+    sigDigitsTextField.setEnabled(enabled);
+  }
+
+  private String dashArrayString(float[] da) {
+    if(da == null) {
+      return "null";
+    }
+    StringBuffer sbuf = new StringBuffer("{");
+    for(int i=0; i < da.length; i++) {
+      sbuf.append(Float.toString(da[i]) + ", ");
+    }
+    sbuf.setLength(sbuf.length()-2);
+    sbuf.append("}");
+    return sbuf.toString();
+  }
+
+  private float[] dashArray() {
+    String arrayString = dashArrayTextField.getText();
+    int start = arrayString.indexOf("{");
+    int stop = arrayString.indexOf("}");
+    String sub = arrayString.substring(start+1,stop);
+    //
+    // parse array
+    //
+    StringTokenizer token = new StringTokenizer(sub, ",");
+    int index = 0;
+    float[] array = new float[token.countTokens()];
+    while(token.hasMoreTokens()) {
+      array[index] = new Float(token.nextToken()).floatValue();
+      index++;
+    }
+    return array;
+  }
+
+  void updateDefaultContourLineAttribute() {
+    //
+    // Line attributes
+    //
+    // Color
+    //
+    attr_.setColor(lineColorPanel.getColor());
+    //
+    // style
+    //
+    attr_.setStyle(lineStyleComboBox.getSelectedIndex());
+    //
+    // width
+    //
+    attr_.setWidth(new Float(widthTextField.getText()).floatValue());
+    //
+    // dash array
+    //
+    attr_.setDashArray(dashArray());
+    //
+    // dash phase
+    //
+    attr_.setDashPhase(new Float(dashPhaseTextField.getText()).floatValue());
+    //
+    // cap style
+    //
+    attr_.setCapStyle(capStyleComboBox.getSelectedIndex());
+    //
+    // miter style
+    //
+    attr_.setMiterStyle(miterStyleComboBox.getSelectedIndex());
+    //
+    // miter limit
+    //
+    attr_.setMiterLimit(new Float(miterLimitTextField.getText()).floatValue());
+    //
+    // Label attributes
+    //
+    // enabled
+    //
+    attr_.setLabelEnabled(labelEnabledCheckBox.isSelected());
+    //
+    // color
+    //
+    attr_.setLabelColor(textColorPanel.getColor());
+    //
+    // font
+    //
+    if(labelFont_ != null) attr_.setLabelFont(labelFont_);
+    //
+    // heightP
+    //
+    attr_.setLabelHeightP(new Double(heightTextField.getText()).doubleValue());
+    //
+    // label format
+    //
+    attr_.setLabelFormat(labelFormatTextField.getText());
+    //
+    // significant digits
+    //
+    attr_.setSignificantDigits(Integer.valueOf(sigDigitsTextField.getText()).intValue());
+  }
+  /**
+   * Get the modified attribute.
+   */
+  public DefaultContourLineAttribute getDefaultContourLineAttribute() {
+    return attr_;
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    DefaultContourLineAttribute attr = new DefaultContourLineAttribute();
+    DefaultContourLineAttributeDialog la = new DefaultContourLineAttributeDialog();
+    la.setDefaultContourLineAttribute(attr);
+    la.setTitle("Test DefaultContourLineAttribute Dialog");
+    la.setVisible(true);
+  }
+
+  void arrayEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    ArrayEditDialog aed = new ArrayEditDialog();
+    Point loc = arrayEditor.getLocationOnScreen();
+    aed.setLocation(loc.x, loc.y);
+    aed.setArray(dashArray());
+    int result = aed.showDialog();
+    if(result == ArrayEditDialog.OK_RESPONSE) {
+      dashArrayTextField.setText(dashArrayString(aed.getFloatArray()));
+    }
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  void labelEnabledCheckBox_actionPerformed(java.awt.event.ActionEvent event) {
+    labelEnabled();
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+
+  void lineStyleComboBox_actionPerformed(ActionEvent e) {
+    int index = lineStyleComboBox.getSelectedIndex();
+    strokePanelEnabled(index == LineAttribute.STROKE);
+    if(index == LineAttribute.MARK || index == LineAttribute.MARK_LINE) {
+      JOptionPane.showMessageDialog(this,
+      "Line stytle MARK or MARK & SOLID not valid for ContourLine",
+      "Illegal Line Style", JOptionPane.ERROR_MESSAGE);
+      lineStyleComboBox.setSelectedIndex(attr_.getStyle());
+    }
+  }
+
+  public void strokePanelEnabled(boolean enabled) {
+    widthTextField.setEnabled(enabled);
+    dashArrayTextField.setEnabled(enabled);
+    arrayEditor.setEnabled(enabled);
+    dashPhaseTextField.setEnabled(enabled);
+    capStyleComboBox.setEnabled(enabled);
+    miterStyleComboBox.setEnabled(enabled);
+    miterLimitTextField.setEnabled(enabled);
+  }
+}
+
+class DefaultContourLineAttributeDialog_lineStyleComboBox_actionAdapter implements java.awt.event.ActionListener {
+  DefaultContourLineAttributeDialog adaptee;
+
+  DefaultContourLineAttributeDialog_lineStyleComboBox_actionAdapter(DefaultContourLineAttributeDialog adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.lineStyleComboBox_actionPerformed(e);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/FontDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/FontDialog.java
new file mode 100755
index 0000000..5a0c9d9
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/FontDialog.java
@@ -0,0 +1,283 @@
+/*
+ * $Id: FontDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Edits a <code>Font</code> object.  This dialog does not
+ * make a copy of the object so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new <code>Font</code>
+ * properties unless
+ * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching}
+ * has been turned on.
+ *
+ * <p> Example of <code>FontDialog</code> use:
+ * <pre>
+ * public void editFont(Font font) {
+ *   FontDialog fd = new FontDialog();
+ *   fd.showDialog(font);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class FontDialog extends JDialog {
+  private int result_;
+  private Font font_;
+  private String[] fontNames_;
+  private int[] styles_ = {Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD|Font.ITALIC};
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  /** OK button was selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button was selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Constructor.
+   */
+  public FontDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    //{{INIT_CONTROLS
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(450,141);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    italicButton.setMnemonic('0');
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(okButton);
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,228);
+    mainPanel.setLayout(new GridBagLayout());
+    getContentPane().add(mainPanel, "Center");
+    mainPanel.add(fontComboBox, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(5,5,5,1),0,0));
+    boldButton.setText("Bold");
+    mainPanel.add(boldButton,  new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 1, 5, 2), 0, 0));
+    italicButton.setText("Italic");
+    mainPanel.add(italicButton,  new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 2, 5, 5), 0, 0));
+    italicButton.setFont(new Font("Dialog", Font.BOLD|Font.ITALIC, 12));
+    fontLabel.setText("Font Name in font.");
+    mainPanel.add(fontLabel, new GridBagConstraints(0,0,3,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0));
+    this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+    setTitle("Select a Mark");
+    //}}
+
+    //{{REGISTER_LISTENERS
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    fontComboBox.addActionListener(lSymAction);
+    boldButton.addActionListener(lSymAction);
+    italicButton.addActionListener(lSymAction);
+    //}}
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public FontDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public FontDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == FontDialog.this)
+        FontDialog_WindowClosing(event);
+    }
+  }
+
+  void FontDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  //{{DECLARE_CONTROLS
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+  javax.swing.JComboBox fontComboBox = new javax.swing.JComboBox();
+  javax.swing.JToggleButton boldButton = new javax.swing.JToggleButton();
+  javax.swing.JToggleButton italicButton = new javax.swing.JToggleButton();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  //}}
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == fontComboBox)
+        fontComboBox_actionPerformed(event);
+      else if (object == boldButton)
+        boldButton_actionPerformed(event);
+      else if (object == italicButton)
+        italicButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    this.setVisible(false);
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    FontDialog la = new FontDialog();
+    la.setFont(null);
+    la.setTitle("Test Font Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Show the dialog and wait for a response
+   *
+   * @param font the font
+   * @return result, either CANCEL_RESPONSE or OK_RESPONSE
+   */
+  public int showDialog(Font font) {
+//    fontNames_ = Toolkit.getDefaultToolkit().getFontList();
+    fontNames_ = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+    for(int i=0; i < fontNames_.length; i++) {
+      fontComboBox.addItem(fontNames_[i]);
+    }
+    setDefaultFont(font);
+    result_ = CANCEL_RESPONSE;
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+  /**
+   * Set the font to be edited
+   */
+  public void setDefaultFont(Font font) {
+    int index=0;
+    font_ = font;
+    if(font_ == null) {
+      font_ = super.getFont();
+    }
+    //
+    // setup font combo box
+    //
+    for(int i=0; i < fontNames_.length; i++) {
+      if(font_.getName().equals(fontNames_[i])) {
+        index = i;
+        break;
+      }
+    }
+    boldButton.setSelected(font_.isBold());
+    italicButton.setSelected(font_.isItalic());
+    fontComboBox.setSelectedIndex(index);
+    fontLabel.setText(fontString());
+    fontLabel.setFont(font_);
+  }
+  /**
+   * Create a string representation of the <code>Font</code>
+   */
+  public String fontString() {
+    int style = (boldButton.isSelected()?1:0) + (italicButton.isSelected()?2:0);
+    return font_.getName() + " " + styleNames_[style];
+  }
+  /**
+   * Get the edited font.
+   */
+  public Font getFont() {
+    return font_;
+  }
+
+  void fontComboBox_actionPerformed(java.awt.event.ActionEvent event) {
+    updateFont();
+  }
+
+  void boldButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateFont();
+  }
+
+  void italicButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateFont();
+  }
+
+  void updateFont() {
+    int style = (boldButton.isSelected()?1:0) + (italicButton.isSelected()?2:0);
+    Font font = new Font(fontNames_[fontComboBox.getSelectedIndex()], styles_[style], 12);
+    font_ = font;
+    fontLabel.setText(fontString());
+    fontLabel.setFont(font_);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GeoDateDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GeoDateDialog.java
new file mode 100755
index 0000000..3188709
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GeoDateDialog.java
@@ -0,0 +1,1243 @@
+/*
+ * $Id: GeoDateDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.util.GeoDate;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.border.*;
+import javax.swing.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.text.*;
+import javax.swing.event.ListSelectionListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyChangeListener;
+
+/**
+ * <code>GeoDateDialog</code> is a calendar, plus optionally, time, chooser 
+ * that produces a date.  It allows the invoker to set the 
+ * allowable range of dates by specifying an earliest and latest 
+ * allowable date.  The user can select a date to within 
+ * 5 minutes.  If the hour and minutes aren't needed, a flag 
+ * allows the exclusion of the display of these fields.  
+ *
+ * @author Chris Windsor
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class GeoDateDialog extends JDialog
+        implements ItemListener,
+                  PropertyChangeListener,
+                   ActionListener {
+  // Get-able, Set-able variables
+  private GeoDate initialDate = new GeoDate();
+  private GeoDate earliestDateAllowed = new GeoDate();
+  private GeoDate latestDateAllowed = new GeoDate();
+  private boolean earliestCheckingEnabled = false;
+  private boolean latestCheckingEnabled = false;
+  private Font regularFont, boldFont;
+  private Color panelBackground, calBackground, selectedButnBackground;
+
+  private final static String[] months = {"Jan","Feb","Mar",
+                                          "Apr","May","Jun",
+                                          "Jul","Aug","Sep",
+                                          "Oct", "Nov","Dec"};
+  private final static String[] daysOfMonth = {" 1"," 2"," 3"," 4"," 5",
+                                               " 6"," 7"," 8"," 9","10",
+                                               "11","12","13","14","15",
+                                               "16","17","18","19","20",
+                                               "21","22","23","24","25",
+                                               "26","27","28","29","30",
+                                               "31"};
+  private final static String[] hours = {"0","1","2","3","4","5","6","7",
+                                         "8","9","10","11","12","13","14",
+                                         "15","16","17","18","19","20","21",
+                                         "22","23"};
+  private final static String[] minutes =  {"0","5","10","15","20","25",
+                                            "30","35","40","45","50","55"};
+  private final static int numWeeks = 6;
+
+  private GregorianCalendar cal;
+  private SimpleDateFormat dateFormatter;
+  private SimpleDateFormat sdf;
+  private SimpleDateFormat tsdf = new SimpleDateFormat("dd MMM yyyy ");
+  private static TimeZone tz = TimeZone.getTimeZone("GMT");
+
+  private int result_;
+  public static int OK_RESPONSE = 1;
+  public static int CANCEL_RESPONSE = 2;
+
+  private JPanel mainPanel_;
+  private JPanel calPanel, okPanel, selectionPanel;
+  private javax.swing.Box box, theBox, timeBox, monthYearBox, okBox, labelBox,
+    hrMinBox;
+  private JButton subYearButn, subMonthButn, addMonthButn, addYearButn,
+    addHourButn, subHourButn, addMinButn, subMinButn;
+  private JButton cancelButn, okButn;
+  private JToggleButton calButtons[ ];
+  private JLabel yearLabel, hourLabel, minLabel, hourMinLabel;
+  private JLabel selectionLabel;
+  private Choice monthChoice, yearChoice;
+  private JComboBox monthList, minList;
+  private JTextField hourText, yearText;
+  private Component caller;
+
+  private ButtonGroup calButtonGroup;
+   
+  private GeoDate liquidDate;
+  private int lastDaySel, lastButnSel = 1;
+  private int xloc, yloc;
+  private String title;
+  private boolean hideTime;
+  //  private JFrame aJFrame = null;
+  static private CompoundBorder cp = new CompoundBorder( 
+                        new BevelBorder( BevelBorder.RAISED ),
+                        new EmptyBorder( 2,2,2,2));
+
+  public static final int DATE = Calendar.DATE;
+  public static final int YEAR = Calendar.YEAR;
+  public static final int MONTH = Calendar.MONTH;
+  public static final int MINUTE = Calendar.MINUTE;
+  public static final int HOUR_OF_DAY = Calendar.HOUR_OF_DAY;
+
+  private boolean TRACE = false;
+  private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
+  // Get/Set Routines ------------------------------------------------------
+  public void setEarliestDateAllowed( GeoDate earliestDateAllowed ) {
+    this.earliestDateAllowed = earliestDateAllowed;
+    earliestCheckingEnabled = true;
+    System.out.println("Earliest date allowed: " + earliestDateAllowed);
+  }
+  public void setLatestDateAllowed( GeoDate latestDateAllowed ) {
+    this.latestDateAllowed = latestDateAllowed;
+    latestCheckingEnabled = true;
+    System.out.println("Latest date allowed: " + latestDateAllowed);
+  }
+  public GeoDate getEarliestDateAllowed() {
+    return( earliestDateAllowed );
+  }
+  public GeoDate getLatestDateAllowed() {
+    return( latestDateAllowed );
+  }
+  //  public void setTimeZone( TimeZone tz ) {
+  //    this.tz = tz;
+  //    setTimeZoneForTimeObjects( tz );
+  //  }
+
+  //  public TimeZone getTimeZone( ) {
+  //    return this.tz;
+  //  }
+
+    public void setOutputDateFormatter( SimpleDateFormat sdf) {
+      this.sdf = sdf;
+    }
+
+  public void setInitialDate( GeoDate initialDateIn) {
+    initialDate = initialDateIn;
+    liquidDate = new GeoDate( initialDate );
+    this.setTitle( composeTimeLabel( liquidDate));
+  }
+  public void setGeoDate( GeoDate dt) {
+    if (TRACE) System.out.println( "setDate entered");
+    liquidDate = new GeoDate( dt );
+    if (liquidDateWithinBounds()) {
+      updateGUIAfterLiquidDateChange();
+      this.setTitle( composeTimeLabel( liquidDate));
+    }
+  }
+  public void setTitle( String title ) {
+    this.title = title;
+  }
+  public String getTitle( ) {
+    return this.title;
+  }
+  public GeoDate getInitialDate() {
+    return( initialDate );
+  }
+  public void setRegularFont( Font regularFontIn ) {
+    regularFont = regularFontIn;
+  }
+  public Font getRegularFont() {
+    return( regularFont );
+  }
+  public void setBoldFont( Font boldFontIn ) {
+    boldFont = boldFontIn;
+  }
+  public Font getBoldFont( ) {
+    return( boldFont );
+  }
+  public void setPanelBackground( Color color ) {
+    panelBackground = color;
+  }
+  public Color getPanelBackground( ) {
+    return( panelBackground );
+  }
+  public void setCalBackground( Color color ) {
+    calBackground = color;
+  }
+  public Color getCalBackground( ) {
+    return( calBackground );
+  }
+  public void setSelectedButnBackground( Color color ) {
+    selectedButnBackground = color;
+  }
+  public Color getSelectedButnBackground( ) {
+    return( selectedButnBackground );
+  }
+  public void setHideTime( boolean ans) {
+    hideTime = ans;
+    if (ans) {
+      removeTime();
+    }
+  }
+  public boolean getHideTime() {
+    return hideTime;
+  }
+  //  public JButton getOkButn() {
+  //    return okButn;
+  //  }
+  //  public JButton getCancelButn() {
+  //    return cancelButn;
+  //  }
+  //----------------------------------------------------------------
+  // Constructor
+  public GeoDateDialog( GeoDate inDate ) {
+
+    super();
+    //    tz = TimeZone.getDefault();
+    cal = new GregorianCalendar();
+    cal.setTimeZone(tz);
+    createDateFormatter();
+    setTimeZoneForTimeObjects( );
+    setInitialDate( inDate ); 
+    finishConstruction();
+  }
+
+  //----------------------------------------------------------------
+  // Constructor
+  public GeoDateDialog( GeoDate inDate, GeoDate earliestDateAllowedIn,
+                          GeoDate latestDateAllowedIn, int xlocIn, int ylocIn) {
+
+    super();
+    //    tz = TimeZone.getDefault();
+    cal = new GregorianCalendar();
+    cal.setTimeZone(tz);
+    createDateFormatter();
+    setTimeZoneForTimeObjects( );
+    xloc = xlocIn;
+    yloc = ylocIn;
+    setInitialDate( inDate ); 
+    setEarliestDateAllowed( earliestDateAllowedIn );
+    setLatestDateAllowed( latestDateAllowedIn );
+    finishConstruction();
+  }
+
+  //----------------------------------------------------------------
+  // Constructor
+  public GeoDateDialog( ) {
+
+    super();
+    //    tz = TimeZone.getDefault();
+    cal = new GregorianCalendar();
+    cal.setTimeZone(tz);
+    createDateFormatter();
+    setTimeZoneForTimeObjects( );
+    // Initialize date to current, but round hours and minutes to 0
+    GeoDate dt = new GeoDate();
+    cal.setTime( dt );
+    computeFields( cal );
+    cal.set(HOUR_OF_DAY,0); cal.set(MINUTE,0); 
+    cal.set( cal.SECOND,0);
+    dt = new GeoDate(cal.getTime());
+    setInitialDate( dt ); 
+
+    finishConstruction();
+  }
+  //----------------------------------------------------------------
+  // Finish Construction
+  // 
+  void finishConstruction( ) {
+
+    mainPanel_ = new JPanel();
+
+    this.addPropertyChangeListener( this );
+    //    mainPanel_.setSize(220 ,323);
+
+    regularFont = new Font( "Dialog", Font.PLAIN, 10);
+    boldFont = new Font( "Dialog", Font.BOLD, 10);
+    setSelectedButnBackground( new Color(240, 240, 240 ));
+    setCalBackground( new Color(200,200,200 ));
+
+    createCalendarPanel();
+    createMonthYearPanel();
+    createTimePanel();
+    createOkPanel();
+    createSelectionPanel();
+
+    theBox = box.createVerticalBox();
+    theBox.add( monthYearBox );
+    theBox.add( calPanel);
+    theBox.add( timeBox);
+    theBox.add( box.createVerticalStrut( 1 ));
+    theBox.add( selectionPanel);
+    theBox.add( okPanel);
+    theBox.add( box.createVerticalGlue()); 
+
+    theBox.validate();
+    theBox.setBackground( panelBackground );
+    theBox.setBackground( Color.white );
+    theBox.repaint();
+    //this.getContentPane().add( theBox );
+    mainPanel_.add( theBox );
+    theBox.setLocation( 10, 10 );
+    mainPanel_.setLocation( xloc, yloc);
+    this.getContentPane().add(mainPanel_);
+    validate();
+    repaint();
+
+    cal.setTime( getInitialDate());
+    computeFields( cal );
+    lastDaySel = cal.get( DATE );
+
+    resetCalendarPanel( initialDate );
+    softwareDayOfMonthClick( initialDate );
+
+    minList.setSelectedIndex( (cal.get(MINUTE)/5));
+    hourText.setText( new String(String.valueOf(cal.get(HOUR_OF_DAY))));
+    monthList.setSelectedIndex( cal.get( MONTH));
+
+  }
+  //----------------------------------------------------------------
+  // showInJFrame
+  //
+  //  show this DateTimeGetter in a JFrame; handles all window closing
+  //
+  public int showDialog(GeoDate date, int x, int y) {
+    this.setSize(220 ,323);
+    this.setLocation(x, y);
+//      aJFrame.addWindowListener( new WindowAdapter() {
+//      public void windowClosing( WindowEvent e) {
+//        closeDown();
+//      }
+//        });
+    setInitialDate(date);
+    setGeoDate(date);
+    result_ = CANCEL_RESPONSE;
+    this.setModal(true);
+    this.setVisible( true );
+    return result_;
+  }
+
+  //----------------------------------------------------------------
+  // Removes the time-related selectors
+  //
+  void removeTime() {
+    theBox.remove(timeBox); 
+    createDateFormatter();
+    updateDateLabel();
+    this.setSize( 220 ,260);
+  }
+
+  //----------------------------------------------------------------
+  //
+  // for all objects that use timezone.
+  // 
+  void setTimeZoneForTimeObjects() {
+      if (TRACE) System.out.println( "setTimeZoneForTimeObjects entered");
+      if (dateFormatter != null) dateFormatter.setTimeZone( tz );
+      if (cal != null) cal.setTimeZone( tz );
+    }
+
+
+  //----------------------------------------------------------------
+  // Create date formatter; need to create this only once for use
+  // many times.
+  void createDateFormatter() {
+
+    if (TRACE) System.out.println( "createDateFormatter entered");
+    dateFormatter = new SimpleDateFormat(" dd MMM yyyy HH:mm ");
+    if (hideTime) {
+      dateFormatter = new SimpleDateFormat("dd MMM yyyy ");
+    }
+    dateFormatter.setTimeZone( tz );
+  }
+
+  //----------------------------------------------------------------
+  // create Calendar panel
+  //----------------------------------------------------------------
+  // The calendar panel has the grid layout of 7 rows, 7 columns,
+  // (One label row; 6 week rows)
+  // 
+
+  void createCalendarPanel( ) {
+
+    if (TRACE) System.out.println( "createCalendarPanel entered");
+    int dayOfWeek, weekOfMonth;
+
+    JLabel jl;
+    // Create a panel for the calendar
+    calPanel = new JPanel();
+    calPanel.setLayout( new GridLayout( numWeeks+1, 7, 2, 1 ));
+    jl = new JLabel("Sun", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    jl = new JLabel("Mon", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    jl = new JLabel("Tue", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    jl = new JLabel("Wed", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    jl = new JLabel("Thu", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    jl = new JLabel("Fri", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    jl = new JLabel("Sat", JLabel.CENTER); jl.setFont(boldFont);
+    calPanel.add( jl);
+    calPanel.setBorder( new EmptyBorder( 2,2,2,2));
+
+    calButtonGroup = new ButtonGroup();
+    calButtons = new JToggleButton[ numWeeks * 7 ];
+    for (int i = 0; i < (7*numWeeks); i++ ) {
+      calButtons[ i ] = new JToggleButton("  ");
+      calButtons[ i ].setBorder( cp );
+      calButtons[ i ].setContentAreaFilled( true );
+      calButtons[ i ].addActionListener( this );
+      calButtons[ i ].setFont(regularFont);
+      calPanel.add( calButtons[ i ] );
+      calButtonGroup.add( calButtons[ i ] );
+      calButtons[ i ].setMinimumSize( new Dimension( 17, 21 ));
+      calButtons[ i ].setMaximumSize( new Dimension( 17, 21 ));
+      calButtons[ i ].setSize( new Dimension( 17, 21 ));
+    }
+
+  }  // createCalendarPanel
+
+  //----------------------------------------------------------------
+  // reset Calendar Panel when the date changes to reflect new month.
+  //----------------------------------------------------------------
+  void resetCalendarPanel( GeoDate newDate ) {
+
+    if (TRACE) System.out.println( "resetCalendarPanel entered");
+    int dayOfWeek, weekOfMonth;
+    String[][] gridLabels = new String[7][numWeeks];
+    GregorianCalendar cal1 = new GregorianCalendar();
+    cal1.setTimeZone( tz );
+
+    // Set labels in grid to "  " 
+    for (dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {   // monday -> sunday
+      for (weekOfMonth = 0; weekOfMonth < numWeeks; weekOfMonth++) {
+        gridLabels[ dayOfWeek][ weekOfMonth ] = "  ";
+      }
+    }
+
+    // Get first day of this month
+    cal1.setTime( newDate );
+    computeFields( cal1 );
+    cal1.set( cal1.DATE, 1 );
+    Date firstThisMonth = cal1.getTime();
+
+    //System.out.println(" firstThisMonth: " + tsdf.format( firstThisMonth));
+    // Get first of next month's date
+    cal1.setTime( firstThisMonth );
+    computeFields( cal1 );
+    dayOfWeek = cal1.get( cal1.DAY_OF_WEEK ) - 1;       // added the subtract 12/99
+    //System.out.println(" day of week is: " + dayOfWeek);
+
+    // Now set calendar to next month
+    if ((cal1.get(cal1.MONTH)+1) == 13) {  // crossing over to the next year
+      cal1.set(cal1.MONTH, 0 );
+      cal1.set(cal1.YEAR, cal1.get( cal1.YEAR ) +1 );
+    }
+    else
+      cal1.set(cal1.MONTH, cal1.get( cal1.MONTH )+1 );
+
+
+    Date firstNextMonth = cal1.getTime();
+    //System.out.println(" firstNextMonth: " + tsdf.format( firstNextMonth));
+
+    long curTime = firstThisMonth.getTime();
+    long endTime = firstNextMonth.getTime();
+    cal1.setTime( firstThisMonth);
+    computeFields( cal1 );
+
+    weekOfMonth = 0;
+    int dayOfMonth = 1;
+    while (curTime < endTime) {
+      // Set labels in grid
+      if (dayOfMonth != 32) // October; daylight savings time causes bug
+        gridLabels[ dayOfWeek][ weekOfMonth ] = daysOfMonth[ dayOfMonth-1 ];
+
+      dayOfWeek++;
+      dayOfMonth++;
+      if (dayOfWeek > 6) {
+        dayOfWeek = 0;
+        weekOfMonth++;
+      }
+      curTime+= (24 * 60 * 60 * 1000);  // add 24 hours
+    }
+
+    int ithButn = 0;
+    for (weekOfMonth = 0; weekOfMonth < numWeeks; weekOfMonth++) {
+      for (dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {// monday -> sunday
+        if (gridLabels[ dayOfWeek][weekOfMonth].equals("  ")) {
+          calButtons[ ithButn ].setText( "  ");
+          calButtons[ ithButn ].setVisible(false);
+        }
+        else {
+          calButtons[ ithButn ].setText( 
+                                        gridLabels[ dayOfWeek][weekOfMonth]);
+          calButtons[ ithButn ].setVisible(true);
+        }
+        ithButn++;
+      }
+    }
+  }
+  //----------------------------------------------------------------
+  // closeDown 
+  //
+  void closeDown() {
+    this.setVisible( false );
+  }
+
+  public GeoDate getGeoDate() {
+    return liquidDate;
+  }
+
+  //----------------------------------------------------------------
+  void softwareDayOfMonthClick( GeoDate dt) {
+
+    if (TRACE) System.out.println( "softwareDayOfMonthClick entered");
+    cal.setTime( dt );
+    computeFields( cal );
+    int date = cal.get( DATE );
+    int idx = 0;
+    for (int i = 0; i < calButtons.length; i++) {
+      if (calButtons[i].getText().equals( daysOfMonth[ date-1 ])) {
+        calButtons[i].doClick(); 
+      }
+    }
+  }  
+
+  //----------------------------------------------------------------
+  void selectDay( int date) {
+
+    if (TRACE) System.out.println( "selectDay entered");
+    if (calButtons != null) {
+      for (int i = 0; i < calButtons.length; i++) {
+        if (calButtons[i].getText().equals( daysOfMonth[ date-1 ])) {
+          lastButnSel = i;
+          lastDaySel = date;
+          break;
+        }
+      }
+    }
+  }  // selectDay
+
+  // --------------------------------------------------------------
+  // Compose time label
+  String composeTimeLabel( GeoDate dt ) {
+    return( dateFormatter.format( dt ));
+  }
+  //----------------------------------------------------------------
+  // computeFields
+  //  forces the Calendar object to compute its fields.  (Unfortunately,
+  //  the computeFields method of the object is protected, so I can't
+  //   call it.)
+  //----------------------------------------------------------------
+  void computeFields( Calendar caln ) {
+    {int yrr=caln.get(caln.YEAR);} // FORCE a call to computeFields 
+  }
+
+  //----------------------------------------------------------------
+  // update Date Label
+  //----------------------------------------------------------------
+  void updateDateLabel( ) {
+
+    //this.setTitle( composeTimeLabel( liquidDate ));
+    selectionLabel.setText( composeTimeLabel( liquidDate ));
+  }
+  //----------------------------------------------------------------
+  // create Month/Year panel
+  //----------------------------------------------------------------
+  // The Month/Year panel has the following grid bag layout structure:
+  //
+  //         x-0    x-1    x-2    x-3    x-4    x-5    x-6    
+  //         ------ ------ ------ ------ ------ ------ ------ 
+  //  y-0:   subYea subMon month  month  year   addMon addYea 
+
+  void createMonthYearPanel() {
+
+    if (TRACE) System.out.println( "createMonthYearPanel entered");
+    subMonthButn = new JButton("<<");
+    subMonthButn.setFont( regularFont );
+    subMonthButn.setBorder( cp );
+    subMonthButn.addActionListener( this );
+    subMonthButn.setBackground( calBackground );
+    subMonthButn.setAlignmentY( 0.5f );
+
+    addMonthButn = new JButton(">>");
+    addMonthButn.setFont( regularFont );
+    addMonthButn.setBorder( cp );
+    addMonthButn.addActionListener( this );
+    addMonthButn.setBackground( calBackground );
+    addMonthButn.setAlignmentY( 0.5f );
+
+    monthList = new JComboBox( months );
+    monthList.setFont( regularFont );
+    monthList.addItemListener( this );
+    monthList.setAlignmentY( 0.5f );
+
+    yearText = new JTextField( new String( String.valueOf(cal.get( YEAR))));
+    yearText.setBackground(calBackground);
+    yearText.addActionListener( this );
+    yearText.setFont( regularFont );
+    int x = subMonthButn.getPreferredSize().width*3;
+    int y = subMonthButn.getPreferredSize().height;
+    yearText.setPreferredSize( new Dimension( x,y));
+    yearText.setMaximumSize( new Dimension( x,y));
+    yearText.setAlignmentY( .5f );
+
+    subYearButn = new JButton("<<");
+    subYearButn.setFont( regularFont );
+    subYearButn.setBorder( cp );
+    subYearButn.addActionListener( this );
+    subYearButn.setBackground( calBackground );
+    subYearButn.setAlignmentY( .5f );
+
+    addYearButn = new JButton(">>");
+    addYearButn.setFont( regularFont );
+    addYearButn.setBorder( cp );
+    addYearButn.addActionListener( this );
+    addYearButn.setBackground( calBackground );
+    addYearButn.setAlignmentY( .5f );
+
+    monthYearBox = box.createHorizontalBox();
+
+
+    monthYearBox.add( box.createHorizontalGlue());
+    monthYearBox.add( subMonthButn );
+    monthYearBox.add( addMonthButn );
+    monthYearBox.add( monthList );
+    monthYearBox.add( box.createHorizontalStrut(1));
+    monthYearBox.add( yearText );
+    monthYearBox.add( subYearButn );
+    monthYearBox.add( addYearButn );
+    monthYearBox.add( box.createHorizontalGlue());
+  }
+
+  //----------------------------------------------------------------
+  // Reset MonthYear Panel
+  public void resetMonthYearPanel( GeoDate newDate ) {
+    if (TRACE) System.out.println( "resetMonthYearPanel entered");
+    cal.setTime( newDate );
+    computeFields( cal );
+    int m = cal.get( MONTH );
+    Integer yr = new Integer( cal.get( YEAR));
+
+    monthList.setVisible(false );
+    monthList.setSelectedIndex( m);
+    monthList.setVisible( true);
+
+    int yr1 = Integer.parseInt( yearText.getText().trim());
+    if (yr.intValue() != yr1) {
+      yearText.setText( yr.toString() );
+    }
+  }
+  //----------------------------------------------------------------
+  // Create Time Panel
+
+  void createTimePanel () {
+
+    if (TRACE) System.out.println( "createTimePanel entered");
+    hourLabel = new JLabel("Hour(0-23)        ");
+    hourLabel.setFont( boldFont );
+
+    minLabel = new JLabel( "Minute    ");
+    minLabel.setFont( boldFont );
+
+    JLabel colonLabel = new JLabel( ":");
+    Font f = new Font( "Dialog", Font.BOLD, 12);
+    colonLabel.setFont( f );
+
+    subHourButn = new JButton("<<");
+    subHourButn.setFont( regularFont );
+    subHourButn.setBorder( cp );
+    subHourButn.addActionListener( this );
+    subHourButn.setBackground( calBackground );
+    subHourButn.setAlignmentY( 0.5f );
+
+    addHourButn = new JButton(">>");
+    addHourButn.setFont( regularFont );
+    addHourButn.setBorder( cp );
+    addHourButn.addActionListener( this );
+    addHourButn.setBackground( calBackground );
+    addHourButn.setAlignmentY( 0.5f );
+
+    hourText = new JTextField(); 
+    hourText.setText("     00");
+    hourText.setFont( regularFont );
+    hourText.setBackground(calBackground);
+    hourText.addActionListener( this );
+    hourText.setHorizontalAlignment( JTextField.RIGHT );
+
+    int x = addHourButn.getPreferredSize().width * 2;
+    int y = addHourButn.getPreferredSize().height;
+    hourText.setPreferredSize( new Dimension( x, y) );
+    hourText.setMaximumSize( hourText.getPreferredSize());
+    hourText.setSize( hourText.getPreferredSize());
+    hourText.setAlignmentY( .5f );
+
+
+    minList = new JComboBox( minutes );
+    minList.addItemListener( this );
+    minList.setFont( regularFont );
+    x = addHourButn.getPreferredSize().width * 2;
+    y = addHourButn.getPreferredSize().height;
+    minList.setPreferredSize( new Dimension( x,y ));
+    minList.setMaximumSize( minList.getPreferredSize());
+    minList.setSize( minList.getPreferredSize());
+    minList.setAlignmentY( .5f );
+
+    subMinButn = new JButton("<<");
+    subMinButn.setFont( regularFont );
+    subMinButn.setBorder( cp );
+    subMinButn.addActionListener( this );
+    subMinButn.setBackground( calBackground );
+    subMinButn.setAlignmentY( .5f );
+
+    addMinButn = new JButton(">>");
+    addMinButn.setFont( regularFont );
+    addMinButn.setBorder( cp );
+    addMinButn.addActionListener( this );
+    addMinButn.setBackground( calBackground );
+    addMinButn.setAlignmentY( .5f );
+
+
+    labelBox = box.createHorizontalBox();
+    labelBox.add( box.createHorizontalGlue());
+    labelBox.add( hourLabel );
+    labelBox.add( box.createHorizontalStrut(1));
+    labelBox.add( minLabel );
+    labelBox.add( box.createHorizontalGlue());
+
+    hrMinBox = box.createHorizontalBox();
+    hrMinBox.add( box.createHorizontalGlue());
+    hrMinBox.add( subHourButn );
+    hrMinBox.add( addHourButn );
+    hrMinBox.add( hourText );
+    hrMinBox.add( box.createHorizontalStrut(5));
+    //hrMinBox.add( colonLabel );
+    hrMinBox.add( minList );
+    hrMinBox.add( subMinButn );
+    hrMinBox.add( addMinButn );
+    hrMinBox.add( box.createHorizontalGlue());
+
+    timeBox = box.createVerticalBox();
+    timeBox.add( box.createVerticalGlue());
+    timeBox.add( labelBox );
+    timeBox.add( hrMinBox );
+    timeBox.add( box.createVerticalGlue());
+  }
+
+  void createSelectionPanel() {
+    if (TRACE) System.out.println( "createSelectionPanel entered");
+    selectionLabel = new JLabel("ddd mmm dd hh:mm yyyy");
+    selectionLabel.setBackground( Color.red );
+    selectionLabel.setForeground( Color.black );
+    selectionPanel = new JPanel();
+    selectionPanel.add( selectionLabel );
+    int x = selectionPanel.getPreferredSize().width;
+    int y = 15;
+    //selectionPanel.setPreferredSize( new Dimension( x,y));
+    //selectionPanel.setMaximumSize( new Dimension( x,y));
+    //selectionPanel.setBackground( Color.yellow );
+    updateDateLabel();
+  }
+  //----------------------------------------------------------------
+  // create the okay/cancel panel
+  void createOkPanel() {
+
+    if (TRACE) System.out.println( "createOkPanel entered");
+    okButn = new JButton(    "OK"); 
+    okButn.addActionListener( this );
+    okButn.setBackground( calBackground );
+    okButn.setMinimumSize( new Dimension( 51, 25 ));
+    okButn.setMaximumSize( new Dimension( 51, 25 ));
+
+    cancelButn = new JButton("Cancel");
+    cancelButn.addActionListener( this );
+    cancelButn.setBackground( calBackground );
+    cancelButn.setMinimumSize( new Dimension( 73, 25 ));
+    cancelButn.setMaximumSize( new Dimension( 73, 25 ));
+
+    okPanel = new JPanel();
+    okPanel.setLayout( new GridLayout(1,2));
+    okPanel.add( okButn);
+    okPanel.add( cancelButn);
+  }  // create okPanel
+
+  //----------------------------------------------------------------
+  // handleHourChange
+  void handleHourChange(){
+    if (TRACE) System.out.println( "handleHourChange entered");
+    try {
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      int prevHr = cal.get(HOUR_OF_DAY);   // hang on to old value
+      int hr = Integer.parseInt( hourText.getText().trim());
+      hr = validateHours( hr );
+      hourText.setText( (new Integer(hr)).toString() );
+      cal.set( HOUR_OF_DAY, hr );
+      liquidDate = new GeoDate(cal.getTime());
+      if (!liquidDateWithinBounds()) {  // restore old value
+        cal.set( HOUR_OF_DAY, prevHr );
+        liquidDate = new GeoDate(cal.getTime());
+        hourText.setText( (new Integer(prevHr)).toString() );
+      }
+      updateDateLabel();
+    } catch (NumberFormatException e) {
+    }
+  }
+  //----------------------------------------------------------------
+  // handleYearChange
+  void handleYearChange(){
+    if (TRACE) System.out.println( "handleYearChange entered");
+    try {
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      int prevYr = cal.get(YEAR);   // hang on to old value
+      int yr = Integer.parseInt( yearText.getText().trim());
+      //yr = validateYear( yr );
+      yearText.setText( (new Integer(yr)).toString() );
+      cal.set( YEAR, yr );
+      liquidDate = new GeoDate(cal.getTime());
+      if (!liquidDateWithinBounds()) {  // restore old value
+        //boundsMsg();
+        cal.set( YEAR, prevYr );
+        liquidDate = new GeoDate(cal.getTime());
+        yearText.setText( (new Integer(prevYr)).toString() );
+      }
+      else {
+        updateGUIAfterLiquidDateChange();
+      }
+      updateDateLabel();
+    } catch (NumberFormatException e) {
+    }
+  }
+  //----------------------------------------------------------------
+  // Validate Hours
+  int validateHours( int hr) {
+    if (TRACE) System.out.println( "validateHours entered");
+    if (hr < 0) return(0);
+    if (hr > 23) return(23);
+    return( hr );
+  }
+  //----------------------------------------------------------------
+  // check Date within range
+  boolean liquidDateWithinBounds( ) {
+
+    if (TRACE) System.out.println( "liquidDateWithinBounds entered");
+    /*
+      cal.setTime( earliestDateAllowed );
+      computeFields( cal );
+      System.out.println(" Floor date is: " + 
+      " year " + cal.get( YEAR) +
+      " month " + cal.get( MONTH) +
+      " date " + cal.get( DATE) +
+      " hour " + cal.get( cal.HOUR) +
+      " min " + cal.get( MINUTE));
+
+      cal.setTime( latestDateAllowed );
+      computeFields( cal );
+      System.out.println(" Latest date is: " + 
+      " year " + cal.get( YEAR) +
+      " month " + cal.get( MONTH) +
+      " date " + cal.get( DATE) +
+      " hour " + cal.get( cal.HOUR) +
+      " min " + cal.get( MINUTE));
+
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      System.out.println(" Liquid date is: " + 
+      " year " + cal.get( YEAR) +
+      " month " + cal.get( MONTH) +
+      " date " + cal.get( DATE) +
+      " hour " + cal.get( cal.HOUR) +
+      " min " + cal.get( MINUTE));
+    */
+
+    if (earliestCheckingEnabled) {
+      System.out.println("liquidDate is: " + liquidDate);
+      System.out.println("earliestDateAllowed is: " + earliestDateAllowed);
+      if (liquidDate.getTime() < earliestDateAllowed.getTime()) {
+        lowerBoundMsg();
+        return (false);
+      }
+    }
+    if (latestCheckingEnabled) {
+      if (liquidDate.getTime() > latestDateAllowed.getTime()) {
+        upperBoundMsg();
+        return( false );
+      }
+    }
+    return( true );
+  }
+  //----------------------------------------------------------------
+  // 
+  void lowerBoundMsg() {
+    if (TRACE) System.out.println( "lowerBoundMsg entered");
+    JOptionPane.showMessageDialog(this, 
+                                  (new String("Lower bound restricted to " + composeTimeLabel( getEarliestDateAllowed()))),
+                                  "Calendar Bounds Exception",
+                                  JOptionPane.WARNING_MESSAGE);
+  }
+  //----------------------------------------------------------------
+  // 
+  void upperBoundMsg() {
+    if (TRACE) System.out.println( "upperBoundMsg entered");
+    JOptionPane.showMessageDialog(this, 
+                                  (new String("Upper bound restricted to " + composeTimeLabel( getLatestDateAllowed()))),
+                                  "Calendar Bounds Exception",
+                                  JOptionPane.WARNING_MESSAGE);
+  }
+  //----------------------------------------------------------------
+  // attempt to add or subract a year
+  void attemptToAddOrSubtractAYear( int numYears ) {
+    if (TRACE) System.out.println( "attemptToAddOrSubtractAYear entered");
+    cal.setTime( liquidDate );
+    computeFields( cal );
+    int yr = cal.get(YEAR) + numYears;
+    cal.set( YEAR, yr );
+    liquidDate = new GeoDate(cal.getTime());
+    if (liquidDateWithinBounds()) {
+      updateGUIAfterLiquidDateChange();
+    }
+    else {  // drops below floor or above ceiling; return to previous value
+      cal.set( YEAR, (cal.get(YEAR) - numYears) );
+      liquidDate = new GeoDate(cal.getTime());
+    }
+  }
+  //----------------------------------------------------------------
+  // update GUI components after liquid Date change
+  void updateGUIAfterLiquidDateChange() {
+    if (TRACE) System.out.println( "updateGUIAfterLIquidDateChange entered");
+    resetMonthYearPanel( liquidDate );
+    resetCalendarPanel( liquidDate );
+    softwareDayOfMonthClick( liquidDate );
+    updateDateLabel();
+  }
+  //----------------------------------------------------------------
+  // item State Changed
+  public void itemStateChanged( ItemEvent itemEvent) {
+    if (TRACE) System.out.println( "itemStateChanged entered");
+
+    if (itemEvent.getSource() == monthList) {
+
+      int mon = monthList.getSelectedIndex();
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      int prevMon = cal.get(MONTH);
+
+      if (prevMon != mon) {
+        cal.set( MONTH, mon );
+        liquidDate = new GeoDate(cal.getTime());
+        if (!liquidDateWithinBounds()) {
+          cal.set(MONTH, prevMon );
+          liquidDate = new GeoDate(cal.getTime());
+        }
+        updateGUIAfterLiquidDateChange();
+      }
+    }
+    else if (itemEvent.getSource() == minList) {
+      int min = Integer.parseInt( (String) minList.getSelectedItem());
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      int oldMin = cal.get(MINUTE);
+      cal.set(MINUTE, min  );
+      liquidDate = new GeoDate(cal.getTime());
+      if (!liquidDateWithinBounds()) {
+        cal.set(MINUTE, oldMin);
+        liquidDate = new GeoDate(cal.getTime());
+        minList.setVisible(false);
+        minList.setSelectedIndex( oldMin/5 );
+        minList.setVisible(true);
+      }
+      updateDateLabel();
+    }
+  }
+  //----------------------------------------------------------------
+  // Action
+  public void actionPerformed( ActionEvent event ) {
+    if (TRACE) System.out.println( "actionPerformed entered");
+    Object source = event.getSource();
+    int mon = 0;
+    int prevMon = 0;
+    int yr = 0;
+    int day = 0;
+    int inputDayOfMonth;
+
+    if (source == okButn) {
+      // First, get the hour from the TextField in case user didn't hit 
+      // return
+      handleHourChange();
+      if (sdf != null) {
+        pcs.firePropertyChange("FormattedDateTime",
+                               sdf.format( getInitialDate()), 
+                               sdf.format(liquidDate));
+      }
+      pcs.firePropertyChange("DateTime",
+                             getInitialDate(),
+                             liquidDate);
+      result_ = OK_RESPONSE;
+      closeDown();
+    }
+    else if (source == cancelButn) {
+      result_ = CANCEL_RESPONSE;
+      closeDown();
+    }
+    else if (source == subYearButn) {
+      attemptToAddOrSubtractAYear( -1 );
+    }
+    else if (source == addYearButn) {
+      attemptToAddOrSubtractAYear( 1 );
+    }
+    else if (source == subMonthButn) {
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      mon = cal.get(MONTH) - 1;
+      if (mon == -1) { // Jan --> Dec
+        mon = 11;
+        cal.set( MONTH, mon );
+        yr = cal.get( YEAR ) - 1;
+        cal.set( YEAR, yr );
+        liquidDate = new GeoDate(cal.getTime());
+        if (!liquidDateWithinBounds()) {
+          yr = cal.get( YEAR ) + 1;
+          cal.set( YEAR, yr);
+          liquidDate = new GeoDate(cal.getTime());
+        }
+      }
+      cal.set( MONTH, mon);
+      liquidDate = new GeoDate(cal.getTime());
+      if (!liquidDateWithinBounds()) {
+        mon = mon + 1;
+        if (mon == 12) mon = 0;
+        cal.set( MONTH, mon );
+        liquidDate = new GeoDate(cal.getTime());
+      }
+      updateGUIAfterLiquidDateChange();
+    }
+    else if (source == addMonthButn) {
+      cal.setTime( liquidDate );
+      computeFields( cal );
+      mon = cal.get(MONTH) + 1;
+      if (mon == 12) {
+        mon = 0;
+        cal.set( MONTH, 0 );
+        yr = cal.get(YEAR) + 1;
+        cal.set( YEAR, yr );
+        liquidDate = new GeoDate(cal.getTime());
+        if (!liquidDateWithinBounds()) {
+          cal.set( YEAR, cal.get(YEAR) - 1);
+          liquidDate = new GeoDate(cal.getTime());
+        }
+      }
+      cal.set(MONTH, mon );
+      liquidDate = new GeoDate(cal.getTime());
+      if (!liquidDateWithinBounds()) {
+        mon = mon - 1;
+        if (mon == -1) mon = 11;
+        cal.set( MONTH, mon );
+        liquidDate = new GeoDate(cal.getTime());
+      }
+      updateGUIAfterLiquidDateChange();
+    }
+    else if (source == hourText) {
+      handleHourChange();
+    }
+    else if (source == yearText) {
+      handleYearChange();
+    }
+    else if (source == subHourButn) {
+      try {
+        // User may have changed the hour text without hitting "return"
+        // so must synchronize the value in TextField with our variables
+        handleHourChange();
+        // Now, get the value in TextField and decrement
+        int hr = Integer.parseInt( hourText.getText().trim());
+        hr--;
+        if (hr == -1) {
+          hr = 23;
+        }
+        hourText.setText( (new Integer(hr)).toString() );
+        handleHourChange();
+      } catch (NumberFormatException e) {
+      }
+    }
+    else if (source == addHourButn) {
+      try {
+        // User may have changed the hour text without hitting "return"
+        // so must synchronize the value in TextField with our variables
+        handleHourChange();
+        // Now, get the value in TextField and decrement
+        int hr = Integer.parseInt( hourText.getText().trim());
+        hr++;
+        if (hr == 24) {
+          hr = 0;
+        }
+        hourText.setText( (new Integer(hr)).toString() );
+        handleHourChange();
+      } catch (NumberFormatException e) {
+      }
+    }
+    else if (source == subMinButn) {
+      try {
+        int min = Integer.parseInt( (String) minList.getSelectedItem());
+        min  = min - 5;
+        if (min == -5) {
+          min = 55;
+        }
+        cal.setTime( liquidDate );
+        computeFields( cal );
+        int oldMin = cal.get( MINUTE);
+        cal.set( MINUTE, min );
+        liquidDate = new GeoDate(cal.getTime());
+        if (!liquidDateWithinBounds()) {
+          cal.set( MINUTE,oldMin);
+          liquidDate = new GeoDate(cal.getTime());
+          min = oldMin;
+        }
+        minList.setVisible(false);
+        minList.setSelectedIndex( min/5 );
+        minList.setVisible(true);
+        updateDateLabel();
+      } catch (NumberFormatException e) {
+      }
+    }
+    else if (source == addMinButn) {
+      try {
+        int min = Integer.parseInt( (String) minList.getSelectedItem());
+        min  = min + 5;
+        if (min == 60) {
+          min = 0;
+        }
+        cal.setTime( liquidDate );
+        computeFields( cal );
+        int oldMin = cal.get(MINUTE);
+        cal.set(MINUTE, min );
+        liquidDate = new GeoDate(cal.getTime());
+        if (!liquidDateWithinBounds()) {
+          cal.set( MINUTE, oldMin);
+          liquidDate = new GeoDate(cal.getTime());
+          min = oldMin;
+        }
+        minList.setVisible(false);
+        minList.setSelectedIndex( min/5 );
+        minList.setVisible(true);
+        updateDateLabel();
+      } catch (NumberFormatException e) {
+      }
+    }
+    else if (source == monthList) {
+    }
+    else { // must be from the calendar
+      try {
+        inputDayOfMonth = Integer.parseInt( event.getActionCommand().trim());
+        cal.setTime( liquidDate );
+        computeFields( cal );
+        int lastDate = cal.get(DATE);
+        cal.set(DATE, inputDayOfMonth );
+        liquidDate = new GeoDate(cal.getTime());
+        if (liquidDateWithinBounds()) {
+          selectDay( inputDayOfMonth);
+          updateDateLabel();
+        }
+        else {
+          cal.set(DATE, lastDate );
+          liquidDate = new GeoDate(cal.getTime());
+        }
+      } catch (NumberFormatException e) {
+        System.out.println(" !!! Trouble with " + event.getActionCommand());
+      }
+    }
+  }
+
+  public GeoDate getDate() {
+    return liquidDate;
+  }
+
+  public void propertyChange( java.beans.PropertyChangeEvent event) {
+    if (TRACE) System.out.println( "propertyChange entered");
+    Object obj = event.getSource();
+    this.setTitle( composeTimeLabel( liquidDate));
+    if (event.getPropertyName().equals("DateTime")) {
+      /*
+        System.out.println(" Property Change, old value: " + 
+        composeTimeLabel( (Date) event.getOldValue()) + " new value: " +
+        composeTimeLabel( (Date) event.getNewValue()));
+      */
+    }
+    else if (event.getPropertyName().equals("FormattedDateTime")) {
+    }
+  }
+  public void addPropertyChangeListener( PropertyChangeListener l ) {
+    pcs.addPropertyChangeListener( l );
+  }
+  public void removePropertyChangeListener( PropertyChangeListener l ) {
+    pcs.removePropertyChangeListener( l );
+  }
+
+
+
+  // ----------------------------------------------------------------
+  //
+  public static void main(String args[]) {
+
+    GeoDateDialog dtg = new GeoDateDialog();
+    dtg.setOutputDateFormatter( new SimpleDateFormat(" dd MMM yyyy HH:mm "));
+
+    /*
+      JFrame jf = new JFrame();
+      jf.setVisible( true );
+      jf.setSize(220 ,323);
+      jf.getContentPane().add( dtg );
+      jf.invalidate();
+      jf.validate();
+      jf.addWindowListener( new WindowAdapter() {
+      public void windowClosing( WindowEvent e) {
+      Window w = e.getWindow();
+      w.setVisible( false );
+      w.dispose();
+      System.exit( 0 );
+      }
+      });
+    */
+
+    int result = dtg.showDialog(new GeoDate(), 200, 200);
+
+    System.out.println("Result = " + result);
+    System.out.println("Date = " + dtg.getGeoDate().toString());
+
+    dtg.addPropertyChangeListener( new PropertyChangeListener() {
+        public void propertyChange( java.beans.PropertyChangeEvent event) {
+          if (event.getPropertyName().equals("FormattedDateTime")) {
+            System.out.println(" MAIN Property Change, old value: " + 
+                               (String) event.getOldValue() + " new value: " +
+                               (String) event.getNewValue());
+          }
+        }
+      });
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GridAttributeDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GridAttributeDialog.java
new file mode 100755
index 0000000..40859bb
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GridAttributeDialog.java
@@ -0,0 +1,885 @@
+/*
+ * $Id: GridAttributeDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.*;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableColumn;
+import javax.swing.event.TableModelEvent;
+import java.util.Vector;
+import java.io.File;
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.StreamTokenizer;
+
+import gov.noaa.pmel.sgt.GridCartesianRenderer;
+import gov.noaa.pmel.sgt.GridAttribute;
+import gov.noaa.pmel.sgt.ContourLineAttribute;
+import gov.noaa.pmel.sgt.DefaultContourLineAttribute;
+import gov.noaa.pmel.sgt.ContourLevels;
+import gov.noaa.pmel.sgt.ColorMap;
+import gov.noaa.pmel.sgt.IndexedColor;
+import gov.noaa.pmel.sgt.swing.ColorSwatchIcon;
+import gov.noaa.pmel.sgt.IndexedColorMap;
+import gov.noaa.pmel.sgt.LinearTransform;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.ContourLevelNotFoundException;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+
+import gov.noaa.pmel.util.Range2D;
+import java.awt.event.*;
+
+/**
+ * Edits the <code>GridAttribute</code>. This dialog does not make a
+ * copy of the attribute so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the properties
+ * immediately unless a <code>JPane</code> was supplied.
+ *
+ * <p> Example of <code>GridAttributeDialog</code> use:
+ * <pre>
+ *  JPane pane_;
+ *  CartesianRenderer rend = ((CartesianGraph)pane_.getFirstLayer().getGraph()).getRenderer();
+ *  ...
+ *  GridAttributeDialog gad = new GridAttributeDialog();
+ *  gad.setJPane(pane_);
+ *  gad.setGridCartesianRenderer((GridCartesianRenderer)rend);
+ *  gad.setVisible(true);
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ * @see NewLevelsDialog
+ * @see ContourLineAttributeDialog
+ * @see DefaultContourLineAttributeDialog
+ */
+public class GridAttributeDialog extends JDialog {
+  private GridAttribute attr_;
+  private ContourLevels conLevels_;
+  private ColorMap colorMap_;
+  private JPane[] paneList_ = null;
+  private int contourLevelIndex_ = 0;
+  private int colorMapIndex_ = 1;
+  private JTable conLevelTable_;
+  private ConLevelTableModel conLevelModel_;
+  private SGTGrid grid_ = null;
+  private JToggleButton[] colorButtons_ = new JToggleButton[256];
+  /**
+   * Constructor.
+   */
+  public GridAttributeDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(516,374);
+    setVisible(false);
+    mainPanel.setPreferredSize(new Dimension(516, 36));
+    getContentPane().add(TabbedPane, "Center");
+    ContourLevelsPanel.setLayout(new BorderLayout(0,0));
+    TabbedPane.add(ContourLevelsPanel, "ContourLevelsPanel");
+    ContourLevelsPanel.setBounds(2,27,511,271);
+    ContourLevelsPanel.setVisible(false);
+    ContourLevelsPanel.add(gridScrollPane, "Center");
+    controlPanel.setLayout(new GridBagLayout());
+    ContourLevelsPanel.add(controlPanel, "East");
+    JPanel1.setBorder(titledBorder1);
+    JPanel1.setLayout(new GridBagLayout());
+    controlPanel.add(JPanel1, new GridBagConstraints(0,1,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,0,0,0),0,0));
+    editButton.setToolTipText("Edit attribute of selected level.");
+    editButton.setText("Edit Attribute");
+    editButton.setActionCommand("Change Value");
+    JPanel1.add(editButton, new GridBagConstraints(0,0,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,0,5),0,0));
+    aboveButton.setToolTipText("Insert level above selected level.");
+    aboveButton.setText("Insert Level Above");
+    aboveButton.setActionCommand("Before Item");
+    JPanel1.add(aboveButton, new GridBagConstraints(0,1,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(2,5,0,5),0,0));
+    belowButton.setToolTipText("Insert level below selected level.");
+    belowButton.setText("Insert Level Below");
+    belowButton.setActionCommand("After Item");
+    JPanel1.add(belowButton, new GridBagConstraints(0,2,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(2,5,0,5),0,0));
+    deleteButton.setToolTipText("Delete the selected level.");
+    deleteButton.setText("Delete Level");
+    deleteButton.setActionCommand("Delete Item");
+    JPanel1.add(deleteButton, new GridBagConstraints(0,3,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(2,5,2,5),0,0));
+    JPanel4.setBorder(titledBorder4);
+    JPanel4.setLayout(new GridBagLayout());
+    controlPanel.add(JPanel4, new GridBagConstraints(0,3,1,1,0.0,0.0,
+        GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,0,0,0),0,0));
+    defaultButton.setToolTipText("Edit default attributes.");
+    defaultButton.setText("Edit Default Attributes");
+    defaultButton.setActionCommand("Edit Default Attributes");
+    JPanel4.add(defaultButton, new GridBagConstraints(0,0,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(2,5,2,5),0,0));
+    sortButton.setToolTipText("Sort levels by value.");
+    sortButton.setText("Sort Levels");
+    sortButton.setActionCommand("Sort");
+    controlPanel.add(sortButton, new GridBagConstraints(0,4,1,1,0.0,0.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0));
+    newConLevelButton.setToolTipText("Create new contour level set.");
+    newConLevelButton.setText("New...");
+    newConLevelButton.setActionCommand("New...");
+    controlPanel.add(newConLevelButton, new GridBagConstraints(0,0,1,1,1.0,0.0,
+        GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,5,0,5),0,0));
+    ColorMapPanel.setLayout(new BorderLayout(0,0));
+    TabbedPane.add(ColorMapPanel, "ColorMapPanel");
+    ColorMapPanel.setBounds(2,27,511,271);
+    ColorMapPanel.setVisible(false);
+    colorControlPanel.setLayout(new GridBagLayout());
+    ColorMapPanel.add(colorControlPanel, "East");
+    colorMapPanel.setBorder(titledBorder2);
+    colorMapPanel.setLayout(new GridBagLayout());
+    colorControlPanel.add(colorMapPanel, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
+            ,GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
+    newColorMapButton.setToolTipText("Create new color map.");
+    newColorMapButton.setText("New...");
+    newColorMapButton.setActionCommand("New...");
+    colorMapPanel.add(newColorMapButton, new GridBagConstraints(0,0,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    loadColorMapButton.setToolTipText("Load color map from disk.");
+    loadColorMapButton.setText("Load...");
+    loadColorMapButton.setActionCommand("Load...");
+    colorMapPanel.add(loadColorMapButton, new GridBagConstraints(0,1,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    saveColorMapButton.setToolTipText("Save color map to disk.");
+    saveColorMapButton.setText("Save...");
+    saveColorMapButton.setActionCommand("Save...");
+    colorMapPanel.add(saveColorMapButton, new GridBagConstraints(0,2,1,1,0.0,0.0,
+        GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    colorPanel.setLayout(new CardLayout(0,0));
+    ColorMapPanel.add(colorPanel, "Center");
+    CLIndexedPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    colorPanel.add("CLIndexed", CLIndexedPanel);
+    CLTransformPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    colorPanel.add("CLTransform", CLTransformPanel);
+    CLTransformPanel.setVisible(false);
+    IndexedPanel.setLayout(new GridBagLayout());
+    colorPanel.add("Indexed", IndexedPanel);
+    IndexedPanel.setVisible(false);
+    colorButtonsPanel.setLayout(new GridLayout(16,16,1,1));
+    IndexedPanel.add(colorButtonsPanel, new GridBagConstraints(0,0,1,1,1.0,1.0,
+        GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    TransformPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    colorPanel.add("Transform", TransformPanel);
+    TransformPanel.setVisible(false);
+    TabbedPane.setSelectedComponent(ContourLevelsPanel);
+    TabbedPane.setSelectedIndex(0);
+    TabbedPane.setTitleAt(0,"Contour Levels");
+    TabbedPane.setTitleAt(1,"Color Map");
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    mainPanel.setLayout(new GridBagLayout());
+    getContentPane().add(mainPanel, "North");
+    JLabel5.setText("Grid Style:");
+    mainPanel.add(JLabel5, new GridBagConstraints(0,0,1,1,0.0,0.0,
+        GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(5,5,0,5),0,0));
+    gridStyleComboBox.setModel(stringComboBoxModel1);
+    mainPanel.add(gridStyleComboBox, new GridBagConstraints(1,0,1,1,0.0,0.0,
+        GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    {
+      String[] tempString = new String[5];
+      tempString[0] = "RASTER";
+      tempString[1] = "AREA_FILL";
+      tempString[2] = "CONTOUR";
+      tempString[3] = "RASTER_CONTOUR";
+      tempString[4] = "AREA_FILL_CONTOUR";
+      for(int i=0; i < tempString.length; i++) {
+        stringComboBoxModel1.addElement(tempString[i]);
+      }
+    }
+    gridStyleComboBox.setSelectedIndex(0);
+    setTitle("GridAttribute Properties");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    gridStyleComboBox.addActionListener(lSymAction);
+    newConLevelButton.addActionListener(lSymAction);
+    newColorMapButton.addActionListener(lSymAction);
+    loadColorMapButton.addActionListener(lSymAction);
+    editButton.addActionListener(lSymAction);
+    aboveButton.addActionListener(lSymAction);
+    belowButton.addActionListener(lSymAction);
+    deleteButton.addActionListener(lSymAction);
+    sortButton.addActionListener(lSymAction);
+    saveColorMapButton.addActionListener(lSymAction);
+    defaultButton.addActionListener(lSymAction);
+
+    makeColorToggleButtons();
+  }
+
+  private void makeColorToggleButtons() {
+    Insets insets = new Insets(0,0,0,0);
+    ButtonGroup bg = new ButtonGroup();
+    ColorSwatchIcon csi = null;
+    for(int i=0; i < 256; i++) {
+      JToggleButton tb = new JToggleButton("");
+      if(System.getProperty("mrj.version") == null ||
+         !UIManager.getSystemLookAndFeelClassName().equals(UIManager.getLookAndFeel().getClass().getName()))
+        tb.setMargin(insets);
+      csi = new ColorSwatchIcon(Color.white, 8, 8);
+      tb.setIcon(csi);
+      colorButtons_[i] = tb;
+      colorButtonsPanel.add(tb);
+      bg.add(tb);
+    }
+  }
+  /** Used internally. */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public GridAttributeDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public GridAttributeDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible.
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == GridAttributeDialog.this)
+        GridAttributeDialog_WindowClosing(event);
+    }
+  }
+
+  void GridAttributeDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  //{{DECLARE_CONTROLS
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel ContourLevelsPanel = new javax.swing.JPanel();
+  javax.swing.JScrollPane gridScrollPane = new javax.swing.JScrollPane();
+  javax.swing.JPanel controlPanel = new javax.swing.JPanel();
+  javax.swing.JPanel JPanel1 = new javax.swing.JPanel();
+  javax.swing.JButton editButton = new javax.swing.JButton();
+  javax.swing.JButton aboveButton = new javax.swing.JButton();
+  javax.swing.JButton belowButton = new javax.swing.JButton();
+  javax.swing.JButton deleteButton = new javax.swing.JButton();
+  javax.swing.JPanel JPanel4 = new javax.swing.JPanel();
+  javax.swing.JButton defaultButton = new javax.swing.JButton();
+  javax.swing.JButton sortButton = new javax.swing.JButton();
+  javax.swing.JButton newConLevelButton = new javax.swing.JButton();
+  javax.swing.JPanel ColorMapPanel = new javax.swing.JPanel();
+  javax.swing.JPanel colorControlPanel = new javax.swing.JPanel();
+  javax.swing.JPanel colorMapPanel = new javax.swing.JPanel();
+  javax.swing.JButton newColorMapButton = new javax.swing.JButton();
+  javax.swing.JButton loadColorMapButton = new javax.swing.JButton();
+  javax.swing.JButton saveColorMapButton = new javax.swing.JButton();
+  javax.swing.JPanel colorPanel = new javax.swing.JPanel();
+  javax.swing.JPanel CLIndexedPanel = new javax.swing.JPanel();
+  javax.swing.JPanel CLTransformPanel = new javax.swing.JPanel();
+  javax.swing.JPanel IndexedPanel = new javax.swing.JPanel();
+  javax.swing.JPanel colorButtonsPanel = new javax.swing.JPanel();
+  javax.swing.JPanel TransformPanel = new javax.swing.JPanel();
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JComboBox gridStyleComboBox = new javax.swing.JComboBox();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  DefaultComboBoxModel stringComboBoxModel1 = new DefaultComboBoxModel();
+  javax.swing.border.EtchedBorder etchedBorder2 = new javax.swing.border.EtchedBorder();
+  javax.swing.border.TitledBorder titledBorder1 = new javax.swing.border.TitledBorder("Contour Level");
+  javax.swing.border.EmptyBorder emptyBorder1 = new javax.swing.border.EmptyBorder(5,0,0,0);
+  javax.swing.border.TitledBorder titledBorder4 = new javax.swing.border.TitledBorder("Default Attributes");
+  javax.swing.border.TitledBorder titledBorder2 = new javax.swing.border.TitledBorder("Color Map");
+  //}}
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == gridStyleComboBox)
+        gridStyleComboBox_actionPerformed(event);
+      if (object == newConLevelButton)
+        newConLevelButton_actionPerformed(event);
+      if (object == newColorMapButton)
+        newColorMapButton_actionPerformed(event);
+      else if (object == loadColorMapButton)
+        loadColorMapButton_actionPerformed(event);
+      else if (object == editButton)
+        editButton_actionPerformed(event);
+      else if (object == aboveButton)
+        aboveButton_actionPerformed(event);
+      else if (object == belowButton)
+        belowButton_actionPerformed(event);
+      else if (object == deleteButton)
+        deleteButton_actionPerformed(event);
+      else if (object == sortButton)
+        sortButton_actionPerformed(event);
+      else if (object == saveColorMapButton)
+        saveColorMapButton_actionPerformed(event);
+      else if (object == defaultButton)
+        defaultButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateGridAttribute();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateGridAttribute();
+  }
+  /**
+   * Set the parent <code>JPane</code>.  This reference to
+   * <code>JPane</code> is used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time.
+   */
+  public void setJPane(JPane pane) {
+    paneList_ = new JPane[1];
+    paneList_[0] = pane;
+  }
+  /**
+   * Get the first parent pane.
+   */
+  public JPane getJPane() {
+    if(paneList_ != null) {
+      return paneList_[0];
+    } else {
+      return null;
+    }
+  }
+  /**
+   * Set the parent <code>JPane</code>s.  These references to
+   * <code>JPane</code> are used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time. A second
+   * <code>JPane</code> is often used for a <code>ColorKey</code>.
+   */
+  public void setJPaneList(JPane[] list) {
+    paneList_ = list;
+  }
+  /** Get an array of parent panes. */
+  public JPane[] getJPaneList() {
+    return paneList_;
+  }
+
+  /**
+   * Set the <code>GridCartesianRenderer</code>.  Specifying the
+   * renderer give <code>GridAttributeDialog</code> a reference to the
+   * data and <code>GridAttribute</code> allowing automated
+   * computation of <code>ColorMap</code> and
+   * <code>ContourLevels</code> ranges.
+   *
+   * @see #setGridAttribute(GridAttribute)
+   */
+  public void setGridCartesianRenderer(GridCartesianRenderer render) {
+    grid_ = render.getGrid();
+    setGridAttribute((GridAttribute)render.getAttribute());
+  }
+  /**
+   * Set the <code>GridAttribute</code>.
+   */
+  public void setGridAttribute(GridAttribute attr) {
+    attr_ = attr;
+    colorMap_ = attr.getColorMap();
+    conLevels_ = attr.getContourLevels();
+    //
+    // style
+    //
+    int style = attr_.getStyle();
+    gridStyleComboBox.setSelectedIndex(style);
+    //
+    // contour ?
+    //
+    enableContourLevels(style);
+    initContourLevels();
+    //
+    // raster ?
+    //
+    enableColorMap(style);
+    initColorMap();
+    //
+    setCurrentTab();
+  }
+
+  private void enableContourLevels(int style) {
+    boolean isContour = (style == GridAttribute.CONTOUR ||
+                         style == GridAttribute.RASTER_CONTOUR ||
+                         style == GridAttribute.AREA_FILL_CONTOUR);
+    TabbedPane.setEnabledAt(contourLevelIndex_, isContour);
+    Component[] list = ContourLevelsPanel.getComponents();
+    boolean clExists = conLevels_ != null;
+    for(int i=0; i < list.length; i++) {
+      list[i].setEnabled(clExists);
+    }
+    newConLevelButton.setEnabled(true);
+  }
+
+  private void enableColorMap(int style) {
+    boolean isRaster = style != GridAttribute.CONTOUR;
+    TabbedPane.setEnabledAt(colorMapIndex_, isRaster);
+    Component[] list = ColorMapPanel.getComponents();
+    boolean cmExists = colorMap_ != null;
+    for(int i=0; i < list.length; i++) {
+      list[i].setEnabled(cmExists);
+    }
+    newColorMapButton.setEnabled(true);
+  }
+
+  private void setCurrentTab() {
+    if(!TabbedPane.isEnabledAt(TabbedPane.getSelectedIndex())) {
+      //
+      // change to other tab
+      //
+      if(TabbedPane.getSelectedIndex() == colorMapIndex_) {
+        TabbedPane.setSelectedIndex(contourLevelIndex_);
+      } else {
+        TabbedPane.setSelectedIndex(colorMapIndex_);
+      }
+    }
+  }
+
+  private void initContourLevels() {
+    createConLevelTable();
+  }
+
+  private void initColorMap() {
+    ColorSwatchIcon csi;
+    int i;
+    if(colorMap_ instanceof IndexedColor) {
+      int maxindx = ((IndexedColor)colorMap_).getMaximumIndex();
+      for(i=0; i <= maxindx; i++) {
+        csi = new ColorSwatchIcon((IndexedColor)colorMap_, i, 8);
+        colorButtons_[i].setIcon(csi);
+        colorButtons_[i].setEnabled(true);
+      }
+      for(i=maxindx+1; i < 256; i++) {
+        csi = new ColorSwatchIcon(Color.white, 8, 8);
+        colorButtons_[i].setIcon(csi);
+        colorButtons_[i].setEnabled(false);
+      }
+      ((CardLayout)colorPanel.getLayout()).show(colorPanel, "Indexed");
+    }
+  }
+
+  void updateGridAttribute() {
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(true, "GridAttributeDialog");
+      }
+    }
+    updateConLevels();
+    attr_.setContourLevels(conLevels_);
+    attr_.setColorMap(colorMap_);
+    attr_.setStyle(gridStyleComboBox.getSelectedIndex());
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(false, "GridAttributeDialog");
+      }
+    }
+  }
+  /**
+   * Test entry point.
+   */
+  public static void main(String[] args) {
+    Range2D range = new Range2D(-20.0f, 45.0f, 5.0f);
+    ContourLevels clevels = ContourLevels.getDefault(range);
+    GridAttribute attr = new GridAttribute(clevels);
+    GridAttributeDialog la = new GridAttributeDialog();
+    la.setGridAttribute(attr);
+    la.setTitle("Test GridAttribute Dialog");
+    la.setVisible(true);
+  }
+
+  void gridStyleComboBox_actionPerformed(java.awt.event.ActionEvent event) {
+    int style = gridStyleComboBox.getSelectedIndex();
+    //
+    enableContourLevels(style);
+    enableColorMap(style);
+    setCurrentTab();
+    //
+  }
+
+  void newConLevelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    NewLevelsDialog nld = new NewLevelsDialog();
+    int result = nld.showDialog(grid_);
+    if(result == NewLevelsDialog.OK_RESPONSE) {
+      Range2D range = nld.getRange();
+      conLevels_ = ContourLevels.getDefault(range);
+      initContourLevels();
+    }
+  }
+
+  void newColorMapButton_actionPerformed(java.awt.event.ActionEvent event) {
+    //
+    // this will be replaced by a specialized dialog
+    //
+    //
+    // define default colormap (ps.64)
+    //
+    int[] red =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  7, 23, 39, 55, 71, 87,103,
+       119,135,151,167,183,199,215,231,
+       247,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,246,228,211,193,175,158,140};
+    int[] green =
+    {  0,  0,  0,  0,  0,  0,  0,  0,
+       0, 11, 27, 43, 59, 75, 91,107,
+       123,139,155,171,187,203,219,235,
+       251,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0};
+    int[] blue =
+    {  0,143,159,175,191,207,223,239,
+       255,255,255,255,255,255,255,255,
+       255,255,255,255,255,255,255,255,
+       255,247,231,215,199,183,167,151,
+       135,119,103, 87, 71, 55, 39, 23,
+       7,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0};
+    //
+    colorMap_ = new IndexedColorMap(red, green, blue);
+    ((IndexedColorMap)colorMap_).setTransform(new LinearTransform(0.0,
+                                              (double)red.length,
+                                               0.0, 1.0));
+    initColorMap();
+  }
+
+  void loadColorMapButton_actionPerformed(ActionEvent event) {
+    int[] r = new int[256];
+    int[] g = new int[256];
+    int[] b = new int[256];
+    int lastindx = -1;
+    File file = null;
+    StreamTokenizer st = null;
+    JFileChooser chooser = new JFileChooser("C:/local/pal");
+    int returnVal = chooser.showOpenDialog(this);
+    if(returnVal == JFileChooser.APPROVE_OPTION) {
+      file = chooser.getSelectedFile();
+      try {
+        Reader rdr = new BufferedReader(new FileReader(file));
+        st = new StreamTokenizer(rdr);
+      } catch (java.io.FileNotFoundException e) {
+        System.out.println(e);
+        return;
+      }
+      try {
+        st.nextToken();
+        while(st.ttype != StreamTokenizer.TT_EOF) {
+          lastindx++;
+          if(st.ttype == StreamTokenizer.TT_NUMBER) {
+            r[lastindx] = (int)st.nval;
+            st.nextToken();
+            g[lastindx] = (int)st.nval;
+            st.nextToken();
+            b[lastindx] = (int)st.nval;
+          }
+          if(st.nextToken() == StreamTokenizer.TT_EOL) st.nextToken();
+        }
+      } catch (java.io.IOException e) {
+        System.out.println(e);
+      }
+      int[] red = new int[lastindx+1];
+      int[] green = new int[lastindx+1];
+      int[] blue = new int[lastindx+1];
+      for(int i=0; i <= lastindx; i++) {
+        red[i] = r[i];
+        green[i] = g[i];
+        blue[i] = b[i];
+      }
+      colorMap_ = new IndexedColorMap(red, green, blue);
+      ((IndexedColorMap)colorMap_).setTransform(new LinearTransform(0.0,
+                                                                    (double)red.length,
+                                                                    0.0, 1.0));
+      initColorMap();
+    }
+  }
+
+  void editButton_actionPerformed(java.awt.event.ActionEvent event) {
+    ContourLineAttribute attr;
+    int index = conLevelTable_.getSelectedRow();
+    if(index < 0) return;
+    ContourLineAttributeDialog clad = new ContourLineAttributeDialog();
+    attr = (ContourLineAttribute)
+      ((ContourLineAttribute)conLevelModel_.getValueAt(index,1)).copy();
+    int result = clad.showDialog(attr);
+    if(result == ContourLineAttributeDialog.OK_RESPONSE) {
+      attr = clad.getContourLineAttribute();
+      conLevelModel_.setValueAt(attr, index, 1);
+    }
+  }
+
+  void aboveButton_actionPerformed(java.awt.event.ActionEvent event) {
+    int index = conLevelTable_.getSelectedRow();
+    if(index < 0) return;
+    conLevelModel_.insert(index,
+                          new Double(0.0),
+                          new ContourLineAttribute(ContourLineAttribute.SOLID));
+  }
+
+  void belowButton_actionPerformed(java.awt.event.ActionEvent event) {
+    int index = conLevelTable_.getSelectedRow();
+    if(index < 0) return;
+    conLevelModel_.insert(index + 1,
+                          new Double(0.0),
+                          new ContourLineAttribute(ContourLineAttribute.SOLID));
+  }
+
+  void deleteButton_actionPerformed(java.awt.event.ActionEvent event) {
+    int index = conLevelTable_.getSelectedRow();
+    if(index < 0) return;
+    conLevelModel_.remove(index);
+  }
+
+  void sortButton_actionPerformed(java.awt.event.ActionEvent event) {
+    conLevelModel_.sort();
+  }
+
+  void defaultButton_actionPerformed(java.awt.event.ActionEvent event) {
+    DefaultContourLineAttribute attr;
+    DefaultContourLineAttributeDialog dclad = new DefaultContourLineAttributeDialog();
+    attr = conLevels_.getDefaultContourLineAttribute();
+    int result = dclad.showDialog((DefaultContourLineAttribute)attr.copy());
+    if(result == DefaultContourLineAttributeDialog.OK_RESPONSE) {
+      attr = dclad.getDefaultContourLineAttribute();
+      conLevels_.setDefaultContourLineAttribute(attr);
+    }
+  }
+
+  void saveColorMapButton_actionPerformed(java.awt.event.ActionEvent event) {
+    // to do: code goes here.
+  }
+
+  void createConLevelTable() {
+    Double val;
+    ContourLineAttribute attr;
+    conLevelModel_ = new ConLevelTableModel();
+    conLevelTable_ = new JTable(conLevelModel_);
+    conLevelTable_.setSize(1000,1000);
+    ListSelectionModel lsm = conLevelTable_.getSelectionModel();
+    lsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+    TableColumn tc;
+    tc = conLevelTable_.getColumnModel().getColumn(0);
+    tc.setPreferredWidth(250);
+    tc = conLevelTable_.getColumnModel().getColumn(1);
+    tc.setPreferredWidth(750);
+    gridScrollPane.getViewport().add(conLevelTable_);
+    //
+    if(conLevels_ == null) return;
+    int size = conLevels_.size();
+    for(int i=0; i < size; i++) {
+      try {
+        val = new Double(conLevels_.getLevel(i));
+        attr = conLevels_.getContourLineAttribute(i);
+        conLevelModel_.add(val, attr);
+      } catch (ContourLevelNotFoundException e) {
+        System.out.println(e);
+      }
+    }
+  }
+
+  private void updateConLevels() {
+    if(conLevels_ == null) return;
+    ContourLevels cl = new ContourLevels();
+    Double val;
+    ContourLineAttribute attr;
+    conLevelModel_.sort();
+    int size = conLevelModel_.getRowCount();
+    for(int i=0; i < size; i++) {
+      val = (Double)conLevelModel_.getValueAt(i,0);
+      attr = (ContourLineAttribute)conLevelModel_.getValueAt(i,1);
+      cl.addLevel(val.doubleValue(), attr);
+    }
+    cl.setDefaultContourLineAttribute(conLevels_.getDefaultContourLineAttribute());
+    conLevels_ = cl;
+  }
+
+  class ConLevelTableModel extends AbstractTableModel {
+    Vector values = new Vector();
+    Vector attr = new Vector();
+    String[] titles = {"Value", "Attribute"};
+
+    public void add(Double val, ContourLineAttribute cla) {
+      values.addElement(val);
+      attr.addElement(cla);
+    }
+
+    public void insert(int row, Double val, ContourLineAttribute cla) {
+      values.insertElementAt(val, row);
+      attr.insertElementAt(cla, row);
+      fireTableChanged(new TableModelEvent(this, row, row,
+                                           TableModelEvent.ALL_COLUMNS,
+                                           TableModelEvent.INSERT));
+    }
+
+    public void remove(int row) {
+      values.removeElementAt(row);
+      attr.removeElementAt(row);
+      fireTableChanged(new TableModelEvent(this, row, row,
+                                           TableModelEvent.ALL_COLUMNS,
+                                           TableModelEvent.DELETE));
+    }
+
+    public void sort() {
+      //
+      // use brain-dead bubble sort (there will be few lines)
+      //
+      int i, temp;
+      int size = values.size();
+      Double a, b;
+      int[] index = new int[size];
+      boolean flipped = true;
+      for(i=0; i < size; i++) {
+        index[i] = i;
+      }
+      while(flipped) {
+        flipped = false;
+        for(i=0; i < size-1; i++) {
+          a = (Double)values.elementAt(index[i]);
+          b = (Double)values.elementAt(index[i+1]);
+          if(a.doubleValue() > b.doubleValue()) {
+            //    if(a.compareTo(b) > 0) { // jdk1.2
+            temp = index[i];
+            index[i] = index[i+1];
+            index[i+1] = temp;
+            flipped = true;
+          }
+        }
+      }
+      Vector oldValues = values;
+      Vector oldAttr = attr;
+      values = new Vector(size);
+      attr = new Vector(size);
+      for(i=0; i < size; i++) {
+        values.addElement(oldValues.elementAt(index[i]));
+        attr.addElement(oldAttr.elementAt(index[i]));
+      }
+      fireTableChanged(new TableModelEvent(this));
+    }
+
+    public Object getValueAt(int row, int col) {
+      if(col == 0) {
+        return values.elementAt(row);
+      } else {
+        return attr.elementAt(row);
+      }
+    }
+
+    public void setValueAt(Object obj, int row, int col) {
+      if(col == 0) {
+        if(obj instanceof Double) {
+          values.setElementAt(obj, row);
+        } else if(obj instanceof String) {
+          values.setElementAt(new Double((String)obj), row);
+        }
+      } else {
+        attr.setElementAt(obj, row);
+      }
+      fireTableCellUpdated(row, col);
+    }
+
+    public int getRowCount() {
+      return values.size();
+    }
+
+    public int getColumnCount() {
+      return 2;
+    }
+
+    public String getColumnName(int col) {
+      return titles[col];
+    }
+
+    public boolean isCellEditable(int row, int col) {
+      return col == 0;
+    }
+
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GridBagConstraints.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GridBagConstraints.java
new file mode 100755
index 0000000..8e2ec50
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/GridBagConstraints.java
@@ -0,0 +1,57 @@
+/*
+ * $Id: GridBagConstraints.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+/**
+ * Creates a <code>GridBagConstraints</code> object from the
+ * constructor.  This class duplicates functionality available in jdk1.2
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class GridBagConstraints extends java.awt.GridBagConstraints {
+
+/**
+  * Creates a <code>GridBagConstraint</code> object.
+  */
+
+    public GridBagConstraints(int gridX,
+        int gridY,
+        int gridWidth,
+        int gridHeight,
+        double weightX,
+        double weightY,
+        int anchor,
+        int fills,
+        java.awt.Insets inset,
+        int ipadX,
+        int ipadY) {
+
+        gridx = gridX;
+        gridy = gridY;
+        gridwidth = gridWidth;
+        gridheight = gridHeight;
+        weightx = weightX;
+        weighty = weightY;
+        this.anchor = anchor;
+        fill = fills;
+        insets = inset;
+        ipadx = ipadX;
+        ipady = ipadY;
+
+    }
+}
+
+
+
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/LineAttributeDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/LineAttributeDialog.java
new file mode 100755
index 0000000..c149753
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/LineAttributeDialog.java
@@ -0,0 +1,587 @@
+/*
+ * $Id: LineAttributeDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.sgt.JPane;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.StringTokenizer;
+
+import gov.noaa.pmel.sgt.LineAttribute;
+import gov.noaa.pmel.sgt.swing.PlotMarkIcon;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import javax.swing.border.*;
+import java.awt.event.*;
+
+/**
+ * Edits a <code>LineAttribute</code>. This dialog does not
+ * make a copy of the attribute so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties unless
+ * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching}
+ * has been turned on.
+ *
+ * <p> Example of <code>LineAttributeDialog</code> use:
+ * <pre>
+ * public void editLineAttribute(LineAttribute attr) {
+ *   LineAttributeDialog lad = new LineAttributeDialog();
+ *   lad.setLineAttribute(attr);
+ *   lad.setVisible(true);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ * @see PlotMarkDialog
+ * @see ArrayEditDialog
+ */
+public class LineAttributeDialog extends JDialog {
+  private LineAttribute attr_;
+  private PlotMarkIcon pmIcon_;
+  private int mark_;
+  private JPane[] paneList_ = null;
+  /**
+   * Constructor.
+   */
+  public LineAttributeDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+
+  void jbInit() throws Exception {
+    {
+      String[] tempString = new String[7];
+      tempString[0] = "SOLID";
+      tempString[1] = "DASHED";
+      tempString[2] = "HEAVY";
+      tempString[3] = "HIGHLIGHT";
+      tempString[4] = "MARK";
+      tempString[5] = "MARK & SOLID";
+      tempString[6] = "STROKE";
+      for(int i=0; i < tempString.length; i++) {
+        lineStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "BUTT";
+      tempString[1] = "ROUND";
+      tempString[2] = "SQUARE";
+      for(int i=0; i < tempString.length; i++) {
+        capStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "MITER";
+      tempString[1] = "ROUND";
+      tempString[2] = "BEVEL";
+      for(int i=0; i < tempString.length; i++) {
+        miterStyleCBM.addElement(tempString[i]);
+      }
+    }
+    strokeBorder = new TitledBorder("");
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(500,490);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    strokePanel.setBorder(strokeBorder);
+    strokePanel.setLayout(gridBagLayout1);
+    strokeBorder.setTitle("Stroke Line Attributes");
+    JLabel10.setText(" Width:");
+    widthTextField.setColumns(10);
+    JLabel8.setText("Dash Array:");
+    dashArrayPanel.setLayout(flowLayout1);
+    arrayEditor.setActionCommand("...");
+    JLabel9.setText("Dash Phase:");
+    dashPhaseTextField.setColumns(10);
+    jLabel1.setText("Cap Style:");
+    jLabel2.setText("Miter Style:");
+    jLabel3.setText("Miter Limit:");
+    miterLimitTextField.setColumns(10);
+    capStyleComboBox.setModel(capStyleCBM);
+    miterStyleComboBox.setModel(miterStyleCBM);
+    lineStyleComboBox.addActionListener(new LineAttributeDialog_lineStyleComboBox_actionAdapter(this));
+    dashArrayTextField.setColumns(28);
+    getContentPane().add(buttonPanel, "South");
+    buttonPanel.setBounds(0,263,430,39);
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    okButton.setBounds(115,7,51,25);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    applyButton.setBounds(171,7,65,25);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    cancelButton.setBounds(241,7,73,25);
+    //$$ etchedBorder1.move(0,300);
+    mainPanel.setLayout(new GridBagLayout());
+    getContentPane().add(mainPanel, "Center");
+    mainPanel.setBounds(0,0,430,263);
+    JLabel1.setText("Color:");
+    mainPanel.add(JLabel1,  new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(15, 15, 5, 5), 0, 0));
+    JLabel1.setBounds(65,43,33,15);
+    colorPanel.setBorder(etchedBorder1);
+    mainPanel.add(colorPanel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(15, 5, 5, 15), 0, 0));
+    colorPanel.setBounds(108,29,295,39);
+    JLabel5.setText("Line Style:");
+    mainPanel.add(JLabel5,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 15, 5, 5), 0, 0));
+    JLabel5.setBounds(40,80,58,15);
+    lineStyleComboBox.setModel(lineStyleCBM);
+    mainPanel.add(lineStyleComboBox, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 15), 0, 0));
+    lineStyleComboBox.setBounds(108,73,92,24);
+    JLabel6.setText("Mark:");
+    mainPanel.add(JLabel6,  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 15, 5, 5), 0, 0));
+    JLabel6.setBounds(66,133,32,15);
+    markPanel.setLayout(flowLayout2);
+    mainPanel.add(markPanel, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 15), 0, 0));
+    markPanel.setBounds(108,126,48,25);
+    markPanel.add(plotMarkIconLabel, null);
+    plotMarkIconLabel.setForeground(java.awt.Color.black);
+    plotMarkIconLabel.setBounds(0,0,0,0);
+    markEditor.setActionCommand("...");
+    markPanel.add(markEditor, null);
+    JLabel7.setText("MarkHeight:");
+    mainPanel.add(JLabel7,  new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 22, 5, 5), 0, 0));
+    JLabel7.setBounds(30,160,68,15);
+    markHeightTextField.setColumns(10);
+    mainPanel.add(markHeightTextField, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(0, 5, 5, 15), 0, 0));
+    markHeightTextField.setBounds(108,156,110,19);
+    mainPanel.add(strokePanel, new GridBagConstraints(0, 5, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 10, 15, 10), 0, 0));
+    strokePanel.add(JLabel10,  new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(widthTextField,   new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(JLabel8,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(dashArrayPanel,   new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 5), 0, 0));
+    dashArrayPanel.add(dashArrayTextField, null);
+    dashArrayPanel.add(arrayEditor, null);
+    strokePanel.add(JLabel9,  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(dashPhaseTextField,  new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel1,  new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel2,  new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(capStyleComboBox,  new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(miterStyleComboBox,  new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel3,  new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    strokePanel.add(miterLimitTextField,  new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    //$$ stringComboBoxModel1.move(24,300);
+    lineStyleComboBox.setSelectedIndex(0);
+    setTitle("LineAttribute Properties");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    markEditor.addActionListener(lSymAction);
+    arrayEditor.addActionListener(lSymAction);
+
+    //
+    pmIcon_ = new PlotMarkIcon(1);
+    plotMarkIconLabel.setIcon(pmIcon_);
+    //
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public LineAttributeDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public LineAttributeDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == LineAttributeDialog.this)
+  LineAttributeDialog_WindowClosing(event);
+    }
+  }
+
+  void LineAttributeDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  ColorEntryPanel colorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JComboBox lineStyleComboBox = new javax.swing.JComboBox();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JPanel markPanel = new javax.swing.JPanel();
+  javax.swing.JLabel plotMarkIconLabel = new javax.swing.JLabel();
+  ThreeDotsButton markEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JTextField markHeightTextField = new javax.swing.JTextField();
+  DefaultComboBoxModel lineStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel capStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel miterStyleCBM = new DefaultComboBoxModel();
+  JPanel strokePanel = new JPanel();
+  TitledBorder strokeBorder;
+  GridBagLayout gridBagLayout1 = new GridBagLayout();
+  JLabel JLabel10 = new javax.swing.JLabel();
+  JTextField widthTextField = new javax.swing.JTextField();
+  JLabel JLabel8 = new javax.swing.JLabel();
+  JTextField dashArrayTextField = new javax.swing.JTextField();
+  JPanel dashArrayPanel = new javax.swing.JPanel();
+  ThreeDotsButton arrayEditor = new ThreeDotsButton();
+  JLabel JLabel9 = new javax.swing.JLabel();
+  JTextField dashPhaseTextField = new javax.swing.JTextField();
+  JLabel jLabel1 = new JLabel();
+  JLabel jLabel2 = new JLabel();
+  JComboBox capStyleComboBox = new JComboBox();
+  JComboBox miterStyleComboBox = new JComboBox();
+  JLabel jLabel3 = new JLabel();
+  JTextField miterLimitTextField = new JTextField();
+  private FlowLayout flowLayout1 = new FlowLayout();
+  private FlowLayout flowLayout2 = new FlowLayout();
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == markEditor)
+        markEditor_actionPerformed(event);
+      else if (object == arrayEditor)
+        arrayEditor_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateLineAttribute();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateLineAttribute();
+  }
+  /**
+   * Set the <code>LineAttribute</code> for the dialog.
+   */
+  public void setLineAttribute(LineAttribute attr) {
+    attr_ = attr;
+    //
+    // Color
+    //
+    colorPanel.setColor(attr_.getColor());
+    //
+    // style
+    //
+    lineStyleComboBox.setSelectedIndex(attr_.getStyle());
+    //
+    // mark
+    //
+    int mark = attr_.getMark();
+    changeMark(mark);
+    //
+    // mark height
+    //
+    markHeightTextField.setText(Double.toString(attr_.getMarkHeightP()));
+    //
+    // Stroke line attributes
+    //
+    // width
+    //
+    widthTextField.setText(Float.toString(attr_.getWidth()));
+    //
+    // dash Array
+    //
+    float[] da = attr_.getDashArray();
+    dashArrayTextField.setText(dashArrayString(da));
+    //
+    // dash phase
+    //
+    dashPhaseTextField.setText(Float.toString(attr_.getDashPhase()));
+    //
+    // cap style
+    //
+    capStyleComboBox.setSelectedIndex(attr_.getCapStyle());
+    //
+    // miter style
+    //
+    miterStyleComboBox.setSelectedIndex(attr_.getMiterStyle());
+    //
+    // miter limit
+    //
+    miterLimitTextField.setText(Float.toString(attr_.getMiterLimit()));
+    //
+    // test for stroke panel enabled
+    //
+    strokePanelEnabled(lineStyleComboBox.getSelectedIndex() == LineAttribute.STROKE);
+  }
+
+  private String dashArrayString(float[] da) {
+    if(da == null) {
+      return "null";
+    }
+    StringBuffer sbuf = new StringBuffer("{");
+    for(int i=0; i < da.length; i++) {
+      sbuf.append(Float.toString(da[i]) + ", ");
+    }
+    sbuf.setLength(sbuf.length()-2);
+    sbuf.append("}");
+    return sbuf.toString();
+  }
+  private float[] dashArray() {
+    String arrayString = dashArrayTextField.getText();
+    int start = arrayString.indexOf("{");
+    int stop = arrayString.indexOf("}");
+    String sub = arrayString.substring(start+1,stop);
+    //
+    // parse array
+    //
+    StringTokenizer token = new StringTokenizer(sub, ",");
+    int index = 0;
+    float[] array = new float[token.countTokens()];
+    while(token.hasMoreTokens()) {
+      array[index] = new Float(token.nextToken()).floatValue();
+      index++;
+    }
+    return array;
+  }
+
+  void updateLineAttribute() {
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(true, "LineAttributeDialog");
+      }
+    }
+    attr_.setBatch(true);
+    //
+    // Color
+    //
+    attr_.setColor(colorPanel.getColor());
+    //
+    // style
+    //
+    attr_.setStyle(lineStyleComboBox.getSelectedIndex());
+    //
+    // mark
+    //
+    attr_.setMark(mark_);
+    //
+    // mark height
+    //
+    attr_.setMarkHeightP(new Double(markHeightTextField.getText()).doubleValue());
+    //
+    // stroke attributes
+    //
+    //
+    // width
+    //
+    attr_.setWidth(new Float(widthTextField.getText()).floatValue());
+    //
+    // dash array
+    //
+    attr_.setDashArray(dashArray());
+    //
+    // dash phase
+    //
+    attr_.setDashPhase(new Float(dashPhaseTextField.getText()).floatValue());
+    //
+    // cap style
+    //
+    attr_.setCapStyle(capStyleComboBox.getSelectedIndex());
+    //
+    // miter style
+    //
+    attr_.setMiterStyle(miterStyleComboBox.getSelectedIndex());
+    //
+    // miter limit
+    //
+    attr_.setMiterLimit(new Float(miterLimitTextField.getText()).floatValue());
+
+    attr_.setBatch(false);
+    //
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(false, "LineAttributeDialog");
+      }
+    }
+  }
+  /**
+   * Dialog test entry.
+   */
+  public static void main(String[] args) {
+    LineAttribute attr = new LineAttribute();
+    LineAttributeDialog la = new LineAttributeDialog();
+    la.setLineAttribute(attr);
+    la.setTitle("Test LineAttribute Dialog");
+    la.setVisible(true);
+  }
+
+  void markEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    PlotMarkDialog pmd = new PlotMarkDialog();
+    Point loc = markEditor.getLocationOnScreen();
+    pmd.setLocation(loc.x, loc.y);
+    int result = pmd.showDialog(mark_);
+    if(result == PlotMarkDialog.OK_RESPONSE) {
+      changeMark(pmd.getMark());
+    }
+  }
+  private void changeMark(int mark) {
+    mark_ = mark;
+    pmIcon_.setMark(mark);
+    plotMarkIconLabel.repaint();
+  }
+
+  void arrayEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    ArrayEditDialog aed = new ArrayEditDialog();
+    Point loc = arrayEditor.getLocationOnScreen();
+    aed.setLocation(loc.x, loc.y);
+    aed.setArray(dashArray());
+    int result = aed.showDialog();
+    if(result == ArrayEditDialog.OK_RESPONSE) {
+      dashArrayTextField.setText(dashArrayString(aed.getFloatArray()));
+    }
+  }
+
+  void lineStyleComboBox_actionPerformed(ActionEvent e) {
+    strokePanelEnabled(lineStyleComboBox.getSelectedIndex() == LineAttribute.STROKE);
+  }
+
+  void strokePanelEnabled(boolean enabled) {
+    widthTextField.setEnabled(enabled);
+    dashArrayTextField.setEnabled(enabled);
+    arrayEditor.setEnabled(enabled);
+    dashPhaseTextField.setEnabled(enabled);
+    capStyleComboBox.setEnabled(enabled);
+    miterStyleComboBox.setEnabled(enabled);
+    miterLimitTextField.setEnabled(enabled);
+  }
+  /**
+   * Set the parent <code>JPane</code>.  This reference to
+   * <code>JPane</code> is used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time.
+   */
+  public void setJPane(JPane pane) {
+    paneList_ = new JPane[1];
+    paneList_[0] = pane;
+  }
+  /** Get the first parent pane. */
+  public JPane getJPane() {
+    if(paneList_ != null) {
+      return paneList_[0];
+    } else {
+      return null;
+    }
+  }
+  /**
+   * Set the parent <code>JPane</code>s.  These references to
+   * <code>JPane</code> are used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time. A second
+   * <code>JPane</code> is often used for a <code>LineKey</code>.
+   */
+  public void setJPaneList(JPane[] list) {
+    paneList_ = list;
+  }
+  /** Get an array of parent panes. */
+  public JPane[] getJPaneList() {
+    return paneList_;
+  }
+}
+
+class LineAttributeDialog_lineStyleComboBox_actionAdapter implements java.awt.event.ActionListener {
+  LineAttributeDialog adaptee;
+
+  LineAttributeDialog_lineStyleComboBox_actionAdapter(LineAttributeDialog adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.lineStyleComboBox_actionPerformed(e);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/LogoDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/LogoDialog.java
new file mode 100755
index 0000000..fbba558
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/LogoDialog.java
@@ -0,0 +1,374 @@
+/*
+ * $Id: LogoDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+
+import gov.noaa.pmel.sgt.Logo;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+
+import javax.swing.*;
+import java.awt.*;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Edits a <code>Logo</code> object.  This dialog does not make a copy
+ * of the object so changes "Applied" will cause <code>sgt</code> to
+ * redraw the plot using the new <code>Logo</code> properties.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class LogoDialog extends JDialog implements PropertyChangeListener {
+  private Logo logo_;
+  private JPane pane_ = null;
+  private boolean ignoreEvent_ = false;
+  /**
+   * Constructor.
+   */
+  public LogoDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(457,294);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,324);
+    mainPanel.setLayout(new GridBagLayout());
+    getContentPane().add(mainPanel, "Center");
+    positionPanel.setBorder(positionBorder);
+    positionPanel.setLayout(new GridBagLayout());
+    mainPanel.add(positionPanel, new GridBagConstraints(0,0,2,1,0.0,0.0,
+                                                        GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel1.setText("X Position:");
+    positionPanel.add(JLabel1, new GridBagConstraints(0,0,1,1,0.0,0.0,
+                                                      GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    xPosTextField.setColumns(20);
+    positionPanel.add(xPosTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+                                                            GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel2.setText("Y Position:");
+    positionPanel.add(JLabel2, new GridBagConstraints(0,1,1,1,0.0,0.0,
+                                                      GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    yPosTextField.setColumns(20);
+    positionPanel.add(yPosTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+                                                            GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    alignPanel.setBorder(alignBorder);
+    alignPanel.setLayout(new GridBagLayout());
+    mainPanel.add(alignPanel, new GridBagConstraints(0,1,1,1,0.0,0.0,
+                                                     GridBagConstraints.WEST,GridBagConstraints.VERTICAL,new Insets(5,0,5,0),20,15));
+    JLabel3.setText("Horizontal:");
+    alignPanel.add(JLabel3, new GridBagConstraints(0,0,1,1,0.0,0.0,
+                                                   GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    horizComboBox.setModel(horizCBModel);
+    alignPanel.add(horizComboBox, new GridBagConstraints(1,0,1,1,0.0,0.0,
+                                                         GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    JLabel4.setText("Vertical:");
+    alignPanel.add(JLabel4, new GridBagConstraints(0,1,1,1,0.0,0.0,
+                                                   GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    vertComboBox.setModel(vertCBModel);
+    alignPanel.add(vertComboBox, new GridBagConstraints(1,1,1,1,0.0,0.0,
+                                                        GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    optionPanel.setBorder(optionBorder);
+    optionPanel.setLayout(new GridBagLayout());
+    mainPanel.add(optionPanel, new GridBagConstraints(1,1,1,1,0.0,0.0,
+                                                      GridBagConstraints.CENTER,GridBagConstraints.VERTICAL,new Insets(5,10,5,0),20,15));
+    JLabel7.setText("Visible:");
+    optionPanel.add(JLabel7, new GridBagConstraints(0,4,1,1,0.0,0.0,
+                                                    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelVisibleCheckBox.setSelected(true);
+    optionPanel.add(labelVisibleCheckBox, new GridBagConstraints(1,4,1,1,0.0,0.0,
+                                                                 GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    JLabel6.setText("Selectable:");
+    optionPanel.add(JLabel6, new GridBagConstraints(0,5,1,1,0.0,0.0,
+                                                    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelSelectableCheckBox.setSelected(true);
+    optionPanel.add(labelSelectableCheckBox, new GridBagConstraints(1,5,1,1,0.0,0.0,
+                                                                    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "LEFT";
+      tempString[1] = "CENTER";
+      tempString[2] = "RIGHT";
+      for(int i=0; i < tempString.length; i++) {
+        horizCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "TOP";
+      tempString[1] = "MIDDLE";
+      tempString[2] = "BOTTOM";
+      for(int i=0; i < tempString.length; i++) {
+        vertCBModel.addElement(tempString[i]);
+      }
+    }
+    vertComboBox.setSelectedIndex(2);
+    horizComboBox.setSelectedIndex(0);
+    setTitle("SGLabel");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+
+  public LogoDialog(String title) {
+    this();
+    setTitle(title);
+  }
+
+  public LogoDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible.
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == LogoDialog.this)
+        FontDialog_WindowClosing(event);
+    }
+  }
+
+  void FontDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    finish();
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+  javax.swing.JPanel positionPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JTextField xPosTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel2 = new javax.swing.JLabel();
+  javax.swing.JTextField yPosTextField = new javax.swing.JTextField();
+  javax.swing.JPanel alignPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
+  javax.swing.JComboBox horizComboBox = new javax.swing.JComboBox();
+  javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
+  javax.swing.JComboBox vertComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel optionPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelVisibleCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelSelectableCheckBox = new javax.swing.JCheckBox();
+  javax.swing.border.TitledBorder alignBorder = new javax.swing.border.TitledBorder("Alignment");
+  javax.swing.border.TitledBorder positionBorder = new javax.swing.border.TitledBorder("Position");
+  DefaultComboBoxModel horizCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel vertCBModel = new DefaultComboBoxModel();
+  javax.swing.border.TitledBorder optionBorder = new javax.swing.border.TitledBorder("Options");
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      if (object == applyButton)
+        applyButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    finish();
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    finish();
+    updateLogo();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateLogo();
+  }
+  /**
+   * Test entry point.
+   */
+  public static void main(String[] args) {
+    LogoDialog la = new LogoDialog();
+    la.setTitle("Test Logo Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Set the <code>Logo</code> to be edited and <code>JPane</code>.  With
+   * <code>JPane</code> set the dialog will use
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} when
+   * updating the <code>Logo</code> properties.
+   */
+  public void setLogo(Logo logo, JPane pane) {
+    setJPane(pane);
+    setLogo(logo);
+  }
+  /**
+   * Set the <code>Logo</code> to be edited.
+   */
+  public void setLogo(Logo logo) {
+    logo_ = logo;
+    logo_.addPropertyChangeListener(this);
+    ignoreEvent_ = false;
+    setLogo();
+  }
+  /**
+   * Get the edited <code>Logo</code>
+   */
+  public Logo getLogo() {
+    return logo_;
+  }
+  /**
+   * Set the parent <code>JPane</code>. With
+   * <code>JPane</code> set the dialog will use
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} when
+   * updating the <code>Logo</code> properties.
+   */
+  public void setJPane(JPane pane) {
+    pane_ = pane;
+  }
+  /**
+   * Get the parent <code>JPane</code>.
+   */
+  public JPane getJPane() {
+    return pane_;
+  }
+
+  private void setLogo() {
+    //
+    // label Id
+    //
+    setTitle("Logo - " + logo_.getId());
+    //
+    // options
+    //
+    labelVisibleCheckBox.setSelected(logo_.isVisible());
+    labelSelectableCheckBox.setSelected(logo_.isSelectable());
+    //
+    // location
+    //
+    Point2D.Double locp = logo_.getLocationP();
+    xPosTextField.setText(String.valueOf(locp.x));
+    yPosTextField.setText(String.valueOf(locp.y));
+    //
+    // alignment
+    //
+    horizComboBox.setSelectedIndex(logo_.getHAlign());
+    vertComboBox.setSelectedIndex(logo_.getVAlign());
+  }
+
+  private void updateLogo() {
+    ignoreEvent_ = true;
+    if(pane_ != null) pane_.setBatch(true, "LogoDialog");
+    //
+    // options
+    //
+    logo_.setVisible(labelVisibleCheckBox.isSelected());
+    logo_.setSelectable(labelSelectableCheckBox.isSelected());
+    //
+    // Location
+    //
+    double x = Double.valueOf(xPosTextField.getText()).doubleValue();
+    double y = Double.valueOf(yPosTextField.getText()).doubleValue();
+    Point2D.Double locp = new Point2D.Double(x, y);
+    logo_.setLocationP(locp);
+    //
+    // alignment
+    //
+    logo_.setHAlign(horizComboBox.getSelectedIndex());
+    logo_.setVAlign(vertComboBox.getSelectedIndex());
+
+    if(pane_ != null) pane_.setBatch(false, "LogoDialog");
+    ignoreEvent_ = false;
+  }
+  private void finish() {
+    logo_.removePropertyChangeListener(this);
+  }
+  /** Used internally for property changes  */
+  public void propertyChange(PropertyChangeEvent event) {
+    if(ignoreEvent_) {
+      if(Debug.EVENT) System.out.println("Logo: ignore event");
+      return;
+    }
+    if(Debug.EVENT) {
+      System.out.println("LogoDialog: " + event);
+      System.out.println("            " + event.getPropertyName());
+    }
+    if(event.getPropertyName().equals("location")) {
+      Point2D.Double locp = logo_.getLocationP();
+      xPosTextField.setText(String.valueOf(locp.x));
+      yPosTextField.setText(String.valueOf(locp.y));
+    }
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/NewLevelsDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/NewLevelsDialog.java
new file mode 100755
index 0000000..c6b99cf
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/NewLevelsDialog.java
@@ -0,0 +1,377 @@
+/*
+ * $Id: NewLevelsDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.sgt.Graph;
+
+import javax.swing.*;
+import java.awt.*;
+
+import gov.noaa.pmel.swing.JSlider2Double;
+
+/**
+ * Computes the range for creating a <code>ContourLevels</code>
+ * object. If a <code>SGTGrid</code> object is provided
+ * <code>NewLevelsDialog</code> can use the actual data range to help
+ * in creating the contour levels.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class NewLevelsDialog extends JDialog {
+  private int result_;
+  private SGTGrid grid_ = null;
+  private boolean useSpacing_ = false;
+  private boolean rangeComputed_ = false;
+  /** OK button selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Constructor.
+   */
+  public NewLevelsDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(282,366);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,444);
+    mainPanel.setLayout(new GridBagLayout());
+    getContentPane().add(mainPanel, "Center");
+    mainPanel.setBackground(new java.awt.Color(204,204,204));
+    JPanel1.setBorder(titledBorder1);
+    JPanel1.setLayout(new GridBagLayout());
+    mainPanel.add(JPanel1, new GridBagConstraints(0,0,1,1,0.0,0.0,
+						  GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0));
+    JLabel1.setText("Minimum:");
+    JPanel1.add(JLabel1,new GridBagConstraints(0,0,1,1,0.0,0.0,
+					       GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(5,10,5,2),0,0));
+    minTextField.setColumns(15);
+    JPanel1.add(minTextField,new GridBagConstraints(1,0,1,1,1.0,1.0,
+						    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,10),0,0));
+    JLabel2.setText("Maximum:");
+    JPanel1.add(JLabel2,new GridBagConstraints(0,1,1,1,0.0,0.0,
+					       GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(5,5,5,2),0,0));
+    maxTextField.setColumns(15);
+    JPanel1.add(maxTextField,new GridBagConstraints(1,1,1,1,1.0,1.0,
+						    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,10),0,0));
+    JPanel3.setBorder(titledBorder3);
+    JPanel3.setLayout(new GridBagLayout());
+    mainPanel.add(JPanel3, new GridBagConstraints(0,1,1,1,0.0,0.0,
+						  GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,5,0,5),0,0));
+    JLabel3.setText("Number:");
+    JPanel3.add(JLabel3,new GridBagConstraints(0,0,1,1,0.0,0.0,
+					       GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(5,10,0,2),0,0));
+    nlevelsTextField.setColumns(5);
+    JPanel3.add(nlevelsTextField,new GridBagConstraints(1,0,1,1,0.0,1.0,
+							GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,0,10),0,0));
+    JLabel5.setText("or");
+    JPanel3.add(JLabel5,new GridBagConstraints(0,1,1,1,0.0,0.0,
+					       GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+    JLabel5.setBackground(new java.awt.Color(204,204,204));
+    JLabel5.setForeground(new java.awt.Color(102,102,153));
+    JLabel4.setText("Spacing:");
+    JPanel3.add(JLabel4,new GridBagConstraints(0,2,1,1,0.0,0.0,
+					       GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,10,5,2),0,0));
+    spacingTextField.setColumns(15);
+    JPanel3.add(spacingTextField,new GridBagConstraints(1,2,1,1,0.0,1.0,
+							GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,5,10),0,0));
+    JPanel4.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    mainPanel.add(JPanel4, new GridBagConstraints(0,2,1,1,0.0,0.0,
+						  GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    computeButton.setText("Compute \"nice\" Range");
+    JPanel4.add(computeButton);
+    JPanel2.setBorder(titledBorder2);
+    JPanel2.setLayout(new GridBagLayout());
+    mainPanel.add(JPanel2, new GridBagConstraints(0,3,1,1,0.0,0.0,
+						  GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+    JLabel6.setText("Minimum:");
+    JPanel2.add(JLabel6,new GridBagConstraints(0,0,1,1,0.0,0.0,
+					       GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(5,10,5,2),0,0));
+    minCompTextField.setEditable(false);
+    minCompTextField.setColumns(15);
+    minCompTextField.setEnabled(false);
+    JPanel2.add(minCompTextField,new GridBagConstraints(1,0,1,1,1.0,1.0,
+							GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,10),0,0));
+    JLabel7.setText("Minimum:");
+    JPanel2.add(JLabel7,new GridBagConstraints(0,1,1,1,0.0,0.0,
+					       GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(5,5,5,2),0,0));
+    maxCompTextField.setEditable(false);
+    maxCompTextField.setColumns(15);
+    maxCompTextField.setEnabled(false);
+    JPanel2.add(maxCompTextField,new GridBagConstraints(1,1,1,1,0.0,1.0,
+							GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,10),0,0));
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    minTextField.addActionListener(lSymAction);
+    maxTextField.addActionListener(lSymAction);
+    nlevelsTextField.addActionListener(lSymAction);
+    spacingTextField.addActionListener(lSymAction);
+    SymPropertyChange lSymPropertyChange = new SymPropertyChange();
+    computeButton.addActionListener(lSymAction);
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public NewLevelsDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public NewLevelsDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == NewLevelsDialog.this)
+	NewLevelsDialog_WindowClosing(event);
+    }
+  }
+
+  void NewLevelsDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+  javax.swing.JPanel JPanel1 = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JTextField minTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel2 = new javax.swing.JLabel();
+  javax.swing.JTextField maxTextField = new javax.swing.JTextField();
+  javax.swing.JPanel JPanel3 = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
+  javax.swing.JTextField nlevelsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
+  javax.swing.JTextField spacingTextField = new javax.swing.JTextField();
+  javax.swing.JPanel JPanel4 = new javax.swing.JPanel();
+  javax.swing.JButton computeButton = new javax.swing.JButton();
+  javax.swing.JPanel JPanel2 = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JTextField minCompTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JTextField maxCompTextField = new javax.swing.JTextField();
+  javax.swing.border.TitledBorder titledBorder1 = new javax.swing.border.TitledBorder("Data Range");
+  javax.swing.border.TitledBorder titledBorder3 = new javax.swing.border.TitledBorder("Select");
+  javax.swing.border.TitledBorder titledBorder2 = new javax.swing.border.TitledBorder("Computed Range");
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+	cancelButton_actionPerformed(event);
+      else if (object == okButton)
+	okButton_actionPerformed(event);
+      else if (object == minTextField)
+	minTextField_actionPerformed(event);
+      else if (object == maxTextField)
+	maxTextField_actionPerformed(event);
+      else if (object == nlevelsTextField)
+	nlevelsTextField_actionPerformed(event);
+      else if (object == spacingTextField)
+	spacingTextField_actionPerformed(event);
+      else if (object == computeButton)
+        computeButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    this.setVisible(false);
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    NewLevelsDialog la = new NewLevelsDialog();
+    la.setTitle("Test New Levels Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Show the dialog and wait for a response.
+   *
+   * @param grid the data grid
+   * @return result, either CANCEL_RESPONSE or OK_RESPONSE
+   */
+  public int showDialog(SGTGrid grid) {
+    setGrid(grid);
+    result_ = CANCEL_RESPONSE;
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+  /**
+   * Return the computed or entered range.
+   */
+  public Range2D getRange() {
+    double min;
+    double max;
+    if(rangeComputed_) {
+      min = (new Double(minCompTextField.getText())).doubleValue();
+      max = (new Double(maxCompTextField.getText())).doubleValue();
+    } else {
+      min = (new Double(minTextField.getText())).doubleValue();
+      max = (new Double(maxTextField.getText())).doubleValue();
+    }
+    double delta = (new Double(spacingTextField.getText())).doubleValue();
+    Range2D range = new Range2D(min, max, delta);
+    return range;
+  }
+  /**
+   * Set the data grid for the computed range.
+   */
+  public void setGrid(SGTGrid grid) {
+    double zmin, zmax;
+    grid_ = grid;
+    if(grid_ == null) {
+      titledBorder1.setTitle("Enter Range");
+      zmin = 0.0;
+      zmax = 10.0;
+    } else {
+      zmin = Double.MAX_VALUE;
+      zmax = -Double.MAX_VALUE;
+      double[] z = grid_.getZArray();
+      for(int i=0; i < z.length; i++) {
+	if(Double.isNaN(z[i])) continue;
+	zmin = Math.min(zmin, z[i]);
+	zmax = Math.max(zmax, z[i]);
+      }
+    }
+    minTextField.setText(Double.toString(zmin));
+    maxTextField.setText(Double.toString(zmax));
+    useSpacing_ = false;
+    nlevelsTextField.setText("10");
+    updateLevSpac();
+  }
+
+  private void updateLevSpac() {
+    int levels;
+    double delta = (new Double(maxTextField.getText())).doubleValue() -
+      (new Double(minTextField.getText())).doubleValue();
+    double spacing;
+    if(useSpacing_) {
+      levels = (int)(delta/(new Double(spacingTextField.getText())).doubleValue());
+      nlevelsTextField.setText(Integer.toString(levels));
+    } else {
+      spacing = delta/(new Integer(nlevelsTextField.getText())).intValue();
+      spacingTextField.setText(Double.toString(spacing));
+    }
+  }
+
+  void minTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    updateLevSpac();
+  }
+
+  void maxTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    updateLevSpac();
+  }
+
+  void nlevelsTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    useSpacing_ = false;
+    updateLevSpac();
+  }
+
+  void spacingTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    useSpacing_ = true;
+    updateLevSpac();
+  }
+
+  class SymPropertyChange implements java.beans.PropertyChangeListener {
+    public void propertyChange(java.beans.PropertyChangeEvent event) {
+    }
+  }
+
+  void computeButton_actionPerformed(java.awt.event.ActionEvent event)	{
+    rangeComputed_ = true;
+    minCompTextField.setEnabled(true);
+    maxCompTextField.setEnabled(true);
+    double min = (new Double(minTextField.getText())).doubleValue();
+    double max = (new Double(maxTextField.getText())).doubleValue();
+    Range2D range = new Range2D(min,max);
+    int levels = Integer.parseInt(nlevelsTextField.getText());
+    Range2D newRange = Graph.computeRange(range, levels);
+    spacingTextField.setText(Double.toString(newRange.delta));
+    minCompTextField.setText(Double.toString(newRange.start));
+    maxCompTextField.setText(Double.toString(newRange.end));
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/PlotMarkDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/PlotMarkDialog.java
new file mode 100755
index 0000000..9511b3e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/PlotMarkDialog.java
@@ -0,0 +1,215 @@
+/*
+ * $Id: PlotMarkDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.*;
+
+import gov.noaa.pmel.sgt.swing.PlotMarkIcon;
+
+/**
+ * Provides a dialog to graphically select a <code>PlotMark</code>
+ * code.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class PlotMarkDialog extends JDialog {
+  private static final int numMarks = 51;
+  private int result_;
+  private int mark_;
+  private JToggleButton[] buttons_ = new JToggleButton[numMarks];
+  /** OK button selected */
+  public static int OK_RESPONSE = 1;
+  /** Cancel button selected */
+  public static int CANCEL_RESPONSE = 2;
+  /**
+   * Constructor
+   */
+  public PlotMarkDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(288,201);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    buttonPanel.setBounds(0,162,288,39);
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    okButton.setBounds(79,7,51,25);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    cancelButton.setBounds(135,7,73,25);
+    //$$ etchedBorder1.move(0,300);
+    mainPanel.setLayout(new GridLayout(4,11,0,0));
+    getContentPane().add(mainPanel, "Center");
+    mainPanel.setBounds(0,0,288,162);
+    setTitle("Select a Mark");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor
+   */
+  public PlotMarkDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor
+   */
+  public PlotMarkDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible.
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == PlotMarkDialog.this)
+        PlotMarkDialog_WindowClosing(event);
+    }
+  }
+
+  void PlotMarkDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JPanel mainPanel = new javax.swing.JPanel();
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+
+
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+    result_ = CANCEL_RESPONSE;
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    result_ = OK_RESPONSE;
+    for(int i=0; i < numMarks; i++) {
+      if(buttons_[i].isSelected()) {
+        mark_ = i+1;
+      }
+    }
+    this.setVisible(false);
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    PlotMarkDialog la = new PlotMarkDialog();
+    la.setTitle("Test PlotMark Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Show the dialog and wait for a response
+   *
+   * @param mark initial <code>PlotMark</code> code
+   * @return result, either CANCEL_RESPONSE or OK_RESPONSE
+   */
+  public int showDialog(int mark) {
+    mark_ = mark;
+    createButtons();
+    result_ = CANCEL_RESPONSE;
+    setModal(true);
+    super.setVisible(true);
+    return result_;
+  }
+  /**
+   * Set initial mark.
+   */
+  public void setMark(int mark) {
+    mark_ = mark;
+  }
+  /**
+   * Get the selected <code>PlotMark</code> code.
+   */
+  public int getMark() {
+    return mark_;
+  }
+
+  private void createButtons() {
+    PlotMarkIcon pmi;
+    ButtonGroup group = new ButtonGroup();
+    for(int i=0; i < numMarks; i++) {
+      pmi = new PlotMarkIcon(i+1);
+      buttons_[i] = new JToggleButton(pmi);
+      buttons_[i].setName(Integer.toString(i+1));
+      group.add(buttons_[i]);
+      mainPanel.add(buttons_[i]);
+    }
+    buttons_[mark_-1].setSelected(true);
+  }
+
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/PointAttributeDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/PointAttributeDialog.java
new file mode 100755
index 0000000..eb72461
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/PointAttributeDialog.java
@@ -0,0 +1,475 @@
+/*
+ * $Id: PointAttributeDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.StringTokenizer;
+
+
+import gov.noaa.pmel.sgt.PointAttribute;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.swing.PlotMarkIcon;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+
+/**
+ * Edits a <code>PointAttribute</code>. This dialog does not
+ * make a copy of the attribute so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties unless
+ * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching}
+ * has been turned on.
+ *
+ * <p> Example of <code>PointAttributeDialog</code> use:
+ * <pre>
+ * public void editPointAttribute(PointAttribute attr, JPane pane) {
+ *   PointAttributeDialog pad = new PointAttributeDialog();
+ *   pad.setPointAttribute(attr, pane);
+ *   pad.setVisible(true);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class PointAttributeDialog extends JDialog {
+  private JPane pane_ = null;
+  private JPane[] paneList_ = null;
+  private PointAttribute attr_;
+  private PlotMarkIcon pmIcon_;
+  private int mark_;
+  private Font labelFont_;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  /**
+   * Constructor.
+   */
+  public PointAttributeDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(new Dimension(504, 320));
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,372);
+    getContentPane().add(JTabbedPane1, "Center");
+    markAttrPanel.setLayout(new GridBagLayout());
+    JTabbedPane1.add(markAttrPanel, "markAttrPanel");
+    JLabel1.setText("Color:");
+    markAttrPanel.add(JLabel1, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    colorPanel.setBorder(etchedBorder1);
+    markAttrPanel.add(colorPanel, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,5,10,5),0,0));
+    JLabel6.setText("Mark:");
+    markAttrPanel.add(JLabel6, new GridBagConstraints(0,1,1,1,0.0,0.0,GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    markPanel.setLayout(new GridBagLayout());
+    markAttrPanel.add(markPanel, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,10,5),0,0));
+    markPanel.add(plotMarkIconLabel, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+    plotMarkIconLabel.setForeground(java.awt.Color.black);
+    markEditor.setActionCommand("...");
+    markPanel.add(markEditor, new GridBagConstraints(2,0,1,1,0.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.VERTICAL,new Insets(0,0,0,0),0,0));
+    JLabel7.setText("Height:");
+    markAttrPanel.add(JLabel7, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    markHeightTextField.setColumns(10);
+    markAttrPanel.add(markHeightTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    labelPanel.setLayout(new GridBagLayout());
+    JTabbedPane1.add(labelPanel, "labelPanel");
+    JLabel5.setText("Position:");
+    labelPanel.add(JLabel5, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    positionComboBox.setModel(positionCBModel);
+    labelPanel.add(positionComboBox, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel8.setText("Font:");
+    labelPanel.add(JLabel8, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(fontPanel, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor);
+    JLabel9.setText("Color:");
+    labelPanel.add(JLabel9, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelColorPanel.setBorder(etchedBorder1);
+    labelColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(labelColorPanel, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,5,5,5),0,0));
+    JLabel10.setText("Height:");
+    labelPanel.add(JLabel10, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelHeightTextField.setColumns(10);
+    labelPanel.add(labelHeightTextField, new GridBagConstraints(1,3,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel14.setText("Draw Label?");
+    labelPanel.add(JLabel14, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelPanel.add(drawLabelCheckBox, new GridBagConstraints(1,4,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JTabbedPane1.setSelectedIndex(0);
+    JTabbedPane1.setTitleAt(0,"Mark");
+    JTabbedPane1.setTitleAt(1,"Label");
+    {
+      String[] tempString = new String[9];
+      tempString[0] = "Centered";
+      tempString[1] = "North";
+      tempString[2] = "NorthEast";
+      tempString[3] = "East";
+      tempString[4] = "SouthEast";
+      tempString[5] = "South";
+      tempString[6] = "SouthWest";
+      tempString[7] = "West";
+      tempString[8] = "NorthWest";
+      for(int i=0; i < tempString.length; i++) {
+        positionCBModel.addElement(tempString[i]);
+      }
+    }
+    markAttrPanel.setBounds(2,27,425,203);
+    labelPanel.setBounds(2,27,425,203);
+    positionComboBox.setSelectedIndex(2);
+    setTitle("PointAttribute Properties");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    markEditor.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    //
+    pmIcon_ = new PlotMarkIcon(1);
+    plotMarkIconLabel.setIcon(pmIcon_);
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor
+   */
+  public PointAttributeDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor
+   */
+  public PointAttributeDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == PointAttributeDialog.this)
+  PointAttributeDialog_WindowClosing(event);
+    }
+  }
+
+  void PointAttributeDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JTabbedPane JTabbedPane1 = new javax.swing.JTabbedPane();
+  javax.swing.JPanel markAttrPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  ColorEntryPanel colorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JPanel markPanel = new javax.swing.JPanel();
+  javax.swing.JLabel plotMarkIconLabel = new javax.swing.JLabel();
+  ThreeDotsButton markEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JTextField markHeightTextField = new javax.swing.JTextField();
+  javax.swing.JPanel labelPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JComboBox positionComboBox = new javax.swing.JComboBox();
+  javax.swing.JLabel JLabel8 = new javax.swing.JLabel();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel9 = new javax.swing.JLabel();
+  ColorEntryPanel labelColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel10 = new javax.swing.JLabel();
+  javax.swing.JTextField labelHeightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel14 = new javax.swing.JLabel();
+  javax.swing.JCheckBox drawLabelCheckBox = new javax.swing.JCheckBox();
+  DefaultComboBoxModel positionCBModel = new DefaultComboBoxModel();
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == markEditor)
+        markEditor_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updatePointAttribute();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updatePointAttribute();
+  }
+  /**
+   * Set the <code>PointAttribute</code> to be edited and the
+   * <code>JPane</code>.
+   */
+  public void setPointAttribute(PointAttribute attr, JPane pane) {
+    pane_ = pane;
+    attr_ = attr;
+    //
+    // Mark attributes
+    //
+    // Color
+    //
+    colorPanel.setColor(attr_.getColor());
+    //
+    // mark
+    //
+    int mark = attr_.getMark();
+    changeMark(mark);
+    //
+    // mark height
+    //
+    markHeightTextField.setText(Double.toString(attr_.getMarkHeightP()));
+    //
+    // Label attributes
+    //
+    // position
+    //
+    positionComboBox.setSelectedIndex(attr_.getLabelPosition());
+    //
+    // font
+    //
+    labelFont_ = attr_.getLabelFont();
+    if(pane_ != null && labelFont_ == null) labelFont_ = pane_.getComponent().getFont();
+    fontLabel.setText(fontString(labelFont_));
+    //
+    // color
+    //
+    labelColorPanel.setColor(attr_.getLabelColor());
+    //
+    // width
+    //
+    labelHeightTextField.setText(Double.toString(attr_.getLabelHeightP()));
+    //
+    // draw label?
+    //
+    drawLabelCheckBox.setSelected(attr_.isDrawLabel());
+  }
+  /**
+   * Set the parent <code>JPane</code>.  This reference to
+   * <code>JPane</code> is used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time.
+   */
+  public void setJPane(JPane pane) {
+    paneList_ = new JPane[1];
+    paneList_[0] = pane;
+  }
+  /**
+   * Get the first parent.
+   */
+  public JPane getJPane() {
+    if(paneList_ != null) {
+      return paneList_[0];
+    } else {
+      return null;
+    }
+  }
+  /**
+   * Set the parent <code>JPane</code>s.  These references to
+   * <code>JPane</code> are used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time. A second
+   * <code>JPane</code> is often used for a <code>PointCollectionKey</code>.
+   */
+  public void setJPaneList(JPane[] list) {
+    paneList_ = list;
+  }
+  /** Get an array of parent panes. */
+  public JPane[] getJPaneList() {
+    return paneList_;
+  }
+
+  void updatePointAttribute() {
+    if(pane_ != null) pane_.setBatch(true, "PointAttributeDialog");
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(true, "PointAttributeDialog");
+      }
+    }
+    attr_.setBatch(true);
+    //
+    // mark attributes
+    //
+    // Color
+    //
+    attr_.setColor(colorPanel.getColor());
+    //
+    // mark
+    //
+    attr_.setMark(mark_);
+    //
+    // mark height
+    //
+    attr_.setMarkHeightP(new Double(markHeightTextField.getText()).doubleValue());
+    //
+    // label attributes
+    //
+    // position
+    //
+    attr_.setLabelPosition(positionComboBox.getSelectedIndex());
+    //
+    // font
+    //
+    attr_.setLabelFont(labelFont_);
+    //
+    // color
+    //
+    attr_.setLabelColor(labelColorPanel.getColor());
+    //
+    // height
+    //
+    attr_.setLabelHeightP(new Double(labelHeightTextField.getText()).doubleValue());
+    //
+    // draw label?
+    //
+    attr_.setDrawLabel(drawLabelCheckBox.isSelected());
+
+    attr_.setBatch(false);
+    //
+    if(pane_ != null) pane_.setBatch(false, "PointAttributeDialog");
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(false, "PointAttributeDialog");
+      }
+    }
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    PointAttribute attr = new PointAttribute();
+    PointAttributeDialog la = new PointAttributeDialog();
+    la.setPointAttribute(attr, null);
+    la.setTitle("Test PointAttribute Dialog");
+    la.setVisible(true);
+  }
+
+  void markEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    PlotMarkDialog pmd = new PlotMarkDialog();
+    Point loc = markEditor.getLocationOnScreen();
+    pmd.setLocation(loc.x, loc.y);
+    int result = pmd.showDialog(mark_);
+    if(result == PlotMarkDialog.OK_RESPONSE) {
+      changeMark(pmd.getMark());
+    }
+  }
+
+  private void changeMark(int mark) {
+    mark_ = mark;
+    pmIcon_.setMark(mark);
+    plotMarkIconLabel.repaint();
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/RulerDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/RulerDialog.java
new file mode 100755
index 0000000..228929f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/RulerDialog.java
@@ -0,0 +1,726 @@
+/*
+ * $Id: RulerDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.sgt.*;
+import gov.noaa.pmel.util.*;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * Edits a <code>Ruler</code>. This dialog does not
+ * make a copy of the object so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties.
+ *
+ * <p> Example of <code>RulerDialog</code> use:
+ * <pre>
+ * public void editRuler(Ruler axis, JPane pane) {
+ *   RulerDialog sad = new RulerDialog();
+ *   sad.setRuler(axis, pane);
+ *   sad.setVisible(true);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 3.0
+ */
+public class RulerDialog extends JDialog {
+  private JPane pane_;
+  private Ruler scale_;
+  private Font labelFont_;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  /**
+   * Constructor.
+   */
+  public RulerDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(new Dimension(531, 358));
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    jLabel1.setText("Line Color:");
+    physicalBorder.setTitle("Physical Bounds");
+    jLabel5.setText("Height:");
+    heightPhysicalTextField.setColumns(10);
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,348);
+    getContentPane().add(TabbedPane, "Center");
+    labelPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(labelPanel, "labelPanel");
+    labelPanel.setBounds(2,27,452,275);
+    labelPanel.setVisible(false);
+    JLabel3.setText("Interval:");
+    labelPanel.add(JLabel3, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    intervalTextField.setColumns(5);
+    labelPanel.add(intervalTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel4.setText("Sig Digits:");
+    labelPanel.add(JLabel4, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    sigDigitsTextField.setColumns(5);
+    labelPanel.add(sigDigitsTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel5.setText("Format:");
+    labelPanel.add(JLabel5, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    formatTextField.setColumns(10);
+    labelPanel.add(formatTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel11.setText("Color:");
+    labelPanel.add(JLabel11, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    textColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(textColorPanel, new GridBagConstraints(1,3,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    JLabel15.setText("Font:");
+    labelPanel.add(JLabel15, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(fontPanel, new GridBagConstraints(1,4,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor);
+    JLabel16.setText("Height:");
+    labelPanel.add(JLabel16, new GridBagConstraints(0,5,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    heightTextField.setColumns(10);
+    labelPanel.add(heightTextField, new GridBagConstraints(1,5,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(15,5,5,5),0,0));
+    JLabel1.setText("Position:");
+    labelPanel.add(JLabel1, new GridBagConstraints(0,6,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    positionComboBox.setModel(positionCBModel);
+    labelPanel.add(positionComboBox, new GridBagConstraints(1,6,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    rangePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(rangePanel, "rangePanel");
+    rangePanel.setBounds(2,27,452,275);
+    rangePanel.setVisible(false);
+    userPanel.setBorder(userBorder);
+    userPanel.setLayout(new GridBagLayout());
+    rangePanel.add(userPanel, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel8.setText("Minimum:");
+    userPanel.add(JLabel8, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    minUserTextField.setColumns(25);
+    userPanel.add(minUserTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel9.setText("Maximum:");
+    userPanel.add(JLabel9, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    maxUserTextField.setColumns(25);
+    userPanel.add(maxUserTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel2.setText("Delta:");
+    userPanel.add(JLabel2, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    incUserTextField.setColumns(25);
+    userPanel.add(incUserTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    physicalPanel.setBorder(physicalBorder);
+    physicalPanel.setLayout(new GridBagLayout());
+    rangePanel.add(physicalPanel, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel10.setText("X:");
+    physicalPanel.add(JLabel10, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    xPhysicalTextField.setColumns(10);
+    physicalPanel.add(xPhysicalTextField,    new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel17.setText("Y:");
+    physicalPanel.add(JLabel17,  new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    yPhysicalTextField.setColumns(10);
+    physicalPanel.add(yPhysicalTextField,    new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    originLabel.setText("Width:");
+    physicalPanel.add(originLabel, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    widthPhysicalTextField.setColumns(10);
+    physicalPanel.add(widthPhysicalTextField,   new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    physicalPanel.add(jLabel5,    new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    physicalPanel.add(heightPhysicalTextField,     new GridBagConstraints(3, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    ticsStylePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(ticsStylePanel, "ticsStylePanel");
+    ticsStylePanel.setBounds(2,27,452,275);
+    ticsStylePanel.setVisible(false);
+    ticsPanel.setBorder(ticsBorder);
+    ticsPanel.setLayout(new GridBagLayout());
+    ticsStylePanel.add(ticsPanel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 10, 10));
+    JLabel18.setText("Large Tic Height:");
+    ticsPanel.add(JLabel18,  new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    largeTicTextField.setColumns(15);
+    ticsPanel.add(largeTicTextField,  new GridBagConstraints(1, 0, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel19.setText("Small Tic Height:");
+    ticsPanel.add(JLabel19,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    smallTicTextField.setColumns(15);
+    ticsPanel.add(smallTicTextField,  new GridBagConstraints(1, 1, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel20.setText("Number of Small Tics:");
+    ticsPanel.add(JLabel20,  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    numSmallTicsTextField.setColumns(5);
+    ticsPanel.add(numSmallTicsTextField,  new GridBagConstraints(1, 2, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel21.setText("Tic Position:");
+    ticsPanel.add(JLabel21,  new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    ticPositionComboBox.setModel(ticPositionCBModel);
+    ticsPanel.add(ticPositionComboBox,  new GridBagConstraints(1, 3, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    ticsPanel.add(lineColorPanel,   new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    stylePanel.setBorder(styleBorder);
+    stylePanel.setLayout(new GridBagLayout());
+    ticsStylePanel.add(stylePanel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 0), 20, 10));
+    JLabel7.setText("Visible:");
+    stylePanel.add(JLabel7, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    axislVisibleCheckBox.setSelected(true);
+    stylePanel.add(axislVisibleCheckBox, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    JLabel6.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    JLabel6.setText("Selectable:");
+    stylePanel.add(JLabel6,  new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 61, 0));
+    axisSelectableCheckBox.setSelected(true);
+    stylePanel.add(axisSelectableCheckBox,   new GridBagConstraints(3, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    ticsPanel.add(jLabel1,     new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    TabbedPane.setSelectedComponent(labelPanel);
+    TabbedPane.setSelectedIndex(0);
+    TabbedPane.setTitleAt(0,"Label");
+    TabbedPane.setTitleAt(1,"Range");
+    TabbedPane.setTitleAt(2,"Tics/Style");
+    TabbedPane.setTitleAt(3,"Attach");
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "LEFT";
+      tempString[1] = "CENTER";
+      tempString[2] = "RIGHT";
+      for(int i=0; i < tempString.length; i++) {
+        horizCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "TOP";
+      tempString[1] = "MIDDLE";
+      tempString[2] = "BOTTOM";
+      for(int i=0; i < tempString.length; i++) {
+        vertCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "POSITIVE_SIDE";
+      tempString[1] = "NEGATIVE_SIDE";
+      tempString[2] = "NO_LABEL";
+      for(int i=0; i < tempString.length; i++) {
+        positionCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "POSITIVE_SIDE";
+      tempString[1] = "NEGATIVE_SIDE";
+      tempString[2] = "BOTH_SIDES";
+      for(int i=0; i < tempString.length; i++) {
+        ticPositionCBModel.addElement(tempString[i]);
+      }
+    }
+    positionComboBox.setSelectedIndex(1);
+    ticPositionComboBox.setSelectedIndex(1);
+    setTitle("TimeAxis");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    minUserTextField.addActionListener(lSymAction);
+    maxUserTextField.addActionListener(lSymAction);
+    widthPhysicalTextField.addActionListener(lSymAction);
+
+//    Insets pup = new Insets(0, 0, 0, 0);
+//    fontEditor.setMargin(pup);
+  }
+  /** Used internally. */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public RulerDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public RulerDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == RulerDialog.this)
+        FontDialog_WindowClosing(event);
+    }
+  }
+
+  void FontDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  //{{DECLARE_CONTROLS
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel labelPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
+  javax.swing.JTextField intervalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
+  javax.swing.JTextField sigDigitsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JTextField formatTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel11 = new javax.swing.JLabel();
+  ColorEntryPanel textColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel15 = new javax.swing.JLabel();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel16 = new javax.swing.JLabel();
+  javax.swing.JTextField heightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JComboBox positionComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel rangePanel = new javax.swing.JPanel();
+  javax.swing.JPanel userPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel8 = new javax.swing.JLabel();
+  javax.swing.JTextField minUserTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel9 = new javax.swing.JLabel();
+  javax.swing.JTextField maxUserTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel2 = new javax.swing.JLabel();
+  javax.swing.JTextField incUserTextField = new javax.swing.JTextField();
+  javax.swing.JPanel physicalPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel10 = new javax.swing.JLabel();
+  javax.swing.JTextField xPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel17 = new javax.swing.JLabel();
+  javax.swing.JTextField yPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel originLabel = new javax.swing.JLabel();
+  javax.swing.JTextField widthPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JPanel ticsStylePanel = new javax.swing.JPanel();
+  javax.swing.JPanel ticsPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel18 = new javax.swing.JLabel();
+  javax.swing.JTextField largeTicTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel19 = new javax.swing.JLabel();
+  javax.swing.JTextField smallTicTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel20 = new javax.swing.JLabel();
+  javax.swing.JTextField numSmallTicsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel21 = new javax.swing.JLabel();
+  javax.swing.JComboBox ticPositionComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel stylePanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox axislVisibleCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JCheckBox axisSelectableCheckBox = new javax.swing.JCheckBox();
+  DefaultComboBoxModel horizCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel vertCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel positionCBModel = new DefaultComboBoxModel();
+  javax.swing.border.TitledBorder userBorder = new javax.swing.border.TitledBorder("User Range");
+  javax.swing.border.TitledBorder physicalBorder = new javax.swing.border.TitledBorder("Physical Range");
+  javax.swing.border.TitledBorder ticsBorder = new javax.swing.border.TitledBorder("Tics");
+  javax.swing.border.TitledBorder styleBorder = new javax.swing.border.TitledBorder("Axis Style");
+  DefaultComboBoxModel ticPositionCBModel = new DefaultComboBoxModel();
+  private ColorEntryPanel lineColorPanel = new ColorEntryPanel();
+  private JLabel jLabel1 = new JLabel();
+  private JLabel jLabel5 = new JLabel();
+  private JTextField heightPhysicalTextField = new JTextField();
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateRuler();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateRuler();
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    RulerDialog la = new RulerDialog();
+    la.setFont(null);
+    la.setTitle("Test Ruler Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Set the <code>Ruler</code> to be edited and the
+   * <code>JPane</code>
+   */
+  public void setRuler(Ruler scale, JPane pane) {
+    setJPane(pane);
+    setRuler(scale);
+  }
+  /**
+   * Set the <code>Ruler</code> to be edited
+   */
+  public void setRuler(Ruler scale) {
+    scale_ = scale;
+    setRuler();
+  }
+  /**
+   * Get the edited <code>Ruler</code>
+   */
+  public Ruler getRuler() {
+    return scale_;
+  }
+  /**
+   * Set the parent <code>JPane</code>.
+   */
+  public void setJPane(JPane pane) {
+    pane_ = pane;
+  }
+  /**
+   * Get the parent <code>JPane</code>.
+   */
+  public JPane getJPane() {
+    return pane_;
+  }
+
+  private void setRuler() {
+    //
+    // time axis ID
+    //
+    setTitle("Ruler - " + scale_.getId());
+    //
+    // label
+    //
+    intervalTextField.setText(Integer.toString(scale_.getLabelInterval()));
+    sigDigitsTextField.setText(Integer.toString(scale_.getSignificantDigits()));
+    formatTextField.setText(scale_.getLabelFormat());
+
+    Color col = scale_.getLabelColor();
+    if(col == null) col = pane_.getComponent().getForeground();
+    textColorPanel.setColor(col);
+
+    labelFont_ = scale_.getLabelFont();
+    if(labelFont_ == null) labelFont_ = pane_.getComponent().getFont();
+    fontLabel.setText(fontString(labelFont_));
+
+    heightTextField.setText(String.valueOf(scale_.getLabelHeightP()));
+    //
+    // range
+    //
+    Range2D urange = scale_.getRangeU();
+    minUserTextField.setText(String.valueOf(urange.start));
+    maxUserTextField.setText(String.valueOf(urange.end));
+    incUserTextField.setText(String.valueOf(urange.delta));
+    Rectangle2D.Double bounds = scale_.getBoundsP();
+//    Range2D range = sa_.getRangeP();
+    xPhysicalTextField.setText(String.valueOf(bounds.x));
+    yPhysicalTextField.setText(String.valueOf(bounds.y));
+    widthPhysicalTextField.setText(String.valueOf(bounds.width));
+    heightPhysicalTextField.setText(String.valueOf(bounds.height));
+//    Point2D.Double pt = sa_.getLocationU();
+//    TimePoint tt = null;
+//    double point = 0.0;
+
+//    if(pt == null) {
+//      originIsGeoDate_ = true;
+//      tt = sa_.getTimeLocationU();
+//      tOrigin_ = tt.t;
+//    } else {
+//      originIsGeoDate_ = false;
+//      if(sa_.getOrientation() == Axis.HORIZONTAL) {
+//        point = pt.y;
+//      } else {
+//        point = pt.x;
+//      }
+//    }
+
+    if(scale_.getOrientation() == Axis.HORIZONTAL) {
+      originLabel.setText("Y Origin:");
+    } else {
+      originLabel.setText("X Origin:");
+    }
+//    if(originIsGeoDate_) {
+//      originDateEditor.setEnabled(true);
+//      originTextField.setText(tOrigin_.toString());
+//    } else {
+//      originDateEditor.setEnabled(false);
+//      originTextField.setText(String.valueOf(point));
+//    }
+    //
+    // tics
+    //
+    largeTicTextField.setText(String.valueOf(scale_.getLargeTicHeightP()));
+    smallTicTextField.setText(String.valueOf(scale_.getSmallTicHeightP()));
+    numSmallTicsTextField.setText(String.valueOf(scale_.getNumberSmallTics()));
+    ticPositionComboBox.setSelectedIndex(scale_.getTicPosition());
+
+    Color lcol = scale_.getLineColor();
+    if(lcol == null) col = pane_.getComponent().getForeground();
+    lineColorPanel.setColor(col);
+
+    //
+    // axis style
+    //
+    axislVisibleCheckBox.setSelected(scale_.isVisible());
+    axisSelectableCheckBox.setSelected(scale_.isSelectable());
+    //
+    // attachments
+    //
+//    boolean test = sa_.getNumberRegisteredTransforms() > 0;
+//    transformCheckBox.setSelected(test);
+
+//    if(sa_.getOrientation() == Axis.HORIZONTAL) {
+////      test = sa_.getGraph().getNumberXAxis() >= 2;
+//      axisLabel.setEnabled(test);
+//      axisCheckBox.setEnabled(test);
+//      axisLabel.setText("Attach X Axis to Axis:");
+//      test = sa_.getNumberRegisteredAxes() > 0;
+//      axisCheckBox.setSelected(test);
+//    } else {
+//      test = sa_.getGraph().getNumberYAxis() >= 2;
+//      axisLabel.setEnabled(test);
+//      axisCheckBox.setEnabled(test);
+//      axisLabel.setText("Attach Y Axis to Axis:");
+//      test = sa_.getNumberRegisteredAxes() > 0;
+//      axisCheckBox.setSelected(test);
+//    }
+
+  }
+
+  private void updateRuler() {
+    pane_.setBatch(true, "RulerDialog");
+    //
+    // label
+    //
+    scale_.setLabelInterval(Integer.parseInt(intervalTextField.getText()));
+    scale_.setSignificantDigits(Integer.parseInt(sigDigitsTextField.getText()));
+    scale_.setLabelFormat(formatTextField.getText());
+
+    scale_.setLabelColor(textColorPanel.getColor());
+    if(labelFont_ != null) scale_.setLabelFont(labelFont_);
+
+    scale_.setLabelHeightP(Double.valueOf(heightTextField.getText()).doubleValue());
+    scale_.setLabelPosition(positionComboBox.getSelectedIndex());
+    //
+    // range
+    //
+    double min = Double.valueOf(minUserTextField.getText()).doubleValue();
+    double max = Double.valueOf(maxUserTextField.getText()).doubleValue();
+    double inc = Double.valueOf(incUserTextField.getText()).doubleValue();
+    scale_.setRangeU(new Range2D(min, max, inc));
+    double x = Double.valueOf(xPhysicalTextField.getText()).doubleValue();
+    double y = Double.valueOf(yPhysicalTextField.getText()).doubleValue();
+    double width = Double.valueOf(widthPhysicalTextField.getText()).doubleValue();
+    double height = Double.valueOf(heightPhysicalTextField.getText()).doubleValue();
+    scale_.setBoundsP(new Rectangle2D.Double(x, y, width, height));
+//    sa_.setRangeP(new Range2D(min, max));
+//    if(originIsGeoDate_) {
+//      TimePoint pt = sa_.getTimeLocationU();
+//      pt.t = tOrigin_;
+//      sa_.setLocationU(pt);
+//    } else {
+//      Point2D.Double pt = sa_.getLocationU();
+//      if(sa_.getOrientation() == Axis.HORIZONTAL) {
+//        pt.y = Double.valueOf(originTextField.getText()).doubleValue();
+//      } else {
+//        pt.x = Double.valueOf(originTextField.getText()).doubleValue();
+//      }
+//      sa_.setLocationU(pt);
+//    }
+    //
+    // tics
+    //
+    scale_.setLargeTicHeightP(Double.valueOf(largeTicTextField.getText()).doubleValue());
+    scale_.setSmallTicHeightP(Double.valueOf(smallTicTextField.getText()).doubleValue());
+    scale_.setNumberSmallTics(Integer.parseInt(numSmallTicsTextField.getText()));
+    scale_.setTicPosition(ticPositionComboBox.getSelectedIndex());
+
+    scale_.setLineColor(lineColorPanel.getColor());
+    //
+    // axis style
+    //
+    scale_.setVisible(axislVisibleCheckBox.isSelected());
+    scale_.setSelectable(axisSelectableCheckBox.isSelected());
+    //
+    // attach
+    //
+//    boolean test;
+/*    if(transformCheckBox.isSelected() && (sa_.getNumberRegisteredTransforms() < 1)) {
+      if(sa_.getOrientation() == Axis.HORIZONTAL) {
+        sa_.register(sa_.getGraph().getXTransform());
+      } else {
+        sa_.register(sa_.getGraph().getYTransform());
+      }
+    } else {
+      if(sa_.getNumberRegisteredTransforms() > 0) sa_.clearAllRegisteredTransforms();
+    }
+    if(sa_.getOrientation() == Axis.HORIZONTAL) {
+      test = (sa_.getGraph().getNumberXAxis() >= 2) &&
+        (sa_.getNumberRegisteredAxes() < 1);
+      if(axisCheckBox.isSelected() && test) {
+        Axis ax;
+        for(Enumeration it = sa_.getGraph().xAxisElements();
+            it.hasMoreElements();) {
+          ax = (Axis)it.nextElement();
+          if(ax.getId() != sa_.getId()) sa_.register(ax);
+        }
+      } else {
+        if(sa_.getNumberRegisteredAxes() > 0) sa_.clearAllRegisteredAxes();
+      }
+    } else {   // vertical axis
+      test = (sa_.getGraph().getNumberYAxis() >= 2) &&
+        (sa_.getNumberRegisteredAxes() < 1);
+      if(axisCheckBox.isSelected() && test) {
+        Axis ax;
+        for(Enumeration it = sa_.getGraph().yAxisElements();
+            it.hasMoreElements();) {
+          ax = (Axis)it.nextElement();
+          if(ax.getId() != sa_.getId()) sa_.register(ax);
+        }
+      } else  {
+        if(sa_.getNumberRegisteredAxes() > 0) sa_.clearAllRegisteredAxes();
+      }
+    } */
+
+    pane_.setBatch(false, "RulerDialog");
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+
+
+//  void widthPhysicalTextField_actionPerformed(java.awt.event.ActionEvent event) {
+/*    if(originIsGeoDate_) {
+      try {
+        tOrigin_ = new GeoDate(originTextField.getText(), dateFormat_);
+      } catch (IllegalTimeValue e) {
+        originTextField.setText(tOrigin_.toString());
+      }
+    } */
+//  }
+
+//  void originDateEditor_actionPerformed(java.awt.event.ActionEvent event)       {
+/*    GeoDateDialog gd = new GeoDateDialog();
+    Point loc = originDateEditor.getLocationOnScreen();
+    int result = gd.showDialog(tOrigin_, loc.x, loc.y);
+    if(result == GeoDateDialog.OK_RESPONSE) {
+      tOrigin_ = gd.getGeoDate();
+      originTextField.setText(tOrigin_.toString());
+    } */
+//  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/SGLabelDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/SGLabelDialog.java
new file mode 100755
index 0000000..4ee79c0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/SGLabelDialog.java
@@ -0,0 +1,525 @@
+/*
+ * $Id: SGLabelDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+
+import gov.noaa.pmel.sgt.SGLabel;
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.Debug;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import gov.noaa.pmel.swing.MRJUtil;
+
+import javax.swing.*;
+import java.awt.*;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+
+/**
+ * Edits a <code>SGLabel</code>. This dialog does not
+ * make a copy of the object so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties.
+ *
+ * <p> Example of <code>SGLabelDialog</code> use:
+ * <pre>
+ * public void editSGLabel(SGLabel label, JPane pane) {
+ *   SGLabelDialog sgld = new SGLabelDialog();
+ *   sgld.setSGLabel(label, pane);
+ *   sgld.setVisible(true);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class SGLabelDialog extends JDialog implements PropertyChangeListener {
+  private SGLabel label_;
+  private JPane pane_;
+  private Font labelFont_;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  private boolean ignoreEvent_ = false;
+//  private ThreeDotsIcon dotsIcon_ = new ThreeDotsIcon(Color.black);
+  /**
+   * Constructor.
+   */
+  public SGLabelDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    //{{INIT_CONTROLS
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(457, 320);
+//    setSize(457,294);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    fontEditor.setAlignmentY((float) 0.0);
+//    fontEditor.setIcon(dotsIcon_);
+    fontLabel.setAlignmentY((float) 0.0);
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,300);
+    getContentPane().add(TabbedPane, "Center");
+    textPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(textPanel, "textPanel");
+    textPanel.setBounds(2,27,452,225);
+    textPanel.setVisible(false);
+    JLabel9.setText("Text:");
+    textPanel.add(JLabel9, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelTextField.setColumns(20);
+    textPanel.add(labelTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    JLabel11.setText("Color:");
+    textPanel.add(JLabel11, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    textColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    textPanel.add(textColorPanel, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    JLabel15.setText("Font:");
+    textPanel.add(JLabel15, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontPanel.setLayout(flowLayout1);
+    textPanel.add(fontPanel,   new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel, null);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor, null);
+    JLabel16.setText("HeightP:");
+    textPanel.add(JLabel16, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    heightTextField.setColumns(10);
+    textPanel.add(heightTextField, new GridBagConstraints(1,3,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel7.setText("Visible:");
+    textPanel.add(JLabel7, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelVisibleCheckBox.setSelected(true);
+    textPanel.add(labelVisibleCheckBox, new GridBagConstraints(1,4,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    JLabel6.setText("Selectable:");
+    textPanel.add(JLabel6, new GridBagConstraints(0,5,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelSelectableCheckBox.setSelected(true);
+    textPanel.add(labelSelectableCheckBox, new GridBagConstraints(1,5,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    locationPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(locationPanel, "locationPanel");
+    locationPanel.setBounds(2,27,452,225);
+    locationPanel.setVisible(false);
+    positionPanel.setBorder(positionBorder);
+    positionPanel.setLayout(new GridBagLayout());
+    locationPanel.add(positionPanel, new GridBagConstraints(0,0,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel1.setText("X Position:");
+    positionPanel.add(JLabel1, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    xPosTextField.setColumns(20);
+    positionPanel.add(xPosTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel2.setText("Y Position:");
+    positionPanel.add(JLabel2, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    yPosTextField.setColumns(20);
+    positionPanel.add(yPosTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    alignPanel.setBorder(alignBorder);
+    alignPanel.setLayout(new GridBagLayout());
+    locationPanel.add(alignPanel, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.VERTICAL,new Insets(5,0,5,0),20,15));
+    JLabel3.setText("Horizontal:");
+    alignPanel.add(JLabel3,new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    horizComboBox.setModel(horizCBModel);
+    alignPanel.add(horizComboBox,new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    JLabel4.setText("Vertical:");
+    alignPanel.add(JLabel4,new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    vertComboBox.setModel(vertCBModel);
+    alignPanel.add(vertComboBox,new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    orientPanel.setBorder(orientBorder);
+    orientPanel.setLayout(new GridBagLayout());
+    locationPanel.add(orientPanel, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.VERTICAL,new Insets(5,10,5,0),20,15));
+    orientPanel.setBackground(new java.awt.Color(204,204,204));
+    horizRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+    horizRadioButton.setText("Horizontal");
+    horizRadioButton.setActionCommand("Horizontal");
+    orientPanel.add(horizRadioButton, new GridBagConstraints(0,0,1,1,1.0,1.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,0),0,0));
+    vertRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+    vertRadioButton.setText("Vertical");
+    vertRadioButton.setActionCommand("Vertical");
+    orientPanel.add(vertRadioButton,new GridBagConstraints(0,1,1,1,1.0,1.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,0),0,0));
+    TabbedPane.setSelectedComponent(textPanel);
+    TabbedPane.setSelectedIndex(0);
+    TabbedPane.setTitleAt(0,"Text");
+    TabbedPane.setTitleAt(1,"Position");
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "LEFT";
+      tempString[1] = "CENTER";
+      tempString[2] = "RIGHT";
+      for(int i=0; i < tempString.length; i++) {
+  horizCBModel.addElement(tempString[i]);
+      }
+      //      horizCBModel.setItems(tempString);
+    }
+    //$$ horizCBModel.move(72,300);
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "TOP";
+      tempString[1] = "MIDDLE";
+      tempString[2] = "BOTTOM";
+      for(int i=0; i < tempString.length; i++) {
+  vertCBModel.addElement(tempString[i]);
+      }
+      //      vertCBModel.setItems(tempString);
+    }
+    vertComboBox.setSelectedIndex(2);
+    horizComboBox.setSelectedIndex(0);
+    setTitle("SGLabel");
+    //}}
+
+    //{{REGISTER_LISTENERS
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    //}}
+
+    if(!MRJUtil.isAquaLookAndFeel()) {
+      Insets pup = new Insets(0, 0, 0, 0);
+      fontEditor.setMargin(pup);
+    }
+
+    ButtonGroup orientBG = new ButtonGroup();
+    orientBG.add(horizRadioButton);
+    orientBG.add(vertRadioButton);
+
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public SGLabelDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public SGLabelDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == SGLabelDialog.this)
+        SGLabelDialog_WindowClosing(event);
+    }
+  }
+
+  void SGLabelDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    finish();
+    dispose();
+  }
+
+  //{{DECLARE_CONTROLS
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel textPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel9 = new javax.swing.JLabel();
+  javax.swing.JTextField labelTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel11 = new javax.swing.JLabel();
+  ColorEntryPanel textColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel15 = new javax.swing.JLabel();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel16 = new javax.swing.JLabel();
+  javax.swing.JTextField heightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelVisibleCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JCheckBox labelSelectableCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JPanel locationPanel = new javax.swing.JPanel();
+  javax.swing.JPanel positionPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JTextField xPosTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel2 = new javax.swing.JLabel();
+  javax.swing.JTextField yPosTextField = new javax.swing.JTextField();
+  javax.swing.JPanel alignPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
+  javax.swing.JComboBox horizComboBox = new javax.swing.JComboBox();
+  javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
+  javax.swing.JComboBox vertComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel orientPanel = new javax.swing.JPanel();
+  javax.swing.JRadioButton horizRadioButton = new javax.swing.JRadioButton();
+  javax.swing.JRadioButton vertRadioButton = new javax.swing.JRadioButton();
+  javax.swing.border.TitledBorder alignBorder = new javax.swing.border.TitledBorder("Alignment");
+  javax.swing.border.TitledBorder positionBorder = new javax.swing.border.TitledBorder("Position");
+  DefaultComboBoxModel horizCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel vertCBModel = new DefaultComboBoxModel();
+  javax.swing.border.TitledBorder orientBorder = new javax.swing.border.TitledBorder("Orientation");
+  private FlowLayout flowLayout1 = new FlowLayout();
+  //}}
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    finish();
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    finish();
+    updateSGLabel();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateSGLabel();
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    SGLabelDialog la = new SGLabelDialog();
+    la.setFont(null);
+    la.setTitle("Test SGLabel Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Set the <code>SGLabel</code> to be edited and the
+   * <code>JPane</code>.
+   */
+  public void setSGLabel(SGLabel label, JPane pane) {
+    setJPane(pane);
+    setSGLabel(label);
+  }
+  /**
+   * Set the <code>SGLabel</code> to be edited.
+   */
+  public void setSGLabel(SGLabel label) {
+    label_ = label;
+    label_.addPropertyChangeListener(this);
+    ignoreEvent_ = false;
+    setSGLabel();
+  }
+  /**
+   * Get the edited object
+   */
+  public SGLabel getSGLabel() {
+    return label_;
+  }
+  /**
+   * Set the parent <code>JPane</code>
+   */
+  public void setJPane(JPane pane) {
+    pane_ = pane;
+  }
+  /**
+   * Get the parent <code>JPane</code>
+   */
+  public JPane getJPane() {
+    return pane_;
+  }
+
+  private void setSGLabel() {
+    //
+    // label Id
+    //
+    setTitle("SGLabel - " + label_.getId());
+    //
+    // text
+    //
+    labelTextField.setText(label_.getText());
+
+    Color col = label_.getColor();
+    if(col == null && pane_ != null) col = pane_.getComponent().getForeground();
+    textColorPanel.setColor(col);
+
+    labelFont_ = label_.getFont();
+    if(labelFont_ == null && pane_ != null) labelFont_ = pane_.getComponent().getFont();
+    fontLabel.setText(fontString(labelFont_));
+
+    heightTextField.setText(String.valueOf(label_.getHeightP()));
+    labelVisibleCheckBox.setSelected(label_.isVisible());
+    labelSelectableCheckBox.setSelected(label_.isSelectable());
+    //
+    // location
+    //
+    Point2D.Double locp = label_.getLocationP();
+    xPosTextField.setText(String.valueOf(locp.x));
+    yPosTextField.setText(String.valueOf(locp.y));
+
+    horizComboBox.setSelectedIndex(label_.getHAlign());
+    vertComboBox.setSelectedIndex(label_.getVAlign());
+
+    if(label_.getOrientation() == SGLabel.HORIZONTAL) {
+      horizRadioButton.setSelected(true);
+    } else {
+      vertRadioButton.setSelected(true);
+    }
+  }
+
+  private void updateSGLabel() {
+    ignoreEvent_ = true;
+    if(pane_ != null) pane_.setBatch(true, "SGLabelDialog");
+    //
+    // text
+    //
+    label_.setText(labelTextField.getText());
+
+    label_.setColor(textColorPanel.getColor());
+
+    if(labelFont_ != null) label_.setFont(labelFont_);
+
+    label_.setHeightP(Double.valueOf(heightTextField.getText()).doubleValue());
+    label_.setVisible(labelVisibleCheckBox.isSelected());
+    label_.setSelectable(labelSelectableCheckBox.isSelected());
+    //
+    // Location
+    //
+    double x = Double.valueOf(xPosTextField.getText()).doubleValue();
+    double y = Double.valueOf(yPosTextField.getText()).doubleValue();
+    Point2D.Double locp = new Point2D.Double(x, y);
+    label_.setLocationP(locp);
+
+    label_.setHAlign(horizComboBox.getSelectedIndex());
+    label_.setVAlign(vertComboBox.getSelectedIndex());
+
+    boolean horiz = horizRadioButton.isSelected();
+    if(horiz) {
+      label_.setOrientation(SGLabel.HORIZONTAL);
+    } else {
+      label_.setOrientation(SGLabel.VERTICAL);
+    }
+
+    if(pane_ != null) pane_.setBatch(false, "SGLabelDialog");
+    ignoreEvent_ = false;
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event)
+  {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+
+  private void finish() {
+    label_.removePropertyChangeListener(this);
+  }
+  /**
+   * Used internally to track changes to a <code>SGLabel</code>
+   */
+  public void propertyChange(PropertyChangeEvent event) {
+    if(ignoreEvent_) {
+      if(Debug.EVENT) System.out.println("SGLabel: ignore event");
+      return;
+    }
+    if(Debug.EVENT) {
+      System.out.println("SGLabelDialog: " + event);
+      System.out.println("               " + event.getPropertyName());
+    }
+    if(event.getPropertyName().equals("location")) {
+      Point2D.Double locp = label_.getLocationP();
+      xPosTextField.setText(String.valueOf(locp.x));
+      yPosTextField.setText(String.valueOf(locp.y));
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/SpaceAxisDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/SpaceAxisDialog.java
new file mode 100755
index 0000000..8ae9907
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/SpaceAxisDialog.java
@@ -0,0 +1,750 @@
+/*
+ * $Id: SpaceAxisDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.SpaceAxis;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.Point2D;
+import gov.noaa.pmel.util.TimePoint;
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+
+import java.util.Enumeration;
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Edits a <code>SpaceAxis</code>. This dialog does not
+ * make a copy of the object so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties.
+ *
+ * <p> Example of <code>SpaceAxisDialog</code> use:
+ * <pre>
+ * public void editSpaceAxis(SpaceAxis axis, JPane pane) {
+ *   SpaceAxisDialog sad = new SpaceAxisDialog();
+ *   sad.setSpaceAxis(axis, pane);
+ *   sad.setVisible(true);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class SpaceAxisDialog extends JDialog {
+  private JPane pane_;
+  private SpaceAxis sa_;
+  private Font labelFont_;
+  private boolean originIsGeoDate_;
+  private GeoDate tOrigin_ = null;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  private String dateFormat_ = "yyyy-MM-dd HH:mm:ss";
+  /**
+   * Constructor.
+   */
+  public SpaceAxisDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(457,344);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    jLabel1.setText("Line Color:");
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,348);
+    getContentPane().add(TabbedPane, "Center");
+    labelPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(labelPanel, "labelPanel");
+    labelPanel.setBounds(2,27,452,275);
+    labelPanel.setVisible(false);
+    JLabel3.setText("Interval:");
+    labelPanel.add(JLabel3, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    intervalTextField.setColumns(5);
+    labelPanel.add(intervalTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel4.setText("Sig Digits:");
+    labelPanel.add(JLabel4, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    sigDigitsTextField.setColumns(5);
+    labelPanel.add(sigDigitsTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel5.setText("Format:");
+    labelPanel.add(JLabel5, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    formatTextField.setColumns(10);
+    labelPanel.add(formatTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel11.setText("Color:");
+    labelPanel.add(JLabel11, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    textColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(textColorPanel, new GridBagConstraints(1,3,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    JLabel15.setText("Font:");
+    labelPanel.add(JLabel15, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(fontPanel, new GridBagConstraints(1,4,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor);
+    JLabel16.setText("Height:");
+    labelPanel.add(JLabel16, new GridBagConstraints(0,5,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    heightTextField.setColumns(10);
+    labelPanel.add(heightTextField, new GridBagConstraints(1,5,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(15,5,5,5),0,0));
+    JLabel1.setText("Position:");
+    labelPanel.add(JLabel1, new GridBagConstraints(0,6,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    positionComboBox.setModel(positionCBModel);
+    labelPanel.add(positionComboBox, new GridBagConstraints(1,6,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    rangePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(rangePanel, "rangePanel");
+    rangePanel.setBounds(2,27,452,275);
+    rangePanel.setVisible(false);
+    userPanel.setBorder(userBorder);
+    userPanel.setLayout(new GridBagLayout());
+    rangePanel.add(userPanel, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel8.setText("Minimum:");
+    userPanel.add(JLabel8, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    minUserTextField.setColumns(25);
+    userPanel.add(minUserTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel9.setText("Maximum:");
+    userPanel.add(JLabel9, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    maxUserTextField.setColumns(25);
+    userPanel.add(maxUserTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel2.setText("Delta:");
+    userPanel.add(JLabel2, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    incUserTextField.setColumns(25);
+    userPanel.add(incUserTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    physicalPanel.setBorder(physicalBorder);
+    physicalPanel.setLayout(new GridBagLayout());
+    rangePanel.add(physicalPanel, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel10.setText("Minimum:");
+    physicalPanel.add(JLabel10, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    minPhysicalTextField.setColumns(25);
+    physicalPanel.add(minPhysicalTextField, new GridBagConstraints(1,0,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel17.setText("Maximum:");
+    physicalPanel.add(JLabel17, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    maxPhysicalTextField.setColumns(25);
+    physicalPanel.add(maxPhysicalTextField, new GridBagConstraints(1,1,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    originLabel.setText("Y Origin:");
+    physicalPanel.add(originLabel, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    originTextField.setColumns(20);
+    physicalPanel.add(originTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    originDateEditor.setToolTipText("Edit origin date.");
+    originDateEditor.setActionCommand("...");
+    originDateEditor.setEnabled(false);
+    physicalPanel.add(originDateEditor, new GridBagConstraints(2,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    ticsStylePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(ticsStylePanel, "ticsStylePanel");
+    ticsStylePanel.setBounds(2,27,452,275);
+    ticsStylePanel.setVisible(false);
+    ticsPanel.setBorder(ticsBorder);
+    ticsPanel.setLayout(new GridBagLayout());
+    ticsStylePanel.add(ticsPanel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 10, 10));
+    JLabel18.setText("Large Tic Height:");
+    ticsPanel.add(JLabel18,  new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    largeTicTextField.setColumns(15);
+    ticsPanel.add(largeTicTextField,  new GridBagConstraints(1, 0, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel19.setText("Small Tic Height:");
+    ticsPanel.add(JLabel19,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    smallTicTextField.setColumns(15);
+    ticsPanel.add(smallTicTextField,  new GridBagConstraints(1, 1, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel20.setText("Number of Small Tics:");
+    ticsPanel.add(JLabel20,  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    numSmallTicsTextField.setColumns(5);
+    ticsPanel.add(numSmallTicsTextField,  new GridBagConstraints(1, 2, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel21.setText("Tic Position:");
+    ticsPanel.add(JLabel21,  new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    ticPositionComboBox.setModel(ticPositionCBModel);
+    ticsPanel.add(ticPositionComboBox,  new GridBagConstraints(1, 3, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    ticsPanel.add(lineColorPanel,   new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    stylePanel.setBorder(styleBorder);
+    stylePanel.setLayout(new GridBagLayout());
+    ticsStylePanel.add(stylePanel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 0), 20, 10));
+    JLabel7.setText("Visible:");
+    stylePanel.add(JLabel7, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    axislVisibleCheckBox.setSelected(true);
+    stylePanel.add(axislVisibleCheckBox, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    JLabel6.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    JLabel6.setText("Selectable:");
+    stylePanel.add(JLabel6,  new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 61, 0));
+    axisSelectableCheckBox.setSelected(true);
+    stylePanel.add(axisSelectableCheckBox,   new GridBagConstraints(3, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    attachPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(attachPanel, "attachPanel");
+    attachPanel.setBounds(2,27,452,275);
+    attachPanel.setVisible(false);
+    JLabel23.setText("Attach Transform to Axis:");
+    attachPanel.add(JLabel23,new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    attachPanel.add(transformCheckBox,new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    axisLabel.setText("Attach X Axis to Axis:");
+    attachPanel.add(axisLabel,new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    attachPanel.add(axisCheckBox,new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    ticsPanel.add(jLabel1,     new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    TabbedPane.setSelectedComponent(labelPanel);
+    TabbedPane.setSelectedIndex(0);
+    TabbedPane.setTitleAt(0,"Label");
+    TabbedPane.setTitleAt(1,"Range");
+    TabbedPane.setTitleAt(2,"Tics/Style");
+    TabbedPane.setTitleAt(3,"Attach");
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "LEFT";
+      tempString[1] = "CENTER";
+      tempString[2] = "RIGHT";
+      for(int i=0; i < tempString.length; i++) {
+        horizCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "TOP";
+      tempString[1] = "MIDDLE";
+      tempString[2] = "BOTTOM";
+      for(int i=0; i < tempString.length; i++) {
+        vertCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "POSITIVE_SIDE";
+      tempString[1] = "NEGATIVE_SIDE";
+      tempString[2] = "NO_LABEL";
+      for(int i=0; i < tempString.length; i++) {
+        positionCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "POSITIVE_SIDE";
+      tempString[1] = "NEGATIVE_SIDE";
+      tempString[2] = "BOTH_SIDES";
+      for(int i=0; i < tempString.length; i++) {
+        ticPositionCBModel.addElement(tempString[i]);
+      }
+    }
+    positionComboBox.setSelectedIndex(1);
+    ticPositionComboBox.setSelectedIndex(1);
+    setTitle("TimeAxis");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    minUserTextField.addActionListener(lSymAction);
+    maxUserTextField.addActionListener(lSymAction);
+    originTextField.addActionListener(lSymAction);
+    originDateEditor.addActionListener(lSymAction);
+  }
+  /** Used internally. */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public SpaceAxisDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public SpaceAxisDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == SpaceAxisDialog.this)
+        FontDialog_WindowClosing(event);
+    }
+  }
+
+  void FontDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  //{{DECLARE_CONTROLS
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel labelPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
+  javax.swing.JTextField intervalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
+  javax.swing.JTextField sigDigitsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JTextField formatTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel11 = new javax.swing.JLabel();
+  ColorEntryPanel textColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel15 = new javax.swing.JLabel();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel16 = new javax.swing.JLabel();
+  javax.swing.JTextField heightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JComboBox positionComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel rangePanel = new javax.swing.JPanel();
+  javax.swing.JPanel userPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel8 = new javax.swing.JLabel();
+  javax.swing.JTextField minUserTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel9 = new javax.swing.JLabel();
+  javax.swing.JTextField maxUserTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel2 = new javax.swing.JLabel();
+  javax.swing.JTextField incUserTextField = new javax.swing.JTextField();
+  javax.swing.JPanel physicalPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel10 = new javax.swing.JLabel();
+  javax.swing.JTextField minPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel17 = new javax.swing.JLabel();
+  javax.swing.JTextField maxPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel originLabel = new javax.swing.JLabel();
+  javax.swing.JTextField originTextField = new javax.swing.JTextField();
+  ThreeDotsButton originDateEditor = new ThreeDotsButton();
+  javax.swing.JPanel ticsStylePanel = new javax.swing.JPanel();
+  javax.swing.JPanel ticsPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel18 = new javax.swing.JLabel();
+  javax.swing.JTextField largeTicTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel19 = new javax.swing.JLabel();
+  javax.swing.JTextField smallTicTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel20 = new javax.swing.JLabel();
+  javax.swing.JTextField numSmallTicsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel21 = new javax.swing.JLabel();
+  javax.swing.JComboBox ticPositionComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel stylePanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox axislVisibleCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JCheckBox axisSelectableCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JPanel attachPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel23 = new javax.swing.JLabel();
+  javax.swing.JCheckBox transformCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel axisLabel = new javax.swing.JLabel();
+  javax.swing.JCheckBox axisCheckBox = new javax.swing.JCheckBox();
+  DefaultComboBoxModel horizCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel vertCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel positionCBModel = new DefaultComboBoxModel();
+  javax.swing.border.TitledBorder userBorder = new javax.swing.border.TitledBorder("User Range");
+  javax.swing.border.TitledBorder physicalBorder = new javax.swing.border.TitledBorder("Physical Range");
+  javax.swing.border.TitledBorder ticsBorder = new javax.swing.border.TitledBorder("Tics");
+  javax.swing.border.TitledBorder styleBorder = new javax.swing.border.TitledBorder("Axis Style");
+  DefaultComboBoxModel ticPositionCBModel = new DefaultComboBoxModel();
+  private ColorEntryPanel lineColorPanel = new ColorEntryPanel();
+  private JLabel jLabel1 = new JLabel();
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == originTextField)
+        originTextField_actionPerformed(event);
+      else if (object == originDateEditor)
+        originDateEditor_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateSpaceAxis();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateSpaceAxis();
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    SpaceAxisDialog la = new SpaceAxisDialog();
+    la.setFont(null);
+    la.setTitle("Test SpaceAxis Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Set the <code>SpaceAxis</code> to be edited and the
+   * <code>JPane</code>
+   */
+  public void setSpaceAxis(SpaceAxis sa, JPane pane) {
+    setJPane(pane);
+    setSpaceAxis(sa);
+  }
+  /**
+   * Set the <code>SpaceAxis</code> to be edited
+   */
+  public void setSpaceAxis(SpaceAxis sa) {
+    sa_ = sa;
+    setSpaceAxis();
+  }
+  /**
+   * Get the edited <code>SpaceAxis</code>
+   */
+  public SpaceAxis getSpaceAxis() {
+    return sa_;
+  }
+  /**
+   * Set the parent <code>JPane</code>.
+   */
+  public void setJPane(JPane pane) {
+    pane_ = pane;
+  }
+  /**
+   * Get the parent <code>JPane</code>.
+   */
+  public JPane getJPane() {
+    return pane_;
+  }
+
+  private void setSpaceAxis() {
+    //
+    // time axis ID
+    //
+    setTitle("SpaceAxis - " + sa_.getId());
+    //
+    // label
+    //
+    intervalTextField.setText(Integer.toString(sa_.getLabelInterval()));
+    sigDigitsTextField.setText(Integer.toString(sa_.getSignificantDigits()));
+    formatTextField.setText(sa_.getLabelFormat());
+
+    Color col = sa_.getLabelColor();
+    if(col == null) col = pane_.getComponent().getForeground();
+    textColorPanel.setColor(col);
+
+    labelFont_ = sa_.getLabelFont();
+    if(labelFont_ == null) labelFont_ = pane_.getComponent().getFont();
+    fontLabel.setText(fontString(labelFont_));
+
+    heightTextField.setText(String.valueOf(sa_.getLabelHeightP()));
+    //
+    // range
+    //
+    Range2D urange = sa_.getRangeU();
+    minUserTextField.setText(String.valueOf(urange.start));
+    maxUserTextField.setText(String.valueOf(urange.end));
+    incUserTextField.setText(String.valueOf(urange.delta));
+    Range2D range = sa_.getRangeP();
+    minPhysicalTextField.setText(String.valueOf(range.start));
+    maxPhysicalTextField.setText(String.valueOf(range.end));
+
+    Point2D.Double pt = sa_.getLocationU();
+    TimePoint tt = null;
+    double point = 0.0;
+
+    if(pt == null) {
+      originIsGeoDate_ = true;
+      tt = sa_.getTimeLocationU();
+      tOrigin_ = tt.t;
+    } else {
+      originIsGeoDate_ = false;
+      if(sa_.getOrientation() == Axis.HORIZONTAL) {
+        point = pt.y;
+      } else {
+        point = pt.x;
+      }
+    }
+
+    if(sa_.getOrientation() == Axis.HORIZONTAL) {
+      originLabel.setText("Y Origin:");
+    } else {
+      originLabel.setText("X Origin:");
+    }
+    if(originIsGeoDate_) {
+      originDateEditor.setEnabled(true);
+      originTextField.setText(tOrigin_.toString());
+    } else {
+      originDateEditor.setEnabled(false);
+      originTextField.setText(String.valueOf(point));
+    }
+    //
+    // tics
+    //
+    largeTicTextField.setText(String.valueOf(sa_.getLargeTicHeightP()));
+    smallTicTextField.setText(String.valueOf(sa_.getSmallTicHeightP()));
+    numSmallTicsTextField.setText(String.valueOf(sa_.getNumberSmallTics()));
+    ticPositionComboBox.setSelectedIndex(sa_.getTicPosition());
+
+    Color lcol = sa_.getLineColor();
+    if(lcol == null) col = pane_.getComponent().getForeground();
+    lineColorPanel.setColor(col);
+
+    //
+    // axis style
+    //
+    axislVisibleCheckBox.setSelected(sa_.isVisible());
+    axisSelectableCheckBox.setSelected(sa_.isSelectable());
+    //
+    // attachments
+    //
+    boolean test = sa_.getNumberRegisteredTransforms() > 0;
+    transformCheckBox.setSelected(test);
+
+    if(sa_.getOrientation() == Axis.HORIZONTAL) {
+      test = sa_.getGraph().getNumberXAxis() >= 2;
+      axisLabel.setEnabled(test);
+      axisCheckBox.setEnabled(test);
+      axisLabel.setText("Attach X Axis to Axis:");
+      test = sa_.getNumberRegisteredAxes() > 0;
+      axisCheckBox.setSelected(test);
+    } else {
+      test = sa_.getGraph().getNumberYAxis() >= 2;
+      axisLabel.setEnabled(test);
+      axisCheckBox.setEnabled(test);
+      axisLabel.setText("Attach Y Axis to Axis:");
+      test = sa_.getNumberRegisteredAxes() > 0;
+      axisCheckBox.setSelected(test);
+    }
+
+  }
+
+  private void updateSpaceAxis() {
+    pane_.setBatch(true, "SpaceAxisDialog");
+    //
+    // label
+    //
+    sa_.setLabelInterval(Integer.parseInt(intervalTextField.getText()));
+    sa_.setSignificantDigits(Integer.parseInt(sigDigitsTextField.getText()));
+    sa_.setLabelFormat(formatTextField.getText());
+
+    sa_.setLabelColor(textColorPanel.getColor());
+    if(labelFont_ != null) sa_.setLabelFont(labelFont_);
+
+    sa_.setLabelHeightP(Double.valueOf(heightTextField.getText()).doubleValue());
+    sa_.setLabelPosition(positionComboBox.getSelectedIndex());
+    //
+    // range
+    //
+    double min = Double.valueOf(minUserTextField.getText()).doubleValue();
+    double max = Double.valueOf(maxUserTextField.getText()).doubleValue();
+    double inc = Double.valueOf(incUserTextField.getText()).doubleValue();
+    sa_.setRangeU(new Range2D(min, max, inc));
+    min = Double.valueOf(minPhysicalTextField.getText()).doubleValue();
+    max = Double.valueOf(maxPhysicalTextField.getText()).doubleValue();
+    sa_.setRangeP(new Range2D(min, max));
+    if(originIsGeoDate_) {
+      TimePoint pt = sa_.getTimeLocationU();
+      pt.t = tOrigin_;
+      sa_.setLocationU(pt);
+    } else {
+      Point2D.Double pt = sa_.getLocationU();
+      if(sa_.getOrientation() == Axis.HORIZONTAL) {
+        pt.y = Double.valueOf(originTextField.getText()).doubleValue();
+      } else {
+        pt.x = Double.valueOf(originTextField.getText()).doubleValue();
+      }
+      sa_.setLocationU(pt);
+    }
+    //
+    // tics
+    //
+    sa_.setLargeTicHeightP(Double.valueOf(largeTicTextField.getText()).doubleValue());
+    sa_.setSmallTicHeightP(Double.valueOf(smallTicTextField.getText()).doubleValue());
+    sa_.setNumberSmallTics(Integer.parseInt(numSmallTicsTextField.getText()));
+    sa_.setTicPosition(ticPositionComboBox.getSelectedIndex());
+
+    sa_.setLineColor(lineColorPanel.getColor());
+    //
+    // axis style
+    //
+    sa_.setVisible(axislVisibleCheckBox.isSelected());
+    sa_.setSelectable(axisSelectableCheckBox.isSelected());
+    //
+    // attach
+    //
+    boolean test;
+    if(transformCheckBox.isSelected() && (sa_.getNumberRegisteredTransforms() < 1)) {
+      if(sa_.getOrientation() == Axis.HORIZONTAL) {
+        sa_.register(sa_.getGraph().getXTransform());
+      } else {
+        sa_.register(sa_.getGraph().getYTransform());
+      }
+    } else {
+      if(sa_.getNumberRegisteredTransforms() > 0) sa_.clearAllRegisteredTransforms();
+    }
+    if(sa_.getOrientation() == Axis.HORIZONTAL) {
+      test = (sa_.getGraph().getNumberXAxis() >= 2) &&
+        (sa_.getNumberRegisteredAxes() < 1);
+      if(axisCheckBox.isSelected() && test) {
+        Axis ax;
+        for(Enumeration it = sa_.getGraph().xAxisElements();
+            it.hasMoreElements();) {
+          ax = (Axis)it.nextElement();
+          if(ax.getId() != sa_.getId()) sa_.register(ax);
+        }
+      } else {
+        if(sa_.getNumberRegisteredAxes() > 0) sa_.clearAllRegisteredAxes();
+      }
+    } else {   // vertical axis
+      test = (sa_.getGraph().getNumberYAxis() >= 2) &&
+        (sa_.getNumberRegisteredAxes() < 1);
+      if(axisCheckBox.isSelected() && test) {
+        Axis ax;
+        for(Enumeration it = sa_.getGraph().yAxisElements();
+            it.hasMoreElements();) {
+          ax = (Axis)it.nextElement();
+          if(ax.getId() != sa_.getId()) sa_.register(ax);
+        }
+      } else  {
+        if(sa_.getNumberRegisteredAxes() > 0) sa_.clearAllRegisteredAxes();
+      }
+    }
+
+    pane_.setBatch(false, "SpaceAxisDialog");
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+
+
+  void originTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    if(originIsGeoDate_) {
+      try {
+        tOrigin_ = new GeoDate(originTextField.getText(), dateFormat_);
+      } catch (IllegalTimeValue e) {
+        originTextField.setText(tOrigin_.toString());
+      }
+    }
+  }
+
+  void originDateEditor_actionPerformed(java.awt.event.ActionEvent event)       {
+    GeoDateDialog gd = new GeoDateDialog();
+    Point loc = originDateEditor.getLocationOnScreen();
+    int result = gd.showDialog(tOrigin_, loc.x, loc.y);
+    if(result == GeoDateDialog.OK_RESPONSE) {
+      tOrigin_ = gd.getGeoDate();
+      originTextField.setText(tOrigin_.toString());
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/TimeAxisDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/TimeAxisDialog.java
new file mode 100755
index 0000000..251dab0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/TimeAxisDialog.java
@@ -0,0 +1,768 @@
+/*
+ * $Id: TimeAxisDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.sgt.JPane;
+import gov.noaa.pmel.sgt.TimeAxis;
+import gov.noaa.pmel.sgt.Axis;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.util.TimeRange;
+import gov.noaa.pmel.util.TimePoint;
+
+import gov.noaa.pmel.util.GeoDate;
+import gov.noaa.pmel.util.IllegalTimeValue;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+
+import java.util.Enumeration;
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Edits a <code>TimeAxis</code>. This dialog does not
+ * make a copy of the object so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties.
+ *
+ * <p> Example of <code>TimeAxisDialog</code> use:
+ * <pre>
+ * public void editTimeAxis(TimeAxis axis, JPane pane) {
+ *   TimeAxisDialog tad = new TimeAxisDialog();
+ *   tad.setTimeAxis(axis, pane);
+ *   tad.setVisible(true);
+ * }
+ * </pre>
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.0
+ */
+public class TimeAxisDialog extends JDialog {
+  private JPane pane_;
+  private TimeAxis ta_;
+  private Font labelFont_;
+  private GeoDate startDate_;
+  private GeoDate endDate_;
+  private String[] styleNames_ = {"plain", "bold", "italic", "bold-italic"};
+  private String dateFormat_ = "yyyy-MM-dd HH:mm:ss";
+  /**
+   * Constructor.
+   */
+  public TimeAxisDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  void jbInit() throws Exception {
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(new Dimension(457, 354));
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    jLabel1.setText("Line Color:");
+    getContentPane().add(buttonPanel, "South");
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    //$$ etchedBorder1.move(0,348);
+    getContentPane().add(TabbedPane, "Center");
+    labelPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(labelPanel, "labelPanel");
+    labelPanel.setBounds(2,27,452,275);
+    labelPanel.setVisible(false);
+    JLabel4.setText("format");
+    labelPanel.add(JLabel4, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    JLabel5.setText("interval");
+    labelPanel.add(JLabel5, new GridBagConstraints(2,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    JLabel2.setText("Minor:");
+    labelPanel.add(JLabel2, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    majorFormatTextField.setColumns(5);
+    labelPanel.add(majorFormatTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    majorIntervalTextField.setColumns(3);
+    labelPanel.add(majorIntervalTextField, new GridBagConstraints(2,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel3.setText("Major:");
+    labelPanel.add(JLabel3, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    labelPanel.add(minorFormatTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,5,5,5),0,0));
+    minorIntervalTextField.setColumns(3);
+    labelPanel.add(minorIntervalTextField, new GridBagConstraints(2,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel11.setText("Color:");
+    labelPanel.add(JLabel11, new GridBagConstraints(0,3,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    textColorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(textColorPanel, new GridBagConstraints(1,3,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    JLabel15.setText("Font:");
+    labelPanel.add(JLabel15, new GridBagConstraints(0,4,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    labelPanel.add(fontPanel, new GridBagConstraints(1,4,2,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    fontLabel.setText("Dialog, 12, Bold");
+    fontPanel.add(fontLabel);
+    fontLabel.setForeground(java.awt.Color.black);
+    fontEditor.setToolTipText("Edit font.");
+    fontEditor.setActionCommand("...");
+    fontPanel.add(fontEditor);
+    JLabel16.setText("Height:");
+    labelPanel.add(JLabel16, new GridBagConstraints(0,5,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(15,5,0,5),0,0));
+    heightTextField.setColumns(10);
+    labelPanel.add(heightTextField, new GridBagConstraints(1,5,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(15,5,5,5),0,0));
+    JLabel1.setText("Position:");
+    labelPanel.add(JLabel1, new GridBagConstraints(0,6,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    positionComboBox.setModel(positionCBModel);
+    labelPanel.add(positionComboBox, new GridBagConstraints(1,6,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    rangePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(rangePanel, "rangePanel");
+    rangePanel.setBounds(2,27,452,275);
+    rangePanel.setVisible(false);
+    userPanel.setBorder(userBorder);
+    userPanel.setLayout(new GridBagLayout());
+    rangePanel.add(userPanel, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel8.setText("Minimum:");
+    userPanel.add(JLabel8, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    minUserTextField.setColumns(25);
+    userPanel.add(minUserTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    minDateEditor.setToolTipText("Edit minimum date.");
+    minDateEditor.setActionCommand("...");
+    userPanel.add(minDateEditor, new GridBagConstraints(2,0,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel9.setText("Maximum:");
+    userPanel.add(JLabel9, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    maxUserTextField.setColumns(25);
+    userPanel.add(maxUserTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    maxDateEditor.setToolTipText("Edit max date.");
+    maxDateEditor.setActionCommand("...");
+    userPanel.add(maxDateEditor, new GridBagConstraints(2,1,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    physicalPanel.setBorder(physicalBorder);
+    physicalPanel.setLayout(new GridBagLayout());
+    rangePanel.add(physicalPanel, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,0,5,0),20,15));
+    JLabel10.setText("Minimum:");
+    physicalPanel.add(JLabel10, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    minPhysicalTextField.setColumns(20);
+    physicalPanel.add(minPhysicalTextField, new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    JLabel17.setText("Maximum:");
+    physicalPanel.add(JLabel17, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    maxPhysicalTextField.setColumns(20);
+    physicalPanel.add(maxPhysicalTextField, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    originLabel.setText("Y Origin:");
+    physicalPanel.add(originLabel, new GridBagConstraints(0,2,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    originTextField.setColumns(20);
+    physicalPanel.add(originTextField, new GridBagConstraints(1,2,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    ticsStylePanel.setLayout(new GridBagLayout());
+    TabbedPane.add(ticsStylePanel, "ticsStylePanel");
+    ticsStylePanel.setBounds(2,27,452,275);
+    ticsStylePanel.setVisible(false);
+    ticsPanel.setBorder(ticsBorder);
+    ticsPanel.setLayout(new GridBagLayout());
+    ticsStylePanel.add(ticsPanel,   new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 10, 10));
+    JLabel18.setText("Large Tic Height:");
+    ticsPanel.add(JLabel18,  new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    largeTicTextField.setColumns(15);
+    ticsPanel.add(largeTicTextField,   new GridBagConstraints(1, 0, 2, 1, 1.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel19.setText("Small Tic Height:");
+    ticsPanel.add(JLabel19,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    smallTicTextField.setColumns(15);
+    ticsPanel.add(smallTicTextField,   new GridBagConstraints(1, 1, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel20.setText("Number of Small Tics:");
+    ticsPanel.add(JLabel20,  new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    numSmallTicsTextField.setColumns(5);
+    ticsPanel.add(numSmallTicsTextField,   new GridBagConstraints(1, 2, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel21.setText("Tic Position:");
+    ticsPanel.add(JLabel21,  new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    ticPositionComboBox.setModel(ticPositionCBModel);
+    ticsPanel.add(ticPositionComboBox,  new GridBagConstraints(1, 3, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    ticsPanel.add(jLabel1,    new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    ticsPanel.add(lineColorPanel,   new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    stylePanel.setBorder(styleBorder);
+    stylePanel.setLayout(new GridBagLayout());
+    ticsStylePanel.add(stylePanel,  new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 0), 10, 10));
+    JLabel22.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    JLabel22.setText("Time Axis Style:");
+    stylePanel.add(JLabel22, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),34,0));
+    axisStyleComboBox.setModel(styleCBModel);
+    axisStyleComboBox.setEnabled(false);
+    stylePanel.add(axisStyleComboBox,  new GridBagConstraints(1, 0, 2, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    JLabel7.setText("Visible:");
+    stylePanel.add(JLabel7, new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,0,5),0,0));
+    axislVisibleCheckBox.setSelected(true);
+    stylePanel.add(axislVisibleCheckBox, new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0));
+    JLabel6.setText("Selectable:");
+    stylePanel.add(JLabel6,  new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    axisSelectableCheckBox.setSelected(true);
+    stylePanel.add(axisSelectableCheckBox,  new GridBagConstraints(3, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    attachPanel.setLayout(new GridBagLayout());
+    TabbedPane.add(attachPanel, "attachPanel");
+    attachPanel.setBounds(2,27,452,275);
+    attachPanel.setVisible(false);
+    JLabel23.setText("Attach Transform to Axis:");
+    attachPanel.add(JLabel23,new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    attachPanel.add(transformCheckBox,new GridBagConstraints(1,0,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    axisLabel.setText("Attach X Axis to Axis:");
+    attachPanel.add(axisLabel,new GridBagConstraints(0,1,1,1,0.0,0.0,
+    GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+    attachPanel.add(axisCheckBox,new GridBagConstraints(1,1,1,1,0.0,0.0,
+    GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,5,5,5),0,0));
+
+    TabbedPane.setTitleAt(0,"Label");
+    TabbedPane.setTitleAt(1,"Range");
+    TabbedPane.setTitleAt(2,"Tics/Style");
+    TabbedPane.setTitleAt(3,"Attach");
+
+    {
+      String[] horizString = new String[3];
+      horizString[0] = "LEFT";
+      horizString[1] = "CENTER";
+      horizString[2] = "RIGHT";
+      for(int i=0; i < horizString.length; i++) {
+         horizCBModel.addElement(horizString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "TOP";
+      tempString[1] = "MIDDLE";
+      tempString[2] = "BOTTOM";
+      for(int i=0; i < tempString.length; i++) {
+        vertCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "POSITIVE_SIDE";
+      tempString[1] = "NEGATIVE_SIDE";
+      tempString[2] = "NO_LABEL";
+      for(int i=0; i < tempString.length; i++) {
+  positionCBModel.addElement(tempString[i]);
+      }
+    }
+   {
+      String[] tempString = new String[3];
+      tempString[0] = "POSITIVE_SIDE";
+      tempString[1] = "NEGATIVE_SIDE";
+      tempString[2] = "BOTH_SIDES";
+      for(int i=0; i < tempString.length; i++) {
+        ticPositionCBModel.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[6];
+      tempString[0] = "Auto";
+      tempString[1] = "Year/Decade";
+      tempString[2] = "Month/Year";
+      tempString[3] = "Day/Month";
+      tempString[4] = "Hour/Day";
+      tempString[5] = "Minute/Hour";
+      for(int i=0; i < tempString.length; i++) {
+        styleCBModel.addElement(tempString[i]);
+      }
+    }
+
+    setTitle("TimeAxis");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    fontEditor.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+    minDateEditor.addActionListener(lSymAction);
+    maxDateEditor.addActionListener(lSymAction);
+    minUserTextField.addActionListener(lSymAction);
+    maxUserTextField.addActionListener(lSymAction);
+
+  }
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public TimeAxisDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor
+   */
+  public TimeAxisDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == TimeAxisDialog.this)
+        FontDialog_WindowClosing(event);
+    }
+  }
+
+  void FontDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  //{{DECLARE_CONTROLS
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  javax.swing.JTabbedPane TabbedPane = new javax.swing.JTabbedPane();
+  javax.swing.JPanel labelPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
+  javax.swing.JLabel JLabel2 = new javax.swing.JLabel();
+  javax.swing.JTextField majorFormatTextField = new javax.swing.JTextField();
+  javax.swing.JTextField majorIntervalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
+  javax.swing.JTextField minorFormatTextField = new javax.swing.JTextField();
+  javax.swing.JTextField minorIntervalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel11 = new javax.swing.JLabel();
+  ColorEntryPanel textColorPanel = new ColorEntryPanel();
+  javax.swing.JLabel JLabel15 = new javax.swing.JLabel();
+  javax.swing.JPanel fontPanel = new javax.swing.JPanel();
+  javax.swing.JLabel fontLabel = new javax.swing.JLabel();
+  ThreeDotsButton fontEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel16 = new javax.swing.JLabel();
+  javax.swing.JTextField heightTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
+  javax.swing.JComboBox positionComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel rangePanel = new javax.swing.JPanel();
+  javax.swing.JPanel userPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel8 = new javax.swing.JLabel();
+  javax.swing.JTextField minUserTextField = new javax.swing.JTextField();
+  ThreeDotsButton minDateEditor = new ThreeDotsButton();
+  javax.swing.JLabel JLabel9 = new javax.swing.JLabel();
+  javax.swing.JTextField maxUserTextField = new javax.swing.JTextField();
+  ThreeDotsButton maxDateEditor = new ThreeDotsButton();
+  javax.swing.JPanel physicalPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel10 = new javax.swing.JLabel();
+  javax.swing.JTextField minPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel17 = new javax.swing.JLabel();
+  javax.swing.JTextField maxPhysicalTextField = new javax.swing.JTextField();
+  javax.swing.JLabel originLabel = new javax.swing.JLabel();
+  javax.swing.JTextField originTextField = new javax.swing.JTextField();
+  javax.swing.JPanel ticsStylePanel = new javax.swing.JPanel();
+  javax.swing.JPanel ticsPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel18 = new javax.swing.JLabel();
+  javax.swing.JTextField largeTicTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel19 = new javax.swing.JLabel();
+  javax.swing.JTextField smallTicTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel20 = new javax.swing.JLabel();
+  javax.swing.JTextField numSmallTicsTextField = new javax.swing.JTextField();
+  javax.swing.JLabel JLabel21 = new javax.swing.JLabel();
+  javax.swing.JComboBox ticPositionComboBox = new javax.swing.JComboBox();
+  javax.swing.JPanel stylePanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel22 = new javax.swing.JLabel();
+  javax.swing.JComboBox axisStyleComboBox = new javax.swing.JComboBox();
+  javax.swing.JLabel JLabel7 = new javax.swing.JLabel();
+  javax.swing.JCheckBox axislVisibleCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel JLabel6 = new javax.swing.JLabel();
+  javax.swing.JCheckBox axisSelectableCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JPanel attachPanel = new javax.swing.JPanel();
+  javax.swing.JLabel JLabel23 = new javax.swing.JLabel();
+  javax.swing.JCheckBox transformCheckBox = new javax.swing.JCheckBox();
+  javax.swing.JLabel axisLabel = new javax.swing.JLabel();
+  javax.swing.JCheckBox axisCheckBox = new javax.swing.JCheckBox();
+  DefaultComboBoxModel horizCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel vertCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel positionCBModel = new DefaultComboBoxModel();
+  javax.swing.border.TitledBorder userBorder = new javax.swing.border.TitledBorder("User Range");
+  javax.swing.border.TitledBorder physicalBorder = new javax.swing.border.TitledBorder("Physical Range");
+  javax.swing.border.TitledBorder ticsBorder = new javax.swing.border.TitledBorder("Tics");
+  javax.swing.border.TitledBorder styleBorder = new javax.swing.border.TitledBorder("Axis Style");
+  DefaultComboBoxModel ticPositionCBModel = new DefaultComboBoxModel();
+  DefaultComboBoxModel styleCBModel = new DefaultComboBoxModel();
+  private JLabel jLabel1 = new JLabel();
+  private ColorEntryPanel lineColorPanel = new ColorEntryPanel();
+  //}}
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == fontEditor)
+        fontEditor_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == minDateEditor)
+        minDateEditor_actionPerformed(event);
+      else if (object == maxDateEditor)
+        maxDateEditor_actionPerformed(event);
+      else if (object == minUserTextField)
+        minUserTextField_actionPerformed(event);
+      else if (object == maxUserTextField)
+        maxUserTextField_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateTimeAxis();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateTimeAxis();
+  }
+  /**
+   * Test entry point
+   */
+  public static void main(String[] args) {
+    TimeAxisDialog la = new TimeAxisDialog();
+    la.setFont(null);
+    la.setTitle("Test TimeAxis Dialog");
+    la.setVisible(true);
+  }
+  /**
+   * Set the <code>TimeAxis</code> to be edited and the
+   * <code>JPane</code>
+   */
+  public void setTimeAxis(TimeAxis ta, JPane pane) {
+    setJPane(pane);
+    setTimeAxis(ta);
+  }
+  /**
+   * Set the <code>TimeAxis</code> to be edited
+   */
+  public void setTimeAxis(TimeAxis ta) {
+    ta_ = ta;
+    setTimeAxis();
+  }
+  /**
+   * Get the edited <code>TimeAxis</code>
+   */
+  public TimeAxis getTimeAxis() {
+    return ta_;
+  }
+  /**
+   * Set the parent <code>JPane</code>.
+   */
+  public void setJPane(JPane pane) {
+    pane_ = pane;
+  }
+  /**
+   * Get the parent <code>JPane</code>.
+   */
+  public JPane getJPane() {
+    return pane_;
+  }
+
+  private void setTimeAxis() {
+    //
+    // time axis ID
+    //
+    setTitle("TimeAxis - " + ta_.getId());
+    //
+    // label
+    //
+    majorFormatTextField.setText(ta_.getMajorLabelFormat());
+    majorIntervalTextField.setText(Integer.toString(ta_.getMajorLabelInterval()));
+    minorFormatTextField.setText(ta_.getMinorLabelFormat());
+    minorIntervalTextField.setText(Integer.toString(ta_.getMinorLabelInterval()));
+
+    Color col = ta_.getLabelColor();
+    if(col == null) col = pane_.getComponent().getForeground();
+    textColorPanel.setColor(col);
+
+    labelFont_ = ta_.getLabelFont();
+    if(labelFont_ == null) labelFont_ = pane_.getComponent().getFont();
+    fontLabel.setText(fontString(labelFont_));
+
+    heightTextField.setText(String.valueOf(ta_.getLabelHeightP()));
+
+    positionComboBox.setSelectedIndex(ta_.getLabelPosition());
+    //
+    // range
+    //
+    TimeRange trange = ta_.getTimeRangeU();
+    startDate_ = trange.start;
+    endDate_ = trange.end;
+    minUserTextField.setText(startDate_.toString());
+    maxUserTextField.setText(endDate_.toString());
+    Range2D range = ta_.getRangeP();
+    minPhysicalTextField.setText(String.valueOf(range.start));
+    maxPhysicalTextField.setText(String.valueOf(range.end));
+
+    TimePoint pt = ta_.getLocationU();
+
+    if(ta_.getOrientation() == Axis.HORIZONTAL) {
+      originLabel.setText("Y Origin:");
+      originTextField.setText(String.valueOf(pt.x));
+    } else {
+      originLabel.setText("X Origin:");
+      originTextField.setText(String.valueOf(pt.x));
+    }
+    //
+    // tics
+    //
+    largeTicTextField.setText(String.valueOf(ta_.getLargeTicHeightP()));
+    smallTicTextField.setText(String.valueOf(ta_.getSmallTicHeightP()));
+    numSmallTicsTextField.setText(String.valueOf(ta_.getNumberSmallTics()));
+    ticPositionComboBox.setSelectedIndex(ta_.getTicPosition());
+    col = ta_.getLineColor();
+    if(col == null) col = pane_.getComponent().getForeground();
+    lineColorPanel.setColor(col);
+    //
+    // axis style
+    //
+    axisStyleComboBox.setSelectedIndex(ta_.getStyle());
+    axislVisibleCheckBox.setSelected(ta_.isVisible());
+    axisSelectableCheckBox.setSelected(ta_.isSelectable());
+    //
+    // attachments
+    //
+    boolean test = ta_.getNumberRegisteredTransforms() > 0;
+    transformCheckBox.setSelected(test);
+
+    if(ta_.getOrientation() == Axis.HORIZONTAL) {
+      test = ta_.getGraph().getNumberXAxis() >= 2;
+      axisLabel.setEnabled(test);
+      axisCheckBox.setEnabled(test);
+      axisLabel.setText("Attach X Axis to Axis:");
+      test = ta_.getNumberRegisteredAxes() > 0;
+      axisCheckBox.setSelected(test);
+    } else {
+      test = ta_.getGraph().getNumberYAxis() >= 2;
+      axisLabel.setEnabled(test);
+      axisCheckBox.setEnabled(test);
+      axisLabel.setText("Attach Y Axis to Axis:");
+      test = ta_.getNumberRegisteredAxes() > 0;
+      axisCheckBox.setSelected(test);
+    }
+
+  }
+
+  private void updateTimeAxis() {
+    pane_.setBatch(true, "TimeAxisDialog");
+    //
+    // label
+    //
+    ta_.setMajorLabelFormat(majorFormatTextField.getText());
+    ta_.setMajorLabelInterval(Integer.parseInt(majorIntervalTextField.getText()));
+    ta_.setMinorLabelFormat(minorFormatTextField.getText());
+    ta_.setMinorLabelInterval(Integer.parseInt(minorIntervalTextField.getText()));
+
+    ta_.setLabelColor(textColorPanel.getColor());
+    if(labelFont_ != null) ta_.setLabelFont(labelFont_);
+
+    ta_.setLabelHeightP(Double.valueOf(heightTextField.getText()).doubleValue());
+    ta_.setLabelPosition(positionComboBox.getSelectedIndex());
+    //
+    // range
+    //
+    ta_.setRangeU(new TimeRange(startDate_, endDate_));
+    double min = Double.valueOf(minPhysicalTextField.getText()).doubleValue();
+    double max = Double.valueOf(maxPhysicalTextField.getText()).doubleValue();
+    ta_.setRangeP(new Range2D(min, max));
+    TimePoint pt = ta_.getLocationU();
+    pt.x = Double.valueOf(originTextField.getText()).doubleValue();
+    ta_.setLocationU(pt);
+    //
+    // tics
+    //
+    ta_.setLargeTicHeightP(Double.valueOf(largeTicTextField.getText()).doubleValue());
+    ta_.setSmallTicHeightP(Double.valueOf(smallTicTextField.getText()).doubleValue());
+    ta_.setNumberSmallTics(Integer.parseInt(numSmallTicsTextField.getText()));
+    ta_.setTicPosition(ticPositionComboBox.getSelectedIndex());
+    ta_.setLineColor(lineColorPanel.getColor());
+    //
+    // axis style
+    //
+    ta_.setVisible(axislVisibleCheckBox.isSelected());
+    ta_.setSelectable(axisSelectableCheckBox.isSelected());
+    //
+    // attach
+    //
+    boolean test;
+    if(transformCheckBox.isSelected() && (ta_.getNumberRegisteredTransforms() < 1)) {
+      if(ta_.getOrientation() == Axis.HORIZONTAL) {
+        ta_.register(ta_.getGraph().getXTransform());
+      } else {
+        ta_.register(ta_.getGraph().getYTransform());
+      }
+    } else {
+      if(ta_.getNumberRegisteredTransforms() > 0) ta_.clearAllRegisteredTransforms();
+    }
+    if(ta_.getOrientation() == Axis.HORIZONTAL) {
+      test = (ta_.getGraph().getNumberXAxis() >= 2) &&
+        (ta_.getNumberRegisteredAxes() < 1);
+      if(axisCheckBox.isSelected() && test) {
+        Axis ax;
+        for(Enumeration it = ta_.getGraph().xAxisElements();
+            it.hasMoreElements();) {
+          ax = (Axis)it.nextElement();
+          if(ax.getId() != ta_.getId()) ta_.register(ax);
+        }
+      } else {
+        if(ta_.getNumberRegisteredAxes() > 0) ta_.clearAllRegisteredAxes();
+      }
+    } else {   // vertical axis
+      test = (ta_.getGraph().getNumberYAxis() >= 2) &&
+        (ta_.getNumberRegisteredAxes() < 1);
+      if(axisCheckBox.isSelected() && test) {
+        Axis ax;
+        for(Enumeration it = ta_.getGraph().yAxisElements();
+            it.hasMoreElements();) {
+          ax = (Axis)it.nextElement();
+          if(ax.getId() != ta_.getId()) ta_.register(ax);
+        }
+      } else  {
+        if(ta_.getNumberRegisteredAxes() > 0) ta_.clearAllRegisteredAxes();
+      }
+    }
+
+    pane_.setBatch(false, "TimeAxisDialog");
+  }
+
+  void fontEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    FontDialog fd = new FontDialog();
+    int result = fd.showDialog(labelFont_);
+    if(result == FontDialog.OK_RESPONSE) {
+      labelFont_ = fd.getFont();
+      fontLabel.setText(fontString(labelFont_));
+      fontLabel.setFont(labelFont_);
+    }
+  }
+
+  String fontString(Font font) {
+    int style = (font.isBold()?1:0) + (font.isItalic()?2:0);
+    return font.getName() + " " + styleNames_[style];
+  }
+
+
+  void minDateEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    GeoDateDialog gd = new GeoDateDialog();
+    Point loc = minDateEditor.getLocationOnScreen();
+    int result = gd.showDialog(startDate_, loc.x, loc.y);
+    if(result == GeoDateDialog.OK_RESPONSE) {
+      startDate_ = gd.getGeoDate();
+      minUserTextField.setText(startDate_.toString());
+    }
+  }
+
+  void maxDateEditor_actionPerformed(java.awt.event.ActionEvent  event) {
+    GeoDateDialog gd = new GeoDateDialog();
+    Point loc = maxDateEditor.getLocationOnScreen();
+    int result = gd.showDialog(endDate_, loc.x, loc.y);
+    if(result == GeoDateDialog.OK_RESPONSE) {
+      endDate_ = gd.getGeoDate();
+      maxUserTextField.setText(endDate_.toString());
+    }
+  }
+
+  void minUserTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    try {
+      startDate_ = new GeoDate(minUserTextField.getText(), dateFormat_);
+    } catch (IllegalTimeValue e) {
+      minUserTextField.setText(startDate_.toString());
+    }
+  }
+
+  void maxUserTextField_actionPerformed(java.awt.event.ActionEvent event) {
+    try {
+      endDate_ = new GeoDate(maxUserTextField.getText(), dateFormat_);
+    } catch (IllegalTimeValue e) {
+      maxUserTextField.setText(endDate_.toString());
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/VectorAttributeDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/VectorAttributeDialog.java
new file mode 100755
index 0000000..d46d40e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/VectorAttributeDialog.java
@@ -0,0 +1,687 @@
+/*
+ * $Id: VectorAttributeDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package gov.noaa.pmel.sgt.swing.prop;
+
+import gov.noaa.pmel.sgt.JPane;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.StringTokenizer;
+
+import gov.noaa.pmel.sgt.VectorAttribute;
+import gov.noaa.pmel.sgt.swing.PlotMarkIcon;
+import gov.noaa.pmel.swing.ThreeDotsButton;
+import javax.swing.border.*;
+import java.awt.event.*;
+
+/**
+ * Edits a <code>VectorAttribute</code>. This dialog does not
+ * make a copy of the attribute so changes "Applied" will cause
+ * <code>sgt</code> to redraw the plot using the new properties unless
+ * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching}
+ * has been turned on.
+ *
+ * <p> Example of <code>VectorAttributeDialog</code> use:
+ * <pre>
+ * public void editVectorAttribute(VectorAttribute attr) {
+ *   VectorAttributeDialog lad = new VectorAttributeDialog();
+ *   lad.setVectorAttribute(attr);
+ *   lad.setVisible(true);
+ * }
+ * </pre>
+ * *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 2.1
+ * @see PlotMarkDialog
+ * @see ArrayEditDialog
+ */
+public class VectorAttributeDialog extends JDialog {
+  private VectorAttribute attr_;
+  private PlotMarkIcon pmIcon_;
+  private int mark_;
+  private JPane[] paneList_ = null;
+  /**
+   * Constructor.
+   */
+  public VectorAttributeDialog(Frame parent) {
+    super(parent);
+    try {
+      jbInit();
+      pack();
+    } catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+
+  void jbInit() throws Exception {
+    //
+    pmIcon_ = new PlotMarkIcon(1);
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "NO_HEAD";
+      tempString[1] = "HEAD";
+      tempString[2] = "SCALED_HEAD";
+      for(int i=0; i < tempString.length; i++) {
+        vectorStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[2];
+      tempString[0] = "NO_MARK";
+      tempString[1] = "MARK";
+      for(int i=0; i < tempString.length; i++) {
+        originStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "BUTT";
+      tempString[1] = "ROUND";
+      tempString[2] = "SQUARE";
+      for(int i=0; i < tempString.length; i++) {
+        capStyleCBM.addElement(tempString[i]);
+      }
+    }
+    {
+      String[] tempString = new String[3];
+      tempString[0] = "MITER";
+      tempString[1] = "ROUND";
+      tempString[2] = "BEVEL";
+      for(int i=0; i < tempString.length; i++) {
+        miterStyleCBM.addElement(tempString[i]);
+      }
+    }
+    getContentPane().setLayout(new BorderLayout(0,0));
+    setSize(500,490);
+    setVisible(false);
+    buttonPanel.setBorder(etchedBorder1);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    vectorMaxSizeTextField.setColumns(8);
+    vectorScaleTextField.setColumns(8);
+    JLabel5.setText("Style:");
+    colorPanel.setBorder(etchedBorder1);
+    colorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    JLabel1.setText("Color:");
+    offsetAngleTextField.setColumns(8);
+    vectorStyleComboBox.setModel(vectorStyleCBM);
+    vectorStyleComboBox.addActionListener(new VectorAttributeDialog_vectorStyleComboBox_actionAdapter(this));
+    jLabel7.setText("Offset Angle:");
+    jLabel6.setText("Max Size:");
+    jLabel5.setText("Scale:");
+    vectorPanel.setLayout(gridBagLayout2);
+    jLabel11.setText("Fixed Size:");
+    jLabel10.setText("Max Size:");
+    headMinSizeTextField.setColumns(8);
+    jLabel9.setText("Min Size:");
+    jLabel8.setText("Scale:");
+    headScaleTextField.setColumns(8);
+    headMaxSizeTextField.setColumns(8);
+    headFixedSizeTextField.setColumns(8);
+    headPanel.setLayout(gridBagLayout4);
+    markHeightTextField.setColumns(8);
+    originStyleComboBox.setModel(originStyleCBM);
+    JLabel12.setText("Color:");
+    JLabel7.setText("Mark Height:");
+    JLabel6.setText("Mark:");
+    markPanel.setLayout(new GridBagLayout());
+    markEditor.addActionListener(new VectorAttributeDialog_markEditor_actionAdapter(this));
+    markEditor.setActionCommand("...");
+//    markEditor.setMargin(new Insets(0, 0, 0, 0));
+    markColorPanel.setBorder(etchedBorder1);
+    Mark.setLayout(gridBagLayout3);
+    jLabel4.setText("Style:");
+    plotMarkIconLabel.setForeground(java.awt.Color.black);
+    plotMarkIconLabel.setIcon(pmIcon_);
+    miterLimitTextField.setColumns(8);
+    JLabel10.setText(" Width:");
+    strokePanel.setLayout(gridBagLayout1);
+    miterStyleComboBox.setModel(miterStyleCBM);
+    jLabel3.setText("Miter Limit:");
+    jLabel2.setText("Miter Style:");
+    jLabel1.setText("Cap Style:");
+    capStyleComboBox.setModel(capStyleCBM);
+    widthTextField.setColumns(8);
+    getContentPane().add(buttonPanel, "South");
+    buttonPanel.setBounds(0,263,430,39);
+    okButton.setText("OK");
+    okButton.setActionCommand("OK");
+    buttonPanel.add(okButton);
+    okButton.setBounds(115,7,51,25);
+    applyButton.setText("Apply");
+    applyButton.setActionCommand("Apply");
+    buttonPanel.add(applyButton);
+    applyButton.setBounds(171,7,65,25);
+    cancelButton.setText("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPanel.add(cancelButton);
+    cancelButton.setBounds(241,7,73,25);
+    //$$ etchedBorder1.move(0,300);
+    this.getContentPane().add(jTabbedPane1, BorderLayout.CENTER);
+    jTabbedPane1.add(vectorPanel, "Vector");
+    vectorPanel.add(vectorStyleComboBox, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(15, 5, 5, 5), 0, 0));
+    vectorPanel.add(colorPanel, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 15), 0, 0));
+    vectorPanel.add(JLabel1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    vectorPanel.add(jLabel5, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 6, 0, 6), 0, 0));
+    vectorPanel.add(jLabel6, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    vectorPanel.add(jLabel7, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 15, 10, 5), 0, 0));
+    vectorPanel.add(vectorScaleTextField, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    vectorPanel.add(vectorMaxSizeTextField, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    vectorPanel.add(offsetAngleTextField, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 15, 5), 0, 0));
+    vectorPanel.add(JLabel5, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(10, 5, 0, 5), 0, 0));
+    jTabbedPane1.add(headPanel, "Head");
+    headPanel.add(jLabel8, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    headPanel.add(headScaleTextField, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    headPanel.add(jLabel9, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    headPanel.add(jLabel10, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    headPanel.add(headMinSizeTextField, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    headPanel.add(headMaxSizeTextField, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    headPanel.add(jLabel11, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    headPanel.add(headFixedSizeTextField, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    jTabbedPane1.add(Mark, "Mark");
+    Mark.add(markPanel, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+    markPanel.add(plotMarkIconLabel, new GridBagConstraints(0,0,1,1,0.0,0.0,
+    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+    markPanel.add(markEditor, new GridBagConstraints(2,0,1,1,0.0,1.0,
+    GridBagConstraints.CENTER,GridBagConstraints.VERTICAL,new Insets(0,0,0,0),0,0));
+    Mark.add(JLabel6, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    Mark.add(JLabel7, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 15, 10, 5), 0, 0));
+    Mark.add(markHeightTextField, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 15, 5), 0, 0));
+    Mark.add(markColorPanel, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 15), 0, 0));
+    Mark.add(JLabel12, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    Mark.add(jLabel4, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(10, 5, 0, 5), 0, 0));
+    Mark.add(originStyleComboBox, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(15, 5, 5, 5), 0, 0));
+    jTabbedPane1.add(strokePanel, "Line Style");
+    strokePanel.add(JLabel10, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(widthTextField, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(jLabel1, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(jLabel2, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(capStyleComboBox, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(miterStyleComboBox, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    strokePanel.add(jLabel3, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
+    strokePanel.add(miterLimitTextField, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
+            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
+    //$$ stringComboBoxModel1.move(24,300);
+    setTitle("VectorAttribute Properties");
+
+    SymWindow aSymWindow = new SymWindow();
+    this.addWindowListener(aSymWindow);
+    SymAction lSymAction = new SymAction();
+    cancelButton.addActionListener(lSymAction);
+    okButton.addActionListener(lSymAction);
+    applyButton.addActionListener(lSymAction);
+  }
+
+  /** Used internally */
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension d = getSize();
+
+    super.addNotify();
+
+    if (fComponentsAdjusted)
+      return;
+
+    // Adjust components according to the insets
+    Insets ins = getInsets();
+    setSize(ins.left + ins.right + d.width, ins.top + ins.bottom + d.height);
+    Component components[] = getContentPane().getComponents();
+    for (int i = 0; i < components.length; i++) {
+      Point p = components[i].getLocation();
+      p.translate(ins.left, ins.top);
+      components[i].setLocation(p);
+    }
+    fComponentsAdjusted = true;
+  }
+
+  // Used for addNotify check.
+  boolean fComponentsAdjusted = false;
+  /**
+   * Constructor.
+   */
+  public VectorAttributeDialog(String title) {
+    this();
+    setTitle(title);
+  }
+  /**
+   * Default constructor.
+   */
+  public VectorAttributeDialog() {
+    this((Frame)null);
+  }
+  /**
+   * Make the dialog visible
+   */
+  public void setVisible(boolean b) {
+    if(b) {
+      setLocation(50, 50);
+    }
+    super.setVisible(b);
+  }
+
+  class SymWindow extends java.awt.event.WindowAdapter {
+    public void windowClosing(java.awt.event.WindowEvent event) {
+      Object object = event.getSource();
+      if (object == VectorAttributeDialog.this)
+  VectorAttributeDialog_WindowClosing(event);
+    }
+  }
+
+  void VectorAttributeDialog_WindowClosing(java.awt.event.WindowEvent event) {
+    dispose();
+  }
+
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton okButton = new javax.swing.JButton();
+  javax.swing.JButton applyButton = new javax.swing.JButton();
+  javax.swing.JButton cancelButton = new javax.swing.JButton();
+  javax.swing.border.EtchedBorder etchedBorder1 = new javax.swing.border.EtchedBorder();
+  DefaultComboBoxModel vectorStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel originStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel capStyleCBM = new DefaultComboBoxModel();
+  DefaultComboBoxModel miterStyleCBM = new DefaultComboBoxModel();
+  JTabbedPane jTabbedPane1 = new JTabbedPane();
+  JTextField vectorMaxSizeTextField = new JTextField();
+  GridBagLayout gridBagLayout2 = new GridBagLayout();
+  JTextField vectorScaleTextField = new JTextField();
+  JLabel JLabel5 = new javax.swing.JLabel();
+  ColorEntryPanel colorPanel = new ColorEntryPanel();
+  JLabel JLabel1 = new javax.swing.JLabel();
+  JTextField offsetAngleTextField = new JTextField();
+  JComboBox vectorStyleComboBox = new javax.swing.JComboBox();
+  JLabel jLabel7 = new JLabel();
+  JLabel jLabel6 = new JLabel();
+  JLabel jLabel5 = new JLabel();
+  JPanel vectorPanel = new JPanel();
+  JLabel jLabel11 = new JLabel();
+  JLabel jLabel10 = new JLabel();
+  GridBagLayout gridBagLayout4 = new GridBagLayout();
+  JTextField headMinSizeTextField = new JTextField();
+  JLabel jLabel9 = new JLabel();
+  JLabel jLabel8 = new JLabel();
+  JTextField headScaleTextField = new JTextField();
+  JTextField headMaxSizeTextField = new JTextField();
+  JTextField headFixedSizeTextField = new JTextField();
+  JPanel headPanel = new JPanel();
+  JTextField markHeightTextField = new javax.swing.JTextField();
+  GridBagLayout gridBagLayout3 = new GridBagLayout();
+  JComboBox originStyleComboBox = new JComboBox();
+  JLabel JLabel12 = new javax.swing.JLabel();
+  JLabel JLabel7 = new javax.swing.JLabel();
+  JLabel JLabel6 = new javax.swing.JLabel();
+  JPanel markPanel = new javax.swing.JPanel();
+  ThreeDotsButton markEditor = new ThreeDotsButton();
+  ColorEntryPanel markColorPanel = new ColorEntryPanel();
+  JPanel Mark = new JPanel();
+  JLabel jLabel4 = new JLabel();
+  JLabel plotMarkIconLabel = new javax.swing.JLabel();
+  GridBagLayout gridBagLayout1 = new GridBagLayout();
+  JTextField miterLimitTextField = new JTextField();
+  JLabel JLabel10 = new javax.swing.JLabel();
+  JPanel strokePanel = new JPanel();
+  JComboBox miterStyleComboBox = new JComboBox();
+  JLabel jLabel3 = new JLabel();
+  JLabel jLabel2 = new JLabel();
+  JLabel jLabel1 = new JLabel();
+  JComboBox capStyleComboBox = new JComboBox();
+  JTextField widthTextField = new javax.swing.JTextField();
+
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event) {
+      Object object = event.getSource();
+      if (object == cancelButton)
+        cancelButton_actionPerformed(event);
+      else if (object == okButton)
+        okButton_actionPerformed(event);
+      else if (object == applyButton)
+        applyButton_actionPerformed(event);
+      else if (object == markEditor)
+        markEditor_actionPerformed(event);
+    }
+  }
+
+  void cancelButton_actionPerformed(java.awt.event.ActionEvent event) {
+    this.setVisible(false);
+  }
+
+  void okButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateVectorAttribute();
+    this.setVisible(false);
+  }
+
+  void applyButton_actionPerformed(java.awt.event.ActionEvent event) {
+    updateVectorAttribute();
+  }
+  /**
+   * Set the <code>VectorAttribute</code> for the dialog.
+   */
+  public void setVectorAttribute(VectorAttribute attr) {
+    attr_ = attr;
+    //
+    // Vector
+    //
+    // Color
+    //
+    colorPanel.setColor(attr_.getVectorColor());
+    //
+    // style
+    //
+    vectorStyleComboBox.setSelectedIndex(attr_.getVectorStyle());
+    vectorStyle(attr_.getVectorStyle());
+    //
+    // vectorScale
+    //
+    vectorScaleTextField.setText(Double.toString(attr_.getVectorScale()));
+    //
+    // vector max size
+    //
+    vectorMaxSizeTextField.setText(Double.toString(attr_.getVectorMaxSize()));
+    //
+    // offset angle
+    //
+    offsetAngleTextField.setText(Double.toString(attr_.getOffsetAngle()));
+    //
+    // head
+    //
+    //
+    // scale
+    //
+    headScaleTextField.setText(Double.toString(attr_.getHeadScale()));
+    //
+    // head max size
+    //
+    headMaxSizeTextField.setText(Double.toString(attr_.getHeadMaxSize()));
+    //
+    // head min size
+    //
+    headMinSizeTextField.setText(Double.toString(attr_.getHeadMinSize()));
+    //
+    // head fixed size
+    //
+    headFixedSizeTextField.setText(Double.toString(attr_.getHeadFixedSize()));
+    //
+    // origin
+    //
+    // style
+    //
+    originStyleComboBox.setSelectedIndex(attr_.getOriginStyle());
+    //
+    // mark
+    //
+    int mark = attr_.getMark();
+    changeMark(mark);
+//    System.out.println(" mark code = " + mark);
+    //
+    // Color
+    //
+    markColorPanel.setColor(attr_.getMarkColor());
+    //
+    // mark height
+    //
+    markHeightTextField.setText(Double.toString(attr_.getMarkHeightP()));
+    //
+    // Stroke line attributes
+    //
+    // width
+    //
+    widthTextField.setText(Float.toString(attr_.getWidth()));
+    //
+    // cap style
+    //
+    capStyleComboBox.setSelectedIndex(attr_.getCapStyle());
+    //
+    // miter style
+    //
+    miterStyleComboBox.setSelectedIndex(attr_.getMiterStyle());
+    //
+    // miter limit
+    //
+    miterLimitTextField.setText(Float.toString(attr_.getMiterLimit()));
+  }
+
+  void updateVectorAttribute() {
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(true, "VectorAttributeDialog");
+      }
+    }
+    attr_.setBatch(true);
+    //
+    // Vector
+    //
+    //
+    // Color
+    //
+    attr_.setVectorColor(colorPanel.getColor());
+    //
+    // style
+    //
+    attr_.setVectorStyle(vectorStyleComboBox.getSelectedIndex());
+    //
+    // vectorScale
+    //
+    attr_.setVectorScale(Double.parseDouble(vectorScaleTextField.getText()));
+    //
+    // vector max size
+    //
+    attr_.setVectorMaxSize(Double.parseDouble(vectorMaxSizeTextField.getText()));
+    //
+    // offset angle
+    //
+    attr_.setOffsetAngle(Double.parseDouble(offsetAngleTextField.getText()));
+    //
+    // head
+    //
+    //
+    // scale
+    //
+    attr_.setHeadScale(Double.parseDouble(headScaleTextField.getText()));
+    //
+    // max head size
+    //
+    attr_.setHeadMaxSize(Double.parseDouble(headMaxSizeTextField.getText()));
+    //
+    // head min size
+    //
+    attr_.setHeadMinSize(Double.parseDouble(headMinSizeTextField.getText()));
+    //
+    // head fixed size
+    //
+    attr_.setHeadFixedSize(Double.parseDouble(headFixedSizeTextField.getText()));
+    //
+    // origin
+    //
+    // style
+    //
+    attr_.setOriginStyle(originStyleComboBox.getSelectedIndex());
+    //
+    // mark
+    //
+    attr_.setMark(mark_);
+    //
+    // color
+    //
+    attr_.setMarkColor(markColorPanel.getColor());
+    //
+    // mark height
+    //
+    attr_.setMarkHeightP(new Double(markHeightTextField.getText()).doubleValue());
+    //
+    // stroke attributes
+    //
+    //
+    // width
+    //
+    attr_.setWidth(new Float(widthTextField.getText()).floatValue());
+    //
+    // cap style
+    //
+    attr_.setCapStyle(capStyleComboBox.getSelectedIndex());
+    //
+    // miter style
+    //
+    attr_.setMiterStyle(miterStyleComboBox.getSelectedIndex());
+    //
+    // miter limit
+    //
+    attr_.setMiterLimit(new Float(miterLimitTextField.getText()).floatValue());
+
+    attr_.setBatch(false);
+    //
+    if(paneList_ != null) {
+      for(int i=0; i < paneList_.length; i++) {
+        paneList_[i].setBatch(false, "VectorAttributeDialog");
+      }
+    }
+  }
+
+  private void vectorStyle(int style) {
+    switch(style) {
+      case VectorAttribute.NO_HEAD:
+        headScaleTextField.setEnabled(false);
+        headMinSizeTextField.setEnabled(false);
+        headMaxSizeTextField.setEnabled(false);
+        headFixedSizeTextField.setEnabled(false);
+      break;
+      case VectorAttribute.HEAD:
+        headScaleTextField.setEnabled(false);
+        headMinSizeTextField.setEnabled(false);
+        headMaxSizeTextField.setEnabled(false);
+        headFixedSizeTextField.setEnabled(true);
+      break;
+      case VectorAttribute.SCALED_HEAD:
+        headScaleTextField.setEnabled(true);
+        headMinSizeTextField.setEnabled(true);
+        headMaxSizeTextField.setEnabled(true);
+        headFixedSizeTextField.setEnabled(false);
+    }
+  }
+  /**
+   * Dialog test entry.
+   */
+  public static void main(String[] args) {
+    VectorAttribute attr = new VectorAttribute();
+    VectorAttributeDialog la = new VectorAttributeDialog();
+    la.setVectorAttribute(attr);
+    la.setTitle("Test VectorAttribute Dialog");
+    la.setVisible(true);
+  }
+
+  void markEditor_actionPerformed(java.awt.event.ActionEvent event) {
+    PlotMarkDialog pmd = new PlotMarkDialog();
+    Point loc = markEditor.getLocationOnScreen();
+    pmd.setLocation(loc.x, loc.y);
+    int result = pmd.showDialog(mark_);
+    if(result == PlotMarkDialog.OK_RESPONSE) {
+      changeMark(pmd.getMark());
+    }
+  }
+
+  private void changeMark(int mark) {
+    mark_ = mark;
+    pmIcon_.setMark(mark);
+    plotMarkIconLabel.repaint();
+  }
+  /**
+   * Set the parent <code>JPane</code>.  This reference to
+   * <code>JPane</code> is used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time.
+   */
+  public void setJPane(JPane pane) {
+    paneList_ = new JPane[1];
+    paneList_[0] = pane;
+  }
+  /** Get the first parent pane. */
+  public JPane getJPane() {
+    if(paneList_ != null) {
+      return paneList_[0];
+    } else {
+      return null;
+    }
+  }
+  /**
+   * Set the parent <code>JPane</code>s.  These references to
+   * <code>JPane</code> are used to enable/disable
+   * {@link gov.noaa.pmel.sgt.JPane#setBatch(boolean) batching} so
+   * multiple property changes are made at one time. A second
+   * <code>JPane</code> is often used for a <code>VectorKey</code>.
+   */
+  public void setJPaneList(JPane[] list) {
+    paneList_ = list;
+  }
+  /** Get an array of parent panes. */
+  public JPane[] getJPaneList() {
+    return paneList_;
+  }
+
+  void vectorStyleComboBox_actionPerformed(ActionEvent e) {
+    int style = vectorStyleComboBox.getSelectedIndex();
+    vectorStyle(style);
+  }
+}
+
+class VectorAttributeDialog_vectorStyleComboBox_actionAdapter implements java.awt.event.ActionListener {
+  VectorAttributeDialog adaptee;
+
+  VectorAttributeDialog_vectorStyleComboBox_actionAdapter(VectorAttributeDialog adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.vectorStyleComboBox_actionPerformed(e);
+  }
+}
+
+class VectorAttributeDialog_markEditor_actionAdapter implements java.awt.event.ActionListener {
+  VectorAttributeDialog adaptee;
+
+  VectorAttributeDialog_markEditor_actionAdapter(VectorAttributeDialog adaptee) {
+    this.adaptee = adaptee;
+  }
+  public void actionPerformed(ActionEvent e) {
+    adaptee.markEditor_actionPerformed(e);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/package.html
new file mode 100755
index 0000000..4147f9e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/prop/package.html
@@ -0,0 +1,22 @@
+<HTML>
+<BODY>
+Property dialogs for <code>sgt</code> components using 
+<code>javax.swing</code>.  Dialogs that edit the properties of
+attributes and other <code>sgt</code> objects do not, in general, work
+on a copy of the object.  Because the references to attributes are
+one-way if a copy were created the editing would not affect most of
+the references. If you want these dialogs to work on copies instead of
+the actual object, the creation of the copy and updating of the
+original, if the changes are applied, will need to be done in the
+users application.
+
+<p><font size="-1">This software is provided by NOAA for full, free
+and open release.  It is understood by the recipient/user that NOAA
+assumes no liability for any errors contained in the code.  Although
+this software is released without conditions or restrictions in its
+use, it is expected that appropriate credit be given to its author and
+to the National Oceanic and Atmospheric Administration should the
+software be included by the recipient as an element in other product
+development.</font></p>
+</BODY>
+</HTML>
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/sgt_logo.png b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/sgt_logo.png
new file mode 100755
index 0000000..0d2f5cd
Binary files /dev/null and b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/sgt/swing/sgt_logo.png differ
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/space/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/space/package.html
new file mode 100755
index 0000000..37f92e2
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/space/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Collaborative support classes for JavaSpaces and Jini.
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSlider2.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSlider2.java
new file mode 100755
index 0000000..c84ec58
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSlider2.java
@@ -0,0 +1,555 @@
+/*
+ * $Id: JSlider2.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ */
+
+package gov.noaa.pmel.swing;
+
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+import java.awt.event.*;
+import java.beans.*;
+import java.awt.Dimension;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.FontMetrics;
+import java.awt.BorderLayout;
+import java.awt.Rectangle;
+
+import gov.noaa.pmel.util.Range;
+import gov.noaa.pmel.swing.beans.SliderHandle;
+
+/**
+ * JSlider2 provides the graphical input and feedback
+ * for JSlider2Double and JSlider2Date.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @see JSlider2Double
+ * @see JSlider2Date
+**/
+public class JSlider2 extends JComponent 
+  implements java.io.Serializable {
+  protected Range rawRange_;
+  protected int handleSize_;
+  protected Dimension size_;
+  protected int yval_;
+  boolean showBorder_;
+  boolean twoHandles_;
+  boolean alwaysPost_;
+  SliderHandle minHandle_, maxHandle_;
+  int min_, max_;
+  double scale_;
+  double minValue_, maxValue_;
+  double minOld_, maxOld_;
+  String minLabel_, maxLabel_;
+  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
+  boolean indexed_ = false;
+  double[] values_;
+  int[] pixels_;
+  
+  private EtchedBorder eBorder_ = null;
+  /**
+   * Class for the Date and Double JSlider2 classes. This class creates
+   * the slider portion of the JSlider2Date and JSlider2Double classes.
+   *
+   * @see JSlider2Date
+   * @see JSlider2Double
+   **/
+  public JSlider2() {
+    this(true);
+    setSize(40,40);
+  }
+
+  /**
+   * Class for the GeoDate and Double JSlider2 classes. This class creates
+   * the slider portion of the JSlider2Date and JSlider2Double classes.
+   *
+   * @param twoHandles if true create two handles
+   * @see JSlider2Date
+   * @see JSlider2Double
+   **/
+  public JSlider2(boolean twoHandles) {
+    super();
+    
+    //{{REGISTER_LISTENERS
+    SymMouse aSymMouse = new SymMouse();
+    this.addMouseListener(aSymMouse);
+    SymMouseMotion aSymMouseMotion = new SymMouseMotion();
+    this.addMouseMotionListener(aSymMouseMotion);
+    MyComponent aMyComponent = new MyComponent();
+    this.addComponentListener(aMyComponent);
+    //}}
+                
+    twoHandles_ = twoHandles;
+    showBorder_ = true;
+    eBorder_ = new EtchedBorder();
+    setBorder(eBorder_);
+    handleSize_ = 6;
+    alwaysPost_ = false;
+        
+    size_ = new Dimension(175, 50);        
+    rawRange_ = new Range(handleSize_ + 1, size_.width - handleSize_ - 1);
+        
+    reset();
+        
+    minLabel_ = Double.toString(minValue_);
+    maxLabel_ = Double.toString(maxValue_);
+        
+    minHandle_ = new SliderHandle(handleSize_, Color.green, SliderHandle.LEFT);
+    maxHandle_ = new SliderHandle(handleSize_, Color.red, SliderHandle.RIGHT);
+    if(!twoHandles_) 
+      minHandle_.setStyle(SliderHandle.SINGLE);
+  }
+  /**
+   * Set the minimum handle value. Valid range 0.0 - 1.0.
+   *
+   * @param min minimum handle value
+   **/
+  public void setMinValue(double min) {
+    minValue_ = Math.max(min, 0.0);
+    if(minOld_ != minValue_) {
+      Double tempOld = new Double(minOld_);
+      minOld_ = minValue_;
+      changes.firePropertyChange("minValue", tempOld, new Double(minValue_));  
+    }
+    repaint();
+  }
+  /**
+   * Get the minimum handle value. 
+   *
+   * @return minimum handle value
+   **/
+  public double getMinValue() {
+    return minValue_;
+  }
+  /**
+   * Set the maximum handle value. Valid range 0.0 - 1.0.
+   *
+   * @param max maximum handle value
+   **/
+  public void setMaxValue(double max) {
+    maxValue_ = Math.min(max, 1.0);
+    if(maxOld_ != maxValue_) {
+      Double tempOld = new Double(maxOld_);
+      maxOld_ = maxValue_;
+      changes.firePropertyChange("maxValue", tempOld, new Double(maxValue_));  
+    }
+    repaint();
+  }
+  /**
+   * Get the maximum handle value.
+   *
+   * @return maximum handle value
+   **/
+  public double getMaxValue() {
+    return maxValue_;
+  } 
+  /**
+   * Reset the max,min values to the range limits
+   **/
+  public void reset() {
+    maxValue_ = 1.0;
+    minValue_ = 0.0;
+    maxOld_ = 1.0;
+    minOld_ = 0.0;
+  }
+   
+  /**
+   * Set the minimum label.
+   *
+   * @param lab minimum string
+   **/
+  public void setMinLabel(String lab) {
+    minLabel_ = lab;
+    repaint();
+  }
+  /**
+   * Get the minimum label.
+   *
+   * @return the minimum label
+   */
+  public String getMinLabel() {
+    return minLabel_;
+  }
+  /**
+   * Set the maximum label.
+   *
+   * @param lab maximum string
+   **/
+  public void setMaxLabel(String lab) {
+    maxLabel_ = lab;
+    repaint();
+  }
+  /**
+   * Get the maximum label.
+   *
+   * @return the maximum label
+   */
+  public String getMaxLabel() {
+    return maxLabel_;
+  }
+  /**
+   * Add a property change listener. The properties that fire a property
+   * change are "minValue" and "maxValue". The old and new Double objects
+   * are set.
+   *
+   * @param l property change listener
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes.addPropertyChangeListener(l);
+  }
+  /**
+   * Remove a property change listener.
+   *
+   * @param l property change listener
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes.removePropertyChangeListener(l);
+  }
+  /**
+   * Set the two handle mode.
+   *
+   * @param th if true set two handles
+   */
+  public void setTwoHandles(boolean th) {
+    twoHandles_ = th;
+    if(twoHandles_) {
+      minHandle_.setStyle(SliderHandle.LEFT);
+    } else {
+      minHandle_.setStyle(SliderHandle.SINGLE);
+    }
+    repaint();
+  }
+  /**
+   * Get the two handle flag.
+   *
+   * @return true if two handles
+   */
+  public boolean isTwoHandles() {
+    return twoHandles_;
+  }
+  /**
+   * Get the two handle flag.
+   *
+   * @return true if two handles
+   */
+  public boolean getTwoHandles() {
+    return twoHandles_;
+  }
+  /**
+   * Show a border around the slider.
+   *
+   * @param sb if true show the border
+   */
+  public void setShowBorder(boolean sb) {
+    showBorder_ = sb;
+    if(!showBorder_) setBorder(null);
+    repaint();
+  }
+  /**
+   * Get border status for the slider.
+   *
+   * @return true if border is showing
+   */
+  public boolean isShowBorder() {
+    return showBorder_;
+  }
+  /**
+   * Get border status for the slider.
+   *
+   * @return true if border is showing
+   */
+  public boolean getShowBorder() {
+    return showBorder_;
+  }
+  /**
+   * Set the handle size for the slider.
+   *
+   * @param sz handle size in pixels
+   */
+  public void setHandleSize(int sz) {
+    if(handleSize_ != sz) {
+      handleSize_ = sz;
+      minHandle_ = new SliderHandle(handleSize_, Color.green);
+      maxHandle_ = new SliderHandle(handleSize_, Color.red);
+      repaint();
+    }
+  }
+  /**
+   * Get the current slider handle size.
+   *
+   * @return handle size in pixels
+   */
+  public int getHandleSize() {
+    return handleSize_;
+  }
+  /**
+   * Set the always post flag for the slider. If true any motion of the
+   * slider will fire a property change, if false a property change is
+   * only caused when the mouse button is released.
+   *
+   * @param ap if true always post
+   */
+  public void setAlwaysPost(boolean ap) {
+    alwaysPost_ = ap;
+  }
+  /**
+   * Get the always post flag for the slider.
+   *
+   * @return true if the slider will always post
+   */
+  public boolean isAlwaysPost() {
+    return alwaysPost_;
+  }
+  /**
+   * Get the always post flag for the slider.
+   *
+   * @return true if the slider will always post
+   */
+  public boolean getAlwaysPost() {
+    return alwaysPost_;
+  }
+  /**
+   * Get the range of the slider. The range is in pixels and is determined from
+   * the size of the slider and the sizes of the handles.
+   *
+   * @return slider range
+   **/
+  public Range getRawRange() {
+    return rawRange_;
+  }
+
+  public void setBounds(Rectangle r) {
+    super.setBounds(r);
+    invalidate();
+    doCompute();
+  }
+
+  public void setBounds(int x, int y, int w, int h) {
+    super.setBounds(x,y,w,h);
+    invalidate();
+    doCompute();
+  }
+  /**
+   * Set the size of the slider.
+   *
+   * @param size slider size
+   **/
+  public void setSize(Dimension size) {
+    super.setSize(size);
+    invalidate();
+    doCompute();
+  }
+  
+  public void setSize(int width, int height) {
+    super.setSize(width, height);
+    invalidate();
+    doCompute();
+  }
+
+  public void setIndexed(boolean ind) {
+    indexed_ = ind;
+  }
+  
+  public boolean isIndexed() {
+    return indexed_;
+  }
+  
+  public void paintComponent(Graphics g) {
+    FontMetrics fmet;
+    int xs, ys, swidth;
+        
+    min_ = rawRange_.start + (int)(minValue_*scale_);
+    max_ = rawRange_.start + (int)(maxValue_*scale_);
+
+    g.setColor(getBackground());
+    g.fillRect(0, 0, size_.width, size_.height);
+
+    g.setColor(Color.black);
+//      if(showBorder_) {
+//        g.drawRect(0, 0, size_.width-1, size_.height-1);
+//      }
+    g.setColor(Color.black);
+    g.drawLine(rawRange_.start, yval_ - 3, rawRange_.end, yval_ - 3);
+    g.setColor(Color.gray);
+    g.drawLine(rawRange_.start, yval_ - 2, rawRange_.end, yval_ - 2);
+    //
+    // draw labels
+    //
+    g.setColor(Color.black);
+    fmet = g.getFontMetrics();
+    ys = yval_ - 8;
+    xs = rawRange_.start;
+    g.drawString(minLabel_, xs, ys);
+    swidth = fmet.stringWidth(maxLabel_);
+    xs = rawRange_.end - swidth;
+    g.drawString(maxLabel_, xs, ys);
+    //
+    // draw handles
+    //
+    minHandle_.draw(g, min_, yval_);
+    if(twoHandles_) maxHandle_.draw(g, max_, yval_);
+  }
+        
+  public Dimension getMinimumSize() {
+    return new Dimension(96,57);
+  }
+    
+  public Dimension getPreferredSize() {
+    return new Dimension(200,57);
+  }
+    
+  public Dimension getMaximumSize() {
+    return new Dimension(Short.MAX_VALUE,Short.MIN_VALUE);
+  }
+  
+  public void setIndexValues(double[] array) {
+    values_ = array;
+    indexed_ = true;
+    pixels_ = new int[values_.length];
+    doCompute();
+  }
+
+  void doCompute() {
+    size_ = getSize();
+    rawRange_.start = 2*handleSize_ + 1;
+    rawRange_.end = size_.width - 2*handleSize_ - 1;    
+    yval_ = size_.height - 3*handleSize_ - 10;
+    scale_ = (double)(rawRange_.end - rawRange_.start);
+    if(indexed_) {
+      for(int i=0; i < values_.length; i++) {
+        pixels_[i] = rawRange_.start + (int)(values_[i]*scale_);
+      }
+    }
+  }
+ 
+  /**
+   *
+   **/
+        
+  void doMove(int xpos, boolean forcePost) {
+    double value;
+    if(xpos > rawRange_.end) xpos = rawRange_.end;
+    if(xpos < rawRange_.start) xpos = rawRange_.start;
+            
+    if(indexed_ && forcePost) {
+      int ind = 0;
+      if(xpos <= pixels_[0]) {
+        ind = 0;
+      } else if(xpos >= pixels_[pixels_.length-1]) {
+        ind = pixels_.length-1;
+      } else {
+        for(int i=0; i < pixels_.length - 1; i++) {
+          if(xpos >= pixels_[i] && xpos < pixels_[i+1]) {
+            if(xpos - pixels_[i] < pixels_[i+1] - xpos) {
+              ind = i;
+            } else {
+              ind = i+1;
+            }
+            break;
+          }
+        }
+      }
+      value = values_[ind];
+      xpos = pixels_[ind];
+    } else {
+      value = (double)(xpos - rawRange_.start)/scale_;
+    }
+    
+    if(twoHandles_) {
+      int toMin = xpos - min_;
+      int toMax = xpos - max_;
+      if(toMin < 0) {
+        minValue_ = value;
+      } else if(toMax > 0) {
+        maxValue_ = value;
+      } else if(toMin < -toMax) {
+        minValue_ = value;
+      } else {
+        maxValue_ = value;
+      }
+    } else 
+      minValue_ = value;
+      
+    if(forcePost || alwaysPost_) {
+      if(minOld_ != minValue_) {
+        Double tempOld = new Double(minOld_);
+        minOld_ = minValue_;
+        changes.firePropertyChange("minValue", tempOld, new Double(minValue_));
+      }
+      if(maxOld_ != maxValue_) {
+        Double tempOld = new Double(maxOld_);
+        maxOld_ = maxValue_;
+        changes.firePropertyChange("maxValue", tempOld, new Double(maxValue_));
+      }
+    }
+    paint(getGraphics());
+  }
+
+  class SymMouse extends MouseAdapter {
+    public void mouseReleased(MouseEvent event) {
+      Object object = event.getSource();
+      if (object == JSlider2.this)
+        JSlider2_MouseRelease(event);
+    }
+
+    public void mouseClicked(MouseEvent event) {
+      Object object = event.getSource();
+      if (object == JSlider2.this)
+        JSlider2_MouseClick(event);
+    }
+  }
+
+  void JSlider2_MouseClick(MouseEvent event) {
+    doMove(event.getX(), true);
+  }
+
+  class MyComponent extends ComponentAdapter {
+    public void componentResized(ComponentEvent event) {
+      Object object = event.getSource();
+      if(object == JSlider2.this)
+        JSlider2_resized(event);
+    }
+  }
+  
+  void JSlider2_resized(ComponentEvent event) {
+    doCompute();
+  }
+  
+  class SymMouseMotion extends MouseMotionAdapter {
+    public void mouseDragged(MouseEvent event) {
+      Object object = event.getSource();
+      if (object == JSlider2.this)
+        JSlider2_MouseDrag(event);
+    }
+  }
+
+  void JSlider2_MouseDrag(MouseEvent event) {
+    doMove(event.getX(), false);
+  }
+  
+
+  void JSlider2_MouseRelease(MouseEvent event) {
+    doMove(event.getX(), true);
+  }
+  
+  public static void main(String[] args) {
+    double[] values = {0.0, 0.1, 0.2, 0.3, 0.4,
+		       0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
+    JFrame jf = new JFrame("JSlider2 Test");
+    jf.setSize(400,100);
+    jf.getContentPane().setLayout(new BorderLayout());
+    JSlider2 js2 = new JSlider2();
+    //
+    // valid range of slider is 0-1
+    //
+    js2.setDoubleBuffered(true);
+    js2.setMinValue(0.2);
+    js2.setMaxValue(0.8);
+    js2.setIndexValues(values);
+    js2.setMinLabel("-20 stuff");
+    js2.setMaxLabel("20 stuff");
+    jf.getContentPane().add(js2, BorderLayout.CENTER);
+    jf.setVisible(true);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSlider2Double.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSlider2Double.java
new file mode 100755
index 0000000..1f8c73d
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSlider2Double.java
@@ -0,0 +1,580 @@
+/*
+ * $Id: JSlider2Double.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ */
+
+package gov.noaa.pmel.swing;
+
+import javax.swing.*;
+import java.awt.event.*;
+import java.beans.*;
+//import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.BorderLayout;
+import java.awt.Insets;
+import java.text.DecimalFormat;
+
+import gov.noaa.pmel.util.Range2D;
+
+/**
+ * Class provides graphical and textual input of a range.
+ * Minimum value are required to be less than or equal 
+ * to the maximum value.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @see JSlider2
+**/
+public 
+//class JSlider2Double extends Container implements java.io.Serializable
+class JSlider2Double extends JComponent implements java.io.Serializable
+{
+  boolean twoHandles_;
+  Range2D range_;
+  double minValue_, oldMinValue_;
+  double maxValue_, oldMaxValue_;
+  double scale_;
+  String format_ = "";
+  DecimalFormat form_;
+  boolean indexed_ = false;
+  double[] values_;
+  double[] scaled_;
+/**
+ * @link aggregationByValue
+ * @clientCardinality 1
+ * @supplierCardinality 1 
+ */
+  JSlider2 slider_;
+  JLabel minLabel_;
+  JTextField minField_;
+  JLabel maxLabel_;
+  JTextField maxField_;
+  JPanel panel_;
+  GridBagLayout layout_;
+
+  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
+  
+  /**
+   * Default constructor. The default creates two handles.
+   **/
+  public JSlider2Double() {
+    this(true);
+  }
+  /**
+   * Constructs a one or two handled slider.
+   *
+   * @param twoHandles if true create two handles
+   */
+  public JSlider2Double(boolean twoHandles) {
+    super();
+    twoHandles_ = twoHandles;
+    
+    setLayout(new BorderLayout(0,0));
+    panel_ = new JPanel();
+    layout_ = new GridBagLayout();
+    panel_.setLayout(layout_);
+    panel_.setBounds(12,12,384,156);
+    slider_ = new JSlider2();
+    slider_.setBounds(5,20,374,49);
+    GridBagConstraints gbc;
+    gbc = new GridBagConstraints();
+    gbc.gridwidth = GridBagConstraints.REMAINDER;
+    gbc.weightx = 1.0;
+    gbc.fill = GridBagConstraints.HORIZONTAL;
+    gbc.insets = new Insets(10,5,5,5);
+    layout_.setConstraints(slider_, gbc);
+    panel_.add(slider_);
+    minLabel_ = new JLabel("Minimum:",JLabel.RIGHT);
+    minLabel_.setBounds(6,79,68,23);
+    gbc = new GridBagConstraints();
+    gbc.fill = GridBagConstraints.NONE;
+    gbc.insets = new Insets(5,5,5,5);
+    layout_.setConstraints(minLabel_, gbc);
+    panel_.add(minLabel_);
+    minField_ = new JTextField();
+    minField_.setBounds(80,79,299,23);
+    gbc = new GridBagConstraints();
+    gbc.gridwidth = GridBagConstraints.REMAINDER;
+    gbc.weightx = 1.0;
+    gbc.fill = GridBagConstraints.HORIZONTAL;
+    gbc.insets = new Insets(5,0,5,5);
+    layout_.setConstraints(minField_, gbc);
+    panel_.add(minField_);
+    // second handle information
+    maxLabel_ = new JLabel("Maximum:",JLabel.RIGHT);
+    maxLabel_.setBounds(5,112,70,23);
+    maxField_ = new JTextField();
+    maxField_.setBounds(80,112,299,23);
+    if(twoHandles_) {
+      gbc = new GridBagConstraints();
+      gbc.fill = GridBagConstraints.NONE;
+      gbc.insets = new Insets(5,5,10,5);
+      layout_.setConstraints(maxLabel_, gbc);
+      panel_.add(maxLabel_);
+		
+      gbc = new GridBagConstraints();
+      gbc.weightx = 1.0;
+      gbc.fill = GridBagConstraints.HORIZONTAL;
+      gbc.insets = new Insets(5,0,10,5);
+      layout_.setConstraints(maxField_, gbc);
+      panel_.add(maxField_);
+    } else {
+      minLabel_.setText("Value:");
+    }
+    add("Center", panel_);
+		
+    SymPropertyChange lSymPropertyChange = new SymPropertyChange();
+    slider_.addPropertyChangeListener(lSymPropertyChange);
+    SymAction lSymAction = new SymAction();
+    minField_.addActionListener(lSymAction);
+    maxField_.addActionListener(lSymAction);
+	
+    form_ = new DecimalFormat(format_);
+
+    form_.setGroupingUsed(false);
+    range_ = new Range2D(0.0f, 1.0f);
+    setRange(range_);
+
+  }
+  /**
+   * Set the range for the slider. The minimum value must be
+   * less than the maximum value.
+   *
+   * @param min minimum value
+   * @param max maximum value
+   **/
+  public void setRange(double min, double max) {
+    setRange(new Range2D(min, max));
+  }
+  /**
+   * Set the range for the slider.
+   *
+   * @param range slider total range
+   **/
+  public void setRange(Range2D range) {
+    double min, max;
+    range_ = range;
+    scale_ = (double)(range_.end - range_.start);
+    slider_.setMinLabel(form_.format(range_.start));
+    slider_.setMaxLabel(form_.format(range_.end));
+    
+    minValue_ = range_.start;
+    oldMinValue_ = minValue_;
+    min = (minValue_ - range_.start)/scale_;
+    slider_.setMinValue(min); 
+    minField_.setText(form_.format(minValue_));
+    
+    maxValue_ = range_.end;
+    oldMaxValue_ = maxValue_;
+    max = (maxValue_ - range_.start)/scale_;
+    slider_.setMaxValue(max);
+    maxField_.setText(form_.format(maxValue_));
+    
+    if(indexed_) {
+        for(int i=0; i < values_.length; i++) {
+            scaled_[i] = (values_[i] - range_.start)/scale_;
+        }
+        slider_.setIndexValues(scaled_);
+    }
+  }
+  /**
+   * Get the slider range.
+   *
+   * @return slider range
+   **/
+  public Range2D getRange() {
+    return range_;
+  }
+  /**
+   * Set the minimum for the range.
+   *
+   * @param min minimum range value
+   */
+  public void setMinRange(double min) {
+    range_.start = min;
+    setRange(range_);
+  }
+  /**
+   * Get the minimum for the range.
+   *
+   * @return minimum range value
+   */
+  public double getMinRange() {
+    return (double)range_.start;
+  }
+  /**
+   * Set the maximum for the range.
+   *
+   * @param max maximum range value
+   */
+  public void setMaxRange(double max) {
+    range_.end = max;
+    setRange(range_);
+  }
+  /**
+   * Get the maximum for the range.
+   *
+   * @return maximum range value
+   */
+  public double getMaxRange() {
+    return (double)range_.end;
+  }
+  /**
+   * Reset the slider handles
+   **/
+  public void reset()
+  {
+    slider_.reset();
+  }
+  
+  public void setIndexValues(double[] array) {
+     values_ = array;
+     indexed_ = true;
+     scaled_ = new double[values_.length];
+     setRange(range_);
+  }
+  /**
+   * Set the two handle mode.
+   *
+   * @param th if true set two handles
+   */
+  public void setTwoHandles(boolean th) {
+    GridBagConstraints gbc;
+    twoHandles_ = th;
+    slider_.setTwoHandles(th);
+    if(twoHandles_) {
+      if(!panel_.isAncestorOf(maxLabel_)) {
+	gbc = new GridBagConstraints();
+	gbc.fill = GridBagConstraints.NONE;
+	gbc.insets = new Insets(5,5,10,5);
+	layout_.setConstraints(maxLabel_, gbc);
+	panel_.add(maxLabel_);
+      }
+      if(!panel_.isAncestorOf(maxField_)) {
+	gbc = new GridBagConstraints();
+	gbc.weightx = 1.0;
+	gbc.fill = GridBagConstraints.HORIZONTAL;
+	gbc.insets = new Insets(5,0,10,5);
+	layout_.setConstraints(maxField_, gbc);
+	panel_.add(maxField_);
+      }
+      minLabel_.setText("Minimum:");
+      panel_.invalidate();
+    } else {
+      minLabel_.setText("Value:");
+      if(panel_.isAncestorOf(maxLabel_)) panel_.remove(maxLabel_);
+      if(panel_.isAncestorOf(maxField_)) panel_.remove(maxField_);
+      panel_.invalidate();
+    }
+
+    slider_.setDoubleBuffered(true);
+  }
+  /**
+   * Get the two handle flag.
+   *
+   * @return true if two handles
+   */
+  public boolean getTwoHandles() {
+    return twoHandles_;
+  }
+  /**
+   * Get the two handle flag.
+   *
+   * @return true if two handles
+   */
+  public boolean isTwoHandles() {
+    return twoHandles_;
+  }
+  /**
+   * Set the format for the slider range label and display.
+   *
+   * @param frmt format in Format syntax
+   */
+  public void setFormat(String frmt) {
+    format_ = frmt;
+    form_ = new DecimalFormat(format_);
+    form_.setGroupingUsed(false);
+    setRange(range_);
+  }
+  /**
+   * Get the format for the slider range label.
+   *
+   * @return the format in Format syntax
+   */
+  public String getFormat() {
+    return format_;
+  }
+  public double getStartValue() {
+    if(range_.start > range_.end) {
+    minValue_ =
+      Math.min((Double.valueOf(minField_.getText())).doubleValue(),
+	       range_.start);
+    } else {
+    minValue_ =
+      Math.max((Double.valueOf(minField_.getText())).doubleValue(),
+	       range_.start);
+    }
+    return minValue_;
+  }
+  public double getEndValue() {
+    if(range_.start > range_.end) {
+    maxValue_ =
+      Math.max((Double.valueOf(maxField_.getText())).doubleValue(), 
+	       range_.end);
+    } else {
+    maxValue_ =
+      Math.min((Double.valueOf(maxField_.getText())).doubleValue(), 
+	       range_.end);
+    }
+    return maxValue_;
+  }
+  public void setStartValue(double min) {
+    if(range_.start > range_.end) {
+      minValue_ = Math.min(min, range_.start);
+    } else {
+      minValue_ = Math.max(min, range_.start);
+    }
+    min = (minValue_ - range_.start)/scale_;
+    slider_.setMinValue(min); 
+  }
+  public void setEndValue(double max) {
+    if(range_.start > range_.end) {
+      maxValue_ = Math.max(max, range_.end);
+    } else {
+      maxValue_ = Math.min(max, range_.end);
+    }
+    max = (maxValue_ - range_.start)/scale_;
+    slider_.setMaxValue(max);
+  }
+  /**
+   * Get the minimum handle value.
+   *
+   * @return minimum handle value.
+   **/
+  public double getMinValue() {
+    minValue_ = Math.max((Double.valueOf(minField_.getText())).doubleValue(), range_.start);
+    minValue_ = Math.min(minValue_, maxValue_);
+    return minValue_;
+  }
+  /**
+   * Set the minimum handle value.
+   *
+   * @param min minimum handle value.
+   **/
+  public void setMinValue(double min) {
+    minValue_ = min;
+    minValue_ = Math.min(minValue_, maxValue_);
+    min = (minValue_ - range_.start)/scale_;
+    slider_.setMinValue(min); 
+  }
+  /**
+   * Get the maximum handle value.
+   *
+   * @return maximum handle value
+   **/
+  public double getMaxValue() {
+    maxValue_ = Math.min((Double.valueOf(maxField_.getText())).doubleValue(), range_.end);
+    maxValue_ = Math.max(maxValue_, minValue_);
+    return maxValue_;
+  }
+  /**
+   * Set the maximum handle value.
+   *
+   * @param max maximum handle value
+   **/
+  public void setMaxValue(double max) {
+    maxValue_ = max;
+    maxValue_ = Math.max(maxValue_, minValue_);
+    max = (maxValue_ - range_.start)/scale_;
+    slider_.setMaxValue(max);
+  }
+  /**
+   * Show a border around the slider.
+   *
+   * @param sb if true show the border
+   */
+  public void setShowBorder(boolean sb) {
+    slider_.setShowBorder(sb);
+  }
+  /**
+   * Get border status for the slider.
+   *
+   * @return true if border is showing
+   */
+  public boolean getShowBorder() {
+    return slider_.getShowBorder();
+  }
+  /**
+   * Set the handle size for the slider.
+   *
+   * @param sz handle size in pixels
+   */
+  public void setHandleSize(int sz) {
+    slider_.setHandleSize(sz);
+  }
+  /**
+   * Get the current slider handle size.
+   *
+   * @return handle size in pixels
+   */
+  public int getHandleSize() {
+    return slider_.getHandleSize();
+  }
+  /**
+   * Set the always post flag for the slider. If true any motion of the
+   * slider will fire a property change, if false a property change is
+   * only caused when the mouse button is released.
+   *
+   * @param ap if true always post
+   */
+  public void setAlwaysPost(boolean ap) {
+    slider_.setAlwaysPost(ap);
+  }
+  /**
+   * Get the always post flag for the slider.
+   *
+   * @return true if the slider will always post
+   */
+  public boolean getAlwaysPost() {
+    return slider_.getAlwaysPost();
+  }
+  /**
+   * Add a property change listener. The properties that fire a property
+   * change are "minValue" and "maxValue". The old and new Double objects
+   * values are set.
+   *
+   * @param l property change listener
+   */
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    changes.addPropertyChangeListener(l);
+  }
+  /**
+   * Remove a property change listener.
+   *
+   * @param l property change listener
+   */
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    changes.removePropertyChangeListener(l);
+  }
+  class SymPropertyChange implements java.beans.PropertyChangeListener
+  {
+    public void propertyChange(java.beans.PropertyChangeEvent event)
+    {
+      Object object = event.getSource();
+      if (object == slider_)
+	slider_propertyChange(event);
+    }
+  }
+
+  public Dimension getMinimumSize() {
+    int hgt;
+    if(twoHandles_)
+      hgt = 135;
+    else
+      hgt = 105;
+    return new Dimension(180,hgt);
+  }
+    
+  public Dimension getPreferredSize() {
+    int hgt;
+    if(twoHandles_)
+      hgt = 135;
+    else
+      hgt = 105;
+    return new Dimension(384,hgt);
+  }
+
+  public boolean isIndexed() {
+     return indexed_;
+  }
+  
+  public void setIndexed(boolean ind) {
+      indexed_ = ind;
+  }
+  
+  public void setSize(Dimension dim) {
+    super.setSize(dim);
+    validate();
+  }
+  public void setSize(int w, int h) {
+    super.setSize(w, h);
+    validate();
+  }
+    
+  public Dimension getMaximumSize() {
+    return new Dimension(Short.MAX_VALUE,Short.MAX_VALUE);
+  }
+
+  void slider_propertyChange(java.beans.PropertyChangeEvent event)
+  {
+    if(event.getPropertyName().equals("minValue")) {
+      minValue_ = range_.start + slider_.getMinValue()*scale_;
+      minField_.setText(form_.format(minValue_));
+      testMin();
+    } else if(event.getPropertyName().equals("maxValue")) {
+      maxValue_ = range_.start + slider_.getMaxValue()*scale_;
+      maxField_.setText(form_.format(maxValue_));
+      testMax();
+    }
+  }
+
+  class SymAction implements java.awt.event.ActionListener
+  {
+    public void actionPerformed(java.awt.event.ActionEvent event)
+    {
+      Object object = event.getSource();
+      if (object == minField_)
+	minField_EnterHit(event);
+      else if (object == maxField_)
+	maxField_EnterHit(event);
+    }
+  }
+
+  void minField_EnterHit(java.awt.event.ActionEvent event) {
+    double min;
+    minValue_ = Math.max((Double.valueOf(minField_.getText())).doubleValue(), range_.start);
+    minValue_ = Math.min(minValue_, maxValue_);
+    min = (minValue_ - range_.start)/scale_;
+    slider_.setMinValue(min);
+  }
+  void maxField_EnterHit(java.awt.event.ActionEvent event) {
+    double max;
+    maxValue_ = Math.min((Double.valueOf(maxField_.getText())).doubleValue(), range_.end);
+    maxValue_ = Math.max(maxValue_, minValue_);
+    max = (maxValue_ - range_.start)/scale_;
+    slider_.setMaxValue(max);
+  }
+  
+  void testMax() {
+    if(oldMaxValue_ != maxValue_) {
+      Double tempOldValue = new Double(oldMaxValue_);
+      oldMaxValue_ = maxValue_;
+      changes.firePropertyChange("maxValue", tempOldValue, new Double(maxValue_)); 
+    }
+  }
+  void testMin() {
+    if(oldMinValue_ != minValue_) {
+      Double tempOldValue = new Double(oldMinValue_);
+      oldMinValue_ = minValue_;
+      changes.firePropertyChange("minValue", tempOldValue, new Double(minValue_)); 
+    }
+  }
+
+  public static void main(String[] args) {
+      double[] values = {-20.0, -10.0, -5.0, -2.5, 0., 2.5, 5.0, 10., 15., 20.0};
+    JFrame jf = new JFrame("JSlider2Double Test");
+    jf.setSize(400,200);
+    jf.getContentPane().setLayout(new BorderLayout());
+    JSlider2Double js2db = new JSlider2Double();
+    //
+    js2db.setRange(new Range2D(-20.0, 20.0));
+    js2db.setStartValue(-10.0);
+    js2db.setEndValue(15.0);
+    js2db.setIndexValues(values);
+    js2db.setAlwaysPost(true);
+    jf.getContentPane().add(js2db, BorderLayout.CENTER);
+    jf.setVisible(true);
+  }
+
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSystemPropertiesDialog.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSystemPropertiesDialog.java
new file mode 100755
index 0000000..db61c0a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/JSystemPropertiesDialog.java
@@ -0,0 +1,205 @@
+/*
+* $Id: JSystemPropertiesDialog.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ */
+package gov.noaa.pmel.swing;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.TableColumn;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+
+/**
+ * Displays the system properties in a scrolling <code>JTable</code>.  The
+ * properties that consist of multiple parts, e.g. CLASSPATH, are
+ * displayed one component per line.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @see javax.swing.JTable
+ * @see java.lang.System#getProperties()
+ **/
+public class JSystemPropertiesDialog extends javax.swing.JDialog {
+  private JTable propTable;
+
+  public JSystemPropertiesDialog(String sTitle)  {
+    this((Frame) null, sTitle, false);
+  }
+
+  public JSystemPropertiesDialog()  {
+    this((Frame)null, (String) null, false);
+  }
+
+  public JSystemPropertiesDialog(Frame frame, String title) {
+    this(frame, title, false);
+  }
+
+  public JSystemPropertiesDialog(Frame parent, String title, boolean modal) {
+    super(parent, title, modal);
+
+    if(title == null) {
+      setTitle("System Properties");
+    }
+    createTable();
+    getContentPane().setLayout(new BorderLayout(0,0));
+    getContentPane().setBackground(new Color(200, 200, 200));
+    setSize(556,305);
+    setVisible(false);
+    displayPanel.setLayout(new GridBagLayout());
+    getContentPane().add(BorderLayout.CENTER,displayPanel);
+    displayPanel.setBounds(0, 0, 556, 270);
+    JScrollPane1.setOpaque(true);
+    JScrollPane1.setBackground(new Color(200, 200, 200));
+
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.gridx = 0;
+    gbc.gridy = 0;
+    gbc.gridwidth = 1;
+    gbc.gridheight = 1;
+    gbc.weightx = 1.0;
+    gbc.weighty = 1.0;
+    gbc.anchor = GridBagConstraints.CENTER;
+    gbc.fill = GridBagConstraints.BOTH;
+    gbc.insets = new java.awt.Insets(5,5,5,5);
+    gbc.ipadx = 0;
+    gbc.ipady = 0;
+    displayPanel.add(JScrollPane1, gbc );
+
+    JScrollPane1.setBounds(5,5,546,260);
+    JScrollPane1.getViewport().add(propTable);
+    propTable.setBounds(0,0,543,0);
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
+    getContentPane().add(BorderLayout.SOUTH,buttonPanel);
+    buttonPanel.setBounds(0,270,556,35);
+    OKButton.setText("OK");
+    OKButton.setActionCommand("OK");
+    buttonPanel.add(OKButton);
+    OKButton.setBounds(252,5,51,25);
+
+    SymAction lSymAction = new SymAction();
+    OKButton.addActionListener(lSymAction);
+
+  }
+
+  void createTable() {
+    Properties prop = System.getProperties();
+    //
+    int size = prop.size() + 50;
+    Vector names = new Vector(size);
+    Vector values = new Vector(size);
+    //
+    // sniff out the version of sgt!
+    //
+    String ver = null;
+    try {
+      Class cls = Class.forName("gov.noaa.pmel.sgt.JPane");
+      java.lang.reflect.Method meth = cls.getMethod("getVersion", null);
+      ver = (String)meth.invoke(null, null);
+    } catch (Exception e) {
+    } finally {
+      names.add("gov.noaa.pmel.sgt.version");
+      values.add(ver);
+    }
+    //
+    String separator = prop.getProperty("path.separator", ";");
+    int row=0;
+    Enumeration e = prop.propertyNames();
+    while(e.hasMoreElements()) {
+      String name = (String)e.nextElement();
+      String value = prop.getProperty(name);
+      int len = value.length();
+      if(value.indexOf(separator) != -1 && !name.equals("path.separator")) {
+        int lastIndex = 0;
+        int count = 1;
+        int ind;
+        int[] indicies = new int[200];
+        indicies[0] = 0;
+        while((ind = value.indexOf(separator, lastIndex)) != -1) {
+          indicies[count] = ind + 1;
+          lastIndex = ind + 1;
+          count++;
+        }
+        indicies[count] = len;
+        for(int i=1; i <= count; i++) {
+          names.addElement(name + "[" + i + "]");
+          values.addElement(value.substring(indicies[i-1], indicies[i]));
+          row++;
+        }
+      } else {
+        names.addElement(name);
+        values.addElement(value);
+        row++;
+      }
+    }
+    Enumeration enames = names.elements();
+    Enumeration evalues = values.elements();
+    String[][] data = new String[names.size()][2];
+    for(int i=0; i < names.size(); i++) {
+      data[i][0] = (String)enames.nextElement();
+      data[i][1] = (String)evalues.nextElement();
+    }
+    propTable = new JTable(data, new String[] {"Property", "Value"});
+    propTable.setSize(1000,1000);
+    TableColumn tc;
+    tc = propTable.getColumnModel().getColumn(0);
+    tc.setPreferredWidth(100);
+    tc = propTable.getColumnModel().getColumn(1);
+    tc.setPreferredWidth(300);
+  }
+
+
+  public void setVisible(boolean b) {
+    if (b) {
+      setLocation(50, 50);
+      //      init();
+    }
+    super.setVisible(b);
+  }
+
+  public void addNotify() {
+    // Record the size of the window prior to calling parents addNotify.
+    Dimension size = getSize();
+
+    super.addNotify();
+
+    if (frameSizeAdjusted)
+      return;
+    frameSizeAdjusted = true;
+
+    // Adjust size of frame according to the insets
+    Insets insets = getInsets();
+    setSize(insets.left + insets.right + size.width,
+            insets.top + insets.bottom + size.height);
+  }
+
+  // Used by addNotify
+  boolean frameSizeAdjusted = false;
+
+  javax.swing.JPanel displayPanel = new javax.swing.JPanel();
+  javax.swing.JScrollPane JScrollPane1 = new javax.swing.JScrollPane();
+  javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+  javax.swing.JButton OKButton = new javax.swing.JButton();
+
+  class SymAction implements java.awt.event.ActionListener {
+    public void actionPerformed(java.awt.event.ActionEvent event)    {
+      Object object = event.getSource();
+      if (object == OKButton)
+        OKButton_actionPerformed(event);
+    }
+  }
+
+  void OKButton_actionPerformed(java.awt.event.ActionEvent event) {
+    try {
+      // JSystemPropertiesDialog Hide the JSystemPropertiesDialog
+      this.setVisible(false);
+    } catch (java.lang.Exception e) {
+    }
+  }
+
+  public static void main(String[] args) {
+    JSystemPropertiesDialog js = new JSystemPropertiesDialog();
+    js.setTitle("Test System Properties Dialog");
+    js.setVisible(true);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/MRJUtil.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/MRJUtil.java
new file mode 100755
index 0000000..7f7f01c
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/MRJUtil.java
@@ -0,0 +1,44 @@
+/*
+ * $Id: MRJUtil.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.swing;
+
+import javax.swing.UIManager;
+
+/**
+ * Uility methods for dealing with Aqua interfaces
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 3.0
+ **/
+public class MRJUtil {
+
+  public MRJUtil() {
+  }
+/**
+ * MacOS Look and feel test
+ * @return true if using Aqua Look n' Feel
+ */
+  public static boolean isAquaLookAndFeel() {
+    return System.getProperty("mrj.version") != null &&
+        UIManager.getSystemLookAndFeelClassName().equals(UIManager.getLookAndFeel().getClass().getName());
+  }
+  /**
+   * MacOS Java version test
+   */
+  public static boolean fixFontMetrics() {
+    String rtVer = System.getProperty("java.runtime.version");
+    return System.getProperty("mrj.version") != null &&
+        (rtVer.equals("1.4.1_01-39") || rtVer.equals("1.4.1_01-69.1"));
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/ThreeDotsButton.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/ThreeDotsButton.java
new file mode 100755
index 0000000..ae2d22a
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/ThreeDotsButton.java
@@ -0,0 +1,34 @@
+/*
+ * $Id: ThreeDotsButton.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.swing;
+
+import javax.swing.JButton;
+import java.awt.Color;
+import java.awt.Insets;
+
+/**
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since SGT 3.0
+ **/
+public class ThreeDotsButton extends JButton {
+  private static ThreeDotsIcon dotsIcon_ = new ThreeDotsIcon(Color.black);
+
+  public ThreeDotsButton() {
+    super();
+    setIcon(dotsIcon_);
+    if(!MRJUtil.isAquaLookAndFeel()) {
+      setMargin(new Insets(0, 0, 0, 0));
+    }
+   }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/ThreeDotsIcon.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/ThreeDotsIcon.java
new file mode 100755
index 0000000..ba1a4eb
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/ThreeDotsIcon.java
@@ -0,0 +1,79 @@
+package gov.noaa.pmel.swing;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Color;
+import javax.swing.Icon;
+
+/**
+ * Creates icon of three dots to be used with a <code>JButton</code>
+ * to open a dialog.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $
+ * @since 3.0
+ */
+
+public class ThreeDotsIcon implements Icon {
+  private Color color_;
+  private int size_;
+  private int space_;
+  private int dot_;
+  private int y_;
+
+  public ThreeDotsIcon() {
+    this(Color.black, 14);
+  }
+
+  public ThreeDotsIcon(Color color) {
+    this(color, 14);
+  }
+
+  public ThreeDotsIcon(Color color, int size) {
+    color_ = color;
+    if(size <= 14) {
+      dot_ = 2;
+      space_ = 2;
+      size_ = 14;
+    } else if(size > 14 && size <= 17) {
+      dot_ = 3;
+      space_ = 2;
+      size_ = 17;
+    } else if(size > 17 && size <= 20) {
+      dot_ = 4;
+      space_ = 2;
+      size_ = 20;
+    } else {
+      size_ = size;
+      dot_ = size_/5;
+      space_ = dot_/2;
+      if(space_ <= 1) space_ = 2;
+      dot_ = (size_ - 4*space_)/3;
+    }
+    y_ = (size_ - dot_)/2;
+  }
+
+  public void paintIcon(Component c, Graphics g, int x, int y) {
+    int xt, yt;
+    Color save = g.getColor();
+    g.setColor(color_);
+
+    xt = x + space_;
+    yt = y + y_;
+    g.fillOval(xt, yt, dot_, dot_);
+    xt = xt + space_ + dot_;
+    g.fillOval(xt, yt, dot_, dot_);
+    xt = xt + space_ + dot_;
+    g.fillOval(xt, yt, dot_, dot_);
+
+    g.setColor(save);
+  }
+
+  public int getIconWidth() {
+    return size_;
+  }
+
+  public int getIconHeight() {
+    return size_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/beans/SliderHandle.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/beans/SliderHandle.java
new file mode 100755
index 0000000..ac6ecca
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/beans/SliderHandle.java
@@ -0,0 +1,145 @@
+/*
+ * $Id: SliderHandle.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ */
+ 
+package gov.noaa.pmel.swing.beans;
+ 
+import java.awt.Color;
+import java.awt.Graphics;
+ 
+/**
+ * Description of Class SliderHandle
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+**/
+public class SliderHandle implements java.io.Serializable {
+  static public int LEFT = 0;
+  static public int RIGHT = 1;
+  static public int SINGLE = 2;
+  Color color_;
+  int size_;
+  int posx_;
+  int posy_;
+  int style_ = SINGLE;
+  int[] xpts = new int[9];
+  int[] ypts = new int[9];
+  /**
+   * Default constructor
+   **/
+  public SliderHandle() {
+    this(6, Color.red, SINGLE);
+  }
+  public SliderHandle(int size, Color color) {
+    this(size, color, SINGLE);
+  }
+  /**
+   * SliderHandle constructor.
+   *
+   * @param xpos horizontal position of handle
+   * @param ypos vertical position of handle
+   * @param size size of handle in pixels
+   * @param color handle color
+   **/
+  public SliderHandle(int size, Color color, int style) {
+    size_ = size;
+    color_ = color;
+    style_ = style;
+  }
+  /**
+   * Get the size of the handle in pixels;
+   *
+   * @return handle size
+   **/
+  public int getSize() {
+    return size_;
+  }
+  /**
+   * Set the size of the handle (in pixels).
+   *
+   * @param sz handle size in pixels
+   **/
+  public void setSize(int sz) {
+    size_ = sz;
+  }
+  public void setStyle(int st) {
+    style_ = st;
+  }
+  public int getStyle() {
+    return style_;
+  }
+  /**
+   * Get the color of the handle
+   *
+   * @return the handle color
+   **/
+  public Color getColor() {
+    return color_;
+  }
+  /**
+   * Set the handle color
+   *
+   * @param clr handle color
+   **/
+  public void setColor(Color clr) {
+    color_ = clr;
+  }
+  /**
+   * Get the current handle position
+   *
+   * @return current handle position
+   **/
+  public int getPosition() {
+    return posx_;
+  }
+  public void draw(Graphics g, int posx, int posy) {
+    g.setColor(color_);
+        
+    posx_ = posx;
+    posy_ = posy;
+
+    int pt = 0;
+    if(style_ == SINGLE || style_ == LEFT) {
+      xpts[0] = posx_;
+      ypts[0] = posy_;
+      xpts[1] = posx_ - size_;
+      ypts[1] = posy_ + size_;
+      xpts[2] = xpts[1];
+      ypts[2] = ypts[1] + size_;
+      xpts[3] = xpts[0];
+      ypts[3] = ypts[2];
+      xpts[4] = xpts[0];
+      ypts[4] = ypts[0];
+      pt = 5;
+    }
+    if(style_ == SINGLE || style_ == RIGHT) {
+      if(pt == 0) {
+        xpts[pt] = posx_;
+        ypts[pt] = posy_;
+        pt++;
+      } else {
+        pt = 4;
+      }
+      xpts[pt] = posx_;
+      ypts[pt] = posy_ + 2*size_;
+      xpts[pt+1] = posx_ + size_;
+      ypts[pt+1] = ypts[pt];
+      xpts[pt+2] = xpts[pt+1];
+      ypts[pt+2] = posy_ + size_;
+      xpts[pt+3] = posx_;
+      ypts[pt+3] = posy_;
+      pt = pt + 4;
+    }
+    
+ /*   xpts[0] = posx_;
+    ypts[0] = posy_;
+    xpts[1] = posx_ - size_;
+    ypts[1] = posy_ + 2*size_;
+    xpts[2] = posx_ + size_;
+    ypts[2] = ypts[1];
+    xpts[3] = xpts[0];
+    ypts[3] = ypts[0]; */
+        
+    g.fillPolygon(xpts, ypts, pt);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/package.html
new file mode 100755
index 0000000..f34bc46
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/swing/package.html
@@ -0,0 +1,10 @@
+<HTML>
+<BODY>
+Classes and beans developed from the <code>javax.swing</code> package.
+
+<P>This package contains both gui classes that begin with a "J")
+and non-visual support classes. </P>
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/text/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/text/package.html
new file mode 100755
index 0000000..3cc4782
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/text/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Provides classes and interfaces for handling text, dates, numbers, and messages.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ColorMap.java
new file mode 100755
index 0000000..7542941
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ColorMap.java
@@ -0,0 +1,85 @@
+package gov.noaa.pmel.util;
+
+import java.util.*;
+import java.awt.*;
+import gov.noaa.pmel.sgt.Transform;
+
+public class ColorMap {
+	protected String mParamName;
+	Vector mPieceRanges = new Vector();		// stores the physical ranges (Range2D) for each of the pieces of the colormap
+	Vector mRedTransforms = new Vector();	// stores the transforms from physical to user coords for the red component
+	Vector mGreenTransforms = new Vector();	// stores the transforms from physical to user coords for the green component
+	Vector mBlueTransforms = new Vector();	// stores the transforms from physical to user coords for blue component
+	
+	public ColorMap() {
+		// zero argument ctor
+	}
+	
+	public ColorMap(ColorMap inMap) {
+		// copy constructor
+	
+	}
+	
+	// public methods
+	public Color getColor(double inVal) {
+		// find the appropriate transform by testing what Range2D it's in
+		int foundPiece = -99;
+		int numPieces = mPieceRanges.size();
+		
+		// first test whether it's out of range
+		double sVal =((Range2D)mPieceRanges.elementAt(0)).start;
+		double eVal =((Range2D)mPieceRanges.elementAt(numPieces - 1)).end;
+		if (inVal <= sVal) {
+			float red = (float)(((Transform)mRedTransforms.elementAt(0)).getTransU(sVal));
+			float green = (float)(((Transform)mGreenTransforms.elementAt(0)).getTransU(sVal));
+			float blue = (float)(((Transform)mBlueTransforms.elementAt(0)).getTransU(sVal));
+			return new Color(red, green, blue);
+		}
+		else if (inVal >= eVal) {
+			float red = (float)(((Transform)mRedTransforms.elementAt(numPieces - 1)).getTransU(eVal));
+			float green = (float)(((Transform)mGreenTransforms.elementAt(numPieces - 1)).getTransU(eVal));
+			float blue = (float)(((Transform)mBlueTransforms.elementAt(numPieces - 1)).getTransU(eVal));
+			System.out.println(red + " " + green + " " + blue);
+			return new Color(red, green, blue);
+		}
+		
+		// value is in range
+		for (int i=0; i<mPieceRanges.size(); i++) {
+			Range2D range = (Range2D)mPieceRanges.elementAt(i);
+			sVal = range.start;
+			eVal = range.end;
+			if (inVal >= sVal && inVal <= eVal) {
+				foundPiece = i;
+				break;
+			}
+		}
+		float red = (float)(((Transform)mRedTransforms.elementAt(foundPiece)).getTransU(eVal));
+		float green = (float)(((Transform)mGreenTransforms.elementAt(foundPiece)).getTransU(eVal));
+		float blue = (float)(((Transform)mBlueTransforms.elementAt(foundPiece)).getTransU(eVal));
+		return new Color(red, green, blue);
+	}
+	
+	public void addTransform(Transform inTransRed, Transform inTransGreen, Transform inTransBlue) {
+		mRedTransforms.addElement(inTransRed);
+		mGreenTransforms.addElement(inTransGreen);
+		mBlueTransforms.addElement(inTransBlue);
+		mPieceRanges.addElement(inTransRed.getRangeP());
+	}
+	
+	public IndexedColorMap getIndexedColorMap(int numColors) {
+		return new IndexedColorMap(this, numColors);
+	}
+	
+	public String getParamName() {
+		return mParamName;
+	}
+	
+	public double getMaxValue() {
+		return ((Range2D)mPieceRanges.elementAt(mPieceRanges.size()-1)).end;
+	}
+	
+	public double getMinValue() {
+		return ((Range2D)mPieceRanges.elementAt(0)).start;
+	
+	}
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ColorTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ColorTransform.java
new file mode 100755
index 0000000..d5379be
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ColorTransform.java
@@ -0,0 +1,75 @@
+/*
+ * $Id: ColorTransform.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.util;
+
+import java.beans.PropertyChangeListener;
+import gov.noaa.pmel.util.Range2D;
+import java.awt.*;
+import gov.noaa.pmel.sgt.TransformColor;
+import gov.noaa.pmel.sgt.Transform;
+ 
+/**
+ * <code>Transform</code> defines an interface for transformations between 
+ * user and physical coordinates.
+ *
+ * @see AxisTransform
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 1.0
+ */
+public class ColorTransform implements TransformColor {
+	Transform mRedTransform;
+	Transform mGreenTransform;
+	Transform mBlueTransform;;
+	
+	public ColorTransform() {
+	}
+	
+	public ColorTransform(Transform redTransform, Transform greenTransform, Transform blueTransform) {
+		mRedTransform = redTransform;
+		mGreenTransform = greenTransform;
+		mBlueTransform = blueTransform;
+	}
+	
+	public Transform getRedTransform() {
+		return mRedTransform;
+	}
+
+	public void setRedTransform(Transform redTransform) {
+		mRedTransform = redTransform;
+	}
+
+	public Transform getGreenTransform()  {
+		return mGreenTransform;
+	}
+
+	public void setGreenTransform(Transform greenTransform) {
+		mGreenTransform = greenTransform;
+	}
+
+	public Transform getBlueTransform() {
+		return mBlueTransform;
+	}
+
+	public void setBlueTransform(Transform blueTransform) {
+		mBlueTransform = blueTransform;
+	}
+
+	public void setColorTransforms(Transform red, Transform green, Transform blue) {
+		mRedTransform = red;
+		mGreenTransform = green;
+		mBlueTransform = blue;
+	}
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Debug.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Debug.java
new file mode 100755
index 0000000..6afac10
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Debug.java
@@ -0,0 +1,23 @@
+/*
+ * $Id: Debug.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ */
+
+package gov.noaa.pmel.util
+;
+/**
+ * For debugging only
+ */
+public class Debug {
+  public static final boolean DEBUG = false;
+  public static final boolean DRAW_TRACE = false;
+  public static final boolean TAXIS = false;
+  /**
+   * Write debug statements related to internal sgt
+   * events.
+   */
+  public static final boolean EVENT = false;
+  /**
+   * Debug for contouring
+   */
+  public static final boolean CONTOUR = false;
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Dimension2D.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Dimension2D.java
new file mode 100755
index 0000000..c615713
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Dimension2D.java
@@ -0,0 +1,87 @@
+/*
+ * $Id: Dimension2D.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.util;
+
+/**
+ * A class to encapsulate a <code>double</code> width and a height.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 1.0
+ */
+public class Dimension2D {
+  public double height;
+  public double width;
+  public Dimension2D() {
+    width = 0.0;
+    height = 0.0;
+}
+  public Dimension2D(double width, double height) {
+    this.width = width;
+    this.height = height;
+  }
+  /**
+   * Returns the width.
+   *
+   * @return the width
+   */
+  public double getWidth() {
+    return width;
+  }
+  
+  /**
+   * Returns the height.
+   *
+   * @return the height
+   */
+  public double getHeight() {
+    return height;
+  }
+  
+  /**
+   * Set the size to the specified width
+   * and height.
+   * This method is included for completeness, to parallel the
+   * getSize method of <code>Component</code>.
+   * @param width  the new width
+   * @param height  the new height
+   */
+  public void setSize(double width, double height) {
+    this.width = width;
+    this.height = height;
+  }
+  
+  /**
+   * Set the size to match the specified size.
+   * This method is included for completeness, to parallel the
+   * getSize method of <code>Component</code>.
+   * @param d  the new size
+   */
+  public void setSize(Dimension2D d) {
+    setSize(d.getWidth(), d.getHeight());
+  }
+  /**
+   *
+   */
+  public String toString() {
+    return getClass().getName() + "[width=" + width + ",height=" + height +
+"]";
+  }
+  /**
+   * Test for equality.  Both width and height must be equal to be
+   * true.
+   */
+  public boolean equals(Dimension2D d) {
+    return (width == d.width && height == d.height);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Domain.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Domain.java
new file mode 100755
index 0000000..1f81e18
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Domain.java
@@ -0,0 +1,221 @@
+/*
+ * $Id: Domain.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package  gov.noaa.pmel.util;
+
+/**
+ * <code>GraphDomain</code> contains the X and Y ranges in user units.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 2.0
+ */
+public class Domain implements java.io.Serializable {
+  Range2D xRange_ = null;
+  Range2D yRange_ = null;
+  TimeRange tRange_ = null;
+  boolean xTime_ = false;
+  boolean yTime_ = false;
+  boolean xReversed_ = false;
+  boolean yReversed_ = false;
+  /**
+   * Default constructor.
+   */
+  public Domain() {
+  }
+  /**
+   * Create a copy of a <code>Domain</code>.  The references for the
+   * ranges are copied, not the objects.
+   */
+  public Domain(Domain domain) {
+    if(domain.isXTime()) {
+      tRange_ = domain.getTimeRange();
+    } else {
+      xRange_ = domain.getXRange();
+    }
+    if(domain.isYTime()) {
+      tRange_ = domain.getTimeRange();
+    } else {
+      yRange_ = domain.getYRange();
+    }
+    xReversed_ = domain.isXReversed();
+    yReversed_ = domain.isYReversed();
+  }
+  public Domain(Range2D xRange, Range2D yRange) {
+    xRange_ = xRange;
+    yRange_ = yRange;
+  }
+  public Domain(TimeRange tRange, Range2D yRange) {
+    tRange_ = tRange;
+    yRange_ = yRange;
+    xTime_ = true;
+  }
+  public Domain(Range2D xRange, TimeRange tRange) {
+    xRange_ = xRange;
+    tRange_ = tRange;
+    yTime_ = true;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public Domain(Range2D xRange, Range2D yRange,
+                boolean xRev, boolean yRev) {
+    xRange_ = xRange;
+    yRange_ = yRange;
+    xReversed_ = xRev;
+    yReversed_ = yRev;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public Domain(TimeRange tRange, Range2D yRange,
+                boolean xRev, boolean yRev) {
+    tRange_ = tRange;
+    yRange_ = yRange;
+    xTime_ = true;
+    xReversed_ = xRev;
+    yReversed_ = yRev;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public Domain(Range2D xRange, TimeRange tRange,
+                boolean xRev, boolean yRev) {
+    xRange_ = xRange;
+    tRange_ = tRange;
+    yTime_ = true;
+    xReversed_ = xRev;
+    yReversed_ = yRev;
+  }
+  /**
+   * Set the x range.
+   */
+  public void setXRange(Range2D xRange) {
+    xTime_ = false;
+    xRange_ = xRange;
+  }
+  /**
+   * Set the x range as time.
+   */
+  public void setXRange(TimeRange tRange) {
+    xTime_ = true;
+    tRange_ = tRange;
+  }
+  /**
+   * Get the x range.
+   */
+  public Range2D getXRange() {
+    return xRange_;
+  }
+  /**
+   * Set the y range
+   */
+  public void setYRange(Range2D yRange) {
+    yTime_ = false;
+    yRange_ = yRange;
+  }
+  /**
+   * Set the yrange as time.
+   */
+  public void setYRange(TimeRange tRange) {
+    yTime_ = true;
+    tRange_ = tRange;
+  }
+  /**
+   * Get the y range.
+   */
+  public Range2D getYRange() {
+    return yRange_;
+  }
+  /**
+   * Get the time range
+   */
+  public TimeRange getTimeRange() {
+    return tRange_;
+  }
+  /**
+   * Test if x range is time.
+   */
+  public boolean isXTime() {
+    return xTime_;
+  }
+  /**
+   * Test if y range is time.
+   */
+  public boolean isYTime() {
+    return yTime_;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public void setYReversed(boolean rev) {
+    yReversed_ = rev;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public boolean isYReversed() {
+    return yReversed_;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public void setXReversed(boolean rev) {
+    xReversed_ = rev;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public boolean isXReversed() {
+    return xReversed_;
+  }
+
+  /**
+   * Tests for equality of <code>Domain</code>s.  Both ranges must be
+   * equal.
+   */
+  public boolean equals(Domain d) {
+    if(xTime_) {
+      if(!d.isXTime()) return false;
+      if(!tRange_.equals(d.getTimeRange())) return false;
+    } else {
+      if(d.isXTime()) return false;
+      if(!xRange_.equals(d.getXRange())) return false;
+    }
+    if(yTime_) {
+      if(!d.isYTime()) return false;
+      if(!tRange_.equals(d.getTimeRange())) return false;
+    } else {
+      if(d.isYTime()) return false;
+      if(!yRange_.equals(d.getYRange())) return false;
+    }
+    if(xReversed_ != d.isXReversed()) return false;
+    if(yReversed_ != d.isYReversed()) return false;
+    return true;
+  }
+  public String toString() {
+    StringBuffer buf = new StringBuffer(100);
+    buf.append("x=");
+    if(xTime_) {
+      buf.append(tRange_).append(",y=");
+    } else {
+      buf.append(xRange_).append(",y=");
+    }
+    if(yTime_) {
+      buf.append(tRange_);
+    } else {
+      buf.append(yRange_);
+    }
+    buf.append(", xRev=").append(xReversed_);
+    buf.append(", yRev=").append(yReversed_);
+    return buf.toString();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/EPICSystem.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/EPICSystem.java
new file mode 100755
index 0000000..3692579
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/EPICSystem.java
@@ -0,0 +1,48 @@
+/*
+ * $Id: EPICSystem.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.util;
+
+import java.util.StringTokenizer;
+
+/**
+ * Uility methods for accessing Java System information.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since 3.0
+ **/
+public class EPICSystem {
+
+  public EPICSystem() {
+  }
+
+  /**
+   * Get the major java version.  If 1.4.2, returns 1.
+   * @return java version
+   */
+  static public int getJavaMajorVersion() {
+    StringTokenizer st = new StringTokenizer(System.getProperty("java.version"),
+        ".", false);
+    return Integer.parseInt(st.nextToken());
+  }
+  /**
+   * Get the minor java version.  If 1.4.2, returns 2.
+   * @return java minor version
+   */
+ static public int getJavaMinorVersion() {
+   StringTokenizer st = new StringTokenizer(System.getProperty("java.version"),
+       ".", false);
+   st.nextToken();
+   return Integer.parseInt(st.nextToken());
+  }
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ExponentialTransformDown.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ExponentialTransformDown.java
new file mode 100755
index 0000000..a70018f
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ExponentialTransformDown.java
@@ -0,0 +1,185 @@
+/*
+ * $Id: ExponentialTransformDown.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.util;
+
+import java.beans.PropertyChangeListener;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.sgt.Transform;
+ 
+/**
+ * <code>ExponentialTransformUp</code> defines a exponential transformations between 
+ * user and physical coordinates defined between two end points.
+ *
+ * @see AxisTransform
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ */
+public class ExponentialTransformDown implements Transform {
+	Range2D mPhysRange = null;
+	Range2D mUserRange = null;
+	//double a = 0.46487;
+	//double b = 1.7563;
+	//double c = -2.8931;
+	//double d = 2.6001;
+	
+	double a = 0.82605;
+	double b = -2.3006;
+	double c = 2.4729;
+
+	public ExponentialTransformDown(double p1, double p2, double u1, double u2) {
+		setRangeP(p1, p2);
+		setRangeU(u1, u2);
+	}
+
+	public ExponentialTransformDown(Range2D prange, Range2D urange) {
+		setRangeP(prange);
+		setRangeU(urange);
+	}
+
+	public ExponentialTransformDown() {
+	}
+	
+	/**
+	* Set physical coordinate range.
+	*
+	* @param p1 minimum value, physical coordinates
+	* @param p2 maximum value, physical coordinates
+	* @see LinearTransform
+	**/
+	public void setRangeP(double p1,double p2) {
+		mPhysRange = new Range2D(p1, p2);
+	}
+
+	/**
+	* Set physical coordinate range.
+	*
+	* @param prange physcial coordinate range
+	* @see Range2D
+	* @see LinearTransform
+	**/
+	public void setRangeP(Range2D prange) {
+		mPhysRange = null;
+		mPhysRange = new Range2D();
+		mPhysRange.add(prange);
+	}
+
+	/**
+	* Get the physical coordinate range.
+	*
+	* @return physcial coordinate range
+	* @see Range2D
+	**/
+	public Range2D getRangeP() {
+		return mPhysRange;
+	}
+
+	/**
+	* Set the user coordinate range for double values.
+	*
+	* @param u1 minimum value, user coordinates
+	* @param u2 maximum value, user coordinates
+	* @see LinearTransform
+	**/
+	public void setRangeU(double u1,double u2) {
+		mUserRange = new Range2D(u1, u2);
+	}
+
+	/**
+	* Set the user coordinate range for double values.
+	*
+	* @param urange user coordinate range
+	* @see Range2D
+	* @see LinearTransform
+	**/
+	public void setRangeU(Range2D urange) {
+		mUserRange = null;
+		mUserRange = new Range2D();
+		mUserRange.add(urange);
+	}
+
+	/**
+	* Get the user coordinate range for double values.
+	*
+	* @return user range
+	* @see Range2D
+	**/
+	public Range2D getRangeU() {
+		return mUserRange;
+	}
+
+	/**
+	* Transform from user to physical coordinates.
+	*
+	* @param u user value
+	* @return physical value
+	*/
+	public double getTransP(double u) {
+		double retVal = 0.0;
+		// first have to find u in the normalized range of the y axis
+		double y = (u - mUserRange.start)/(mUserRange.end - mUserRange.start);
+		
+		// now iterate to find solution
+		double x = 0.5;
+		double inc = 0.0001;
+		double eps = 0.001;
+		int cnt = 0;
+		while (true) {
+			//double tstVal = d * x + c * (x * x) + b * (x * x * x) + a * (x * x * x * x);
+			double tstVal = c * x + b * (x * x) + a * (x * x * x);
+			if (Math.abs(tstVal - y) < eps) {
+				retVal = x;
+				break;
+			}
+			else {
+				if (tstVal > y)
+					x -= inc;
+				else
+					x += inc;
+			}
+			cnt++;
+		}
+		//System.out.println("iter count = " + cnt);
+		
+		// scale the x value back to the unnormalized range
+		retVal = mPhysRange.start + x * (mPhysRange.end - mPhysRange.start);
+		return retVal;
+	}
+
+	/**
+	* Transform from physical to user coordinates.
+	*
+	* @param p physical value
+	* @return user value
+	*/
+	public double getTransU(double p) {
+		double retVal = 0.0;
+		double x = (p - mPhysRange.start)/(mPhysRange.end - mPhysRange.start);
+		//double y = d * x + c * (x * x) + b * (x * x * x) + a * (x * x * x * x);
+		double y = c * x + b * (x * x) + a * (x * x * x);
+		retVal = mUserRange.start + y * (mUserRange.end - mUserRange.start);
+		return retVal;
+	}
+
+	/**
+	* Add listener for changes to transform properties.
+	*/
+	public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+	}
+
+	public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+	}
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ExponentialTransformUp.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ExponentialTransformUp.java
new file mode 100755
index 0000000..590f673
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/ExponentialTransformUp.java
@@ -0,0 +1,178 @@
+/*
+ * $Id: ExponentialTransformUp.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.util;
+
+import java.beans.PropertyChangeListener;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.sgt.Transform;
+ 
+/**
+ * <code>ExponentialTransformUp</code> defines a exponential transformations between 
+ * user and physical coordinates defined between two end points.
+ *
+ * @see AxisTransform
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ */
+public class ExponentialTransformUp implements Transform {
+	Range2D mPhysRange = null;
+	Range2D mUserRange = null;
+	double a = 0.82809;
+	double b = -0.17839;
+	double c = 0.349;
+
+	public ExponentialTransformUp(double p1, double p2, double u1, double u2) {
+		setRangeP(p1, p2);
+		setRangeU(u1, u2);
+	}
+
+	public ExponentialTransformUp(Range2D prange, Range2D urange) {
+		setRangeP(prange);
+		setRangeU(urange);
+	}
+
+	public ExponentialTransformUp() {
+	}
+	
+	/**
+	* Set physical coordinate range.
+	*
+	* @param p1 minimum value, physical coordinates
+	* @param p2 maximum value, physical coordinates
+	* @see LinearTransform
+	**/
+	public void setRangeP(double p1,double p2) {
+		mPhysRange = new Range2D(p1, p2);
+	}
+
+	/**
+	* Set physical coordinate range.
+	*
+	* @param prange physcial coordinate range
+	* @see Range2D
+	* @see LinearTransform
+	**/
+	public void setRangeP(Range2D prange) {
+		mPhysRange = null;
+		mPhysRange = new Range2D();
+		mPhysRange.add(prange);
+	}
+
+	/**
+	* Get the physical coordinate range.
+	*
+	* @return physcial coordinate range
+	* @see Range2D
+	**/
+	public Range2D getRangeP() {
+		return mPhysRange;
+	}
+
+	/**
+	* Set the user coordinate range for double values.
+	*
+	* @param u1 minimum value, user coordinates
+	* @param u2 maximum value, user coordinates
+	* @see LinearTransform
+	**/
+	public void setRangeU(double u1,double u2) {
+		mUserRange = new Range2D(u1, u2);
+	}
+
+	/**
+	* Set the user coordinate range for double values.
+	*
+	* @param urange user coordinate range
+	* @see Range2D
+	* @see LinearTransform
+	**/
+	public void setRangeU(Range2D urange) {
+		mUserRange = null;
+		mUserRange = new Range2D();
+		mUserRange.add(urange);
+	}
+
+	/**
+	* Get the user coordinate range for double values.
+	*
+	* @return user range
+	* @see Range2D
+	**/
+	public Range2D getRangeU() {
+		return mUserRange;
+	}
+
+	/**
+	* Transform from user to physical coordinates.
+	*
+	* @param u user value
+	* @return physical value
+	*/
+	public double getTransP(double u) {
+		double retVal = 0.0;
+		// first have to find u in the normalized range of the y axis
+		double y = (u - mUserRange.start)/(mUserRange.end - mUserRange.start);
+		
+		// now iterate to find solution
+		double x = 0.5;
+		double inc = 0.0001;
+		double eps = 0.001;
+		int cnt = 0;
+		while (true) {
+			double tstVal = c * x + b * (x * x) + a * (x * x * x);
+			if (Math.abs(tstVal - y) < eps) {
+				retVal = x;
+				break;
+			}
+			else {
+				if (tstVal > y)
+					x -= inc;
+				else
+					x += inc;
+			}
+			cnt++;
+		}
+		//System.out.println("iter count = " + cnt);
+		
+		// scale the x value back to the unnormalized range
+		retVal = mPhysRange.start + x * (mPhysRange.end - mPhysRange.start);
+		return retVal;
+	}
+
+	/**
+	* Transform from physical to user coordinates.
+	*
+	* @param p physical value
+	* @return user value
+	*/
+	public double getTransU(double p) {
+		double retVal = 0.0;
+		double x = (p - mPhysRange.start)/(mPhysRange.end - mPhysRange.start);
+		double y = c * x + b * (x * x) + a * (x * x * x);
+		retVal = mUserRange.start + y * (mUserRange.end - mUserRange.start);
+		return retVal;
+	}
+
+	/**
+	* Add listener for changes to transform properties.
+	*/
+	public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+	}
+
+	public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+	}
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeoDate.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeoDate.java
new file mode 100755
index 0000000..0d526f8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeoDate.java
@@ -0,0 +1,777 @@
+/*
+ * $Id: GeoDate.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.util;
+
+import  java.util.Date;
+import  java.util.Calendar;
+import  java.util.GregorianCalendar;
+import  java.util.TimeZone;
+
+import  java.text.DateFormat;
+import  java.text.SimpleDateFormat;
+import  java.text.ParsePosition;
+
+/**
+ * <code>GeoDate</code> extends the capabilities of <code>Date</code>.
+ * Additional features of <code>GeoDate</code> include methods for
+ * incrementing and decrementing, adding and substracting
+ * <code>GeoDate</code> objects. All <code>GeoDate</code> objects
+ * share the same <code>GregorianCalendar</code> set to a "GMT" time
+ * zone. Thus, all <code>GeoDate</code> times are in "GMT". This
+ * simplifies the conversion to and from <code>String</code>
+ * representations of time.
+ *
+ * @see GregorianCalendar
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 1.0
+ */
+public class GeoDate extends java.util.Date implements java.io.Serializable {
+  private int max_day_[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+  private boolean splitDone_;
+  private int yearday_;
+  private int dayofweek_;
+  private int year_;
+  private int month_;
+  private int day_;
+  private int hour_;
+  private int minute_;
+  private int second_;
+  private int msec_;
+  private int MSec_;
+  private int JDay_;
+  private boolean EPICTimeDone_;
+  private boolean relativeTime_ = false;
+  private static Calendar cal_ = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+  /** Increment or decrement in days. */
+  public static final int DAYS = 1;
+  /** Increment or decrement in months.  */
+  public static final int MONTHS = 2;
+  /** Increment or decrement in years.  */
+  public static final int YEARS = 4;
+  /** Increment or decrement in hours.  */
+  public static final int HOURS = 5;
+  /** Increment or decrement in minutes  */
+  public static final int MINUTES = 6;
+  /** Increment or decrement in seonds  */
+  public static final int SECONDS = 7;
+  /** Increment or decrement in milliseconds */
+  public static final int MSEC = 8;
+  /** Number of milliseconds in a day. */
+  public static final long MSECS_IN_DAY = 86400000;
+  /** Construct a new <code>GeoDate</code>. */
+  public GeoDate() {
+    super();
+  }
+  /**
+   * Construct a new <code>GeoDate</code> from a
+   * <code>String</code>. Formatting is done using
+   * <code>SimpleDateFormat</code>. The specified time
+   * is taken to be "GMT".
+   *
+   * @param time character representation of time
+   * @param format codes used to read time
+   */
+  public GeoDate(String time,String format) throws IllegalTimeValue {
+    super();
+    ParsePosition pos = new ParsePosition(0);
+    DateFormat df = new SimpleDateFormat(format);
+    df.setCalendar(cal_);
+
+    Date dte = df.parse(time, pos);
+    if(dte == null) {
+      throw new IllegalTimeValue("Parse error: " + time + ", " + format);
+    }
+    setTime(dte.getTime());
+  }
+  /**
+   * Constructs a new <code>GeoDate</code> from an
+   * existing <code>GeoDate</code>.
+   *
+   * @param t <code>GeoDate</code>
+   */
+  public GeoDate(GeoDate t) {
+    super(t.getTime());
+  }
+  /**
+   * Construct a new <code>GeoDate</code> from values. The
+   * specified time is taken to be "GMT".
+   *
+   * @param mon month
+   * @param day day of the month
+   * @param year year (no offset!)
+   * @param hour hour
+   * @param min minutes
+   * @param sec seconds
+   * @param msec milliseconds
+   * @exception IllegalTimeValue The constructor was called with a set
+   * of parameters that does not constitute a legitimate time value.
+   */
+  public GeoDate(int mon,int day,int year,int hour,int min,int sec,int msec) throws IllegalTimeValue  {
+    this.set(mon, day, year, hour, min, sec, msec);
+  }
+  /**
+   * Construct a new <code>GeoDate</code> from a
+   * <code>Date</code> object. No time zone conversion
+   * is done.
+   *
+   * @param date Date object
+   */
+  public GeoDate(Date date) {
+    setTime(date.getTime());
+  }
+  /**
+   * Construct a new <code>GeoDate</code> from EPIC double integers.
+   * Time zone for conversion is "GMT".
+   *
+   * @param jday julian day
+   * @param msec milliseconds since midnight
+   */
+  public GeoDate(int jday, int msec) {
+    set(jday, msec);
+  }
+
+  /**
+   * Allocates a GeoDate object and initializes it to represent
+   * the specified number of milliseconds since the standard
+   * base time know as "the epoch", namely January 1, 1970, 00:00:00
+   * GMT.
+   */
+  public GeoDate(long date) {
+    setTime(date);
+  }
+  /**
+   * Set the relativeTime flag.  The relativeTime flag indicates that
+   * the <code>GeoDate</code> object does not represent an actual
+   * absolute time, but a temporal duration.
+   */
+  public void setRelativeTime(boolean relative) {
+    relativeTime_ = relative;
+  }
+  /**
+   * Tests the relativeTime flag.
+   *
+   * @return if true, time is a duration
+   */
+  public boolean isRelativeTime() {
+    return relativeTime_;
+  }
+  /**
+   * Change value of <code>GeoDate</code> from EPIC double
+   * integers.
+   * Time zone for conversion is "GMT".
+   *
+   * @param jday julian day
+   * @param msec milliseconds since midnight
+   */
+  public void set(int jday, int msec) {
+    int ja, jb, jc, jd, je;
+    double jalpha, second;
+    int day, month, year, hour, minute, sec;
+
+    if(jday > 2299161) {
+      jalpha = ((double)(jday - 1867216)-0.25)/36524.25;
+      ja = jday + 1 + (int)jalpha - (int)(0.25*jalpha);
+    } else {
+      ja = jday;
+    }
+    jb = ja + 1524;
+    jc = (int)(6680.0 + ((double)(jb - 2439870) - 122.1)/365.25);
+    jd = (int)(365*jc + (0.25*jc));
+    je = (int)((jb - jd)/30.6001);
+
+    day = (int)(jb - jd) - (int)(30.6001*je);
+    month = (int)(je - 1);
+    if(month > 12) month -= 12;
+    year = (int)(jc - 4715);
+    if(month > 2) --year;
+    if(year <= 0) --year;
+    ja = msec/1000;
+    hour = (int)(ja/3600);
+    minute = (int)((ja - hour*3600)/60);
+    second = (double)(msec - (hour*3600 + minute*60)*1000)/1000.0;
+    sec = (int)second;
+    msec = ((int)(second*1000.0))%1000;
+    try{
+      set(month, day, year, hour, minute, sec, msec);
+    } catch (IllegalTimeValue e) {}
+  }
+  /**
+   * Change value of <code>GeoDate</code> from values.
+   * Time zone for conversion is "GMT".
+   *
+   * @param mon month (1=January, 12=December)
+   * @param day day of the month
+   * @param year year (no offset!)
+   * @param hour hour
+   * @param min minutes
+   * @param sec seconds
+   * @param msec milliseconds
+   * @exception IllegalTimeValue The parameters passed to this method represent a time
+   * value that is invalid
+   *
+   */
+  public void set(int mon,int day,int year,int hour,int min,int sec,int msec) throws IllegalTimeValue  {
+    int jy, jm, ja, jul;
+    int leap = (year%4 != 0? 0: (year%400 == 0? 1: (year%100==0? 0: 1)));
+    max_day_[1] = 28 + leap;
+
+    if(mon > 12 || mon < 1) {
+      this.setTime(0);
+      throw new IllegalTimeValue("value of month out of range");
+    }
+    if(day > max_day_[mon-1] || day < 1) {
+      this.setTime(0);
+      throw new IllegalTimeValue("value of day out of range");
+    }
+    if(hour >= 24 || hour < 0) {
+      this.setTime(0);
+      throw new IllegalTimeValue("value of hour out of range");
+    }
+    if(min >= 60 || min < 0) {
+      this.setTime(0);
+      throw new IllegalTimeValue("value of minute out of range");
+    }
+    if(sec >= 60 || sec < 0) {
+      this.setTime(0);
+      throw new IllegalTimeValue("value of second out of range");
+    }
+    if(msec >= 1000 || msec < 0) {
+      this.setTime(0);
+      throw new IllegalTimeValue("value of msec out of range");
+    }
+
+    cal_.clear();
+    cal_.set(year, mon - 1, day, hour, min, sec);
+
+    //    this.setTime(cal.getTimeInMillis() + msec);
+    this.setTime((cal_.getTime()).getTime() + msec);
+    splitDone_ = false;
+    EPICTimeDone_ = false;
+  }
+  /**
+   * Get the number of days in the current month.
+   *
+   * @return number of days in current month
+   **/
+  public int getDaysInMonth() {
+    int leap;
+    int year = cal_.get(Calendar.YEAR);
+    leap = (year%4 != 0? 0: (year%400 == 0? 1: (year%100==0? 0: 1)));
+    max_day_[1] = 28 + leap;
+    return max_day_[month_-1];
+  }
+  /**
+   * Set to current time.
+   */
+  public void now() {
+    Date nw = new Date();
+    this.setTime(nw.getTime());
+  }
+  /**
+   * Add time to current <code>GeoDate</code>. This operation only
+   * makes since if <code>time</code> is a relative time value,
+   * i.e. the result of a
+   * <code>GeoDate</code> subrtraction.
+   *
+   * @param time <code>GeoDate</code>
+   * @return new <code>GeoDate</code>
+   */
+  public GeoDate add(GeoDate time) {
+    GeoDate time2 = new GeoDate();
+    long MSec = getTime() + time.getTime();
+
+    time2.splitDone_ = false;
+    time2.EPICTimeDone_ = false;
+    time2.setTime(MSec);
+    return time2;
+  }
+  /**
+   * Subtract time2 from current <code>GeoDate</code>.
+   *
+   * @param time2 subtracthend
+   * @return new <code>GeoDate</code>
+   */
+  public GeoDate subtract(GeoDate time2) {
+    GeoDate delta = new GeoDate();
+    long MSec = getTime() - time2.getTime();
+
+    delta.splitDone_ = false;
+    delta.EPICTimeDone_ = false;
+    delta.setTime(MSec);
+    delta.setRelativeTime(true);
+    return delta;
+  }
+  /**
+   * Divide by value. Current time should the result of adding two times or
+   * subtracting two times to be a meaningful calculation.
+   *
+   * @param val divisor
+   * @return new <code>GeoDate</code>
+   */
+  public GeoDate divide(double val) {
+    GeoDate result = new GeoDate();
+
+    if(val == 0.0) return null;
+
+    result.setTime((long)(((double)getTime())/val));
+
+    result.splitDone_ = false;
+    result.EPICTimeDone_ = false;
+    result.setRelativeTime(true);
+    return result;
+  }
+  void splitTimeFormat() {
+    int ja, jb, jc, jd, je;
+    double jalpha;
+    GeoDate gt;
+
+    if(splitDone_) return;
+
+    cal_.setTime(this);
+    day_ = cal_.get(Calendar.DAY_OF_MONTH);
+    month_ = cal_.get(Calendar.MONTH) + 1;
+    year_ = cal_.get(Calendar.YEAR);
+    hour_ = cal_.get(Calendar.HOUR_OF_DAY);
+    minute_ = cal_.get(Calendar.MINUTE);
+    second_ = cal_.get(Calendar.SECOND);
+    msec_ = cal_.get(Calendar.MILLISECOND);
+    dayofweek_ = cal_.get(Calendar.DAY_OF_WEEK) - 1;
+    yearday_ = cal_.get(Calendar.DAY_OF_YEAR);
+
+    splitDone_ = true;
+  }
+  /**
+   * Increment current <code>GeoDate</code>
+   * by <code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>,
+   * <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>
+   *
+   * @param val amount to increment
+   * @param tu time units (<code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>, <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>)
+   * operation.
+   */
+  public GeoDate increment(float val,int tu) {
+    return increment((double)val, tu);
+  }
+  /**
+   * Increment current <code>GeoDate</code>
+   * by <code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>,
+   * <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>
+   *
+   * @param val amount to increment
+   * @param tu time units (<code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>, <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>)
+   * operation.
+   */
+  public GeoDate increment(double val,int tu) {
+    int leap;
+    int ival = (int)val;
+    double fract = (val - ival);
+    long MSec = getTime();
+    switch(tu) {
+    case MSEC:
+      MSec += (long)val;
+      setTime(MSec);
+      break;
+    case SECONDS:
+      MSec += (long)(val*1000);
+      setTime(MSec);
+      break;
+    case MINUTES:
+      MSec += (long)(val*60000);
+      setTime(MSec);
+      break;
+    case HOURS:
+      MSec += (long)(val*3600000);
+      setTime(MSec);
+      break;
+    case DAYS:                          // days and fraction days
+      MSec += (long)(val*MSECS_IN_DAY);
+      setTime(MSec);
+      break;
+    case MONTHS:                        // nearest day
+      splitTimeFormat();
+      month_ += ival;
+      year_ += ((month_-1)/12);
+      month_ -= ((month_-1)/12)*12;
+      if(month_ == 0) month_ = 1;
+      leap = (year_%4 != 0? 0: (year_%400 == 0? 1: (year_%100==0? 0: 1)));
+      max_day_[1] = 28 + leap;
+      day_ += (int)(fract*max_day_[month_-1]);
+      if(day_ > max_day_[month_-1]) {
+        day_ -= max_day_[month_-1];
+        month_++;
+        year_ += ((month_-1)/12);
+        month_ -= ((month_-1)/12)*12;
+        if(month_ == 0) month_ =1;
+      }
+      try {
+        this.set(month_, day_, year_, hour_, minute_, second_, msec_);
+      } catch (IllegalTimeValue e) {
+        System.err.println(e);
+      }
+      break;
+    case YEARS:                         // nearest day
+      splitTimeFormat();
+      year_ += ival;
+      leap = (year_%4 != 0? 0: (year_%400 == 0? 1: (year_%100==0? 0: 1)));
+      max_day_[1] = 28 + leap;
+      if(day_ > max_day_[month_-1]) day_ = max_day_[month_-1];
+      try {
+        this.set(month_, day_, year_, hour_, minute_, second_, msec_);
+      } catch (IllegalTimeValue e) {
+        System.err.println(e);
+      }
+      setTime(getTime() + (long)(fract*365.25)*MSECS_IN_DAY);
+      break;
+    }
+    splitDone_ = false;
+    EPICTimeDone_ = false;
+    return this;
+  }
+  /**
+   * Decrement current <code>GeoDate</code>
+   * by <code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>,
+   * <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>
+   *
+   * @param val amount to decrement
+   * @param tu time units (<code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>, <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>)
+   * operation.
+   */
+  public GeoDate decrement(float val,int tu) {
+    return decrement((double)val, tu);
+  }
+  /**
+   * Decrement current <code>GeoDate</code>
+   * by <code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>,
+   * <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>
+   *
+   * @param val amount to decrement
+   * @param tu time units (<code>SECONDS</code>, <code>MINUTES</code>, <code>HOURS</code>, <code>DAYS</code>, <code>MONTHS</code>, or <code>YEARS</code>)
+   * operation.
+   */
+  public GeoDate decrement(double val,int tu) {
+    int leap;
+    int ival = (int)val;
+    double fract = (val - ival);
+    long MSec = getTime();
+
+    switch(tu) {
+    case MSEC:
+      MSec -= (long)val;
+      setTime(MSec);
+      break;
+    case SECONDS:
+      MSec -= (long)(val*1000);
+      setTime(MSec);
+      break;
+    case MINUTES:
+      MSec -= (long)(val*60000);
+      setTime(MSec);
+      break;
+    case HOURS:
+      MSec -= (long)(val*3600000);
+      setTime(MSec);
+      break;
+    case DAYS:
+      MSec -= (long)(val*MSECS_IN_DAY);
+      setTime(MSec);
+      break;
+    case MONTHS:
+      splitTimeFormat();
+      month_ -= ival;
+      if(month_ <= 0) {
+	year_ -= (month_-1)/12 + 1;
+	month_ += ((month_-1)/12)*12 + 12;
+      }
+      if(month_ == 0) month_ = 12;
+      leap = (year_%4 != 0? 0: (year_%400 == 0? 1: (year_%100==0? 0: 1)));
+      max_day_[1] = 28 + leap;
+      day_ -= (int)(fract*max_day_[month_-1]);
+      if(day_ > max_day_[month_-1]) {
+	day_ -= max_day_[month_-1];
+	month_--;
+	if(month_ <= 0) {
+	  year_ -= (month_-1)/12 + 1;
+	  month_ += ((month_-1)/12)*12;
+	}
+	if(month_ == 0) month_ = 12;
+      }
+      try {
+	this.set(month_, day_, year_, hour_, minute_, second_, msec_);
+      } catch (IllegalTimeValue e) {
+	System.err.println(e);
+      }
+      break;
+    case YEARS:
+      splitTimeFormat();
+      year_ -= ival;
+      leap = (year_%4 != 0? 0: (year_%400 == 0? 1: (year_%100==0? 0: 1)));
+      max_day_[1] = 28 + leap;
+      if(day_ > max_day_[month_-1]) day_ = max_day_[month_-1];
+      try {
+	this.set(month_, day_, year_, hour_, minute_, second_, msec_);
+      } catch (IllegalTimeValue e) {
+	System.err.println(e);
+      }
+      setTime(getTime() - (long)(fract*365.25)*MSECS_IN_DAY);
+      break;
+    }
+    splitDone_ = false;
+    EPICTimeDone_ = false;
+    return this;
+  }
+  /**
+   * Time offset from reference <code>GeoDate</code>
+   *
+   * @param ref reference <code>GeoDate</code>
+   * @return offset in days
+   */
+  public double offset(GeoDate ref) {
+    double val;
+    val = ((double)(this.getTime() - ref.getTime()))/86400000.0;
+    return val;
+  }
+  /**
+   * Set a <code>GeoDate</code> from year and year-day.
+   *
+   * @param year year
+   * @param yearday year-day number (Jan 1 = 1)
+   * parameters that does not constitute a legitimate time value.
+   */
+  public void setYearYearDay(int year,int yearday) {
+    try {
+      this.set(1, 1, year, 0, 0, 0, 0);
+    } catch (IllegalTimeValue e) {
+      System.err.println(e);
+    }
+    setTime(getTime() + (yearday - 1)*MSECS_IN_DAY);
+  }
+  /**
+   * Get a reference to the <code>GregorianCalendar</code> set
+   * to the current <code>GeoDate</code> time.
+   *
+   * @return <code>Calendar</code>
+   */
+  public Calendar getCalendar() {
+    cal_.setTime(this);
+    return cal_;
+  }
+  /**
+   * Get year-day number (Jan 1 = 1)
+   */
+  public int getYearday() {
+    splitTimeFormat();
+    return yearday_;
+  }
+  /**
+   * Get year
+   *
+   * @deprecated Overrides a deprecated method, replaced by {@link #getGMTYear}.
+   */
+  public int getYear() {
+    splitTimeFormat();
+    return year_;
+  }
+  /**
+   * Get year.
+   */
+  public int getGMTYear() {
+    splitTimeFormat();
+    return year_;
+  }
+  /**
+   * Get month
+   *
+   * @deprecated Overrides a deprecated method, replaced by {@link #getGMTMonth}.
+   */
+  public int getMonth() {
+    splitTimeFormat();
+    return month_;
+  }
+  /**
+   * Get month
+   */
+  public int getGMTMonth() {
+    splitTimeFormat();
+    return month_;
+  }
+  /**
+   * Get day
+   *
+   * @deprecated Overrides a deprecated method, replaced by {@link #getGMTDay}.
+   */
+  public int getDay() {
+    splitTimeFormat();
+    return day_;
+  }
+  /**
+   * Get day
+   */
+  public int getGMTDay() {
+    splitTimeFormat();
+    return day_;
+  }
+  /**
+   * Get hours
+   *
+   * @deprecated Overrides a deprecated method, replaced by {@link #getGMTHours}.
+   */
+  public int getHours() {
+    splitTimeFormat();
+    return hour_;
+  }
+  /**
+   * Get hours
+   */
+  public int getGMTHours() {
+    splitTimeFormat();
+    return hour_;
+  }
+  /**
+   * Get minutes
+   *
+   * @deprecated Overrides a deprecated method, replaced by {@link #getGMTMinutes}.
+   */
+  public int getMinutes() {
+    splitTimeFormat();
+    return minute_;
+  }
+  /**
+   * Get minutes
+   */
+  public int getGMTMinutes() {
+    splitTimeFormat();
+    return minute_;
+  }
+  /**
+   * Get secondss
+   * @deprecated replaced by {@link #getGMTSeconds}.
+   */
+  public double getSecondss() {
+    splitTimeFormat();
+    return second_;
+  }
+  /**
+   * Get seconds and fraction of seconds.
+   */
+  public double getGMTSeconds() {
+    splitTimeFormat();
+    return second_;
+  }
+  /**
+   * get EPIC Julian Day
+   */
+  public int getJDay() {
+    splitTimeFormat();
+    computeEPICTime();
+    return JDay_;
+  }
+  /**
+   * get milliseconds since midnight
+   */
+  public int getMSec() {
+    splitTimeFormat();
+    computeEPICTime();
+    return MSec_;
+  }
+
+  private void computeEPICTime() {
+    if(EPICTimeDone_) return;
+    int GREGORIAN__ = (15+31*(10+12*1582));
+    int jy, jm, ja, jul;
+    int year = year_;
+    int mon = month_;
+    int day = day_;
+    int hour = hour_;
+    int min = minute_;
+    int sec = second_;
+    int msec = msec_;
+
+    int leap = (year%4 != 0? 0: (year%400 == 0? 1: (year%100==0? 0: 1)));
+
+    if(year < 0) ++year;
+    if(mon > 2) {
+      jy = year;
+      jm = mon + 1;
+    } else {
+      jy = year - 1;
+      jm = mon + 13;
+    }
+    jul = (int)(Math.floor(365.25*jy)+Math.floor(30.6001*jm)+day+1720995);
+    if(day + 31L*(mon+12L*year) >= GREGORIAN__) {
+      ja = (int)(0.01*jy);
+      jul += 2 - ja + (int)(0.25*ja);
+    }
+
+    JDay_ = jul;
+    MSec_ = (int)((hour*3600L+min*60L)*1000L+sec*1000L+msec);
+
+    EPICTimeDone_ = true;
+  }
+  /**
+   * Convert <code>GeoDate</code> to <code>String</code>
+   * using standard format "yyyy-MM-dd HH:mm:ss z"
+   * and "GMT" time zone.
+   *
+   * @return date
+   */
+  public String toString() {
+    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
+    df.setCalendar(cal_);
+    return df.format(this);
+  }
+  /**
+   * Convert <code>GeoDate</code> to <code>String</code>
+   * using provided format. The <code>SimpleDateFormat</code>
+   * and the <code>GregorianCalendar</code> is used to format
+   * the <code>GeoDate</code>. A format of "decade" will create
+   * a string of the form 1990 or 1980.
+   *
+   * @see SimpleDateFormat
+   *
+   * @param format String containing codes used to write time.
+   */
+  public String toString(String format) {
+    if(format.equals("decade")) {
+      splitTimeFormat();
+      return Integer.toString((year_/10)*10);
+    } else {
+      DateFormat df = new SimpleDateFormat(format);
+      df.setCalendar(cal_);
+      return df.format(this);
+    }
+  }
+  /**
+   * Tests to see if value represents missing data. A value from the
+   * getTime() method of <code>Long.MIN_VALUE</code> represents a
+   * missing observation.
+   *
+   * @see gov.noaa.pmel.sgt.dm.SGTData#getXRange()
+   */
+  public boolean isMissing() {
+    return getTime() == Long.MIN_VALUE;
+  }
+  /**
+   * Tests to see if the current GeoDate is less than, equal, or greater than.
+   * another GeoDate
+   */
+  public int compareTo(GeoDate anotherDate) {
+  	if (this.getTime() < anotherDate.getTime())
+  		return -1;
+  	else if (this.getTime() == anotherDate.getTime())
+  		return 0;
+  	else
+  		return 1;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeoDateArray.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeoDateArray.java
new file mode 100755
index 0000000..161b8e0
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeoDateArray.java
@@ -0,0 +1,171 @@
+/*
+ * $Id: GeoDateArray.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+import java.util.Date;
+import java.io.Serializable;
+
+/**
+ * <code>GeoDateArray</code> creates an efficient storage of
+ * <code>GeoDate</code> objects.  This is accomplished by using an
+ * internal storage of <code>long</code> for the number of
+ * milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 3.0
+ */
+public class GeoDateArray implements Serializable {
+  private long[] date_;
+
+  /**
+   * Construct a new <code>GeoDateArray</code> from an array of
+   * <code>GeoDate</code>s.
+   *
+   * @param dates an array of <code>GeoDate</code>s.
+   */
+  public GeoDateArray(GeoDate[] dates) {
+    date_ = new long[dates.length];
+    for(int i=0; i < dates.length; i++) {
+      if(!(dates[i] == null || dates[i].isMissing())) {
+        date_[i] = dates[i].getTime();
+      } else {
+        date_[i] = Long.MAX_VALUE;
+      }
+    }
+  }
+
+  /**
+   * Construct a new <code>GeoDateArray</code> from an array of
+   * <code>Date</code>s.
+   *
+   * @param dates an array of <code>Date</code>s.
+   */
+  public GeoDateArray(Date[] dates) {
+    date_ = new long[dates.length];
+    for(int i=0; i < dates.length; i++) {
+      if(!(dates[i] == null)) {
+        date_[i] = dates[i].getTime();
+      } else {
+        date_[i] = Long.MAX_VALUE;
+      }
+    }
+  }
+
+  /**
+   * Construct a new <code>GeoDateArray</code> from an array of
+   * <code>long</code>s that represent the number of
+   * milliseconds since January 1, 1970, 00:00:00 GMT.  Missing value
+   * for date is <code>Long.MAX_VALUE</code>.
+   *
+   * @param dates an array of <code>long</code>s.
+   */
+  public GeoDateArray(long[] dates) {
+    date_ = dates;
+  }
+
+  public long[] getTime() {
+    return date_;
+  }
+
+  public long getTime(int index) {
+    if(index < 0 || index >= date_.length) return Long.MAX_VALUE;
+    return date_[index];
+  }
+
+  public GeoDate getGeoDate(int index) {
+    if(index < 0 || index >= date_.length) return null;
+    return new GeoDate(date_[index]);
+  }
+
+  public GeoDate[] getGeoDate() {
+    GeoDate[] gd = new GeoDate[date_.length];
+    for(int i=0; i < date_.length; i++) {
+      gd[i] = new GeoDate(date_[i]);
+    }
+    return gd;
+  }
+  /**
+   * Time offset for reference <code>GeoDate</code>.
+   *
+   * @param ref reference <code>GeoDate</code>
+   * @return offset in days
+   */
+  public double getOffset(int index, GeoDate ref) {
+    if(index < 0 || index >= date_.length) return Double.NaN;
+    return ((double)(date_[index] - ref.getTime()))/86400000.0;
+  }
+
+  /**
+   * Time offset for reference <code>GeoDate</code>.
+   *
+   * @param ref reference <code>GeoDate</code>
+   * @return offset in days
+   */
+  public double[] getOffset(GeoDate ref) {
+    long refgd = ref.getTime();
+    double[] off = new double[date_.length];
+    for(int i=0; i < date_.length; i++) {
+      off[i] = ((double)(date_[i] - refgd))/86400000.0;
+    }
+    return off;
+  }
+  /**
+   * Time offset for reference <code>GeoDate</code>.
+   *
+   * @param ref reference <code>GeoDate</code>
+   * @return offset in milliseconds
+   */
+  public long getOffsetTime(int index, GeoDate ref) {
+    if(index < 0 || index >= date_.length) return Long.MAX_VALUE;
+    return date_[index] - ref.getTime();
+  }
+
+  /**
+   * Time offset for reference <code>GeoDate</code>.
+   *
+   * @param ref reference <code>GeoDate</code>
+   * @return offset in milliseconds
+   */
+  public long[] getOffsetTime(GeoDate ref) {
+    long refgd = ref.getTime();
+    long[] off = new long[date_.length];
+    for(int i=0; i < date_.length; i++) {
+      off[i] = date_[i] - refgd;
+    }
+    return off;
+  }
+  /**
+   * Add offset to all dates.
+   */
+  public void addOffset(long offset) {
+    for(int i=0; i < date_.length; i++) {
+      date_[i] += offset;
+    }
+  }
+   /**
+    * Add offset to single date.
+    */
+  public void addOffset(int index, long offset) {
+    if(index < 0 || index >= date_.length) return;
+    date_[index] += offset;
+  }
+  /**
+   * Get length of array.
+   */
+  public int getLength() {
+    return date_.length;
+  }
+}
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeographicValue.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeographicValue.java
new file mode 100755
index 0000000..aefd775
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/GeographicValue.java
@@ -0,0 +1,152 @@
+
+
+ package gov.noaa.pmel.util;
+
+/**
+* Base class used by LatitudeValue and LongitudeValue for translating between
+* a float and deg/min/sec.
+*/
+  public class GeographicValue {
+
+     protected int degrees;
+     protected int minutes;
+     protected int seconds;
+     protected int sign;
+     protected float decimalValue;
+     
+     // ---------------------------------------------
+     //
+     public GeographicValue( ) {
+        this.decimalValue = 0;
+        decimalToDegMinSec();
+     }
+
+     // ---------------------------------------------
+     //
+     public GeographicValue( float decVal ) {
+        this.decimalValue = decVal;
+        decimalToDegMinSec();
+     }
+
+     // ---------------------------------------------
+     //
+     public void decimalToDegMinSec() {
+        sign = 1;
+        if (decimalValue < 0) sign = -1;
+
+        float num1 = Math.abs( decimalValue );
+        degrees = (new Double( num1)).intValue();
+        float f1 = Math.abs( num1 - degrees);
+        float f2 = (f1 * 60);
+
+        float num2 = Math.abs( f2 );
+        minutes = new Double( Math.floor( (new Double(num2)).doubleValue() )).intValue();
+        float f3 = Math.abs( num2 - minutes);
+	double dd = f3 * 60;
+        seconds = new Long( Math.round( dd )).intValue();
+	if (seconds == 60) {
+	   seconds = 0;
+	   minutes++;
+	}
+	/*
+	System.out.println("======================================================");
+	System.out.println(" num1: " + num1 
+		+ " \n degrees: " + degrees 
+		+ " \n f1: " + f1
+		+ " \n f2: " + f2
+		+ " \n num2: " + num2
+		+ " \n minutes: " + minutes
+		+ " \n f3: " + f3
+		+ " \n dd: " + dd
+		+ " \n seconds: " + seconds);
+	System.out.println("");
+	*/
+     }
+
+
+     // ---------------------------------------------
+     //
+     public void degMinSecToDecimal() {
+        float minVal = minutes;
+        float degVal = degrees;
+        float secVal = seconds;
+	if (seconds == 0) secVal = 0.1f;
+        minVal += (secVal/60f);
+        degVal += (minVal/60f);
+	degVal = degVal * sign;
+ 	decimalValue = degVal;
+     }
+
+     // ---------------------------------------------
+     //
+     public void setDegrees( int degrees ) {
+        this.degrees = degrees;
+     }
+     // ---------------------------------------------
+     //
+     public void setMinutes( int minutes ) {
+        this.minutes = minutes;
+     }
+     // ---------------------------------------------
+     //
+     public void setSeconds( int seconds ) {
+        this.seconds = seconds;
+     }
+     // ---------------------------------------------
+     //
+     public void setSign( int sign ) {
+        this.sign = sign;
+     }
+     // ---------------------------------------------
+     //
+     public void setDecimalValue( float decimalValue ) {
+        this.decimalValue = decimalValue;
+	decimalToDegMinSec();
+     }
+
+     // ---------------------------------------------
+     //
+     public int getDegrees( ) {
+        return degrees;
+     }
+     // ---------------------------------------------
+     //
+     public int getMinutes( ) {
+        return minutes;
+     }
+     // ---------------------------------------------
+     //
+     public int getSeconds( ) {
+        return seconds;
+     }
+     // ---------------------------------------------
+     //
+     public int getSign( ) {
+        return sign;
+     }
+     // ---------------------------------------------
+     //
+     public float getDecimalValue( ) {
+        return decimalValue;
+     }
+     
+     // ---------------------------------------------
+     //
+     public String toString( ) {
+       StringBuffer str = new StringBuffer();
+       str.append( " ----------------------------: " 
+		+ " \n degrees: " + degrees 
+		+ " \n minutes: " + minutes
+		+ " \n seconds: " + seconds
+		+ " \n decimalValue: " + decimalValue);
+       return str.toString();
+     }
+
+     // ---------------------------------------------
+     //
+     public static void main( String args[] ) {
+        GeographicValue l1 = new GeographicValue( -154.7002716064453f);
+        System.out.println(" toString: " + l1.toString());
+     }
+  
+  }
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/IllegalTimeValue.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/IllegalTimeValue.java
new file mode 100755
index 0000000..3ba88f8
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/IllegalTimeValue.java
@@ -0,0 +1,29 @@
+/*
+ * $Id: IllegalTimeValue.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.util;
+
+/**
+ * The specified time was unreadable or illegal.
+ *
+ * @author Don Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ **/
+
+ public class IllegalTimeValue extends Exception {
+    public IllegalTimeValue() {
+        super();
+}
+    public IllegalTimeValue(String s) {
+        super(s);
+    }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/IndexedColorMap.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/IndexedColorMap.java
new file mode 100755
index 0000000..f0dff90
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/IndexedColorMap.java
@@ -0,0 +1,65 @@
+package gov.noaa.pmel.util;
+
+import java.util.*;
+import java.awt.*;
+
+
+public class IndexedColorMap {
+	String mParamName;
+	double mMinVal;
+	double mMaxVal;
+	double[] mVals = null;
+	Color[] mColors = null;
+	int mNumColors;
+	ColorMap mColorMap;
+	
+	public IndexedColorMap(ColorMap inCM, int numColors) {
+		mNumColors = numColors;
+		mColorMap = inCM;
+		mVals = new double[mNumColors];
+		mColors = new Color[mNumColors];
+		
+		// initialize the indexed colormap
+		mMinVal = mColorMap.getMinValue();
+		mMaxVal = mColorMap.getMaxValue();
+		mParamName = new String(mColorMap.getParamName());
+		
+		double delta = (mMaxVal - mMinVal)/(double)mNumColors;
+		
+		for (int i=0; i<mNumColors; i++) {
+			mVals[i] = mMinVal + (double)i * delta;
+		}
+		
+		mVals[mNumColors-1] = mMaxVal;
+		
+		for (int i=0; i<mNumColors; i++) {
+			mColors[i] = mColorMap.getColor(mVals[i]);
+		}
+	}
+	
+	public IndexedColorMap(IndexedColorMap inMap) {
+		// copy constructor
+	}
+	
+	// public methods
+	public Color getColor(double inVal) {
+		return new Color(1.0f, 1.0f, 1.0f);
+	}
+	
+	public Color getColor(int index) {
+		if (index < 0)
+			return mColors[0];
+		else if (index >= mNumColors)
+			return mColors[mNumColors-1];
+		else
+			return mColors[index];
+	}
+	
+	public Color[] getColors() {
+		return mColors;
+	}
+	
+	public String getParamName() {
+		return mParamName;
+	}
+}
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Latitude.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Latitude.java
new file mode 100755
index 0000000..a41cc49
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Latitude.java
@@ -0,0 +1,28 @@
+
+ package gov.noaa.pmel.util;
+
+/**
+* LatitudeValue translates between float and deg/min/sec.
+*/
+  public class Latitude extends GeographicValue {
+
+     // ---------------------------------------------
+     //
+     public Latitude( ) {
+        super();
+     }
+
+     // ---------------------------------------------
+     //
+     public Latitude( float latitude ) {
+        super( latitude );
+     }
+
+     // ---------------------------------------------
+     //
+     public static void main( String args[] ) {
+        Latitude l1 = new Latitude( -54.7002716064453f);
+        System.out.println(" toString: " + l1.toString());
+     }
+  
+  }
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/LinearTransform.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/LinearTransform.java
new file mode 100755
index 0000000..0f732da
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/LinearTransform.java
@@ -0,0 +1,168 @@
+/*
+ * $Id: LinearTransform.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package gov.noaa.pmel.util;
+
+import java.beans.PropertyChangeListener;
+import gov.noaa.pmel.util.Range2D;
+import gov.noaa.pmel.sgt.Transform;
+ 
+/**
+ * <code>LinearTransform</code> defines a liniear transformations between 
+ * user and physical coordinates defined between two end points.
+ *
+ * @see AxisTransform
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ */
+public class LinearTransform implements Transform {
+	Range2D mPhysRange = null;
+	Range2D mUserRange = null;
+	double mPUSlope, mPUYintercept;
+	double mUPSlope, mUPYintercept;
+
+	public LinearTransform(double p1, double p2, double u1, double u2) {
+		setRangeP(p1, p2);
+		setRangeU(u1, u2);
+		computeTransforms();
+	}
+
+	public LinearTransform(Range2D prange, Range2D urange) {
+		setRangeP(prange);
+		setRangeU(urange);
+		computeTransforms();
+	}
+
+	public LinearTransform() {
+	}
+	
+	/**
+	* Set physical coordinate range.
+	*
+	* @param p1 minimum value, physical coordinates
+	* @param p2 maximum value, physical coordinates
+	* @see LinearTransform
+	**/
+	public void setRangeP(double p1,double p2) {
+		mPhysRange = new Range2D(p1, p2);
+	}
+
+	/**
+	* Set physical coordinate range.
+	*
+	* @param prange physcial coordinate range
+	* @see Range2D
+	* @see LinearTransform
+	**/
+	public void setRangeP(Range2D prange) {
+		mPhysRange = null;
+		mPhysRange = new Range2D();
+		mPhysRange.add(prange);
+	}
+
+	/**
+	* Get the physical coordinate range.
+	*
+	* @return physcial coordinate range
+	* @see Range2D
+	**/
+	public Range2D getRangeP() {
+		return mPhysRange;
+	}
+
+	/**
+	* Set the user coordinate range for double values.
+	*
+	* @param u1 minimum value, user coordinates
+	* @param u2 maximum value, user coordinates
+	* @see LinearTransform
+	**/
+	public void setRangeU(double u1,double u2) {
+		mUserRange = new Range2D(u1, u2);
+	}
+
+	/**
+	* Set the user coordinate range for double values.
+	*
+	* @param urange user coordinate range
+	* @see Range2D
+	* @see LinearTransform
+	**/
+	public void setRangeU(Range2D urange) {
+		mUserRange = null;
+		mUserRange = new Range2D();
+		mUserRange.add(urange);
+		computeTransforms();
+	}
+
+	/**
+	* Get the user coordinate range for double values.
+	*
+	* @return user range
+	* @see Range2D
+	**/
+	public Range2D getRangeU() {
+		return mUserRange;
+	}
+
+	/**
+	* Transform from user to physical coordinates.
+	*
+	* @param u user value
+	* @return physical value
+	*/
+	public double getTransP(double u) {
+		return (mUPSlope * u) + mUPYintercept;
+	}
+
+	/**
+	* Transform from physical to user coordinates.
+	*
+	* @param p physical value
+	* @return user value
+	*/
+	public double getTransU(double p) {
+		return (mPUSlope *p) + mPUYintercept;
+	}
+
+	/**
+	* Add listener for changes to transform properties.
+	*/
+	public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+	}
+
+	public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+	}
+	
+	public void computeTransforms() {
+		computePULine();
+		computeUPLine();
+	}
+	
+	private void computePULine() {
+		double denom = mPhysRange.start - mPhysRange.end;
+		double num = mUserRange.start - mUserRange.end;
+		mPUSlope = num/denom;
+		mPUYintercept = mUserRange.start - (mPUSlope * mPhysRange.start);
+	}
+	
+	private void computeUPLine() {
+		double num = mPhysRange.start - mPhysRange.end;
+		double denom = mUserRange.start - mUserRange.end;
+		mUPSlope = num/denom;
+		mUPYintercept = mPhysRange.start - (mPUSlope * mUserRange.start);
+	}
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Longitude.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Longitude.java
new file mode 100755
index 0000000..370ed77
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Longitude.java
@@ -0,0 +1,29 @@
+
+ package gov.noaa.pmel.util;
+
+/**
+* LongitudeValue translates between float and deg/min/sec.
+*/
+  public class Longitude extends GeographicValue {
+
+     
+     // ---------------------------------------------
+     //
+     public Longitude( ) {
+	super();
+     }
+
+     // ---------------------------------------------
+     //
+     public Longitude( float longitude ) {
+        super( longitude );
+     }
+
+     // ---------------------------------------------
+     //
+     public static void main( String args[] ) {
+        Longitude l1 = new Longitude( -154.7002716064453f);
+        System.out.println(" toString: " + l1.toString());
+     }
+  
+  }
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Point2D.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Point2D.java
new file mode 100755
index 0000000..eb2b611
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Point2D.java
@@ -0,0 +1,139 @@
+/*
+ * $Id: Point2D.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+import java.io.Serializable;
+
+/**
+ * Point2D will be part of java.java2d.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 1.0
+ */
+public abstract class Point2D implements Serializable, Cloneable {
+  /**
+   * Inner class for <code>Point2D</code> for type
+   * <code>double</code>.
+   * @since sgt 1.0
+   */
+  public static class Double extends Point2D {
+    /** x coordinate */
+    public double x;
+    /** y coordinate */
+    public double y;
+    /**
+     * Default constructor
+     */
+    public Double() {
+    }
+    public Double(double x,double y) {
+      this.x = x;
+      this.y = y;
+    }
+    /**
+     * Test for equality.  Both x and y coordinates must be equal for
+     * equality.
+     */
+    public boolean equals(Point2D.Double pt) {
+      return (x == pt.x && y == pt.y) ;
+    }
+    /**
+     * @since sgt 3.0
+     */
+    public boolean equals(Object pt) {
+      if(pt instanceof Point2D.Double) {
+        Point2D.Double pt2 = (Point2D.Double)pt;
+        return (x == pt2.x) && (y == pt2.y);
+      } else {
+        return false;
+      }
+    }
+    public String toString() {
+      return new String("(" + x + ", " + y + ")");
+    }
+    /**
+     * Make a copy of the <code>Rectangle2D</code>.
+     * @since sgt 3.0
+     */
+    public Point2D copy() {
+      try {
+        return (Point2D)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+  }
+  /**
+   * Inner class for <code>Point2D</code> for type
+   * <code>float</code>.
+   * @since sgt 2.0
+   */
+  public static class Float extends Point2D {
+    /** x coordinate */
+    public float x;
+    /** y coordinate */
+    public float y;
+    /**
+     * Default constructor
+     */
+    public Float() {
+    }
+    public Float(float x,float y) {
+      this.x = x;
+      this.y = y;
+    }
+    /**
+     * Test for equality.  Both x and y coordinates must be equal for
+     * equality.
+     */
+    public boolean equals(Point2D.Float pt) {
+      return (x == pt.x && y == pt.y) ;
+    }
+    /**
+     * @since sgt 3.0
+     */
+    public boolean equals(Object pt) {
+      if(pt instanceof Point2D.Float) {
+        Point2D.Float pt2 = (Point2D.Float)pt;
+        return (x == pt2.x) && (y == pt2.y);
+      } else {
+        return false;
+      }
+    }
+    public String toString() {
+      return new String("(" + x + ", " + y + ")");
+    }
+    /**
+     * Make a copy of the <code>Rectangle2D</code>.
+     * @since sgt 3.0
+     */
+    public Point2D copy() {
+      try {
+        return (Point2D)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+  }
+  /**
+   * This is an abstract class that cannot be instantiated directly.
+   * Type-specific implementation subclasses are available for
+   * instantiation and provide a number of formats for storing
+   * the information necessary to satisfy the various accessor
+   * methods below.
+   *
+   */
+  protected Point2D() {
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Range.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Range.java
new file mode 100755
index 0000000..2b6f5f6
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Range.java
@@ -0,0 +1,50 @@
+/*
+ * $Id: Range.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+ 
+package  gov.noaa.pmel.util;
+ 
+/**
+ * Contains minimum and maximum integer values.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 1.0
+ */
+public class Range implements java.io.Serializable {
+  /** The range's first value */
+  public int start;
+  /** The range's last value */
+  public int end;
+  /**
+   * Default constructor
+   */
+  public Range() {
+    this(0, 0);
+  }
+  /**
+   * Initializes Range with start and end integral values.
+   *
+   * @param start first value
+   * @param end last value
+   */
+  public Range(int start,int end) {
+    this.start = start;
+    this.end = end;
+  }
+  /**
+   * Test <code>Range</code> for equality.  Both start and end must be
+   * equal for equality.
+   */
+  public boolean equals(Range r) {
+    return (start == r.start && end == r.end);
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Range2D.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Range2D.java
new file mode 100755
index 0000000..1f974b5
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Range2D.java
@@ -0,0 +1,107 @@
+/*
+ * $Id: Range2D.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.util;
+ 
+/**
+ * Contains minimum, maximum, and delta double values. 
+ *
+ * @author Donald Denbo
+ * @verstion $Revision: 1.1.1.1 $ $Date: 2007/09/07 06:32:05 $ 
+ * @since sgt 1.0
+ */
+public class Range2D implements java.io.Serializable, Cloneable {
+  /** The range's first value  */
+  public double start;
+  /** The range's last value  */
+  public double end;
+  /**  The value of the increment  */
+  public double delta;
+  /**
+   * Default constructor.
+   */
+  public Range2D() {
+    this(Double.NaN, Double.NaN, Double.NaN);
+  }
+  /**
+   * Construct Range2D with start and end. Default for
+   * delta is NaN
+   *
+   * @param ustart first value
+   * @param uend last value
+   */
+  public Range2D(double ustart,double uend) {
+    this(ustart, uend, Double.NaN);
+  }
+  /**
+   * Range2D constructor. 
+   *
+   * @param ustart first value
+   * @param uend last value
+   * @param udel increment value
+   */
+  public Range2D(double ustart,double uend,double udel) {
+    start = ustart;
+    end = uend;
+    delta = udel;
+  }
+  /**
+   * Adds the <code>Range2D</code> object to this
+   * <code>Range2D</code>. The resulting <code>Range2D</code> is
+   * the smallest <code>Range2D</code> that contains both the
+   * origial <code>Range2D</code> and the specified 
+   * <code>Range2D</code>.
+   */
+  public void add(Range2D range) {
+    start = Math.min(start, range.start);
+    end = Math.max(end, range.end);
+  }
+  /**
+   * Test for equality.  Both start, end, and delta must be equal for
+   * equality. 
+   */
+  public boolean equals(Range2D r) {
+    if(!Double.isNaN(start) && !Double.isNaN(r.start)) {
+      if(Double.isNaN(start) || Double.isNaN(r.start)) return false;
+      if(start != r.start) return false;
+    }
+    if(!Double.isNaN(end) && !Double.isNaN(r.end)) {
+      if(Double.isNaN(end) || Double.isNaN(r.end)) return false;
+      if(end != r.end) return false;
+    }
+    if(!Double.isNaN(delta) && !Double.isNaN(r.delta)) {
+      if(Double.isNaN(delta) || Double.isNaN(r.delta)) return false;
+      if(delta != r.delta) return false;
+    }
+    return true;
+  }
+  public String toString() {
+    StringBuffer buf = new StringBuffer(50);
+    buf.append("[").append(start).append(";").append(end);
+    if(Double.isNaN(delta)) {
+      buf.append("]");
+    } else {
+      buf.append(";").append(delta).append("]");
+    }
+    return buf.toString();
+  }
+  /**
+   * Create a copy of <code>Range2D</code> object.
+   */
+  public Range2D copy() {
+    try {
+      return (Range2D)clone();
+    } catch (CloneNotSupportedException e) {
+      return null;
+    }
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Rectangle2D.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Rectangle2D.java
new file mode 100755
index 0000000..0d96c24
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Rectangle2D.java
@@ -0,0 +1,279 @@
+/*
+ * $Id: Rectangle2D.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+import java.io.Serializable;
+
+/**
+ * Rectangle2D will be part of java.java2d
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 1.0
+ */
+public abstract class Rectangle2D implements Serializable, Cloneable {
+  /**
+   * Inner class that implements <code>Rectangle2D</code> for
+   * type <code>double</code>.
+   *
+   * @since sgt 1.0
+   */
+  public static class Double extends Rectangle2D {
+    /** height of rectangle */
+    public double height;
+    /** width of rectangle */
+    public double width;
+    /** x coordinate of rectangle */
+    public double x;
+    /** y coordinate of rectangle */
+    public double y;
+    /**
+     * Default constructor
+     */
+    public Double() {
+    }
+    public Double(double x,double y,double width,double height) {
+      this.x = x;
+      this.y = y;
+      this.width = width;
+      this.height = height;
+    }
+    public Double(double width,double height) {
+      this.width = width;
+      this.height = height;
+    }
+    public Double(Rectangle2D.Double r) {
+      x = r.x;
+      y = r.y;
+      width = r.width;
+      height = r.height;
+    }
+    /**
+     * Test for equality. Height, width, x, and y must be equal for
+     * equality.
+     */
+    public boolean equals(Rectangle2D.Double r) {
+      return !(x != r.x ||
+              y != r.y ||
+              width != r.width ||
+              height != r.height);
+    }
+    public boolean equals(Object r) {
+      if(r instanceof Rectangle2D.Double) {
+        Rectangle2D.Double r2 = (Rectangle2D.Double)r;
+        return !(x != r2.x ||
+                y != r2.y ||
+                width != r2.width ||
+                height != r2.height);
+      } else {
+        return false;
+      }
+    }
+    public String toString() {
+        String result;
+        result = "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
+        return result;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setWidth(double w) {
+      width = w;
+    }
+    /**
+     * @since 3.0
+     */
+    public double getWidth() {
+      return width;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setHeight(double h) {
+      height = h;
+    }
+    /**
+     * @since 3.0
+     */
+    public double getHeight() {
+      return height;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setX(double x) {
+      this.x = x;
+    }
+    /**
+     * @since 3.0
+     */
+    public double getX() {
+      return x;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setY(double y) {
+      this.y = y;
+    }
+    /**
+     * @since 3.0
+     */
+    public double getY() {
+      return y;
+    }
+    /**
+     * Make a copy of the <code>Rectangle2D</code>.
+     */
+    public Rectangle2D copy() {
+      try {
+        return (Rectangle2D)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+  }
+  /**
+   * Inner class that implements <code>Rectangle2D</code> for
+   * type <code>float</code>.
+   *
+   * @since sgt 1.0
+   */
+  public static class Float extends Rectangle2D {
+    /** height of rectangle */
+    public float height;
+    /** width of rectangle */
+    public float width;
+    /** x coordinate of rectangle */
+    public float x;
+    /** y coordinate of rectangle */
+    public float y;
+    /**
+     * Default constructor
+     */
+    public Float() {
+    }
+    public Float(float x,float y,float width,float height) {
+      this.x = x;
+      this.y = y;
+      this.width = width;
+      this.height = height;
+    }
+    public Float(float width,float height) {
+      this.width = width;
+      this.height = height;
+    }
+    public Float(Rectangle2D.Float r) {
+      x = r.x;
+      y = r.y;
+      width = r.width;
+      height = r.height;
+    }
+    /**
+     * Test for equality. Height, width, x, and y must be equal for
+     * equality.
+     */
+    public boolean equals(Rectangle2D.Float r) {
+      return !(x != r.x ||
+              y != r.y ||
+              width != r.width ||
+              height != r.height);
+    }
+    public boolean equals(Object r) {
+      if(r instanceof Rectangle2D.Float) {
+        Rectangle2D.Float r2 = (Rectangle2D.Float)r;
+        return !(x != r2.x ||
+                y != r2.y ||
+                width != r2.width ||
+                height != r2.height);
+      } else {
+        return false;
+      }
+    }
+    public String toString() {
+        String result;
+        result = "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
+        return result;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setWidth(float w) {
+      width = w;
+    }
+    /**
+     * @since 3.0
+     */
+    public float getWidth() {
+      return width;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setHeight(float h) {
+      height = h;
+    }
+    /**
+     * @since 3.0
+     */
+    public float getHeight() {
+      return height;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setX(float x) {
+      this.x = x;
+    }
+    /**
+     * @since 3.0
+     */
+    public float getX() {
+      return x;
+    }
+    /**
+     * @since 3.0
+     */
+    public void setY(float y) {
+      this.y = y;
+    }
+    /**
+     * @since 3.0
+     */
+    public float getY() {
+      return y;
+    }
+    /**
+     * Make a copy of the <code>Rectangle2D</code>.
+     */
+    public Rectangle2D copy() {
+      try {
+        return (Rectangle2D)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+  }
+  /**
+   * This is an abstract class that cannot be instantiated directly.
+   * Type-specific implementation subclasses are available for
+   * instantiation and provide a number of formats for storing
+   * the information necessary to satisfy the various accessor
+   * methods below.
+   *
+   */
+  protected Rectangle2D() { }
+  public abstract Rectangle2D copy();
+}
+
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SimpleFileFilter.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SimpleFileFilter.java
new file mode 100755
index 0000000..d130324
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SimpleFileFilter.java
@@ -0,0 +1,55 @@
+/*
+ * $Id: SimpleFileFilter.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ */
+package gov.noaa.pmel.util;
+
+import javax.swing.filechooser.*;
+import java.io.File;
+
+public class SimpleFileFilter extends FileFilter {
+  private String[] extensions;
+  private String description;
+  
+  public SimpleFileFilter(String ext) {
+    this(new String[] {ext}, null);
+  }
+  public SimpleFileFilter(String[] exts, String descr) {
+    extensions = new String[exts.length];
+    for(int i=exts.length -1; i >=0; i--) {
+      extensions[i]= exts[i].toLowerCase();
+    }
+    description = (descr ==null? exts[0] + " files" : descr);
+  }
+  
+  public boolean accept(File f) {
+    if(f.isDirectory()) {return true;}
+    String name = f.getName().toLowerCase();
+    for(int i=extensions.length-1; i>=0; i--) {
+      if(name.endsWith(extensions[i])) {
+	return true;
+      }
+    }
+    return false;
+  }
+  
+  public boolean hasExtension(String ext) {
+    for(int i=0; i < extensions.length; i++) {
+      if(extensions[i].equals(ext)) return true;
+    }
+    return false;
+  }
+  
+  public String getExtension() {
+    return getExtension(0);
+  }
+  
+  public String getExtension(int index) {
+    int idx = index;
+    if(idx < 0 || idx >= extensions.length) idx = 0;
+    return extensions[idx];
+  }
+  public String getDescription() {
+    return description;
+  }
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTDomain.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTDomain.java
new file mode 100755
index 0000000..638a4a1
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTDomain.java
@@ -0,0 +1,183 @@
+/*
+ * $Id: SoTDomain.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+package  gov.noaa.pmel.util;
+
+/**
+ * <code>SoTDomain</code> contains the X and Y ranges of a domain in
+ * user units.  These ranges are <code>SoTRange</code> objects which
+ * can be either Space or Time.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 2.0
+ */
+public class SoTDomain implements java.io.Serializable {
+  SoTRange xRange_ = null;
+  SoTRange yRange_ = null;
+  boolean xReversed_ = false;
+  boolean yReversed_ = false;
+  /**
+   * Default constructor.
+   */
+  public SoTDomain() {
+  }
+  /**
+   * Construct a <code>SoTDomain</code> from a <code>Domain</code>.
+   */
+  public SoTDomain(Domain domain) {
+    if(domain.isXTime()) {
+//      xRange_ = new SoTRange.GeoDate(domain.getTimeRange());
+      xRange_ = new SoTRange.Time(domain.getTimeRange());
+    } else {
+      xRange_ = new SoTRange.Double(domain.getXRange());
+    }
+    if(domain.isYTime()) {
+//      yRange_ = new SoTRange.GeoDate(domain.getTimeRange());
+      yRange_ = new SoTRange.Time(domain.getTimeRange());
+    } else {
+      yRange_ = new SoTRange.Double(domain.getYRange());
+    }
+    xReversed_ = domain.isXReversed();
+    yReversed_ = domain.isYReversed();
+  }
+  /**
+   * Constract a <code>SoTDomain</code> from a <code>SoTDomain</code>
+   */
+  public SoTDomain(SoTDomain domain) {
+    xRange_ = domain.getXRange();
+    yRange_ = domain.getYRange();
+    xReversed_ = domain.isXReversed();
+    yReversed_ = domain.isYReversed();
+  }
+  /**
+   * Construct a <code>SoTDomain</code> from <code>SoTRange</code>s.
+   */
+  public SoTDomain(SoTRange xRange, SoTRange yRange) {
+    xRange_ = xRange;
+    yRange_ = yRange;
+    xReversed_ = false;
+    yReversed_ = false;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public SoTDomain(SoTRange xRange, SoTRange yRange,
+                   boolean xRev, boolean yRev) {
+    xRange_ = xRange;
+    yRange_ = yRange;
+    xReversed_ = xRev;
+    yReversed_ = yRev;
+  }
+  /**
+   * Set the x range
+   */
+  public void setXRange(SoTRange xRange) {
+    xRange_ = xRange;
+  }
+  /**
+   * Get the x range
+   */
+  public SoTRange getXRange() {
+    return xRange_;
+  }
+  /**
+   * Set the y range
+   */
+  public void setYRange(SoTRange yRange) {
+    yRange_ = yRange;
+  }
+  /**
+   * Get the y range
+   */
+  public SoTRange getYRange() {
+    return yRange_;
+  }
+  /**
+   * Test if the x range is temporal.
+   */
+  public boolean isXTime() {
+    return xRange_.isTime();
+  }
+  /**
+   * Test if the y range is temporal
+   */
+  public boolean isYTime() {
+    return yRange_.isTime();
+  }
+  /**
+   * Get the center of the domain.
+   * @since sgt 3.0
+   */
+  public SoTPoint getCenter() {
+    SoTValue xVal = null;
+    SoTValue yVal = null;
+    if(isXTime()) {
+      xVal = new SoTValue.Time((xRange_.getStart().getLongTime()+
+                                xRange_.getEnd().getLongTime())/2);
+    } else {
+      xVal = new SoTValue.Double((((Number)xRange_.getStart().getObjectValue()).doubleValue() +
+                                  ((Number)xRange_.getEnd().getObjectValue()).doubleValue())/2.0);
+    }
+    if(isYTime()) {
+      yVal = new SoTValue.Time((yRange_.getStart().getLongTime()+
+                                yRange_.getEnd().getLongTime())/2);
+    } else {
+      yVal = new SoTValue.Double((((Number)yRange_.getStart().getObjectValue()).doubleValue() +
+                                  ((Number)yRange_.getEnd().getObjectValue()).doubleValue())/2.0);
+    }
+
+    return new SoTPoint(xVal, yVal);
+  }
+  /**
+   * Test for equality.  Both ranges must be equal for equality.
+   */
+  public boolean equals(SoTDomain d) {
+    if(!xRange_.equals(d.getXRange())) return false;
+    if(!yRange_.equals(d.getYRange())) return false;
+    if(xReversed_ != d.isXReversed()) return false;
+    if(yReversed_ != d.isYReversed()) return false;
+    return true;
+  }
+  public String toString() {
+    StringBuffer buf = new StringBuffer(100);
+    buf.append("x=");
+    buf.append(xRange_).append(",y=");
+    buf.append(yRange_);
+    buf.append(", xRev=").append(xReversed_);
+    buf.append(", yRev=").append(yReversed_);
+    return buf.toString();
+  }
+  /**
+  * @since sgt 3.0
+  */
+ public void setXReversed(boolean rev) {
+    xReversed_ = rev;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public boolean isXReversed() {
+    return xReversed_;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public void setYReversed(boolean rev) {
+    yReversed_ = rev;
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public boolean isYReversed() {
+    return yReversed_;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTPoint.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTPoint.java
new file mode 100755
index 0000000..0bfa261
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTPoint.java
@@ -0,0 +1,158 @@
+/*
+ * $Id: SoTPoint.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+import java.io.Serializable;
+
+/**
+ * <code>SoTPoint</code> has two coordinates which are of
+ * type <code>SoTValue</code>. SoT stands for
+ * space or time, but being basically lazy I've abbreviated it.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @sgt 2.0
+ */
+public class SoTPoint implements Serializable, Cloneable {
+  /** X coordinate  */
+  private SoTValue x_;
+  /** Y coordinate  */
+  private SoTValue y_;
+  /**
+   * Default constructor.
+   */
+  public SoTPoint() {
+  }
+  /**
+   * Construct a <code>SoTPoint</code> from <code>SoTValue</code>s.
+   *
+   * @param x space or time coordinate
+   * @param y space or time coordinate
+   */
+  public SoTPoint(SoTValue x, SoTValue y) {
+    x_ = x;
+    y_ = y;
+  }
+  /**
+   * Construct a <code>SoTPoint</code> from <code>double</code>s.
+   */
+  public SoTPoint(double x, double y) {
+    this(new SoTValue.Double(x), new SoTValue.Double(y));
+  }
+  /**
+   * Construct a <code>SoTPoint</code> from a <code>double</code> and
+   * a <code>GeoDate</code>.
+   */
+  public SoTPoint(double x, GeoDate y) {
+    this(new SoTValue.Double(x), new SoTValue.Time(y));
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public SoTPoint(double x, long y) {
+    this(new SoTValue.Double(x), new SoTValue.Time(y));
+  }
+  /**
+   * Construct a <code>SoTPoint</code> from a <code>GeoDate</code> and
+   * a <code>double</code>.
+   */
+  public SoTPoint(GeoDate x, double y) {
+    this(new SoTValue.Time(x), new SoTValue.Double(y));
+  }
+  /**
+   * @since sgt 3.0
+   */
+  public SoTPoint(long x, double y) {
+    this(new SoTValue.Time(x), new SoTValue.Double(y));
+  }
+  /**
+   * Construct a <code>SoTPoint</code> from a <code>SoTPoint</code>.
+   */
+  public SoTPoint(SoTPoint pt) {
+    this(pt.getX(), pt.getY());
+  }
+  /**
+   * Get x value
+   */
+  public SoTValue getX() {
+    return x_;
+  }
+  /**
+   * Set x value
+   * @since sgt 3.0
+   */
+  public void setX(SoTValue x) {
+    x_ = x;
+  }
+  /**
+   * Get y value
+   */
+  public SoTValue getY() {
+    return y_;
+  }
+  /**
+   * Set y value
+   * @since sgt 3.0
+   */
+  public void setY(SoTValue y) {
+    y_ = y;
+  }
+  /**
+   * Test for equality.  For equality both x and y values must be
+   * equal.
+   */
+  public boolean equals(SoTPoint stp) {
+    return (x_.equals(stp.getX()) &&
+            y_.equals(stp.getY()));
+  }
+  /**
+   * Test if x value is time
+   */
+  public boolean isXTime() {
+    return x_.isTime();
+  }
+  /**
+   * Test if y value is time
+   */
+  public boolean isYTime() {
+    return y_.isTime();
+  }
+  /**
+   * Add to point.
+   *
+   * @since sgt 3.0
+   */
+   public void add(SoTPoint point) {
+     x_.add(point.getX());
+     y_.add(point.getY());
+   }
+   /**
+    * Make a copy of the <code>SoTRange</code>.
+    * @since sgt 3.0
+    */
+   public SoTPoint copy() {
+     try {
+       return (SoTPoint)clone();
+     } catch (CloneNotSupportedException e) {
+       return null;
+     }
+   }
+  /**
+   * Convert <code>SoTPoint</code> to a default string
+   *
+   * @return string representation of the SoTPoint.
+   */
+  public String toString() {
+    return new String("(" + x_ + ", " + y_ + ")");
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTRange.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTRange.java
new file mode 100755
index 0000000..190a84b
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTRange.java
@@ -0,0 +1,1150 @@
+/*
+ * $Id: SoTRange.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package gov.noaa.pmel.util;
+
+/**
+ * <code>SoTRange</code> is an abstract class used to wrap either a
+ * <code>double</code> or <code>GeoDate</code>.  SoT stands for
+ * space or time, but being basically lazy I've abbreviated it.
+ * Contains minimum, maximum, and delta <code>SoTRange</code>.
+ * The <code>SoTRange</code> object represents the range of all
+ * missing data as <code>Double.NaN</code>
+ * as the start and end values for data of type <code>Double</code>
+ * and return <code>GeoDate(Long.MIN_VALUE)</code> for data of type
+ * <code>GeoDate</code>.
+ *
+ * @author Donald Denbo
+ * @verstion $Revision: 1.1.1.1 $ $Date: 2007/09/07 06:32:05 $
+ * @since sgt 2.0
+ * @see gov.noaa.pmel.sgt.dm.SGTData
+ */
+public abstract class SoTRange implements java.io.Serializable, Cloneable {
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>GeoDate</code>.
+   * @since sgt 2.0
+   * @deprecated As of sgt 3.0, replaced by {@link gov.noaa.pmel.util.SoTRange.Time SoTRange.Time}
+   */
+  public static class GeoDate extends SoTRange {
+    /** The range's first time  */
+    public gov.noaa.pmel.util.GeoDate start = null;
+    /** The range's last time  */
+    public gov.noaa.pmel.util.GeoDate end = null;
+    /** The range's time increment  */
+    public gov.noaa.pmel.util.GeoDate delta = null;
+    /**
+     * the Default constructor
+     */
+    public GeoDate() {
+    }
+    /**
+     * Constructor
+     *
+     * @param tstart first time
+     * @param tend last time
+     */
+    public GeoDate(gov.noaa.pmel.util.GeoDate tstart,
+       gov.noaa.pmel.util.GeoDate tend) {
+      this(tstart, tend, null);
+    }
+    /**
+     * Constructor
+     *
+     * @param tstart first time
+     * @param tend last time
+     * @param delta time increment
+     */
+    public GeoDate(gov.noaa.pmel.util.GeoDate tstart,
+       gov.noaa.pmel.util.GeoDate tend,
+       gov.noaa.pmel.util.GeoDate tdelta) {
+      this.start = tstart;
+      this.end = tend;
+      this.delta = tdelta;
+    }
+    /**
+     * @deprecated use SoTRange
+     */
+    public GeoDate(TimeRange trange) {
+      start = new gov.noaa.pmel.util.GeoDate(trange.start.getTime());
+      end = new gov.noaa.pmel.util.GeoDate(trange.end.getTime());
+      if(trange.delta != null) {
+        delta = new gov.noaa.pmel.util.GeoDate(trange.delta.getTime());
+      } else {
+        delta = null;
+      }
+    }
+    /**
+     * Get start value
+     */
+    public SoTValue getStart() {
+      return new SoTValue.GeoDate(start);
+    }
+    public void setStart(SoTValue value) {
+      start = ((SoTValue.GeoDate)value).getValue();
+    }
+    /**
+     * Get end value
+     */
+    public SoTValue getEnd() {
+      return new SoTValue.GeoDate(end);
+    }
+    public void setEnd(SoTValue value) {
+      end = ((SoTValue.GeoDate)value).getValue();
+    }
+    /**
+     * Get delta value
+     */
+    public SoTValue getDelta() {
+      return new SoTValue.GeoDate(delta);
+    }
+    public void setDelta(SoTValue value) {
+      delta = ((SoTValue.GeoDate)value).getValue();
+    }
+    public Object getStartObject() {
+      return start;
+    }
+    public Object getEndObject() {
+      return end;
+    }
+    public Object getDeltaObject() {
+      return delta;
+    }
+    /**
+     * Adds the <code>TimeRange</code> object to this
+     * <code>TimeRange</code>. The resulting <code>TimeRange</code> is
+     * the smallest <code>TimeRange</code> that contains both the
+     * origial <code>TimeRange</code> and the specified
+     * <code>TimeRange</code>.
+     */
+    public void add(SoTRange tr) {
+      if(!tr.isTime()) return;
+      SoTRange.GeoDate tRange = (SoTRange.GeoDate)tr;
+
+      if(tRange.start.before(start)) start = tRange.start;
+      if(tRange.end.after(end)) end = tRange.end;
+    }
+    /**
+     * Test for equality.  For equality start, end, and delta must all
+     * be equal.
+     */
+    public boolean equals(SoTRange tr) {
+      if(!tr.isTime()) return false;
+
+      SoTRange.GeoDate tRange = (SoTRange.GeoDate)tr;
+      if(start != null && tRange.start != null) {
+        if(!start.equals(tRange.start)) return false;
+      } else {
+        return false;
+      }
+      if(end != null && tRange.end != null) {
+        if(!end.equals(tRange.end)) return false;
+      } else {
+        return false;
+      }
+      if(delta != null && tRange.delta != null) {
+        if(!delta.equals(tRange.delta)) return false;
+      } else if(delta == null && tRange.delta == null){
+        return true;
+      } else {
+        return false;
+      }
+      return true;
+    }
+    /**
+     * Test if <code>SoTRange</code> is temporal.
+     */
+    public boolean isTime() {
+      return true;
+    }
+    /**
+     * Exchange start and end values
+     */
+    public void flipStartAndEnd() {
+      gov.noaa.pmel.util.GeoDate save = end;
+      end = start;
+      start = save;
+    }
+
+    public String toString() {
+      StringBuffer buf = new StringBuffer(50);
+      buf.append("[").append(start).append(";").append(end);
+      if(delta == null) {
+        buf.append("]");
+      } else {
+        buf.append(";").append(delta).append("]");
+      }
+      return buf.toString();
+    }
+    /**
+     * Make a copy of the <code>SoTRange</code>.
+     */
+    public SoTRange copy() {
+      gov.noaa.pmel.util.GeoDate cStart = null;
+      gov.noaa.pmel.util.GeoDate cEnd = null;
+      gov.noaa.pmel.util.GeoDate cDelta = null;
+      if(start != null)
+        cStart = new gov.noaa.pmel.util.GeoDate(start.getTime());
+      if(end != null)
+        cEnd = new gov.noaa.pmel.util.GeoDate(end.getTime());
+      if(delta != null)
+        cDelta = new gov.noaa.pmel.util.GeoDate(delta.getTime());
+
+      SoTRange.GeoDate cRange = new SoTRange.GeoDate(cStart, cEnd, cDelta);
+      return cRange;
+    }
+    /**
+     * Test if start or end is missing
+     */
+    public boolean isStartOrEndMissing() {
+      if((start == null) || (end == null)) return true;
+      if(start.isMissing() || end.isMissing()) return true;
+      return false;
+    }
+
+  }
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>long</code>.  Alternative method for storing
+   * time range.
+   * @since sgt 3.0
+   */
+  public static class Time extends SoTRange {
+    /** The range's first value  */
+    public long start;
+    /** The range's last value  */
+    public long end;
+    /** The value of the increment  */
+    public long delta;
+    /**
+     * Default constructor.
+     */
+    public Time() {
+      this(java.lang.Long.MAX_VALUE,
+           java.lang.Long.MAX_VALUE,
+           java.lang.Long.MAX_VALUE);
+    }
+    /**
+     * Construct <code>SoTRange</code> with start and end. Default for
+     * delta is MAX_VALUE
+     *
+     * @param ustart first value
+     * @param uend last value
+     */
+    public Time(long ustart, long uend) {
+      this(ustart, uend, java.lang.Long.MAX_VALUE);
+    }
+    public Time(gov.noaa.pmel.util.GeoDate ustart,
+                gov.noaa.pmel.util.GeoDate uend) {
+      this(ustart.getTime(), uend.getTime(), java.lang.Long.MAX_VALUE);
+    }
+    /**
+     * <code>SoTRange</code> constructor.
+     *
+     * @param ustart first value
+     * @param uend last value
+     * @param udel increment value
+     */
+    public Time(long ustart, long uend, long udel) {
+      start = ustart;
+      end = uend;
+      delta = udel;
+    }
+    public Time(gov.noaa.pmel.util.GeoDate ustart,
+                gov.noaa.pmel.util.GeoDate uend,
+                gov.noaa.pmel.util.GeoDate udel) {
+      this(ustart.getTime(), uend.getTime(), udel.getTime());
+    }
+    /**
+     * @deprecated use SoTRange
+     */
+    public Time(TimeRange trange) {
+      start = trange.start.getTime();
+      end = trange.end.getTime();
+      if(trange.delta != null) {
+        delta = trange.delta.getTime();
+      } else {
+        delta = java.lang.Long.MAX_VALUE;
+      }
+    }
+    /**
+     * @deprecated use SoTRange.Time
+     */
+    public Time(SoTRange.GeoDate trange) {
+      this(trange.start, trange.end, trange.delta);
+    }
+    public Time(SoTRange.Time trange) {
+      this(trange.start, trange.end, trange.delta);
+    }
+    /**
+     * Get start value
+     */
+    public SoTValue getStart() {
+      return new SoTValue.Time(start);
+    }
+    public void setStart(SoTValue value) {
+      start = ((SoTValue.Time)value).getValue();
+    }
+    /**
+     * Get end value
+     */
+    public SoTValue getEnd() {
+      return new SoTValue.Time(end);
+    }
+    public void setEnd(SoTValue value) {
+      end = ((SoTValue.Time)value).getValue();
+    }
+    /**
+     * Get delta value
+     */
+    public SoTValue getDelta() {
+      return new SoTValue.Time(delta);
+    }
+    public void setDelta(SoTValue value) {
+      delta = ((SoTValue.Time)value).getValue();
+    }
+    public Object getStartObject() {
+      return new java.lang.Long(start);
+    }
+    public Object getEndObject() {
+      return new java.lang.Long(end);
+    }
+    public Object getDeltaObject() {
+      return new java.lang.Long(delta);
+    }
+    /**
+     * Adds the <code>SoTRange</code> object to this
+     * <code>SoTRange</code>. The resulting <code>SoTRange</code> is
+     * the smallest <code>SoTRange</code> that contains both the
+     * origial <code>SoTRange</code> and the specified
+     * <code>SoTRange</code>.
+     */
+    public void add(SoTRange range) {
+      if(!range.isTime()) return;
+      if((start <= end) &&
+        ((SoTRange.Time)range).start <= ((SoTRange.Time)range).end) {
+        start = Math.min(start, ((SoTRange.Time)range).start);
+        end = Math.max(end, ((SoTRange.Time)range).end);
+      } else {
+        start = Math.max(start, ((SoTRange.Time)range).start);
+        end = Math.min(end, ((SoTRange.Time)range).end);
+      }
+    }
+    /**
+     * Test for equality.  For equality start, end, and delta must all
+     * be equal.
+     */
+    public boolean equals(SoTRange r) {
+      if(r.isTime()) return false;
+
+      long rstart = ((SoTRange.Time)r).start;
+      long rend = ((SoTRange.Time)r).end;
+      long rdelta = ((SoTRange.Time)r).delta;
+
+      if(!(start == java.lang.Long.MAX_VALUE) &&
+         !(rstart == java.lang.Long.MAX_VALUE)) {
+        if((start == java.lang.Long.MAX_VALUE) ||
+           (rstart == java.lang.Long.MAX_VALUE)) return false;
+        if(start != rstart) return false;
+      }
+      if(!(end == java.lang.Long.MAX_VALUE) &&
+         !(rend == java.lang.Long.MAX_VALUE)) {
+        if((end == java.lang.Long.MAX_VALUE) ||
+           (rend == java.lang.Long.MAX_VALUE)) return false;
+        if(end != rend) return false;
+      }
+      if(!(delta == java.lang.Long.MAX_VALUE) &&
+         !(rdelta == java.lang.Long.MAX_VALUE)) {
+        if((delta == java.lang.Long.MAX_VALUE) ||
+           (rdelta == java.lang.Long.MAX_VALUE)) return false;
+        if(delta != rdelta) return false;
+      }
+      return true;
+    }
+    /**
+     * Test if <code>SoTRange</code> is temportal
+     */
+    public boolean isTime() {
+      return true;
+    }
+    /**
+     * Exchange start and end values
+     */
+    public void flipStartAndEnd() {
+      long save = end;
+      end = start;
+      start = save;
+    }
+    public String toString() {
+      StringBuffer buf = new StringBuffer(50);
+      buf.append("[").append(start).append(";").append(end);
+      if(delta == java.lang.Long.MAX_VALUE) {
+        buf.append("]");
+      } else {
+        buf.append(";").append(delta).append("]");
+      }
+      return buf.toString();
+    }
+    /**
+     * Make a copy of the <code>SoTRange</code>.
+     */
+    public SoTRange copy() {
+      try {
+        return (SoTRange)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+    /**
+     * Test if start or end values are missing
+     */
+    public boolean isStartOrEndMissing() {
+      return (start == java.lang.Long.MAX_VALUE) ||
+        (end == java.lang.Long.MAX_VALUE);
+    }
+  }
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>integer</code>.
+   * @since sgt 2.0
+   */
+  public static class Integer extends SoTRange {
+    /** The range's first value  */
+    public int start;
+    /** The range's last value  */
+    public int end;
+    /** The value of the increment  */
+    public int delta;
+    /**
+     * Default constructor.
+     */
+    public Integer() {
+      this(java.lang.Integer.MAX_VALUE,
+           java.lang.Integer.MAX_VALUE,
+           java.lang.Integer.MAX_VALUE);
+    }
+    /**
+     * Construct <code>SoTRange</code> with start and end. Default for
+     * delta is MAX_VALUE
+     *
+     * @param ustart first value
+     * @param uend last value
+     */
+    public Integer(int ustart,int uend) {
+      this(ustart, uend, java.lang.Integer.MAX_VALUE);
+    }
+    /**
+     * <code>SoTRange</code> constructor.
+     *
+     * @param ustart first value
+     * @param uend last value
+     * @param udel increment value
+     */
+    public Integer(int ustart, int uend, int udel) {
+      start = ustart;
+      end = uend;
+      delta = udel;
+    }
+    /**
+     * Construct a <code>SoTRange</code> from a <code>Range</code>.
+     */
+    public Integer(Range range) {
+      start = range.start;
+      end = range.end;
+      delta = java.lang.Integer.MAX_VALUE;
+    }
+    /**
+     * Get start value
+     */
+    public SoTValue getStart() {
+      return new SoTValue.Integer(start);
+    }
+    public void setStart(SoTValue value) {
+      start = ((SoTValue.Integer)value).getValue();
+    }
+    /**
+     * Get end value
+     */
+    public SoTValue getEnd() {
+      return new SoTValue.Integer(end);
+    }
+    public void setEnd(SoTValue value) {
+      end = ((SoTValue.Integer)value).getValue();
+    }
+    /**
+     * Get delta value
+     */
+    public SoTValue getDelta() {
+      return new SoTValue.Integer(delta);
+    }
+    public void setDelta(SoTValue value) {
+      delta = ((SoTValue.Integer)value).getValue();
+    }
+    public Object getStartObject() {
+      return new java.lang.Integer(start);
+    }
+    public Object getEndObject() {
+      return new java.lang.Integer(end);
+    }
+    public Object getDeltaObject() {
+      return new java.lang.Integer(delta);
+    }
+    /**
+     * Adds the <code>SoTRange</code> object to this
+     * <code>SoTRange</code>. The resulting <code>SoTRange</code> is
+     * the smallest <code>SoTRange</code> that contains both the
+     * origial <code>SoTRange</code> and the specified
+     * <code>SoTRange</code>.
+     */
+    public void add(SoTRange range) {
+      if(range.isTime()) return;
+      if((start <= end) &&
+        ((SoTRange.Integer)range).start <= ((SoTRange.Integer)range).end) {
+        start = Math.min(start, ((SoTRange.Integer)range).start);
+        end = Math.max(end, ((SoTRange.Integer)range).end);
+      } else {
+        start = Math.max(start, ((SoTRange.Integer)range).start);
+        end = Math.min(end, ((SoTRange.Integer)range).end);
+      }
+    }
+    /**
+     * Test for equality.  For equality start, end, and delta must all
+     * be equal.
+     */
+    public boolean equals(SoTRange r) {
+      if(r.isTime()) return false;
+
+      int rstart = ((SoTRange.Integer)r).start;
+      int rend = ((SoTRange.Integer)r).end;
+      int rdelta = ((SoTRange.Integer)r).delta;
+
+      if(!(start == java.lang.Integer.MAX_VALUE) &&
+         !(rstart == java.lang.Integer.MAX_VALUE)) {
+        if((start == java.lang.Integer.MAX_VALUE) ||
+           (rstart == java.lang.Integer.MAX_VALUE)) return false;
+        if(start != rstart) return false;
+      }
+      if(!(end == java.lang.Integer.MAX_VALUE) &&
+         !(rend == java.lang.Integer.MAX_VALUE)) {
+        if((end == java.lang.Integer.MAX_VALUE) ||
+           (rend == java.lang.Integer.MAX_VALUE)) return false;
+        if(end != rend) return false;
+      }
+      if(!(delta == java.lang.Integer.MAX_VALUE) &&
+         !(rdelta == java.lang.Integer.MAX_VALUE)) {
+        if((delta == java.lang.Integer.MAX_VALUE) ||
+           (rdelta == java.lang.Integer.MAX_VALUE)) return false;
+        if(delta != rdelta) return false;
+      }
+      return true;
+    }
+    /**
+     * Test if <code>SoTRange</code> is temportal
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Exchange start and end values
+     */
+    public void flipStartAndEnd() {
+      int save = end;
+      end = start;
+      start = save;
+    }
+    public String toString() {
+      StringBuffer buf = new StringBuffer(50);
+      buf.append("[").append(start).append(";").append(end);
+      if(delta == java.lang.Integer.MAX_VALUE) {
+        buf.append("]");
+      } else {
+        buf.append(";").append(delta).append("]");
+      }
+      return buf.toString();
+    }
+    /**
+     * Make a copy of the <code>SoTRange</code>.
+     */
+    public SoTRange copy() {
+      try {
+        return (SoTRange)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+    /**
+     * Test if start or end values are missing
+     */
+    public boolean isStartOrEndMissing() {
+      return (start == java.lang.Integer.MAX_VALUE) ||
+        (end == java.lang.Integer.MAX_VALUE);
+    }
+  }
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>short</code>.
+   * @since sgt 2.0
+   */
+  public static class Short extends SoTRange {
+    /** The range's first value  */
+    public short start;
+    /** The range's last value  */
+    public short end;
+    /** The value of the increment  */
+    public short delta;
+    /**
+     * Default constructor.
+     */
+    public Short() {
+      this(java.lang.Short.MAX_VALUE,
+           java.lang.Short.MAX_VALUE,
+           java.lang.Short.MAX_VALUE);
+    }
+    /**
+     * Construct <code>SoTRange</code> with start and end. Default for
+     * delta is MAX_VALUE
+     *
+     * @param ustart first value
+     * @param uend last value
+     */
+    public Short(short ustart,short uend) {
+      this(ustart, uend, java.lang.Short.MAX_VALUE);
+    }
+    /**
+     * <code>SoTRange</code> constructor.
+     *
+     * @param ustart first value
+     * @param uend last value
+     * @param udel increment value
+     */
+    public Short(short ustart, short uend, short udel) {
+      start = ustart;
+      end = uend;
+      delta = udel;
+    }
+//      /**
+//       * Construct a <code>SoTRange</code> from a <code>Range2D</code>.
+//       */
+//      public Double(Range2D range) {
+//        start = range.start;
+//        end = range.end;
+//        delta = range.delta;
+//      }
+    /**
+     * Get start value
+     */
+    public SoTValue getStart() {
+      return new SoTValue.Short(start);
+    }
+    public void setStart(SoTValue value) {
+      start = ((SoTValue.Short)value).getValue();
+    }
+    /**
+     * Get end value
+     */
+    public SoTValue getEnd() {
+      return new SoTValue.Short(end);
+    }
+    public void setEnd(SoTValue value) {
+      end = ((SoTValue.Short)value).getValue();
+    }
+    /**
+     * Get delta value
+     */
+    public SoTValue getDelta() {
+      return new SoTValue.Short(delta);
+    }
+    public void setDelta(SoTValue value) {
+      delta = ((SoTValue.Short)value).getValue();
+    }
+    public Object getStartObject() {
+      return new java.lang.Short(start);
+    }
+    public Object getEndObject() {
+      return new java.lang.Short(end);
+    }
+    public Object getDeltaObject() {
+      return new java.lang.Short(delta);
+    }
+    /**
+     * Adds the <code>SoTRange</code> object to this
+     * <code>SoTRange</code>. The resulting <code>SoTRange</code> is
+     * the smallest <code>SoTRange</code> that contains both the
+     * origial <code>SoTRange</code> and the specified
+     * <code>SoTRange</code>.
+     */
+    public void add(SoTRange range) {
+      if(range.isTime()) return;
+      if((start <= end) &&
+        ((SoTRange.Short)range).start <= ((SoTRange.Short)range).end) {
+        start = (short)Math.min(start, ((SoTRange.Short)range).start);
+        end = (short)Math.max(end, ((SoTRange.Short)range).end);
+      } else {
+        start = (short)Math.max(start, ((SoTRange.Short)range).start);
+        end = (short)Math.min(end, ((SoTRange.Short)range).end);
+      }
+    }
+    /**
+     * Test for equality.  For equality start, end, and delta must all
+     * be equal.
+     */
+    public boolean equals(SoTRange r) {
+      if(r.isTime()) return false;
+
+      short rstart = ((SoTRange.Short)r).start;
+      short rend = ((SoTRange.Short)r).end;
+      short rdelta = ((SoTRange.Short)r).delta;
+
+      if(!(start == java.lang.Short.MAX_VALUE) &&
+         !(rstart == java.lang.Short.MAX_VALUE)) {
+        if((start == java.lang.Short.MAX_VALUE) ||
+           (rstart == java.lang.Short.MAX_VALUE)) return false;
+        if(start != rstart) return false;
+      }
+      if(!(end == java.lang.Short.MAX_VALUE) &&
+         !(rend == java.lang.Short.MAX_VALUE)) {
+        if((end == java.lang.Short.MAX_VALUE) ||
+           (rend == java.lang.Short.MAX_VALUE)) return false;
+        if(end != rend) return false;
+      }
+      if(!(delta == java.lang.Short.MAX_VALUE) &&
+         !(rdelta == java.lang.Short.MAX_VALUE)) {
+        if((delta == java.lang.Short.MAX_VALUE) ||
+           (rdelta == java.lang.Short.MAX_VALUE)) return false;
+        if(delta != rdelta) return false;
+      }
+      return true;
+    }
+    /**
+     * Test if <code>SoTRange</code> is temportal
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Exchange start and end values
+     */
+    public void flipStartAndEnd() {
+      short save = end;
+      end = start;
+      start = save;
+    }
+    public String toString() {
+      StringBuffer buf = new StringBuffer(50);
+      buf.append("[").append(start).append(";").append(end);
+      if(delta == java.lang.Short.MAX_VALUE) {
+        buf.append("]");
+      } else {
+        buf.append(";").append(delta).append("]");
+      }
+      return buf.toString();
+    }
+    /**
+     * Make a copy of the <code>SoTRange</code>.
+     */
+    public SoTRange copy() {
+      try {
+        return (SoTRange)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+    /**
+     * Test if start or end values are missing
+     */
+    public boolean isStartOrEndMissing() {
+      return (start == java.lang.Short.MAX_VALUE) ||
+        (end == java.lang.Short.MAX_VALUE);
+    }
+  }
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>flaot</code>.
+   * @since sgt 2.0
+   */
+  public static class Float extends SoTRange {
+    /** The range's first value  */
+    public float start;
+    /** The range's last value  */
+    public float end;
+    /** The value of the increment  */
+    public float delta;
+    /**
+     * Default constructor.
+     */
+    public Float() {
+      this(java.lang.Float.NaN,
+           java.lang.Float.NaN,
+           java.lang.Float.NaN);
+    }
+    /**
+     * Construct <code>SoTRange</code> with start and end. Default for
+     * delta is NaN
+     *
+     * @param ustart first value
+     * @param uend last value
+     */
+    public Float(float ustart,float uend) {
+      this(ustart, uend, java.lang.Float.NaN);
+    }
+    /**
+     * <code>SoTRange</code> constructor.
+     *
+     * @param ustart first value
+     * @param uend last value
+     * @param udel increment value
+     */
+    public Float(float ustart,float uend,float udel) {
+      start = ustart;
+      end = uend;
+      delta = udel;
+    }
+//      /**
+//       * Construct a <code>SoTRange</code> from a <code>Range2D</code>.
+//       */
+//      public Float(Range2D range) {
+//        start = range.start;
+//        end = range.end;
+//        delta = range.delta;
+//      }
+    /**
+     * Get start value
+     */
+    public SoTValue getStart() {
+      return new SoTValue.Float(start);
+    }
+    public void setStart(SoTValue value) {
+      start = ((SoTValue.Float)value).getValue();
+    }
+    /**
+     * Get end value
+     */
+    public SoTValue getEnd() {
+      return new SoTValue.Float(end);
+    }
+    public void setEnd(SoTValue value) {
+      end = ((SoTValue.Float)value).getValue();
+    }
+    /**
+     * Get delta value
+     */
+    public SoTValue getDelta() {
+      return new SoTValue.Float(delta);
+    }
+    public void setDelta(SoTValue value) {
+      delta = ((SoTValue.Float)value).getValue();
+    }
+    public Object getStartObject() {
+      return new java.lang.Float(start);
+    }
+    public Object getEndObject() {
+      return new java.lang.Float(end);
+    }
+    public Object getDeltaObject() {
+      return new java.lang.Float(delta);
+    }
+    /**
+     * Adds the <code>SoTRange</code> object to this
+     * <code>SoTRange</code>. The resulting <code>SoTRange</code> is
+     * the smallest <code>SoTRange</code> that contains both the
+     * origial <code>SoTRange</code> and the specified
+     * <code>SoTRange</code>.
+     */
+    public void add(SoTRange range) {
+      if(range.isTime()) return;
+      if((start <= end) &&
+        ((SoTRange.Float)range).start <= ((SoTRange.Float)range).end) {
+        start = Math.min(start, ((SoTRange.Float)range).start);
+        end = Math.max(end, ((SoTRange.Float)range).end);
+      } else {
+        start = Math.max(start, ((SoTRange.Float)range).start);
+        end = Math.min(end, ((SoTRange.Float)range).end);
+      }
+    }
+    /**
+     * Test for equality.  For equality start, end, and delta must all
+     * be equal.
+     */
+    public boolean equals(SoTRange r) {
+      if(r.isTime()) return false;
+
+      float rstart = ((SoTRange.Float)r).start;
+      float rend = ((SoTRange.Float)r).end;
+      float rdelta = ((SoTRange.Float)r).delta;
+
+      if(!java.lang.Float.isNaN(start) &&
+         !java.lang.Float.isNaN(rstart)) {
+        if(java.lang.Float.isNaN(start) ||
+           java.lang.Float.isNaN(rstart)) return false;
+        if(start != rstart) return false;
+      }
+      if(!java.lang.Float.isNaN(end) &&
+         !java.lang.Float.isNaN(rend)) {
+        if(java.lang.Float.isNaN(end) ||
+           java.lang.Float.isNaN(rend)) return false;
+        if(end != rend) return false;
+      }
+      if(!java.lang.Float.isNaN(delta) &&
+         !java.lang.Float.isNaN(rdelta)) {
+        if(java.lang.Float.isNaN(delta) ||
+           java.lang.Float.isNaN(rdelta)) return false;
+        if(delta != rdelta) return false;
+      }
+      return true;
+    }
+    /**
+     * Test if <code>SoTRange</code> is temportal
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Exchange start and end values
+     */
+    public void flipStartAndEnd() {
+      float save = end;
+      end = start;
+      start = save;
+    }
+    public String toString() {
+      StringBuffer buf = new StringBuffer(50);
+      buf.append("[").append(start).append(";").append(end);
+      if(java.lang.Float.isNaN(delta)) {
+        buf.append("]");
+      } else {
+        buf.append(";").append(delta).append("]");
+      }
+      return buf.toString();
+    }
+    /**
+     * Make a copy of the <code>SoTRange</code>.
+     */
+    public SoTRange copy() {
+      try {
+        return (SoTRange)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+    /**
+     * Test if start or end values are missing
+     */
+    public boolean isStartOrEndMissing() {
+      return java.lang.Float.isNaN(start) ||
+        java.lang.Float.isNaN(end);
+    }
+  }
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>double</code>.
+   * @since sgt 2.0
+   */
+  public static class Double extends SoTRange {
+    /** The range's first value  */
+    public double start;
+    /** The range's last value  */
+    public double end;
+    /** The value of the increment  */
+    public double delta;
+    /**
+     * Default constructor.
+     */
+    public Double() {
+      this(java.lang.Double.NaN,
+           java.lang.Double.NaN,
+           java.lang.Double.NaN);
+    }
+    /**
+     * Construct <code>SoTRange</code> with start and end. Default for
+     * delta is NaN
+     *
+     * @param ustart first value
+     * @param uend last value
+     */
+    public Double(double ustart,double uend) {
+      this(ustart, uend, java.lang.Double.NaN);
+    }
+    /**
+     * <code>SoTRange</code> constructor.
+     *
+     * @param ustart first value
+     * @param uend last value
+     * @param udel increment value
+     */
+    public Double(double ustart,double uend,double udel) {
+      start = ustart;
+      end = uend;
+      delta = udel;
+    }
+    /**
+     * Construct a <code>SoTRange</code> from a <code>Range2D</code>.
+     */
+    public Double(Range2D range) {
+      start = range.start;
+      end = range.end;
+      delta = range.delta;
+    }
+    /**
+     * Get start value
+     */
+    public SoTValue getStart() {
+      return new SoTValue.Double(start);
+    }
+    public void setStart(SoTValue value) {
+      start = ((SoTValue.Double)value).getValue();
+    }
+    /**
+     * Get end value
+     */
+    public SoTValue getEnd() {
+      return new SoTValue.Double(end);
+    }
+    public void setEnd(SoTValue value) {
+      end = ((SoTValue.Double)value).getValue();
+    }
+    /**
+     * Get delta value
+     */
+    public SoTValue getDelta() {
+      return new SoTValue.Double(delta);
+    }
+    public void setDelta(SoTValue value) {
+      delta = ((SoTValue.Double)value).getValue();
+    }
+    public Object getStartObject() {
+      return new java.lang.Double(start);
+    }
+    public Object getEndObject() {
+      return new java.lang.Double(end);
+    }
+    public Object getDeltaObject() {
+      return new java.lang.Double(delta);
+    }
+    /**
+     * Adds the <code>SoTRange</code> object to this
+     * <code>SoTRange</code>. The resulting <code>SoTRange</code> is
+     * the smallest <code>SoTRange</code> that contains both the
+     * origial <code>SoTRange</code> and the specified
+     * <code>SoTRange</code>.
+     */
+    public void add(SoTRange range) {
+      if(range.isTime()) return;
+      if((start <= end) &&
+        ((SoTRange.Double)range).start <= ((SoTRange.Double)range).end) {
+        start = Math.min(start, ((SoTRange.Double)range).start);
+        end = Math.max(end, ((SoTRange.Double)range).end);
+      } else {
+        start = Math.max(start, ((SoTRange.Double)range).start);
+        end = Math.min(end, ((SoTRange.Double)range).end);
+      }
+    }
+    /**
+     * Test for equality.  For equality start, end, and delta must all
+     * be equal.
+     */
+    public boolean equals(SoTRange r) {
+      if(r.isTime()) return false;
+
+      double rstart = ((SoTRange.Double)r).start;
+      double rend = ((SoTRange.Double)r).end;
+      double rdelta = ((SoTRange.Double)r).delta;
+
+      if(!java.lang.Double.isNaN(start) &&
+         !java.lang.Double.isNaN(rstart)) {
+        if(java.lang.Double.isNaN(start) ||
+           java.lang.Double.isNaN(rstart)) return false;
+        if(start != rstart) return false;
+      }
+      if(!java.lang.Double.isNaN(end) &&
+         !java.lang.Double.isNaN(rend)) {
+        if(java.lang.Double.isNaN(end) ||
+           java.lang.Double.isNaN(rend)) return false;
+        if(end != rend) return false;
+      }
+      if(!java.lang.Double.isNaN(delta) &&
+         !java.lang.Double.isNaN(rdelta)) {
+        if(java.lang.Double.isNaN(delta) ||
+           java.lang.Double.isNaN(rdelta)) return false;
+        if(delta != rdelta) return false;
+      }
+      return true;
+    }
+    /**
+     * Test if <code>SoTRange</code> is temportal
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Exchange start and end values
+     */
+    public void flipStartAndEnd() {
+      double save = end;
+      end = start;
+      start = save;
+    }
+    public String toString() {
+      StringBuffer buf = new StringBuffer(50);
+      buf.append("[").append(start).append(";").append(end);
+      if(java.lang.Double.isNaN(delta)) {
+        buf.append("]");
+      } else {
+        buf.append(";").append(delta).append("]");
+      }
+      return buf.toString();
+    }
+    /**
+     * Make a copy of the <code>SoTRange</code>.
+     */
+    public SoTRange copy() {
+      try {
+        return (SoTRange)clone();
+      } catch (CloneNotSupportedException e) {
+        return null;
+      }
+    }
+    /**
+     * Test if start or end values are missing
+     */
+    public boolean isStartOrEndMissing() {
+      return java.lang.Double.isNaN(start) ||
+        java.lang.Double.isNaN(end);
+    }
+  }
+
+  /**
+   * This is an abstract class that cannot be instantiated directly.
+   * Type-specific implementation subclasses are available for
+   * instantiation and provide a number of formats for storing
+   * the information necessary to satisfy the various accessor
+   * methods below.
+   *
+   */
+  protected SoTRange() {}
+
+  public abstract boolean isTime();
+  public abstract String toString();
+  public abstract boolean equals(SoTRange range);
+  public abstract void add(SoTRange range);
+  public abstract SoTValue getStart();
+  public abstract SoTValue getEnd();
+  public abstract SoTValue getDelta();
+  public abstract Object getStartObject();
+  public abstract Object getEndObject();
+  public abstract Object getDeltaObject();
+  public abstract void setStart(SoTValue value);
+  public abstract void setEnd(SoTValue value);
+  public abstract void setDelta(SoTValue value);
+  public abstract void flipStartAndEnd();
+  public abstract boolean isStartOrEndMissing();
+  public abstract SoTRange copy();
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTValue.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTValue.java
new file mode 100755
index 0000000..ae33073
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/SoTValue.java
@@ -0,0 +1,544 @@
+/*
+ * $Id: SoTValue.java,v 1.1.1.1 2007/09/07 06:32:05 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+import java.io.Serializable;
+
+/**
+ * <code>SoTValue</code> is an abstract class used to wrap either a
+ * <code>double</code> or <code>GeoDate</code>.  SoT stands for
+ * space or time, but being basically lazy I've abbreviated it.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:05 $
+ * @since sgt 2.0
+ */
+public abstract class SoTValue implements Serializable {
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>GeoDate</code>.
+   * @since sgt 2.0
+   * @deprecated As of sgt 3.0, replaced by {@link gov.noaa.pmel.util.SoTValue.Time SoTValue.Time}
+   */
+  public static class GeoDate extends SoTValue {
+    gov.noaa.pmel.util.GeoDate date_;
+    /**
+     * Default constructor.
+     */
+    public GeoDate() {}
+    /**
+     * Construct a <code>SoTValue</code> from a <code>GeoDate</code>.
+     */
+    public GeoDate(gov.noaa.pmel.util.GeoDate date) {
+      date_ = date;
+    }
+    /**
+     * Construct a <code>SoTValue</code> and initialize it to
+     * represent the specified number of milliseconds since the
+     * standard base time known as "the epoch", namely January 1,
+     * 1970, 00:00:00.
+     */
+    public GeoDate(long time) {
+      this(new gov.noaa.pmel.util.GeoDate(time));
+    }
+    /**
+     * Get the value
+     */
+    public gov.noaa.pmel.util.GeoDate getValue() {
+      return date_;
+    }
+    /**
+     * Set the value from a <code>GeoDate</code>
+     */
+    public void setValue(gov.noaa.pmel.util.GeoDate date) {
+      date_ = date;
+    }
+    /**
+     * Set the value from the number of milliseconds since the epoch.
+     */
+    public void setValue(long time) {
+      date_ = new gov.noaa.pmel.util.GeoDate(time);
+    }
+    public Object getObjectValue() {
+      return date_;
+    }
+    /**
+     * Test if <code>SoTValue</code> is time.
+     */
+    public boolean isTime() {
+      return true;
+    }
+    /**
+     * Test for equality
+     */
+    public boolean equals(SoTValue val) {
+      if(val.isTime()) {
+        return date_.equals(((SoTValue.GeoDate)val).getValue());
+      } else {
+        return false;
+      }
+    }
+    /**
+     * Add to value.
+     *
+     * @since 3.0
+     */
+    public void add(SoTValue val) {
+      if(!val.isTime()) return;
+      date_.add(((SoTValue.GeoDate)val).getValue());
+    }
+    /**
+     * Get time as <code>long</code> since 1970-01-01.
+     *
+     * @since 3.0
+     */
+    public long getLongTime() {
+      if(date_ == null) return Long.MAX_VALUE;
+      return date_.getTime();
+    }
+    /**
+     * Get time as <code>GeoDate</code>.
+     *
+     * @since 3.0
+     */
+    public gov.noaa.pmel.util.GeoDate getGeoDate() {
+      return new gov.noaa.pmel.util.GeoDate(date_);
+    }
+
+    public String toString() {
+      return date_.toString();
+    }
+  }
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>long</code>.  Used for time storage.
+   * @since sgt 3.0
+   */
+  public static class Time extends SoTValue {
+    long value_;
+    /**
+     * Default constructor.
+     */
+    public Time() {}
+    /**
+     * Construct and initialize value.
+     */
+    public Time(long value) {
+      value_ = value;
+    }
+    public Time(gov.noaa.pmel.util.GeoDate value) {
+      value_ = value.getTime();
+    }
+    /**
+     * Get the value
+     */
+    public long getValue() {
+      return value_;
+    }
+    /**
+     * Set the value
+     */
+    public void setValue(long value) {
+      value_ = value;
+    }
+    public Object getObjectValue() {
+      return new java.lang.Long(value_);
+    }
+    /**
+     * Test if <code>SoTValue</code> is time
+     */
+    public boolean isTime() {
+      return true;
+    }
+    /**
+     * Test for equality
+     */
+    public boolean equals(SoTValue val) {
+      if(val.isTime()) {
+        return value_ == ((SoTValue.Time)val).getValue();
+      } else {
+        return false;
+      }
+    }
+    /**
+     * Add to value.
+     *
+     * @since 3.0
+     */
+    public void add(SoTValue val) {
+      if(!val.isTime()) return;
+      long dval = val.getLongTime();
+      value_ += dval;
+    }
+    /**
+     * Get time as <code>long</code> since 1970-01-01.
+     *
+     * @since 3.0
+     */
+    public long getLongTime() {
+      return value_;
+    }
+    /**
+     * Get time as <code>GeoDate</code>.
+     *
+     * @since 3.0
+     */
+    public gov.noaa.pmel.util.GeoDate getGeoDate() {
+      return new gov.noaa.pmel.util.GeoDate(value_);
+    }
+
+    public String toString() {
+//      return java.lang.Long.toString(value_);
+      return getGeoDate().toString();
+    }
+  }
+
+
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>int</code>.
+   * @since sgt 2.0
+   */
+  public static class Integer extends SoTValue {
+    int value_;
+    /**
+     * Default constructor.
+     */
+    public Integer() {}
+    /**
+     * Construct and initialize value.
+     */
+    public Integer(int value) {
+      value_ = value;
+    }
+    /**
+     * Get the value
+     */
+    public int getValue() {
+      return value_;
+    }
+    /**
+     * Set the value
+     */
+    public void setValue(int value) {
+      value_ = value;
+    }
+    public Object getObjectValue() {
+      return new java.lang.Integer(value_);
+    }
+    /**
+     * Test if <code>SoTValue</code> is time
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Test for equality
+     */
+    public boolean equals(SoTValue val) {
+      if(val.isTime()) {
+        return false;
+      } else {
+        return value_ == ((SoTValue.Integer)val).getValue();
+      }
+    }
+    /**
+     * Add to value.
+     *
+     * @since 3.0
+     */
+    public void add(SoTValue val) {
+      if(val.isTime()) return;
+      int dval = ((Number)val.getObjectValue()).intValue();
+      value_ += dval;
+    }
+    /**
+     * Get time as <code>long</code> since 1970-01-01.
+     *
+     * @since 3.0
+     */
+    public long getLongTime() {
+      throw new Error("Method not appropriate for SoTValue.Int");
+    }
+    /**
+     * Get time as <code>GeoDate</code>.
+     *
+     * @since 3.0
+     */
+    public gov.noaa.pmel.util.GeoDate getGeoDate() {
+      throw new Error("Method not appropriate for SoTValue.Int");
+    }
+
+    public String toString() {
+      return java.lang.Integer.toString(value_);
+    }
+  }
+
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>short</code>.
+   * @since sgt 2.0
+   */
+  public static class Short extends SoTValue {
+    short value_;
+    /**
+     * Default constructor.
+     */
+    public Short() {}
+    /**
+     * Construct and initialize value.
+     */
+    public Short(short value) {
+      value_ = value;
+    }
+    /**
+     * Get the value
+     */
+    public short getValue() {
+      return value_;
+    }
+    /**
+     * Set the value
+     */
+    public void setValue(short value) {
+      value_ = value;
+    }
+    public Object getObjectValue() {
+      return new java.lang.Short(value_);
+    }
+    /**
+     * Test if <code>SoTValue</code> is time
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Test for equality
+     */
+    public boolean equals(SoTValue val) {
+      if(val.isTime()) {
+        return false;
+      } else {
+        return value_ == ((SoTValue.Short)val).getValue();
+      }
+    }
+    /**
+     * Add to value.
+     *
+     * @since 3.0
+     */
+    public void add(SoTValue val) {
+      if(val.isTime()) return;
+      short dval = ((Number)val.getObjectValue()).shortValue();
+      value_ += dval;
+    }
+    /**
+     * Get time as <code>long</code> since 1970-01-01.
+     *
+     * @since 3.0
+     */
+    public long getLongTime() {
+      throw new Error("Method not appropriate for SoTValue.Short");
+    }
+    /**
+     * Get time as <code>GeoDate</code>.
+     *
+     * @since 3.0
+     */
+    public gov.noaa.pmel.util.GeoDate getGeoDate() {
+      throw new Error("Method not appropriate for SoTValue.Short");
+    }
+
+    public String toString() {
+      return java.lang.Short.toString(value_);
+    }
+  }
+
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>float</code>.
+   * @since sgt 2.0
+   */
+  public static class Float extends SoTValue {
+    float value_;
+    /**
+     * Default constructor.
+     */
+    public Float() {}
+    /**
+     * Construct and initialize value.
+     */
+    public Float(float value) {
+      value_ = value;
+    }
+    /**
+     * Get the value
+     */
+    public float getValue() {
+      return value_;
+    }
+    /**
+     * Set the value
+     */
+    public void setValue(float value) {
+      value_ = value;
+    }
+    public Object getObjectValue() {
+      return new java.lang.Float(value_);
+    }
+    /**
+     * Test if <code>SoTValue</code> is time
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Test for equality
+     */
+    public boolean equals(SoTValue val) {
+      if(val.isTime()) {
+        return false;
+      } else {
+        return value_ == ((SoTValue.Float)val).getValue();
+      }
+    }
+    /**
+     * Add to value.
+     *
+     * @since 3.0
+     */
+    public void add(SoTValue val) {
+      if(val.isTime()) return;
+      float dval = ((Number)val.getObjectValue()).floatValue();
+      value_ += dval;
+    }
+    /**
+     * Get time as <code>long</code> since 1970-01-01.
+     *
+     * @since 3.0
+     */
+    public long getLongTime() {
+      throw new Error("Method not appropriate for SoTValue.Float");
+    }
+    /**
+     * Get time as <code>GeoDate</code>.
+     *
+     * @since 3.0
+     */
+    public gov.noaa.pmel.util.GeoDate getGeoDate() {
+      throw new Error("Method not appropriate for SoTValue.Float");
+    }
+
+    public String toString() {
+      return java.lang.Float.toString(value_);
+    }
+  }
+
+  /**
+   * Inner class for <code>SoTRange</code> for type
+   * <code>double</code>.
+   * @since sgt 2.0
+   */
+  public static class Double extends SoTValue {
+    double value_;
+    /**
+     * Default constructor.
+     */
+    public Double() {}
+    /**
+     * Construct and initialize value.
+     */
+    public Double(double value) {
+      value_ = value;
+    }
+    /**
+     * Get the value
+     */
+    public double getValue() {
+      return value_;
+    }
+    /**
+     * Set the value
+     */
+    public void setValue(double value) {
+      value_ = value;
+    }
+    public Object getObjectValue() {
+      return new java.lang.Double(value_);
+    }
+    /**
+     * Test if <code>SoTValue</code> is time
+     */
+    public boolean isTime() {
+      return false;
+    }
+    /**
+     * Test for equality
+     */
+    public boolean equals(SoTValue val) {
+      if(val.isTime()) {
+        return false;
+      } else {
+        return value_ == ((SoTValue.Double)val).getValue();
+      }
+    }
+    /**
+     * Add to value.
+     *
+     * @since 3.0
+     */
+    public void add(SoTValue val) {
+      if(val.isTime()) return;
+      double dval = ((Number)val.getObjectValue()).doubleValue();
+      value_ += dval;
+    }
+    /**
+     * Get time as <code>long</code> since 1970-01-01.
+     *
+     * @since 3.0
+     */
+    public long getLongTime() {
+      throw new Error("Method not appropriate for SoTValue.Double");
+    }
+    /**
+     * Get time as <code>GeoDate</code>.
+     *
+     * @since 3.0
+     */
+    public gov.noaa.pmel.util.GeoDate getGeoDate() {
+      throw new Error("Method not appropriate for SoTValue.Double");
+    }
+    public String toString() {
+      return java.lang.Double.toString(value_);
+    }
+  }
+
+  /**
+   * This is an abstract class that cannot be instantiated directly.
+   * Type-specific implementation subclasses are available for
+   * instantiation and provide a number of formats for storing
+   * the information necessary to satisfy the various accessor
+   * methods below.
+   *
+   */
+  protected SoTValue() {}
+
+  public abstract boolean isTime();
+  public abstract String toString();
+  public abstract boolean equals(SoTValue val);
+  public abstract Object getObjectValue();
+  public abstract long getLongTime();
+  public abstract gov.noaa.pmel.util.GeoDate getGeoDate();
+  public abstract void add(SoTValue val);
+}
+
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/TimePoint.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/TimePoint.java
new file mode 100755
index 0000000..0497d31
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/TimePoint.java
@@ -0,0 +1,62 @@
+/*
+ * $Id: TimePoint.java,v 1.1.1.1 2007/09/07 06:32:06 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+/**
+ * TimePoint allows specification of a time-space point.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:06 $
+ * @since sgt 1.0
+ *
+ * @deprecated As of sgt 3.0, replaced by {@link gov.noaa.pmel.util.SoTPoint SoTPoint}.
+ */
+public class TimePoint {
+  /** Space coordinate  */
+  public double x;
+  /** Time coordinate */
+  public GeoDate t;
+  /**
+   * Default constructor.
+   */
+  public TimePoint() {
+  }
+  /**
+   * Construct a TimePoint.
+   *
+   * @param x space coordinate
+   * @param t time coordinate
+   */
+  public TimePoint(double x,GeoDate t) {
+    this.x = x;
+    this.t = t;
+  }
+  /**
+   * Test for equality.  Both x and t must be equal for equality.
+   */
+  public boolean equals(TimePoint tp) {
+    if(t != null && tp.t != null) {
+      return (x == tp.x && t.equals(tp.t));
+    } else {
+      return false;
+    }
+  }
+  /**
+   * Convert TimePoint to a default string
+   *
+   * @return string representation of the TimePoint.
+   */
+  public String toString() {
+    return new String("(" + x + ", " + t.toString() + ")");
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/TimeRange.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/TimeRange.java
new file mode 100755
index 0000000..194400e
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/TimeRange.java
@@ -0,0 +1,106 @@
+/*
+ * $Id: TimeRange.java,v 1.1.1.1 2007/09/07 06:32:06 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+/**
+ * Contains minimum and maximum Time values.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:06 $
+ * @since sgt 1.0
+ *
+ * @deprecated As of sgt 3.0, use {@link gov.noaa.pmel.util.SoTRange.Time SoTRange.Time}
+ */
+public class TimeRange implements java.io.Serializable {
+  /** The range's first time  */
+  public GeoDate start;
+  /** The range's last time  */
+  public GeoDate end;
+  /** The range's time increment */
+  public GeoDate delta;
+  /**
+   * the Default constructor
+   */
+  public TimeRange() {
+  }
+  /**
+   * Constructor
+   *
+   * @param tstart first time
+   * @param tend last time
+   */
+  public TimeRange(GeoDate tstart,GeoDate tend) {
+    this(tstart, tend, null);
+  }
+  public TimeRange(long start, long end) {
+    this(new GeoDate(start), new GeoDate(end));
+  }
+  /**
+   * Constructor
+   *
+   * @param tstart first time
+   * @param tend last time
+   * @param delta time increment
+   */
+  public TimeRange(GeoDate tstart,GeoDate tend, GeoDate tdelta) {
+    this.start = tstart;
+    this.end = tend;
+    this.delta = tdelta;
+  }
+  public TimeRange(long start, long end, long delta) {
+    this(new GeoDate(start), new GeoDate(end), new GeoDate(delta));
+  }
+  /**
+   * Adds the <code>TimeRange</code> object to this
+   * <code>TimeRange</code>. The resulting <code>TimeRange</code> is
+   * the smallest <code>TimeRange</code> that contains both the
+   * origial <code>TimeRange</code> and the specified
+   * <code>TimeRange</code>.
+   */
+  public void add(TimeRange trange) {
+    if(trange.start.before(start)) start = trange.start;
+    if(trange.end.after(end)) end = trange.end;
+  }
+  /**
+   * Test for equality.  The start, end, and delta must all be equal
+   * for equality.
+   */
+  public boolean equals(TimeRange tr) {
+    if(start != null && tr.start != null) {
+      if(!start.equals(tr.start)) return false;
+    } else {
+      return false;
+    }
+    if(end != null && tr.end != null) {
+      if(!end.equals(tr.end)) return false;
+    } else {
+      return false;
+    }
+    if(delta != null && tr.delta != null) {
+      if(!delta.equals(tr.delta)) return false;
+    } else {
+      return false;
+    }
+    return true;
+  }
+  public String toString() {
+    StringBuffer buf = new StringBuffer(50);
+    buf.append("[").append(start).append(";").append(end);
+    if(delta == null) {
+      buf.append("]");
+    } else {
+      buf.append(";").append(delta).append("]");
+    }
+    return buf.toString();
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Units.java b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Units.java
new file mode 100755
index 0000000..6e5e1dc
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/Units.java
@@ -0,0 +1,786 @@
+/*
+ * $Id: Units.java,v 1.1.1.1 2007/09/07 06:32:06 koennecke Exp $
+ *
+ * This software is provided by NOAA for full, free and open release.  It is
+ * understood by the recipient/user that NOAA assumes no liability for any
+ * errors contained in the code.  Although this software is released without
+ * conditions or restrictions in its use, it is expected that appropriate
+ * credit be given to its author and to the National Oceanic and Atmospheric
+ * Administration should the software be included by the recipient as an
+ * element in other product development.
+ */
+
+package  gov.noaa.pmel.util;
+
+import gov.noaa.pmel.sgt.dm.SGTMetaData;
+import gov.noaa.pmel.sgt.dm.SGTData;
+import gov.noaa.pmel.sgt.dm.SGTLine;
+import gov.noaa.pmel.sgt.dm.SGTGrid;
+import gov.noaa.pmel.sgt.dm.SimpleLine;
+import gov.noaa.pmel.sgt.dm.SimpleGrid;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Units is a static class for converting the units of DependentVariables.
+ *
+ * @author Donald Denbo
+ * @version $Revision: 1.1.1.1 $, $Date: 2007/09/07 06:32:06 $
+ * @since sgt 1.0
+**/
+public class Units implements java.io.Serializable {
+  /** No base units selected  */
+  public static final int NONE = 0;
+  /** base units are temperature  */
+  public static final int TEMPERATURE = 1;
+  /** base units are velocity  */
+  public static final int VELOCITY = 2;
+  /** base units are distance  */
+  public static final int DISTANCE = 3;
+  /** check X MetaData for units  */
+  public static final int X_AXIS = 0;
+  /** check Y MetaData for units  */
+  public static final int Y_AXIS = 1;
+  /** check Z MetaData for units */
+  public static final int Z_AXIS = 2;
+  /**
+   * Return the base unit for the meta data.
+   *
+   * @return TEMPERATURE, VELOCITY, DISTANCE, or NONE
+   */
+  public static int getBaseUnit(SGTMetaData meta) {
+    if(Temperature.isBaseUnit(meta)) {
+      return TEMPERATURE;
+    } else if(Velocity.isBaseUnit(meta)) {
+      return VELOCITY;
+    } else if(Distance.isBaseUnit(meta)) {
+      return DISTANCE;
+    } else {
+      return NONE;
+    }
+  }
+  /**
+   * Convert data to common units.
+   *
+   * @param grid the data
+   * @param base the base units, TEMPERATURE, VELOCITY, DISTANCE, or NONE
+   * @param comp grid component, X_AXIS, Y_AXIS, or Z_AXIS
+   */
+  public static SGTData convertToBaseUnit(SGTData grid, int base, int comp) {
+    switch(base) {
+      case TEMPERATURE: return Temperature.convertToBaseUnit(grid, comp);
+      case VELOCITY: return Velocity.convertToBaseUnit(grid, comp);
+      case DISTANCE: return Distance.convertToBaseUnit(grid, comp);
+      default:
+      case NONE: return grid;
+    }
+  }
+}
+/**
+ * Supports temperature conversions.
+ */
+class Temperature implements java.io.Serializable {
+  //
+  // All conversions are to the default units of degC
+  //
+  // degC = scale*origUnits + offset
+  //
+  private static final String[] name =
+  {"C", "degC", "K", "degK", "F", "degF", "k", "deg_c", "deg_k"};
+  private static final double[] scale =
+  {1.0, 1.0, 1.0, 1.0, 5.0/9.0, 5.0/9.0, 1.0, 1.0, 1.0};
+  private static final double[] offset =
+  {0.0, 0.0, -273.15, -273.15, 32.0*5.0/9.0, 32.0*5.0/9.0, -273.15, 0.0, -273.15};
+  //
+  private static final String timeArrayName = "[Lgov.noaa.pmel.util.GeoDate";
+  private static final String doubleArrayName = "[D";
+  private static final String stringName = "java.lang.String";
+  /**
+   *
+   */
+  static SGTData convertToBaseUnit(SGTData grid, int comp) {
+    int unit, count;
+    boolean hand;
+    //    GeoVariable xDim, yDim, zDim;
+    //    TimeVariable tDim;
+    //    DependentVariable variable, new_variable;
+    //    VarDesc new_vardesc;
+    SGTData new_grid = null;
+    SGTMetaData meta, newMeta;
+    int projection;
+    
+    String units;
+    switch(comp) {
+    default:
+    case Units.X_AXIS:
+      meta = ((SGTLine)grid).getXMetaData();
+      break;
+    case Units.Y_AXIS:
+      meta = ((SGTLine)grid).getYMetaData();
+      break;
+    case Units.Z_AXIS:
+      meta = ((SGTGrid)grid).getZMetaData();
+    }
+    units = meta.getUnits();
+    //
+    // is it one of the changeable units?
+    //
+    for(unit = 0; unit < name.length; unit++) {
+      if(units.equals(name[unit])) break;
+    }
+    
+    if(unit >= name.length) return grid;
+    //
+    // is it already in the base units?
+    //
+    if(scale[unit] == 1.0 && offset[unit] == 0.0) return grid;
+    //
+    // convert the units
+    //
+    double values[], new_values[];
+    switch(comp) {
+    default:
+    case Units.X_AXIS:
+      values = ((SGTLine)grid).getXArray();
+      break;
+    case Units.Y_AXIS:
+      values = ((SGTLine)grid).getYArray();
+      break;
+    case Units.Z_AXIS:
+      values = ((SGTGrid)grid).getZArray();
+    }
+    new_values = new double[values.length];
+    
+    for(count=0; count < values.length; count++) {
+      new_values[count] = scale[unit]*values[count] + offset[unit];
+    }
+    //
+    // build the new dependent variable
+    //
+    newMeta = new SGTMetaData(meta.getName(), "degC", meta.isReversed(), meta.isModulo());
+    newMeta.setModuloValue(meta.getModuloValue());
+    newMeta.setModuloTime(meta.getModuloTime());
+
+    if(grid instanceof SGTLine) {
+      boolean simpleLine = grid instanceof SimpleLine;
+      if(simpleLine) {
+	new_grid = (SGTLine)grid.copy();
+      }
+      Class[] classArgs = new Class[3];
+      Object[] constructArgs = new Object[3];
+      Class gridClass = grid.getClass();
+      Constructor gridConstruct;
+      switch(comp) {
+      default:
+      case Units.X_AXIS:
+	if(simpleLine) {
+	  ((SimpleLine)new_grid).setXArray(new_values);
+	} else {
+	  if(((SGTLine)grid).isYTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(timeArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTLine)grid).getTimeArray();
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTLine)grid).getYArray();
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  }
+	  ((SimpleLine)new_grid).setYMetaData(((SGTLine)grid).getYMetaData());
+	}
+	((SimpleLine)new_grid).setXMetaData(newMeta);
+	break;
+      case Units.Y_AXIS:
+	if(simpleLine) {
+	  ((SimpleLine)new_grid).setYArray(new_values);
+	} else {
+	  if(((SGTLine)grid).isXTime()) {
+	    try {
+	      classArgs[0] = Class.forName(timeArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTLine)grid).getTimeArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTLine)grid).getXArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  }
+	  ((SimpleLine)new_grid).setXMetaData(((SGTLine)grid).getXMetaData());
+	}
+	((SimpleLine)new_grid).setYMetaData(newMeta);
+      }
+    } else if(grid instanceof SGTGrid) {
+      boolean simpleGrid = grid instanceof SimpleGrid;
+      if(simpleGrid) {
+	new_grid = (SGTGrid)grid.copy();
+      }
+      Class[] classArgs = new Class[4];
+      Object[] constructArgs = new Object[4];
+      Class gridClass = grid.getClass();
+      Constructor gridConstruct;
+      switch(comp) {
+      default:
+      case Units.X_AXIS:
+	if(simpleGrid) {
+	  ((SimpleGrid)new_grid).setXArray(new_values);
+	} else {
+	  if(((SGTGrid)grid).isYTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(timeArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getYArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  }
+	  ((SimpleGrid)new_grid).setYMetaData(((SGTGrid)grid).getYMetaData());
+	  ((SimpleGrid)new_grid).setZMetaData(((SGTGrid)grid).getZMetaData());
+	}
+	((SimpleGrid)new_grid).setXMetaData(newMeta);
+	break;
+      case Units.Y_AXIS:
+	if(simpleGrid) {
+	  ((SimpleGrid)new_grid).setYArray(new_values);
+	} else {
+	  if(((SGTGrid)grid).isXTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(timeArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = ((SGTGrid)grid).getXArray();
+	      constructArgs[2] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  }
+	  ((SimpleGrid)new_grid).setXMetaData(((SGTGrid)grid).getXMetaData());
+	  ((SimpleGrid)new_grid).setZMetaData(((SGTGrid)grid).getZMetaData());
+	}
+	((SimpleGrid)new_grid).setYMetaData(newMeta);
+	break;
+      case Units.Z_AXIS:
+	if(simpleGrid) {
+	  ((SimpleGrid)new_grid).setZArray(new_values);
+	} else {
+	  if(((SGTGrid)grid).isXTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(timeArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = ((SGTGrid)grid).getYArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  } else if(((SGTGrid)grid).isYTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(timeArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTGrid)grid).getXArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTGrid)grid).getXArray();
+	      constructArgs[2] = ((SGTGrid)grid).getYArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Temperature conversion: " + e);
+	    }
+	  }
+	  ((SimpleGrid)new_grid).setXMetaData(((SGTGrid)grid).getXMetaData());
+	  ((SimpleGrid)new_grid).setYMetaData(((SGTGrid)grid).getYMetaData());
+	}
+	((SimpleGrid)new_grid).setZMetaData(newMeta);
+      }
+    }
+    return new_grid;
+  }
+  
+  static boolean isBaseUnit(SGTMetaData meta) {
+    int count;
+    String units = meta.getUnits();
+    
+    for(count=0; count < name.length; count++) {
+      if(units.equals(name[count])) return true;
+    }
+    return false;
+  }
+}
+
+/**
+ * Supports distance conversions.
+ */
+class Distance implements java.io.Serializable {
+  static SGTData convertToBaseUnit(SGTData grid, int comp) {
+    return grid;
+  }
+  static boolean isBaseUnit(SGTMetaData meta) {
+    return false;
+  }
+}
+
+/**
+ * Supports velocity conversions.
+ */
+class Velocity implements java.io.Serializable {
+  //
+  // All conversions are to the default units of "m s-1"
+  //
+  // m s-1 = scale*origUnits + offset
+  //
+  private static final String[] name =
+  {"m s-1", "m/s", "cm s-1", "cm/s"};
+  private static final double[] scale =
+  {1.0, 1.0, 0.01, 0.01};
+  private static final double[] offset =
+  {0.0, 0.0, 0.0, 0.0};
+  //
+  private static final String timeArrayName = "[Lgov.noaa.pmel.util.GeoDate";
+  private static final String doubleArrayName = "[D";
+  private static final String stringName = "java.lang.String";
+  /**
+   *
+   */
+  static SGTData convertToBaseUnit(SGTData grid, int comp) {
+    int unit, count;
+    boolean hand;
+    //    GeoVariable xDim, yDim, zDim;
+    //    TimeVariable tDim;
+    //    DependentVariable variable, new_variable;
+    //    VarDesc new_vardesc;
+    SGTData new_grid = null;
+    SGTMetaData meta, newMeta;
+    int projection;
+    
+    String units;
+    switch(comp) {
+    default:
+    case Units.X_AXIS:
+      meta = ((SGTLine)grid).getXMetaData();
+      break;
+    case Units.Y_AXIS:
+      meta = ((SGTLine)grid).getYMetaData();
+      break;
+    case Units.Z_AXIS:
+      meta = ((SGTGrid)grid).getZMetaData();
+    }
+    units = meta.getUnits();
+    //
+    // is it one of the changeable units?
+    //
+    for(unit = 0; unit < name.length; unit++) {
+      if(units.equals(name[unit])) break;
+    }
+    
+    if(unit >= name.length) return grid;
+    //
+    // is it already in the base units?
+    //
+    if(scale[unit] == 1.0 && offset[unit] == 0.0) return grid;
+    //
+    // convert the units
+    //
+    double values[], new_values[];
+    switch(comp) {
+    default:
+    case Units.X_AXIS:
+      values = ((SGTLine)grid).getXArray();
+      break;
+    case Units.Y_AXIS:
+      values = ((SGTLine)grid).getYArray();
+      break;
+    case Units.Z_AXIS:
+      values = ((SGTGrid)grid).getZArray();
+    }
+    new_values = new double[values.length];
+    
+    for(count=0; count < values.length; count++) {
+      new_values[count] = scale[unit]*values[count] + offset[unit];
+    }
+    //
+    // build the new dependent variable
+    //
+    newMeta = new SGTMetaData(meta.getName(), 
+                              "m s-1", 
+                              meta.isReversed(), 
+                              meta.isModulo());
+    newMeta.setModuloValue(meta.getModuloValue());
+    newMeta.setModuloTime(meta.getModuloTime());
+
+    if(grid instanceof SGTLine) {
+      boolean simpleLine = grid instanceof SimpleLine;
+      if(simpleLine) {
+	new_grid = (SGTLine)grid.copy();
+      }
+      Class[] classArgs = new Class[3];
+      Object[] constructArgs = new Object[3];
+      Class gridClass = grid.getClass();
+      Constructor gridConstruct;
+      switch(comp) {
+      default:
+      case Units.X_AXIS:
+	if(simpleLine) {
+	  ((SimpleLine)new_grid).setXArray(new_values);
+	} else {
+	  if(((SGTLine)grid).isYTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(timeArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTLine)grid).getTimeArray();
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+	    //              new_grid = new SimpleLine(new_values, 
+	    //                                      ((SGTLine)grid).getTimeArray(), 
+	    //                                      ((SGTLine)grid).getTitle());
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTLine)grid).getYArray();
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+	    //              new_grid = new SimpleLine(new_values, 
+	    //                                      ((SGTLine)grid).getYArray(), 
+	    //                                      ((SGTLine)grid).getTitle());
+	  }
+	  ((SimpleLine)new_grid).setYMetaData(((SGTLine)grid).getYMetaData());
+	}
+	((SimpleLine)new_grid).setXMetaData(newMeta);
+	break;
+      case Units.Y_AXIS:
+	if(simpleLine) {
+	  ((SimpleLine)new_grid).setYArray(new_values);
+	} else {
+	  if(((SGTLine)grid).isXTime()) {
+	    try {
+	      classArgs[0] = Class.forName(timeArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTLine)grid).getTimeArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+	    //              new_grid = new SimpleLine(((SGTLine)grid).getTimeArray(),
+	    //                                        new_values,
+	    //                                        ((SGTLine)grid).getTitle());
+	  } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTLine)grid).getXArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTLine)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+	    //              new_grid = new SimpleLine(((SGTLine)grid).getXArray(),
+	    //                                        new_values,
+	    //                                        ((SGTLine)grid).getTitle());
+	  }
+	  ((SimpleLine)new_grid).setXMetaData(((SGTLine)grid).getXMetaData());
+	}
+	((SimpleLine)new_grid).setYMetaData(newMeta);
+      }
+    } else if(grid instanceof SGTGrid) {
+      boolean simpleGrid = grid instanceof SimpleGrid;
+      if(simpleGrid) {
+	new_grid = (SGTGrid)grid.copy();
+      }
+      Class[] classArgs = new Class[4];
+      Object[] constructArgs = new Object[4];
+      Class gridClass = grid.getClass();
+      Constructor gridConstruct;
+      switch(comp) {
+      default:
+      case Units.X_AXIS:
+	if(simpleGrid) {
+	  ((SimpleGrid)new_grid).setXArray(new_values);
+	} else {
+          if(((SGTGrid)grid).isYTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(timeArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(((SGTGrid)grid).getZArray(),
+//                                      new_values, 
+//                                      ((SGTGrid)grid).getTimeArray(), 
+//                                      ((SGTGrid)grid).getTitle());
+          } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getYArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(((SGTGrid)grid).getZArray(),
+//                                      new_values, 
+//                                      ((SGTGrid)grid).getYArray(), 
+//                                      ((SGTGrid)grid).getTitle());
+          }
+          ((SimpleGrid)new_grid).setYMetaData(((SGTGrid)grid).getYMetaData());
+          ((SimpleGrid)new_grid).setZMetaData(((SGTGrid)grid).getZMetaData());
+	}
+	((SimpleGrid)new_grid).setXMetaData(newMeta);
+	break;
+      case Units.Y_AXIS:
+	if(simpleGrid) {
+	  ((SimpleGrid)new_grid).setYArray(new_values);
+	} else {
+          if(((SGTGrid)grid).isXTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(timeArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(((SGTGrid)grid).getZArray(),
+//                                        ((SGTGrid)grid).getTimeArray(),
+//                                        new_values,
+//                                        ((SGTGrid)grid).getTitle());
+          } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = ((SGTGrid)grid).getZArray();
+	      constructArgs[1] = ((SGTGrid)grid).getXArray();
+	      constructArgs[2] = new_values;
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(((SGTGrid)grid).getZArray(),
+//                                        ((SGTGrid)grid).getXArray(),
+//                                        new_values,
+//                                        ((SGTGrid)grid).getTitle());
+          }
+          ((SimpleGrid)new_grid).setXMetaData(((SGTGrid)grid).getXMetaData());
+          ((SimpleGrid)new_grid).setZMetaData(((SGTGrid)grid).getZMetaData());
+	}
+	((SimpleGrid)new_grid).setYMetaData(newMeta);
+	break;
+      case Units.Z_AXIS:
+	if(simpleGrid) {
+	  ((SimpleGrid)new_grid).setZArray(new_values);
+	} else {
+          if(((SGTGrid)grid).isXTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(timeArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = ((SGTGrid)grid).getYArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(new_values,
+//                                        ((SGTGrid)grid).getTimeArray(),
+//                                        ((SGTGrid)grid).getYArray(),
+//                                        ((SGTGrid)grid).getTitle());
+          } else if(((SGTGrid)grid).isYTime()) {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(timeArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTGrid)grid).getXArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTimeArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(new_values,
+//                                        ((SGTGrid)grid).getXArray(),
+//                                        ((SGTGrid)grid).getTimeArray(),
+//                                        ((SGTGrid)grid).getTitle());
+          } else {
+	    try {
+	      classArgs[0] = Class.forName(doubleArrayName);
+	      classArgs[1] = Class.forName(doubleArrayName);
+	      classArgs[2] = Class.forName(doubleArrayName);
+	      classArgs[3] = Class.forName(stringName);
+	      gridConstruct = gridClass.getConstructor(classArgs);
+	      constructArgs[0] = new_values;
+	      constructArgs[1] = ((SGTGrid)grid).getXArray();
+	      constructArgs[2] = ((SGTGrid)grid).getYArray();
+	      constructArgs[2] = ((SGTGrid)grid).getTitle();
+	      new_grid = (SGTData)gridConstruct.newInstance(constructArgs);
+	    } catch (java.lang.Exception e) {
+	      System.out.println("Velocity conversion: " + e);
+	    }
+//              new_grid = new SimpleGrid(new_values,
+//                                        ((SGTGrid)grid).getXArray(),
+//                                        ((SGTGrid)grid).getYArray(),
+//                                        ((SGTGrid)grid).getTitle());
+          }
+          ((SimpleGrid)new_grid).setXMetaData(((SGTGrid)grid).getXMetaData());
+          ((SimpleGrid)new_grid).setYMetaData(((SGTGrid)grid).getYMetaData());
+	}
+	((SimpleGrid)new_grid).setZMetaData(newMeta);
+      }
+      
+    }
+    return new_grid;
+  }
+  static boolean isBaseUnit(SGTMetaData meta) {
+    int count;
+    String units = meta.getUnits();
+    
+    for(count=0; count < name.length; count++) {
+      if(units.equals(name[count])) return true;
+    }
+    return false;
+  }
+}
diff --git a/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/package.html b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/package.html
new file mode 100755
index 0000000..1b39912
--- /dev/null
+++ b/contrib/applications/nxplot/sgtgraphics/src/gov/noaa/pmel/util/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+Contains date and time facilities and miscellaneous utility classes.
+
+</BODY>
+
+</HTML>
\ No newline at end of file
diff --git a/contrib/applications/nxplot/sharedscientific/.classpath b/contrib/applications/nxplot/sharedscientific/.classpath
new file mode 100755
index 0000000..ad32c83
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/contrib/applications/nxplot/sharedscientific/.project b/contrib/applications/nxplot/sharedscientific/.project
new file mode 100755
index 0000000..31b8ae0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>sharedscientific</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/contrib/applications/nxplot/sharedscientific/.settings/org.eclipse.jdt.core.prefs b/contrib/applications/nxplot/sharedscientific/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 0000000..f17f926
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Mon Aug 31 16:27:10 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/contrib/applications/nxplot/sharedscientific/META-INF/MANIFEST.MF b/contrib/applications/nxplot/sharedscientific/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..e318a43
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Shared Scientific Toolbox
+Bundle-SymbolicName: sharedscientific
+Bundle-Version: 1.0.0
+Bundle-Vendor: http://hubris.ucsd.edu/shared/
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: shared.array
diff --git a/contrib/applications/nxplot/sharedscientific/bin/font/Vera.ttf b/contrib/applications/nxplot/sharedscientific/bin/font/Vera.ttf
new file mode 100755
index 0000000..58cd6b5
Binary files /dev/null and b/contrib/applications/nxplot/sharedscientific/bin/font/Vera.ttf differ
diff --git a/contrib/applications/nxplot/sharedscientific/bin/shared/log4j.xml b/contrib/applications/nxplot/sharedscientific/bin/shared/log4j.xml
new file mode 100755
index 0000000..c47d835
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/bin/shared/log4j.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "classpath://org/apache/log4j/xml/log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="target" value="System.out" />
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="[%c{1}] %p - %m%n" />
+        </layout>
+    </appender>
+
+    <root>
+        <priority value="debug" />
+        <appender-ref ref="stdout" />
+    </root>
+
+</log4j:configuration>
diff --git a/contrib/applications/nxplot/sharedscientific/bin/shared/project.properties b/contrib/applications/nxplot/sharedscientific/bin/shared/project.properties
new file mode 100755
index 0000000..29ceaa4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/bin/shared/project.properties
@@ -0,0 +1,3 @@
+### Properties with values specific to the SST. ###
+
+build.version   = 1.10
diff --git a/contrib/applications/nxplot/sharedscientific/build.properties b/contrib/applications/nxplot/sharedscientific/build.properties
new file mode 100755
index 0000000..34d2e4d
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/contrib/applications/nxplot/sharedscientific/src/font/Vera.ttf b/contrib/applications/nxplot/sharedscientific/src/font/Vera.ttf
new file mode 100755
index 0000000..58cd6b5
Binary files /dev/null and b/contrib/applications/nxplot/sharedscientific/src/font/Vera.ttf differ
diff --git a/contrib/applications/nxplot/sharedscientific/src/font/package-info.java b/contrib/applications/nxplot/sharedscientific/src/font/package-info.java
new file mode 100755
index 0000000..cf56485
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/font/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * The location, by convention, of fonts.
+ */
+package font;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/lib/package-info.java b/contrib/applications/nxplot/sharedscientific/src/lib/package-info.java
new file mode 100755
index 0000000..99a5c0e
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/lib/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * The location, by convention, of Jar and native libraries.
+ */
+package lib;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/Constants.java b/contrib/applications/nxplot/sharedscientific/src/shared/Constants.java
new file mode 100755
index 0000000..9295038
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/Constants.java
@@ -0,0 +1,65 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.Properties;
+
+/**
+ * Contains SST constant values.
+ * 
+ * @author Roy Liu
+ */
+public class Constants {
+
+    /**
+     * The major version of the software.
+     */
+    final public static int MAJOR_VERSION;
+
+    /**
+     * The minor version of the software.
+     */
+    final public static int MINOR_VERSION;
+
+    static {
+
+        Properties p = new Properties();
+
+        try {
+
+            p.load(Constants.class.getClassLoader().getResourceAsStream("shared/project.properties"));
+
+        } catch (IOException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        BigDecimal version = new BigDecimal(p.getProperty("build.version"));
+
+        int versionAsInt = version.movePointRight(2).intValue();
+
+        MAJOR_VERSION = versionAsInt / 100;
+        MINOR_VERSION = versionAsInt % 100;
+    }
+
+    // Dummy constructor.
+    Constants() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractArray.java
new file mode 100755
index 0000000..72f24ea
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractArray.java
@@ -0,0 +1,332 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.FFTService;
+import static shared.array.ArrayBase.FIELD_PRECISION;
+import static shared.array.ArrayBase.FIELD_WIDTH;
+import static shared.array.ArrayBase.formatEmptyArray;
+import static shared.array.ArrayBase.formatRescale;
+import static shared.array.ArrayBase.formatSlice;
+
+import java.util.Arrays;
+import java.util.Formatter;
+
+import shared.array.kernel.MappingOps;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * An abstract base class for multidimensional arrays of real and complex values.
+ * 
+ * @apiviz.uses shared.array.ArrayBase
+ * @param <T>
+ *            the base parameterization.
+ * @param <U>
+ *            the "up" parameterization representing the forwards FFT type.
+ * @param <D>
+ *            the "down" parameterization representing the backwards FFT type.
+ * @param <E>
+ *            the array element type.
+ * @author Roy Liu
+ */
+abstract public class AbstractArray<T extends AbstractArray<T, U, D, E>, U extends AbstractArray<U, ?, ?, ?>, D extends AbstractArray<D, ?, ?, ?>, E>
+        extends ProtoArray<T, double[], E> {
+
+    /**
+     * An extra bit of information to help {@link #rifft()} correctly size destination arrays.
+     */
+    final protected int parity;
+
+    /**
+     * A value for {@link #parity} indicating that this array was not the result of {@link #rfft()}.
+     */
+    final protected static int INVALID_PARITY = -1;
+
+    /**
+     * Default constructor.
+     */
+    protected AbstractArray(double[] values, int parity, IndexingOrder order, int[] dims, int[] strides) {
+        super(values, order, dims, strides);
+
+        this.parity = parity;
+    }
+
+    /**
+     * Creates an instance of the base type.
+     */
+    abstract protected T wrap(int parity, IndexingOrder order, int[] dims, int[] strides);
+
+    /**
+     * Creates an instance of the "up" type after a forwards FFT.
+     */
+    abstract protected U wrapUp(int parity, IndexingOrder order, int[] dims, int[] strides);
+
+    /**
+     * Creates an instance of the "down" type after a backwards FFT.
+     */
+    abstract protected D wrapDown(int parity, IndexingOrder order, int[] dims, int[] strides);
+
+    /**
+     * Gets the value at the given logical index.
+     */
+    public double get(int... s) {
+        return this.values[physical(s)];
+    }
+
+    /**
+     * Sets the value at the given logical index.
+     */
+    public void set(double value, int... s) {
+        this.values[physical(s)] = value;
+    }
+
+    @Override
+    public double[] values() {
+        return this.values;
+    }
+
+    @Override
+    protected T wrap(IndexingOrder order, int[] dims, int[] strides) {
+        return wrap(this.parity, order, dims, strides);
+    }
+
+    @Override
+    public String toString() {
+
+        double[] values = this.values;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int ndims = dims.length;
+        int nrows = (ndims == 1) ? 1 : size(ndims - 2);
+        int ncols = size(ndims - 1);
+        int sliceSize = nrows * ncols;
+
+        int exponent = (int) Math.log10(Arithmetic.max( //
+                Arithmetic.max(values), Math.abs(Arithmetic.min(values)), 1e-128));
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        String format = String.format("%%%d.%df", FIELD_WIDTH, FIELD_PRECISION);
+
+        values = formatRescale(f, exponent, values);
+
+        int[] indices = MappingOps.assignMappingIndices(Arithmetic.product(dims), //
+                dims, strides);
+
+        strides = IndexingOrder.FAR.strides(dims);
+
+        if (ndims <= 2) {
+
+            f.format("%n");
+
+            formatSlice(f, format, //
+                    values, indices, 0, nrows, ncols, false);
+
+            return f.toString();
+        }
+
+        for (int offset = 0, m = values.length; offset < m; offset += sliceSize) {
+
+            f.format("%n[slice (");
+
+            for (int i = 0, n = ndims - 2, offsetAcc = offset; i < n; offsetAcc %= strides[i], i++) {
+                f.format("%d, ", offsetAcc / strides[i]);
+            }
+
+            f.format(":, :)]%n");
+
+            formatSlice(f, format, //
+                    values, indices, offset, nrows, ncols, false);
+        }
+
+        return f.toString();
+    }
+
+    /**
+     * Infers dimensions from the backing array length if the number of declared dimensions is {@code 0}.
+     * 
+     * @param dims
+     *            the declared dimensions.
+     * @param len
+     *            the array length.
+     * @param isComplex
+     *            whether the array contains complex values.
+     * @return the inferred dimensions.
+     */
+    protected static int[] inferDimensions(int[] dims, int len, boolean isComplex) {
+        return (dims.length > 0) ? dims.clone() : (isComplex ? new int[] {
+                Control.checkEquals(len, (len >>> 1) << 1) >>> 1, 2 } : new int[] { len });
+    }
+
+    /**
+     * Computes the reduced FFT of this array.
+     */
+    protected U rfft() {
+
+        int[] newDims = rfftDimensions();
+
+        // Very important: Derive the original size from the parity.
+        U dst = wrapUp(this.dims[this.dims.length - 1] % 2, DEFAULT_ORDER, newDims, this.order.strides(newDims));
+
+        FFTService.rfft(this.dims, values(), dst.values());
+
+        return dst;
+    }
+
+    /**
+     * Computes the reduced IFFT of this array.
+     */
+    protected D rifft() {
+
+        int[] newDims = rifftDimensions();
+
+        D dst = wrapDown(INVALID_PARITY, DEFAULT_ORDER, newDims, this.order.strides(newDims));
+
+        FFTService.rifft(dst.dims, values(), dst.values());
+
+        return dst;
+    }
+
+    /**
+     * Computes the full FFT of this array.
+     */
+    protected T fft() {
+        return transform(+1);
+    }
+
+    /**
+     * Computes the full IFFT of this array.
+     */
+    protected T ifft() {
+        return transform(-1);
+    }
+
+    /**
+     * Gets the reduced FFT dimensions.
+     */
+    protected int[] rfftDimensions() {
+
+        int ndims = this.dims.length;
+        int lastDimSize = (this.dims[ndims - 1] / 2 + 1);
+
+        int[] dimsModified = Arrays.copyOf(this.dims, ndims + 1);
+        dimsModified[ndims - 1] = lastDimSize;
+        dimsModified[ndims] = 2;
+
+        return dimsModified;
+    }
+
+    /**
+     * Gets the reduced IFFT dimensions.
+     */
+    protected int[] rifftDimensions() {
+
+        Control.checkTrue(this.parity != INVALID_PARITY, //
+                "Array must have valid parity");
+
+        int ndims = this.dims.length;
+        int lastDimSize = (this.dims[ndims - 2] - 1) * 2 + this.parity;
+
+        int[] dimsModified = Arrays.copyOf(this.dims, ndims - 1);
+        dimsModified[ndims - 2] = lastDimSize;
+
+        return dimsModified;
+    }
+
+    /**
+     * Checks that this array has storage order {@link ArrayBase#DEFAULT_ORDER}.
+     */
+    protected void checkMatrixOrder() {
+        Control.checkTrue(this.order == DEFAULT_ORDER, //
+                "Array must have row major indexing");
+    }
+
+    /**
+     * Checks that this array's parity is {@link #INVALID_PARITY}.
+     */
+    protected void checkInvalidParity() {
+        Control.checkTrue(this.parity == INVALID_PARITY, //
+                "Array must have invalid parity");
+    }
+
+    /**
+     * Checks that two {@link AbstractArray}s have the same size and underlying {@link Array.IndexingOrder}.
+     * 
+     * @param b
+     *            the {@link AbstractArray} to compare to.
+     * @return the common {@link #parity} value.
+     */
+    protected int checkShape(T b) {
+
+        AbstractArray<?, ?, ?, ?> a = this;
+
+        final int parity = Control.checkEquals(a.parity, b.parity, //
+                "Parity mismatch");
+
+        Control.checkTrue(a.order == b.order, //
+                "Indexing orders do not match");
+
+        Control.checkTrue(Arrays.equals(a.dims, b.dims), //
+                "Dimensions do not match");
+
+        return parity;
+    }
+
+    /**
+     * Transforms this array in the forwards/backwards FFT direction.
+     * 
+     * @param direction
+     *            the FFT direction.
+     * @return the transformed array.
+     */
+    @SuppressWarnings("unchecked")
+    protected T transform(int direction) {
+
+        checkInvalidParity();
+
+        T a = (T) this;
+
+        T res = wrap(INVALID_PARITY, DEFAULT_ORDER, a.dims, a.strides);
+
+        switch (direction) {
+
+        case +1:
+            FFTService.fft(Arrays.copyOf(a.dims, a.dims.length - 1), a.values, res.values);
+            break;
+
+        case -1:
+            FFTService.ifft(Arrays.copyOf(a.dims, a.dims.length - 1), a.values, res.values);
+            break;
+
+        default:
+            throw new IllegalArgumentException("Direction not recognized");
+        }
+
+        return res;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractComplexArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractComplexArray.java
new file mode 100755
index 0000000..a4cd3df
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractComplexArray.java
@@ -0,0 +1,585 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.FIELD_PRECISION;
+import static shared.array.ArrayBase.FIELD_WIDTH;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.formatEmptyArray;
+import static shared.array.ArrayBase.formatRescale;
+import static shared.array.ArrayBase.formatSlice;
+
+import java.util.Arrays;
+import java.util.Formatter;
+
+import shared.array.kernel.ArrayKernel;
+import shared.array.kernel.MappingOps;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * An abstract base class for arrays of complex values.
+ * 
+ * @apiviz.owns shared.array.AbstractComplexArray.Complex
+ * @param <C>
+ *            the complex array type.
+ * @param <R>
+ *            the real array type.
+ * @author Roy Liu
+ */
+abstract public class AbstractComplexArray<C extends AbstractComplexArray<C, R>, R extends AbstractRealArray<R, C>>
+        extends AbstractArray<C, C, R, AbstractComplexArray.Complex> {
+
+    /**
+     * Default constructor.
+     */
+    protected AbstractComplexArray(double[] values, int parity, int[] dims, int[] strides) {
+        super(values, parity, DEFAULT_ORDER, dims, strides);
+    }
+
+    /**
+     * Shifts the entries of this array to the zero frequency component.
+     */
+    public C fftShift() {
+        return fftShift(+1);
+    }
+
+    /**
+     * Undoes the effects of {@link #fftShift()}.
+     */
+    public C ifftShift() {
+        return fftShift(-1);
+    }
+
+    /**
+     * Depending on the direction, performs an {@link #fftShift()} or {@link #ifftShift()} of this array.
+     * 
+     * @param direction
+     *            the shift direction.
+     * @return the shifted array.
+     */
+    protected C fftShift(int direction) {
+
+        checkInvalidParity();
+
+        int ndims = this.dims.length;
+        int[] shift = new int[ndims];
+
+        for (int i = 0, n = ndims - 1; i < n; i++) {
+            shift[i] = direction * (this.dims[i] / 2);
+        }
+
+        return shift(shift);
+    }
+
+    @Override
+    public String toString() {
+
+        double[] values = this.values;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int ndims = dims.length;
+        int nrows = (ndims == 2) ? 1 : size(ndims - 3);
+        int ncols = size(ndims - 2);
+        int sliceSize = nrows * ncols * 2;
+
+        int exponent = (int) Math.log10(Arithmetic.max( //
+                Arithmetic.max(values), Math.abs(Arithmetic.min(values)), 1e-128));
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        String format = String.format("%%%d.%df +%%%d.%dfi", //
+                FIELD_WIDTH, FIELD_PRECISION, FIELD_WIDTH, FIELD_PRECISION);
+
+        values = formatRescale(f, exponent, values);
+
+        int[] indices = MappingOps.assignMappingIndices(Arithmetic.product(dims), //
+                dims, strides);
+
+        strides = IndexingOrder.FAR.strides(dims);
+
+        if (ndims <= 3) {
+
+            f.format("%n");
+
+            formatSlice(f, format, //
+                    values, indices, 0, nrows, ncols, true);
+
+            return f.toString();
+        }
+
+        for (int offset = 0, m = values.length; offset < m; offset += sliceSize) {
+
+            f.format("%n[slice (");
+
+            for (int i = 0, n = ndims - 3, offsetAcc = offset; i < n; offsetAcc %= strides[i], i++) {
+                f.format("%d, ", offsetAcc / strides[i]);
+            }
+
+            f.format(":, :)]%n");
+
+            formatSlice(f, format, //
+                    values, indices, offset, nrows, ncols, true);
+        }
+
+        return f.toString();
+    }
+
+    @Override
+    protected C wrap(Complex value, IndexingOrder order, int[] dims, int[] strides) {
+        return wrap(order, dims, strides).uFill(value.re, value.im);
+    }
+
+    @Override
+    protected C wrapUp(int parity, IndexingOrder order, int[] dims, int[] strides) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int[] dimensions() {
+        return super.dimensions();
+    }
+
+    @Override
+    public int[] rifftDimensions() {
+        return super.rifftDimensions();
+    }
+
+    @Override
+    public R rifft() {
+        return super.rifft();
+    }
+
+    @Override
+    public C fft() {
+        return super.fft();
+    }
+
+    @Override
+    public C ifft() {
+        return super.ifft();
+    }
+
+    @Override
+    public C subarray(int... bounds) {
+
+        Control.checkTrue((bounds[bounds.length - 1] - bounds[bounds.length - 2]) == 2, //
+                "Invalid subarray bounds for complex-valued array");
+
+        return super.subarray(bounds);
+    }
+
+    @Override
+    public C tile(int... repetitions) {
+
+        Control.checkTrue(repetitions[repetitions.length - 1] == 1, //
+                "Invalid tile repetitions for complex-valued array");
+
+        return super.tile(repetitions);
+    }
+
+    @Override
+    public C transpose(int... permutation) {
+
+        Control.checkTrue(permutation[permutation.length - 1] == permutation.length - 1, //
+                "Invalid transpose permutation for complex-valued array");
+
+        return super.transpose(permutation);
+    }
+
+    @Override
+    public C reshape(int... dims) {
+
+        Control.checkTrue(dims[dims.length - 1] == 2, //
+                "Invalid reshape dimensions for complex-valued array");
+
+        return super.reshape(dims);
+    }
+
+    @Override
+    public C reverseOrder() {
+        throw new UnsupportedOperationException("Cannot reverse storage orders of complex-valued arrays");
+    }
+
+    public Class<Complex> getComponentType() {
+        return Complex.class;
+    }
+
+    /**
+     * Creates an {@link AbstractRealArray} from the complex magnitudes of this array's elements.
+     */
+    public R torAbs() {
+        return applyKernelComplexToRealOperation(ArrayKernel.CTOR_ABS);
+    }
+
+    /**
+     * Creates an {@link AbstractRealArray} from the real parts of this array's elements.
+     */
+    public R torRe() {
+        return applyKernelComplexToRealOperation(ArrayKernel.CTOR_RE);
+    }
+
+    /**
+     * Creates an {@link AbstractRealArray} from the imaginary parts of this array's elements.
+     */
+    public R torIm() {
+        return applyKernelComplexToRealOperation(ArrayKernel.CTOR_IM);
+    }
+
+    /**
+     * Computes the elementwise addition.
+     */
+    public C eAdd(C array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.CE_ADD);
+    }
+
+    /**
+     * Computes the elementwise subtraction.
+     */
+    public C eSub(C array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.CE_SUB);
+    }
+
+    /**
+     * Computes the elementwise multiplication.
+     */
+    public C eMul(C array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.CE_MUL);
+    }
+
+    /**
+     * Computes the elementwise division.
+     */
+    public C eDiv(C array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.CE_DIV);
+    }
+
+    /**
+     * Computes the left elementwise addition.
+     */
+    public C lAdd(C array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.CE_ADD);
+    }
+
+    /**
+     * Computes the left elementwise subtraction.
+     */
+    public C lSub(C array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.CE_SUB);
+    }
+
+    /**
+     * Computes the left elementwise multiplication.
+     */
+    public C lMul(C array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.CE_MUL);
+    }
+
+    /**
+     * Computes the left elementwise division.
+     */
+    public C lDiv(C array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.CE_DIV);
+    }
+
+    /**
+     * Mutatively exponentiates the elements to the base {@link Math#E}.
+     */
+    public C uExp() {
+        return applyKernelComplexUnaryOperation(Double.NaN, Double.NaN, ArrayKernel.CU_EXP);
+    }
+
+    /**
+     * Mutatively randomizes the elements.
+     */
+    public C uRnd(double aRe, double aIm) {
+        return applyKernelComplexUnaryOperation(aRe, aIm, ArrayKernel.CU_RND);
+    }
+
+    /**
+     * Mutatively takes the complex conjugates of the elements.
+     */
+    public C uConj() {
+        return applyKernelComplexUnaryOperation(Double.NaN, Double.NaN, ArrayKernel.CU_CONJ);
+    }
+
+    /**
+     * Mutatively takes the cosine of the elements.
+     */
+    public C uCos() {
+        return applyKernelComplexUnaryOperation(Double.NaN, Double.NaN, ArrayKernel.CU_COS);
+    }
+
+    /**
+     * Mutatively takes the sine of the elements.
+     */
+    public C uSin() {
+        return applyKernelComplexUnaryOperation(Double.NaN, Double.NaN, ArrayKernel.CU_SIN);
+    }
+
+    /**
+     * Mutatively adds the argument to the elements.
+     */
+    public C uAdd(double aRe, double aIm) {
+        return applyKernelComplexUnaryOperation(aRe, aIm, ArrayKernel.CU_ADD);
+    }
+
+    /**
+     * Mutatively multiplies the elements by the argument.
+     */
+    public C uMul(double aRe, double aIm) {
+        return applyKernelComplexUnaryOperation(aRe, aIm, ArrayKernel.CU_MUL);
+    }
+
+    /**
+     * Mutatively fills this array with the argument.
+     */
+    public C uFill(double aRe, double aIm) {
+        return applyKernelComplexUnaryOperation(aRe, aIm, ArrayKernel.CU_FILL);
+    }
+
+    /**
+     * Mutatively shuffles this array.
+     */
+    public C uShuffle() {
+        return applyKernelComplexUnaryOperation(Double.NaN, Double.NaN, ArrayKernel.CU_SHUFFLE);
+    }
+
+    /**
+     * Computes the sum over the elements.
+     */
+    public double[] aSum() {
+        return applyKernelComplexAccumulatorOperation(ArrayKernel.CA_SUM);
+    }
+
+    /**
+     * Computes the product over the elements.
+     */
+    public double[] aProd() {
+        return applyKernelComplexAccumulatorOperation(ArrayKernel.CA_PROD);
+    }
+
+    /**
+     * Computes the mean over the elements.
+     */
+    public double[] aMean() {
+
+        int len = values().length / 2;
+
+        double[] res = aSum();
+        res[0] /= len;
+        res[1] /= len;
+
+        return res;
+    }
+
+    /**
+     * Supports the a* series of operations.
+     */
+    protected double[] applyKernelComplexAccumulatorOperation(int type) {
+        return OpKernel.caOp(type, this.values);
+    }
+
+    /**
+     * Supports the tor* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected R applyKernelComplexToRealOperation(int type) {
+
+        checkInvalidParity();
+
+        C a = (C) this;
+
+        int[] newDims = Arrays.copyOf(a.dims, a.dims.length - 1);
+
+        R res = wrapDown(INVALID_PARITY, a.order, newDims, a.order.strides(newDims));
+
+        OpKernel.convert(type, a.values, true, res.values, false);
+
+        return res;
+    }
+
+    /**
+     * Supports the e* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected C applyKernelElementwiseOperation(C b, int type) {
+
+        int parity = checkShape(b);
+
+        C a = (C) this;
+
+        C res = wrap(parity, a.order, a.dims, a.strides);
+
+        OpKernel.eOp(type, a.values, b.values, res.values, true);
+
+        return res;
+    }
+
+    /**
+     * Supports the l* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected C applyKernelLeftElementwiseOperation(C b, int type) {
+
+        checkShape(b);
+
+        C a = (C) this;
+
+        OpKernel.eOp(type, a.values, b.values, a.values, false);
+
+        return a;
+    }
+
+    /**
+     * Supports the u* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected C applyKernelComplexUnaryOperation(double aRe, double aIm, int type) {
+
+        OpKernel.cuOp(type, aRe, aIm, this.values);
+
+        return (C) this;
+    }
+
+    /**
+     * A representation of complex numbers.
+     */
+    @SuppressWarnings("serial")
+    public static class Complex extends Number implements Comparable<Complex> {
+
+        /**
+         * The real part.
+         */
+        final public double re;
+
+        /**
+         * The imaginary part.
+         */
+        final public double im;
+
+        /**
+         * Default constructor.
+         * 
+         * @param re
+         *            the real part.
+         * @param im
+         *            the imaginary part.
+         */
+        public Complex(double re, double im) {
+
+            this.re = re;
+            this.im = im;
+        }
+
+        /**
+         * Calculates the complex magnitude.
+         * 
+         * @return the magnitude.
+         */
+        public double magnitude() {
+            return Math.sqrt(this.re * this.re + this.im * this.im);
+        }
+
+        /**
+         * Checks if the real and imaginary parts are equal.
+         */
+        @Override
+        public boolean equals(Object o) {
+
+            if (!(o instanceof Complex)) {
+                return false;
+            }
+
+            Complex c = (Complex) o;
+            return (this.re == c.re) && (this.im == c.im);
+        }
+
+        /**
+         * Fulfills the {@link Object#hashCode()} contract.
+         */
+        @Override
+        public int hashCode() {
+            return (int) (Double.doubleToRawLongBits(this.re) ^ Double.doubleToRawLongBits(this.im));
+        }
+
+        /**
+         * Does a comparison on the basis of magnitude.
+         */
+        public int compareTo(Complex b) {
+            return Double.compare(magnitude(), b.magnitude());
+        }
+
+        /**
+         * Gets the {@code double} value.
+         */
+        @Override
+        public double doubleValue() {
+            return magnitude();
+        }
+
+        /**
+         * Gets the {@code float} value.
+         */
+        @Override
+        public float floatValue() {
+            return new Double(magnitude()).floatValue();
+        }
+
+        /**
+         * Gets the {@code int} value.
+         */
+        @Override
+        public int intValue() {
+            return new Double(magnitude()).intValue();
+        }
+
+        /**
+         * Gets the {@code long} value.
+         */
+        @Override
+        public long longValue() {
+            return new Double(magnitude()).longValue();
+        }
+
+        /**
+         * Gets the {@code byte} value.
+         */
+        @Override
+        public byte byteValue() {
+            return new Double(magnitude()).byteValue();
+        }
+
+        /**
+         * Creates a human-readable representation of this number.
+         */
+        @Override
+        public String toString() {
+            return String.format("%f + %fi", this.re, this.im);
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractRealArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractRealArray.java
new file mode 100755
index 0000000..73da56c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/AbstractRealArray.java
@@ -0,0 +1,686 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.OpKernel;
+
+import java.util.Arrays;
+
+import shared.array.kernel.ArrayKernel;
+
+/**
+ * An abstract base class for arrays of real values.
+ * 
+ * @apiviz.has shared.array.AbstractRealArray.RealMap - - - argument
+ * @apiviz.has shared.array.AbstractRealArray.RealReduce - - - argument
+ * @param <R>
+ *            the real array type.
+ * @param <C>
+ *            the complex array type.
+ * @author Roy Liu
+ */
+abstract public class AbstractRealArray<R extends AbstractRealArray<R, C>, C extends AbstractComplexArray<C, R>>
+        extends AbstractArray<R, C, R, Double> {
+
+    /**
+     * Default constructor.
+     */
+    protected AbstractRealArray(double[] values, IndexingOrder order, int[] dims, int[] strides) {
+        super(values, INVALID_PARITY, order, dims, strides);
+    }
+
+    @Override
+    protected R wrap(Double value, IndexingOrder order, int[] dims, int[] strides) {
+        return wrap(order, dims, strides).uFill(value);
+    }
+
+    @Override
+    protected R wrapDown(int parity, IndexingOrder order, int[] dims, int[] strides) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public int[] dimensions() {
+        return super.dimensions();
+    }
+
+    @Override
+    public int[] rfftDimensions() {
+        return super.rfftDimensions();
+    }
+
+    @Override
+    public C rfft() {
+        return super.rfft();
+    }
+
+    public Class<Double> getComponentType() {
+        return Double.class;
+    }
+
+    /**
+     * Creates an {@link AbstractComplexArray} with the real parts set to this array's elements.
+     */
+    public C tocRe() {
+        return applyKernelRealToComplexOperation(ArrayKernel.RTOC_RE);
+    }
+
+    /**
+     * Creates an {@link AbstractComplexArray} with the imaginary parts set to this array's elements.
+     */
+    public C tocIm() {
+        return applyKernelRealToComplexOperation(ArrayKernel.RTOC_IM);
+    }
+
+    /**
+     * Mutatively exponentiates the elements to the base {@link Math#E}.
+     */
+    public R uExp() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_EXP);
+    }
+
+    /**
+     * Mutatively takes the cosine of the elements.
+     */
+    public R uCos() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_COS);
+    }
+
+    /**
+     * Mutatively takes the sine of the elements.
+     */
+    public R uSin() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_SIN);
+    }
+
+    /**
+     * Mutatively takes the arctangent of the elements.
+     */
+    public R uAtan() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_ATAN);
+    }
+
+    /**
+     * Mutatively randomizes the elements.
+     */
+    public R uRnd(double a) {
+        return applyKernelRealUnaryOperation(a, ArrayKernel.RU_RND);
+    }
+
+    /**
+     * Mutatively takes the natural logarithm of the elements.
+     */
+    public R uLog() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_LOG);
+    }
+
+    /**
+     * Mutatively takes the absolute value of the elements.
+     */
+    public R uAbs() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_ABS);
+    }
+
+    /**
+     * Mutatively takes the elements to the power of the argument.
+     */
+    public R uPow(double a) {
+        return applyKernelRealUnaryOperation(a, ArrayKernel.RU_POW);
+    }
+
+    /**
+     * Mutatively adds the argument to the elements.
+     */
+    public R uAdd(double a) {
+        return applyKernelRealUnaryOperation(a, ArrayKernel.RU_ADD);
+    }
+
+    /**
+     * Mutatively multiplies the elements by the argument.
+     */
+    public R uMul(double a) {
+        return applyKernelRealUnaryOperation(a, ArrayKernel.RU_MUL);
+    }
+
+    /**
+     * Mutatively takes the square root of the elements.
+     */
+    public R uSqrt() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_SQRT);
+    }
+
+    /**
+     * Mutatively squares the elements.
+     */
+    public R uSqr() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_SQR);
+    }
+
+    /**
+     * Mutatively takes the multiplicative inverse of the elements.
+     */
+    public R uInv(double a) {
+        return applyKernelRealUnaryOperation(a, ArrayKernel.RU_INV);
+    }
+
+    /**
+     * Mutatively fills this array with the argument.
+     */
+    public R uFill(double a) {
+        return applyKernelRealUnaryOperation(a, ArrayKernel.RU_FILL);
+    }
+
+    /**
+     * Mutatively shuffles this array.
+     */
+    public R uShuffle() {
+        return applyKernelRealUnaryOperation(Double.NaN, ArrayKernel.RU_SHUFFLE);
+    }
+
+    /**
+     * Computes the elementwise addition.
+     */
+    public R eAdd(R array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.RE_ADD);
+    }
+
+    /**
+     * Computes the elementwise subtraction.
+     */
+    public R eSub(R array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.RE_SUB);
+    }
+
+    /**
+     * Computes the elementwise multiplication.
+     */
+    public R eMul(R array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.RE_MUL);
+    }
+
+    /**
+     * Computes the elementwise division.
+     */
+    public R eDiv(R array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.RE_DIV);
+    }
+
+    /**
+     * Computes the elementwise maximum.
+     */
+    public R eMax(R array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.RE_MAX);
+    }
+
+    /**
+     * Computes the elementwise minimum.
+     */
+    public R eMin(R array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.RE_MIN);
+    }
+
+    /**
+     * Computes the left elementwise addition.
+     */
+    public R lAdd(R array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.RE_ADD);
+    }
+
+    /**
+     * Computes the left elementwise subtraction.
+     */
+    public R lSub(R array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.RE_SUB);
+    }
+
+    /**
+     * Computes the left elementwise multiplication.
+     */
+    public R lMul(R array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.RE_MUL);
+    }
+
+    /**
+     * Computes the left elementwise division.
+     */
+    public R lDiv(R array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.RE_DIV);
+    }
+
+    /**
+     * Computes the left elementwise maximum.
+     */
+    public R lMax(R array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.RE_MAX);
+    }
+
+    /**
+     * Computes the left elementwise minimum.
+     */
+    public R lMin(R array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.RE_MIN);
+    }
+
+    /**
+     * Computes the sum over the elements.
+     */
+    public double aSum() {
+        return applyKernelRealAccumulatorOperation(ArrayKernel.RA_SUM);
+    }
+
+    /**
+     * Computes the product over the elements.
+     */
+    public double aProd() {
+        return applyKernelRealAccumulatorOperation(ArrayKernel.RA_PROD);
+    }
+
+    /**
+     * Computes the maximum over the elements.
+     */
+    public double aMax() {
+        return applyKernelRealAccumulatorOperation(ArrayKernel.RA_MAX);
+    }
+
+    /**
+     * Computes the variance over the elements.
+     */
+    public double aVar() {
+        return applyKernelRealAccumulatorOperation(ArrayKernel.RA_VAR);
+    }
+
+    /**
+     * Computes the entropy over the elements.
+     */
+    public double aEnt() {
+        return applyKernelRealAccumulatorOperation(ArrayKernel.RA_ENT);
+    }
+
+    /**
+     * Computes the minimum over the elements.
+     */
+    public double aMin() {
+        return applyKernelRealAccumulatorOperation(ArrayKernel.RA_MIN);
+    }
+
+    /**
+     * Computes the mean over the elements.
+     */
+    public double aMean() {
+        return aSum() / values().length;
+    }
+
+    /**
+     * Computes the sum along the given dimensions.
+     */
+    public R rSum(int... selectedDims) {
+        return applyKernelRealReduceOperation(ArrayKernel.RR_SUM, selectedDims);
+    }
+
+    /**
+     * Computes the product along the given dimensions.
+     */
+    public R rProd(int... selectedDims) {
+        return applyKernelRealReduceOperation(ArrayKernel.RR_PROD, selectedDims);
+    }
+
+    /**
+     * Computes the maximum along the given dimensions.
+     */
+    public R rMax(int... selectedDims) {
+        return applyKernelRealReduceOperation(ArrayKernel.RR_MAX, selectedDims);
+    }
+
+    /**
+     * Computes the minimum along the given dimensions.
+     */
+    public R rMin(int... selectedDims) {
+        return applyKernelRealReduceOperation(ArrayKernel.RR_MIN, selectedDims);
+    }
+
+    /**
+     * Computes the mean along the given dimensions.
+     */
+    public R rMean(int... selectedDims) {
+
+        int acc = 1;
+
+        for (int dim : selectedDims) {
+            acc *= size(dim);
+        }
+
+        return rSum(selectedDims).uMul(1.0 / acc);
+    }
+
+    /**
+     * Computes the variance along the given dimensions.
+     */
+    public R rVar(int... selectedDims) {
+        return applyKernelRealReduceOperation(ArrayKernel.RR_VAR, selectedDims);
+    }
+
+    /**
+     * Finds the maximum values along the given dimension.
+     */
+    public IntegerArray iMax(int dim) {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_MAX, dim);
+    }
+
+    /**
+     * Finds the minimum values along the given dimension.
+     */
+    public IntegerArray iMin(int dim) {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_MIN, dim);
+    }
+
+    /**
+     * Finds all zeros along the given dimension.
+     */
+    public IntegerArray iZero(int dim) {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_ZERO, dim);
+    }
+
+    /**
+     * Finds all greater-than-zeros along the given dimension.
+     */
+    public IntegerArray iGZero(int dim) {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_GZERO, dim);
+    }
+
+    /**
+     * Finds all less-than-zeros along the given dimension.
+     */
+    public IntegerArray iLZero(int dim) {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_LZERO, dim);
+    }
+
+    /**
+     * Sorts along the given dimension.
+     */
+    public IntegerArray iSort(int dim) {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_SORT, dim);
+    }
+
+    /**
+     * Equates to calling {@link #iMax(int)} with argument {@code -1}.
+     */
+    public IntegerArray iMax() {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_MAX, -1);
+    }
+
+    /**
+     * Equates to calling {@link #iMin(int)} with argument {@code -1}.
+     */
+    public IntegerArray iMin() {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_MIN, -1);
+    }
+
+    /**
+     * Equates to calling {@link #iZero(int)} with argument {@code -1}.
+     */
+    public IntegerArray iZero() {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_ZERO, -1);
+    }
+
+    /**
+     * Equates to calling {@link #iGZero(int)} with argument {@code -1}.
+     */
+    public IntegerArray iGZero() {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_GZERO, -1);
+    }
+
+    /**
+     * Equates to calling {@link #iLZero(int)} with argument {@code -1}.
+     */
+    public IntegerArray iLZero() {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_LZERO, -1);
+    }
+
+    /**
+     * Equates to calling {@link #iSort(int)} with argument {@code -1}.
+     */
+    public IntegerArray iSort() {
+        return applyKernelRealIndexOperation(ArrayKernel.RI_SORT, -1);
+    }
+
+    /**
+     * Takes the sum along the given dimensions.
+     */
+    public R dSum(int... selectedDims) {
+        return applyKernelRealDimensionOperation(ArrayKernel.RD_SUM, selectedDims);
+    }
+
+    /**
+     * Takes the product along the given dimensions.
+     */
+    public R dProd(int... selectedDims) {
+        return applyKernelRealDimensionOperation(ArrayKernel.RD_PROD, selectedDims);
+    }
+
+    /**
+     * Supports the a* series of operations.
+     */
+    protected double applyKernelRealAccumulatorOperation(int type) {
+        return OpKernel.raOp(type, this.values);
+    }
+
+    /**
+     * Supports the e* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected R applyKernelElementwiseOperation(R b, int type) {
+
+        checkShape(b);
+
+        R a = (R) this;
+
+        R res = wrap(INVALID_PARITY, a.order, a.dims, a.strides);
+
+        OpKernel.eOp(type, a.values, b.values, res.values, false);
+
+        return res;
+    }
+
+    /**
+     * Supports the l* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected R applyKernelLeftElementwiseOperation(R b, int type) {
+
+        checkShape(b);
+
+        R a = (R) this;
+
+        OpKernel.eOp(type, a.values, b.values, a.values, false);
+
+        return a;
+    }
+
+    /**
+     * Supports the toc* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected C applyKernelRealToComplexOperation(int type) {
+
+        checkMatrixOrder();
+
+        R a = (R) this;
+
+        int[] newDims = Arrays.copyOf(a.dims, a.dims.length + 1);
+        newDims[newDims.length - 1] = 2;
+
+        C res = wrapUp(INVALID_PARITY, DEFAULT_ORDER, newDims, a.order.strides(newDims));
+
+        OpKernel.convert(type, a.values, false, res.values, true);
+
+        return res;
+    }
+
+    /**
+     * Supports the u* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected R applyKernelRealUnaryOperation(double a, int type) {
+
+        OpKernel.ruOp(type, a, this.values);
+
+        return (R) this;
+    }
+
+    /**
+     * Supports the r* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected R applyKernelRealReduceOperation(int type, int[] selectedDims) {
+
+        R a = (R) this;
+
+        int[] newDims = a.dims.clone();
+
+        for (int dim : selectedDims) {
+
+            // In case the dimension is 0.
+            newDims[dim] = Math.min(a.dims[dim], 1);
+        }
+
+        R res = wrap(INVALID_PARITY, a.order, newDims, a.order.strides(newDims));
+
+        OpKernel.rrOp(type, //
+                a.values, a.dims, a.strides, //
+                res.values, res.dims, res.strides, //
+                selectedDims);
+
+        return res;
+    }
+
+    /**
+     * Supports the i* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected IntegerArray applyKernelRealIndexOperation(int type, int dim) {
+
+        R a = (R) this;
+
+        IntegerArray res = new IntegerArray(a.order, a.dims);
+
+        OpKernel.riOp(type, //
+                a.values, a.dims, a.strides, res.values, //
+                dim);
+
+        return res;
+    }
+
+    /**
+     * Supports the d* series of operations.
+     */
+    @SuppressWarnings("unchecked")
+    protected R applyKernelRealDimensionOperation(int type, int[] selectedDims) {
+
+        R a = (R) this;
+
+        R res = wrap(INVALID_PARITY, a.order, a.dims, a.strides);
+
+        OpKernel.rdOp(type, //
+                a.values, a.dims, a.strides, res.values, //
+                selectedDims);
+
+        return res;
+    }
+
+    /**
+     * Mutatively maps the elements.
+     * 
+     * @param rm
+     *            the {@link RealMap}.
+     */
+    @SuppressWarnings("unchecked")
+    public R map(RealMap rm) {
+
+        R a = (R) this;
+
+        int[] logical = new int[a.dims.length];
+
+        for (int i = 0, n = a.values.length; i < n; i++) {
+            a.values[i] = rm.apply(a.values[i], ArrayBase.logical(i, a.strides, logical));
+        }
+
+        return a;
+    }
+
+    /**
+     * Reduces the elements.
+     * 
+     * @param rr
+     *            the {@link RealReduce}.
+     * @return the reduction result.
+     */
+    @SuppressWarnings("unchecked")
+    public double reduce(RealReduce rr) {
+
+        R a = (R) this;
+
+        int[] logical = new int[a.dims.length];
+
+        for (int i = 0, n = a.values.length; i < n; i++) {
+            rr.apply(a.values[i], ArrayBase.logical(i, a.strides, logical));
+        }
+
+        return rr.get();
+    }
+
+    /**
+     * Defines an elementwise "map" operation over real-valued multidimensional arrays.
+     */
+    public interface RealMap {
+
+        /**
+         * Applies the mapping.
+         * 
+         * @param value
+         *            the input value.
+         * @param logical
+         *            the current array logical index.
+         * @return the output value.
+         */
+        public double apply(double value, int[] logical);
+    }
+
+    /**
+     * Defines an elementwise "reduce" operation over real-valued multidimensional arrays.
+     */
+    public interface RealReduce {
+
+        /**
+         * Applies the reduction.
+         * 
+         * @param value
+         *            the input value.
+         * @param logical
+         *            the current array logical index.
+         */
+        public void apply(double value, int[] logical);
+
+        /**
+         * Gets the reduction result.
+         * 
+         * @return the reduction result.
+         */
+        public double get();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/Array.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/Array.java
new file mode 100755
index 0000000..1df0510
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/Array.java
@@ -0,0 +1,279 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+/**
+ * Defines functionality that can be expected from all multidimensional arrays.
+ * 
+ * @apiviz.owns shared.array.Array.IndexingOrder
+ * @param <T>
+ *            the parameterization lower bounded by {@link Array} itself.
+ * @param <E>
+ *            the component type.
+ * @author Roy Liu
+ */
+public interface Array<T extends Array<T, E>, E> extends Cloneable {
+
+    /**
+     * Gets the storage order of this array.
+     */
+    public IndexingOrder order();
+
+    /**
+     * Gets the size along the given dimension.
+     */
+    public int size(int i);
+
+    /**
+     * Gets the stride along the given dimension.
+     */
+    public int stride(int i);
+
+    /**
+     * Gets the number of dimensions.
+     */
+    public int ndims();
+
+    /**
+     * Gets the dimensions.
+     */
+    public int[] dimensions();
+
+    /**
+     * Gets the strides.
+     */
+    public int[] strides();
+
+    /**
+     * Maps this array into a destination array.
+     * 
+     * @param dst
+     *            the destination array.
+     * @param bounds
+     *            the mapping bounds as an array of three-tuples. Given the <tt>i</tt>th tuple, the first component
+     *            denotes the source start, the second component denotes the destination start, and the third component
+     *            denotes the mapping size. Is very much the multidimensional analogy to
+     *            {@link System#arraycopy(Object, int, Object, int, int)}.
+     * @return the destination array.
+     */
+    public T map(T dst, int... bounds);
+
+    /**
+     * A primitive slicing operation.
+     * 
+     * @param dst
+     *            the destination array.
+     * @param slices
+     *            the slicing specifications as an array of three-tuples. Given the <tt>i</tt>th tuple, the first
+     *            component denotes the source index, the second component denotes the destination index, and the third
+     *            component denotes the dimension of interest. The sliced portion is the Cartesian product subarray
+     *            delineated by these specifications.
+     * @return the destination array.
+     */
+    public T splice(T dst, int... slices);
+
+    /**
+     * Slices this array into a destination array.
+     * 
+     * @param srcSlices
+     *            the source slicing indices along each dimension.
+     * @param dst
+     *            the destination array.
+     * @param dstSlices
+     *            the destination slicing indices along each dimension.
+     * @return the destination array.
+     */
+    public T slice(int[][] srcSlices, T dst, int[][] dstSlices);
+
+    /**
+     * Slices this entire array into a destination array.
+     * 
+     * @param dst
+     *            the destination array.
+     * @param dstSlices
+     *            the destination slicing indices along each dimension.
+     * @return the destination array.
+     */
+    public T slice(T dst, int[]... dstSlices);
+
+    /**
+     * Slices a value into this array.
+     * 
+     * @param value
+     *            the value.
+     * @param srcSlices
+     *            the source slicing indices along each dimension.
+     * @return this array.
+     */
+    public T slice(E value, int[]... srcSlices);
+
+    /**
+     * Gets a subarray specified by the given slicing indices.
+     * 
+     * @param srcSlices
+     *            the slicing indices.
+     * @return the subarray.
+     */
+    public T slice(int[]... srcSlices);
+
+    /**
+     * Gets a subarray delimited by the given bounds.
+     * 
+     * @param bounds
+     *            the subarray bounds as an array of two-tuples. Given the <tt>i</tt>th tuple, the first component is
+     *            the (inclusive) lower range and the second component is the (exclusive) upper range.
+     * @return the subarray.
+     */
+    public T subarray(int... bounds);
+
+    /**
+     * Tiles this array according to the given number repetitions along each dimension.
+     * 
+     * @param repetitions
+     *            the number times to repeat along each dimension.
+     * @return the tiled result.
+     */
+    public T tile(int... repetitions);
+
+    /**
+     * Transposes (permutes) the dimensions of this array.
+     * 
+     * @param permutation
+     *            the dimension permutation.
+     * @return the transposed result.
+     */
+    public T transpose(int... permutation);
+
+    /**
+     * Circularly shifts this array.
+     * 
+     * @param shifts
+     *            the shift amounts.
+     * @return the shifted array.
+     */
+    public T shift(int... shifts);
+
+    /**
+     * Reshapes this array.
+     * 
+     * @param dims
+     *            the reshaped dimensions.
+     * @return the reshaped array.
+     */
+    public T reshape(int... dims);
+
+    /**
+     * Reverses along the given dimensions.
+     * 
+     * @param selectedDims
+     *            the dimensions to reverse along.
+     * @return the reversed array.
+     */
+    public T reverse(int... selectedDims);
+
+    /**
+     * Creates an array where the storage order is reversed.
+     */
+    public T reverseOrder();
+
+    /**
+     * Copies this array.
+     */
+    public T clone();
+
+    /**
+     * Gets the component type.
+     */
+    public Class<E> getComponentType();
+
+    /**
+     * Creates a human-readable representation of this array.
+     */
+    @Override
+    public String toString();
+
+    /**
+     * An enumeration of internal storage orders for {@link Array}s.
+     */
+    public enum IndexingOrder {
+
+        /**
+         * An ordering where low indices vary most.
+         */
+        NEAR {
+
+            @Override
+            public int[] strides(int[] dims) {
+
+                final int numDims = dims.length;
+                final int[] strides = new int[numDims];
+
+                strides[0] = 1;
+
+                for (int i = 1; i < numDims; i++) {
+                    strides[i] = strides[i - 1] * dims[i - 1];
+                }
+
+                return strides;
+            }
+
+            @Override
+            public IndexingOrder reverse() {
+                return FAR;
+            }
+        }, //
+
+        /**
+         * An ordering where high indices vary most.
+         */
+        FAR {
+
+            @Override
+            public int[] strides(int[] dims) {
+
+                final int numDims = dims.length;
+                final int[] strides = new int[numDims];
+
+                strides[numDims - 1] = 1;
+
+                for (int i = numDims - 2; i >= 0; i--) {
+                    strides[i] = strides[i + 1] * dims[i + 1];
+                }
+
+                return strides;
+            }
+
+            @Override
+            public IndexingOrder reverse() {
+                return NEAR;
+            }
+        };
+
+        /**
+         * Creates strides for the given dimensions.
+         * 
+         * @return the strides -- a vector such that its dot product with a logical index yields a physical index.
+         */
+        abstract public int[] strides(int[] dims);
+
+        /**
+         * Gets the reversed value.
+         */
+        abstract public IndexingOrder reverse();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/ArrayBase.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/ArrayBase.java
new file mode 100755
index 0000000..32a221c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/ArrayBase.java
@@ -0,0 +1,396 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.util.Control.LineSeparator;
+
+import java.lang.reflect.Array;
+import java.util.Formatter;
+
+import shared.array.Array.IndexingOrder;
+import shared.array.kernel.ModalArrayIOKernel;
+import shared.array.kernel.ModalArrayKernel;
+import shared.fft.ModalFFTService;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A collection of useful static methods and data structures common to all {@link Array} implementations.
+ * 
+ * @author Roy Liu
+ */
+public class ArrayBase {
+
+    /**
+     * The array operations kernel.
+     */
+    final public static ModalArrayKernel OpKernel = new ModalArrayKernel();
+
+    /**
+     * The array I/O kernel.
+     */
+    final public static ModalArrayIOKernel IOKernel = new ModalArrayIOKernel();
+
+    /**
+     * A global service providing access to FFT operations.
+     */
+    final public static ModalFFTService FFTService = new ModalFFTService();
+
+    /**
+     * The default storage order shall be {@link shared.array.Array.IndexingOrder#FAR}.
+     */
+    final public static IndexingOrder DEFAULT_ORDER = IndexingOrder.FAR;
+
+    /**
+     * The field width to use when printing.
+     */
+    public static int FIELD_WIDTH = 8;
+
+    /**
+     * The field precision to use when printing.
+     */
+    public static int FIELD_PRECISION = 2;
+
+    /**
+     * Canonicalizes the alternate slicing specification.
+     */
+    final public static int[] canonicalizeSlices(int[][] srcSlices, int[] srcDims, int[][] dstSlices, int[] dstDims) {
+
+        int ndims = srcSlices.length;
+
+        Control.checkTrue(ndims == dstSlices.length //
+                && ndims == srcDims.length //
+                && ndims == dstDims.length, //
+                "Dimensionality mismatch");
+
+        int nslices = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+            nslices += Control.checkEquals(srcSlices[dim].length, dstSlices[dim].length, //
+                    "Dimension mismatch");
+        }
+
+        int[] slices = new int[3 * nslices];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++) {
+
+            int[] srcSlice = srcSlices[dim];
+            int[] dstSlice = dstSlices[dim];
+
+            for (int j = 0, m = srcSlice.length; j < m; j++, offset += 3) {
+
+                slices[offset] = srcSlice[j];
+                slices[offset + 1] = dstSlice[j];
+                slices[offset + 2] = dim;
+            }
+        }
+
+        return slices;
+    }
+
+    /**
+     * Canonicalizes the alternate slicing specification.
+     */
+    final public static int[] canonicalizeSlices(int[] srcDims, int[] dstDims, int[][] dstSlices) {
+
+        int ndims = dstSlices.length;
+
+        Control.checkTrue(ndims == srcDims.length //
+                && ndims == dstDims.length, //
+                "Dimensionality mismatch");
+
+        int nslices = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+            nslices += Control.checkEquals(srcDims[dim], dstSlices[dim].length, //
+                    "Dimension mismatch");
+        }
+
+        int[] slices = new int[3 * nslices];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++) {
+
+            int[] dstSlice = dstSlices[dim];
+
+            for (int j = 0, m = dstSlice.length; j < m; j++, offset += 3) {
+
+                slices[offset] = j;
+                slices[offset + 1] = dstSlice[j];
+                slices[offset + 2] = dim;
+            }
+        }
+
+        return slices;
+    }
+
+    /**
+     * Canonicalizes the alternate slicing specification.
+     */
+    final public static int[] canonicalizeSlices(int nslices, int[] srcDims, int[][] srcSlices) {
+
+        int[] slices = new int[3 * nslices];
+
+        for (int dim = 0, offset = 0, ndims = srcDims.length; dim < ndims; dim++) {
+
+            int[] srcSlice = srcSlices[dim];
+
+            for (int j = 0, m = srcSlice.length; j < m; j++, offset += 3) {
+
+                slices[offset] = srcSlice[j];
+                slices[offset + 1] = j;
+                slices[offset + 2] = dim;
+            }
+        }
+
+        return slices;
+    }
+
+    /**
+     * Creates a slicing specification for {@link shared.array.Array#reverse(int...)}.
+     */
+    final public static int[] createReverseSlices(int[] srcDims, int[] selectedDims) {
+
+        int ndims = srcDims.length;
+        int nindices = selectedDims.length;
+
+        int nslices = Arithmetic.sum(srcDims);
+        int[] slices = new int[3 * nslices];
+
+        boolean[] sentinel = new boolean[ndims];
+
+        for (int i = 0; i < nindices; i++) {
+            sentinel[selectedDims[i]] = true;
+        }
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++) {
+
+            int dimSize = srcDims[dim];
+
+            if (sentinel[dim]) {
+
+                for (int j = 0, k = dimSize - 1; j < dimSize; j++, k--, offset += 3) {
+
+                    slices[offset] = j;
+                    slices[offset + 1] = k;
+                    slices[offset + 2] = dim;
+                }
+
+            } else {
+
+                for (int j = 0; j < dimSize; j++, offset += 3) {
+
+                    slices[offset] = j;
+                    slices[offset + 1] = j;
+                    slices[offset + 2] = dim;
+                }
+            }
+        }
+
+        return slices;
+    }
+
+    /**
+     * Sets the formatting parameters {@link #FIELD_WIDTH} and {@link #FIELD_PRECISION}.
+     * 
+     * @param width
+     *            the number width.
+     * @param precision
+     *            the number precision.
+     */
+    final public static void format(int width, int precision) {
+
+        Control.checkTrue(width >= precision + 4 && precision >= 1, //
+                "Invalid formatting parameters");
+
+        FIELD_WIDTH = width;
+        FIELD_PRECISION = precision;
+    }
+
+    /**
+     * Formats a two-dimensional slice of an array for display.
+     * 
+     * @param f
+     *            the target {@link Formatter}.
+     * @param format
+     *            the formatting string.
+     * @param values
+     *            the values.
+     * @param indices
+     *            the physical indices.
+     * @param offset
+     *            the physical index offset.
+     * @param nrows
+     *            the number of rows in the slice.
+     * @param ncols
+     *            the number of columns in the slice.
+     * @param isComplex
+     *            whether the values are complex.
+     */
+    final public static void formatSlice(Formatter f, String format, //
+            Object values, int[] indices, //
+            int offset, int nrows, int ncols, boolean isComplex) {
+
+        if (!isComplex) {
+
+            for (int j = 0, k = 0; j < nrows; j++) {
+
+                for (int i = 0; i < ncols; i++, k++) {
+                    f.format(format, Array.get(values, indices[offset + k]));
+                }
+
+                f.format(LineSeparator);
+            }
+
+        } else {
+
+            for (int j = 0, k = 0; j < nrows; j++) {
+
+                for (int i = 0; i < ncols; i++, k += 2) {
+                    f.format(format, //
+                            Array.get(values, indices[offset + k]), //
+                            Array.get(values, indices[offset + k + 1]));
+                }
+
+                f.format(LineSeparator);
+            }
+        }
+    }
+
+    /**
+     * Formats an empty array message.
+     * 
+     * @param f
+     *            the target {@link Formatter}.
+     * @param dims
+     *            the dimensions.
+     */
+    final public static void formatEmptyArray(Formatter f, int[] dims) {
+
+        int ndims = dims.length;
+
+        f.format(LineSeparator).format("[empty (");
+
+        for (int i = 0, n = ndims - 1; i < n; i++) {
+            f.format("%d, ", dims[i]);
+        }
+
+        f.format("%d)]", dims[ndims - 1]).format(LineSeparator);
+    }
+
+    /**
+     * Formats a potential rescale message if the given exponent is too large or too small.
+     * 
+     * @param f
+     *            the target {@link Formatter}.
+     * @param exponent
+     *            the exponent.
+     * @param values
+     *            the values.
+     * @return the potentially rescaled values.
+     */
+    final public static double[] formatRescale(Formatter f, int exponent, double[] values) {
+
+        if (FIELD_WIDTH < exponent + FIELD_PRECISION + 4 || exponent < 0) {
+
+            f.format("%s[rescale 10^%d]%s", //
+                    LineSeparator, exponent, LineSeparator);
+
+            double scale = Math.pow(10.0, -exponent);
+
+            double[] res = values.clone();
+
+            for (int i = 0, n = res.length; i < n; i++) {
+                res[i] *= scale;
+            }
+
+            return res;
+
+        } else {
+
+            return values;
+        }
+    }
+
+    /**
+     * Formats a sparse array for display.
+     * 
+     * @param f
+     *            the target {@link Formatter}.
+     * @param valueFormat
+     *            the formatting string for values.
+     * @param indexFormat
+     *            the formatting string for logical indices.
+     * @param values
+     *            the values.
+     * @param indices
+     *            the physical indices.
+     * @param strides
+     *            the strides.
+     */
+    final public static void formatSparseArray(Formatter f, String valueFormat, String indexFormat, //
+            Object values, int[] indices, int[] strides) {
+
+        int ndims = strides.length;
+
+        for (int i = 0, n = Control.checkEquals(Array.getLength(values), indices.length); i < n; i++) {
+
+            int physical = indices[i];
+
+            f.format("(");
+
+            for (int j = 0, m = ndims - 1; j < m; j++) {
+
+                f.format(indexFormat, physical / strides[j]);
+                f.format(",");
+
+                physical %= strides[j];
+            }
+
+            f.format(indexFormat, physical / strides[ndims - 1]);
+            f.format(")");
+            f.format(valueFormat, Array.get(values, i));
+            f.format(LineSeparator);
+        }
+    }
+
+    /**
+     * Computes the logical index from the given physical index and strides.
+     * 
+     * @param physical
+     *            the physical index.
+     * @param strides
+     *            the strides.
+     * @param logical
+     *            the logical index.
+     * @return the logical index.
+     */
+    final public static int[] logical(int physical, int[] strides, int[] logical) {
+
+        for (int dim = 0, ndims = Control.checkEquals(strides.length, logical.length); dim < ndims; dim++) {
+
+            logical[dim] = physical / strides[dim];
+            physical %= strides[dim];
+        }
+
+        return logical;
+    }
+
+    // Dummy constructor.
+    ArrayBase() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/ComplexArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/ComplexArray.java
new file mode 100755
index 0000000..a072120
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/ComplexArray.java
@@ -0,0 +1,166 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.IOKernel;
+import static shared.array.ArrayBase.OpKernel;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A multidimensional complex array class.
+ * 
+ * @author Roy Liu
+ */
+public class ComplexArray extends AbstractComplexArray<ComplexArray, RealArray> implements
+        Matrix<ComplexArray, AbstractComplexArray.Complex> {
+
+    /**
+     * Default constructor.
+     */
+    public ComplexArray(int... dims) {
+        this(0, dims.clone());
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected ComplexArray(int unused, int[] dims) {
+        super(new double[Arithmetic.product(dims)], INVALID_PARITY, dims, DEFAULT_ORDER.strides(dims));
+
+        Control.checkTrue(dims.length >= 2 && dims[dims.length - 1] == 2);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ComplexArray(double[] values, int... dims) {
+        this(0, values, inferDimensions(dims, values.length, true));
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ComplexArray(ComplexArray array) {
+        this(0, array.values.clone(), array.dims);
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected ComplexArray(int unused, double[] values, int[] dims) {
+        super(values, INVALID_PARITY, dims, DEFAULT_ORDER.strides(dims));
+
+        Control.checkTrue(dims.length >= 2 && dims[dims.length - 1] == 2 //
+                && values.length == Arithmetic.product(dims));
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected ComplexArray(int parity, int[] dims, int[] strides) {
+        super(new double[Arithmetic.product(dims)], parity, dims, strides);
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected ComplexArray(double[] values, int parity, int[] dims) {
+        super(values, parity, dims, DEFAULT_ORDER.strides(dims));
+    }
+
+    @Override
+    protected ComplexArray wrap(int parity, IndexingOrder order, int[] dims, int[] strides) {
+        return new ComplexArray(parity, dims, strides);
+    }
+
+    @Override
+    protected RealArray wrapDown(int parity, IndexingOrder order, int[] dims, int[] strides) {
+        return new RealArray(order, dims, strides);
+    }
+
+    public ComplexArray mMul(ComplexArray b) {
+
+        ComplexArray a = this;
+
+        Control.checkTrue(Control.checkEquals(a.dims.length, b.dims.length, //
+                "Dimensionality mismatch") == 3, //
+                "Arrays must have exactly three dimensions");
+
+        // Matrices are already in matrix order.
+        ComplexArray res = new ComplexArray(a.dims[0], b.dims[1], 2);
+
+        OpKernel.mul(a.values, b.values, a.dims[0], b.dims[1], res.values, true);
+
+        return res;
+    }
+
+    public ComplexArray mDiag() {
+
+        ComplexArray a = this;
+
+        Control.checkTrue(a.dims.length == 3, //
+                "Array must have exactly three dimensions");
+
+        int n = Control.checkEquals(a.dims[0], a.dims[1], //
+                "Dimensionality mismatch");
+
+        // Matrices are already in matrix order.
+        ComplexArray res = new ComplexArray(n, 1, 2);
+
+        OpKernel.diag(a.values, res.values, n, true);
+
+        return res;
+    }
+
+    public ComplexArray mTranspose() {
+
+        ComplexArray a = this;
+
+        Control.checkTrue(a.dims.length == 3, //
+                "Array must have exactly three dimensions");
+
+        return transpose(1, 0, 2);
+    }
+
+    @Override
+    public byte[] getBytes() {
+        return IOKernel.getBytes(this);
+    }
+
+    /**
+     * Parses an array from {@code byte}s.
+     */
+    final public static ComplexArray parse(byte[] data) {
+        return IOKernel.parse(data);
+    }
+
+    public ComplexArray[] mSVD() {
+        throw new UnsupportedOperationException(
+                "Complex matrices currently do not support singular value decompositions");
+    }
+
+    public ComplexArray[] mEigs() {
+        throw new UnsupportedOperationException("Complex matrices currently do not support eigenvalue decompositions");
+    }
+
+    public ComplexArray mInvert() {
+        throw new UnsupportedOperationException("Complex matrices currently do not support inverses");
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/IntegerArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/IntegerArray.java
new file mode 100755
index 0000000..dcbfc14
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/IntegerArray.java
@@ -0,0 +1,381 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.IOKernel;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.formatEmptyArray;
+import static shared.array.ArrayBase.formatSlice;
+import static shared.array.kernel.ArrayKernel.ITOR;
+
+import java.util.Arrays;
+import java.util.Formatter;
+
+import shared.array.kernel.ArrayKernel;
+import shared.array.kernel.MappingOps;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A multidimensional integer array class.
+ * 
+ * @apiviz.uses shared.array.ArrayBase
+ * @author Roy Liu
+ */
+public class IntegerArray extends ProtoArray<IntegerArray, int[], Integer> {
+
+    /**
+     * Default constructor.
+     */
+    public IntegerArray(IndexingOrder order, int... dims) {
+        this(0, order, dims.clone());
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected IntegerArray(int unused, IndexingOrder order, int[] dims) {
+        super(new int[Arithmetic.product(dims)], order, dims, order.strides(dims));
+
+        Control.checkTrue(dims.length > 0);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public IntegerArray(int[] values, int... dims) {
+        this(0, values, IndexingOrder.FAR, dims);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public IntegerArray(int[] values, IndexingOrder order, int... dims) {
+        this(0, values, order, dims);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public IntegerArray(IntegerArray array) {
+        this(0, array.values.clone(), array.order, array.dims);
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected IntegerArray(int unused, int[] values, IndexingOrder order, int[] dims) {
+        super(values, order, dims, order.strides(dims));
+
+        Control.checkTrue(dims.length > 0 //
+                && values.length == Arithmetic.product(dims));
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected IntegerArray(IndexingOrder order, int[] dims, int[] strides) {
+        super(new int[Arithmetic.product(dims)], order, dims, strides);
+    }
+
+    @Override
+    protected IntegerArray wrap(IndexingOrder order, int[] dims, int[] strides) {
+        return new IntegerArray(order, dims, strides);
+    }
+
+    @Override
+    protected IntegerArray wrap(Integer value, IndexingOrder order, int[] dims, int[] strides) {
+        return wrap(order, dims, strides).uFill(value);
+    }
+
+    /**
+     * Gets the value at the given logical index.
+     */
+    public int get(int... s) {
+        return this.values[physical(s)];
+    }
+
+    /**
+     * Sets the value at the given logical index.
+     */
+    public void set(int value, int... s) {
+        this.values[physical(s)] = value;
+    }
+
+    @Override
+    public int[] values() {
+        return this.values;
+    }
+
+    @Override
+    public byte[] getBytes() {
+        return IOKernel.getBytes(this);
+    }
+
+    public Class<Integer> getComponentType() {
+        return Integer.class;
+    }
+
+    @Override
+    public String toString() {
+
+        int[] values = this.values;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int ndims = dims.length;
+        int nrows = (ndims == 1) ? 1 : size(ndims - 2);
+        int ncols = size(ndims - 1);
+        int sliceSize = nrows * ncols;
+
+        int max = Math.max(Arithmetic.max(values), Math.abs(Arithmetic.min(values)));
+        int exponent = max > 0 ? (int) Math.log10(max) : 0;
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        String format = String.format("%%%dd", exponent + 3);
+
+        int[] indices = MappingOps.assignMappingIndices(Arithmetic.product(dims), //
+                dims, strides);
+
+        strides = IndexingOrder.FAR.strides(dims);
+
+        if (ndims <= 2) {
+
+            f.format("%n");
+
+            formatSlice(f, format, //
+                    values, indices, 0, nrows, ncols, false);
+
+            return f.toString();
+        }
+
+        for (int offset = 0, m = values.length; offset < m; offset += sliceSize) {
+
+            f.format("%n[slice (");
+
+            for (int i = 0, n = ndims - 2, offsetAcc = offset; i < n; offsetAcc %= strides[i], i++) {
+                f.format("%d, ", offsetAcc / strides[i]);
+            }
+
+            f.format(":, :)]%n");
+
+            formatSlice(f, format, //
+                    values, indices, offset, nrows, ncols, false);
+        }
+
+        return f.toString();
+    }
+
+    /**
+     * Assumes that this array results from an indexing operation. Extracts the valid indices along a dimension anchored
+     * at the given logical index.
+     * 
+     * @param s
+     *            the logical index, where the dimension of interest is marked with a {@code -1}.
+     * @return the valid indices along said dimension and at said logical index.
+     */
+    public int[] find(int... s) {
+
+        IntegerArray a = this;
+
+        return OpKernel.find(a.values, a.dims, a.strides, s);
+    }
+
+    /**
+     * Converts this array to a {@link RealArray}.
+     */
+    public RealArray tor() {
+
+        IntegerArray a = this;
+
+        RealArray res = new RealArray(a.order, a.dims);
+
+        OpKernel.convert(ITOR, a.values, false, res.values, false);
+
+        return res;
+    }
+
+    /**
+     * Mutatively adds the argument to the elements.
+     */
+    public IntegerArray uAdd(int a) {
+        return applyKernelIntegerUnaryOperation(a, ArrayKernel.IU_ADD);
+    }
+
+    /**
+     * Mutatively multiplies the elements by the argument.
+     */
+    public IntegerArray uMul(int a) {
+        return applyKernelIntegerUnaryOperation(a, ArrayKernel.IU_MUL);
+    }
+
+    /**
+     * Mutatively fills this array with the argument.
+     */
+    public IntegerArray uFill(int a) {
+        return applyKernelIntegerUnaryOperation(a, ArrayKernel.IU_FILL);
+    }
+
+    /**
+     * Mutatively shuffles this array.
+     */
+    public IntegerArray uShuffle() {
+        return applyKernelIntegerUnaryOperation(Integer.MIN_VALUE, ArrayKernel.IU_SHUFFLE);
+    }
+
+    /**
+     * Computes the elementwise addition.
+     */
+    public IntegerArray eAdd(IntegerArray array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.IE_ADD);
+    }
+
+    /**
+     * Computes the elementwise subtraction.
+     */
+    public IntegerArray eSub(IntegerArray array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.IE_SUB);
+    }
+
+    /**
+     * Computes the elementwise multiplication.
+     */
+    public IntegerArray eMul(IntegerArray array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.IE_MUL);
+    }
+
+    /**
+     * Computes the elementwise maximum.
+     */
+    public IntegerArray eMax(IntegerArray array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.IE_MAX);
+    }
+
+    /**
+     * Computes the elementwise minimum.
+     */
+    public IntegerArray eMin(IntegerArray array) {
+        return applyKernelElementwiseOperation(array, ArrayKernel.IE_MIN);
+    }
+
+    /**
+     * Computes the left elementwise addition.
+     */
+    public IntegerArray lAdd(IntegerArray array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.IE_ADD);
+    }
+
+    /**
+     * Computes the left elementwise subtraction.
+     */
+    public IntegerArray lSub(IntegerArray array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.IE_SUB);
+    }
+
+    /**
+     * Computes the left elementwise multiplication.
+     */
+    public IntegerArray lMul(IntegerArray array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.IE_MUL);
+    }
+
+    /**
+     * Computes the left elementwise maximum.
+     */
+    public IntegerArray lMax(IntegerArray array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.IE_MAX);
+    }
+
+    /**
+     * Computes the left elementwise minimum.
+     */
+    public IntegerArray lMin(IntegerArray array) {
+        return applyKernelLeftElementwiseOperation(array, ArrayKernel.IE_MIN);
+    }
+
+    /**
+     * Supports the e* series of operations.
+     */
+    protected IntegerArray applyKernelElementwiseOperation(IntegerArray b, int type) {
+
+        checkShape(b);
+
+        IntegerArray a = this;
+        IntegerArray res = wrap(a.order, a.dims, a.strides);
+
+        OpKernel.eOp(type, a.values, b.values, res.values, false);
+
+        return res;
+    }
+
+    /**
+     * Supports the l* series of operations.
+     */
+    protected IntegerArray applyKernelLeftElementwiseOperation(IntegerArray b, int type) {
+
+        checkShape(b);
+
+        IntegerArray a = this;
+
+        OpKernel.eOp(type, a.values, b.values, a.values, false);
+
+        return a;
+    }
+
+    /**
+     * Supports the u* series of operations.
+     */
+    protected IntegerArray applyKernelIntegerUnaryOperation(int a, int type) {
+
+        OpKernel.iuOp(type, a, this.values);
+
+        return this;
+    }
+
+    /**
+     * Checks that two {@link IntegerArray}s have the same size and underlying {@link Array.IndexingOrder}.
+     * 
+     * @param b
+     *            the {@link IntegerArray} to compare to.
+     */
+    protected void checkShape(IntegerArray b) {
+
+        IntegerArray a = this;
+
+        Control.checkTrue(a.order == b.order, //
+                "Indexing orders do not match");
+
+        Control.checkTrue(Arrays.equals(a.dims, b.dims), //
+                "Dimensions do not match");
+    }
+
+    /**
+     * Parses an array from {@code byte}s.
+     */
+    final public static IntegerArray parse(byte[] data) {
+        return IOKernel.parse(data);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/Matrix.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/Matrix.java
new file mode 100755
index 0000000..c169e59
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/Matrix.java
@@ -0,0 +1,74 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+/**
+ * Defines functionality that can be expected from all matrices.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link Matrix} itself.
+ * @param <E>
+ *            the element type.
+ * @author Roy Liu
+ */
+public interface Matrix<T extends Matrix<T, E>, E> extends Array<T, E> {
+
+    /**
+     * Multiplies two matrices.
+     * 
+     * @param rhs
+     *            the right hand side.
+     * @return the multiplication result.
+     */
+    public T mMul(T rhs);
+
+    /**
+     * Gets the diagonal of this matrix as a column vector.
+     * 
+     * @return the diagonal.
+     */
+    public T mDiag();
+
+    /**
+     * Transposes this matrix.
+     * 
+     * @return the transposed matrix.
+     */
+    public T mTranspose();
+
+    /**
+     * Inverts this matrix.
+     * 
+     * @return the inverted matrix.
+     */
+    public T mInvert();
+
+    /**
+     * Gets the singular value decomposition of this matrix.
+     * 
+     * @return the matrices "U", "S", and "V".
+     */
+    public T[] mSVD();
+
+    /**
+     * Gets the eigenvectors and eigenvalues of this matrix.
+     * 
+     * @return the eigenvectors and eigenvalues.
+     */
+    public T[] mEigs();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/ObjectArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/ObjectArray.java
new file mode 100755
index 0000000..49a1f02
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/ObjectArray.java
@@ -0,0 +1,242 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.formatEmptyArray;
+import static shared.array.ArrayBase.formatSlice;
+
+import java.lang.reflect.Array;
+import java.util.Formatter;
+
+import shared.array.kernel.DimensionOps;
+import shared.array.kernel.MappingOps;
+import shared.array.kernel.PermutationEntry;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A multidimensional object array class.
+ * 
+ * @apiviz.uses shared.array.ArrayBase
+ * @param <T>
+ *            the storage type.
+ * @author Roy Liu
+ */
+public class ObjectArray<T> extends ProtoArray<ObjectArray<T>, T[], T> {
+
+    /**
+     * Default constructor.
+     */
+    public ObjectArray(Class<T> clazz, int... dims) {
+        this(0, clazz, IndexingOrder.FAR, dims);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ObjectArray(Class<T> clazz, IndexingOrder order, int... dims) {
+        this(0, clazz, order, dims);
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    @SuppressWarnings("unchecked")
+    protected ObjectArray(int unused, Class<T> clazz, IndexingOrder order, int[] dims) {
+        super((T[]) Array.newInstance(clazz, Arithmetic.product(dims)), order, dims, order.strides(dims));
+
+        Control.checkTrue(dims.length > 0);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ObjectArray(T[] values, int... dims) {
+        this(0, values, IndexingOrder.FAR, //
+                AbstractArray.inferDimensions(dims, values.length, false));
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ObjectArray(T[] values, IndexingOrder order, int... dims) {
+        this(0, values, order, //
+                AbstractArray.inferDimensions(dims, values.length, false));
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ObjectArray(ObjectArray<T> array) {
+        this(0, array.values.clone(), array.order, array.dims);
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected ObjectArray(int unused, T[] values, IndexingOrder order, int[] dims) {
+        super(values, order, dims, order.strides(dims));
+
+        Control.checkTrue(dims.length > 0 //
+                && values.length == Arithmetic.product(dims));
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    @SuppressWarnings("unchecked")
+    protected ObjectArray(Class<T> clazz, IndexingOrder order, int[] dims, int[] strides) {
+        super((T[]) Array.newInstance(clazz, Arithmetic.product(dims)), order, dims, strides);
+    }
+
+    @Override
+    protected ObjectArray<T> wrap(IndexingOrder order, int[] dims, int[] strides) {
+        return new ObjectArray<T>(getComponentType(), order, dims, strides);
+    }
+
+    @Override
+    protected ObjectArray<T> wrap(T value, IndexingOrder order, int[] dims, int[] strides) {
+
+        ObjectArray<T> tmp = wrap(order, dims, strides);
+        java.util.Arrays.fill(tmp.values, value);
+
+        return tmp;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Class<T> getComponentType() {
+        return (Class<T>) this.values.getClass().getComponentType();
+    }
+
+    /**
+     * Gets the value at the given logical index.
+     */
+    public T get(int... s) {
+        return this.values[physical(s)];
+    }
+
+    /**
+     * Sets the value at the given logical index.
+     */
+    public void set(T value, int... s) {
+        this.values[physical(s)] = value;
+    }
+
+    @Override
+    public T[] values() {
+        return this.values;
+    }
+
+    @Override
+    public byte[] getBytes() {
+        throw new UnsupportedOperationException("Serialization of object arrays is not yet supported");
+    }
+
+    @Override
+    public String toString() {
+
+        T[] values = this.values;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int ndims = dims.length;
+        int nrows = (ndims == 1) ? 1 : size(ndims - 2);
+        int ncols = size(ndims - 1);
+        int sliceSize = nrows * ncols;
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        int[] indices = MappingOps.assignMappingIndices(Arithmetic.product(dims), //
+                dims, strides);
+
+        strides = IndexingOrder.FAR.strides(dims);
+
+        if (ndims <= 2) {
+
+            f.format("%n");
+
+            formatSlice(f, " \"%s\"", //
+                    values, indices, 0, nrows, ncols, false);
+
+            return f.toString();
+        }
+
+        for (int offset = 0, m = values.length; offset < m; offset += sliceSize) {
+
+            f.format("%n[slice (");
+
+            for (int i = 0, n = ndims - 2, offsetAcc = offset; i < n; offsetAcc %= strides[i], i++) {
+                f.format("%d, ", offsetAcc / strides[i]);
+            }
+
+            f.format(":, :)]%n");
+
+            formatSlice(f, " \"%s\"", //
+                    values, indices, offset, nrows, ncols, false);
+        }
+
+        return f.toString();
+    }
+
+    /**
+     * Sorts along the given dimension.
+     */
+    @SuppressWarnings("unchecked")
+    public IntegerArray iSort(int dim) {
+
+        ObjectArray<T> src = this;
+        IntegerArray dst = new IntegerArray(src.order, src.dims);
+
+        T[] srcV = src.values;
+        int[] srcD = src.dims;
+        int[] srcS = src.strides;
+
+        int[] dstV = dst.values();
+
+        int srcLen = MappingOps.checkDimensions(srcV.length, srcD, srcS);
+
+        Control.checkTrue(srcLen == dstV.length, //
+                "Invalid arguments");
+
+        if (srcLen == 0) {
+            return dst;
+        }
+
+        if (dim != -1) {
+
+            PermutationEntry.iSort(((ObjectArray<Comparable>) this).values(), //
+                    DimensionOps.assignBaseIndices(srcLen / srcD[dim], srcD, srcS, dim), //
+                    dstV, //
+                    srcD[dim], srcS[dim]);
+
+        } else {
+
+            PermutationEntry.iSort(((ObjectArray<Comparable>) this).values(), //
+                    null, dstV, -1, -1);
+        }
+
+        return dst;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/ProtoArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/ProtoArray.java
new file mode 100755
index 0000000..fa36382
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/ProtoArray.java
@@ -0,0 +1,437 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.IOKernel;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.canonicalizeSlices;
+import static shared.array.ArrayBase.createReverseSlices;
+
+import java.util.Arrays;
+
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * An abstract, primordial base class for all multidimensional arrays. Supports operations like mapping, slicing,
+ * tiling, shifting, transposition of dimensions, and storage order reversals.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link ProtoArray} itself.
+ * @param <V>
+ *            the storage array type.
+ * @param <E>
+ *            the element type.
+ * @author Roy Liu
+ */
+abstract public class ProtoArray<T extends ProtoArray<T, V, E>, V, E> implements Array<T, E> {
+
+    /**
+     * The backing values.
+     */
+    final protected V values;
+
+    /**
+     * The storage order.
+     */
+    final protected IndexingOrder order;
+
+    /**
+     * The dimensions.
+     */
+    final protected int[] dims;
+
+    /**
+     * The strides.
+     */
+    final protected int[] strides;
+
+    /**
+     * Default constructor.
+     */
+    protected ProtoArray(V values, IndexingOrder order, int[] dims, int[] strides) {
+
+        this.values = values;
+        this.order = order;
+        this.dims = dims;
+        this.strides = strides;
+    }
+
+    /**
+     * Allocates a new array.
+     * 
+     * @param order
+     *            the storage order.
+     * @param dims
+     *            the dimensions.
+     * @param strides
+     *            the strides.
+     * @return the new array.
+     */
+    abstract protected T wrap(IndexingOrder order, int[] dims, int[] strides);
+
+    /**
+     * Allocates a new array initialized to the given value.
+     * 
+     * @param value
+     *            the initial value.
+     * @param order
+     *            the storage order.
+     * @param dims
+     *            the dimensions.
+     * @param strides
+     *            the strides.
+     * @return the new array.
+     */
+    abstract protected T wrap(E value, IndexingOrder order, int[] dims, int[] strides);
+
+    /**
+     * Converts this array into {@code byte}s.
+     * 
+     * @return the {@code byte}s.
+     */
+    @SuppressWarnings("unchecked")
+    public byte[] getBytes() {
+        return IOKernel.getBytes((T) this);
+    }
+
+    /**
+     * Gets the backing values.
+     */
+    protected V values() {
+        return this.values;
+    }
+
+    /**
+     * Converts a logical index into a physical index.
+     */
+    protected int physical(int[] logical) {
+
+        int index = 0;
+
+        for (int i = 0, n = logical.length; i < n; i++) {
+            index += this.strides[i] * logical[i];
+        }
+
+        return index;
+    }
+
+    public T map(T dst, int... bounds) {
+
+        ProtoArray<T, V, E> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        OpKernel.map(bounds, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T splice(T dst, int... slices) {
+
+        ProtoArray<T, V, E> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        OpKernel.slice(slices, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T slice(int[][] srcSlices, T dst, int[][] dstSlices) {
+
+        ProtoArray<T, V, E> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        int[] slices = ArrayBase.canonicalizeSlices(srcSlices, src.dims, dstSlices, dst.dims);
+
+        OpKernel.slice(slices, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T slice(T dst, int[]... dstSlices) {
+
+        ProtoArray<T, V, E> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        OpKernel.slice(canonicalizeSlices(src.dims, dst.dims, dstSlices), //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T slice(E value, int[]... srcSlices) {
+
+        T src = (T) this;
+
+        int ndims = srcSlices.length;
+        int[] dstDims = new int[ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            dstDims[dim] = srcSlices[dim].length;
+        }
+
+        return wrap(value, src.order, dstDims, src.order.strides(dstDims)).slice(src, srcSlices);
+    }
+
+    public T slice(int[]... srcSlices) {
+
+        ProtoArray<T, V, E> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, srcSlices.length, //
+                "Dimensionality mismatch");
+
+        int nslices = 0;
+        int[] dstDims = new int[ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            nslices += (dstDims[dim] = srcSlices[dim].length);
+        }
+
+        T dst = wrap(src.order, dstDims, src.order.strides(dstDims));
+
+        OpKernel.slice(canonicalizeSlices(nslices, src.dims, srcSlices), //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T tile(int... repetitions) {
+
+        ProtoArray<T, V, E> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, repetitions.length, //
+                "Dimensionality mismatch");
+
+        int[] newDims = src.dims.clone();
+
+        for (int dim = 0; dim < ndims; dim++) {
+            newDims[dim] *= repetitions[dim];
+        }
+
+        T dst = wrap(src.order, newDims, src.order.strides(newDims));
+
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+            mappingBounds[offset + 2] = dst.dims[dim];
+        }
+
+        OpKernel.map(mappingBounds, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T transpose(int... permutation) {
+
+        ProtoArray<T, V, E> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, permutation.length, //
+                "Dimensionality mismatch");
+
+        int[] newDims = new int[ndims];
+        int[] copy = permutation.clone();
+
+        Arrays.sort(copy);
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            newDims[permutation[dim]] = src.dims[dim];
+
+            Control.checkTrue(copy[dim] == dim, //
+                    "Invalid permutation");
+        }
+
+        T dst = wrap(src.order, newDims, src.order.strides(newDims));
+
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+            mappingBounds[offset + 2] = src.dims[dim];
+        }
+
+        for (int dim = 0; dim < ndims; dim++) {
+            copy[dim] = dst.strides[permutation[dim]];
+        }
+
+        OpKernel.map(mappingBounds, //
+                src.values, src.dims, src.strides, //
+                dst.values, src.dims, copy);
+
+        return dst;
+    }
+
+    public T shift(int... shifts) {
+
+        ProtoArray<T, V, E> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, shifts.length, //
+                "Dimensionality mismatch");
+
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+
+            mappingBounds[offset + 1] = shifts[dim];
+            mappingBounds[offset + 2] = src.dims[dim];
+        }
+
+        T dst = wrap(src.order, src.dims, src.strides);
+
+        OpKernel.map(mappingBounds, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T reverseOrder() {
+
+        ProtoArray<T, V, E> src = this;
+
+        IndexingOrder newOrder = src.order.reverse();
+        T dst = wrap(newOrder, src.dims, newOrder.strides(src.dims));
+
+        int ndims = src.dims.length;
+
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+            mappingBounds[offset + 2] = src.dims[dim];
+        }
+
+        OpKernel.map(mappingBounds, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T subarray(int... bounds) {
+
+        ProtoArray<T, V, E> src = this;
+
+        int ndims = src.dims.length;
+
+        Control.checkTrue(ndims * 2 == bounds.length, //
+                "Invalid subarray bounds");
+
+        int[] newDims = new int[ndims];
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            int lower = bounds[2 * dim];
+            int upper = bounds[2 * dim + 1];
+
+            newDims[dim] = upper - lower;
+            mappingBounds[3 * dim] = lower;
+            mappingBounds[3 * dim + 2] = newDims[dim];
+        }
+
+        T dst = wrap(src.order, newDims, src.order.strides(newDims));
+
+        OpKernel.map(mappingBounds, //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T reverse(int... selectedDims) {
+
+        ProtoArray<T, V, E> src = this;
+
+        T dst = wrap(src.order, src.dims, src.strides);
+
+        OpKernel.slice(createReverseSlices(src.dims, selectedDims), //
+                src.values, src.dims, src.strides, //
+                dst.values, dst.dims, dst.strides);
+
+        return dst;
+    }
+
+    public T reshape(int... dims) {
+
+        ProtoArray<T, V, E> src = this;
+
+        int len = Control.checkEquals( //
+                Arithmetic.product(dims), Arithmetic.product(src.dims), //
+                "Cardinality mismatch");
+
+        T dst = wrap(src.order, dims, src.order.strides(dims));
+
+        System.arraycopy(src.values, 0, dst.values, 0, len);
+
+        return dst;
+    }
+
+    @Override
+    public T clone() {
+
+        ProtoArray<T, V, E> src = this;
+
+        T dst = wrap(src.order, src.dims, src.strides);
+
+        System.arraycopy(src.values, 0, dst.values, 0, Arithmetic.product(src.dims));
+
+        return dst;
+    }
+
+    public IndexingOrder order() {
+        return this.order;
+    }
+
+    public int size(int i) {
+        return this.dims[i];
+    }
+
+    public int stride(int i) {
+        return this.strides[i];
+    }
+
+    public int ndims() {
+        return this.dims.length;
+    }
+
+    public int[] dimensions() {
+        return this.dims.clone();
+    }
+
+    public int[] strides() {
+        return this.strides.clone();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/RealArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/RealArray.java
new file mode 100755
index 0000000..54ebcd2
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/RealArray.java
@@ -0,0 +1,294 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.IOKernel;
+import static shared.array.ArrayBase.OpKernel;
+import shared.util.Arithmetic;
+import shared.util.Arrays;
+import shared.util.Control;
+
+/**
+ * A multidimensional real array class.
+ * 
+ * @author Roy Liu
+ */
+public class RealArray extends AbstractRealArray<RealArray, ComplexArray> implements Matrix<RealArray, Double> {
+
+    /**
+     * Default constructor.
+     */
+    public RealArray(int... dims) {
+        this(0, DEFAULT_ORDER, dims.clone());
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public RealArray(IndexingOrder order, int... dims) {
+        this(0, order, dims.clone());
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected RealArray(int unused, IndexingOrder order, int[] dims) {
+        super(new double[Arithmetic.product(dims)], order, dims, order.strides(dims));
+
+        Control.checkTrue(dims.length > 0);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public RealArray(double[] values, int... dims) {
+        this(0, values, DEFAULT_ORDER, inferDimensions(dims, values.length, false));
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public RealArray(double[] values, IndexingOrder order, int... dims) {
+        this(0, values, order, inferDimensions(dims, values.length, false));
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public RealArray(RealArray array) {
+        this(0, array.values.clone(), array.order, array.dims);
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected RealArray(int unused, double[] values, IndexingOrder order, int[] dims) {
+        super(values, order, dims, order.strides(dims));
+
+        Control.checkTrue(dims.length > 0 //
+                && values.length == Arithmetic.product(dims));
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected RealArray(IndexingOrder order, int[] dims, int[] strides) {
+        super(new double[Arithmetic.product(dims)], order, dims, strides);
+    }
+
+    @Override
+    protected RealArray wrap(int parity, IndexingOrder order, int[] dims, int[] strides) {
+        return new RealArray(order, dims, strides);
+    }
+
+    @Override
+    protected ComplexArray wrapUp(int parity, IndexingOrder order, int[] dims, int[] strides) {
+        return new ComplexArray(parity, dims, strides);
+    }
+
+    public RealArray mMul(RealArray b) {
+
+        RealArray a = this;
+
+        a.checkMatrixOrder();
+        b.checkMatrixOrder();
+
+        Control.checkTrue(Control.checkEquals(a.dims.length, b.dims.length, //
+                "Dimensionality mismatch") == 2, //
+                "Arrays must have exactly two dimensions");
+
+        RealArray res = new RealArray(DEFAULT_ORDER, a.dims[0], b.dims[1]);
+
+        OpKernel.mul(a.values, b.values, a.dims[0], b.dims[1], res.values, false);
+
+        return res;
+    }
+
+    public RealArray mDiag() {
+
+        RealArray a = this;
+
+        a.checkMatrixOrder();
+
+        Control.checkTrue(a.dims.length == 2, //
+                "Array must have exactly two dimensions");
+
+        int size = Control.checkEquals(a.dims[0], a.dims[1], //
+                "Dimensionality mismatch");
+
+        RealArray res = new RealArray(DEFAULT_ORDER, size, 1);
+
+        OpKernel.diag(a.values, res.values, size, false);
+
+        return res;
+    }
+
+    public RealArray mTranspose() {
+
+        RealArray a = this;
+
+        a.checkMatrixOrder();
+
+        Control.checkTrue(a.dims.length == 2, //
+                "Array must have exactly two dimensions");
+
+        return transpose(1, 0);
+    }
+
+    public RealArray[] mSVD() {
+
+        RealArray a = this;
+
+        a.checkMatrixOrder();
+
+        Control.checkTrue(a.dims.length == 2, //
+                "Array must have exactly two dimensions");
+
+        int nrows = a.dims[0];
+        int ncols = a.dims[1];
+
+        final int matStrideRow, matStrideCol, nrowsT, ncolsT;
+
+        boolean transpose = (nrows < ncols);
+
+        if (!transpose) {
+
+            nrowsT = nrows;
+            ncolsT = ncols;
+
+            matStrideRow = ncolsT;
+            matStrideCol = 1;
+
+        } else {
+
+            nrowsT = ncols;
+            ncolsT = nrows;
+
+            matStrideRow = 1;
+            matStrideCol = nrowsT;
+        }
+
+        RealArray u = new RealArray(nrowsT, ncolsT);
+        RealArray s = new RealArray(ncolsT, ncolsT);
+        RealArray v = new RealArray(ncolsT, ncolsT);
+
+        double[] sV = new double[ncolsT];
+
+        OpKernel.svd(a.values, matStrideRow, matStrideCol, u.values(), sV, v.values(), nrowsT, ncolsT);
+
+        double[] sValues = s.values();
+
+        for (int i = 0; i < ncolsT; i++) {
+            sValues[ncolsT * i + i] = sV[i];
+        }
+
+        return !transpose ? new RealArray[] { u, s, v } : new RealArray[] { v, s, u };
+    }
+
+    public RealArray[] mEigs() {
+
+        RealArray a = this;
+
+        a.checkMatrixOrder();
+
+        Control.checkTrue(a.dims.length == 2, //
+                "Array must have exactly two dimensions");
+
+        int size = Control.checkEquals(a.dims[0], a.dims[1], //
+                "Dimensionality mismatch");
+
+        RealArray eigVectors = new RealArray(size, size);
+
+        double[] eigValues = new double[2 * size];
+
+        OpKernel.eigs(a.values, eigVectors.values, eigValues, size);
+
+        RealArray eigValueMatrix = new RealArray(size, size);
+
+        for (int i = 0, n = 2 * size; i < n; i += 2) {
+
+            int dim = i >>> 1;
+
+            if (i < n - 2 //
+                    && eigValues[i] == eigValues[i + 2] //
+                    && eigValues[i + 1] > 0 //
+                    && eigValues[i + 3] < 0) {
+
+                eigValueMatrix.set(eigValues[i], dim, dim);
+                eigValueMatrix.set(eigValues[i + 1], dim, dim + 1);
+                eigValueMatrix.set(eigValues[i + 2], dim + 1, dim + 1);
+                eigValueMatrix.set(eigValues[i + 3], dim + 1, dim);
+
+                i += 2;
+
+            } else {
+
+                eigValueMatrix.set(eigValues[i], dim, dim);
+            }
+        }
+
+        return new RealArray[] { eigVectors, eigValueMatrix };
+    }
+
+    public RealArray mInvert() {
+
+        RealArray a = this;
+
+        a.checkMatrixOrder();
+
+        Control.checkTrue(a.dims.length == 2, //
+                "Array must have exactly two dimensions");
+
+        int size = Control.checkEquals(a.dims[0], a.dims[1], //
+                "Dimensionality mismatch");
+
+        RealArray res = new RealArray(DEFAULT_ORDER, size, size);
+
+        OpKernel.invert(a.values, res.values, size);
+
+        return res;
+    }
+
+    @Override
+    public byte[] getBytes() {
+        return IOKernel.getBytes(this);
+    }
+
+    /**
+     * Parses an array from {@code byte}s.
+     */
+    final public static RealArray parse(byte[] data) {
+        return IOKernel.parse(data);
+    }
+
+    /**
+     * Creates an array of the given size and number of dimensions, with ones for diagonals.
+     */
+    final public static RealArray eye(int size, int ndims) {
+
+        RealArray res = new RealArray(Arrays.newArray(ndims, size));
+        double[] resValues = res.values();
+
+        for (int i = 0, offset = 0, increment = Arithmetic.sum(res.strides()); i < size; i++, offset += increment) {
+            resValues[offset] = 1.0;
+        }
+
+        return res;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/jni/NativeArrayKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/jni/NativeArrayKernel.java
new file mode 100755
index 0000000..0abb50b
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/jni/NativeArrayKernel.java
@@ -0,0 +1,122 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.jni;
+
+import shared.array.kernel.ArrayKernel;
+import shared.array.sparse.SparseArrayState;
+import shared.metaclass.Library;
+import shared.util.Control;
+
+/**
+ * A native implementation of {@link ArrayKernel}.
+ * 
+ * @author Roy Liu
+ */
+public class NativeArrayKernel implements ArrayKernel {
+
+    /**
+     * Default constructor. Checks the validity of native bindings.
+     */
+    public NativeArrayKernel() {
+
+        Control.checkTrue(Library.isInitialized(), //
+                "Could not instantiate native bindings -- Linking failed");
+    }
+
+    //
+
+    final public native void randomize();
+
+    final public native void derandomize();
+
+    //
+
+    final public native void map(int[] bounds, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS);
+
+    final public native void slice( //
+            int[] slices, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS);
+
+    //
+
+    final public native void rrOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS, //
+            int... selectedDims);
+
+    final public native void riOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, int[] dstV, //
+            int dim);
+
+    final public native void rdOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, double[] dstV, //
+            int... selectedDims);
+
+    //
+
+    final public native double raOp(int type, double[] srcV);
+
+    final public native double[] caOp(int type, double[] srcV);
+
+    final public native void ruOp(int type, double a, double[] srcV);
+
+    final public native void cuOp(int type, double aRe, double aIm, double[] srcV);
+
+    final public native void iuOp(int type, int a, int[] srcV);
+
+    final public native void eOp(int type, Object lhsV, Object rhsV, Object dstV, boolean isComplex);
+
+    final public native void convert(int type, //
+            Object srcV, boolean isSrcComplex, //
+            Object dstV, boolean isDstComplex);
+
+    //
+
+    final public native void mul(double[] lhsV, double[] rhsV, int lr, int rc, double[] dstV, boolean isComplex);
+
+    final public native void diag(double[] srcV, double[] dstV, int size, boolean isComplex);
+
+    //
+
+    final public native void svd(double[] srcV, int srcStrideRow, int srcStrideCol, //
+            double[] uV, double[] sV, double[] vV, //
+            int nrows, int ncols);
+
+    final public native void eigs(double[] srcV, double[] vecV, double[] valV, int size);
+
+    final public native void invert(double[] srcV, double[] dstV, int size);
+
+    //
+
+    final public native int[] find(int[] srcV, int[] srcD, int[] srcS, int[] logical);
+
+    //
+
+    final public native <V> SparseArrayState<V> insertSparse( //
+            V oldV, int[] oldD, int[] oldS, int[] oldDO, int[] oldI, //
+            V newV, int[] newLI);
+
+    final public native <V> SparseArrayState<V> sliceSparse(int[] slices, //
+            V srcV, int[] srcD, int[] srcS, int[] srcDO, //
+            int[] srcI, int[] srcIO, int[] srcII, //
+            V dstV, int[] dstD, int[] dstS, int[] dstDO, //
+            int[] dstI, int[] dstIO, int[] dstII);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/jni/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/jni/package-info.java
new file mode 100755
index 0000000..66a170c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/jni/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package for providing JNI-backed {@link shared.array.Array} operations.
+ */
+ at shared.metaclass.Policy(recursive = false)
+package shared.array.jni;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ArrayIOKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ArrayIOKernel.java
new file mode 100755
index 0000000..b9bbed8
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ArrayIOKernel.java
@@ -0,0 +1,53 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.array.Array;
+import shared.util.Service;
+
+/**
+ * A provider of {@link Array} I/O operations.
+ * 
+ * @author Roy Liu
+ */
+public interface ArrayIOKernel extends Service {
+
+    /**
+     * Converts an {@link Array} into {@code byte}s.
+     * 
+     * @param <T>
+     *            the {@link Array} type.
+     * @param <E>
+     *            the {@link Array} element type.
+     * @param array
+     *            the {@link Array}.
+     * @return the {@code byte}s.
+     */
+    public <T extends Array<T, E>, E> byte[] getBytes(T array);
+
+    /**
+     * Parses an {@link Array} from {@code byte}s.
+     * 
+     * @param data
+     *            the {@code byte}s.
+     * @param <T>
+     *            the inferred {@link Array} type.
+     * @return the {@link Array}.
+     */
+    public <T extends Array<T, ?>> T parse(byte[] data);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ArrayKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ArrayKernel.java
new file mode 100755
index 0000000..bbb8053
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ArrayKernel.java
@@ -0,0 +1,664 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.array.Array;
+import shared.array.Matrix;
+import shared.array.Array.IndexingOrder;
+import shared.array.sparse.SparseArrayState;
+import shared.util.Service;
+
+/**
+ * A provider of operations on {@link Array}s.
+ * 
+ * @author Roy Liu
+ */
+public interface ArrayKernel extends Service {
+
+    /** Real reduce sum. */
+    final public static int RR_SUM = 0;
+
+    /** Real reduce product. */
+    final public static int RR_PROD = 1;
+
+    /** Real reduce maximum. */
+    final public static int RR_MAX = 2;
+
+    /** Real reduce minimum. */
+    final public static int RR_MIN = 3;
+
+    /** Real reduce variance. */
+    final public static int RR_VAR = 4;
+
+    //
+
+    /** Real index maximum. */
+    final public static int RI_MAX = 0;
+
+    /** Real index minimum. */
+    final public static int RI_MIN = 1;
+
+    /** Real index find zeros. */
+    final public static int RI_ZERO = 2;
+
+    /** Real index find greater-than-zeros. */
+    final public static int RI_GZERO = 3;
+
+    /** Real index find less-than-zeros. */
+    final public static int RI_LZERO = 4;
+
+    /** Real index sort. */
+    final public static int RI_SORT = 5;
+
+    //
+
+    /** Real dimension sum. */
+    final public static int RD_SUM = 0;
+
+    /** Real dimension product. */
+    final public static int RD_PROD = 1;
+
+    //
+
+    /** Real accumulator sum. */
+    final public static int RA_SUM = 0;
+
+    /** Real accumulator product. */
+    final public static int RA_PROD = 1;
+
+    /** Real accumulator variance. */
+    final public static int RA_VAR = 2;
+
+    /** Real accumulator maximum. */
+    final public static int RA_MAX = 3;
+
+    /** Real accumulator minimum. */
+    final public static int RA_MIN = 4;
+
+    /** Real accumulator entropy. */
+    final public static int RA_ENT = 5;
+
+    //
+
+    /** Complex accumulator sum. */
+    final public static int CA_SUM = 0;
+
+    /** Complex accumulator product. */
+    final public static int CA_PROD = 1;
+
+    //
+
+    /** Real unary addition. */
+    final public static int RU_ADD = 0;
+
+    /** Real unary multiplication. */
+    final public static int RU_MUL = 1;
+
+    /** Real unary absolute value. */
+    final public static int RU_ABS = 2;
+
+    /** Real unary power. */
+    final public static int RU_POW = 3;
+
+    /** Real unary exponentiation. */
+    final public static int RU_EXP = 4;
+
+    /** Real unary randomization. */
+    final public static int RU_RND = 5;
+
+    /** Real unary natural logarithm. */
+    final public static int RU_LOG = 6;
+
+    /** Real unary square root. */
+    final public static int RU_SQRT = 7;
+
+    /** Real unary square. */
+    final public static int RU_SQR = 8;
+
+    /** Real unary inverse. */
+    final public static int RU_INV = 9;
+
+    /** Real unary cosine. */
+    final public static int RU_COS = 10;
+
+    /** Real unary sine. */
+    final public static int RU_SIN = 11;
+
+    /** Real unary arctangent. */
+    final public static int RU_ATAN = 12;
+
+    /** Real unary fill. */
+    final public static int RU_FILL = 13;
+
+    /** Real unary shuffle. */
+    final public static int RU_SHUFFLE = 14;
+
+    //
+
+    /** Complex unary addition. */
+    final public static int CU_ADD = 0;
+
+    /** Complex unary multiplication. */
+    final public static int CU_MUL = 1;
+
+    /** Complex unary exponentiation. */
+    final public static int CU_EXP = 2;
+
+    /** Complex unary randomization. */
+    final public static int CU_RND = 3;
+
+    /** Complex unary conjugation. */
+    final public static int CU_CONJ = 4;
+
+    /** Complex unary cosine. */
+    final public static int CU_COS = 5;
+
+    /** Complex unary sine. */
+    final public static int CU_SIN = 6;
+
+    /** Complex unary fill. */
+    final public static int CU_FILL = 7;
+
+    /** Complex unary shuffle. */
+    final public static int CU_SHUFFLE = 8;
+
+    //
+
+    /** Integer unary addition. */
+    final public static int IU_ADD = 0;
+
+    /** Integer unary multiplication. */
+    final public static int IU_MUL = 1;
+
+    /** Integer unary fill. */
+    final public static int IU_FILL = 2;
+
+    /** Integer unary shuffle. */
+    final public static int IU_SHUFFLE = 3;
+
+    //
+
+    /** Real elementwise addition. */
+    final public static int RE_ADD = 0;
+
+    /** Real elementwise subtraction. */
+    final public static int RE_SUB = 1;
+
+    /** Real elementwise multiplication. */
+    final public static int RE_MUL = 2;
+
+    /** Real elementwise division. */
+    final public static int RE_DIV = 3;
+
+    /** Real elementwise maximum. */
+    final public static int RE_MAX = 4;
+
+    /** Real elementwise minimum. */
+    final public static int RE_MIN = 5;
+
+    //
+
+    /** Integer elementwise addition. */
+    final public static int IE_ADD = 0;
+
+    /** Integer elementwise subtraction. */
+    final public static int IE_SUB = 1;
+
+    /** Integer elementwise multiplication. */
+    final public static int IE_MUL = 2;
+
+    /** Integer elementwise maximum. */
+    final public static int IE_MAX = 3;
+
+    /** Integer elementwise minimum. */
+    final public static int IE_MIN = 4;
+
+    //
+
+    /** Complex elementwise addition. */
+    final public static int CE_ADD = 0;
+
+    /** Complex elementwise subtraction. */
+    final public static int CE_SUB = 1;
+
+    /** Complex elementwise multiplication. */
+    final public static int CE_MUL = 2;
+
+    /** Complex elementwise division. */
+    final public static int CE_DIV = 3;
+
+    //
+
+    /** Complex to real conversion by complex magnitudes. */
+    final public static int CTOR_ABS = 0;
+
+    /** Complex to real conversion by real part. */
+    final public static int CTOR_RE = 1;
+
+    /** Complex to real conversion by imaginary part. */
+    final public static int CTOR_IM = 2;
+
+    //
+
+    /** Real to complex conversion by real part. */
+    final public static int RTOC_RE = 0;
+
+    /** Real to complex conversion by imaginary part. */
+    final public static int RTOC_IM = 1;
+
+    //
+
+    /** Integer to real conversion by up-casting. */
+    final public static int ITOR = 0;
+
+    //
+
+    /**
+     * Seeds the underlying source of randomness with the current time.
+     */
+    public void randomize();
+
+    /**
+     * Seeds the underlying source of randomness with a constant.
+     */
+    public void derandomize();
+
+    /**
+     * Performs a mapping operation.
+     * 
+     * @param bounds
+     *            the mapping bounds.
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param dstV
+     *            the destination values.
+     * @param dstD
+     *            the destination dimensions.
+     * @param dstS
+     *            the destination strides.
+     */
+    public void map( //
+            int[] bounds, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS);
+
+    /**
+     * Performs a slicing operation.
+     * 
+     * @param slices
+     *            the slicing specification.
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param dstV
+     *            the destination values.
+     * @param dstD
+     *            the destination dimensions.
+     * @param dstS
+     *            the destination strides.
+     */
+    public void slice( //
+            int[] slices, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS);
+
+    //
+
+    /**
+     * Performs a real reduce operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param dstV
+     *            the destination values.
+     * @param dstD
+     *            the destination dimensions.
+     * @param dstS
+     *            the destination strides.
+     * @param selectedDims
+     *            the dimensions of interest.
+     */
+    public void rrOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS, //
+            int... selectedDims);
+
+    /**
+     * Performs a real index operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param dstV
+     *            the destination values.
+     * @param dim
+     *            the dimension of interest.
+     */
+    public void riOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, //
+            int[] dstV, //
+            int dim);
+
+    /**
+     * Performs a real dimension operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param dstV
+     *            the destination values.
+     * @param selectedDims
+     *            the dimensions of interest.
+     */
+    public void rdOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, double[] dstV, //
+            int... selectedDims);
+
+    //
+
+    /**
+     * Performs a real accumulator operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param srcV
+     *            the array.
+     * @return the accumulated result.
+     */
+    public double raOp(int type, double[] srcV);
+
+    /**
+     * Performs a complex accumulator operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param srcV
+     *            the array.
+     * @return the accumulated result.
+     */
+    public double[] caOp(int type, double[] srcV);
+
+    /**
+     * Applies a real unary operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param a
+     *            the argument, if any.
+     * @param srcV
+     *            the array.
+     */
+    public void ruOp(int type, double a, double[] srcV);
+
+    /**
+     * Applies a complex unary operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param aRe
+     *            the real part of the argument, if any.
+     * @param aIm
+     *            the imaginary part of the argument, if any.
+     * @param srcV
+     *            the array.
+     */
+    public void cuOp(int type, double aRe, double aIm, double[] srcV);
+
+    /**
+     * Applies an integer unary operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param a
+     *            the argument, if any.
+     * @param srcV
+     *            the array.
+     */
+    public void iuOp(int type, int a, int[] srcV);
+
+    /**
+     * Applies a binary operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param lhsV
+     *            the left hand side values.
+     * @param rhsV
+     *            the right hand side values.
+     * @param dstV
+     *            the destination values.
+     * @param isComplex
+     *            whether the operation is complex-valued.
+     */
+    public void eOp(int type, Object lhsV, Object rhsV, Object dstV, boolean isComplex);
+
+    /**
+     * Performs a conversion operation.
+     * 
+     * @param type
+     *            the operation type.
+     * @param srcV
+     *            the source values.
+     * @param isSrcComplex
+     *            whether the source is complex-valued.
+     * @param dstV
+     *            the destination values.
+     * @param isDstComplex
+     *            whether the destination is complex-valued.
+     */
+    public void convert(int type, //
+            Object srcV, boolean isSrcComplex, //
+            Object dstV, boolean isDstComplex);
+
+    //
+
+    /**
+     * Multiplies two {@link Matrix}s. They are assumed to have storage order {@link IndexingOrder#FAR}.
+     * 
+     * @param lhsV
+     *            the left hand side values.
+     * @param rhsV
+     *            the right hand side values.
+     * @param lr
+     *            the row count of the result.
+     * @param rc
+     *            the column count of the result.
+     * @param dstV
+     *            the destination values.
+     * @param isComplex
+     *            whether the operation is complex-valued.
+     */
+    public void mul(double[] lhsV, double[] rhsV, int lr, int rc, double[] dstV, boolean isComplex);
+
+    /**
+     * Gets the diagonal of a {@link Matrix}.
+     * 
+     * @param srcV
+     *            source values.
+     * @param dstV
+     *            destination values.
+     * @param size
+     *            the matrix size.
+     * @param isComplex
+     *            whether the operation is complex-valued.
+     */
+    public void diag(double[] srcV, double[] dstV, int size, boolean isComplex);
+
+    //
+
+    /**
+     * Computes the singular value decomposition of a {@link Matrix}.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param srcStrideRow
+     *            the source row stride.
+     * @param srcStrideCol
+     *            the source column stride.
+     * @param uV
+     *            the input vectors.
+     * @param sV
+     *            the gain controls.
+     * @param vV
+     *            the output vectors.
+     * @param nrows
+     *            the number of rows.
+     * @param ncols
+     *            the number of columns.
+     */
+    public void svd(double[] srcV, int srcStrideRow, int srcStrideCol, //
+            double[] uV, double[] sV, double[] vV, //
+            int nrows, int ncols);
+
+    /**
+     * Computes the eigenvectors and eigenvalues of a {@link Matrix}.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param vecV
+     *            the eigenvectors.
+     * @param valV
+     *            the eigenvalues.
+     * @param size
+     *            the matrix size.
+     */
+    public void eigs(double[] srcV, double[] vecV, double[] valV, int size);
+
+    /**
+     * Computes the inverse of a {@link Matrix}.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param dstV
+     *            the destination values.
+     * @param size
+     *            the matrix size.
+     */
+    public void invert(double[] srcV, double[] dstV, int size);
+
+    //
+
+    /**
+     * Extracts the valid indices along a dimension anchored at the given logical index.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param logical
+     *            the logical index.
+     * @return the valid indices.
+     */
+    public int[] find(int[] srcV, int[] srcD, int[] srcS, int[] logical);
+
+    //
+
+    /**
+     * Inserts elements into a sparse array.
+     * 
+     * @param oldV
+     *            the old values.
+     * @param oldD
+     *            the old dimensions.
+     * @param oldS
+     *            the old strides.
+     * @param oldDO
+     *            the old dimension offsets.
+     * @param oldI
+     *            the old physical indices. Invariant: Sorted in ascending order, and does not contain duplicates.
+     * @param newV
+     *            the new values.
+     * @param newI
+     *            the new physical indices, which need not be sorted in ascending order.
+     * @param <V>
+     *            the storage array type.
+     * @return the {@link SparseArrayState}.
+     */
+    public <V> SparseArrayState<V> insertSparse( //
+            V oldV, int[] oldD, int[] oldS, int[] oldDO, int[] oldI, //
+            V newV, int[] newI);
+
+    /**
+     * Slices one sparse array into another.
+     * 
+     * @param slices
+     *            the slicing specification.
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param srcDO
+     *            the source dimension offsets.
+     * @param srcI
+     *            the source physical indices. Invariant: Sorted in ascending order, and does not contain duplicates.
+     * @param srcIO
+     *            the source indirection offsets.
+     * @param srcII
+     *            the source indirections.
+     * @param dstV
+     *            the destination values.
+     * @param dstD
+     *            the destination dimensions.
+     * @param dstS
+     *            the destination strides.
+     * @param dstDO
+     *            the destination dimension offsets.
+     * @param dstI
+     *            the destination physical indices. Invariant: Sorted in ascending order, and does not contain
+     *            duplicates.
+     * @param dstIO
+     *            the destination indirection offsets.
+     * @param dstII
+     *            the destination indirections.
+     * @param <V>
+     *            the storage array type.
+     * @return the {@link SparseArrayState}.
+     */
+    public <V> SparseArrayState<V> sliceSparse(int[] slices, //
+            V srcV, int[] srcD, int[] srcS, int[] srcDO, //
+            int[] srcI, int[] srcIO, int[] srcII, //
+            V dstV, int[] dstD, int[] dstS, int[] dstDO, //
+            int[] dstI, int[] dstIO, int[] dstII);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/DimensionOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/DimensionOps.java
new file mode 100755
index 0000000..caf4f90
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/DimensionOps.java
@@ -0,0 +1,690 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import static shared.array.kernel.ArrayKernel.RD_PROD;
+import static shared.array.kernel.ArrayKernel.RD_SUM;
+import static shared.array.kernel.ArrayKernel.RI_GZERO;
+import static shared.array.kernel.ArrayKernel.RI_LZERO;
+import static shared.array.kernel.ArrayKernel.RI_MAX;
+import static shared.array.kernel.ArrayKernel.RI_MIN;
+import static shared.array.kernel.ArrayKernel.RI_SORT;
+import static shared.array.kernel.ArrayKernel.RI_ZERO;
+import static shared.array.kernel.ArrayKernel.RR_MAX;
+import static shared.array.kernel.ArrayKernel.RR_MIN;
+import static shared.array.kernel.ArrayKernel.RR_PROD;
+import static shared.array.kernel.ArrayKernel.RR_SUM;
+import static shared.array.kernel.ArrayKernel.RR_VAR;
+
+import java.util.Arrays;
+
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A class for dimension operations in pure Java.
+ * 
+ * @apiviz.has shared.array.kernel.DimensionOps.RealReduceOperation - - - argument
+ * @apiviz.has shared.array.kernel.DimensionOps.RealIndexOperation - - - argument
+ * @apiviz.has shared.array.kernel.DimensionOps.RealDimensionOperation - - - argument
+ * @apiviz.uses shared.array.kernel.PermutationEntry
+ * @author Roy Liu
+ */
+public class DimensionOps {
+
+    /**
+     * Defines real reduce operations.
+     */
+    protected interface RealReduceOperation {
+
+        /**
+         * Performs a real reduce operation.
+         */
+        public void op(double[] working, int[] workingIndices, int size, int stride);
+    }
+
+    final static RealReduceOperation RRSumOp = new RealReduceOperation() {
+
+        public void op(double[] working, int[] workingIndices, int size, int stride) {
+
+            for (int workingIndex : workingIndices) {
+
+                for (int j = 1, offset = workingIndex + stride; j < size; j++, offset += stride) {
+                    working[workingIndex] += working[offset];
+                }
+            }
+        }
+    };
+
+    final static RealReduceOperation RRProdOp = new RealReduceOperation() {
+
+        public void op(double[] working, int[] workingIndices, int size, int stride) {
+
+            for (int workingIndex : workingIndices) {
+
+                for (int j = 1, offset = workingIndex + stride; j < size; j++, offset += stride) {
+                    working[workingIndex] *= working[offset];
+                }
+            }
+        }
+    };
+
+    final static RealReduceOperation RRMaxOp = new RealReduceOperation() {
+
+        public void op(double[] working, int[] workingIndices, int size, int stride) {
+
+            for (int workingIndex : workingIndices) {
+
+                for (int j = 1, offset = workingIndex + stride; j < size; j++, offset += stride) {
+                    working[workingIndex] = Math.max(working[offset], working[workingIndex]);
+                }
+            }
+        }
+    };
+
+    final static RealReduceOperation RRMinOp = new RealReduceOperation() {
+
+        public void op(double[] working, int[] workingIndices, int size, int stride) {
+
+            for (int workingIndex : workingIndices) {
+
+                for (int j = 1, offset = workingIndex + stride; j < size; j++, offset += stride) {
+                    working[workingIndex] = Math.min(working[offset], working[workingIndex]);
+                }
+            }
+        }
+    };
+
+    final static RealReduceOperation RRVarOp = new RealReduceOperation() {
+
+        public void op(double[] working, int[] workingIndices, int size, int stride) {
+
+            for (int workingIndex : workingIndices) {
+
+                double mean = 0.0;
+
+                for (int j = 0, offset = workingIndex; j < size; j++, offset += stride) {
+                    mean += working[offset];
+                }
+
+                mean /= size;
+
+                for (int j = 0, offset = workingIndex; j < size; j++, offset += stride) {
+
+                    double diff = working[offset] - mean;
+                    working[offset] = diff * diff;
+                }
+
+                for (int j = 1, offset = workingIndex + stride; j < size; j++, offset += stride) {
+                    working[workingIndex] += working[offset];
+                }
+
+                working[workingIndex] /= size;
+            }
+        }
+    };
+
+    /**
+     * Defines real index operations.
+     */
+    protected interface RealIndexOperation {
+
+        /**
+         * Performs a real index operation.
+         */
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride);
+    }
+
+    final static RealIndexOperation RIMaxOp = new RealIndexOperation() {
+
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride) {
+
+            if (srcIndices != null) {
+
+                int maxStride = stride * size;
+
+                for (int i = 0, nindices = srcIndices.length; i < nindices; i++) {
+
+                    double acc = -Double.MAX_VALUE;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+                        acc = Math.max(acc, srcV[srcIndices[i] + offset]);
+                    }
+
+                    int count = 0;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+
+                        if (srcV[srcIndices[i] + offset] == acc) {
+
+                            dstV[srcIndices[i] + count] = offset / stride;
+                            count += stride;
+                        }
+                    }
+
+                    for (int offset = count; offset < maxStride; offset += stride) {
+                        dstV[srcIndices[i] + offset] = -1;
+                    }
+                }
+
+            } else {
+
+                double maxValue = Arithmetic.max(srcV);
+
+                for (int i = 0, n = srcV.length; i < n; i++) {
+                    dstV[i] = (srcV[i] == maxValue) ? 1 : 0;
+                }
+            }
+        }
+    };
+
+    final static RealIndexOperation RIMinOp = new RealIndexOperation() {
+
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride) {
+
+            if (srcIndices != null) {
+
+                int maxStride = stride * size;
+
+                for (int i = 0, nindices = srcIndices.length; i < nindices; i++) {
+
+                    double acc = Double.MAX_VALUE;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+                        acc = Math.min(acc, srcV[srcIndices[i] + offset]);
+                    }
+
+                    int count = 0;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+
+                        if (srcV[srcIndices[i] + offset] == acc) {
+
+                            dstV[srcIndices[i] + count] = offset / stride;
+                            count += stride;
+                        }
+                    }
+
+                    for (int offset = count; offset < maxStride; offset += stride) {
+                        dstV[srcIndices[i] + offset] = -1;
+                    }
+                }
+
+            } else {
+
+                double minValue = Arithmetic.min(srcV);
+
+                for (int i = 0, n = srcV.length; i < n; i++) {
+                    dstV[i] = (srcV[i] == minValue) ? 1 : 0;
+                }
+            }
+        }
+    };
+
+    final static RealIndexOperation RIZeroOp = new RealIndexOperation() {
+
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride) {
+
+            if (srcIndices != null) {
+
+                int maxStride = stride * size;
+
+                for (int i = 0, nindices = srcIndices.length; i < nindices; i++) {
+
+                    int count = 0;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+
+                        if (srcV[srcIndices[i] + offset] == 0.0) {
+
+                            dstV[srcIndices[i] + count] = offset / stride;
+                            count += stride;
+                        }
+                    }
+
+                    for (int offset = count; offset < maxStride; offset += stride) {
+                        dstV[srcIndices[i] + offset] = -1;
+                    }
+                }
+
+            } else {
+
+                for (int i = 0, n = srcV.length; i < n; i++) {
+                    dstV[i] = (srcV[i] == 0.0) ? 1 : 0;
+                }
+            }
+        }
+    };
+
+    final static RealIndexOperation RIGZeroOp = new RealIndexOperation() {
+
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride) {
+
+            if (srcIndices != null) {
+
+                int maxStride = stride * size;
+
+                for (int i = 0, nindices = srcIndices.length; i < nindices; i++) {
+
+                    int count = 0;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+
+                        if (srcV[srcIndices[i] + offset] > 0.0) {
+
+                            dstV[srcIndices[i] + count] = offset / stride;
+                            count += stride;
+                        }
+                    }
+
+                    for (int offset = count; offset < maxStride; offset += stride) {
+                        dstV[srcIndices[i] + offset] = -1;
+                    }
+                }
+
+            } else {
+
+                for (int i = 0, n = srcV.length; i < n; i++) {
+                    dstV[i] = (srcV[i] > 0.0) ? 1 : 0;
+                }
+            }
+        }
+    };
+
+    final static RealIndexOperation RILZeroOp = new RealIndexOperation() {
+
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride) {
+
+            if (srcIndices != null) {
+
+                int maxStride = stride * size;
+
+                for (int i = 0, nindices = srcIndices.length; i < nindices; i++) {
+
+                    int count = 0;
+
+                    for (int offset = 0; offset < maxStride; offset += stride) {
+
+                        if (srcV[srcIndices[i] + offset] < 0.0) {
+
+                            dstV[srcIndices[i] + count] = offset / stride;
+                            count += stride;
+                        }
+                    }
+
+                    for (int offset = count; offset < maxStride; offset += stride) {
+                        dstV[srcIndices[i] + offset] = -1;
+                    }
+                }
+
+            } else {
+
+                for (int i = 0, n = srcV.length; i < n; i++) {
+                    dstV[i] = (srcV[i] < 0.0) ? 1 : 0;
+                }
+            }
+        }
+    };
+
+    final static RealIndexOperation RISortOp = new RealIndexOperation() {
+
+        public void op(double[] srcV, int[] srcIndices, int[] dstV, int size, int stride) {
+
+            Double[] srcVBoxed = shared.util.Arrays.box(srcV);
+
+            PermutationEntry.iSort(srcVBoxed, srcIndices, dstV, size, stride);
+
+            for (int i = 0, n = srcV.length; i < n; i++) {
+                srcV[i] = srcVBoxed[i];
+            }
+        }
+    };
+
+    /**
+     * Defines real dimension operations.
+     */
+    protected interface RealDimensionOperation {
+
+        /**
+         * Performs a real dimension operation.
+         */
+        public void op(double[] srcV, int[] srcD, int[] srcS, double[] dstV, int[] selectedDims);
+    }
+
+    final static RealDimensionOperation RDSumOp = new RealDimensionOperation() {
+
+        public void op(double[] srcV, int[] srcD, int[] srcS, double[] dstV, int[] selectedDims) {
+
+            int len = Control.checkEquals(srcV.length, dstV.length);
+            int ndims = Control.checkEquals(srcD.length, srcS.length);
+
+            boolean[] indicator = new boolean[ndims];
+
+            for (int dim : selectedDims) {
+                indicator[dim] = true;
+            }
+
+            int[] srcIndices = MappingOps.assignMappingIndices(len, srcD, srcS);
+
+            //
+
+            System.arraycopy(srcV, 0, dstV, 0, len);
+
+            for (int dim = 0, indexBlockIncrement = len; dim < ndims; indexBlockIncrement /= srcD[dim++]) {
+
+                if (!indicator[dim]) {
+                    continue;
+                }
+
+                int size = srcD[dim];
+                int stride = srcS[dim];
+
+                for (int lower = 0, upper = indexBlockIncrement / size; //
+                lower < len; //
+                lower += indexBlockIncrement, upper += indexBlockIncrement) {
+
+                    for (int indexIndex = lower; indexIndex < upper; indexIndex++) {
+
+                        double acc = 0.0;
+
+                        for (int k = 0, physical = srcIndices[indexIndex]; k < size; k++, physical += stride) {
+
+                            acc += dstV[physical];
+                            dstV[physical] = acc;
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    final static RealDimensionOperation RDProdOp = new RealDimensionOperation() {
+
+        public void op(double[] srcV, int[] srcD, int[] srcS, double[] dstV, int[] selectedDims) {
+
+            int len = Control.checkEquals(srcV.length, dstV.length);
+            int ndims = Control.checkEquals(srcD.length, srcS.length);
+
+            boolean[] indicator = new boolean[ndims];
+
+            for (int dim : selectedDims) {
+                indicator[dim] = true;
+            }
+
+            int[] srcIndices = MappingOps.assignMappingIndices(len, srcD, srcS);
+
+            //
+
+            System.arraycopy(srcV, 0, dstV, 0, len);
+
+            for (int dim = 0, indexBlockIncrement = len; dim < ndims; indexBlockIncrement /= srcD[dim++]) {
+
+                if (!indicator[dim]) {
+                    continue;
+                }
+
+                int size = srcD[dim];
+                int stride = srcS[dim];
+
+                for (int lower = 0, upper = indexBlockIncrement / size; //
+                lower < len; //
+                lower += indexBlockIncrement, upper += indexBlockIncrement) {
+
+                    for (int indexIndex = lower; indexIndex < upper; indexIndex++) {
+
+                        double acc = 1.0;
+
+                        for (int k = 0, physical = srcIndices[indexIndex]; k < size; k++, physical += stride) {
+
+                            acc *= dstV[physical];
+                            dstV[physical] = acc;
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    /**
+     * Assigns base indices when excluding a dimension.
+     * 
+     * @param nindices
+     *            the number of indices.
+     * @param srcD
+     *            the dimensions.
+     * @param srcS
+     *            the strides.
+     * @param dim
+     *            the dimension to exclude.
+     * @return the base physical indices.
+     */
+    final public static int[] assignBaseIndices(int nindices, int[] srcD, int[] srcS, int dim) {
+
+        int ndims = Control.checkEquals(srcD.length, srcS.length, //
+                "Invalid arguments");
+
+        int[] dModified = new int[ndims - 1];
+        int[] sModified = new int[ndims - 1];
+
+        System.arraycopy(srcD, 0, dModified, 0, dim);
+        System.arraycopy(srcD, dim + 1, dModified, dim, (ndims - 1) - dim);
+
+        System.arraycopy(srcS, 0, sModified, 0, dim);
+        System.arraycopy(srcS, dim + 1, sModified, dim, (ndims - 1) - dim);
+
+        return MappingOps.assignMappingIndices(nindices, dModified, sModified);
+    }
+
+    /**
+     * Dimension reduce operations in support of
+     * {@link JavaArrayKernel#rrOp(int, double[], int[], int[], double[], int[], int[], int...)}.
+     */
+    final public static void rrOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS, //
+            int[] selectedDims) {
+
+        int srcLen = MappingOps.checkDimensions(srcV.length, srcD, srcS);
+        int dstLen = MappingOps.checkDimensions(dstV.length, dstD, dstS);
+
+        final RealReduceOperation op;
+
+        switch (type) {
+
+        case RR_SUM:
+            op = RRSumOp;
+            break;
+
+        case RR_PROD:
+            op = RRProdOp;
+            break;
+
+        case RR_MAX:
+            op = RRMaxOp;
+            break;
+
+        case RR_MIN:
+            op = RRMinOp;
+            break;
+
+        case RR_VAR:
+            op = RRVarOp;
+            break;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        Arrays.sort(selectedDims);
+
+        int nselectedDims = selectedDims.length;
+        int ndims = Control.checkEquals(srcD.length, dstD.length, //
+                "Dimensionality mismatch");
+
+        for (int i = 1; i < nselectedDims; i++) {
+            Control.checkTrue(selectedDims[i - 1] != selectedDims[i], //
+                    "Duplicate selected dimensions not allowed");
+        }
+
+        int acc = dstLen;
+
+        for (int i = 0; i < nselectedDims; i++) {
+
+            int dim = selectedDims[i];
+
+            Control.checkTrue(dim >= 0 && dim < ndims, //
+                    "Invalid dimension");
+
+            Control.checkTrue(dstD[dim] <= 1, //
+                    "Selected dimension must have singleton or zero length");
+
+            acc *= srcD[dim];
+        }
+
+        Control.checkTrue(acc == srcLen, //
+                "Invalid arguments");
+
+        if (srcLen == 0) {
+            return;
+        }
+
+        double[] workingV = srcV.clone();
+        int[] workingD = srcD.clone();
+
+        acc = srcLen;
+
+        for (int i = 0; i < nselectedDims; i++) {
+
+            int dim = selectedDims[i];
+
+            acc /= srcD[dim];
+
+            op.op(workingV, assignBaseIndices(acc, workingD, srcS, dim), //
+                    workingD[dim], srcS[dim]);
+
+            workingD[dim] = 1;
+        }
+
+        MappingOps.assign( //
+                workingV, MappingOps.assignMappingIndices(dstLen, dstD, srcS), //
+                dstV, MappingOps.assignMappingIndices(dstLen, dstD, dstS));
+    }
+
+    /**
+     * Dimension index operations in support of {@link ArrayKernel#riOp(int, double[], int[], int[], int[], int)}.
+     */
+    final public static void riOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, int[] dstV, //
+            int dim) {
+
+        int srcLen = MappingOps.checkDimensions(srcV.length, srcD, srcS);
+
+        final RealIndexOperation op;
+
+        switch (type) {
+
+        case RI_MAX:
+            op = RIMaxOp;
+            break;
+
+        case RI_MIN:
+            op = RIMinOp;
+            break;
+
+        case RI_ZERO:
+            op = RIZeroOp;
+            break;
+
+        case RI_GZERO:
+            op = RIGZeroOp;
+            break;
+
+        case RI_LZERO:
+            op = RILZeroOp;
+            break;
+
+        case RI_SORT:
+            op = RISortOp;
+            break;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        Control.checkTrue(srcLen == dstV.length, //
+                "Invalid arguments");
+
+        if (srcLen == 0) {
+            return;
+        }
+
+        if (dim != -1) {
+
+            op.op(srcV, assignBaseIndices(srcLen / srcD[dim], srcD, srcS, dim), //
+                    dstV, srcD[dim], srcS[dim]);
+
+        } else {
+
+            op.op(srcV, null, dstV, -1, -1);
+        }
+    }
+
+    /**
+     * Dimension operations in support of {@link ArrayKernel#rdOp(int, double[], int[], int[], double[], int...)}.
+     */
+    final public static void rdOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, double[] dstV, //
+            int[] selectedDims) {
+
+        int srcLen = MappingOps.checkDimensions(srcV.length, srcD, srcS);
+
+        final RealDimensionOperation op;
+
+        switch (type) {
+
+        case RD_SUM:
+            op = RDSumOp;
+            break;
+
+        case RD_PROD:
+            op = RDProdOp;
+            break;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        int ndims = Control.checkEquals(srcD.length, srcS.length, //
+                "Dimensionality mismatch");
+
+        for (int dim : selectedDims) {
+            Control.checkTrue(dim >= 0 && dim < ndims, //
+                    "Invalid dimension");
+        }
+
+        if (srcLen == 0) {
+            return;
+        }
+
+        op.op(srcV, srcD, srcS, dstV, selectedDims);
+    }
+
+    // Dummy constructor.
+    DimensionOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ElementOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ElementOps.java
new file mode 100755
index 0000000..01d2115
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ElementOps.java
@@ -0,0 +1,1038 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import static shared.array.kernel.ArrayKernel.CA_PROD;
+import static shared.array.kernel.ArrayKernel.CA_SUM;
+import static shared.array.kernel.ArrayKernel.CE_ADD;
+import static shared.array.kernel.ArrayKernel.CE_DIV;
+import static shared.array.kernel.ArrayKernel.CE_MUL;
+import static shared.array.kernel.ArrayKernel.CE_SUB;
+import static shared.array.kernel.ArrayKernel.CTOR_ABS;
+import static shared.array.kernel.ArrayKernel.CTOR_IM;
+import static shared.array.kernel.ArrayKernel.CTOR_RE;
+import static shared.array.kernel.ArrayKernel.CU_ADD;
+import static shared.array.kernel.ArrayKernel.CU_CONJ;
+import static shared.array.kernel.ArrayKernel.CU_COS;
+import static shared.array.kernel.ArrayKernel.CU_EXP;
+import static shared.array.kernel.ArrayKernel.CU_FILL;
+import static shared.array.kernel.ArrayKernel.CU_MUL;
+import static shared.array.kernel.ArrayKernel.CU_RND;
+import static shared.array.kernel.ArrayKernel.CU_SHUFFLE;
+import static shared.array.kernel.ArrayKernel.CU_SIN;
+import static shared.array.kernel.ArrayKernel.IE_ADD;
+import static shared.array.kernel.ArrayKernel.IE_MAX;
+import static shared.array.kernel.ArrayKernel.IE_MIN;
+import static shared.array.kernel.ArrayKernel.IE_MUL;
+import static shared.array.kernel.ArrayKernel.IE_SUB;
+import static shared.array.kernel.ArrayKernel.IU_ADD;
+import static shared.array.kernel.ArrayKernel.IU_FILL;
+import static shared.array.kernel.ArrayKernel.IU_MUL;
+import static shared.array.kernel.ArrayKernel.IU_SHUFFLE;
+import static shared.array.kernel.ArrayKernel.RA_ENT;
+import static shared.array.kernel.ArrayKernel.RA_MAX;
+import static shared.array.kernel.ArrayKernel.RA_MIN;
+import static shared.array.kernel.ArrayKernel.RA_PROD;
+import static shared.array.kernel.ArrayKernel.RA_SUM;
+import static shared.array.kernel.ArrayKernel.RA_VAR;
+import static shared.array.kernel.ArrayKernel.RE_ADD;
+import static shared.array.kernel.ArrayKernel.RE_DIV;
+import static shared.array.kernel.ArrayKernel.RE_MAX;
+import static shared.array.kernel.ArrayKernel.RE_MIN;
+import static shared.array.kernel.ArrayKernel.RE_MUL;
+import static shared.array.kernel.ArrayKernel.RE_SUB;
+import static shared.array.kernel.ArrayKernel.RTOC_IM;
+import static shared.array.kernel.ArrayKernel.RTOC_RE;
+import static shared.array.kernel.ArrayKernel.RU_ABS;
+import static shared.array.kernel.ArrayKernel.RU_ADD;
+import static shared.array.kernel.ArrayKernel.RU_ATAN;
+import static shared.array.kernel.ArrayKernel.RU_COS;
+import static shared.array.kernel.ArrayKernel.RU_EXP;
+import static shared.array.kernel.ArrayKernel.RU_FILL;
+import static shared.array.kernel.ArrayKernel.RU_INV;
+import static shared.array.kernel.ArrayKernel.RU_LOG;
+import static shared.array.kernel.ArrayKernel.RU_MUL;
+import static shared.array.kernel.ArrayKernel.RU_POW;
+import static shared.array.kernel.ArrayKernel.RU_RND;
+import static shared.array.kernel.ArrayKernel.RU_SHUFFLE;
+import static shared.array.kernel.ArrayKernel.RU_SIN;
+import static shared.array.kernel.ArrayKernel.RU_SQR;
+import static shared.array.kernel.ArrayKernel.RU_SQRT;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A class for elementwise operations in pure Java.
+ * 
+ * @apiviz.has shared.array.kernel.ElementOps.RealBinaryOperation - - - argument
+ * @apiviz.has shared.array.kernel.ElementOps.RealAccumulatorOperation - - - argument
+ * @apiviz.has shared.array.kernel.ElementOps.RealToComplexOperation - - - argument
+ * @apiviz.has shared.array.kernel.ElementOps.IntegerBinaryOperation - - - argument
+ * @apiviz.has shared.array.kernel.ElementOps.ComplexBinaryOperation - - - argument
+ * @apiviz.has shared.array.kernel.ElementOps.ComplexAccumulatorOperation - - - argument
+ * @apiviz.has shared.array.kernel.ElementOps.ComplexToRealOperation - - - argument
+ * @author Roy Liu
+ */
+public class ElementOps {
+
+    /**
+     * Defines real binary operations.
+     */
+    protected interface RealBinaryOperation {
+
+        /**
+         * Performs a real binary operation.
+         */
+        public double op(double a, double b);
+    }
+
+    final static RealBinaryOperation REAddOp = new RealBinaryOperation() {
+
+        public double op(double a, double b) {
+            return a + b;
+        }
+    };
+
+    final static RealBinaryOperation RESubOp = new RealBinaryOperation() {
+
+        public double op(double a, double b) {
+            return a - b;
+        }
+    };
+
+    final static RealBinaryOperation REMulOp = new RealBinaryOperation() {
+
+        public double op(double a, double b) {
+            return a * b;
+        }
+    };
+
+    final static RealBinaryOperation REDivOp = new RealBinaryOperation() {
+
+        public double op(double a, double b) {
+            return a / b;
+        }
+    };
+
+    final static RealBinaryOperation REMaxOp = new RealBinaryOperation() {
+
+        public double op(double a, double b) {
+            return Math.max(a, b);
+        }
+    };
+
+    final static RealBinaryOperation REMinOp = new RealBinaryOperation() {
+
+        public double op(double a, double b) {
+            return Math.min(a, b);
+        }
+    };
+
+    /**
+     * Defines complex binary operations.
+     */
+    public interface ComplexBinaryOperation {
+
+        /**
+         * Performs a complex binary operation.
+         */
+        public void op(double[] res, double aRe, double aIm, double bRe, double bIm);
+    }
+
+    final static ComplexBinaryOperation CEAddOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double bRe, double bIm) {
+
+            res[0] = aRe + bRe;
+            res[1] = aIm + bIm;
+        }
+    };
+
+    final static ComplexBinaryOperation CESubOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double bRe, double bIm) {
+
+            res[0] = aRe - bRe;
+            res[1] = aIm - bIm;
+        }
+    };
+
+    final static ComplexBinaryOperation CEMulOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double bRe, double bIm) {
+
+            res[0] = aRe * bRe - aIm * bIm;
+            res[1] = aRe * bIm + bRe * aIm;
+        }
+    };
+
+    final static ComplexBinaryOperation CEDivOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double bRe, double bIm) {
+
+            res[0] = (aRe * bRe + aIm * bIm) / (bRe * bRe + bIm * bIm);
+            res[1] = (aIm * bRe - aRe * bIm) / (bRe * bRe + bIm * bIm);
+        }
+    };
+
+    /**
+     * Defines integer binary operations.
+     */
+    protected interface IntegerBinaryOperation {
+
+        /**
+         * Performs an integer binary operation.
+         */
+        public int op(int a, int b);
+    }
+
+    final static IntegerBinaryOperation IEAddOp = new IntegerBinaryOperation() {
+
+        public int op(int a, int b) {
+            return a + b;
+        }
+    };
+
+    final static IntegerBinaryOperation IESubOp = new IntegerBinaryOperation() {
+
+        public int op(int a, int b) {
+            return a - b;
+        }
+    };
+
+    final static IntegerBinaryOperation IEMulOp = new IntegerBinaryOperation() {
+
+        public int op(int a, int b) {
+            return a * b;
+        }
+    };
+
+    final static IntegerBinaryOperation IEMaxOp = new IntegerBinaryOperation() {
+
+        public int op(int a, int b) {
+            return Math.max(a, b);
+        }
+    };
+
+    final static IntegerBinaryOperation IEMinOp = new IntegerBinaryOperation() {
+
+        public int op(int a, int b) {
+            return Math.min(a, b);
+        }
+    };
+
+    /**
+     * Defines complex-to-real operations.
+     */
+    public interface ComplexToRealOperation {
+
+        /**
+         * Performs a complex-to-real operation.
+         */
+        public double op(double aRe, double aIm);
+    }
+
+    final static ComplexToRealOperation CTORAbsOp = new ComplexToRealOperation() {
+
+        public double op(double aRe, double aIm) {
+            return Math.sqrt(aRe * aRe + aIm * aIm);
+        }
+    };
+
+    final static ComplexToRealOperation CTORReOp = new ComplexToRealOperation() {
+
+        public double op(double aRe, double aIm) {
+            return aRe;
+        }
+    };
+
+    final static ComplexToRealOperation CTORImOp = new ComplexToRealOperation() {
+
+        public double op(double aRe, double aIm) {
+            return aIm;
+        }
+    };
+
+    /**
+     * Defines real-to-complex operations.
+     */
+    protected interface RealToComplexOperation {
+
+        /**
+         * Performs a real-to-complex operation.
+         */
+        public void op(double[] res, double a);
+    }
+
+    final static RealToComplexOperation RTOCReOp = new RealToComplexOperation() {
+
+        public void op(double[] res, double a) {
+
+            res[0] = a;
+            res[1] = 0;
+        }
+    };
+
+    final static RealToComplexOperation RTOCImOp = new RealToComplexOperation() {
+
+        public void op(double[] res, double a) {
+
+            res[0] = 0;
+            res[1] = a;
+        }
+    };
+
+    final static RealBinaryOperation RUAbsOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.abs(v);
+        }
+    };
+
+    final static RealBinaryOperation RUPowOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.pow(v, a);
+        }
+    };
+
+    final static RealBinaryOperation RUExpOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.exp(v);
+        }
+    };
+
+    final static RealBinaryOperation RURndOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Arithmetic.nextDouble(a);
+        }
+    };
+
+    final static RealBinaryOperation RULogOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.log(v);
+        }
+    };
+
+    final static RealBinaryOperation RUSqrtOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.sqrt(v);
+        }
+    };
+
+    final static RealBinaryOperation RUSqrOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return v * v;
+        }
+    };
+
+    final static RealBinaryOperation RUInvOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return a / v;
+        }
+    };
+
+    final static RealBinaryOperation RUCosOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.cos(v);
+        }
+    };
+
+    final static RealBinaryOperation RUSinOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.sin(v);
+        }
+    };
+
+    final static RealBinaryOperation RUAtanOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return Math.atan(v);
+        }
+    };
+
+    final static RealBinaryOperation RUFillOp = new RealBinaryOperation() {
+
+        public double op(double a, double v) {
+            return a;
+        }
+    };
+
+    final static ComplexBinaryOperation CUExpOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double vRe, double vIm) {
+
+            res[0] = Math.exp(vRe) * Math.cos(vIm);
+            res[1] = Math.exp(vRe) * Math.sin(vIm);
+        }
+    };
+
+    final static ComplexBinaryOperation CURndOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double vRe, double vIm) {
+
+            res[0] = Arithmetic.nextDouble(aRe);
+            res[1] = Arithmetic.nextDouble(aIm);
+        }
+    };
+
+    final static ComplexBinaryOperation CUConjOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double vRe, double vIm) {
+
+            res[0] = vRe;
+            res[1] = -vIm;
+        }
+    };
+
+    final static ComplexBinaryOperation CUCosOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double vRe, double vIm) {
+
+            CEMulOp.op(res, 0.0, 1.0, vRe, vIm);
+            CUExpOp.op(res, Double.NaN, Double.NaN, res[0], res[1]);
+
+            double xRe = res[0];
+            double xIm = res[1];
+
+            CEMulOp.op(res, 0.0, -1.0, vRe, vIm);
+            CUExpOp.op(res, Double.NaN, Double.NaN, res[0], res[1]);
+
+            double yRe = res[0];
+            double yIm = res[1];
+
+            CEAddOp.op(res, xRe, xIm, yRe, yIm);
+            CEDivOp.op(res, res[0], res[1], 2.0, 0.0);
+        }
+    };
+
+    final static ComplexBinaryOperation CUSinOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double vRe, double vIm) {
+
+            CEMulOp.op(res, 0.0, 1.0, vRe, vIm);
+            CUExpOp.op(res, Double.NaN, Double.NaN, res[0], res[1]);
+
+            double xRe = res[0];
+            double xIm = res[1];
+
+            CEMulOp.op(res, 0.0, -1.0, vRe, vIm);
+            CUExpOp.op(res, Double.NaN, Double.NaN, res[0], res[1]);
+
+            double yRe = res[0];
+            double yIm = res[1];
+
+            CESubOp.op(res, xRe, xIm, yRe, yIm);
+            CEDivOp.op(res, res[0], res[1], 0.0, 2.0);
+        }
+    };
+
+    final static ComplexBinaryOperation CUFillOp = new ComplexBinaryOperation() {
+
+        public void op(double[] res, double aRe, double aIm, double vRe, double vIm) {
+
+            res[0] = aRe;
+            res[1] = aIm;
+        }
+    };
+
+    final static IntegerBinaryOperation IUFillOp = new IntegerBinaryOperation() {
+
+        public int op(int a, int v) {
+            return a;
+        }
+    };
+
+    /**
+     * Defines real accumulator operations.
+     */
+    protected interface RealAccumulatorOperation {
+
+        /**
+         * Performs a real accumulator operation.
+         */
+        public double op(double[] srcV);
+    }
+
+    final static RealAccumulatorOperation RASumOp = new RealAccumulatorOperation() {
+
+        public double op(double[] srcV) {
+            return Arithmetic.sum(srcV);
+        }
+    };
+
+    final static RealAccumulatorOperation RAProdOp = new RealAccumulatorOperation() {
+
+        public double op(double[] srcV) {
+            return Arithmetic.product(srcV);
+        }
+    };
+
+    final static RealAccumulatorOperation RAMaxOp = new RealAccumulatorOperation() {
+
+        public double op(double[] srcV) {
+            return Arithmetic.max(srcV);
+        }
+    };
+
+    final static RealAccumulatorOperation RAMinOp = new RealAccumulatorOperation() {
+
+        public double op(double[] srcV) {
+            return Arithmetic.min(srcV);
+        }
+    };
+
+    final static RealAccumulatorOperation RAVarOp = new RealAccumulatorOperation() {
+
+        public double op(double[] srcV) {
+            return Arithmetic.variance(srcV);
+        }
+    };
+
+    final static RealAccumulatorOperation RAEntOp = new RealAccumulatorOperation() {
+
+        public double op(double[] srcV) {
+            return Arithmetic.entropy(srcV);
+        }
+    };
+
+    /**
+     * Defines complex accumulator operations.
+     */
+    protected interface ComplexAccumulatorOperation {
+
+        /**
+         * Performs a complex accumulator operation.
+         */
+        public double[] op(double[] srcV);
+    }
+
+    final static ComplexAccumulatorOperation CASumOp = new ComplexAccumulatorOperation() {
+
+        public double[] op(double[] srcV) {
+
+            double[] res = new double[2];
+
+            for (int i = 0, n = srcV.length; i < n; i += 2) {
+                CEAddOp.op(res, res[0], res[1], srcV[i], srcV[i + 1]);
+            }
+
+            return res;
+        }
+    };
+
+    final static ComplexAccumulatorOperation CAProdOp = new ComplexAccumulatorOperation() {
+
+        public double[] op(double[] srcV) {
+
+            double[] res = new double[] { 1.0, 0.0 };
+
+            for (int i = 0, n = srcV.length; i < n; i += 2) {
+                CEMulOp.op(res, res[0], res[1], srcV[i], srcV[i + 1]);
+            }
+
+            return res;
+        }
+    };
+
+    /**
+     * A real accumulator operation in support of {@link JavaArrayKernel#raOp(int, double[])}.
+     */
+    final public static double raOp(int type, double[] srcV) {
+
+        final RealAccumulatorOperation op;
+
+        switch (type) {
+
+        case RA_SUM:
+            op = RASumOp;
+            break;
+
+        case RA_PROD:
+            op = RAProdOp;
+            break;
+
+        case RA_ENT:
+            op = RAEntOp;
+            break;
+
+        case RA_VAR:
+            op = RAVarOp;
+            break;
+
+        case RA_MAX:
+            op = RAMaxOp;
+            break;
+
+        case RA_MIN:
+            op = RAMinOp;
+            break;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        return op.op(srcV);
+    }
+
+    /**
+     * A complex accumulator operation in support of {@link JavaArrayKernel#caOp(int, double[])}.
+     */
+    final public static double[] caOp(int type, double[] srcV) {
+
+        final ComplexAccumulatorOperation op;
+
+        switch (type) {
+
+        case CA_SUM:
+            op = CASumOp;
+            break;
+
+        case CA_PROD:
+            op = CAProdOp;
+            break;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        Control.checkTrue(srcV.length % 2 == 0);
+
+        return op.op(srcV);
+    }
+
+    /**
+     * A real unary elementwise operation in support of {@link JavaArrayKernel#ruOp(int, double, double[])}.
+     */
+    final public static void ruOp(int type, double a, double[] srcV) {
+
+        final RealBinaryOperation op;
+
+        switch (type) {
+
+        case RU_ADD:
+            op = REAddOp;
+            break;
+
+        case RU_MUL:
+            op = REMulOp;
+            break;
+
+        case RU_EXP:
+            op = RUExpOp;
+            break;
+
+        case RU_LOG:
+            op = RULogOp;
+            break;
+
+        case RU_POW:
+            op = RUPowOp;
+            break;
+
+        case RU_RND:
+            op = RURndOp;
+            break;
+
+        case RU_ABS:
+            op = RUAbsOp;
+            break;
+
+        case RU_SQRT:
+            op = RUSqrtOp;
+            break;
+
+        case RU_SQR:
+            op = RUSqrOp;
+            break;
+
+        case RU_INV:
+            op = RUInvOp;
+            break;
+
+        case RU_COS:
+            op = RUCosOp;
+            break;
+
+        case RU_SIN:
+            op = RUSinOp;
+            break;
+
+        case RU_ATAN:
+            op = RUAtanOp;
+            break;
+
+        case RU_FILL:
+            op = RUFillOp;
+            break;
+
+        case RU_SHUFFLE:
+            Arithmetic.shuffle(srcV);
+            return;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        for (int i = 0, n = srcV.length; i < n; i++) {
+            srcV[i] = op.op(a, srcV[i]);
+        }
+    }
+
+    /**
+     * A complex unary elementwise operation in support of {@link JavaArrayKernel#cuOp(int, double, double, double[])}.
+     */
+    final public static void cuOp(int type, double aRe, double aIm, double[] srcV) {
+
+        double[] tmp = new double[2];
+
+        int n = srcV.length;
+
+        final ComplexBinaryOperation op;
+
+        switch (type) {
+
+        case CU_ADD:
+            op = CEAddOp;
+            break;
+
+        case CU_MUL:
+            op = CEMulOp;
+            break;
+
+        case CU_EXP:
+            op = CUExpOp;
+            break;
+
+        case CU_RND:
+            op = CURndOp;
+            break;
+
+        case CU_CONJ:
+            op = CUConjOp;
+            break;
+
+        case CU_COS:
+            op = CUCosOp;
+            break;
+
+        case CU_SIN:
+            op = CUSinOp;
+            break;
+
+        case CU_FILL:
+            op = CUFillOp;
+            break;
+
+        case CU_SHUFFLE:
+
+            for (int i = n / 2; i > 1; i--) {
+
+                int index = Arithmetic.nextInt(i);
+
+                double tmpRe = srcV[2 * (i - 1)];
+                double tmpIm = srcV[2 * (i - 1) + 1];
+
+                srcV[2 * (i - 1)] = srcV[2 * index];
+                srcV[2 * (i - 1) + 1] = srcV[2 * index + 1];
+
+                srcV[2 * index] = tmpRe;
+                srcV[2 * index + 1] = tmpIm;
+            }
+
+            return;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        Control.checkTrue(n % 2 == 0);
+
+        for (int i = 0; i < n; i += 2) {
+
+            op.op(tmp, aRe, aIm, srcV[i], srcV[i + 1]);
+
+            srcV[i] = tmp[0];
+            srcV[i + 1] = tmp[1];
+        }
+    }
+
+    /**
+     * An integer unary elementwise operation in support of {@link JavaArrayKernel#iuOp(int, int, int[])}.
+     */
+    final public static void iuOp(int type, int a, int[] srcV) {
+
+        final IntegerBinaryOperation op;
+
+        switch (type) {
+
+        case IU_ADD:
+            op = IEAddOp;
+            break;
+
+        case IU_MUL:
+            op = IEMulOp;
+            break;
+
+        case IU_FILL:
+            op = IUFillOp;
+            break;
+
+        case IU_SHUFFLE:
+            Arithmetic.shuffle(srcV);
+            return;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+
+        for (int i = 0, n = srcV.length; i < n; i++) {
+            srcV[i] = op.op(a, srcV[i]);
+        }
+    }
+
+    /**
+     * A binary elementwise operation in support of {@link JavaArrayKernel#eOp(int, Object, Object, Object, boolean)}.
+     */
+    final public static void eOp(int type, Object lhs, Object rhs, Object dst, boolean isComplex) {
+
+        if (lhs instanceof double[] && rhs instanceof double[] && dst instanceof double[]) {
+
+            final double[] lhsV = (double[]) lhs;
+            final double[] rhsV = (double[]) rhs;
+            final double[] dstV = (double[]) dst;
+
+            if (isComplex) {
+
+                final ComplexBinaryOperation op;
+
+                switch (type) {
+
+                case CE_ADD:
+                    op = CEAddOp;
+                    break;
+
+                case CE_SUB:
+                    op = CESubOp;
+                    break;
+
+                case CE_MUL:
+                    op = CEMulOp;
+                    break;
+
+                case CE_DIV:
+                    op = CEDivOp;
+                    break;
+
+                default:
+                    throw new IllegalArgumentException();
+                }
+
+                double[] tmp = new double[2];
+
+                int n = Control.checkEquals(Control.checkEquals(lhsV.length, rhsV.length), dstV.length);
+
+                Control.checkTrue(n % 2 == 0);
+
+                for (int i = 0; i < n; i += 2) {
+
+                    op.op(tmp, lhsV[i], lhsV[i + 1], rhsV[i], rhsV[i + 1]);
+
+                    dstV[i] = tmp[0];
+                    dstV[i + 1] = tmp[1];
+                }
+
+            } else {
+
+                final RealBinaryOperation op;
+
+                switch (type) {
+
+                case RE_ADD:
+                    op = REAddOp;
+                    break;
+
+                case RE_SUB:
+                    op = RESubOp;
+                    break;
+
+                case RE_MUL:
+                    op = REMulOp;
+                    break;
+
+                case RE_DIV:
+                    op = REDivOp;
+                    break;
+
+                case RE_MAX:
+                    op = REMaxOp;
+                    break;
+
+                case RE_MIN:
+                    op = REMinOp;
+                    break;
+
+                default:
+                    throw new IllegalArgumentException();
+                }
+
+                for (int i = 0, n = Control.checkEquals(Control.checkEquals(lhsV.length, rhsV.length), dstV.length); //
+                i < n; i++) {
+                    dstV[i] = op.op(lhsV[i], rhsV[i]);
+                }
+            }
+
+        } else if (lhs instanceof int[] && rhs instanceof int[] && dst instanceof int[]) {
+
+            final int[] lhsV = (int[]) lhs;
+            final int[] rhsV = (int[]) rhs;
+            final int[] dstV = (int[]) dst;
+
+            final IntegerBinaryOperation op;
+
+            switch (type) {
+
+            case IE_ADD:
+                op = IEAddOp;
+                break;
+
+            case IE_SUB:
+                op = IESubOp;
+                break;
+
+            case IE_MUL:
+                op = IEMulOp;
+                break;
+
+            case IE_MAX:
+                op = IEMaxOp;
+                break;
+
+            case IE_MIN:
+                op = IEMinOp;
+                break;
+
+            default:
+                throw new IllegalArgumentException();
+            }
+
+            for (int i = 0, n = Control.checkEquals(Control.checkEquals(lhsV.length, rhsV.length), dstV.length); //
+            i < n; i++) {
+                dstV[i] = op.op(lhsV[i], rhsV[i]);
+            }
+
+        } else {
+
+            throw new IllegalArgumentException("Invalid array types");
+        }
+    }
+
+    /**
+     * A type conversion operation in support of {@link JavaArrayKernel#convert(int, Object, boolean, Object, boolean)}.
+     */
+    final public static void convert(int type, Object srcV, boolean isSrcComplex, Object dstV, boolean isDstComplex) {
+
+        if (srcV instanceof double[] && !isSrcComplex && dstV instanceof double[] && isDstComplex) {
+
+            double[] srcV_d = (double[]) srcV;
+            double[] dstV_d = (double[]) dstV;
+
+            final RealToComplexOperation op;
+
+            switch (type) {
+
+            case RTOC_RE:
+                op = RTOCReOp;
+                break;
+
+            case RTOC_IM:
+                op = RTOCImOp;
+                break;
+
+            default:
+                throw new IllegalArgumentException();
+            }
+
+            double[] tmp = new double[2];
+
+            for (int i = 0, j = 0, n = Control.checkEquals(srcV_d.length * 2, dstV_d.length) / 2; //
+            i < n; i++, j += 2) {
+
+                op.op(tmp, srcV_d[i]);
+
+                dstV_d[j] = tmp[0];
+                dstV_d[j + 1] = tmp[1];
+            }
+
+        } else if (srcV instanceof double[] && isSrcComplex && dstV instanceof double[] && !isDstComplex) {
+
+            double[] srcV_d = (double[]) srcV;
+            double[] dstV_d = (double[]) dstV;
+
+            final ComplexToRealOperation op;
+
+            switch (type) {
+
+            case CTOR_ABS:
+                op = CTORAbsOp;
+                break;
+
+            case CTOR_RE:
+                op = CTORReOp;
+                break;
+
+            case CTOR_IM:
+                op = CTORImOp;
+                break;
+
+            default:
+                throw new IllegalArgumentException();
+            }
+
+            for (int i = 0, j = 0, n = Control.checkEquals(srcV_d.length, dstV_d.length * 2); //
+            i < n; i += 2, j++) {
+                dstV_d[j] = op.op(srcV_d[i], srcV_d[i + 1]);
+            }
+
+        } else if (srcV instanceof int[] && !isSrcComplex && dstV instanceof double[] && !isDstComplex) {
+
+            int[] srcV_i = (int[]) srcV;
+            double[] dstV_d = (double[]) dstV;
+
+            for (int i = 0, n = Control.checkEquals(srcV_i.length, dstV_d.length); i < n; i++) {
+                dstV_d[i] = srcV_i[i];
+            }
+
+        } else {
+
+            throw new IllegalArgumentException("Invalid arguments");
+        }
+    }
+
+    // Dummy constructor.
+    ElementOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/IndexOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/IndexOps.java
new file mode 100755
index 0000000..2abf267
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/IndexOps.java
@@ -0,0 +1,85 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A class for indexing operations in pure Java.
+ * 
+ * @author Roy Liu
+ */
+public class IndexOps {
+
+    /**
+     * An operation in support of {@link JavaArrayKernel#find(int[], int[], int[], int[])}.
+     */
+    final public static int[] find(int[] srcV, int[] srcD, int[] srcS, int[] logical) {
+
+        int ndims = srcD.length;
+
+        Control.checkTrue(ndims == srcS.length //
+                && ndims == logical.length);
+
+        MappingOps.checkDimensions(srcV.length, srcD, srcS);
+
+        int activeDim = Arithmetic.indexOf(logical, -1);
+
+        Control.checkTrue(Arithmetic.count(logical, -1) == 1, //
+                "The dimension marker must be unique");
+
+        int offset = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            if (dim != activeDim) {
+
+                int index = logical[dim];
+
+                offset += index * srcS[dim];
+
+                Control.checkTrue(index >= 0 && index < srcD[dim], //
+                        "Invalid index");
+            }
+        }
+
+        int upper = 0;
+        int size = srcD[activeDim];
+        int stride = srcS[activeDim];
+
+        for (int i = 0, physical = offset; i < size; i++, physical += stride) {
+
+            if (srcV[physical] >= 0) {
+                upper++;
+            }
+        }
+
+        int[] res = new int[upper];
+
+        for (int i = 0, physical = offset; i < upper; i++, physical += stride) {
+            res[i] = srcV[physical];
+        }
+
+        return res;
+    }
+
+    // Dummy constructor.
+    IndexOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/JavaArrayKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/JavaArrayKernel.java
new file mode 100755
index 0000000..96804b7
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/JavaArrayKernel.java
@@ -0,0 +1,170 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.array.sparse.SparseArrayState;
+import shared.util.Arithmetic;
+
+/**
+ * A pure Java implementation of {@link ArrayKernel}.
+ * 
+ * @apiviz.uses shared.array.kernel.DimensionOps
+ * @apiviz.uses shared.array.kernel.ElementOps
+ * @apiviz.uses shared.array.kernel.IndexOps
+ * @apiviz.uses shared.array.kernel.LinearAlgebraOps
+ * @apiviz.uses shared.array.kernel.MappingOps
+ * @apiviz.uses shared.array.kernel.MatrixOps
+ * @apiviz.uses shared.array.kernel.SparseOps
+ * @author Roy Liu
+ */
+public class JavaArrayKernel implements ArrayKernel {
+
+    /**
+     * Default constructor.
+     */
+    public JavaArrayKernel() {
+    }
+
+    //
+
+    public void randomize() {
+        Arithmetic.randomize();
+    }
+
+    public void derandomize() {
+        Arithmetic.derandomize();
+    }
+
+    //
+
+    public void map(int[] bounds, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS) {
+        MappingOps.map(bounds, srcV, srcD, srcS, dstV, dstD, dstS);
+    }
+
+    public void slice( //
+            int[] slices, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS) {
+        MappingOps.slice(slices, srcV, srcD, srcS, dstV, dstD, dstS);
+    }
+
+    //
+
+    public void rrOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS, //
+            int... selectedDims) {
+        DimensionOps.rrOp(type, srcV, srcD, srcS, dstV, dstD, dstS, selectedDims);
+    }
+
+    public void riOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, int[] dstV, //
+            int dim) {
+        DimensionOps.riOp(type, srcV, srcD, srcS, dstV, dim);
+    }
+
+    public void rdOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, double[] dstV, //
+            int... selectedDims) {
+        DimensionOps.rdOp(type, srcV, srcD, srcS, dstV, selectedDims);
+    }
+
+    //
+
+    public double raOp(int type, double[] srcV) {
+        return ElementOps.raOp(type, srcV);
+    }
+
+    public double[] caOp(int type, double[] srcV) {
+        return ElementOps.caOp(type, srcV);
+    }
+
+    public void ruOp(int type, double a, double[] srcV) {
+        ElementOps.ruOp(type, a, srcV);
+    }
+
+    public void cuOp(int type, double aRe, double aIm, double[] srcV) {
+        ElementOps.cuOp(type, aRe, aIm, srcV);
+    }
+
+    public void iuOp(int type, int a, int[] srcV) {
+        ElementOps.iuOp(type, a, srcV);
+    }
+
+    public void eOp(int type, Object lhsV, Object rhsV, Object dstV, boolean isComplex) {
+        ElementOps.eOp(type, lhsV, rhsV, dstV, isComplex);
+    }
+
+    public void convert(int type, Object srcV, boolean isSrcComplex, Object dstV, boolean isDstComplex) {
+        ElementOps.convert(type, srcV, isSrcComplex, dstV, isDstComplex);
+    }
+
+    //
+
+    public void mul(double[] lhsV, double[] rhsV, int lr, int rc, double[] dstV, boolean isComplex) {
+        MatrixOps.mul(lhsV, rhsV, lr, rc, dstV, isComplex);
+    }
+
+    public void diag(double[] srcV, double[] dstV, int size, boolean isComplex) {
+        MatrixOps.diag(srcV, dstV, size, isComplex);
+    }
+
+    //
+
+    public void svd(double[] srcV, int srcStrideRow, int srcStrideCol, //
+            double[] uV, double[] sV, double[] vV, //
+            int nrows, int ncols) {
+        LinearAlgebraOps.svd(srcV, srcStrideRow, srcStrideCol, uV, sV, vV, nrows, ncols);
+    }
+
+    public void eigs(double[] srcV, double[] vecV, double[] valV, int size) {
+        LinearAlgebraOps.eigs(srcV, vecV, valV, size);
+    }
+
+    public void invert(double[] srcV, double[] dstV, int size) {
+        LinearAlgebraOps.invert(srcV, dstV, size);
+    }
+
+    //
+
+    public int[] find(int[] srcV, int[] srcD, int[] srcS, int[] logical) {
+        return IndexOps.find(srcV, srcD, srcS, logical);
+    }
+
+    //
+
+    public <V> SparseArrayState<V> insertSparse( //
+            V oldV, int[] oldD, int[] oldS, int[] oldDO, int[] oldI, //
+            V newV, int[] newI) {
+        return SparseOps.insert(oldV, oldD, oldS, oldDO, oldI, newV, newI);
+    }
+
+    public <V> SparseArrayState<V> sliceSparse(int[] slices, //
+            V srcV, int[] srcD, int[] srcS, int[] srcDO, //
+            int[] srcI, int[] srcIO, int[] srcII, //
+            V dstV, int[] dstD, int[] dstS, int[] dstDO, //
+            int[] dstI, int[] dstIO, int[] dstII) {
+        return SparseOps.slice(slices, //
+                srcV, srcD, srcS, srcDO, //
+                srcI, srcIO, srcII, //
+                dstV, dstD, dstS, dstDO, //
+                dstI, dstIO, dstII);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/LinearAlgebraOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/LinearAlgebraOps.java
new file mode 100755
index 0000000..c936a3f
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/LinearAlgebraOps.java
@@ -0,0 +1,1180 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import static shared.array.kernel.ElementOps.CEDivOp;
+import static shared.array.kernel.ElementOps.CTORAbsOp;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A class for linear algebra operations in pure Java.
+ * 
+ * @author Roy Liu
+ */
+public class LinearAlgebraOps {
+
+    /**
+     * A singular value decomposition operation in support of
+     * {@link JavaArrayKernel#svd(double[], int, int, double[], double[], double[], int, int)}.
+     */
+    final public static void svd(double[] srcV, int srcStrideRow, int srcStrideCol, //
+            double[] uV, double[] sV, double[] vV, //
+            int nrows, int ncols) {
+
+        Control.checkTrue(nrows >= ncols //
+                && srcV.length == nrows * ncols //
+                && uV.length == nrows * ncols //
+                && sV.length == ncols //
+                && vV.length == ncols * ncols //
+                && ((srcStrideRow == ncols && srcStrideCol == 1) //
+                || (srcStrideRow == 1 && srcStrideCol == nrows)), //
+                "Invalid arguments");
+
+        int uStrideRow = ncols;
+        int vStrideRow = ncols;
+
+        double[] e = new double[ncols];
+        double[] work = new double[nrows];
+        double[] a = srcV.clone();
+
+        // Reduce A to bidiagonal form, storing the diagonal elements
+        // in s and the super-diagonal elements in e.
+
+        int nct = Math.min(nrows - 1, ncols);
+        int nrt = Math.max(0, Math.min(ncols - 2, nrows));
+        for (int k = 0, l = Math.max(nct, nrt); k < l; k++) {
+            if (k < nct) {
+
+                // Compute the transformation for the k-th column and
+                // place the k-th diagonal in s[k].
+                // Compute 2-norm of k-th column without under/overflow.
+                sV[k] = 0;
+                for (int i = k; i < nrows; i++) {
+                    sV[k] = CTORAbsOp.op(sV[k], a[srcStrideRow * (i) + srcStrideCol * (k)]);
+                }
+                if (sV[k] != 0.0) {
+                    if (a[srcStrideRow * (k) + srcStrideCol * (k)] < 0.0) {
+                        sV[k] = -sV[k];
+                    }
+                    for (int i = k; i < nrows; i++) {
+                        a[srcStrideRow * (i) + srcStrideCol * (k)] /= sV[k];
+                    }
+                    a[srcStrideRow * (k) + srcStrideCol * (k)] += 1.0;
+                }
+                sV[k] = -sV[k];
+            }
+            for (int j = k + 1; j < ncols; j++) {
+                if ((k < nct) & (sV[k] != 0.0)) {
+
+                    // Apply the transformation.
+
+                    double t = 0;
+                    for (int i = k; i < nrows; i++) {
+                        t += a[srcStrideRow * (i) + srcStrideCol * (k)] * a[srcStrideRow * (i) + srcStrideCol * (j)];
+                    }
+                    t = -t / a[srcStrideRow * (k) + srcStrideCol * (k)];
+                    for (int i = k; i < nrows; i++) {
+                        a[srcStrideRow * (i) + srcStrideCol * (j)] += t * a[srcStrideRow * (i) + srcStrideCol * (k)];
+                    }
+                }
+
+                // Place the k-th row of A into e for the
+                // subsequent calculation of the row transformation.
+
+                e[j] = a[srcStrideRow * (k) + srcStrideCol * (j)];
+            }
+            if (k < nct) {
+
+                // Place the transformation in U for subsequent back
+                // multiplication.
+
+                for (int i = k; i < nrows; i++) {
+                    uV[uStrideRow * (i) + (k)] = a[srcStrideRow * (i) + srcStrideCol * (k)];
+                }
+            }
+            if (k < nrt) {
+
+                // Compute the k-th row transformation and place the
+                // k-th super-diagonal in e[k].
+                // Compute 2-norm without under/overflow.
+                e[k] = 0;
+                for (int i = k + 1; i < ncols; i++) {
+                    e[k] = CTORAbsOp.op(e[k], e[i]);
+                }
+                if (e[k] != 0.0) {
+                    if (e[k + 1] < 0.0) {
+                        e[k] = -e[k];
+                    }
+                    for (int i = k + 1; i < ncols; i++) {
+                        e[i] /= e[k];
+                    }
+                    e[k + 1] += 1.0;
+                }
+                e[k] = -e[k];
+                if ((k + 1 < nrows) & (e[k] != 0.0)) {
+
+                    // Apply the transformation.
+
+                    for (int i = k + 1; i < nrows; i++) {
+                        work[i] = 0.0;
+                    }
+                    for (int j = k + 1; j < ncols; j++) {
+                        for (int i = k + 1; i < nrows; i++) {
+                            work[i] += e[j] * a[srcStrideRow * (i) + srcStrideCol * (j)];
+                        }
+                    }
+                    for (int j = k + 1; j < ncols; j++) {
+                        double t = -e[j] / e[k + 1];
+                        for (int i = k + 1; i < nrows; i++) {
+                            a[srcStrideRow * (i) + srcStrideCol * (j)] += t * work[i];
+                        }
+                    }
+                }
+
+                // Place the transformation in V for subsequent
+                // back multiplication.
+
+                for (int i = k + 1; i < ncols; i++) {
+                    vV[vStrideRow * (i) + (k)] = e[i];
+                }
+            }
+        }
+
+        // Set up the final bidiagonal matrix or order p.
+
+        int p = ncols;
+        if (nct < ncols) {
+            sV[nct] = a[srcStrideRow * (nct) + srcStrideCol * (nct)];
+        }
+        if (nrows < p) {
+            sV[p - 1] = 0.0;
+        }
+        if (nrt + 1 < p) {
+            e[nrt] = a[srcStrideRow * (nrt) + srcStrideCol * (p - 1)];
+        }
+        e[p - 1] = 0.0;
+
+        // If required, generate U.
+
+        for (int j = nct; j < ncols; j++) {
+            for (int i = 0; i < nrows; i++) {
+                uV[uStrideRow * (i) + (j)] = 0.0;
+            }
+            uV[uStrideRow * (j) + (j)] = 1.0;
+        }
+        for (int k = nct - 1; k >= 0; k--) {
+            if (sV[k] != 0.0) {
+                for (int j = k + 1; j < ncols; j++) {
+                    double t = 0;
+                    for (int i = k; i < nrows; i++) {
+                        t += uV[uStrideRow * (i) + (k)] * uV[uStrideRow * (i) + (j)];
+                    }
+                    t = -t / uV[uStrideRow * (k) + (k)];
+                    for (int i = k; i < nrows; i++) {
+                        uV[uStrideRow * (i) + (j)] += t * uV[uStrideRow * (i) + (k)];
+                    }
+                }
+                for (int i = k; i < nrows; i++) {
+                    uV[uStrideRow * (i) + (k)] = -uV[uStrideRow * (i) + (k)];
+                }
+                uV[uStrideRow * (k) + (k)] = 1.0 + uV[uStrideRow * (k) + (k)];
+                for (int i = 0; i < k - 1; i++) {
+                    uV[uStrideRow * (i) + (k)] = 0.0;
+                }
+            } else {
+                for (int i = 0; i < nrows; i++) {
+                    uV[uStrideRow * (i) + (k)] = 0.0;
+                }
+                uV[uStrideRow * (k) + (k)] = 1.0;
+            }
+        }
+
+        // If required, generate V.
+
+        for (int k = ncols - 1; k >= 0; k--) {
+            if ((k < nrt) & (e[k] != 0.0)) {
+                for (int j = k + 1; j < ncols; j++) {
+                    double t = 0;
+                    for (int i = k + 1; i < ncols; i++) {
+                        t += vV[vStrideRow * (i) + (k)] * vV[vStrideRow * (i) + (j)];
+                    }
+                    t = -t / vV[vStrideRow * (k + 1) + (k)];
+                    for (int i = k + 1; i < ncols; i++) {
+                        vV[vStrideRow * (i) + (j)] += t * vV[vStrideRow * (i) + (k)];
+                    }
+                }
+            }
+            for (int i = 0; i < ncols; i++) {
+                vV[vStrideRow * (i) + (k)] = 0.0;
+            }
+            vV[vStrideRow * (k) + (k)] = 1.0;
+        }
+
+        // Main iteration loop for the singular values.
+
+        int pp = p - 1;
+        int iter = 0;
+        double eps = Math.pow(2.0, -52.0);
+        double tiny = Math.pow(2.0, -966.0);
+        while (p > 0) {
+            int k, kase;
+
+            // Here is where a test for too many iterations would go.
+
+            // This section of the program inspects for
+            // negligible elements in the s and e arrays. On
+            // completion the variables kase and k are set as follows.
+
+            // kase = 1 if s(p) and e[k-1] are negligible and k<p
+            // kase = 2 if s(k) is negligible and k<p
+            // kase = 3 if e[k-1] is negligible, k<p, and
+            // s(k), ..., s(p) are not negligible (qr step).
+            // kase = 4 if e(p-1) is negligible (convergence).
+
+            for (k = p - 2; k >= -1; k--) {
+                if (k == -1) {
+                    break;
+                }
+                if (Math.abs(e[k]) <= tiny + eps * (Math.abs(sV[k]) + Math.abs(sV[k + 1]))) {
+                    e[k] = 0.0;
+                    break;
+                }
+            }
+            if (k == p - 2) {
+                kase = 4;
+            } else {
+                int ks;
+                for (ks = p - 1; ks >= k; ks--) {
+                    if (ks == k) {
+                        break;
+                    }
+                    double t = (ks != p ? Math.abs(e[ks]) : 0.) + (ks != k + 1 ? Math.abs(e[ks - 1]) : 0.);
+                    if (Math.abs(sV[ks]) <= tiny + eps * t) {
+                        sV[ks] = 0.0;
+                        break;
+                    }
+                }
+                if (ks == k) {
+                    kase = 3;
+                } else if (ks == p - 1) {
+                    kase = 1;
+                } else {
+                    kase = 2;
+                    k = ks;
+                }
+            }
+            k++;
+
+            // Perform the task indicated by kase.
+
+            switch (kase) {
+
+            // Deflate negligible s(p).
+
+            case 1: {
+                double f = e[p - 2];
+                e[p - 2] = 0.0;
+                for (int j = p - 2; j >= k; j--) {
+                    double t = CTORAbsOp.op(sV[j], f);
+                    double cs = sV[j] / t;
+                    double sn = f / t;
+                    sV[j] = t;
+                    if (j != k) {
+                        f = -sn * e[j - 1];
+                        e[j - 1] = cs * e[j - 1];
+                    }
+                    for (int i = 0; i < ncols; i++) {
+                        t = cs * vV[vStrideRow * (i) + (j)] + sn * vV[vStrideRow * (i) + (p - 1)];
+                        vV[vStrideRow * (i) + (p - 1)] = -sn * vV[vStrideRow * (i) + (j)] + cs
+                                * vV[vStrideRow * (i) + (p - 1)];
+                        vV[vStrideRow * (i) + (j)] = t;
+                    }
+                }
+            }
+                break;
+
+            // Split at negligible s(k).
+
+            case 2: {
+                double f = e[k - 1];
+                e[k - 1] = 0.0;
+                for (int j = k; j < p; j++) {
+                    double t = CTORAbsOp.op(sV[j], f);
+                    double cs = sV[j] / t;
+                    double sn = f / t;
+                    sV[j] = t;
+                    f = -sn * e[j];
+                    e[j] = cs * e[j];
+                    for (int i = 0; i < nrows; i++) {
+                        t = cs * uV[uStrideRow * (i) + (j)] + sn * uV[uStrideRow * (i) + (k - 1)];
+                        uV[uStrideRow * (i) + (k - 1)] = -sn * uV[uStrideRow * (i) + (j)] + cs
+                                * uV[uStrideRow * (i) + (k - 1)];
+                        uV[uStrideRow * (i) + (j)] = t;
+                    }
+                }
+            }
+                break;
+
+            // Perform one qr step.
+
+            case 3: {
+
+                // Calculate the shift.
+
+                double scale = Math.max(Math.max(Math.max(Math.max(Math.abs(sV[p - 1]), Math.abs(sV[p - 2])), Math
+                        .abs(e[p - 2])), Math.abs(sV[k])), Math.abs(e[k]));
+                double sp = sV[p - 1] / scale;
+                double spm1 = sV[p - 2] / scale;
+                double epm1 = e[p - 2] / scale;
+                double sk = sV[k] / scale;
+                double ek = e[k] / scale;
+                double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
+                double c = (sp * epm1) * (sp * epm1);
+                double shift = 0.0;
+                if ((b != 0.0) | (c != 0.0)) {
+                    shift = Math.sqrt(b * b + c);
+                    if (b < 0.0) {
+                        shift = -shift;
+                    }
+                    shift = c / (b + shift);
+                }
+                double f = (sk + sp) * (sk - sp) + shift;
+                double g = sk * ek;
+
+                // Chase zeros.
+
+                for (int j = k; j < p - 1; j++) {
+                    double t = CTORAbsOp.op(f, g);
+                    double cs = f / t;
+                    double sn = g / t;
+                    if (j != k) {
+                        e[j - 1] = t;
+                    }
+                    f = cs * sV[j] + sn * e[j];
+                    e[j] = cs * e[j] - sn * sV[j];
+                    g = sn * sV[j + 1];
+                    sV[j + 1] = cs * sV[j + 1];
+                    for (int i = 0; i < ncols; i++) {
+                        t = cs * vV[vStrideRow * (i) + (j)] + sn * vV[vStrideRow * (i) + (j + 1)];
+                        vV[vStrideRow * (i) + (j + 1)] = -sn * vV[vStrideRow * (i) + (j)] + cs
+                                * vV[vStrideRow * (i) + (j + 1)];
+                        vV[vStrideRow * (i) + (j)] = t;
+                    }
+                    t = CTORAbsOp.op(f, g);
+                    cs = f / t;
+                    sn = g / t;
+                    sV[j] = t;
+                    f = cs * e[j] + sn * sV[j + 1];
+                    sV[j + 1] = -sn * e[j] + cs * sV[j + 1];
+                    g = sn * e[j + 1];
+                    e[j + 1] = cs * e[j + 1];
+                    if (j < nrows - 1) {
+                        for (int i = 0; i < nrows; i++) {
+                            t = cs * uV[uStrideRow * (i) + (j)] + sn * uV[uStrideRow * (i) + (j + 1)];
+                            uV[uStrideRow * (i) + (j + 1)] = -sn * uV[uStrideRow * (i) + (j)] + cs
+                                    * uV[uStrideRow * (i) + (j + 1)];
+                            uV[uStrideRow * (i) + (j)] = t;
+                        }
+                    }
+                }
+                e[p - 2] = f;
+                iter = iter + 1;
+            }
+                break;
+
+            // Convergence.
+
+            case 4: {
+
+                // Make the singular values positive.
+
+                if (sV[k] <= 0.0) {
+                    sV[k] = (sV[k] < 0.0 ? -sV[k] : 0.0);
+                    for (int i = 0; i <= pp; i++) {
+                        vV[vStrideRow * (i) + (k)] = -vV[vStrideRow * (i) + (k)];
+                    }
+                }
+
+                // Order the singular values.
+
+                while (k < pp) {
+                    if (sV[k] >= sV[k + 1]) {
+                        break;
+                    }
+                    double t = sV[k];
+                    sV[k] = sV[k + 1];
+                    sV[k + 1] = t;
+                    if (k < ncols - 1) {
+                        for (int i = 0; i < ncols; i++) {
+                            t = vV[vStrideRow * (i) + (k + 1)];
+                            vV[vStrideRow * (i) + (k + 1)] = vV[vStrideRow * (i) + (k)];
+                            vV[vStrideRow * (i) + (k)] = t;
+                        }
+                    }
+                    if (k < nrows - 1) {
+                        for (int i = 0; i < nrows; i++) {
+                            t = uV[uStrideRow * (i) + (k + 1)];
+                            uV[uStrideRow * (i) + (k + 1)] = uV[uStrideRow * (i) + (k)];
+                            uV[uStrideRow * (i) + (k)] = t;
+                        }
+                    }
+                    k++;
+                }
+                iter = 0;
+                p--;
+            }
+                break;
+            }
+        }
+    }
+
+    /**
+     * An eigenvector and eigenvalue operation in support of
+     * {@link JavaArrayKernel#eigs(double[], double[], double[], int)}.
+     */
+    final public static void eigs(double[] srcV, double[] vecV, double[] valV, int size) {
+
+        Control.checkTrue(srcV.length == size * size //
+                && vecV.length == size * size //
+                && valV.length == 2 * size, //
+                "Invalid arguments");
+
+        double[] h = srcV.clone();
+
+        hessenberg(h, vecV, size);
+        hessenbergToSchur(h, vecV, valV, size);
+    }
+
+    /**
+     * Computes the reduction to Hessenberg form.
+     * 
+     * @param h
+     *            the working Hessenberg matrix.
+     * @param vecV
+     *            the eigenvectors.
+     * @param size
+     *            the matrix size.
+     */
+    final protected static void hessenberg(double[] h, double[] vecV, int size) {
+
+        int hStrideRow = size;
+        int vStrideRow = size;
+
+        double[] ort = new double[size];
+
+        // This is derived from the Algol procedures orthes and ortran,
+        // by Martin and Wilkinson, Handbook for Auto. Comp.,
+        // Vol.ii-Linear Algebra, and the corresponding
+        // Fortran subroutines in EISPACK.
+
+        int low = 0;
+        int high = size - 1;
+
+        for (int m = low + 1; m <= high - 1; m++) {
+
+            // Scale column.
+
+            double scale = 0.0;
+            for (int i = m; i <= high; i++) {
+                scale = scale + Math.abs(h[hStrideRow * (i) + (m - 1)]);
+            }
+            if (scale != 0.0) {
+
+                // Compute Householder transformation.
+
+                double hAcc = 0.0;
+                for (int i = high; i >= m; i--) {
+                    ort[i] = h[hStrideRow * (i) + (m - 1)] / scale;
+                    hAcc += ort[i] * ort[i];
+                }
+                double g = Math.sqrt(hAcc);
+                if (ort[m] > 0) {
+                    g = -g;
+                }
+                hAcc = hAcc - ort[m] * g;
+                ort[m] = ort[m] - g;
+
+                // Apply Householder similarity transformation
+                // H = (I-u*u'/h)*H*(I-u*u')/h)
+
+                for (int j = m; j < size; j++) {
+                    double f = 0.0;
+                    for (int i = high; i >= m; i--) {
+                        f += ort[i] * h[hStrideRow * (i) + (j)];
+                    }
+                    f = f / hAcc;
+                    for (int i = m; i <= high; i++) {
+                        h[hStrideRow * (i) + (j)] -= f * ort[i];
+                    }
+                }
+
+                for (int i = 0; i <= high; i++) {
+                    double f = 0.0;
+                    for (int j = high; j >= m; j--) {
+                        f += ort[j] * h[hStrideRow * (i) + (j)];
+                    }
+                    f = f / hAcc;
+                    for (int j = m; j <= high; j++) {
+                        h[hStrideRow * (i) + (j)] -= f * ort[j];
+                    }
+                }
+                ort[m] = scale * ort[m];
+                h[hStrideRow * (m) + (m - 1)] = scale * g;
+            }
+        }
+
+        // Accumulate transformations (Algol's ortran).
+
+        for (int i = 0; i < size; i++) {
+            for (int j = 0; j < size; j++) {
+                vecV[vStrideRow * (i) + (j)] = (i == j ? 1.0 : 0.0);
+            }
+        }
+
+        for (int m = high - 1; m >= low + 1; m--) {
+            if (h[hStrideRow * (m) + (m - 1)] != 0.0) {
+                for (int i = m + 1; i <= high; i++) {
+                    ort[i] = h[hStrideRow * (i) + (m - 1)];
+                }
+                for (int j = m; j <= high; j++) {
+                    double g = 0.0;
+                    for (int i = m; i <= high; i++) {
+                        g += ort[i] * vecV[vStrideRow * (i) + (j)];
+                    }
+                    // Double division avoids possible underflow
+                    g = (g / ort[m]) / h[hStrideRow * (m) + (m - 1)];
+                    for (int i = m; i <= high; i++) {
+                        vecV[vStrideRow * (i) + (j)] += g * ort[i];
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Computes the reduction from Hessenberg form to real Schur form.
+     * 
+     * @param h
+     *            the working Hessenberg matrix.
+     * @param vecV
+     *            the eigenvectors.
+     * @param valV
+     *            the eigenvalues.
+     * @param size
+     *            the matrix size.
+     */
+    final protected static void hessenbergToSchur(double[] h, double[] vecV, double[] valV, int size) {
+
+        int hStrideRow = size;
+        int vStrideRow = size;
+
+        double[] cdiv = new double[2];
+
+        // This is derived from the Algol procedure hqr2,
+        // by Martin and Wilkinson, Handbook for Auto. Comp.,
+        // Vol.ii-Linear Algebra, and the corresponding
+        // Fortran subroutine in EISPACK.
+
+        // Initialize
+
+        int nn = size;
+        int n = nn - 1;
+        int low = 0;
+        int high = nn - 1;
+        double eps = Math.pow(2.0, -52.0);
+        double exShift = 0.0;
+        double p = 0, q = 0, r = 0, s = 0, z = 0, t, w, x, y;
+
+        // Store roots isolated by balanc and compute matrix norm
+
+        double norm = 0.0;
+        for (int i = 0; i < nn; i++) {
+            if (i < low || i > high) {
+                valV[2 * (i)] = h[hStrideRow * (i) + (i)];
+                valV[2 * (i) + 1] = 0.0;
+            }
+            for (int j = Math.max(i - 1, 0); j < nn; j++) {
+                norm = norm + Math.abs(h[hStrideRow * (i) + (j)]);
+            }
+        }
+
+        // Outer loop over eigenvalue index
+
+        int iter = 0;
+        while (n >= low) {
+
+            // Look for single small sub-diagonal element
+
+            int l = n;
+            while (l > low) {
+                s = Math.abs(h[hStrideRow * (l - 1) + (l - 1)]) + Math.abs(h[hStrideRow * (l) + (l)]);
+                if (s == 0.0) {
+                    s = norm;
+                }
+                if (Math.abs(h[hStrideRow * (l) + (l - 1)]) < eps * s) {
+                    break;
+                }
+                l--;
+            }
+
+            // Check for convergence
+            // One root found
+
+            if (l == n) {
+                h[hStrideRow * (n) + (n)] = h[hStrideRow * (n) + (n)] + exShift;
+                valV[2 * (n)] = h[hStrideRow * (n) + (n)];
+                valV[2 * (n) + 1] = 0.0;
+                n--;
+                iter = 0;
+
+                // Two roots found
+
+            } else if (l == n - 1) {
+                w = h[hStrideRow * (n) + (n - 1)] * h[hStrideRow * (n - 1) + (n)];
+                p = (h[hStrideRow * (n - 1) + (n - 1)] - h[hStrideRow * (n) + (n)]) / 2.0;
+                q = p * p + w;
+                z = Math.sqrt(Math.abs(q));
+                h[hStrideRow * (n) + (n)] = h[hStrideRow * (n) + (n)] + exShift;
+                h[hStrideRow * (n - 1) + (n - 1)] = h[hStrideRow * (n - 1) + (n - 1)] + exShift;
+                x = h[hStrideRow * (n) + (n)];
+
+                // Real pair
+
+                if (q >= 0) {
+                    if (p >= 0) {
+                        z = p + z;
+                    } else {
+                        z = p - z;
+                    }
+                    valV[2 * (n - 1)] = x + z;
+                    valV[2 * (n)] = valV[2 * (n - 1)];
+                    if (z != 0.0) {
+                        valV[2 * (n)] = x - w / z;
+                    }
+                    valV[2 * (n - 1) + 1] = 0.0;
+                    valV[2 * (n) + 1] = 0.0;
+                    x = h[hStrideRow * (n) + (n - 1)];
+                    s = Math.abs(x) + Math.abs(z);
+                    p = x / s;
+                    q = z / s;
+                    r = Math.sqrt(p * p + q * q);
+                    p = p / r;
+                    q = q / r;
+
+                    // Row modification
+
+                    for (int j = n - 1; j < nn; j++) {
+                        z = h[hStrideRow * (n - 1) + (j)];
+                        h[hStrideRow * (n - 1) + (j)] = q * z + p * h[hStrideRow * (n) + (j)];
+                        h[hStrideRow * (n) + (j)] = q * h[hStrideRow * (n) + (j)] - p * z;
+                    }
+
+                    // Column modification
+
+                    for (int i = 0; i <= n; i++) {
+                        z = h[hStrideRow * (i) + (n - 1)];
+                        h[hStrideRow * (i) + (n - 1)] = q * z + p * h[hStrideRow * (i) + (n)];
+                        h[hStrideRow * (i) + (n)] = q * h[hStrideRow * (i) + (n)] - p * z;
+                    }
+
+                    // Accumulate transformations
+
+                    for (int i = low; i <= high; i++) {
+                        z = vecV[vStrideRow * (i) + (n - 1)];
+                        vecV[vStrideRow * (i) + (n - 1)] = q * z + p * vecV[vStrideRow * (i) + (n)];
+                        vecV[vStrideRow * (i) + (n)] = q * vecV[vStrideRow * (i) + (n)] - p * z;
+                    }
+
+                    // Complex pair
+
+                } else {
+                    valV[2 * (n - 1)] = x + p;
+                    valV[2 * (n)] = x + p;
+                    valV[2 * (n - 1) + 1] = z;
+                    valV[2 * (n) + 1] = -z;
+                }
+                n = n - 2;
+                iter = 0;
+
+                // No convergence yet
+
+            } else {
+
+                // Form shift
+
+                x = h[hStrideRow * (n) + (n)];
+                y = 0.0;
+                w = 0.0;
+                if (l < n) {
+                    y = h[hStrideRow * (n - 1) + (n - 1)];
+                    w = h[hStrideRow * (n) + (n - 1)] * h[hStrideRow * (n - 1) + (n)];
+                }
+
+                // Wilkinson's original ad hoc shift
+
+                if (iter == 10) {
+                    exShift += x;
+                    for (int i = low; i <= n; i++) {
+                        h[hStrideRow * (i) + (i)] -= x;
+                    }
+                    s = Math.abs(h[hStrideRow * (n) + (n - 1)]) + Math.abs(h[hStrideRow * (n - 1) + (n - 2)]);
+                    x = y = 0.75 * s;
+                    w = -0.4375 * s * s;
+                }
+
+                // MATLAB's new ad hoc shift
+
+                if (iter == 30) {
+                    s = (y - x) / 2.0;
+                    s = s * s + w;
+                    if (s > 0) {
+                        s = Math.sqrt(s);
+                        if (y < x) {
+                            s = -s;
+                        }
+                        s = x - w / ((y - x) / 2.0 + s);
+                        for (int i = low; i <= n; i++) {
+                            h[hStrideRow * (i) + (i)] -= s;
+                        }
+                        exShift += s;
+                        x = y = w = 0.964;
+                    }
+                }
+
+                iter = iter + 1; // (Could check iteration count here.)
+
+                // Look for two consecutive small sub-diagonal elements
+
+                int m = n - 2;
+                while (m >= l) {
+                    z = h[hStrideRow * (m) + (m)];
+                    r = x - z;
+                    s = y - z;
+                    p = (r * s - w) / h[hStrideRow * (m + 1) + (m)] + h[hStrideRow * (m) + (m + 1)];
+                    q = h[hStrideRow * (m + 1) + (m + 1)] - z - r - s;
+                    r = h[hStrideRow * (m + 2) + (m + 1)];
+                    s = Math.abs(p) + Math.abs(q) + Math.abs(r);
+                    p = p / s;
+                    q = q / s;
+                    r = r / s;
+                    if (m == l) {
+                        break;
+                    }
+                    if (Math.abs(h[hStrideRow * (m) + (m - 1)]) * (Math.abs(q) + Math.abs(r)) < eps
+                            * (Math.abs(p) * (Math.abs(h[hStrideRow * (m - 1) + (m - 1)]) + Math.abs(z) + Math
+                                    .abs(h[hStrideRow * (m + 1) + (m + 1)])))) {
+                        break;
+                    }
+                    m--;
+                }
+
+                for (int i = m + 2; i <= n; i++) {
+                    h[hStrideRow * (i) + (i - 2)] = 0.0;
+                    if (i > m + 2) {
+                        h[hStrideRow * (i) + (i - 3)] = 0.0;
+                    }
+                }
+
+                // Double QR step involving rows l:n and columns m:n
+
+                for (int k = m; k <= n - 1; k++) {
+                    boolean notlast = (k != n - 1);
+                    if (k != m) {
+                        p = h[hStrideRow * (k) + (k - 1)];
+                        q = h[hStrideRow * (k + 1) + (k - 1)];
+                        r = (notlast ? h[hStrideRow * (k + 2) + (k - 1)] : 0.0);
+                        x = Math.abs(p) + Math.abs(q) + Math.abs(r);
+                        if (x != 0.0) {
+                            p = p / x;
+                            q = q / x;
+                            r = r / x;
+                        }
+                    }
+                    if (x == 0.0) {
+                        break;
+                    }
+                    s = Math.sqrt(p * p + q * q + r * r);
+                    if (p < 0) {
+                        s = -s;
+                    }
+                    if (s != 0) {
+                        if (k != m) {
+                            h[hStrideRow * (k) + (k - 1)] = -s * x;
+                        } else if (l != m) {
+                            h[hStrideRow * (k) + (k - 1)] = -h[hStrideRow * (k) + (k - 1)];
+                        }
+                        p = p + s;
+                        x = p / s;
+                        y = q / s;
+                        z = r / s;
+                        q = q / p;
+                        r = r / p;
+
+                        // Row modification
+
+                        for (int j = k; j < nn; j++) {
+                            p = h[hStrideRow * (k) + (j)] + q * h[hStrideRow * (k + 1) + (j)];
+                            if (notlast) {
+                                p = p + r * h[hStrideRow * (k + 2) + (j)];
+                                h[hStrideRow * (k + 2) + (j)] = h[hStrideRow * (k + 2) + (j)] - p * z;
+                            }
+                            h[hStrideRow * (k) + (j)] = h[hStrideRow * (k) + (j)] - p * x;
+                            h[hStrideRow * (k + 1) + (j)] = h[hStrideRow * (k + 1) + (j)] - p * y;
+                        }
+
+                        // Column modification
+
+                        for (int i = 0; i <= Math.min(n, k + 3); i++) {
+                            p = x * h[hStrideRow * (i) + (k)] + y * h[hStrideRow * (i) + (k + 1)];
+                            if (notlast) {
+                                p = p + z * h[hStrideRow * (i) + (k + 2)];
+                                h[hStrideRow * (i) + (k + 2)] = h[hStrideRow * (i) + (k + 2)] - p * r;
+                            }
+                            h[hStrideRow * (i) + (k)] = h[hStrideRow * (i) + (k)] - p;
+                            h[hStrideRow * (i) + (k + 1)] = h[hStrideRow * (i) + (k + 1)] - p * q;
+                        }
+
+                        // Accumulate transformations
+
+                        for (int i = low; i <= high; i++) {
+                            p = x * vecV[vStrideRow * (i) + (k)] + y * vecV[vStrideRow * (i) + (k + 1)];
+                            if (notlast) {
+                                p = p + z * vecV[vStrideRow * (i) + (k + 2)];
+                                vecV[vStrideRow * (i) + (k + 2)] = vecV[vStrideRow * (i) + (k + 2)] - p * r;
+                            }
+                            vecV[vStrideRow * (i) + (k)] = vecV[vStrideRow * (i) + (k)] - p;
+                            vecV[vStrideRow * (i) + (k + 1)] = vecV[vStrideRow * (i) + (k + 1)] - p * q;
+                        }
+                    } // (s != 0)
+                } // k loop
+            } // check convergence
+        } // while (n >= low)
+
+        // Backsubstitute to find vectors of upper triangular form
+
+        if (norm == 0.0) {
+            return;
+        }
+
+        for (n = nn - 1; n >= 0; n--) {
+            p = valV[2 * (n)];
+            q = valV[2 * (n) + 1];
+
+            // Real vector
+
+            if (q == 0) {
+                int l = n;
+                h[hStrideRow * (n) + (n)] = 1.0;
+                for (int i = n - 1; i >= 0; i--) {
+                    w = h[hStrideRow * (i) + (i)] - p;
+                    r = 0.0;
+                    for (int j = l; j <= n; j++) {
+                        r = r + h[hStrideRow * (i) + (j)] * h[hStrideRow * (j) + (n)];
+                    }
+                    if (valV[2 * (i) + 1] < 0.0) {
+                        z = w;
+                        s = r;
+                    } else {
+                        l = i;
+                        if (valV[2 * (i) + 1] == 0.0) {
+                            if (w != 0.0) {
+                                h[hStrideRow * (i) + (n)] = -r / w;
+                            } else {
+                                h[hStrideRow * (i) + (n)] = -r / (eps * norm);
+                            }
+
+                            // Solve real equations
+
+                        } else {
+                            x = h[hStrideRow * (i) + (i + 1)];
+                            y = h[hStrideRow * (i + 1) + (i)];
+                            q = (valV[2 * (i)] - p) * (valV[2 * (i)] - p) + valV[2 * (i) + 1] * valV[2 * (i) + 1];
+                            t = (x * s - z * r) / q;
+                            h[hStrideRow * (i) + (n)] = t;
+                            if (Math.abs(x) > Math.abs(z)) {
+                                h[hStrideRow * (i + 1) + (n)] = (-r - w * t) / x;
+                            } else {
+                                h[hStrideRow * (i + 1) + (n)] = (-s - y * t) / z;
+                            }
+                        }
+
+                        // Overflow control
+
+                        t = Math.abs(h[hStrideRow * (i) + (n)]);
+                        if ((eps * t) * t > 1) {
+                            for (int j = i; j <= n; j++) {
+                                h[hStrideRow * (j) + (n)] = h[hStrideRow * (j) + (n)] / t;
+                            }
+                        }
+                    }
+                }
+
+                // Complex vector
+
+            } else if (q < 0) {
+                int l = n - 1;
+
+                // Last vector component imaginary so matrix is triangular
+
+                if (Math.abs(h[hStrideRow * (n) + (n - 1)]) > Math.abs(h[hStrideRow * (n - 1) + (n)])) {
+                    h[hStrideRow * (n - 1) + (n - 1)] = q / h[hStrideRow * (n) + (n - 1)];
+                    h[hStrideRow * (n - 1) + (n)] = -(h[hStrideRow * (n) + (n)] - p) / h[hStrideRow * (n) + (n - 1)];
+                } else {
+                    CEDivOp.op(cdiv, //
+                            0.0, -h[hStrideRow * (n - 1) + (n)], //
+                            h[hStrideRow * (n - 1) + (n - 1)] - p, q);
+                    h[hStrideRow * (n - 1) + (n - 1)] = cdiv[0];
+                    h[hStrideRow * (n - 1) + (n)] = cdiv[1];
+                }
+                h[hStrideRow * (n) + (n - 1)] = 0.0;
+                h[hStrideRow * (n) + (n)] = 1.0;
+                for (int i = n - 2; i >= 0; i--) {
+                    double ra, sa, vr, vi;
+                    ra = 0.0;
+                    sa = 0.0;
+                    for (int j = l; j <= n; j++) {
+                        ra = ra + h[hStrideRow * (i) + (j)] * h[hStrideRow * (j) + (n - 1)];
+                        sa = sa + h[hStrideRow * (i) + (j)] * h[hStrideRow * (j) + (n)];
+                    }
+                    w = h[hStrideRow * (i) + (i)] - p;
+
+                    if (valV[2 * (i) + 1] < 0.0) {
+                        z = w;
+                        r = ra;
+                        s = sa;
+                    } else {
+                        l = i;
+                        if (valV[2 * (i) + 1] == 0) {
+                            CEDivOp.op(cdiv, //
+                                    -ra, -sa, w, q);
+                            h[hStrideRow * (i) + (n - 1)] = cdiv[0];
+                            h[hStrideRow * (i) + (n)] = cdiv[1];
+                        } else {
+
+                            // Solve complex equations
+
+                            x = h[hStrideRow * (i) + (i + 1)];
+                            y = h[hStrideRow * (i + 1) + (i)];
+                            vr = (valV[2 * (i)] - p) * (valV[2 * (i)] - p) + valV[2 * (i) + 1] * valV[2 * (i) + 1] - q
+                                    * q;
+                            vi = (valV[2 * (i)] - p) * 2.0 * q;
+                            if (vr == 0.0 && vi == 0.0) {
+                                vr = eps * norm * (Math.abs(w) + Math.abs(q) + Math.abs(x) + Math.abs(y) + Math.abs(z));
+                            }
+                            CEDivOp.op(cdiv, //
+                                    x * r - z * ra + q * sa, //
+                                    x * s - z * sa - q * ra, //
+                                    vr, vi);
+                            h[hStrideRow * (i) + (n - 1)] = cdiv[0];
+                            h[hStrideRow * (i) + (n)] = cdiv[1];
+                            if (Math.abs(x) > (Math.abs(z) + Math.abs(q))) {
+                                h[hStrideRow * (i + 1) + (n - 1)] = (-ra - w * h[hStrideRow * (i) + (n - 1)] + q
+                                        * h[hStrideRow * (i) + (n)])
+                                        / x;
+                                h[hStrideRow * (i + 1) + (n)] = (-sa - w * h[hStrideRow * (i) + (n)] - q
+                                        * h[hStrideRow * (i) + (n - 1)])
+                                        / x;
+                            } else {
+                                CEDivOp.op(cdiv, //
+                                        -r - y * h[hStrideRow * (i) + (n - 1)], //
+                                        -s - y * h[hStrideRow * (i) + (n)], //
+                                        z, q);
+                                h[hStrideRow * (i + 1) + (n - 1)] = cdiv[0];
+                                h[hStrideRow * (i + 1) + (n)] = cdiv[1];
+                            }
+                        }
+
+                        // Overflow control
+
+                        t = Math.max(Math.abs(h[hStrideRow * (i) + (n - 1)]), Math.abs(h[hStrideRow * (i) + (n)]));
+                        if ((eps * t) * t > 1) {
+                            for (int j = i; j <= n; j++) {
+                                h[hStrideRow * (j) + (n - 1)] = h[hStrideRow * (j) + (n - 1)] / t;
+                                h[hStrideRow * (j) + (n)] = h[hStrideRow * (j) + (n)] / t;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Vectors of isolated roots
+
+        for (int i = 0; i < nn; i++) {
+            if (i < low || i > high) {
+                for (int j = i; j < nn; j++) {
+                    vecV[vStrideRow * (i) + (j)] = h[hStrideRow * (i) + (j)];
+                }
+            }
+        }
+
+        // Back transformation to get eigenvectors of original matrix
+
+        for (int j = nn - 1; j >= low; j--) {
+            for (int i = low; i <= high; i++) {
+                z = 0.0;
+                for (int k = low; k <= Math.min(j, high); k++) {
+                    z = z + vecV[vStrideRow * (i) + (k)] * h[hStrideRow * (k) + (j)];
+                }
+                vecV[vStrideRow * (i) + (j)] = z;
+            }
+        }
+    }
+
+    /**
+     * A matrix inversion operation in support of {@link JavaArrayKernel#invert(double[], double[], int)}.
+     */
+    final public static void invert(double[] srcV, double[] dstV, int size) {
+
+        Control.checkTrue(srcV.length == size * size //
+                && dstV.length == size * size, //
+                "Invalid arguments");
+
+        double[] lu = srcV.clone();
+        int[] pivots = Arithmetic.range(size);
+
+        lup(lu, pivots, size, size);
+
+        for (int i = 0; i < size; i++) {
+
+            Control.checkTrue(lu[size * i + i] != 0, //
+                    "Matrix is singular");
+
+            dstV[size * i + pivots[i]] = 1.0;
+        }
+
+        luSolve(lu, size, dstV, size);
+    }
+
+    /**
+     * Computes the LU decomposition along with row pivots.
+     * 
+     * @param lu
+     *            the LU matrix.
+     * @param pivots
+     *            the row pivots.
+     * @param nrows
+     *            the number of rows.
+     * @param ncols
+     *            the number of columns.
+     */
+    final protected static void lup(double[] lu, int[] pivots, int nrows, int ncols) {
+
+        int luStrideRow = ncols;
+
+        // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+
+        double[] luColJ = new double[nrows];
+
+        // Outer loop.
+
+        for (int j = 0; j < ncols; j++) {
+
+            // Make a copy of the j-th column to localize references.
+
+            for (int i = 0; i < nrows; i++) {
+                luColJ[i] = lu[luStrideRow * (i) + (j)];
+            }
+
+            // Apply previous transformations.
+
+            for (int i = 0; i < nrows; i++) {
+
+                // Most of the time is spent in the following dot product.
+
+                int kmax = Math.min(i, j);
+                double s = 0.0;
+                for (int k = 0; k < kmax; k++) {
+                    s += lu[luStrideRow * (i) + (k)] * luColJ[k];
+                }
+
+                lu[luStrideRow * (i) + (j)] = luColJ[i] -= s;
+            }
+
+            // Find pivot and exchange if necessary.
+
+            int p = j;
+            for (int i = j + 1; i < nrows; i++) {
+                if (Math.abs(luColJ[i]) > Math.abs(luColJ[p])) {
+                    p = i;
+                }
+            }
+            if (p != j) {
+                for (int k = 0; k < ncols; k++) {
+                    double t = lu[luStrideRow * (p) + (k)];
+                    lu[luStrideRow * (p) + (k)] = lu[luStrideRow * (j) + (k)];
+                    lu[luStrideRow * (j) + (k)] = t;
+                }
+                int k = pivots[p];
+                pivots[p] = pivots[j];
+                pivots[j] = k;
+            }
+
+            // Compute multipliers.
+
+            if (j < nrows && lu[luStrideRow * (j) + (j)] != 0.0) {
+                for (int i = j + 1; i < nrows; i++) {
+                    lu[luStrideRow * (i) + (j)] /= lu[luStrideRow * (j) + (j)];
+                }
+            }
+        }
+    }
+
+    /**
+     * Uses an existing LU decomposition to solve a system of linear equations.
+     * 
+     * @param lu
+     *            the LU matrix.
+     * @param nluCols
+     *            the number of columns in the LU matrix.
+     * @param dstV
+     *            the destination matrix.
+     * @param ndstVCols
+     *            the number of columns in the destination matrix.
+     */
+    final protected static void luSolve(double[] lu, int nluCols, double[] dstV, int ndstVCols) {
+
+        int luStrideRow = nluCols;
+        int vStrideRow = ndstVCols;
+
+        // Solve L*Y = B(piv,:)
+        for (int k = 0; k < nluCols; k++) {
+            for (int i = k + 1; i < nluCols; i++) {
+                for (int j = 0; j < ndstVCols; j++) {
+                    dstV[vStrideRow * (i) + (j)] -= dstV[vStrideRow * (k) + (j)] * lu[luStrideRow * (i) + (k)];
+                }
+            }
+        }
+        // Solve U*X = Y;
+        for (int k = nluCols - 1; k >= 0; k--) {
+            for (int j = 0; j < nluCols; j++) {
+                dstV[vStrideRow * (k) + (j)] /= lu[luStrideRow * (k) + (k)];
+            }
+            for (int i = 0; i < k; i++) {
+                for (int j = 0; j < ndstVCols; j++) {
+                    dstV[vStrideRow * (i) + (j)] -= dstV[vStrideRow * (k) + (j)] * lu[luStrideRow * (i) + (k)];
+                }
+            }
+        }
+    }
+
+    // Dummy constructor.
+    LinearAlgebraOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MappingOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MappingOps.java
new file mode 100755
index 0000000..2464193
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MappingOps.java
@@ -0,0 +1,332 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+import shared.util.Control;
+
+/**
+ * A class for mapping operations in pure Java.
+ * 
+ * @author Roy Liu
+ */
+public class MappingOps {
+
+    /**
+     * Creates an array of physical indices.
+     * 
+     * @param nindices
+     *            the number of indices.
+     * @param dims
+     *            the mapping dimensions.
+     * @param strides
+     *            the strides.
+     * @return the physical indices.
+     */
+    final public static int[] assignMappingIndices(int nindices, int[] dims, int[] strides) {
+
+        int[] indices = new int[nindices];
+
+        for (int k = dims.length - 1, blockSize = 1, stride, size; k >= 0; blockSize *= size, k--) {
+
+            stride = strides[k];
+            size = dims[k];
+
+            for (int offset = blockSize, m = blockSize * size; offset < m; offset += blockSize) {
+
+                for (int i = offset - blockSize, j = offset; i < offset; i++, j++) {
+                    indices[j] = indices[i] + stride;
+                }
+            }
+        }
+
+        return indices;
+    }
+
+    /**
+     * Creates an array of physical slicing indices.
+     * 
+     * @param nindices
+     *            the number of indices.
+     * @param strides
+     *            the strides.
+     * @param sliceIndices
+     *            the indices to slice on arranged by dimension.
+     * @return the physical indices.
+     */
+    final public static int[] assignSlicingIndices(int nindices, int[] strides, int[][] sliceIndices) {
+
+        int[] indices = new int[nindices];
+
+        for (int i = 0, n = strides.length; i < n; i++) {
+            indices[0] += strides[i] * sliceIndices[i][0];
+        }
+
+        for (int k = strides.length - 1, blockSize = 1, strideOffset, size; k >= 0; blockSize *= size, k--) {
+
+            int[] arr = sliceIndices[k];
+            size = arr.length;
+
+            for (int offset = blockSize, m = blockSize * size, n = 1; offset < m; offset += blockSize, n++) {
+
+                strideOffset = strides[k] * (arr[n] - arr[n - 1]);
+
+                for (int i = offset - blockSize, j = offset; i < offset; i++, j++) {
+                    indices[j] = indices[i] + strideOffset;
+                }
+            }
+        }
+
+        return indices;
+    }
+
+    /**
+     * Checks an array's dimensions and strides.
+     * 
+     * @param len
+     *            the array length.
+     * @param dims
+     *            the dimensions.
+     * @param strides
+     *            the strides.
+     * @return the array length.
+     */
+    final public static int checkDimensions(int len, int[] dims, int[] strides) {
+
+        int acc = 0;
+
+        for (int dim = 0, ndims = dims.length; dim < ndims; dim++) {
+
+            Control.checkTrue(dims[dim] >= 0 && strides[dim] >= 0, //
+                    "Invalid dimensions and/or strides");
+
+            acc += (dims[dim] - 1) * strides[dim];
+        }
+
+        Control.checkTrue(acc == len - 1, //
+                "Invalid dimensions and/or strides");
+
+        return len;
+    }
+
+    /**
+     * Assigns source values to destination values based on arrays of physical indices.
+     * 
+     * @param srcV
+     *            the source array.
+     * @param srcIndices
+     *            the source indices.
+     * @param dstV
+     *            the destination array.
+     * @param dstIndices
+     *            the destination indices.
+     */
+    final public static void assign(Object srcV, int[] srcIndices, Object dstV, int[] dstIndices) {
+
+        int nindices = Control.checkEquals(srcIndices.length, dstIndices.length, //
+                "Invalid arguments");
+
+        if (srcV instanceof double[] && dstV instanceof double[]) {
+
+            double[] srcVArr = (double[]) srcV;
+            double[] dstVArr = (double[]) dstV;
+
+            for (int i = 0; i < nindices; i++) {
+                dstVArr[dstIndices[i]] = srcVArr[srcIndices[i]];
+            }
+
+        } else if (srcV instanceof int[] && dstV instanceof int[]) {
+
+            int[] srcVArr = (int[]) srcV;
+            int[] dstVArr = (int[]) dstV;
+
+            for (int i = 0; i < nindices; i++) {
+                dstVArr[dstIndices[i]] = srcVArr[srcIndices[i]];
+            }
+
+        } else if (srcV instanceof Object[] && dstV instanceof Object[]) {
+
+            Control.checkTrue(dstV.getClass().isAssignableFrom(srcV.getClass()), //
+                    "Invalid array types");
+
+            Object[] srcVArr = (Object[]) srcV;
+            Object[] dstVArr = (Object[]) dstV;
+
+            for (int i = 0; i < nindices; i++) {
+                dstVArr[dstIndices[i]] = srcVArr[srcIndices[i]];
+            }
+
+        } else {
+
+            throw new IllegalArgumentException("Invalid arguments");
+        }
+    }
+
+    /**
+     * A mapping operation in support of {@link JavaArrayKernel#map(int[], Object, int[], int[], Object, int[], int[])}.
+     */
+    final public static void map(int[] bounds, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS) {
+
+        int ndims = srcD.length;
+
+        Control.checkTrue(ndims == srcS.length //
+                && ndims == dstD.length //
+                && ndims == dstS.length //
+                && 3 * ndims == bounds.length, //
+                "Invalid arguments");
+
+        int srcLen = checkDimensions(Array.getLength(srcV), srcD, srcS);
+        int dstLen = checkDimensions(Array.getLength(dstV), dstD, dstS);
+
+        int nslices = 0;
+        int mapLen = 1;
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+
+            int size = bounds[offset + 2];
+
+            Control.checkTrue(size >= 0, //
+                    "Invalid mapping parameters");
+
+            nslices += size;
+            mapLen *= size;
+        }
+
+        if (srcLen == 0 || dstLen == 0) {
+            return;
+        }
+
+        int[][] ssi = new int[ndims][];
+        int[][] dsi = new int[ndims][];
+
+        for (int dim = 0, acc = 0, offset = 0; dim < ndims; dim++, acc += bounds[offset + 2], offset += 3) {
+
+            int mapSize = bounds[offset + 2];
+
+            int[] srcSlices = (ssi[dim] = new int[mapSize]);
+            int[] dstSlices = (dsi[dim] = new int[mapSize]);
+
+            for (int j = 0, //
+            srcSize = srcD[dim], //
+            srcOffset = (((bounds[offset]) % srcSize) + srcSize) % srcSize, //
+            dstSize = dstD[dim], //
+            dstOffset = (((bounds[offset + 1]) % dstSize) + dstSize) % dstSize; //
+            j < mapSize; //
+            j++, //
+            srcOffset = (srcOffset + 1) % srcSize, //
+            dstOffset = (dstOffset + 1) % dstSize) {
+
+                srcSlices[j] = srcOffset;
+                dstSlices[j] = dstOffset;
+            }
+        }
+
+        if (mapLen == 0) {
+            return;
+        }
+
+        int[] srcIndices = assignSlicingIndices(mapLen, srcS, ssi);
+        int[] dstIndices = assignSlicingIndices(mapLen, dstS, dsi);
+
+        assign(srcV, srcIndices, dstV, dstIndices);
+    }
+
+    /**
+     * A slicing operation in support of
+     * {@link JavaArrayKernel#slice(int[], Object, int[], int[], Object, int[], int[])}.
+     */
+    final public static void slice( //
+            int[] slices, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS) {
+
+        Control.checkTrue(slices.length % 3 == 0, //
+                "Invalid slicing specification");
+
+        int nslices = slices.length / 3;
+        int ndims = srcD.length;
+
+        Control.checkTrue(ndims == srcS.length //
+                && ndims == dstD.length //
+                && ndims == dstS.length);
+
+        checkDimensions(Array.getLength(srcV), srcD, srcS);
+        checkDimensions(Array.getLength(dstV), dstD, dstS);
+
+        for (int i = 0, n = 3 * nslices; i < n; i += 3) {
+
+            int srcIndex = slices[i];
+            int dstIndex = slices[i + 1];
+            int dim = slices[i + 2];
+
+            Control.checkTrue(dim >= 0 && dim < ndims, //
+                    "Invalid dimension");
+
+            Control.checkTrue((srcIndex >= 0 && srcIndex < srcD[dim]) //
+                    && (dstIndex >= 0 && dstIndex < dstD[dim]), //
+                    "Invalid index");
+        }
+
+        int[] dimCounts = new int[ndims];
+
+        for (int i = 0, n = 3 * nslices; i < n; i += 3) {
+            dimCounts[slices[i + 2]]++;
+        }
+
+        int nindices = 1;
+
+        int[][] ssi = new int[ndims][];
+        int[][] dsi = new int[ndims][];
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            ssi[dim] = new int[dimCounts[dim]];
+            dsi[dim] = new int[dimCounts[dim]];
+
+            nindices *= dimCounts[dim];
+        }
+
+        Arrays.fill(dimCounts, 0);
+
+        for (int i = 0, n = 3 * nslices; i < n; i += 3) {
+
+            int dim = slices[i + 2];
+            int idx = dimCounts[dim]++;
+
+            ssi[dim][idx] = slices[i];
+            dsi[dim][idx] = slices[i + 1];
+        }
+
+        if (nindices == 0) {
+            return;
+        }
+
+        int[] srcIndices = assignSlicingIndices(nindices, srcS, ssi);
+        int[] dstIndices = assignSlicingIndices(nindices, dstS, dsi);
+
+        assign(srcV, srcIndices, dstV, dstIndices);
+    }
+
+    // Dummy constructor.
+    MappingOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatlabIO.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatlabIO.java
new file mode 100755
index 0000000..c7ff371
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatlabIO.java
@@ -0,0 +1,376 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+/**
+ * Contains constant values pertaining to the reading and writing of Matlab's "mat" file format.
+ * 
+ * @apiviz.exclude
+ * @author Roy Liu
+ */
+public class MatlabIO {
+
+    /**
+     * A value such that observation in its reversed form necessitates conversion from Little-Endian values to
+     * Big-Endian values, and vice versa.
+     */
+    final public static short ENDIANNESS = 0x4D49;
+
+    /**
+     * Matlab's value for a signed {@code byte}.
+     */
+    final public static int MATLAB_MI_INT8 = 1;
+
+    /**
+     * Matlab's value for an unsigned {@code byte}.
+     */
+    final public static int MATLAB_MI_UINT8 = 2;
+
+    /**
+     * Matlab's value for a signed {@code short}.
+     */
+    final public static int MATLAB_MI_INT16 = 3;
+
+    /**
+     * Matlab's value for an unsigned {@code short}.
+     */
+    final public static int MATLAB_MI_UINT16 = 4;
+
+    /**
+     * Matlab's value for a signed {@code int}.
+     */
+    final public static int MATLAB_MI_INT32 = 5;
+
+    /**
+     * Matlab's value for an unsigned {@code int}.
+     */
+    final public static int MATLAB_MI_UINT32 = 6;
+
+    /**
+     * Matlab's value for a {@code float}.
+     */
+    final public static int MATLAB_MI_SINGLE = 7;
+
+    /**
+     * Matlab's value for a {@code double}.
+     */
+    final public static int MATLAB_MI_DOUBLE = 9;
+
+    /**
+     * Matlab's value for an array of {@code double}s.
+     */
+    final public static int MATLAB_MX_DOUBLE_CLASS = 6;
+
+    /**
+     * Matlab's value for an array of {@code float}s.
+     */
+    final public static int MATLAB_MX_SINGLE_CLASS = 7;
+
+    /**
+     * Matlab's value for an array of signed {@code byte}s.
+     */
+    final public static int MATLAB_MX_INT8_CLASS = 8;
+
+    /**
+     * Matlab's value for an array of unsigned {@code byte}s.
+     */
+    final public static int MATLAB_MX_UINT8_CLASS = 9;
+
+    /**
+     * Matlab's value for an array of signed {@code short}s.
+     */
+    final public static int MATLAB_MX_INT16_CLASS = 10;
+
+    /**
+     * Matlab's value for an array of unsigned {@code short}s.
+     */
+    final public static int MATLAB_MX_UINT16_CLASS = 11;
+
+    /**
+     * Matlab's value for an array of signed {@code int}s.
+     */
+    final public static int MATLAB_MX_INT32_CLASS = 12;
+
+    /**
+     * Matlab's value for an array of unsigned {@code int}s.
+     */
+    final public static int MATLAB_MX_UINT32_CLASS = 13;
+
+    /**
+     * Matlab's value for a matrix.
+     */
+    final public static int MATLAB_MI_MATRIX = 14;
+
+    /**
+     * An enumeration of Matlab data types.
+     */
+    public enum DataType {
+
+        /**
+         * Denotes a signed {@code byte}.
+         */
+        MI_INT8 {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_INT8;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 1;
+            }
+        }, //
+
+        /**
+         * Denotes an unsigned {@code byte}.
+         */
+        MI_UINT8 {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_UINT8;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 1;
+            }
+        }, //
+
+        /**
+         * Denotes a signed {@code short}.
+         */
+        MI_INT16 {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_INT16;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 2;
+            }
+        }, //
+
+        /**
+         * Denotes an unsigned {@code short}.
+         */
+        MI_UINT16 {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_UINT16;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 2;
+            }
+        }, //
+
+        /**
+         * Denotes a signed {@code int}.
+         */
+        MI_INT32 {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_INT32;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 4;
+            }
+        }, //
+
+        /**
+         * Denotes an unsigned {@code int}.
+         */
+        MI_UINT32 {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_UINT32;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 4;
+            }
+        }, //
+
+        /**
+         * Denotes a {@code float}.
+         */
+        MI_SINGLE {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_SINGLE;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 4;
+            }
+        }, //
+
+        /**
+         * Denotes a {@code double}.
+         */
+        MI_DOUBLE {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_DOUBLE;
+            }
+
+            @Override
+            public int sizeOf() {
+                return 8;
+            }
+        };
+
+        /**
+         * Gets the physical Matlab value.
+         */
+        abstract public int getMatlabValue();
+
+        /**
+         * Gets the size of this type in {@code byte}s.
+         */
+        abstract public int sizeOf();
+    }
+
+    /**
+     * An enumeration of Matlab object types.
+     */
+    public enum ObjectType {
+
+        /**
+         * Denotes a Matlab array of {@code double}s.
+         */
+        MX_DOUBLE_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_DOUBLE_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of {@code float}s.
+         */
+        MX_SINGLE_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_SINGLE_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of signed {@code byte}s.
+         */
+        MX_INT8_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_INT8_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of unsigned {@code byte}s.
+         */
+        MX_UINT8_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_UINT8_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of signed {@code short}s.
+         */
+        MX_INT16_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_INT16_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of unsigned {@code short}s.
+         */
+        MX_UINT16_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_UINT16_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of signed {@code int}s.
+         */
+        MX_INT32_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_INT32_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab array of unsigned {@code int}s.
+         */
+        MX_UINT32_CLASS {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MX_UINT32_CLASS;
+            }
+        }, //
+
+        /**
+         * Denotes a Matlab matrix.
+         */
+        MI_MATRIX {
+
+            @Override
+            public int getMatlabValue() {
+                return MATLAB_MI_MATRIX;
+            }
+        };
+
+        /**
+         * Gets the physical Matlab value.
+         */
+        abstract public int getMatlabValue();
+    }
+
+    // Dummy constructor.
+    MatlabIO() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatlabIOKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatlabIOKernel.java
new file mode 100755
index 0000000..2baf28e
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatlabIOKernel.java
@@ -0,0 +1,796 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import static shared.Constants.MAJOR_VERSION;
+import static shared.Constants.MINOR_VERSION;
+import static shared.array.kernel.MatlabIO.ENDIANNESS;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_DOUBLE;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_INT16;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_INT32;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_INT8;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_MATRIX;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_SINGLE;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_UINT16;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_UINT32;
+import static shared.array.kernel.MatlabIO.MATLAB_MI_UINT8;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_DOUBLE_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_INT16_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_INT32_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_INT8_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_SINGLE_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_UINT16_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_UINT32_CLASS;
+import static shared.array.kernel.MatlabIO.MATLAB_MX_UINT8_CLASS;
+import static shared.array.kernel.MatlabIO.DataType.MI_DOUBLE;
+import static shared.array.kernel.MatlabIO.DataType.MI_INT32;
+import static shared.array.kernel.MatlabIO.DataType.MI_INT8;
+import static shared.array.kernel.MatlabIO.DataType.MI_UINT32;
+import static shared.array.kernel.MatlabIO.ObjectType.MI_MATRIX;
+import static shared.array.kernel.MatlabIO.ObjectType.MX_DOUBLE_CLASS;
+import static shared.array.kernel.MatlabIO.ObjectType.MX_INT32_CLASS;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import shared.array.Array;
+import shared.array.ComplexArray;
+import shared.array.IntegerArray;
+import shared.array.RealArray;
+import shared.array.Array.IndexingOrder;
+import shared.array.kernel.MatlabIO.DataType;
+import shared.util.Control;
+
+/**
+ * An implementation of {@link ArrayIOKernel} that reads and writes Matlab "mat" files.
+ * 
+ * @apiviz.composedOf shared.array.kernel.MatlabIOKernel.DoubleArrayDataElement
+ * @apiviz.composedOf shared.array.kernel.MatlabIOKernel.IntArrayDataElement
+ * @apiviz.composedOf shared.array.kernel.MatlabIOKernel.MatrixDataElement
+ * @apiviz.owns shared.array.kernel.MatlabIO.DataType
+ * @apiviz.owns shared.array.kernel.MatlabIO.ObjectType
+ * @author Roy Liu
+ */
+public class MatlabIOKernel implements ArrayIOKernel {
+
+    /**
+     * A {@link RealArray} counter local to the current thread.
+     */
+    final protected static ThreadLocal<Integer> RealArrayCountLocal = new ThreadLocal<Integer>();
+
+    /**
+     * A {@link ComplexArray} counter local to the current thread.
+     */
+    final protected static ThreadLocal<Integer> ComplexArrayCountLocal = new ThreadLocal<Integer>();
+
+    /**
+     * An {@link IntegerArray} counter local to the current thread.
+     */
+    final protected static ThreadLocal<Integer> IntegerArrayCountLocal = new ThreadLocal<Integer>();
+
+    /**
+     * Default constructor.
+     */
+    public MatlabIOKernel() {
+    }
+
+    public <T extends Array<T, E>, E> byte[] getBytes(T array) {
+
+        final Integer count;
+        final String name;
+
+        final Object arrayObj = array;
+
+        if (arrayObj instanceof RealArray) {
+
+            count = RealArrayCountLocal.get();
+
+            if (count != null) {
+
+                name = String.format("ra_%d", count);
+
+                RealArrayCountLocal.set(count + 1);
+
+            } else {
+
+                name = "ra";
+            }
+
+            return getBytes((RealArray) arrayObj, name);
+
+        } else if (arrayObj instanceof ComplexArray) {
+
+            count = ComplexArrayCountLocal.get();
+
+            if (count != null) {
+
+                name = String.format("ca_%d", count);
+
+                ComplexArrayCountLocal.set(count + 1);
+
+            } else {
+
+                name = "ca";
+            }
+
+            return getBytes((ComplexArray) arrayObj, name);
+
+        } else if (arrayObj instanceof IntegerArray) {
+
+            count = IntegerArrayCountLocal.get();
+
+            if (count != null) {
+
+                name = String.format("ia_%d", count);
+
+                IntegerArrayCountLocal.set(count + 1);
+
+            } else {
+
+                name = "ia";
+            }
+
+            return getBytes((IntegerArray) arrayObj, name);
+
+        } else {
+
+            throw new IllegalArgumentException("Invalid array type");
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Array<T, ?>> T parse(byte[] data) {
+        return (T) new MatrixDataElement(ByteBuffer.wrap(data)).get();
+    }
+
+    /**
+     * Gets the binary representation of the "mat" file header.
+     */
+    final public static byte[] getHeaderBytes(String text) {
+
+        ByteBuffer bb = ByteBuffer.allocate(128);
+
+        int len = text.length();
+
+        Control.checkTrue(len <= 124, //
+                "The descriptive text is too long");
+
+        bb.put(text.getBytes());
+
+        for (int i = 0, n = 124 - len; i < n; i++) {
+            bb.put((byte) ' ');
+        }
+
+        bb.putShort((short) 0x0100);
+        bb.putShort(ENDIANNESS);
+
+        return bb.array();
+    }
+
+    /**
+     * Converts the given {@link RealArray} into {@code byte}s.
+     */
+    final public static byte[] getBytes(RealArray array, String name) {
+
+        // Force column-major indexing.
+        if (array.order() == IndexingOrder.FAR) {
+            array = array.reverseOrder();
+        }
+
+        int[] dims = array.dimensions();
+        double[] values = array.values();
+
+        int totalSize = getDataElementSize(MI_UINT32, 2) //
+                + getDataElementSize(MI_INT32, dims.length) //
+                + getDataElementSize(MI_INT8, name.length()) //
+                + getDataElementSize(MI_DOUBLE, values.length);
+
+        ByteBuffer bb = ByteBuffer.allocate(totalSize + 8);
+
+        bb.putInt(MI_MATRIX.getMatlabValue());
+        bb.putInt(totalSize);
+
+        writeDataElementHeader(bb, MI_UINT32, 2);
+        bb.putInt(MX_DOUBLE_CLASS.getMatlabValue());
+        bb.putInt(0);
+
+        writeDataElementHeader(bb, MI_INT32, dims.length);
+        writeDataElementBody(bb, dims);
+
+        writeDataElementHeader(bb, MI_INT8, name.length());
+        writeDataElementBody(bb, name.getBytes());
+
+        writeDataElementHeader(bb, MI_DOUBLE, values.length);
+        writeDataElementBody(bb, values);
+
+        return bb.array();
+    }
+
+    /**
+     * Converts the given {@link ComplexArray} into {@code byte}s.
+     */
+    final public static byte[] getBytes(ComplexArray complexArray, String name) {
+
+        RealArray array = new RealArray(complexArray.values(), complexArray.order(), complexArray.dimensions()) //
+                .reverseOrder();
+
+        int[] dims = array.dimensions();
+        double[] values = array.values();
+
+        int totalSize = getDataElementSize(MI_UINT32, 2) //
+                + getDataElementSize(MI_INT32, dims.length - 1) //
+                + getDataElementSize(MI_INT8, name.length()) //
+                + 2 * getDataElementSize(MI_DOUBLE, values.length >>> 1);
+
+        ByteBuffer bb = ByteBuffer.allocate(totalSize + 8);
+
+        bb.putInt(MI_MATRIX.getMatlabValue());
+        bb.putInt(totalSize);
+
+        writeDataElementHeader(bb, MI_UINT32, 2);
+        bb.putInt(0x00000800 | MX_DOUBLE_CLASS.getMatlabValue());
+        bb.putInt(0);
+
+        writeDataElementHeader(bb, MI_INT32, dims.length - 1);
+        writeDataElementBody(bb, Arrays.copyOf(dims, dims.length - 1));
+
+        writeDataElementHeader(bb, MI_INT8, name.length());
+        writeDataElementBody(bb, name.getBytes());
+
+        writeDataElementHeader(bb, MI_DOUBLE, values.length >>> 1);
+        writeDataElementBody(bb, Arrays.copyOfRange(values, 0, values.length >>> 1));
+
+        writeDataElementHeader(bb, MI_DOUBLE, values.length >>> 1);
+        writeDataElementBody(bb, Arrays.copyOfRange(values, values.length >>> 1, values.length));
+
+        return bb.array();
+    }
+
+    /**
+     * Converts the given {@link IntegerArray} into {@code byte}s.
+     */
+    final public static byte[] getBytes(IntegerArray array, String name) {
+
+        // Force column-major indexing.
+        if (array.order() == IndexingOrder.FAR) {
+            array = array.reverseOrder();
+        }
+
+        int[] dims = array.dimensions();
+        int[] values = array.values();
+
+        int totalSize = getDataElementSize(MI_UINT32, 2) //
+                + getDataElementSize(MI_INT32, dims.length) //
+                + getDataElementSize(MI_INT8, name.length()) //
+                + getDataElementSize(MI_INT32, values.length);
+
+        ByteBuffer bb = ByteBuffer.allocate(totalSize + 8);
+
+        bb.putInt(MI_MATRIX.getMatlabValue());
+        bb.putInt(totalSize);
+
+        writeDataElementHeader(bb, MI_UINT32, 2);
+        bb.putInt(MX_INT32_CLASS.getMatlabValue());
+        bb.putInt(0);
+
+        writeDataElementHeader(bb, MI_INT32, dims.length);
+        writeDataElementBody(bb, dims);
+
+        writeDataElementHeader(bb, MI_INT8, name.length());
+        writeDataElementBody(bb, name.getBytes());
+
+        writeDataElementHeader(bb, MI_INT32, values.length);
+        writeDataElementBody(bb, values);
+
+        return bb.array();
+    }
+
+    /**
+     * Converts the given {@link Array}s into "mat" format.
+     * 
+     * @param <T>
+     *            the {@link Array} type.
+     * @param <E>
+     *            the {@link Array} element type.
+     */
+    public <T extends Array<T, E>, E> byte[] getMatBytes(T... arrays) {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        RealArrayCountLocal.set(0);
+        ComplexArrayCountLocal.set(0);
+        IntegerArrayCountLocal.set(0);
+
+        try {
+
+            out.write(getHeaderBytes(String.format("MATLAB 5.0 MAT-file, " //
+                    + "Platform: Shared Scientific Toolbox in Java %d.%02d", //
+                    MAJOR_VERSION, MINOR_VERSION)));
+
+            for (T array : arrays) {
+                out.write(getBytes(array));
+            }
+
+        } catch (IOException e) {
+
+            throw new RuntimeException(e);
+
+        } finally {
+
+            RealArrayCountLocal.set(null);
+            ComplexArrayCountLocal.set(null);
+            IntegerArrayCountLocal.set(null);
+        }
+
+        return out.toByteArray();
+    }
+
+    /**
+     * Parses a series of {@link Array}s from "mat" format.
+     */
+    public Array<?, ?>[] parseMat(byte[] data) {
+
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        bb.position(126);
+
+        if (bb.getShort() == (short) ((ENDIANNESS >>> 8) | (ENDIANNESS << 8))) {
+            bb.order(bb.order().equals(ByteOrder.BIG_ENDIAN) ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
+        }
+
+        bb.position(124);
+
+        Control.checkTrue(bb.getShort() == 0x0100, //
+                "Invalid version");
+
+        Control.checkTrue(bb.getShort() == ENDIANNESS, //
+                "Invalid Endian indicator");
+
+        List<Array<?, ?>> arrays = new ArrayList<Array<?, ?>>();
+
+        for (; bb.hasRemaining();) {
+            arrays.add(new MatrixDataElement(bb).get());
+        }
+
+        return arrays.toArray(new Array<?, ?>[] {});
+    }
+
+    /**
+     * Writes the data element header, given the {@link DataType} and the number of elements.
+     */
+    final protected static void writeDataElementHeader(ByteBuffer bb, DataType type, int nelts) {
+
+        int nbytes = type.sizeOf() * nelts;
+
+        if (nbytes > 4 || nbytes == 0) {
+
+            bb.putInt(type.getMatlabValue());
+            bb.putInt(nbytes);
+
+        } else {
+
+            bb.putShort((short) nbytes);
+            bb.putShort((short) type.getMatlabValue());
+        }
+    }
+
+    /**
+     * Writes the data element body.
+     */
+    final protected static void writeDataElementBody(ByteBuffer bb, byte[] arr) {
+
+        bb.put(arr);
+
+        if (arr.length > 4) {
+
+            for (int i = 0, n = (8 - arr.length % 8) % 8; i < n; i++) {
+                bb.put((byte) 0);
+            }
+
+        } else if (arr.length >= 1) {
+
+            for (int i = 0, n = 4 - arr.length; i < n; i++) {
+                bb.put((byte) 0);
+            }
+        }
+    }
+
+    /**
+     * Writes the data element body.
+     */
+    final protected static void writeDataElementBody(ByteBuffer bb, int[] arr) {
+
+        for (int i : arr) {
+            bb.putInt(i);
+        }
+
+        if (arr.length > 1) {
+
+            for (int i = 0, n = (2 - arr.length % 2) % 2; i < n; i++) {
+                bb.putInt(0);
+            }
+
+        } else if (arr.length >= 1) {
+
+            for (int i = 0, n = 1 - arr.length; i < n; i++) {
+                bb.putInt(0);
+            }
+        }
+    }
+
+    /**
+     * Writes the data element body.
+     */
+    final protected static void writeDataElementBody(ByteBuffer bb, double[] arr) {
+
+        for (double r : arr) {
+            bb.putDouble(r);
+        }
+    }
+
+    /**
+     * Gets the data element size, given the {@link DataType} and the number of elements.
+     */
+    final protected static int getDataElementSize(DataType type, int nelts) {
+
+        int nbytes = type.sizeOf() * nelts;
+        return (nbytes > 4) ? (8 + nbytes + (8 - nbytes % 8) % 8) : 8;
+    }
+
+    /**
+     * A Matlab data element.
+     * 
+     * @param <T>
+     *            the result type.
+     */
+    abstract protected static class DataElement<T> {
+
+        final int initialPosition;
+        final int type;
+        final int size;
+        final ByteBuffer bb;
+
+        /**
+         * Default constructor.
+         */
+        protected DataElement(ByteBuffer bb) {
+
+            this.initialPosition = bb.position();
+
+            int tag = bb.getInt();
+            bb.position(bb.position() - 4);
+
+            if ((tag & 0xFFFF0000) == 0) {
+
+                this.type = bb.getInt();
+                this.size = bb.getInt();
+
+            } else {
+
+                this.size = bb.getShort();
+                this.type = bb.getShort();
+            }
+
+            this.bb = bb;
+        }
+
+        /**
+         * Reads padding up to an eight {@code byte} alignment.
+         */
+        protected void readPadding() {
+
+            for (int i = 0, n = (8 - (this.bb.position() - this.initialPosition) % 8) % 8; i < n; i++) {
+                this.bb.get();
+            }
+        }
+
+        /**
+         * Gets the result.
+         */
+        abstract protected T get();
+    }
+
+    /**
+     * A Matlab data element that is an array of {@code int}s.
+     */
+    protected static class IntArrayDataElement extends DataElement<int[]> {
+
+        final int[] values;
+
+        /**
+         * Default constructor.
+         */
+        protected IntArrayDataElement(ByteBuffer bb) {
+            super(bb);
+
+            switch (this.type) {
+
+            case MATLAB_MI_INT8:
+
+                this.values = new int[this.size];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.get();
+                }
+
+                break;
+
+            case MATLAB_MI_UINT8:
+
+                this.values = new int[this.size];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = (bb.get() & 0x000000FF);
+                }
+
+                break;
+
+            case MATLAB_MI_INT16:
+
+                Control.checkTrue(this.size % 2 == 0, //
+                        "Invalid size");
+
+                this.values = new int[this.size >>> 1];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.getShort();
+                }
+
+                break;
+
+            case MATLAB_MI_UINT16:
+
+                Control.checkTrue(this.size % 2 == 0, //
+                        "Invalid size");
+
+                this.values = new int[this.size >>> 1];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = (bb.getShort() & 0x0000FFFF);
+                }
+
+                break;
+
+            case MATLAB_MI_INT32:
+            case MATLAB_MI_UINT32:
+
+                Control.checkTrue(this.size % 4 == 0, //
+                        "Invalid size");
+
+                this.values = new int[this.size >>> 2];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.getInt();
+                }
+
+                break;
+
+            default:
+                throw new UnsupportedOperationException("Unknown data type");
+            }
+
+            readPadding();
+        }
+
+        @Override
+        protected int[] get() {
+            return this.values;
+        }
+    }
+
+    /**
+     * A Matlab data element that is an array of {@code double}s.
+     */
+    protected static class DoubleArrayDataElement extends DataElement<double[]> {
+
+        final double[] values;
+
+        /**
+         * Default constructor.
+         */
+        protected DoubleArrayDataElement(ByteBuffer bb) {
+            super(bb);
+
+            switch (this.type) {
+
+            case MATLAB_MI_SINGLE:
+
+                Control.checkTrue(this.size % 4 == 0, //
+                        "Invalid size");
+
+                this.values = new double[this.size >>> 2];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.getFloat();
+                }
+
+                break;
+
+            case MATLAB_MI_DOUBLE:
+
+                Control.checkTrue(this.size % 8 == 0, //
+                        "Invalid size");
+
+                this.values = new double[this.size >>> 3];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.getDouble();
+                }
+
+                break;
+
+            case MATLAB_MI_INT8:
+
+                this.values = new double[this.size];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.get();
+                }
+
+                break;
+
+            case MATLAB_MI_UINT8:
+
+                this.values = new double[this.size];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = (bb.get() & 0x000000FF);
+                }
+
+                break;
+
+            case MATLAB_MI_INT16:
+
+                Control.checkTrue(this.size % 2 == 0, //
+                        "Invalid size");
+
+                this.values = new double[this.size >>> 1];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.getShort();
+                }
+
+                break;
+
+            case MATLAB_MI_UINT16:
+
+                Control.checkTrue(this.size % 2 == 0, //
+                        "Invalid size");
+
+                this.values = new double[this.size >>> 1];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = (bb.getShort() & 0x0000FFFF);
+                }
+
+                break;
+
+            case MATLAB_MI_INT32:
+            case MATLAB_MI_UINT32:
+
+                Control.checkTrue(this.size % 4 == 0, //
+                        "Invalid size");
+
+                this.values = new double[this.size >>> 2];
+
+                for (int i = 0, n = this.values.length; i < n; i++) {
+                    this.values[i] = bb.getInt();
+                }
+
+                break;
+
+            default:
+                throw new UnsupportedOperationException("Unknown data type");
+            }
+
+            readPadding();
+        }
+
+        @Override
+        protected double[] get() {
+            return this.values;
+        }
+    }
+
+    /**
+     * A Matlab matrix data element.
+     */
+    protected static class MatrixDataElement extends DataElement<Array<?, ?>> {
+
+        final Array<?, ?> array;
+
+        /**
+         * Default constructor.
+         */
+        protected MatrixDataElement(ByteBuffer bb) {
+            super(bb);
+
+            int savePosition = bb.position();
+
+            Control.checkTrue(this.type == MATLAB_MI_MATRIX, //
+                    "Data element must be a Matlab matrix");
+
+            int arrayType = new IntArrayDataElement(bb).get()[0];
+            int[] dims = new IntArrayDataElement(bb).get();
+
+            // Read in the array name and forget it.
+            new IntArrayDataElement(bb);
+
+            switch (arrayType & 0x000000FF) {
+
+            case MATLAB_MX_DOUBLE_CLASS:
+            case MATLAB_MX_SINGLE_CLASS:
+
+                // The regular case.
+                if ((arrayType & 0x00000800) != 0x00000800) {
+
+                    this.array = new RealArray(new DoubleArrayDataElement(bb).get(), //
+                            IndexingOrder.NEAR, dims).reverseOrder();
+
+                }
+                // The complex case.
+                else {
+
+                    double[] reals = new DoubleArrayDataElement(bb).get();
+                    double[] complexes = new DoubleArrayDataElement(bb).get();
+
+                    int len = Control.checkEquals(reals.length, complexes.length, //
+                            "Number of real values must equal number of complex values");
+
+                    double[] composite = new double[2 * len];
+
+                    System.arraycopy(reals, 0, composite, 0, len);
+                    System.arraycopy(complexes, 0, composite, len, len);
+
+                    int[] newDims = Arrays.copyOf(dims, dims.length + 1);
+                    newDims[newDims.length - 1] = 2;
+
+                    RealArray tmpArray = new RealArray(composite, IndexingOrder.NEAR, newDims);
+                    this.array = new ComplexArray(tmpArray.reverseOrder().values(), newDims);
+                }
+
+                break;
+
+            case MATLAB_MX_INT8_CLASS:
+            case MATLAB_MX_UINT8_CLASS:
+            case MATLAB_MX_INT16_CLASS:
+            case MATLAB_MX_UINT16_CLASS:
+            case MATLAB_MX_INT32_CLASS:
+            case MATLAB_MX_UINT32_CLASS:
+                this.array = new IntegerArray(new IntArrayDataElement(bb).get(), //
+                        IndexingOrder.NEAR, dims).reverseOrder();
+                break;
+
+            default:
+                throw new IllegalArgumentException("Invalid Matlab matrix type");
+            }
+
+            Control.checkTrue(this.size == bb.position() - savePosition, //
+                    "Actual data element size does not match expected");
+        }
+
+        @Override
+        protected Array<?, ?> get() {
+            return this.array;
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatrixOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatrixOps.java
new file mode 100755
index 0000000..7f5849c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/MatrixOps.java
@@ -0,0 +1,120 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.util.Control;
+
+/**
+ * A class for matrix operations in pure Java.
+ * 
+ * @author Roy Liu
+ */
+public class MatrixOps {
+
+    /**
+     * A matrix multiply operation in support of
+     * {@link JavaArrayKernel#mul(double[], double[], int, int, double[], boolean)}.
+     */
+    final public static void mul(double[] lhsV, double[] rhsV, int lr, int rc, double[] dstV, boolean isComplex) {
+
+        int factor = (isComplex ? 2 : 1);
+        int lc = (lr != 0) ? lhsV.length / (factor * lr) : 0;
+        int rr = (rc != 0) ? rhsV.length / (factor * rc) : 0;
+        int inner = Control.checkEquals(lc, rr);
+
+        Control.checkTrue(lr >= 0 && rc >= 0 //
+                && (lhsV.length == factor * lr * lc) //
+                && (rhsV.length == factor * rr * rc) //
+                && (dstV.length == factor * lr * rc), //
+                "Invalid array lengths");
+
+        if (isComplex) {
+
+            for (int i = 0; i < lr; i++) {
+
+                for (int j = 0; j < rc; j++) {
+
+                    double sumRe = 0.0;
+                    double sumIm = 0.0;
+
+                    for (int k = 0; k < inner; k++) {
+
+                        int lIndex = 2 * (i * lc + k);
+                        int rIndex = 2 * (k * rc + j);
+
+                        sumRe += lhsV[lIndex] * rhsV[rIndex] //
+                                - lhsV[lIndex + 1] * rhsV[rIndex + 1];
+                        sumIm += lhsV[lIndex] * rhsV[rIndex + 1] //
+                                + lhsV[lIndex + 1] * rhsV[rIndex];
+                    }
+
+                    int outIndex = 2 * (i * rc + j);
+
+                    dstV[outIndex] = sumRe;
+                    dstV[outIndex + 1] = sumIm;
+                }
+            }
+
+        } else {
+
+            for (int i = 0; i < lr; i++) {
+
+                for (int j = 0; j < rc; j++) {
+
+                    double sum = 0.0;
+
+                    for (int k = 0; k < inner; k++) {
+                        sum += lhsV[i * lc + k] * rhsV[k * rc + j];
+                    }
+
+                    dstV[i * rc + j] = sum;
+                }
+            }
+        }
+    }
+
+    /**
+     * A matrix diagonal operation in support of {@link JavaArrayKernel#diag(double[], double[], int, boolean)}.
+     */
+    final public static void diag(double[] srcV, double[] dstV, int size, boolean isComplex) {
+
+        int factor = (isComplex ? 2 : 1);
+
+        Control.checkTrue((srcV.length == factor * size * size) && (dstV.length == factor * size), //
+                "Invalid array lengths");
+
+        if (isComplex) {
+
+            for (int j = 0, m = 2 * size; j < m; j += 2) {
+
+                dstV[j] = srcV[j * size + j];
+                dstV[j + 1] = srcV[j * size + j + 1];
+            }
+
+        } else {
+
+            for (int i = 0; i < size; i++) {
+                dstV[i] = srcV[i * size + i];
+            }
+        }
+    }
+
+    // Dummy constructor.
+    MatrixOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ModalArrayIOKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ModalArrayIOKernel.java
new file mode 100755
index 0000000..6d069e6
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ModalArrayIOKernel.java
@@ -0,0 +1,59 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.array.Array;
+import shared.util.Services;
+
+/**
+ * An implementation of {@link ArrayIOKernel} that is a gateway to multiple I/O schemes.
+ * 
+ * @apiviz.owns shared.array.kernel.MatlabIOKernel
+ * @author Roy Liu
+ */
+public class ModalArrayIOKernel implements ArrayIOKernel {
+
+    volatile ArrayIOKernel opKernel;
+
+    /**
+     * Default constructor.
+     */
+    public ModalArrayIOKernel() {
+
+        this.opKernel = Services.createService(ArrayIOKernel.class);
+
+        if (this.opKernel == null) {
+            this.opKernel = new MatlabIOKernel();
+        }
+    }
+
+    /**
+     * Attempts to use the underlying {@link MatlabIOKernel}.
+     */
+    public void useMatlabIO() {
+        this.opKernel = new MatlabIOKernel();
+    }
+
+    public <T extends Array<T, E>, E> byte[] getBytes(T array) {
+        return this.opKernel.getBytes(array);
+    }
+
+    public <T extends Array<T, ?>> T parse(byte[] data) {
+        return this.opKernel.parse(data);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ModalArrayKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ModalArrayKernel.java
new file mode 100755
index 0000000..b5f7127
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/ModalArrayKernel.java
@@ -0,0 +1,200 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import shared.array.jni.NativeArrayKernel;
+import shared.array.sparse.SparseArrayState;
+import shared.util.Services;
+
+/**
+ * An implementation of {@link ArrayKernel} that has JNI and pure Java bindings.
+ * 
+ * @apiviz.owns shared.array.kernel.JavaArrayKernel
+ * @author Roy Liu
+ */
+public class ModalArrayKernel implements ArrayKernel {
+
+    volatile ArrayKernel opKernel;
+
+    /**
+     * Default constructor. Tries to create an underlying {@link NativeArrayKernel}. Failing that, creates an underlying
+     * {@link JavaArrayKernel}.
+     */
+    public ModalArrayKernel() {
+
+        this.opKernel = Services.createService(ArrayKernel.class);
+
+        if (this.opKernel == null) {
+            this.opKernel = new JavaArrayKernel();
+        }
+    }
+
+    /**
+     * Uses the underlying {@link NativeArrayKernel} obtained from {@link Services#createService(Class)}.
+     */
+    public boolean useNative() {
+
+        this.opKernel = Services.createService(ArrayKernel.class);
+
+        if (this.opKernel == null) {
+
+            this.opKernel = new JavaArrayKernel();
+
+            return false;
+
+        } else {
+
+            return true;
+        }
+    }
+
+    /**
+     * Uses the underlying {@link JavaArrayKernel}.
+     */
+    public void useJava() {
+        this.opKernel = new JavaArrayKernel();
+    }
+
+    //
+
+    public void randomize() {
+        this.opKernel.randomize();
+    }
+
+    public void derandomize() {
+        this.opKernel.derandomize();
+    }
+
+    //
+
+    public void map(int[] bounds, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS) {
+        this.opKernel.map(bounds, srcV, srcD, srcS, dstV, dstD, dstS);
+    }
+
+    public void slice( //
+            int[] slices, //
+            Object srcV, int[] srcD, int[] srcS, //
+            Object dstV, int[] dstD, int[] dstS) {
+        this.opKernel.slice(slices, srcV, srcD, srcS, dstV, dstD, dstS);
+    }
+
+    //
+
+    public void rrOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS, //
+            int... selectedDims) {
+        this.opKernel.rrOp(type, srcV, srcD, srcS, dstV, dstD, dstS, selectedDims);
+    }
+
+    public void riOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, int[] dstV, //
+            int dim) {
+        this.opKernel.riOp(type, srcV, srcD, srcS, dstV, dim);
+    }
+
+    public void rdOp(int type, //
+            double[] srcV, int[] srcD, int[] srcS, double[] dstV, //
+            int... selectedDims) {
+        this.opKernel.rdOp(type, srcV, srcD, srcS, dstV, selectedDims);
+    }
+
+    public double raOp(int type, double[] srcV) {
+        return this.opKernel.raOp(type, srcV);
+    }
+
+    public double[] caOp(int type, double[] srcV) {
+        return this.opKernel.caOp(type, srcV);
+    }
+
+    public void ruOp(int type, double a, double[] srcV) {
+        this.opKernel.ruOp(type, a, srcV);
+    }
+
+    public void cuOp(int type, double aRe, double aIm, double[] srcV) {
+        this.opKernel.cuOp(type, aRe, aIm, srcV);
+    }
+
+    public void iuOp(int type, int a, int[] srcV) {
+        this.opKernel.iuOp(type, a, srcV);
+    }
+
+    public void eOp(int type, Object lhsV, Object rhsV, Object dstV, boolean isComplex) {
+        this.opKernel.eOp(type, lhsV, rhsV, dstV, isComplex);
+    }
+
+    public void convert(int type, //
+            Object srcV, boolean isSrcComplex, //
+            Object dstV, boolean isDstComplex) {
+        this.opKernel.convert(type, srcV, isSrcComplex, dstV, isDstComplex);
+    }
+
+    //
+
+    public void mul(double[] lhsV, double[] rhsV, int lr, int rc, double[] dstV, boolean isComplex) {
+        this.opKernel.mul(lhsV, rhsV, lr, rc, dstV, isComplex);
+    }
+
+    public void diag(double[] srcV, double[] dstV, int size, boolean isComplex) {
+        this.opKernel.diag(srcV, dstV, size, isComplex);
+    }
+
+    //
+
+    public void svd(double[] srcV, int srcStrideRow, int srcStrideCol, //
+            double[] uV, double[] sV, double[] vV, //
+            int nrows, int ncols) {
+        this.opKernel.svd(srcV, srcStrideRow, srcStrideCol, uV, sV, vV, nrows, ncols);
+    }
+
+    public void eigs(double[] srcV, double[] vecV, double[] valV, int size) {
+        this.opKernel.eigs(srcV, vecV, valV, size);
+    }
+
+    public void invert(double[] srcV, double[] dstV, int size) {
+        this.opKernel.invert(srcV, dstV, size);
+    }
+
+    //
+
+    public int[] find(int[] srcV, int[] srcD, int[] srcS, int[] logical) {
+        return this.opKernel.find(srcV, srcD, srcS, logical);
+    }
+
+    //
+
+    public <V> SparseArrayState<V> insertSparse( //
+            V oldV, int[] oldD, int[] oldS, int[] oldDO, int[] oldI, //
+            V newV, int[] newI) {
+        return this.opKernel.insertSparse(oldV, oldD, oldS, oldDO, oldI, newV, newI);
+    }
+
+    public <V> SparseArrayState<V> sliceSparse(int[] slices, //
+            V srcV, int[] srcD, int[] srcS, int[] srcDO, //
+            int[] srcI, int[] srcIO, int[] srcII, //
+            V dstV, int[] dstD, int[] dstS, int[] dstDO, //
+            int[] dstI, int[] dstIO, int[] dstII) {
+        return this.opKernel.sliceSparse(slices, //
+                srcV, srcD, srcS, srcDO, //
+                srcI, srcIO, srcII, //
+                dstV, dstD, dstS, dstDO, //
+                dstI, dstIO, dstII);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/PermutationEntry.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/PermutationEntry.java
new file mode 100755
index 0000000..6bc3660
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/PermutationEntry.java
@@ -0,0 +1,129 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import java.util.Arrays;
+
+/**
+ * A bookkeeping class for permutations.
+ * 
+ * @param <C>
+ *            the {@link Comparable} type.
+ * @author Roy Liu
+ */
+public class PermutationEntry<C extends Comparable<? super C>> implements Comparable<PermutationEntry<C>> {
+
+    C value;
+
+    int order;
+
+    /**
+     * Default constructor.
+     */
+    public PermutationEntry(C value, int order) {
+
+        this.value = value;
+        this.order = order;
+    }
+
+    /**
+     * Compares values.
+     */
+    public int compareTo(PermutationEntry<C> o) {
+        return this.value.compareTo(o.value);
+    }
+
+    /**
+     * Gets the value.
+     */
+    public C getValue() {
+        return this.value;
+    }
+
+    /**
+     * Gets the order.
+     */
+    public int getOrder() {
+        return this.order;
+    }
+
+    /**
+     * Performs an index sort operation in support of {@link DimensionOps}.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param srcIndices
+     *            the source indices.
+     * @param dstV
+     *            the destination values.
+     * @param size
+     *            the dimension size.
+     * @param stride
+     *            the dimension stride.
+     * @param <T>
+     *            the component type.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <T extends Comparable<? super T>> void iSort(T[] srcV, int[] srcIndices, int[] dstV, int size,
+            int stride) {
+
+        int len = (srcIndices != null) ? size : srcV.length;
+
+        PermutationEntry<T>[] entries = new PermutationEntry[len];
+
+        for (int i = 0; i < len; i++) {
+            entries[i] = new PermutationEntry<T>((T) null, -1);
+        }
+
+        if (srcIndices != null) {
+
+            for (int i = 0, nindices = srcIndices.length; i < nindices; i++) {
+
+                for (int offset = 0, j = 0; j < size; offset += stride, j++) {
+
+                    entries[j].value = srcV[srcIndices[i] + offset];
+                    entries[j].order = j;
+                }
+
+                Arrays.sort(entries);
+
+                for (int offset = 0, j = 0; j < size; offset += stride, j++) {
+
+                    srcV[srcIndices[i] + offset] = entries[j].value;
+                    dstV[srcIndices[i] + offset] = entries[j].order;
+                }
+            }
+
+        } else {
+
+            for (int i = 0, n = srcV.length; i < n; i++) {
+
+                entries[i].value = srcV[i];
+                entries[i].order = i;
+            }
+
+            Arrays.sort(entries);
+
+            for (int i = 0, n = srcV.length; i < n; i++) {
+
+                srcV[i] = entries[i].value;
+                dstV[i] = entries[i].order;
+            }
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/SparseOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/SparseOps.java
new file mode 100755
index 0000000..4107263
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/SparseOps.java
@@ -0,0 +1,820 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.kernel;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+import shared.array.sparse.SparseArrayState;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A class for sparse array operations in pure Java.
+ * 
+ * @author Roy Liu
+ */
+public class SparseOps {
+
+    /**
+     * An insertion operation in support of
+     * {@link JavaArrayKernel#insertSparse(Object, int[], int[], int[], int[], Object, int[])}.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <V> SparseArrayState<V> insert( //
+            V oldV, int[] oldD, int[] oldS, int[] oldDO, int[] oldI, //
+            V newV, int[] newI) {
+
+        int ndims = oldD.length;
+        int oldLen = Array.getLength(oldV);
+        int newLen = Array.getLength(newV);
+
+        Control.checkTrue(ndims == oldS.length //
+                && oldLen == oldI.length //
+                && newLen == newI.length, //
+                "Invalid arguments");
+
+        MappingOps.checkDimensions(Arithmetic.product(oldD), oldD, oldS);
+
+        for (int dim = 0; dim < ndims; dim++) {
+            Control.checkTrue(oldDO[dim + 1] - oldDO[dim] - 1 == oldD[dim], //
+                    "Invalid arguments");
+        }
+
+        PermutationEntry<Integer>[] entries = new PermutationEntry[newLen];
+
+        for (int i = 0; i < newLen; i++) {
+            entries[i] = new PermutationEntry<Integer>(newI[i], i);
+        }
+
+        Arrays.sort(entries);
+
+        int[] perm = new int[newLen];
+
+        for (int i = 0; i < newLen; i++) {
+
+            newI[i] = entries[i].getValue();
+            perm[i] = entries[i].getOrder();
+        }
+
+        for (int i = 1; i < newLen; i++) {
+            Control.checkTrue(entries[i - 1].getValue() != entries[i].getValue(), //
+                    "Duplicate values are not allowed");
+        }
+
+        int[][] mergeResult = merge( //
+                oldI, Arithmetic.range(oldLen), //
+                newI, Arithmetic.range(newLen), //
+                oldD, oldS, oldDO);
+
+        int[] newIndirections = mergeResult[3];
+
+        for (int i = 0; i < newLen; i++) {
+            perm[i] = newIndirections[perm[i]];
+        }
+
+        System.arraycopy(perm, 0, newIndirections, 0, newLen);
+
+        return assign(oldV, newV, mergeResult);
+    }
+
+    /**
+     * A slicing operation in support of
+     * {@link JavaArrayKernel#sliceSparse(int[], Object, int[], int[], int[], int[], int[], int[], Object, int[], int[], int[], int[], int[], int[])}
+     * .
+     */
+    final public static <V> SparseArrayState<V> slice(int[] slices, //
+            V srcV, int[] srcD, int[] srcS, int[] srcDO, //
+            int[] srcI, int[] srcIO, int[] srcII, //
+            V dstV, int[] dstD, int[] dstS, int[] dstDO, //
+            int[] dstI, int[] dstIO, int[] dstII) {
+
+        int nslices = slices.length / 3;
+        int ndims = srcD.length;
+        int srcLen = Array.getLength(srcV);
+        int dstLen = Array.getLength(dstV);
+
+        Control.checkTrue(ndims == srcS.length //
+                && ndims == dstD.length //
+                && ndims == dstS.length //
+                && slices.length % 3 == 0 //
+                && srcLen == srcI.length //
+                && dstLen == dstI.length //
+                && srcDO.length == ndims + 1 //
+                && srcIO.length == Arithmetic.sum(srcD) + ndims //
+                && srcII.length == ndims * srcLen //
+                && dstDO.length == ndims + 1 //
+                && dstIO.length == Arithmetic.sum(dstD) + ndims //
+                && dstII.length == ndims * dstLen, //
+                "Invalid arguments");
+
+        MappingOps.checkDimensions(Arithmetic.product(srcD), srcD, srcS);
+        MappingOps.checkDimensions(Arithmetic.product(dstD), dstD, dstS);
+
+        for (int i = 0, n = 3 * nslices; i < n; i += 3) {
+
+            int srcIndex = slices[i];
+            int dstIndex = slices[i + 1];
+            int dim = slices[i + 2];
+
+            Control.checkTrue(dim >= 0 && dim < ndims, //
+                    "Invalid dimension");
+
+            Control.checkTrue((srcIndex >= 0 && srcIndex < srcD[dim]) //
+                    && (dstIndex >= 0 && dstIndex < dstD[dim]), //
+                    "Invalid index");
+        }
+
+        for (int dim = 0; dim < ndims; dim++) {
+            Control.checkTrue((srcDO[dim + 1] - srcDO[dim] - 1 == srcD[dim]) //
+                    && (dstDO[dim + 1] - dstDO[dim] - 1 == dstD[dim]), //
+                    "Invalid arguments");
+        }
+
+        //
+
+        int offsetArrayLen = srcDO[ndims];
+
+        int[] srcSliceCounts = new int[ndims];
+        int[] lookupCounts = new int[offsetArrayLen];
+
+        Arrays.fill(srcSliceCounts, 0);
+        Arrays.fill(lookupCounts, 0);
+
+        for (int i = 0, n = 3 * nslices; i < n; i += 3) {
+
+            int srcIndex = slices[i];
+            int dim = slices[i + 2];
+
+            srcSliceCounts[dim]++;
+            lookupCounts[srcDO[dim] + srcIndex]++;
+        }
+
+        //
+
+        int[] sliceOffsets = new int[ndims + 1];
+        int[] lookupOffsets = new int[offsetArrayLen];
+
+        int sliceOffset = 0;
+        int lookupOffset = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            sliceOffsets[dim] = sliceOffset;
+            sliceOffset += srcSliceCounts[dim];
+
+            int dimSize = srcD[dim];
+
+            for (int dimIndex = 0; dimIndex < dimSize; dimIndex++) {
+
+                lookupOffsets[srcDO[dim] + dimIndex] = lookupOffset;
+                lookupOffset += lookupCounts[srcDO[dim] + dimIndex];
+            }
+
+            lookupOffsets[srcDO[dim] + dimSize] = lookupOffset;
+        }
+
+        sliceOffsets[ndims] = sliceOffset;
+
+        //
+
+        int[] srcSlices = new int[sliceOffset];
+        int[] dstSlices = new int[sliceOffset];
+        int[] dstSliceCounts = new int[ndims];
+        int[] dstLookups = new int[lookupOffset];
+
+        Arrays.fill(srcSliceCounts, 0);
+        Arrays.fill(lookupCounts, 0);
+
+        for (int i = 0, n = 3 * nslices; i < n; i += 3) {
+
+            int srcIndex = slices[i];
+            int dstIndex = slices[i + 1];
+            int dim = slices[i + 2];
+
+            srcSlices[sliceOffsets[dim] + srcSliceCounts[dim]] = srcIndex;
+            dstSlices[sliceOffsets[dim] + srcSliceCounts[dim]] = dstIndex;
+            dstLookups[lookupOffsets[srcDO[dim] + srcIndex] //
+                    + lookupCounts[srcDO[dim] + srcIndex]] = dstIndex;
+
+            srcSliceCounts[dim]++;
+            lookupCounts[srcDO[dim] + srcIndex]++;
+        }
+
+        //
+
+        Arrays.fill(srcSliceCounts, 0);
+        Arrays.fill(lookupCounts, 0);
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            srcSliceCounts[dim] = normalize(srcSlices, sliceOffsets[dim], sliceOffsets[dim + 1]);
+            dstSliceCounts[dim] = normalize(dstSlices, sliceOffsets[dim], sliceOffsets[dim + 1]);
+
+            for (int dimIndex = 0, dimSize = srcD[dim]; dimIndex < dimSize; dimIndex++) {
+                lookupCounts[srcDO[dim] + dimIndex] = normalize(dstLookups, //
+                        lookupOffsets[srcDO[dim] + dimIndex], //
+                        lookupOffsets[srcDO[dim] + dimIndex + 1]);
+            }
+        }
+
+        //
+
+        int[] srcIndirections = getSlicedIndirections(sliceOffsets, srcSliceCounts, srcSlices, //
+                srcDO, srcIO, srcII, srcD);
+        int nsrcIndirections = srcIndirections.length;
+
+        int[] dstIndirections = getSlicedIndirections(sliceOffsets, dstSliceCounts, dstSlices, //
+                dstDO, dstIO, dstII, dstD);
+        int ndstIndirections = dstIndirections.length;
+
+        //
+
+        int[] indirectionOffsets = new int[nsrcIndirections + 1];
+        int indirectionOffset = 0;
+
+        for (int i = 0, prodD = Arithmetic.product(srcD); i < nsrcIndirections; i++) {
+
+            int indirection = srcIndirections[i];
+
+            Control.checkTrue(indirection >= 0 && indirection < srcLen, //
+                    "Invalid indirection index");
+
+            int physical = srcI[indirection];
+
+            Control.checkTrue(physical >= 0 && physical < prodD, //
+                    "Invalid physical index");
+
+            int mapLen = 1;
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                int logicalIndex = physical / srcS[dim];
+
+                mapLen *= lookupCounts[srcDO[dim] + logicalIndex];
+
+                physical %= srcS[dim];
+            }
+
+            indirectionOffsets[i] = indirectionOffset;
+            indirectionOffset += mapLen;
+        }
+
+        indirectionOffsets[nsrcIndirections] = indirectionOffset;
+
+        //
+
+        int[] newIndirections = new int[indirectionOffset];
+        int[] newIndices = new int[indirectionOffset];
+        int[] logical = new int[ndims];
+
+        for (int i = 0; i < nsrcIndirections; i++) {
+
+            int indirection = srcIndirections[i];
+            int physical = srcI[indirection];
+
+            indirectionOffset = indirectionOffsets[i];
+
+            newIndices[indirectionOffset] = 0;
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                logical[dim] = physical / srcS[dim];
+
+                newIndices[indirectionOffset] += dstS[dim] //
+                        * dstLookups[lookupOffsets[srcDO[dim] + logical[dim]]];
+
+                physical %= srcS[dim];
+            }
+
+            Arrays.fill(newIndirections, indirectionOffsets[i], indirectionOffsets[i + 1], indirection);
+
+            for (int dim = ndims - 1, blockSize = 1, size; dim >= 0; blockSize *= size, dim--) {
+
+                int start = lookupOffsets[srcDO[dim] + logical[dim]];
+                size = lookupCounts[srcDO[dim] + logical[dim]];
+
+                for (int offset = indirectionOffset + blockSize, //
+                offsetEnd = indirectionOffset + blockSize * size, n = start + 1; //
+                offset < offsetEnd; offset += blockSize, n++) {
+
+                    int strideOffset = dstS[dim] * (dstLookups[n] - dstLookups[n - 1]);
+
+                    for (int j = offset - blockSize, k = offset; j < offset; j++, k++) {
+                        newIndices[k] = newIndices[j] + strideOffset;
+                    }
+                }
+            }
+        }
+
+        //
+
+        final int[] oldIndices;
+        final int[] oldIndirections;
+
+        if (ndstIndirections > 0) {
+
+            oldIndices = new int[dstI.length - ndstIndirections];
+            oldIndirections = new int[dstI.length - ndstIndirections];
+
+            int count = 0;
+
+            for (int i = 0, m = dstIndirections[0]; i < m; i++, count++) {
+
+                oldIndices[count] = dstI[i];
+                oldIndirections[count] = i;
+            }
+
+            for (int i = 0, n = ndstIndirections - 1; i < n; i++) {
+
+                for (int j = dstIndirections[i] + 1, m = dstIndirections[i + 1]; j < m; j++, count++) {
+
+                    oldIndices[count] = dstI[j];
+                    oldIndirections[count] = j;
+                }
+            }
+
+            for (int i = dstIndirections[ndstIndirections - 1] + 1, m = dstI.length; i < m; i++, count++) {
+
+                oldIndices[count] = dstI[i];
+                oldIndirections[count] = i;
+            }
+
+        } else {
+
+            oldIndices = dstI;
+            oldIndirections = Arithmetic.range(dstI.length);
+        }
+
+        //
+
+        int[][] res = merge(newIndices, newIndirections);
+        newIndices = res[0];
+        newIndirections = res[1];
+
+        return assign(dstV, srcV, merge(oldIndices, oldIndirections, newIndices, newIndirections, //
+                dstD, dstS, dstDO));
+    }
+
+    /**
+     * Aggregates old values, new values, and their assignments into a {@link SparseArrayState}.
+     * 
+     * @param oldV
+     *            the old values.
+     * @param newV
+     *            the new values.
+     * @param mergeResult
+     *            the result of {@link #merge(int[], int[], int[], int[], int[], int[], int[])}.
+     * @param <V>
+     *            the storage array type.
+     * @return the {@link SparseArrayState}.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <V> SparseArrayState<V> assign(V oldV, V newV, int[][] mergeResult) {
+
+        int[] oldAssignments = mergeResult[0];
+        int[] oldIndirections = mergeResult[1];
+        int[] newAssignments = mergeResult[2];
+        int[] newIndirections = mergeResult[3];
+        int[] indices = mergeResult[4];
+        int[] indirectionOffsets = mergeResult[5];
+        int[] indirections = mergeResult[6];
+
+        int nindices = indices.length;
+
+        final V values;
+
+        if (oldV instanceof double[] && newV instanceof double[]) {
+
+            double[] oldVArr = (double[]) oldV;
+            double[] newVArr = (double[]) newV;
+            double[] dstVArr = new double[nindices];
+
+            for (int i = 0, n = oldAssignments.length; i < n; i++) {
+                dstVArr[oldAssignments[i]] = oldVArr[oldIndirections[i]];
+            }
+
+            for (int i = 0, n = newAssignments.length; i < n; i++) {
+                dstVArr[newAssignments[i]] = newVArr[newIndirections[i]];
+            }
+
+            values = (V) dstVArr;
+
+        } else if (oldV instanceof int[] && newV instanceof int[]) {
+
+            int[] oldVArr = (int[]) oldV;
+            int[] newVArr = (int[]) newV;
+            int[] dstVArr = new int[nindices];
+
+            for (int i = 0, n = oldAssignments.length; i < n; i++) {
+                dstVArr[oldAssignments[i]] = oldVArr[oldIndirections[i]];
+            }
+
+            for (int i = 0, n = newAssignments.length; i < n; i++) {
+                dstVArr[newAssignments[i]] = newVArr[newIndirections[i]];
+            }
+
+            values = (V) dstVArr;
+
+        } else if (oldV instanceof Object[] && newV instanceof Object[]) {
+
+            Control.checkTrue(oldV.getClass().isAssignableFrom(newV.getClass()), //
+                    "Invalid array types");
+
+            Object[] oldVArr = (Object[]) oldV;
+            Object[] newVArr = (Object[]) newV;
+            Object[] dstVArr = (Object[]) Array.newInstance( //
+                    oldVArr.getClass().getComponentType(), nindices);
+
+            for (int i = 0, n = oldAssignments.length; i < n; i++) {
+                dstVArr[oldAssignments[i]] = oldVArr[oldIndirections[i]];
+            }
+
+            for (int i = 0, n = newAssignments.length; i < n; i++) {
+                dstVArr[newAssignments[i]] = newVArr[newIndirections[i]];
+            }
+
+            values = (V) dstVArr;
+
+        } else {
+
+            throw new IllegalArgumentException("Invalid arguments");
+        }
+
+        return new SparseArrayState<V>(values, indices, indirectionOffsets, indirections);
+    }
+
+    /**
+     * Merges old and new array metadata.
+     * 
+     * @param oldIndices
+     *            the old physical indices. Invariant: Sorted in ascending order, and does not contain duplicates.
+     * @param oldIndirections
+     *            the indirections on old values.
+     * @param newIndices
+     *            the new physical indices. Invariant: Sorted in ascending order, and does not contain duplicates.
+     * @param newIndirections
+     *            the indirections on new values.
+     * @param dims
+     *            the dimensions.
+     * @param strides
+     *            the strides.
+     * @param dimOffsets
+     *            the dimension offsets.
+     * @return the assignments and metadata.
+     */
+    final public static int[][] merge( //
+            int[] oldIndices, int[] oldIndirections, //
+            int[] newIndices, int[] newIndirections, //
+            int[] dims, int[] strides, int[] dimOffsets) {
+
+        int oldLen = oldIndices.length;
+        int newLen = newIndices.length;
+
+        int[] oldAssignments = new int[oldLen];
+        int[] newAssignments = new int[newLen];
+
+        int count = 0;
+        int oldCount = 0;
+        int newCount = 0;
+
+        for (; oldCount < oldLen && newCount < newLen;) {
+
+            if (oldIndices[oldCount] < newIndices[newCount]) {
+
+                oldAssignments[oldCount++] = count++;
+
+            } else if (oldIndices[oldCount] > newIndices[newCount]) {
+
+                newAssignments[newCount++] = count++;
+
+            } else {
+
+                oldAssignments[oldCount++] = count;
+                newAssignments[newCount++] = count;
+                count++;
+            }
+        }
+
+        for (; oldCount < oldLen; oldCount++, count++) {
+            oldAssignments[oldCount] = count;
+        }
+
+        for (; newCount < newLen; newCount++, count++) {
+            newAssignments[newCount] = count;
+        }
+
+        //
+
+        int[] indices = new int[count];
+
+        for (int i = 0; i < oldLen; i++) {
+            indices[oldAssignments[i]] = oldIndices[i];
+        }
+
+        for (int i = 0; i < newLen; i++) {
+            indices[newAssignments[i]] = newIndices[i];
+        }
+
+        //
+
+        int sumD = Arithmetic.sum(dims);
+        int prodD = Arithmetic.product(dims);
+        int ndims = Control.checkEquals(dims.length, strides.length);
+
+        //
+
+        int[] dimCounts = new int[sumD + ndims];
+
+        Arrays.fill(dimCounts, 0);
+
+        for (int i = 0, acc; i < count; i++) {
+
+            acc = indices[i];
+
+            Control.checkTrue(acc >= 0 && acc < prodD, //
+                    "Invalid physical index");
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                int dimOffset = dimOffsets[dim] + acc / strides[dim];
+
+                dimCounts[dimOffset]++;
+                acc %= strides[dim];
+            }
+        }
+
+        //
+
+        int[] indirectionOffsets = new int[sumD + ndims];
+
+        for (int dim = 0, acc; dim < ndims; dim++) {
+
+            acc = 0;
+
+            int dimOffset = dimOffsets[dim];
+            int dimSize = dims[dim];
+
+            for (int dimIndex = 0; dimIndex < dimSize; dimIndex++) {
+
+                indirectionOffsets[dimOffset + dimIndex] = acc;
+                acc += dimCounts[dimOffsets[dim] + dimIndex];
+            }
+
+            indirectionOffsets[dimOffset + dimSize] = count;
+        }
+
+        //
+
+        Arrays.fill(dimCounts, 0);
+
+        int[] indirections = new int[ndims * count];
+
+        for (int i = 0, acc; i < count; i++) {
+
+            acc = indices[i];
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                int dimOffset = dimOffsets[dim] + acc / strides[dim];
+
+                indirections[count * dim + indirectionOffsets[dimOffset] + dimCounts[dimOffset]] = i;
+                dimCounts[dimOffset]++;
+                acc %= strides[dim];
+            }
+        }
+
+        return new int[][] {
+        //
+                oldAssignments, //
+                oldIndirections, //
+                newAssignments, //
+                newIndirections, //
+                indices, //
+                indirectionOffsets, //
+                indirections //
+        };
+    }
+
+    /**
+     * Normalizes a range of sorted values such that duplicates are removed.
+     * 
+     * @param values
+     *            the array of values.
+     * @param start
+     *            the start index.
+     * @param end
+     *            the end index.
+     * @return the number of resulting unique values.
+     */
+    final public static int normalize(int[] values, int start, int end) {
+
+        Arrays.sort(values, start, end);
+
+        int propagate = 0;
+
+        for (int i = start, current = -1; i < end; i++) {
+
+            values[i - propagate] = values[i];
+
+            if (current != values[i]) {
+
+                current = values[i];
+
+            } else {
+
+                propagate++;
+            }
+        }
+
+        return end - start - propagate;
+    }
+
+    /**
+     * Gets the sliced indirections.
+     * 
+     * @param sliceOffsets
+     *            the slice offsets.
+     * @param sliceCounts
+     *            the slice counts.
+     * @param slices
+     *            the slices.
+     * @param dimOffsets
+     *            the dimension offsets.
+     * @param indirectionOffsets
+     *            the indirection offsets.
+     * @param indirections
+     *            the indirections.
+     * @param dims
+     *            the dimensions.
+     * @return the sliced indirections.
+     */
+    final public static int[] getSlicedIndirections( //
+            int[] sliceOffsets, int[] sliceCounts, int[] slices, //
+            int[] dimOffsets, int[] indirectionOffsets, int[] indirections, int[] dims) {
+
+        int ndims = sliceOffsets.length - 1;
+        int nindirections = indirections.length / ndims;
+
+        int[] intersection = null;
+        int len = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            int dimOffset = dimOffsets[dim];
+
+            int sliceStart = sliceOffsets[dim];
+            int sliceEnd = sliceOffsets[dim] + sliceCounts[dim];
+
+            int nslices = sliceEnd - sliceStart;
+
+            int nelts = 0;
+
+            for (int i = 0; i < nslices; i++) {
+
+                int index = slices[i + sliceStart];
+
+                int start = indirectionOffsets[dimOffset + index];
+                int end = indirectionOffsets[dimOffset + index + 1];
+
+                Control.checkTrue(start >= 0 //
+                        && start <= end //
+                        && end >= 0 //
+                        && end <= nindirections, //
+                        "Invalid arguments");
+
+                nelts += end - start;
+            }
+
+            int[] res = new int[nelts];
+
+            for (int i = 0, resCount = 0; i < nslices; i++) {
+
+                int index = slices[i + sliceStart];
+
+                int start = indirectionOffsets[dimOffset + index];
+                int end = indirectionOffsets[dimOffset + index + 1];
+
+                for (int j = start; j < end; j++) {
+                    res[resCount++] = indirections[nindirections * dim + j];
+                }
+            }
+
+            Arrays.sort(res);
+
+            if (intersection != null) {
+
+                int intersectionLower = 0;
+                int intersectionUpper = len;
+
+                int resLower = 0;
+                int resUpper = nelts;
+
+                int propagate = 0;
+
+                for (; intersectionLower < intersectionUpper && resLower < resUpper;) {
+
+                    if (intersection[intersectionLower] < res[resLower]) {
+
+                        intersection[intersectionLower - propagate] = intersection[intersectionLower];
+                        propagate++;
+
+                        intersectionLower++;
+
+                    } else if (intersection[intersectionLower] > res[resLower]) {
+
+                        resLower++;
+
+                    } else {
+
+                        intersection[intersectionLower - propagate] = intersection[intersectionLower];
+
+                        intersectionLower++;
+                        resLower++;
+                    }
+                }
+
+                len = intersectionLower - propagate;
+
+            } else {
+
+                intersection = res;
+                len = nelts;
+            }
+        }
+
+        return Arrays.copyOf(intersection, len);
+    }
+
+    /**
+     * Merges sliced indirections by physical index.
+     * 
+     * @param indices
+     *            the physical indices.
+     * @param indirections
+     *            the sliced indirections.
+     * @return the merged physical indices and indirections.
+     */
+    @SuppressWarnings("unchecked")
+    final public static int[][] merge(int[] indices, int[] indirections) {
+
+        int nelts = Control.checkEquals(indices.length, indirections.length, //
+                "Invalid arguments");
+
+        PermutationEntry<Integer>[] entries = new PermutationEntry[nelts];
+
+        for (int i = 0; i < nelts; i++) {
+            entries[i] = new PermutationEntry<Integer>(indices[i], indirections[i]);
+        }
+
+        Arrays.sort(entries);
+
+        int propagate = 0;
+
+        for (int i = 0, current = -1; i < nelts; i++) {
+
+            entries[i - propagate] = entries[i];
+
+            if (current != entries[i].getValue()) {
+
+                current = entries[i].getValue();
+
+            } else {
+
+                propagate++;
+            }
+        }
+
+        int resLen = nelts - propagate;
+
+        int[] resIndices = new int[resLen];
+        int[] resIndirections = new int[resLen];
+
+        for (int i = 0; i < resLen; i++) {
+
+            resIndices[i] = entries[i].getValue();
+            resIndirections[i] = entries[i].getOrder();
+        }
+
+        return new int[][] { resIndices, resIndirections };
+    }
+
+    // Dummy constructor.
+    SparseOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/package-info.java
new file mode 100755
index 0000000..3847fc4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/kernel/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package for basic operations on {@link shared.array.Array}s.
+ */
+package shared.array.kernel;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/package-info.java
new file mode 100755
index 0000000..bf9651b
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of multidimensional arrays.
+ */
+package shared.array;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/IntegerSparseArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/IntegerSparseArray.java
new file mode 100755
index 0000000..8c36e28
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/IntegerSparseArray.java
@@ -0,0 +1,168 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.sparse;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.formatSparseArray;
+
+import java.util.Formatter;
+
+import shared.array.ArrayBase;
+import shared.array.IntegerArray;
+import shared.util.Arithmetic;
+import shared.util.Arrays;
+import shared.util.Control;
+
+/**
+ * A sparse integer array class.
+ * 
+ * @author Roy Liu
+ */
+public class IntegerSparseArray extends ProtoSparseArray<IntegerSparseArray, int[], Integer, IntegerArray> {
+
+    /**
+     * An empty array.
+     */
+    final protected static int[] Empty = new int[] {};
+
+    /**
+     * Default constructor.
+     */
+    public IntegerSparseArray(int... dims) {
+        this(0, dims.clone());
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected IntegerSparseArray(int unused, int[] dims) {
+        super(new SparseArrayState<int[]>(Empty, dims), //
+                dims, DEFAULT_ORDER.strides(dims), createDimensionOffsets(dims));
+
+        Control.checkTrue(dims.length > 0);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public IntegerSparseArray(IntegerSparseArray array) {
+        this(array.state, array.dims, array.strides, array.dimOffsets);
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected IntegerSparseArray(SparseArrayState<int[]> state, int[] dims, int[] strides, int[] dimOffsets) {
+        super(state, dims, strides, dimOffsets);
+    }
+
+    public Class<Integer> getComponentType() {
+        return Integer.class;
+    }
+
+    @Override
+    protected IntegerSparseArray wrap(Integer value, int[] dims, int[] strides, int[] dimOffsets) {
+
+        final SparseArrayState<int[]> state;
+
+        if (value == null) {
+
+            state = new SparseArrayState<int[]>(Empty, dims);
+
+        } else {
+
+            int[] values = Arrays.newArray(Arithmetic.product(dims), value.intValue());
+
+            state = OpKernel.insertSparse( //
+                    Empty, dims, strides, dimOffsets, EmptyIndices, //
+                    values, Arithmetic.range(values.length));
+        }
+
+        return new IntegerSparseArray(state, dims, strides, dimOffsets);
+    }
+
+    @Override
+    protected IntegerSparseArray wrap(SparseArrayState<int[]> state, int[] dims, int[] strides, int[] dimOffsets) {
+        return new IntegerSparseArray(state, dims, strides, dimOffsets);
+    }
+
+    @Override
+    protected int length(int[] values) {
+        return values.length;
+    }
+
+    @Override
+    protected int[] empty() {
+        return Empty;
+    }
+
+    @Override
+    public IntegerArray toDense() {
+
+        IntegerSparseArray src = this;
+
+        IntegerArray dst = new IntegerArray(src.order(), src.dims);
+
+        SparseArrayState<int[]> srcState = src.state;
+
+        int[] srcValues = srcState.values;
+        int[] srcIndices = srcState.indices;
+
+        int[] dstValues = dst.values();
+
+        for (int i = 0, n = srcValues.length; i < n; i++) {
+            dstValues[srcIndices[i]] = srcValues[i];
+        }
+
+        return dst;
+    }
+
+    @Override
+    public String toString() {
+
+        SparseArrayState<int[]> state = this.state;
+
+        int[] values = state.values;
+        int[] indices = state.indices;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int max = Math.max(Arithmetic.max(values), Math.abs(Arithmetic.min(values)));
+        int exponent = max > 0 ? (int) Math.log10(max) : 0;
+
+        int maxIndex = Arithmetic.max(dims);
+        int exponentIndex = maxIndex > 0 ? (int) Math.log10(maxIndex) : 0;
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            ArrayBase.formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        String valueFormat = String.format("%%%dd", exponent + 3);
+        String indexFormat = String.format("%%%dd", exponentIndex + 2);
+
+        formatSparseArray(f, valueFormat, indexFormat, values, indices, strides);
+
+        return f.toString();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/ObjectSparseArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/ObjectSparseArray.java
new file mode 100755
index 0000000..7ef61ee
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/ObjectSparseArray.java
@@ -0,0 +1,165 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.sparse;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.formatSparseArray;
+
+import java.lang.reflect.Array;
+import java.util.Formatter;
+
+import shared.array.ArrayBase;
+import shared.array.ObjectArray;
+import shared.util.Arithmetic;
+import shared.util.Arrays;
+import shared.util.Control;
+
+/**
+ * A sparse object array class.
+ * 
+ * @param <T>
+ *            the storage type.
+ */
+public class ObjectSparseArray<T> extends ProtoSparseArray<ObjectSparseArray<T>, T[], T, ObjectArray<T>> {
+
+    /**
+     * Default constructor.
+     */
+    public ObjectSparseArray(Class<T> clazz, int... dims) {
+        this(0, clazz, dims.clone());
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    @SuppressWarnings("unchecked")
+    protected ObjectSparseArray(int unused, Class<T> clazz, int[] dims) {
+        super(new SparseArrayState<T[]>((T[]) Array.newInstance(clazz, 0), dims), //
+                dims, DEFAULT_ORDER.strides(dims), createDimensionOffsets(dims));
+
+        Control.checkTrue(dims.length > 0);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ObjectSparseArray(ObjectSparseArray<T> array) {
+        this(array.state, array.dims, array.strides, array.dimOffsets);
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected ObjectSparseArray(SparseArrayState<T[]> state, int[] dims, int[] strides, int[] dimOffsets) {
+        super(state, dims, strides, dimOffsets);
+    }
+
+    @SuppressWarnings("unchecked")
+    public Class<T> getComponentType() {
+        return (Class<T>) this.state.values.getClass().getComponentType();
+    }
+
+    @Override
+    protected ObjectSparseArray<T> wrap(T value, int[] dims, int[] strides, int[] dimOffsets) {
+
+        final SparseArrayState<T[]> state;
+
+        if (value == null) {
+
+            state = new SparseArrayState<T[]>(empty(), dims);
+
+        } else {
+
+            T[] values = Arrays.newArray(getComponentType(), Arithmetic.product(dims), value);
+
+            state = OpKernel.insertSparse( //
+                    empty(), dims, strides, dimOffsets, EmptyIndices, //
+                    values, Arithmetic.range(values.length));
+        }
+
+        return new ObjectSparseArray<T>(state, dims, strides, dimOffsets);
+    }
+
+    @Override
+    protected ObjectSparseArray<T> wrap(SparseArrayState<T[]> state, int[] dims, int[] strides, int[] dimOffsets) {
+        return new ObjectSparseArray<T>(state, dims, strides, dimOffsets);
+    }
+
+    @Override
+    protected int length(T[] values) {
+        return values.length;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected T[] empty() {
+        return (T[]) Array.newInstance(getComponentType(), 0);
+    }
+
+    @Override
+    public ObjectArray<T> toDense() {
+
+        ObjectSparseArray<T> src = this;
+
+        ObjectArray<T> dst = new ObjectArray<T>(getComponentType(), src.order(), src.dims);
+
+        SparseArrayState<T[]> srcState = src.state;
+
+        T[] srcValues = srcState.values;
+        int[] srcIndices = srcState.indices;
+
+        T[] dstValues = dst.values();
+
+        for (int i = 0, n = srcValues.length; i < n; i++) {
+            dstValues[srcIndices[i]] = srcValues[i];
+        }
+
+        return dst;
+    }
+
+    @Override
+    public String toString() {
+
+        SparseArrayState<T[]> state = this.state;
+
+        T[] values = state.values;
+        int[] indices = state.indices;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int maxIndex = Arithmetic.max(dims);
+        int exponentIndex = maxIndex > 0 ? (int) Math.log10(maxIndex) : 0;
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            ArrayBase.formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        String valueFormat = String.format(" \"%%s\"");
+        String indexFormat = String.format("%%%dd", exponentIndex + 2);
+
+        formatSparseArray(f, valueFormat, indexFormat, values, indices, strides);
+
+        return f.toString();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/ProtoSparseArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/ProtoSparseArray.java
new file mode 100755
index 0000000..3cf4a39
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/ProtoSparseArray.java
@@ -0,0 +1,555 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.sparse;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.canonicalizeSlices;
+import static shared.array.ArrayBase.createReverseSlices;
+
+import java.util.Arrays;
+
+import shared.array.Array;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * An abstract, primordial base class for all sparse arrays.
+ * 
+ * @apiviz.owns shared.array.sparse.SparseArrayState
+ * @param <T>
+ *            the parameterization lower bounded by {@link ProtoSparseArray} itself.
+ * @param <V>
+ *            the storage array type.
+ * @param <E>
+ *            the element type.
+ * @param <D>
+ *            the dense array type.
+ * @author Roy Liu
+ */
+abstract public class ProtoSparseArray<T extends ProtoSparseArray<T, V, E, D>, V, E, D extends Array<D, E>> implements
+        Array<T, E> {
+
+    /**
+     * An empty array of indices.
+     */
+    final protected static int[] EmptyIndices = new int[] {};
+
+    /**
+     * The {@link SparseArrayState}.
+     */
+    volatile protected SparseArrayState<V> state;
+
+    /**
+     * The dimensions.
+     */
+    final protected int[] dims;
+
+    /**
+     * The strides.
+     */
+    final protected int[] strides;
+
+    /**
+     * The dimension offsets.
+     */
+    final protected int[] dimOffsets;
+
+    /**
+     * Default constructor.
+     */
+    protected ProtoSparseArray(SparseArrayState<V> state, int[] dims, int[] strides, int[] dimOffsets) {
+
+        this.state = state;
+        this.dims = dims;
+        this.strides = strides;
+        this.dimOffsets = dimOffsets;
+    }
+
+    /**
+     * Creates dimension offsets from the given dimensions.
+     * 
+     * @param dims
+     *            the dimensions.
+     * @return the dimension offsets.
+     */
+    final protected static int[] createDimensionOffsets(int[] dims) {
+
+        int ndims = dims.length;
+        int[] dimOffsets = new int[ndims + 1];
+        int dimOffset = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            dimOffsets[dim] = dimOffset;
+            dimOffset += dims[dim] + 1;
+        }
+
+        dimOffsets[ndims] = dimOffset;
+
+        return dimOffsets;
+    }
+
+    /**
+     * Allocates a new array.
+     * 
+     * @param state
+     *            the {@link SparseArrayState}.
+     * @param dims
+     *            the dimensions.
+     * @param strides
+     *            the strides.
+     * @param dimOffsets
+     *            the dimension offsets.
+     * @return the new array.
+     */
+    abstract protected T wrap(SparseArrayState<V> state, int[] dims, int[] strides, int[] dimOffsets);
+
+    /**
+     * Allocates a new array initialized to the given value.
+     * 
+     * @param value
+     *            the initial value.
+     * @param dims
+     *            the dimensions.
+     * @param strides
+     *            the strides.
+     * @param dimOffsets
+     *            the dimension offsets.
+     * @return the new array.
+     */
+    abstract protected T wrap(E value, int[] dims, int[] strides, int[] dimOffsets);
+
+    /**
+     * Gets the length of the given array.
+     * 
+     * @param values
+     *            the array.
+     * @return the length.
+     */
+    abstract protected int length(V values);
+
+    /**
+     * Gets an empty array of values.
+     */
+    abstract protected V empty();
+
+    /**
+     * Converts this array to its dense form.
+     */
+    abstract public D toDense();
+
+    /**
+     * Inserts values at the given logical indices, which are given in row major order.
+     * 
+     * @param values
+     *            the values to be inserted.
+     * @param logicals
+     *            the logical indices.
+     * @return this array.
+     */
+    @SuppressWarnings("unchecked")
+    public T insert(V values, int... logicals) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = src.dims.length;
+        int newLen = length(values);
+
+        Control.checkTrue(ndims * newLen == logicals.length, //
+                "Invalid arguments");
+
+        int[] newI = new int[newLen];
+
+        for (int i = 0; i < newLen; i++) {
+
+            int physical = 0;
+
+            for (int dim = 0; dim < ndims; dim++) {
+                physical += src.strides[dim] * logicals[ndims * i + dim];
+            }
+
+            newI[i] = physical;
+        }
+
+        SparseArrayState<V> srcState = src.state;
+
+        src.state = OpKernel.insertSparse( //
+                srcState.values, src.dims, src.strides, src.dimOffsets, srcState.indices, //
+                values, newI);
+
+        return (T) src;
+    }
+
+    /**
+     * Gets the number of non-zero elements.
+     */
+    public int size() {
+        return length(this.state.values);
+    }
+
+    public T map(T dst, int... bounds) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, dst.dims.length, //
+                "Dimensionality mismatch");
+
+        Control.checkTrue(3 * ndims == bounds.length, //
+                "Invalid arguments");
+
+        //
+
+        int nslices = 0;
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+
+            int size = bounds[offset + 2];
+
+            Control.checkTrue(size >= 0, //
+                    "Invalid mapping parameters");
+
+            nslices += size;
+        }
+
+        if (Arithmetic.product(src.dims) == 0 || Arithmetic.product(dst.dims) == 0) {
+            return dst;
+        }
+
+        //
+
+        int[] slices = new int[3 * nslices];
+
+        for (int dim = 0, acc = 0, offset = 0, sliceOffset = 0; dim < ndims; dim++, acc += bounds[offset + 2], offset += 3) {
+
+            int size = bounds[offset + 2];
+
+            for (int j = 0, //
+            srcSize = src.dims[dim], //
+            srcOffset = (((bounds[offset]) % srcSize) + srcSize) % srcSize, //
+            dstSize = dst.dims[dim], //
+            dstOffset = (((bounds[offset + 1]) % dstSize) + dstSize) % dstSize; //
+            j < size; //
+            j++, //
+            srcOffset = (srcOffset + 1) % srcSize, //
+            dstOffset = (dstOffset + 1) % dstSize, //
+            sliceOffset += 3) {
+
+                slices[sliceOffset] = srcOffset;
+                slices[sliceOffset + 1] = dstOffset;
+                slices[sliceOffset + 2] = dim;
+            }
+        }
+
+        return splice(dst, slices);
+    }
+
+    public T splice(T dst, int... slices) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        SparseArrayState<V> srcState = src.state;
+        SparseArrayState<V> dstState = dst.state;
+
+        dst.state = OpKernel.sliceSparse(slices, //
+                srcState.values, src.dims, src.strides, src.dimOffsets, //
+                srcState.indices, srcState.indirectionOffsets, srcState.indirections, //
+                dstState.values, dst.dims, dst.strides, dst.dimOffsets, //
+                dstState.indices, dstState.indirectionOffsets, dstState.indirections);
+
+        return dst;
+    }
+
+    public T slice(int[][] srcSlices, T dst, int[][] dstSlices) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        SparseArrayState<V> srcState = src.state;
+        SparseArrayState<V> dstState = dst.state;
+
+        dst.state = OpKernel.sliceSparse(canonicalizeSlices(srcSlices, src.dims, dstSlices, dst.dims), //
+                srcState.values, src.dims, src.strides, src.dimOffsets, //
+                srcState.indices, srcState.indirectionOffsets, srcState.indirections, //
+                dstState.values, dst.dims, dst.strides, dst.dimOffsets, //
+                dstState.indices, dstState.indirectionOffsets, dstState.indirections);
+
+        return dst;
+    }
+
+    public T slice(T dst, int[]... dstSlices) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        Control.checkTrue(src != dst, //
+                "Source and destination cannot be the same");
+
+        SparseArrayState<V> srcState = src.state;
+        SparseArrayState<V> dstState = dst.state;
+
+        dst.state = OpKernel.sliceSparse(canonicalizeSlices(src.dims, dst.dims, dstSlices), //
+                srcState.values, src.dims, src.strides, src.dimOffsets, //
+                srcState.indices, srcState.indirectionOffsets, srcState.indirections, //
+                dstState.values, dst.dims, dst.strides, dst.dimOffsets, //
+                dstState.indices, dstState.indirectionOffsets, dstState.indirections);
+
+        return dst;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T slice(E value, int[]... srcSlices) {
+
+        T src = (T) this;
+
+        int ndims = srcSlices.length;
+        int[] dstDims = new int[ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            dstDims[dim] = srcSlices[dim].length;
+        }
+
+        return wrap(value, dstDims, src.order().strides(dstDims), createDimensionOffsets(dstDims)) //
+                .slice(src, srcSlices);
+    }
+
+    public T slice(int[]... srcSlices) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, srcSlices.length, //
+                "Dimensionality mismatch");
+
+        int nslices = 0;
+        int[] dstDims = new int[ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            nslices += (dstDims[dim] = srcSlices[dim].length);
+        }
+
+        T dst = wrap((E) null, dstDims, src.order().strides(dstDims), createDimensionOffsets(dstDims));
+
+        SparseArrayState<V> srcState = src.state;
+        SparseArrayState<V> dstState = dst.state;
+
+        dst.state = OpKernel.sliceSparse(canonicalizeSlices(nslices, src.dims, srcSlices), //
+                srcState.values, src.dims, src.strides, src.dimOffsets, //
+                srcState.indices, srcState.indirectionOffsets, srcState.indirections, //
+                dstState.values, dst.dims, dst.strides, dst.dimOffsets, //
+                dstState.indices, dstState.indirectionOffsets, dstState.indirections);
+
+        return dst;
+    }
+
+    public T tile(int... repetitions) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, repetitions.length, //
+                "Dimensionality mismatch");
+
+        int[] newDims = src.dims.clone();
+
+        for (int dim = 0; dim < ndims; dim++) {
+            newDims[dim] *= repetitions[dim];
+        }
+
+        T dst = wrap((E) null, newDims, src.order().strides(newDims), createDimensionOffsets(newDims));
+
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+            mappingBounds[offset + 2] = dst.dims[dim];
+        }
+
+        return map(dst, mappingBounds);
+    }
+
+    public T transpose(int... permutation) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, permutation.length, //
+                "Dimensionality mismatch");
+
+        int[] newDims = new int[ndims];
+        int[] copy = permutation.clone();
+
+        Arrays.sort(copy);
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            newDims[permutation[dim]] = src.dims[dim];
+
+            Control.checkTrue(copy[dim] == dim, //
+                    "Invalid permutation");
+        }
+
+        SparseArrayState<V> srcState = src.state;
+
+        int nindices = srcState.indices.length;
+        int[] newStrides = src.order().strides(newDims);
+        int[] newDimOffsets = createDimensionOffsets(newDims);
+        int[] newIndices = new int[nindices];
+
+        for (int i = 0; i < nindices; i++) {
+
+            int newPhysical = 0;
+            int physical = srcState.indices[i];
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                newPhysical += newStrides[permutation[dim]] * (physical / src.strides[dim]);
+                physical %= src.strides[dim];
+            }
+
+            newIndices[i] = newPhysical;
+        }
+
+        return wrap(OpKernel.insertSparse( //
+                empty(), newDims, newStrides, newDimOffsets, EmptyIndices, //
+                srcState.values, newIndices), newDims, newStrides, newDimOffsets);
+    }
+
+    public T shift(int... shifts) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = Control.checkEquals(src.dims.length, shifts.length, //
+                "Dimensionality mismatch");
+
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 3) {
+
+            mappingBounds[offset + 1] = shifts[dim];
+            mappingBounds[offset + 2] = src.dims[dim];
+        }
+
+        return map(wrap((E) null, src.dims, src.strides, src.dimOffsets), mappingBounds);
+    }
+
+    public T subarray(int... bounds) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        int ndims = src.dims.length;
+
+        Control.checkTrue(ndims * 2 == bounds.length, //
+                "Invalid subarray bounds");
+
+        int[] newDims = new int[ndims];
+        int[] mappingBounds = new int[3 * ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            int lower = bounds[2 * dim];
+            int upper = bounds[2 * dim + 1];
+
+            newDims[dim] = upper - lower;
+            mappingBounds[3 * dim] = lower;
+            mappingBounds[3 * dim + 2] = newDims[dim];
+        }
+
+        return map(wrap((E) null, newDims, src.order().strides(newDims), createDimensionOffsets(newDims)), //
+                mappingBounds);
+    }
+
+    public T reverse(int... selectedDims) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        T dst = wrap((E) null, src.dims, src.strides, src.dimOffsets);
+
+        SparseArrayState<V> srcState = src.state;
+        SparseArrayState<V> dstState = dst.state;
+
+        dst.state = OpKernel.sliceSparse(createReverseSlices(src.dims, selectedDims), //
+                srcState.values, src.dims, src.strides, src.dimOffsets, //
+                srcState.indices, srcState.indirectionOffsets, srcState.indirections, //
+                dstState.values, dst.dims, dst.strides, dst.dimOffsets, //
+                dstState.indices, dstState.indirectionOffsets, dstState.indirections);
+
+        return dst;
+    }
+
+    public T reshape(int... dims) {
+
+        ProtoSparseArray<T, V, E, D> src = this;
+
+        Control.checkTrue(Arithmetic.product(dims) == Arithmetic.product(src.dims), //
+                "Cardinality mismatch");
+
+        int[] strides = src.order().strides(dims);
+        int[] dimOffsets = createDimensionOffsets(dims);
+
+        SparseArrayState<V> srcState = src.state;
+
+        T dst = wrap(OpKernel.insertSparse( //
+                empty(), dims, strides, dimOffsets, EmptyIndices, //
+                srcState.values, srcState.indices), dims, strides, dimOffsets);
+
+        return dst;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T clone() {
+
+        try {
+
+            return (T) super.clone();
+
+        } catch (CloneNotSupportedException e) {
+
+            throw new RuntimeException(e);
+        }
+    }
+
+    public IndexingOrder order() {
+        return DEFAULT_ORDER;
+    }
+
+    public int size(int i) {
+        return this.dims[i];
+    }
+
+    public int stride(int i) {
+        return this.strides[i];
+    }
+
+    public int ndims() {
+        return this.dims.length;
+    }
+
+    public int[] dimensions() {
+        return this.dims.clone();
+    }
+
+    public int[] strides() {
+        return this.strides.clone();
+    }
+
+    public T reverseOrder() {
+        throw new UnsupportedOperationException("Sparse arrays always have row major indexing");
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/RealSparseArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/RealSparseArray.java
new file mode 100755
index 0000000..79d9bf0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/RealSparseArray.java
@@ -0,0 +1,171 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.sparse;
+
+import static shared.array.ArrayBase.DEFAULT_ORDER;
+import static shared.array.ArrayBase.FIELD_PRECISION;
+import static shared.array.ArrayBase.FIELD_WIDTH;
+import static shared.array.ArrayBase.OpKernel;
+import static shared.array.ArrayBase.formatRescale;
+import static shared.array.ArrayBase.formatSparseArray;
+
+import java.util.Formatter;
+
+import shared.array.ArrayBase;
+import shared.array.RealArray;
+import shared.util.Arithmetic;
+import shared.util.Arrays;
+import shared.util.Control;
+
+/**
+ * A sparse real array class.
+ * 
+ * @author Roy Liu
+ */
+public class RealSparseArray extends ProtoSparseArray<RealSparseArray, double[], Double, RealArray> {
+
+    /**
+     * An empty array.
+     */
+    final protected static double[] Empty = new double[] {};
+
+    /**
+     * Default constructor.
+     */
+    public RealSparseArray(int... dims) {
+        this(0, dims.clone());
+    }
+
+    /**
+     * Internal constructor with a distinctive signature.
+     */
+    protected RealSparseArray(int unused, int[] dims) {
+        super(new SparseArrayState<double[]>(Empty, dims), //
+                dims, DEFAULT_ORDER.strides(dims), createDimensionOffsets(dims));
+
+        Control.checkTrue(dims.length > 0);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public RealSparseArray(RealSparseArray array) {
+        this(array.state, array.dims, array.strides, array.dimOffsets);
+    }
+
+    /**
+     * Internal constructor for package use only.
+     */
+    protected RealSparseArray(SparseArrayState<double[]> state, int[] dims, int[] strides, int[] dimOffsets) {
+        super(state, dims, strides, dimOffsets);
+    }
+
+    public Class<Double> getComponentType() {
+        return Double.class;
+    }
+
+    @Override
+    protected RealSparseArray wrap(Double value, int[] dims, int[] strides, int[] dimOffsets) {
+
+        final SparseArrayState<double[]> state;
+
+        if (value == null) {
+
+            state = new SparseArrayState<double[]>(Empty, dims);
+
+        } else {
+
+            double[] values = Arrays.newArray(Arithmetic.product(dims), value.doubleValue());
+
+            state = OpKernel.insertSparse( //
+                    Empty, dims, strides, dimOffsets, EmptyIndices, //
+                    values, Arithmetic.range(values.length));
+        }
+
+        return new RealSparseArray(state, dims, strides, dimOffsets);
+    }
+
+    @Override
+    protected RealSparseArray wrap(SparseArrayState<double[]> state, int[] dims, int[] strides, int[] dimOffsets) {
+        return new RealSparseArray(state, dims, strides, dimOffsets);
+    }
+
+    @Override
+    protected int length(double[] values) {
+        return values.length;
+    }
+
+    @Override
+    protected double[] empty() {
+        return Empty;
+    }
+
+    @Override
+    public RealArray toDense() {
+
+        RealSparseArray src = this;
+
+        RealArray dst = new RealArray(src.order(), src.dims);
+
+        SparseArrayState<double[]> srcState = src.state;
+
+        double[] srcValues = srcState.values;
+        int[] srcIndices = srcState.indices;
+
+        double[] dstValues = dst.values();
+
+        for (int i = 0, n = srcValues.length; i < n; i++) {
+            dstValues[srcIndices[i]] = srcValues[i];
+        }
+
+        return dst;
+    }
+
+    @Override
+    public String toString() {
+
+        SparseArrayState<double[]> state = this.state;
+
+        double[] values = state.values;
+        int[] indices = state.indices;
+        int[] dims = this.dims;
+        int[] strides = this.strides;
+
+        int exponent = (int) Math.log10(Arithmetic.max( //
+                Arithmetic.max(values), Math.abs(Arithmetic.min(values)), 1e-128));
+
+        int maxIndex = Arithmetic.max(dims);
+        int exponentIndex = maxIndex > 0 ? (int) Math.log10(maxIndex) : 0;
+
+        Formatter f = new Formatter();
+
+        if (values.length == 0) {
+
+            ArrayBase.formatEmptyArray(f, dims);
+
+            return f.toString();
+        }
+
+        String valueFormat = String.format("%%%d.%df", FIELD_WIDTH, FIELD_PRECISION);
+        String indexFormat = String.format("%%%dd", exponentIndex + 2);
+
+        formatSparseArray(f, valueFormat, indexFormat, formatRescale(f, exponent, values), indices, strides);
+
+        return f.toString();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/SparseArrayState.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/SparseArrayState.java
new file mode 100755
index 0000000..96504db
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/SparseArrayState.java
@@ -0,0 +1,77 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.array.sparse;
+
+import shared.util.Arithmetic;
+
+/**
+ * A container class for sparse array state.
+ * 
+ * @param <V>
+ *            the storage array type.
+ * @author Roy Liu
+ */
+public class SparseArrayState<V> {
+
+    /**
+     * An empty array.
+     */
+    final protected static int[] Empty = new int[] {};
+
+    /**
+     * The values.
+     */
+    final protected V values;
+
+    /**
+     * The physical indices.
+     */
+    final protected int[] indices;
+
+    /**
+     * The offsets into {@link #indirections}.
+     */
+    final protected int[] indirectionOffsets;
+
+    /**
+     * The indirection indices into {@link #values} and {@link #indices}.
+     */
+    final protected int[] indirections;
+
+    /**
+     * Default constructor.
+     */
+    public SparseArrayState(V values, int[] indices, int[] indirectionOffsets, int[] indirections) {
+
+        this.values = values;
+        this.indices = indices;
+        this.indirectionOffsets = indirectionOffsets;
+        this.indirections = indirections;
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public SparseArrayState(V emptyValues, int[] dims) {
+
+        this.values = emptyValues;
+        this.indices = Empty;
+        this.indirectionOffsets = new int[Arithmetic.sum(dims) + dims.length];
+        this.indirections = Empty;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/package-info.java
new file mode 100755
index 0000000..0593334
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/array/sparse/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of multidimensional sparse arrays.
+ */
+package shared.array.sparse;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/EnumStatus.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/EnumStatus.java
new file mode 100755
index 0000000..a2d0f96
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/EnumStatus.java
@@ -0,0 +1,37 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * Defines a mutable, enumerated state.
+ * 
+ * @param <T>
+ *            the enumeration type.
+ */
+public interface EnumStatus<T extends Enum<T>> {
+
+    /**
+     * Gets the status.
+     */
+    public T getStatus();
+
+    /**
+     * Sets the status.
+     */
+    public void setStatus(T status);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/EnumType.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/EnumType.java
new file mode 100755
index 0000000..69036f8
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/EnumType.java
@@ -0,0 +1,32 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * Defines an enumerated type.
+ * 
+ * @param <T>
+ *            the enumeration type.
+ */
+public interface EnumType<T extends Enum<T>> {
+
+    /**
+     * Gets the type.
+     */
+    public T getType();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/Event.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/Event.java
new file mode 100755
index 0000000..2e78de0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/Event.java
@@ -0,0 +1,43 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * Defines functionality that can be expected from all events.
+ * 
+ * @apiviz.owns shared.event.Source
+ * @param <T>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @param <E>
+ *            the {@link Event} enumeration type.
+ * @param <S>
+ *            the {@link Source} enumeration type.
+ * @author Roy Liu
+ */
+public interface Event<T extends Event<T, E, S>, E extends Enum<E>, S extends Enum<S>> extends EnumType<E> {
+
+    /**
+     * Gets the {@link Source} from which this event originated.
+     */
+    public Source<T, S> getSource();
+
+    /**
+     * Gets the {@link Event} type.
+     */
+    public E getType();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/Handler.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/Handler.java
new file mode 100755
index 0000000..337d772
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/Handler.java
@@ -0,0 +1,33 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * Defines a handler for generic objects.
+ * 
+ * @param <T>
+ *            the object type.
+ * @author Roy Liu
+ */
+public interface Handler<T> {
+
+    /**
+     * Handles a generic object.
+     */
+    public void handle(T value);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/Processor.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/Processor.java
new file mode 100755
index 0000000..2bb51d6
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/Processor.java
@@ -0,0 +1,149 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+import java.io.Closeable;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import shared.util.Control;
+import shared.util.CoreThread;
+import shared.util.Finalizable;
+
+/**
+ * A base class for a thread repetitively going through the event processing motions {@link BlockingQueue#take()}
+ * (fetch), {@link Event#getSource()} (see who it's from), {@link Source#getHandler()} (see how the source wishes to
+ * process events), and {@link Handler#handle(Object)} (process the event).
+ * 
+ * @apiviz.composedOf shared.event.Processor.ProcessorThread
+ * @param <T>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @author Roy Liu
+ */
+public class Processor<T extends Event<T, ?, ?>> implements SourceLocal<T>, Finalizable<Processor<T>>, Closeable {
+
+    final ProcessorThread<T> thread;
+
+    /**
+     * Default constructor.
+     */
+    public Processor(String name) {
+        this.thread = new ProcessorThread<T>(name);
+    }
+
+    /**
+     * Shuts down the internal thread.
+     */
+    public void close() {
+
+        this.thread.run = false;
+        this.thread.interrupt();
+    }
+
+    public void onLocal(T evt) {
+        this.thread.eq.add(evt);
+    }
+
+    public Processor<T> setFinalizer(Runnable finalizer) {
+
+        Control.checkTrue(finalizer != null, //
+                "Finalizer must be non-null");
+
+        this.thread.finalizer = finalizer;
+
+        return this;
+    }
+
+    /**
+     * Gets the name of the underlying {@link ProcessorThread}.
+     */
+    @Override
+    public String toString() {
+        return this.thread.toString();
+    }
+
+    /**
+     * Checks that {@link Thread#currentThread()} is indeed this processor's internal thread. Helpful for enforcing a
+     * serial event processing model.
+     */
+    public void checkCurrentThread() {
+        Control.checkTrue(Thread.currentThread() == this.thread, //
+                "Expected call from within processor thread");
+    }
+
+    /**
+     * A worker thread class for processing events.
+     * 
+     * @param <T>
+     *            the parameterization lower bounded by {@link Event} itself.
+     */
+    final protected static class ProcessorThread<T extends Event<T, ?, ?>> extends CoreThread {
+
+        final BlockingQueue<T> eq;
+
+        volatile Runnable finalizer;
+        volatile boolean run;
+
+        /**
+         * Default constructor.
+         */
+        protected ProcessorThread(String name) {
+            super(name);
+
+            this.eq = new LinkedBlockingQueue<T>();
+
+            this.finalizer = Control.NullRunnable;
+            this.run = true;
+
+            setDaemon(true);
+            start();
+        }
+
+        /**
+         * Runs the event processing loop.
+         */
+        @Override
+        protected void runUnchecked() {
+
+            for (; this.run;) {
+
+                try {
+
+                    T evt = this.eq.take();
+                    evt.getSource().getHandler().handle(evt);
+
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
+        @Override
+        protected void runFinalizer() {
+            this.finalizer.run();
+        }
+    }
+
+    // A finalizer guardian for the processor thread.
+    final Object threadReaper = new Object() {
+
+        @Override
+        protected void finalize() {
+            Control.close(Processor.this);
+        }
+    };
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/Source.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/Source.java
new file mode 100755
index 0000000..c5b0380
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/Source.java
@@ -0,0 +1,48 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+import java.io.Closeable;
+
+/**
+ * Defines an originator of {@link Event}s.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @param <S>
+ *            the {@link Source} enumeration type.
+ * @author Roy Liu
+ */
+public interface Source<T extends Event<T, ?, S>, S extends Enum<S>> extends SourceLocal<T>, SourceRemote<T>,
+        EnumType<S>, Closeable {
+
+    /**
+     * Gets the {@link Handler} that will process incoming {@link Event}s.
+     */
+    public Handler<T> getHandler();
+
+    /**
+     * Sets the {@link Handler} that will process incoming {@link Event}s.
+     */
+    public void setHandler(Handler<T> handler);
+
+    /**
+     * Overrides {@link Closeable#close()} so that it doesn't throw an exception.
+     */
+    public void close();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/SourceLocal.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/SourceLocal.java
new file mode 100755
index 0000000..b885058
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/SourceLocal.java
@@ -0,0 +1,33 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * Defines the local manifestation of an originator {@link Event}s.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @author Roy Liu
+ */
+public interface SourceLocal<T extends Event<T, ?, ?>> {
+
+    /**
+     * Delivers an {@link Event} to the local manifestation.
+     */
+    public void onLocal(T evt);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/SourceRemote.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/SourceRemote.java
new file mode 100755
index 0000000..7f4fc55
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/SourceRemote.java
@@ -0,0 +1,33 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * Defines the local manifestation of an originator {@link Event}s.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @author Roy Liu
+ */
+public interface SourceRemote<T extends Event<T, ?, ?>> {
+
+    /**
+     * Delivers an {@link Event} to the remote manifestation.
+     */
+    public void onRemote(T evt);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/StateProcessor.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/StateProcessor.java
new file mode 100755
index 0000000..aab2b0e
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/StateProcessor.java
@@ -0,0 +1,53 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+/**
+ * A state-based {@link Processor} subclass that is a {@link Source} in itself.
+ * 
+ * @apiviz.owns shared.event.StateTable
+ * @param <T>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @param <E>
+ *            the {@link Event} enumeration type.
+ * @param <S>
+ *            the {@link Source} enumeration type.
+ * @author Roy Liu
+ */
+abstract public class StateProcessor<T extends Event<T, E, S>, E extends Enum<E>, S extends Enum<S>> extends
+        Processor<T> implements Source<T, S>, Handler<T> {
+
+    /**
+     * Default constructor.
+     */
+    public StateProcessor(String name) {
+        super(name);
+    }
+
+    public Handler<T> getHandler() {
+        return this;
+    }
+
+    public void onRemote(T evt) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void setHandler(Handler<T> handler) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/StateTable.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/StateTable.java
new file mode 100755
index 0000000..392fc70
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/StateTable.java
@@ -0,0 +1,305 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2005 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import shared.array.ObjectArray;
+import shared.event.Transitions.Transition;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A finite state machine class.
+ * 
+ * @apiviz.composedOf shared.event.StateTable.StateHandler
+ * @apiviz.has shared.event.Transitions - - - argument
+ * @apiviz.has shared.event.Event - - - event
+ * @param <X>
+ *            the state enumeration type.
+ * @param <Y>
+ *            the {@link Event} enumeration type.
+ * @param <Z>
+ *            the parameterization lower bounded by {@link Event} itself.
+ * @author Roy Liu
+ */
+public class StateTable<X extends Enum<X>, Y extends Enum<Y>, Z extends Event<Z, Y, ?>> {
+
+    /**
+     * An array of all four wildcard combinations.
+     */
+    final protected static String[] WildcardCombinations = new String[] { "**", "* ", " *", "  " };
+
+    final ObjectArray<StateHandler> backingArray;
+
+    /**
+     * Default constructor.
+     */
+    @SuppressWarnings("unchecked")
+    public StateTable(Object target, Class<X> stateClass, Class<Y> eventTypeClass, String group) {
+
+        this.backingArray = new ObjectArray( //
+                StateHandler.class, //
+                stateClass.getEnumConstants().length, //
+                eventTypeClass.getEnumConstants().length);
+
+        final Map<String, List<StateHandler>> handlersMap = //
+        new HashMap<String, List<StateHandler>>();
+
+        for (String str : WildcardCombinations) {
+            handlersMap.put(str, new ArrayList<StateHandler>());
+        }
+
+        for (Class<?> clazz = target.getClass(); clazz != null //
+                && !clazz.getName().startsWith("java.") //
+                && !clazz.getName().startsWith("javax."); clazz = clazz.getSuperclass()) {
+
+            outerLoop: for (Field field : clazz.getDeclaredFields()) {
+
+                Transitions ts = field.getAnnotation(Transitions.class);
+                Transition t = field.getAnnotation(Transition.class);
+
+                Control.checkTrue(ts == null || t == null, //
+                        "Transition and Transitions annotations cannot occur simultaneously");
+
+                final Transition[] transitions;
+
+                if (ts != null) {
+
+                    transitions = ts.transitions();
+
+                } else if (t != null) {
+
+                    transitions = new Transition[] { t };
+
+                } else {
+
+                    continue outerLoop;
+                }
+
+                final Object obj;
+
+                field.setAccessible(true);
+
+                try {
+
+                    obj = field.get(target);
+
+                } catch (IllegalAccessException e) {
+
+                    throw new RuntimeException(e);
+
+                } finally {
+
+                    field.setAccessible(false);
+                }
+
+                Control.checkTrue(obj instanceof Handler, //
+                        "Field does not reference an event handler");
+
+                final Handler<Z> handler = (Handler<Z>) obj;
+                final String name = field.getName();
+
+                innerLoop: for (Transition transition : transitions) {
+
+                    if (!transition.group().equals(group)) {
+                        continue innerLoop;
+                    }
+
+                    X currentState = !transition.currentState().equals("*") ? Enum.valueOf( //
+                            stateClass, transition.currentState()) : null;
+                    Y eventType = !transition.eventType().equals("*") ? Enum.valueOf( //
+                            eventTypeClass, transition.eventType()) : null;
+
+                    final StateHandler stateHandler;
+
+                    if (!transition.nextState().equals("")) {
+
+                        final X nextState = Enum.valueOf(stateClass, transition.nextState());
+
+                        stateHandler = new StateHandler(currentState, eventType) {
+
+                            @Override
+                            public void handle(EnumStatus<X> stateObj, Z evt) {
+
+                                handler.handle(evt);
+                                stateObj.setStatus(nextState);
+                            }
+
+                            @Override
+                            public String toString() {
+                                return String.format("%s -> %s : %s", //
+                                        super.toString(), nextState, name);
+                            }
+                        };
+
+                    } else {
+
+                        stateHandler = new StateHandler(currentState, eventType) {
+
+                            @Override
+                            public void handle(EnumStatus<X> stateObj, Z evt) {
+                                handler.handle(evt);
+                            }
+
+                            @Override
+                            public String toString() {
+                                return String.format("%s : %s", //
+                                        super.toString(), name);
+                            }
+                        };
+                    }
+
+                    final String key;
+
+                    if (currentState == null && eventType == null) {
+
+                        key = "**";
+
+                    } else if (currentState == null && eventType != null) {
+
+                        key = "* ";
+
+                    } else if (currentState != null && eventType == null) {
+
+                        key = " *";
+
+                    } else {
+
+                        key = "  ";
+                    }
+
+                    handlersMap.get(key).add(stateHandler);
+                }
+            }
+        }
+
+        int[] rowRange = Arithmetic.range(this.backingArray.size(0));
+        int[] colRange = Arithmetic.range(this.backingArray.size(1));
+
+        for (String key : WildcardCombinations) {
+
+            for (StateHandler stateHandler : handlersMap.get(key)) {
+
+                int[][] slices = new int[][] {
+                //
+                        (stateHandler.state != null) ? new int[] { stateHandler.state //
+                                .ordinal() } : rowRange, //
+                        (stateHandler.eventType != null) ? new int[] { stateHandler.eventType //
+                                .ordinal() } : colRange //
+                };
+
+                this.backingArray.slice(stateHandler, slices);
+            }
+        }
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public StateTable(Object target, Class<X> stateClass, Class<Y> eventTypeClass) {
+        this(target, stateClass, eventTypeClass, "");
+    }
+
+    /**
+     * Creates a human-readable representation of this table.
+     */
+    @Override
+    public String toString() {
+
+        StringBuilder sb = new StringBuilder();
+
+        int nrows = this.backingArray.size(0);
+        int ncols = this.backingArray.size(1);
+
+        for (int i = 0; i < nrows; i++) {
+
+            for (int j = 0; j < ncols; j++) {
+
+                StateHandler stateHandler = this.backingArray.get(i, j);
+
+                if (stateHandler != null) {
+                    sb.append(stateHandler).append(Control.LineSeparator);
+                }
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Looks up and handles an {@link Event} based on the current state and the event type.
+     * 
+     * @param stateObj
+     *            the {@link EnumStatus} object.
+     * @param evt
+     *            the {@link Event}.
+     */
+    public void lookup(EnumStatus<X> stateObj, Z evt) {
+
+        StateHandler handler = this.backingArray.get(stateObj.getStatus().ordinal(), evt.getType().ordinal());
+
+        if (handler != null) {
+            handler.handle(stateObj, evt);
+        }
+    }
+
+    /**
+     * Defines an {@link Event} handler that may mutate {@link EnumStatus} objects.
+     */
+    abstract protected class StateHandler {
+
+        /**
+         * The state.
+         */
+        final protected X state;
+
+        /**
+         * The event type.
+         */
+        final protected Y eventType;
+
+        /**
+         * Default constructor.
+         */
+        protected StateHandler(X state, Y eventType) {
+
+            this.state = state;
+            this.eventType = eventType;
+        }
+
+        /**
+         * Creates a human-readable representation of this handler.
+         */
+        @Override
+        public String toString() {
+            return String.format("(%s, %s)", //
+                    (this.state != null) ? this.state : "*", //
+                    (this.eventType != null) ? this.eventType : "*");
+        }
+
+        /**
+         * Handles an {@link Event}. May optionally mutate the given {@link EnumStatus} object.
+         */
+        abstract protected void handle(EnumStatus<X> state, Z evt);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/Transitions.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/Transitions.java
new file mode 100755
index 0000000..11456d0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/Transitions.java
@@ -0,0 +1,68 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation class for specifying finite state machine transitions. Inspired by Apache MINA's <a
+ * href="http://mina.apache.org/introduction-to-mina-statemachine.html">StateMachine</a> construct.
+ * 
+ * @apiviz.owns shared.event.Transitions.Transition
+ * @author Roy Liu
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.FIELD)
+public @interface Transitions {
+
+    /**
+     * Gets the {@link Transition}s.
+     */
+    public Transition[] transitions();
+
+    /**
+     * An annotation for a single transition.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface Transition {
+
+        /**
+         * The current state.
+         */
+        String currentState();
+
+        /**
+         * The {@link Event} type.
+         */
+        String eventType();
+
+        /**
+         * The next state.
+         */
+        String nextState() default "";
+
+        /**
+         * The group name.
+         */
+        String group() default "";
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/XMLEvent.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/XMLEvent.java
new file mode 100755
index 0000000..fade428
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/XMLEvent.java
@@ -0,0 +1,53 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.event;
+
+import org.w3c.dom.Element;
+
+/**
+ * An abstract base class for all XML-derived events.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link XMLEvent} itself.
+ * @param <E>
+ *            the {@link XMLEvent} enumeration type.
+ * @param <S>
+ *            the {@link Source} enumeration type.
+ * @author Roy Liu
+ */
+abstract public class XMLEvent<T extends XMLEvent<T, E, S>, E extends Enum<E>, S extends Enum<S>> implements
+        Event<T, E, S> {
+
+    final E type;
+
+    /**
+     * Default constructor.
+     */
+    protected XMLEvent(E type) {
+        this.type = type;
+    }
+
+    public E getType() {
+        return this.type;
+    }
+
+    /**
+     * Transforms this event into an XML DOM {@link Element}.
+     */
+    abstract public Element toDOM();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/event/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/event/package-info.java
new file mode 100755
index 0000000..4acc6de
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/event/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A framework for event-driven programming.
+ */
+package shared.event;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/Cacheable.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/Cacheable.java
new file mode 100755
index 0000000..476adbe
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/Cacheable.java
@@ -0,0 +1,26 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.fft;
+
+/**
+ * Marks an array as being suitable for having its FFT cached.
+ * 
+ * @author Roy Liu
+ */
+public interface Cacheable {
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/ConvolutionCache.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/ConvolutionCache.java
new file mode 100755
index 0000000..bd4b7b1
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/ConvolutionCache.java
@@ -0,0 +1,233 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.fft;
+
+import shared.array.AbstractArray;
+import shared.array.ComplexArray;
+import shared.array.RealArray;
+import shared.util.Control;
+
+/**
+ * A specialization of {@link FFTCache} for {@link RealArray}s and {@link ComplexArray}s.
+ * 
+ * @apiviz.owns shared.fft.Cacheable
+ * @author Roy Liu
+ */
+public class ConvolutionCache extends FFTCache<ComplexArray, RealArray> {
+
+    /**
+     * A global instance.
+     */
+    protected static ConvolutionCache Instance = null;
+
+    /**
+     * Gets the global instance.
+     */
+    final public static ConvolutionCache getInstance() {
+
+        if (Instance == null) {
+            Instance = new ConvolutionCache();
+        }
+
+        return Instance;
+    }
+
+    /**
+     * Performs convolution in the complex domain.
+     * 
+     * @param cIm
+     *            the already transformed image.
+     * @param ker
+     *            the kernel.
+     * @return the convolution result.
+     */
+    public ComplexArray convolve(ComplexArray cIm, ComplexArray ker) {
+
+        int[] dimsT = cIm.dimensions();
+        ComplexArray res = (cIm.eMul(ker instanceof Cacheable ? get(ker, dimsT) //
+                : createCacheable(ker, dimsT))).ifft();
+
+        int[] dims = res.dimensions();
+        int ndims = dims.length;
+        int[] bounds = new int[ndims * 2];
+
+        for (int i = 0, n = ndims - 1; i < n; i++) {
+            Control.checkTrue((bounds[2 * i + 1] = dims[i] - ker.size(i) + 1) > 0, //
+                    "Invalid kernel size");
+        }
+
+        bounds[bounds.length - 1] = 2;
+
+        return res.subarray(bounds);
+    }
+
+    /**
+     * Performs convolution in the real domain.
+     * 
+     * @param cIm
+     *            the already transformed image.
+     * @param ker
+     *            the kernel.
+     * @return the convolution result.
+     */
+    public RealArray convolve(ComplexArray cIm, RealArray ker) {
+
+        int[] dimsT = cIm.rifftDimensions();
+        RealArray res = (cIm.eMul(ker instanceof Cacheable ? get(ker, dimsT) //
+                : createCacheable(ker, dimsT))).rifft();
+
+        int[] dims = res.dimensions();
+        int ndims = dims.length;
+        int[] bounds = new int[ndims * 2];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            bounds[2 * dim + 1] = dims[dim] - ker.size(dim) + 1;
+        }
+
+        return res.subarray(bounds);
+    }
+
+    @Override
+    protected <A extends AbstractArray<?, ComplexArray, ?, ?>> ComplexArray createCacheable(A array, int[] dims) {
+
+        int ndims = dims.length;
+        int[] bounds = new int[ndims * 3];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            bounds[3 * dim + 2] = array.size(dim);
+        }
+
+        if (array instanceof RealArray) {
+
+            return ((RealArray) array).map(new RealArray(dims), bounds).rfft().uConj();
+
+        } else if (array instanceof ComplexArray) {
+
+            return ((ComplexArray) array).map(new ComplexArray(dims), bounds).fft().uConj();
+
+        } else {
+
+            throw new RuntimeException("Invalid array type");
+        }
+    }
+
+    /**
+     * Pads an image in an extrapolative way.
+     * 
+     * @param im
+     *            the intensity image.
+     * @param margins
+     *            the padding margins.
+     * @return the padded result.
+     */
+    final public static RealArray pad(RealArray im, int... margins) {
+
+        int ndims = im.ndims();
+        int[] dims = im.dimensions();
+        int[] newDims = dims.clone();
+
+        Control.checkTrue(dims.length == margins.length, //
+                "Dimensionality mismatch");
+
+        for (int dim = 0; dim < ndims; dim++) {
+            newDims[dim] += 2 * margins[dim];
+        }
+
+        RealArray res = new RealArray(newDims);
+
+        // Slice for all partitions of dimensions into corners and edges.
+
+        Control.checkTrue(ndims <= 16, //
+                "Too many dimensions");
+
+        for (int i = 0, n = (1 << ndims), cdi = 0, edi = 0; i < n; i++, cdi = 0, edi = 0) {
+
+            int ncornerDims = Integer.bitCount(i);
+            int nedgeDims = ndims - ncornerDims;
+
+            int[] cornerDimIndices = new int[ncornerDims];
+            int[] edgeDimIndices = new int[nedgeDims];
+
+            int nedgeSlices = 0;
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                if (((i >>> dim) & 0x1) == 0x1) {
+
+                    cornerDimIndices[cdi++] = dim;
+
+                } else {
+
+                    nedgeSlices += dims[edgeDimIndices[edi++] = dim];
+                }
+            }
+
+            //
+
+            int nmarginIndices = 0;
+
+            for (int j = 0; j < ncornerDims; j++) {
+                nmarginIndices += margins[cornerDimIndices[j]];
+            }
+
+            int[] slices = new int[6 * nmarginIndices + 3 * nedgeSlices];
+
+            for (int j = 0, base = 0, offset = 3 * nmarginIndices; j < ncornerDims; j++) {
+
+                int dim = cornerDimIndices[j];
+                int size = dims[dim];
+                int margin = margins[dim];
+
+                for (int k = 0; k < margin; k++, base += 3) {
+
+                    slices[base] = k;
+                    slices[base + 1] = margin - 1 - k;
+                    slices[base + 2] = dim;
+
+                    slices[offset + base] = size - margin + k;
+                    slices[offset + base + 1] = size + 2 * margin - 1 - k;
+                    slices[offset + base + 2] = dim;
+                }
+            }
+
+            for (int j = 0, base = 0, offset = 6 * nmarginIndices; j < nedgeDims; j++) {
+
+                int dim = edgeDimIndices[j];
+                int size = dims[dim];
+                int margin = margins[dim];
+
+                for (int k = 0; k < size; k++, base += 3) {
+
+                    slices[offset + base] = k;
+                    slices[offset + base + 1] = margin + k;
+                    slices[offset + base + 2] = dim;
+                }
+            }
+
+            //
+
+            im.splice(res, slices);
+        }
+
+        return res;
+    }
+
+    // Dummy constructor.
+    ConvolutionCache() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTCache.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTCache.java
new file mode 100755
index 0000000..fef3bcc
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTCache.java
@@ -0,0 +1,137 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.fft;
+
+import java.lang.ref.Reference;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import shared.array.AbstractArray;
+import shared.util.ReferenceReaper;
+import shared.util.ReferenceReaper.ReferenceType;
+
+/**
+ * A class for thread-safe caching of padded and FFT'd convolution kernels.
+ * 
+ * @apiviz.composedOf shared.fft.FFTCache.CacheKey
+ * @param <C>
+ *            the complex array type.
+ * @param <R>
+ *            the real array type.
+ * @author Roy Liu
+ */
+abstract public class FFTCache<C extends AbstractArray<C, C, R, ?>, R extends AbstractArray<R, C, R, ?>> {
+
+    final ConcurrentMap<CacheKey, Reference<C>> kernelMap;
+    final ReferenceReaper<C> rr;
+
+    /**
+     * Default constructor.
+     */
+    public FFTCache() {
+
+        this.kernelMap = new ConcurrentHashMap<CacheKey, Reference<C>>();
+        this.rr = new ReferenceReaper<C>();
+    }
+
+    /**
+     * Delegates to {@link ConcurrentHashMap#toString()}.
+     */
+    @Override
+    public String toString() {
+        return this.kernelMap.toString();
+    }
+
+    /**
+     * Attempts to retrieve a cached, padded, and FFT'd companion of the given {@link AbstractArray}.
+     * 
+     * @param tag
+     *            the query key.
+     * @param dims
+     *            the size of the cached result.
+     * @param <A>
+     *            the query array type.
+     * @return the cached result, or a newly created and inserted one.
+     */
+    public <A extends AbstractArray<?, C, ?, ?>> C get(A tag, int... dims) {
+
+        final CacheKey key = new CacheKey(tag, dims);
+
+        Reference<C> ref = this.kernelMap.get(key);
+
+        C kernel = (ref != null) ? ref.get() : null;
+
+        if (kernel == null) {
+
+            kernel = createCacheable(tag, dims);
+            this.rr.register(ReferenceType.SOFT, kernel, this.kernelMap, key);
+        }
+
+        return kernel;
+    }
+
+    /**
+     * Creates an instance of the complex array type.
+     * 
+     * @param array
+     *            the query key.
+     * @param dims
+     *            the size of the cached result.
+     * @param <A>
+     *            the query array type.
+     * @return an instance of the complex array type.
+     */
+    abstract protected <A extends AbstractArray<?, C, ?, ?>> C createCacheable(A array, int[] dims);
+
+    /**
+     * A lookup key class for cached kernels.
+     */
+    protected class CacheKey {
+
+        final AbstractArray<?, C, ?, ?> tag;
+        final int[] dims;
+
+        /**
+         * Default constructor.
+         */
+        protected CacheKey(AbstractArray<?, C, ?, ?> tag, int[] dims) {
+
+            this.tag = tag;
+            this.dims = dims;
+        }
+
+        /**
+         * Computes the <tt>xor</tt> of the hash codes of the array and the padded dimensions.
+         */
+        @Override
+        public int hashCode() {
+            return this.tag.hashCode() ^ Arrays.hashCode(this.dims);
+        }
+
+        /**
+         * Checks for equality on the array and the padded dimensions.
+         */
+        @Override
+        public boolean equals(Object o) {
+
+            CacheKey key = (CacheKey) o;
+            return key.tag.equals(this.tag) && Arrays.equals(key.dims, this.dims);
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTOps.java
new file mode 100755
index 0000000..cef96d9
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTOps.java
@@ -0,0 +1,260 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>. <br />
+ * <br />
+ * This file is derived from previous work, whose license terms are attached. <br />
+ * <br />
+ * Copyright (c) 2003-2006 Mark Borgerding <br />
+ * All rights reserved. <br />
+ * <br />
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+ * following conditions are met:
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+ * disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other materials provided with the distribution.</li>
+ * <li>Neither the author nor the names of any contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package shared.fft;
+
+import java.util.ArrayList;
+
+import shared.util.Arithmetic;
+
+/**
+ * A class of mixed-radix FFT operations in support of {@link JavaFFTService}.
+ * 
+ * @author Roy Liu
+ */
+public class FFTOps {
+
+    /**
+     * An FFT operation in support of {@link JavaFFTService#fft(int[], double[], double[])}. Very slow and unoptimized;
+     * for demonstration purposes only.
+     * 
+     * @param direction
+     *            the transform direction.
+     * @param dims
+     *            the array dimensions.
+     * @param in
+     *            the in array.
+     * @param out
+     *            the out array.
+     */
+    final public static void fft(int direction, int[] dims, double[] in, double[] out) {
+
+        int ndims = dims.length;
+        int len = Arithmetic.product(dims);
+
+        double[] outTmp = new double[len << 1];
+        double[] scratch = new double[len << 1];
+
+        System.arraycopy(in, 0, out, 0, len << 1);
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            int dimSize = dims[dim];
+            int dimStride = len / dimSize;
+
+            int[] factors = createFactors(dimSize);
+            double[] twiddles = createTwiddles(dimSize, direction);
+
+            int srcOffsetIncr = 2;
+            int dstOffsetIncr = dimSize << 1;
+
+            for (int j = 0, srcOffset = 0, dstOffset = 0; j < dimStride; //
+            j++, srcOffset += srcOffsetIncr, dstOffset += dstOffsetIncr) {
+                fft(out, srcOffset, outTmp, dstOffset, scratch, //
+                        factors, 0, twiddles, dimSize, dimStride, 1);
+            }
+
+            System.arraycopy(outTmp, 0, out, 0, len << 1);
+        }
+
+        switch (direction) {
+
+        case +1:
+            break;
+
+        case -1:
+
+            double factor = 1.0 / len;
+
+            for (int i = 0, offset = 0; i < len; i++, offset += 2) {
+
+                out[offset] *= factor;
+                out[offset + 1] *= factor;
+            }
+
+            break;
+
+        default:
+            throw new IllegalArgumentException("Invalid transform direction");
+        }
+    }
+
+    /**
+     * Creates a prime factorization and stride modifiers array.
+     */
+    final protected static int[] createFactors(int num) {
+
+        ArrayList<Integer> factors = new ArrayList<Integer>();
+
+        int p = 2;
+        int upper = (int) Math.floor(Math.sqrt(num));
+
+        do {
+
+            for (; num % p != 0;) {
+
+                switch (p) {
+
+                case 1:
+                    p = 1;
+                    break;
+
+                default:
+                    p += 2;
+                    break;
+                }
+
+                p = p > upper ? num : p;
+            }
+
+            num /= p;
+
+            factors.add(p);
+            factors.add(num);
+
+        } while (num > 1);
+
+        int[] res = new int[factors.size()];
+
+        for (int i = 0, n = res.length; i < n; i++) {
+            res[i] = factors.get(i);
+        }
+
+        return res;
+    }
+
+    /**
+     * Creates an array of twiddle factors.
+     */
+    final protected static double[] createTwiddles(int n, int direction) {
+
+        double[] res = new double[n << 1];
+
+        for (int i = 0, offset = 0; i < n; i++, offset += 2) {
+
+            double phase = (-2 * direction * Math.PI * i) / n;
+
+            res[offset] = Math.cos(phase);
+            res[offset + 1] = Math.sin(phase);
+        }
+
+        return res;
+    }
+
+    /**
+     * The main mixed-radix FFT procedure.
+     */
+    final protected static void fft(double[] src, int srcOffset, double[] dst, int dstOffset, double[] scratch, //
+            int[] factors, int factorIndexCurrent, double[] twiddles, //
+            int size, int stride, int strideCurrent) {
+
+        int p = factors[factorIndexCurrent];
+        int m = factors[factorIndexCurrent + 1];
+
+        int srcOffsetIncr = (strideCurrent * stride) << 1;
+        int dstOffsetIncr = m << 1;
+        int upper = dstOffset + ((p * m) << 1);
+
+        if (m == 1) {
+
+            for (int srcOffsetCurrent = srcOffset, dstOffsetCurrent = dstOffset; dstOffsetCurrent < upper; //
+            srcOffsetCurrent += srcOffsetIncr, dstOffsetCurrent += 2) {
+
+                dst[dstOffsetCurrent] = src[srcOffsetCurrent];
+                dst[dstOffsetCurrent + 1] = src[srcOffsetCurrent + 1];
+            }
+
+        } else {
+
+            for (int srcOffsetCurrent = srcOffset, dstOffsetCurrent = dstOffset; dstOffsetCurrent < upper; //
+            srcOffsetCurrent += srcOffsetIncr, dstOffsetCurrent += dstOffsetIncr) {
+                fft(src, srcOffsetCurrent, dst, dstOffsetCurrent, scratch, //
+                        factors, factorIndexCurrent + 2, twiddles, //
+                        size, stride, strideCurrent * p);
+            }
+        }
+
+        fft(dst, dstOffset, scratch, p, m, twiddles, size, strideCurrent);
+    }
+
+    /**
+     * A recursive FFT subroutine for a specific radix.
+     */
+    final protected static void fft(double[] dst, int dstOffsetCurrent, double[] scratch, //
+            int p, int m, double[] twiddles, int size, int strideCurrent) {
+
+        int dstOffsetIncr = m << 1;
+        int scratchOffsetIncr = 2;
+        int twiddleOffsetIncr = (strideCurrent * m) << 1;
+
+        int modulus = size << 1;
+
+        for (int i = 0; i < m; i++) {
+
+            for (int j = 0, dstOffset = (i << 1) + dstOffsetCurrent, scratchOffset = 0; j < p; //
+            j++, dstOffset += dstOffsetIncr, scratchOffset += scratchOffsetIncr) {
+
+                scratch[scratchOffset] = dst[dstOffset];
+                scratch[scratchOffset + 1] = dst[dstOffset + 1];
+            }
+
+            for (int j = 0, dstOffset = (i << 1) + dstOffsetCurrent, twiddleOffset = (strideCurrent * i) << 1; j < p; //
+            j++, dstOffset += dstOffsetIncr, twiddleOffset += twiddleOffsetIncr) {
+
+                dst[dstOffset] = scratch[0];
+                dst[dstOffset + 1] = scratch[1];
+
+                for (int k = 1, scratchOffset = 2, modOffset = twiddleOffset; k < p; //
+                k++, scratchOffset += scratchOffsetIncr, //
+                modOffset = (modOffset + twiddleOffset) % modulus) {
+
+                    dst[dstOffset] += scratch[scratchOffset] * twiddles[modOffset] //
+                            - scratch[scratchOffset + 1] * twiddles[modOffset + 1];
+                    dst[dstOffset + 1] += scratch[scratchOffset] * twiddles[modOffset + 1] //
+                            + scratch[scratchOffset + 1] * twiddles[modOffset];
+                }
+            }
+        }
+    }
+
+    // Dummy constructor.
+    FFTOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTService.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTService.java
new file mode 100755
index 0000000..9316e2b
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/FFTService.java
@@ -0,0 +1,95 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.fft;
+
+import shared.util.Service;
+
+/**
+ * Defines a {@link Service} for FFT operations.
+ * 
+ * @author Roy Liu
+ */
+public interface FFTService extends Service {
+
+    /**
+     * Computes a reduced forwards transform.
+     * 
+     * @param dims
+     *            the dimensions of the transform.
+     * @param in
+     *            the input array.
+     * @param out
+     *            the output array.
+     */
+    public void rfft(int[] dims, double[] in, double[] out);
+
+    /**
+     * Computes a reduced backwards transform.
+     * 
+     * @param dims
+     *            the dimensions of the transform.
+     * @param in
+     *            the input array.
+     * @param out
+     *            the output array.
+     */
+    public void rifft(int[] dims, double[] in, double[] out);
+
+    /**
+     * Computes a forwards transform.
+     * 
+     * @param dims
+     *            the dimensions of the transform.
+     * @param in
+     *            the input array.
+     * @param out
+     *            the output array.
+     */
+    public void fft(int[] dims, double[] in, double[] out);
+
+    /**
+     * Computes a backwards transform.
+     * 
+     * @param dims
+     *            the dimensions of the transform.
+     * @param in
+     *            the input array.
+     * @param out
+     *            the output array.
+     */
+    public void ifft(int[] dims, double[] in, double[] out);
+
+    /**
+     * Sets the value of the given hint.
+     * 
+     * @param name
+     *            the hint name.
+     * @param value
+     *            the value.
+     */
+    public void setHint(String name, String value);
+
+    /**
+     * Gets the value of the given hint.
+     * 
+     * @param name
+     *            the hint name.
+     * @return the hint value.
+     */
+    public String getHint(String name);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/JavaFFTService.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/JavaFFTService.java
new file mode 100755
index 0000000..cf55833
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/JavaFFTService.java
@@ -0,0 +1,191 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.fft;
+
+import java.util.Arrays;
+
+import shared.array.ComplexArray;
+import shared.array.RealArray;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * An {@link FFTService} implementation in pure Java.
+ * 
+ * @apiviz.uses shared.fft.FFTOps
+ * @author Roy Liu
+ */
+public class JavaFFTService implements FFTService {
+
+    /**
+     * Default constructor.
+     */
+    public JavaFFTService() {
+    }
+
+    public void rfft(int[] dims, double[] in, double[] out) {
+
+        ComplexArray proxyIn = new RealArray(in, dims).tocRe();
+        ComplexArray proxyOut = proxyIn.clone();
+
+        FFTOps.fft(+1, dims, proxyIn.values(), proxyOut.values());
+
+        proxyOut = fullToReduced(proxyOut);
+
+        System.arraycopy(proxyOut.values(), 0, out, 0, //
+                Control.checkEquals(proxyOut.values().length, out.length));
+    }
+
+    public void rifft(int[] dims, double[] in, double[] out) {
+
+        int ndims = dims.length;
+        int[] subdims = Arrays.copyOf(dims, ndims + 1);
+
+        subdims[ndims - 1] = (subdims[ndims - 1] >>> 1) + 1;
+        subdims[ndims] = 2;
+
+        ComplexArray proxyIn = reducedToFull(new ComplexArray(in, subdims), dims);
+        ComplexArray proxyOut = proxyIn.clone();
+
+        FFTOps.fft(-1, dims, proxyIn.values(), proxyOut.values());
+
+        RealArray realProxyOut = proxyOut.torRe();
+
+        System.arraycopy(realProxyOut.values(), 0, out, 0, //
+                Control.checkEquals(realProxyOut.values().length, out.length));
+    }
+
+    public void fft(int[] dims, double[] in, double[] out) {
+        FFTOps.fft(+1, dims, in, out);
+    }
+
+    public void ifft(int[] dims, double[] in, double[] out) {
+        FFTOps.fft(-1, dims, in, out);
+    }
+
+    public void setHint(String name, String value) {
+        throw new IllegalArgumentException("Unknown hint");
+    }
+
+    public String getHint(String name) {
+        throw new IllegalArgumentException("Unknown hint");
+    }
+
+    /**
+     * Derives a full {@link ComplexArray} from a reduced, half-complex {@link ComplexArray}.
+     * 
+     * @param reduced
+     *            the reduced array.
+     * @param logicalDims
+     *            the logical {@link RealArray} dimensions.
+     * @return the full array.
+     */
+    public ComplexArray reducedToFull(ComplexArray reduced, int[] logicalDims) {
+
+        int[] reducedDims = reduced.dimensions();
+        int ndims = reducedDims.length;
+
+        int[] fullDims = Arrays.copyOf(logicalDims, ndims);
+        fullDims[ndims - 1] = 2;
+
+        ComplexArray full = new ComplexArray(fullDims);
+
+        //
+
+        int[] mapBounds = new int[3 * ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            mapBounds[3 * dim] = 0;
+            mapBounds[3 * dim + 1] = 0;
+            mapBounds[3 * dim + 2] = reducedDims[dim];
+        }
+
+        reduced.map(full, mapBounds);
+
+        //
+
+        int[] slices = new int[3 * Arithmetic.sum(reducedDims)];
+        int[] sliceOffsets = new int[ndims];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++) {
+
+            sliceOffsets[dim] = offset;
+
+            for (int j = 0, m = reducedDims[dim]; j < m; j++, offset += 3) {
+
+                slices[offset] = j;
+                slices[offset + 1] = j;
+                slices[offset + 2] = dim;
+            }
+        }
+
+        for (int dim = ndims - 2; dim >= 0; dim--) {
+
+            int sliceOffset = sliceOffsets[dim];
+
+            for (int j = 1, m = reducedDims[dim], offset = sliceOffset + 3; j < m; j++, offset += 3) {
+
+                slices[offset] = j;
+                slices[offset + 1] = m - j;
+                slices[offset + 2] = dim;
+            }
+
+            reduced = reduced.splice(new ComplexArray(reducedDims), slices);
+
+            for (int j = 1, m = reducedDims[dim], offset = sliceOffset + 3; j < m; j++, offset += 3) {
+
+                slices[offset] = j;
+                slices[offset + 1] = j;
+                slices[offset + 2] = dim;
+            }
+        }
+
+        //
+
+        mapBounds[3 * (ndims - 2)] = 2 * reducedDims[ndims - 2] - fullDims[ndims - 2];
+        mapBounds[3 * (ndims - 2) + 1] = reducedDims[ndims - 2];
+        mapBounds[3 * (ndims - 2) + 2] = fullDims[ndims - 2] - reducedDims[ndims - 2];
+
+        return reduced.uConj().map(full, mapBounds);
+    }
+
+    /**
+     * Derives a reduced, half-complex {@link ComplexArray} from a full {@link ComplexArray}.
+     * 
+     * @param full
+     *            the full array.
+     * @return the reduced array.
+     */
+    public ComplexArray fullToReduced(ComplexArray full) {
+
+        int[] fullDims = full.dimensions();
+        int ndims = fullDims.length;
+
+        int[] subbounds = new int[ndims << 1];
+
+        for (int dim = 0, offset = 0; dim < ndims; dim++, offset += 2) {
+            subbounds[offset + 1] = fullDims[dim];
+        }
+
+        subbounds[((ndims - 2) << 1) + 1] >>>= 1;
+        subbounds[((ndims - 2) << 1) + 1]++;
+
+        return full.subarray(subbounds);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/ModalFFTService.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/ModalFFTService.java
new file mode 100755
index 0000000..014cfe4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/ModalFFTService.java
@@ -0,0 +1,93 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.fft;
+
+import shared.util.Services;
+
+/**
+ * An {@link FFTService} backed by a service provider as well as a pure Java implementation.
+ * 
+ * @apiviz.owns shared.fft.JavaFFTService
+ * @author Roy Liu
+ */
+public class ModalFFTService implements FFTService {
+
+    volatile FFTService service;
+
+    /**
+     * Default constructor. Tries to obtain a service provider. Failing that, falls back to {@link JavaFFTService}.
+     */
+    public ModalFFTService() {
+
+        this.service = Services.createService(FFTService.class);
+
+        if (this.service == null) {
+            this.service = new JavaFFTService();
+        }
+    }
+
+    /**
+     * Uses the service provider obtained from {@link Services#createService(Class)}.
+     */
+    public boolean useProvider() {
+
+        this.service = Services.createService(FFTService.class);
+
+        if (this.service == null) {
+
+            this.service = new JavaFFTService();
+
+            return false;
+
+        } else {
+
+            return true;
+        }
+    }
+
+    /**
+     * Uses {@link JavaFFTService}.
+     */
+    public void useJava() {
+        this.service = new JavaFFTService();
+    }
+
+    public void rfft(int[] dims, double[] in, double[] out) {
+        this.service.rfft(dims, in, out);
+    }
+
+    public void rifft(int[] dims, double[] in, double[] out) {
+        this.service.rifft(dims, in, out);
+    }
+
+    public void fft(int[] dims, double[] in, double[] out) {
+        this.service.fft(dims, in, out);
+    }
+
+    public void ifft(int[] dims, double[] in, double[] out) {
+        this.service.ifft(dims, in, out);
+    }
+
+    public void setHint(String name, String value) {
+        this.service.setHint(name, value);
+    }
+
+    public String getHint(String name) {
+        return this.service.getHint(name);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/fft/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/fft/package-info.java
new file mode 100755
index 0000000..4d7bdf1
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/fft/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package for FFT's.
+ */
+package shared.fft;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/IntegralHistogram.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/IntegralHistogram.java
new file mode 100755
index 0000000..1c6260c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/IntegralHistogram.java
@@ -0,0 +1,124 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image;
+
+import shared.array.IntegerArray;
+import shared.array.RealArray;
+import shared.image.kernel.ImageOps;
+import shared.util.Control;
+
+/**
+ * A data structure for computing the histogram over any rectangular region quickly.
+ * 
+ * @author Roy Liu
+ */
+public class IntegralHistogram extends RealArray {
+
+    final int[] ilut;
+
+    /**
+     * Default constructor.
+     * 
+     * @param src
+     *            the {@link RealArray} to integrate over.
+     * @param membership
+     *            the class membership information.
+     * @param nbins
+     *            the number of bins.
+     */
+    public IntegralHistogram(RealArray src, IntegerArray membership, int nbins) {
+        super(getDimensionsPlusOne(src, nbins));
+
+        RealArray dst = this;
+
+        int[] srcDims = src.dimensions();
+        int[] dstDims = dst.dimensions();
+
+        Control.checkTrue(src.order() == membership.order(), //
+                "Indexing order mismatch");
+
+        ImageOps.ImKernel.createIntegralHistogram( //
+                src.values(), srcDims, src.order().strides(srcDims), membership.values(), //
+                dst.values(), dstDims, dst.order().strides(dstDims));
+
+        this.ilut = ImageOps.createILUT(ndims() - 1);
+    }
+
+    /**
+     * Queries for the values histogram within a rectangular region, whose bounds are expressed in the same way as
+     * {@link RealArray#subarray(int...)}.
+     * 
+     * @see RealArray#subarray(int...)
+     */
+    public double[] query(double[] res, int... bounds) {
+
+        double[] values = values();
+
+        int ndims = ndims() - 1;
+        int stride = ndims + 1;
+        int[] ilut = this.ilut;
+
+        int nbins = size(ndims);
+        int binStride = stride(ndims);
+
+        for (int binIndex = 0, binOffset = 0; binIndex < nbins; binIndex++, binOffset += binStride) {
+
+            double sum = 0.0;
+
+            for (int i = 0, n = (1 << ndims), offset = 0; i < n; i++, offset += stride) {
+
+                int index = binOffset;
+
+                for (int dim = 0; dim < ndims; dim++) {
+                    index += bounds[ilut[offset + dim]] * stride(dim);
+                }
+
+                sum += values[index] * ilut[offset + ndims];
+            }
+
+            res[binIndex] = sum;
+        }
+
+        return res;
+    }
+
+    /**
+     * Gets the number of bins.
+     */
+    public int nbins() {
+        return size(ndims() - 1);
+    }
+
+    /**
+     * Gets the original dimensions plus one with an additional "bins" dimension at the end.
+     */
+    final protected static int[] getDimensionsPlusOne(RealArray arr, int nbins) {
+
+        int ndims = arr.ndims();
+
+        int[] res = new int[ndims + 1];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            res[dim] = arr.size(dim) + 1;
+        }
+
+        res[ndims] = nbins;
+
+        return res;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/IntegralImage.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/IntegralImage.java
new file mode 100755
index 0000000..1e98d3c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/IntegralImage.java
@@ -0,0 +1,97 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image;
+
+import shared.array.RealArray;
+import shared.image.kernel.ImageOps;
+
+/**
+ * A data structure for computing the sum over any rectangular region quickly.
+ * 
+ * @author Roy Liu
+ */
+public class IntegralImage extends RealArray {
+
+    final int[] ilut;
+
+    /**
+     * Default constructor.
+     * 
+     * @param src
+     *            the {@link RealArray} to integrate over.
+     */
+    public IntegralImage(RealArray src) {
+        super(getDimensionsPlusOne(src));
+
+        RealArray dst = this;
+
+        int[] srcDims = src.dimensions();
+        int[] dstDims = dst.dimensions();
+
+        ImageOps.ImKernel.createIntegralImage( //
+                src.values(), srcDims, src.order().strides(srcDims), //
+                dst.values(), dstDims, dst.order().strides(dstDims));
+
+        this.ilut = ImageOps.createILUT(ndims());
+    }
+
+    /**
+     * Queries for the sum of the values within a rectangular region, whose bounds are expressed in the same way as
+     * {@link RealArray#subarray(int...)}.
+     * 
+     * @see RealArray#subarray(int...)
+     */
+    public double query(int... bounds) {
+
+        double sum = 0.0;
+        double[] values = values();
+
+        int ndims = ndims();
+        int stride = ndims + 1;
+        int[] ilut = this.ilut;
+
+        for (int i = 0, n = (1 << ndims), offset = 0; i < n; i++, offset += stride) {
+
+            int index = 0;
+
+            for (int dim = 0; dim < ndims; dim++) {
+                index += bounds[ilut[offset + dim]] * stride(dim);
+            }
+
+            sum += values[index] * ilut[offset + ndims];
+        }
+
+        return sum;
+    }
+
+    /**
+     * Gets the original dimensions plus one.
+     */
+    final protected static int[] getDimensionsPlusOne(RealArray arr) {
+
+        int ndims = arr.ndims();
+
+        int[] res = new int[ndims];
+
+        for (int dim = 0; dim < ndims; dim++) {
+            res[dim] = arr.size(dim) + 1;
+        }
+
+        return res;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/IntensityImages.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/IntensityImages.java
new file mode 100755
index 0000000..27cddaa
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/IntensityImages.java
@@ -0,0 +1,262 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+
+import shared.array.RealArray;
+import shared.array.Array.IndexingOrder;
+import shared.util.Control;
+
+/**
+ * A collection of static methods for reading and writing intensity images represented as {@link RealArray}s.
+ * 
+ * @author Roy Liu
+ */
+public class IntensityImages {
+
+    /**
+     * A mapping of color names to interpolating color maps.
+     */
+    final protected static Map<String, int[]> ColorMaps;
+
+    static {
+
+        ColorMaps = new HashMap<String, int[]>();
+
+        ColorMaps.put("gray", createInterpolatingColorMap( //
+                0, 0xFF000000, //
+                255, 0xFFFFFFFF));
+
+        ColorMaps.put("jet", createInterpolatingColorMap( //
+                0, 0xFF000080, //
+                31, 0xFF0000FF, //
+                95, 0xFF00FFFF, //
+                160, 0xFFFFFF00, //
+                223, 0xFFFF0000, //
+                255, 0xFF800000));
+    }
+
+    /**
+     * Converts a {@link RealArray} to a {@link BufferedImage}.
+     * 
+     * @param m
+     *            the intensity image.
+     * @param cmName
+     *            the name of the color map to display with.
+     * @param rangeMin
+     *            the minimum intensity.
+     * @param rangeMax
+     *            the maximum intensity.
+     * @return an image representation.
+     */
+    final public static BufferedImage createImage(RealArray m, String cmName, double rangeMin, double rangeMax) {
+
+        Control.checkTrue(m.ndims() == 2, //
+                "Number of array dimensions must equal two");
+
+        Control.checkTrue(rangeMax > rangeMin, //
+                "Invalid intensity range");
+
+        int[] colorMap = ColorMaps.get(cmName);
+
+        Control.checkTrue(colorMap != null, //
+                "Invalid color map name");
+
+        m = m.transpose(1, 0).reverseOrder().uAdd(-rangeMin) //
+                .uMul(1.0 / (rangeMax - rangeMin));
+
+        double[] backing = m.values();
+        int[] arr = new int[backing.length];
+
+        for (int i = 0, n = backing.length; i < n; i++) {
+            arr[i] = colorMap[(int) (backing[i] * 255)];
+        }
+
+        BufferedImage bi = new BufferedImage(m.size(0), m.size(1), BufferedImage.TYPE_INT_RGB);
+        bi.getRaster().setDataElements(0, 0, m.size(0), m.size(1), arr);
+
+        return bi;
+    }
+
+    /**
+     * Converts a {@link BufferedImage} to a {@link RealArray}.
+     * 
+     * @param image
+     *            the original image.
+     * @return an intensity image representation.
+     */
+    final public static RealArray createMatrix(BufferedImage image) {
+
+        Raster raster = ensureGrayscale(image).getRaster();
+
+        RealArray res = new RealArray(IndexingOrder.NEAR, image.getWidth(), image.getHeight());
+
+        raster.getSamples(0, 0, image.getWidth(), image.getHeight(), 0, res.values());
+
+        return res.reverseOrder().transpose(1, 0).uMul(1.0d / 256);
+    }
+
+    /**
+     * Creates a {@link RealArray} from an image file.
+     * 
+     * @param file
+     *            the image file.
+     * @return the intensity image.
+     * @throws IOException
+     *             when the load operation goes awry.
+     */
+    final public static RealArray createMatrix(File file) throws IOException {
+        return createMatrix(ImageIO.read(file));
+    }
+
+    /**
+     * Creates a {@link RealArray} from a {@code byte} array.
+     * 
+     * @param data
+     *            the binary data.
+     * @return the intensity image.
+     * @throws IOException
+     *             when the load operation goes awry.
+     */
+    final public static RealArray createMatrix(byte[] data) throws IOException {
+        return createMatrix(bytesToJpeg(data));
+    }
+
+    /**
+     * Converts a {@link BufferedImage} to a {@code byte} array.
+     * 
+     * @param bi
+     *            the image.
+     * @return the binary data.
+     * @throws IOException
+     *             when the encoding operation goes awry.
+     */
+    final public static byte[] jpegToBytes(BufferedImage bi) throws IOException {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ImageIO.write(ensureGrayscale(bi), "jpeg", out);
+
+        return out.toByteArray();
+    }
+
+    /**
+     * Converts a {@code byte} array to a {@link BufferedImage}.
+     * 
+     * @param data
+     *            the binary data.
+     * @return the image.
+     * @throws IOException
+     *             when the decoding operation goes awry.
+     */
+    final public static BufferedImage bytesToJpeg(byte[] data) throws IOException {
+
+        ByteArrayInputStream in = new ByteArrayInputStream(data);
+        BufferedImage bi = ImageIO.read(in);
+
+        return bi;
+    }
+
+    /**
+     * Ensures that an image is in grayscale, converting it if necessary.
+     */
+    final protected static BufferedImage ensureGrayscale(BufferedImage src) {
+
+        BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), //
+                BufferedImage.TYPE_BYTE_GRAY);
+
+        Graphics2D g2 = dst.createGraphics();
+        g2.drawImage(src, 0, 0, null);
+        g2.dispose();
+
+        return dst;
+    }
+
+    /**
+     * Creates a color map by interpolating between start, end, and intermediate colors.
+     */
+    final protected static int[] createInterpolatingColorMap(int... args) {
+
+        Control.checkTrue(args.length < 4 //
+                || args.length % 2 == 0 //
+                || args[0] != 0 //
+                || args[args.length - 2] != 255, //
+                "Invalid arguments");
+
+        int[] indices = new int[args.length / 2];
+        int[] values = new int[args.length / 2];
+
+        for (int i = 0, n = indices.length; i < n; i++) {
+
+            indices[i] = args[2 * i];
+            values[i] = args[2 * i + 1];
+        }
+
+        int[] colorMap = new int[256];
+
+        for (int i = 1, n = indices.length; i < n; i++) {
+
+            int lower = indices[i - 1];
+            int upper = indices[i];
+            int diff = upper - lower;
+
+            if (diff <= 0) {
+                throw new RuntimeException("Invalid arguments");
+            }
+
+            int srcARGB = values[i - 1];
+            int dstARGB = values[i];
+
+            int aSrc = (srcARGB >>> 24) & 0xFF;
+            int rSrc = (srcARGB >>> 16) & 0xFF;
+            int gSrc = (srcARGB >>> 8) & 0xFF;
+            int bSrc = srcARGB & 0xFF;
+
+            double aIncr = (((dstARGB >>> 24) & 0xFF) - aSrc) / (double) diff;
+            double rIncr = (((dstARGB >>> 16) & 0xFF) - rSrc) / (double) diff;
+            double gIncr = (((dstARGB >>> 8) & 0xFF) - gSrc) / (double) diff;
+            double bIncr = ((dstARGB & 0xFF) - bSrc) / (double) diff;
+
+            for (int j = lower; j <= upper; j++) {
+
+                int a = ((((int) Math.round(aSrc + (j - lower) * aIncr)) & 0xFF) << 24);
+                int r = ((((int) Math.round(rSrc + (j - lower) * rIncr)) & 0xFF) << 16);
+                int g = ((((int) Math.round(gSrc + (j - lower) * gIncr)) & 0xFF) << 8);
+                int b = (((int) Math.round(bSrc + (j - lower) * bIncr)) & 0xFF);
+
+                colorMap[j] = a | r | g | b;
+            }
+        }
+
+        return colorMap;
+    }
+
+    // Dummy constructor.
+    IntensityImages() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/DerivativeOfGaussian.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/DerivativeOfGaussian.java
new file mode 100755
index 0000000..af1307a
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/DerivativeOfGaussian.java
@@ -0,0 +1,141 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.filter;
+
+import shared.array.RealArray;
+import shared.fft.Cacheable;
+
+/**
+ * An implementation of DooG filters up to {@code 0}th and {@code 1}st derivatives.
+ * 
+ * @apiviz.uses shared.image.filter.Filters
+ * @author Roy Liu
+ */
+public class DerivativeOfGaussian extends RealArray implements Cacheable {
+
+    final double theta, scale;
+    final int ord, hashCode, supportRadius;
+
+    @Override
+    public String toString() {
+        return String.format("DooG[%d, %4.2f, %4.2f, %d]", //
+                this.supportRadius, this.theta, this.scale, this.ord);
+    }
+
+    /**
+     * Fulfills the {@link Object#equals(Object)} contract.
+     */
+    @Override
+    public boolean equals(Object o) {
+
+        if (!(o instanceof DerivativeOfGaussian)) {
+            return false;
+        }
+
+        DerivativeOfGaussian g = (DerivativeOfGaussian) o;
+        return this.supportRadius == g.supportRadius //
+                && this.theta == g.theta //
+                && this.scale == g.scale //
+                && this.ord == g.ord;
+    }
+
+    /**
+     * Fulfills the {@link Object#hashCode()} contract.
+     */
+    @Override
+    public int hashCode() {
+        return this.hashCode;
+    }
+
+    /**
+     * Default constructor.
+     * 
+     * @param supportRadius
+     *            the support radius.
+     * @param theta
+     *            the orientation.
+     * @param scale
+     *            the scale.
+     * @param ord
+     *            the order of the derivative.
+     */
+    public DerivativeOfGaussian(int supportRadius, double theta, double scale, int ord) {
+        super(2 * supportRadius + 1, 2 * supportRadius + 1);
+
+        this.supportRadius = supportRadius;
+        this.theta = theta;
+        this.scale = scale;
+        this.ord = ord;
+
+        this.hashCode = new Integer(supportRadius).hashCode() //
+                ^ new Double(theta).hashCode() //
+                ^ new Double(scale).hashCode() //
+                ^ new Integer(ord).hashCode();
+
+        double sigma = (scale * supportRadius) / 3.0d;
+
+        RealArray ptsMatrix = Filters.createRotationMatrix(theta) //
+                .mMul(Filters.createPointSupport(supportRadius));
+
+        RealArray ptsY = ptsMatrix.subarray(0, 1, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+        RealArray ptsX = ptsMatrix.subarray(1, 2, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+
+        RealArray gX = derivative(sigma, ptsX, ord);
+        RealArray gY = derivative(sigma, ptsY, 0);
+
+        gX.eMul(gY).map(this, 0, 0, size(0), 0, 0, size(1));
+
+        switch (ord) {
+
+        case 0:
+            uMul(1.0 / aSum());
+            break;
+
+        case 1:
+            uAdd(-aMean());
+            break;
+        }
+    }
+
+    /**
+     * Calculates a Gaussian derivative to the specified order.
+     */
+    final protected static RealArray derivative(double sigma, RealArray support, int order) {
+
+        double variance = sigma * sigma;
+
+        // Get a working copy.
+        RealArray g = support.eMul(support) //
+                .uMul(-1.0 / (2 * variance)).uExp() //
+                .uMul(1.0 / Math.sqrt(2 * Math.PI * variance));
+
+        switch (order) {
+
+        case 0:
+            return g;
+
+        case 1:
+            return g.eMul(support.clone().uMul(-1.0d / variance));
+
+        default:
+            throw new IllegalArgumentException("Order of derivative can only be zero or one");
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Filters.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Filters.java
new file mode 100755
index 0000000..1adef4f
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Filters.java
@@ -0,0 +1,123 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.filter;
+
+import shared.array.AbstractArray;
+import shared.array.ComplexArray;
+import shared.array.RealArray;
+
+/**
+ * A collection of static methods in support of two-dimensional filters.
+ * 
+ * @author Roy Liu
+ */
+public class Filters {
+
+    /**
+     * Mutatively normalizes a {@link RealArray} by its <tt>L1</tt> norm or, alternatively, a {@link ComplexArray} by
+     * its complex magnitudes.
+     */
+    final public static <T extends AbstractArray<?, ?, ?, ?>> void normalize(T array) {
+
+        if (array instanceof RealArray) {
+
+            RealArray m = (RealArray) array;
+
+            m = m.uAdd(-m.aMean());
+            m.uMul(1.0 / m.clone().uAbs().aSum());
+
+        } else if (array instanceof ComplexArray) {
+
+            ComplexArray c = (ComplexArray) array;
+
+            double[] mean = c.aMean();
+
+            c.uAdd(-mean[0], -mean[1]);
+            c.uMul(1.0 / c.torAbs().aSum(), 0.0);
+
+        } else {
+
+            throw new IllegalArgumentException("Array type not recognized");
+        }
+    }
+
+    /**
+     * Creates the <tt>2x2</tt> rotation matrix <br />
+     * <tt>-cos(theta) -sin(theta)</tt> <br />
+     * <tt>-sin(theta) cos(theta)</tt>. <br />
+     * 
+     * @param theta
+     *            the angle of rotation.
+     * @return the rotation matrix.
+     */
+    final public static RealArray createRotationMatrix(double theta) {
+
+        RealArray res = new RealArray(2, 2);
+
+        res.set(-Math.cos(theta), 0, 0);
+        res.set(-Math.sin(theta), 0, 1);
+        res.set(-Math.sin(theta), 1, 0);
+        res.set(Math.cos(theta), 1, 1);
+
+        return res;
+    }
+
+    /**
+     * Creates a pair of <tt>x</tt> and <tt>y</tt> axis aligned DooG kernels for gradient calculations.
+     * 
+     * @param supportRadius
+     *            the kernel support radius.
+     * @return the pair of kernels.
+     */
+    final public static RealArray[] createGradientKernels(int supportRadius) {
+
+        RealArray[] gk = new RealArray[2];
+
+        normalize(gk[0] = new DerivativeOfGaussian(supportRadius, 0.0, 1.0, 1));
+        normalize(gk[1] = new DerivativeOfGaussian(supportRadius, 3.0 * Math.PI / 2.0, 1.0, 1));
+
+        return gk;
+    }
+
+    /**
+     * Creates a point support matrix. The top row consists of <tt>x</tt> coordinates, and the bottom row consists of
+     * <tt>y</tt> coordinates. The points range in a square where the origin is at the center.
+     * 
+     * @param supportRadius
+     *            the support radius.
+     * @return the point support matrix.
+     */
+    final public static RealArray createPointSupport(int supportRadius) {
+
+        int support = supportRadius * 2 + 1;
+
+        RealArray pts = new RealArray(2, support * support);
+
+        for (int i = 0, n = support * support; i < n; i++) {
+
+            pts.set((i / support) - supportRadius, 0, i);
+            pts.set((i % support) - supportRadius, 1, i);
+        }
+
+        return pts;
+    }
+
+    // Dummy constructor.
+    Filters() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Gabor.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Gabor.java
new file mode 100755
index 0000000..bf5c1e7
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Gabor.java
@@ -0,0 +1,120 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.filter;
+
+import shared.array.ComplexArray;
+import shared.array.RealArray;
+import shared.fft.Cacheable;
+
+/**
+ * An implementation of oriented, complex-valued Gabor filters.
+ * 
+ * @apiviz.uses shared.image.filter.Filters
+ * @author Roy Liu
+ */
+public class Gabor extends ComplexArray implements Cacheable {
+
+    final double theta, scale, frequency, elongation;
+    final int hashCode, supportRadius;
+
+    @Override
+    public String toString() {
+        return String.format("Gabor[%d, %4.2f, %4.2f, %4.2f, %4.2f]", //
+                this.supportRadius, this.theta, this.scale, this.frequency, this.elongation);
+    }
+
+    /**
+     * Fulfills the {@link Object#equals(Object)} contract.
+     */
+    @Override
+    public boolean equals(Object o) {
+
+        if (!(o instanceof Gabor)) {
+            return false;
+        }
+
+        Gabor g = (Gabor) o;
+        return this.supportRadius == g.supportRadius //
+                && this.theta == g.theta //
+                && this.scale == g.scale //
+                && this.frequency == g.frequency //
+                && this.elongation == g.elongation;
+    }
+
+    /**
+     * Fulfills the {@link Object#hashCode()} contract.
+     */
+    @Override
+    public int hashCode() {
+        return this.hashCode;
+    }
+
+    /**
+     * Default constructor.
+     * 
+     * @param supportRadius
+     *            the support radius.
+     * @param theta
+     *            the orientation.
+     * @param scale
+     *            the scale.
+     * @param frequency
+     *            the frequency.
+     * @param elongation
+     *            the elongation.
+     */
+    public Gabor(int supportRadius, //
+            final double theta, double scale, //
+            double frequency, final double elongation) {
+        super(2 * supportRadius + 1, 2 * supportRadius + 1, 2);
+
+        this.supportRadius = supportRadius;
+        this.elongation = elongation;
+        this.theta = theta;
+        this.scale = scale;
+        this.frequency = frequency;
+
+        this.hashCode = new Integer(supportRadius).hashCode() //
+                ^ new Double(theta).hashCode() //
+                ^ new Double(scale).hashCode() //
+                ^ new Double(frequency).hashCode() //
+                ^ new Double(elongation).hashCode();
+
+        RealArray ptsMatrix = Filters.createRotationMatrix(theta) //
+                .mMul(Filters.createPointSupport(supportRadius));
+
+        RealArray ptsY = ptsMatrix.subarray(0, 1, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+        RealArray ptsX = ptsMatrix.subarray(1, 2, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+
+        final double k = scale * supportRadius / elongation;
+
+        final double a = -4.0d / (k * k);
+
+        RealArray ptsRe = ((ptsX.clone().uPow(2.0).uMul(1.0 / (elongation * elongation))) //
+                .eAdd(ptsY.clone().uPow(2.0))) //
+                .uMul(a);
+
+        final double b = 2.0d * Math.PI * frequency / k;
+
+        RealArray ptsIm = ptsY.clone().uMul(b);
+
+        (ptsRe.tocRe()).eAdd(ptsIm.tocIm()).uExp().map(this, 0, 0, size(0), 0, 0, size(1), 0, 0, 2);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/GaborCircular.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/GaborCircular.java
new file mode 100755
index 0000000..4a7e282
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/GaborCircular.java
@@ -0,0 +1,104 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.filter;
+
+import shared.array.ComplexArray;
+import shared.array.RealArray;
+import shared.fft.Cacheable;
+
+/**
+ * An implementation of circular, complex-valued Gabor filters.
+ * 
+ * @apiviz.uses shared.image.filter.Filters
+ * @author Roy Liu
+ */
+public class GaborCircular extends ComplexArray implements Cacheable {
+
+    final double scale, frequency;
+    final int hashCode, supportRadius;
+
+    @Override
+    public String toString() {
+        return String.format("GaborCircular[%d, %4.2f, %4.2f]", //
+                this.supportRadius, this.scale, this.frequency);
+    }
+
+    /**
+     * Fulfills the {@link Object#equals(Object)} contract.
+     */
+    @Override
+    public boolean equals(Object o) {
+
+        if (!(o instanceof GaborCircular)) {
+            return false;
+        }
+
+        GaborCircular g = (GaborCircular) o;
+        return this.supportRadius == g.supportRadius //
+                && this.scale == g.scale //
+                && this.frequency == g.frequency;
+    }
+
+    /**
+     * Fulfills the {@link Object#hashCode()} contract.
+     */
+    @Override
+    public int hashCode() {
+        return this.hashCode;
+    }
+
+    /**
+     * Default constructor.
+     * 
+     * @param supportRadius
+     *            the support radius.
+     * @param scale
+     *            the scale.
+     * @param frequency
+     *            the frequency.
+     */
+    public GaborCircular(int supportRadius, double scale, double frequency) {
+        super(2 * supportRadius + 1, 2 * supportRadius + 1, 2);
+
+        this.supportRadius = supportRadius;
+        this.scale = scale;
+        this.frequency = frequency;
+
+        this.hashCode = new Integer(supportRadius).hashCode() //
+                ^ new Double(scale).hashCode() //
+                ^ new Double(frequency).hashCode();
+
+        RealArray ptsMatrix = Filters.createPointSupport(supportRadius);
+        RealArray ptsY = ptsMatrix.subarray(0, 1, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+        RealArray ptsX = ptsMatrix.subarray(1, 2, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+
+        final double k = scale * supportRadius;
+
+        final double a = -4.0d / (k * k);
+
+        RealArray ptsRe = ((ptsX.clone().uPow(2.0)).eAdd(ptsY.clone().uPow(2.0))).uMul(a);
+
+        final double b = 2.0d * Math.PI * frequency / k;
+
+        RealArray ptsIm = ((ptsX.clone().uPow(2.0)).eAdd(ptsY.clone().uPow(2.0))).uPow(0.5).uMul(b);
+
+        (ptsRe.tocRe()).eAdd(ptsIm.tocIm()).uExp().map(this, 0, 0, size(0), 0, 0, size(1), 0, 0, 2);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/LaplacianOfGaussian.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/LaplacianOfGaussian.java
new file mode 100755
index 0000000..58ec054
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/LaplacianOfGaussian.java
@@ -0,0 +1,95 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.filter;
+
+import shared.array.RealArray;
+import shared.fft.Cacheable;
+
+/**
+ * An implementation of LoG filters.
+ * 
+ * @apiviz.uses shared.image.filter.Filters
+ * @author Roy Liu
+ */
+public class LaplacianOfGaussian extends RealArray implements Cacheable {
+
+    final double scale;
+    final int hashCode, supportRadius;
+
+    @Override
+    public String toString() {
+        return String.format("LoG[%d, %4.2f]", //
+                this.supportRadius, this.scale);
+    }
+
+    /**
+     * Fulfills the {@link Object#equals(Object)} contract.
+     */
+    @Override
+    public boolean equals(Object o) {
+
+        if (!(o instanceof LaplacianOfGaussian)) {
+            return false;
+        }
+
+        LaplacianOfGaussian g = (LaplacianOfGaussian) o;
+        return this.supportRadius == g.supportRadius && this.scale == g.scale;
+    }
+
+    /**
+     * Fulfills the {@link Object#hashCode()} contract.
+     */
+    @Override
+    public int hashCode() {
+        return this.hashCode;
+    }
+
+    /**
+     * Default constructor.
+     * 
+     * @param supportRadius
+     *            the support radius.
+     * @param scale
+     *            the scale.
+     */
+    public LaplacianOfGaussian(int supportRadius, double scale) {
+        super(2 * supportRadius + 1, 2 * supportRadius + 1);
+
+        this.supportRadius = supportRadius;
+        this.scale = scale;
+
+        this.hashCode = new Integer(supportRadius).hashCode() ^ new Double(scale).hashCode();
+
+        double sigma = (scale * supportRadius) / 3.0d;
+
+        RealArray ptsMatrix = Filters.createPointSupport(supportRadius);
+
+        RealArray ptsY = ptsMatrix.subarray(0, 1, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+        RealArray ptsX = ptsMatrix.subarray(1, 2, 0, ptsMatrix.size(1)) //
+                .reshape(2 * supportRadius + 1, 2 * supportRadius + 1);
+
+        ptsX.clone().uSqr().eAdd(ptsY.clone().uSqr()) //
+                .uAdd(-2.0 * sigma * sigma) //
+                .uMul(1.0 / (sigma * sigma * sigma * sigma)) //
+                .eMul(new DerivativeOfGaussian(supportRadius, 0.0, 1.0, 0)) //
+                .map(this, 0, 0, size(0), 0, 0, size(1));
+
+        uAdd(-aMean());
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Mean.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Mean.java
new file mode 100755
index 0000000..511a43b
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/Mean.java
@@ -0,0 +1,82 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.filter;
+
+import shared.array.RealArray;
+import shared.fft.Cacheable;
+
+/**
+ * A mean low-pass filter.
+ * 
+ * @author Roy Liu
+ */
+public class Mean extends RealArray implements Cacheable {
+
+    final int hashCode;
+    final int width;
+    final int height;
+
+    @Override
+    public String toString() {
+        return String.format("Mean[%d, %d]", //
+                this.width, this.height);
+    }
+
+    /**
+     * Fulfills the {@link Object#equals(Object)} contract.
+     */
+    @Override
+    public boolean equals(Object o) {
+
+        if (!(o instanceof Mean)) {
+            return false;
+        }
+
+        Mean m = (Mean) o;
+        return this.width == m.width //
+                && this.height == m.height;
+    }
+
+    /**
+     * Fulfills the {@link Object#hashCode()} contract.
+     */
+    @Override
+    public int hashCode() {
+        return this.hashCode;
+    }
+
+    /**
+     * Default constructor.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     */
+    public Mean(int width, int height) {
+        super(width, height);
+
+        this.hashCode = new Integer(width).hashCode() //
+                ^ new Integer(height).hashCode();
+
+        this.width = width;
+        this.height = height;
+
+        uFill(1.0 / (width * height));
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/package-info.java
new file mode 100755
index 0000000..3414e32
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/filter/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of two-dimensional filters.
+ */
+package shared.image.filter;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/jni/NativeImageKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/jni/NativeImageKernel.java
new file mode 100755
index 0000000..7ccd798
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/jni/NativeImageKernel.java
@@ -0,0 +1,47 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.jni;
+
+import shared.image.kernel.ImageKernel;
+import shared.metaclass.Library;
+import shared.util.Control;
+
+/**
+ * A native implementation of {@link ImageKernel}.
+ * 
+ * @author Roy Liu
+ */
+public class NativeImageKernel implements ImageKernel {
+
+    /**
+     * Default constructor.
+     */
+    public NativeImageKernel() {
+
+        Control.checkTrue(Library.isInitialized(), //
+                "Could not instantiate native bindings -- Linking failed");
+    }
+
+    final public native void createIntegralImage( //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS);
+
+    final public native void createIntegralHistogram( //
+            double[] srcV, int[] srcD, int[] srcS, int[] memV, //
+            double[] dstV, int[] dstD, int[] dstS);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/jni/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/jni/package-info.java
new file mode 100755
index 0000000..ddaa423
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/jni/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package for providing JNI-backed image processing operations.
+ */
+ at shared.metaclass.Policy(recursive = false)
+package shared.image.jni;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ImageKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ImageKernel.java
new file mode 100755
index 0000000..b51d3b7
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ImageKernel.java
@@ -0,0 +1,70 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.kernel;
+
+import shared.util.Service;
+
+/**
+ * A provider of image processing operations.
+ * 
+ * @author Roy Liu
+ */
+public interface ImageKernel extends Service {
+
+    /**
+     * Creates an integral image.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param dstV
+     *            the destination values.
+     * @param dstD
+     *            the destination dimensions.
+     * @param dstS
+     *            the destination strides.
+     */
+    public void createIntegralImage( //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS);
+
+    /**
+     * Creates an integral histogram.
+     * 
+     * @param srcV
+     *            the source values.
+     * @param srcD
+     *            the source dimensions.
+     * @param srcS
+     *            the source strides.
+     * @param memV
+     *            the class memberships.
+     * @param dstV
+     *            the destination values.
+     * @param dstD
+     *            the destination dimensions.
+     * @param dstS
+     *            the destination strides.
+     */
+    public void createIntegralHistogram( //
+            double[] srcV, int[] srcD, int[] srcS, int[] memV, //
+            double[] dstV, int[] dstD, int[] dstS);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ImageOps.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ImageOps.java
new file mode 100755
index 0000000..76c20c0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ImageOps.java
@@ -0,0 +1,206 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.kernel;
+
+import java.util.Arrays;
+
+import shared.array.kernel.MappingOps;
+import shared.util.Control;
+
+/**
+ * A class for image processing operations in pure Java.
+ * 
+ * @author Roy Liu
+ */
+public class ImageOps {
+
+    /**
+     * The image processing kernel.
+     */
+    public static ModalImageKernel ImKernel = new ModalImageKernel();
+
+    /**
+     * Creates an index lookup table for speedy index calculations.
+     */
+    final public static int[] createILUT(int ndims) {
+
+        int stride = ndims + 1;
+        int[] ilut = new int[(1 << ndims) * stride];
+
+        for (int i = 0, n = (1 << ndims), offset = 0, parity = ndims % 2; i < n; i++, offset += stride) {
+
+            for (int dim = 0; dim < ndims; dim++) {
+                ilut[offset + dim] = (dim << 1) + ((i >>> dim) & 0x1);
+            }
+
+            ilut[offset + ndims] = 1 - (((Integer.bitCount(i) + parity) % 2) << 1);
+        }
+
+        return ilut;
+    }
+
+    /**
+     * Supports {@link JavaImageKernel#createIntegralImage(double[], int[], int[], double[], int[], int[])}.
+     */
+    final public static void createIntegralImage( //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS) {
+
+        int ndims = srcD.length;
+
+        Control.checkTrue(ndims == srcS.length //
+                && ndims == dstD.length //
+                && ndims == dstS.length);
+
+        int srcLen = MappingOps.checkDimensions(srcV.length, srcD, srcS);
+        int dstLen = MappingOps.checkDimensions(dstV.length, dstD, dstS);
+
+        int dstOffset = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            Control.checkTrue(srcD[dim] + 1 == dstD[dim], //
+                    "Dimension mismatch");
+
+            dstOffset += dstS[dim];
+        }
+
+        if (srcLen == 0) {
+            return;
+        }
+
+        int[] srcIndices = MappingOps.assignMappingIndices(srcLen, srcD, srcS);
+        int[] dstIndices = MappingOps.assignMappingIndices(srcLen, srcD, dstS);
+
+        for (int i = 0; i < srcLen; i++) {
+            dstV[dstIndices[i] + dstOffset] = srcV[srcIndices[i]];
+        }
+
+        //
+
+        dstIndices = MappingOps.assignMappingIndices(dstLen, dstD, dstS);
+
+        for (int dim = 0, indexBlockIncrement = dstLen; dim < ndims; indexBlockIncrement /= dstD[dim++]) {
+
+            int size = dstD[dim];
+            int stride = dstS[dim];
+
+            for (int lower = 0, upper = indexBlockIncrement / size; //
+            lower < dstLen; //
+            lower += indexBlockIncrement, upper += indexBlockIncrement) {
+
+                for (int indexIndex = lower; indexIndex < upper; indexIndex++) {
+
+                    double acc = 0.0;
+
+                    for (int k = 0, physical = dstIndices[indexIndex]; k < size; k++, physical += stride) {
+
+                        acc += dstV[physical];
+                        dstV[physical] = acc;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Supports {@link JavaImageKernel#createIntegralHistogram(double[], int[], int[], int[], double[], int[], int[])}.
+     */
+    final public static void createIntegralHistogram( //
+            double[] srcV, int[] srcD, int[] srcS, int[] memV, //
+            double[] dstV, int[] dstD, int[] dstS) {
+
+        int memLen = memV.length;
+        int ndims = srcD.length;
+
+        Control.checkTrue(ndims == srcS.length //
+                && ndims + 1 == dstD.length //
+                && ndims + 1 == dstS.length //
+                && memLen == srcV.length);
+
+        int[] dstDModified = Arrays.copyOf(dstD, ndims);
+        int[] dstSModified = Arrays.copyOf(dstS, ndims);
+
+        int srcLen = MappingOps.checkDimensions(srcV.length, srcD, srcS);
+        int dstLen = MappingOps.checkDimensions(dstV.length, dstD, dstS);
+
+        int dstOffset = 0;
+
+        for (int dim = 0; dim < ndims; dim++) {
+
+            Control.checkTrue(srcD[dim] + 1 == dstD[dim], //
+                    "Dimension mismatch");
+
+            dstOffset += dstS[dim];
+        }
+
+        if (srcLen == 0) {
+            return;
+        }
+
+        int[] srcIndices = MappingOps.assignMappingIndices(srcLen, srcD, srcS);
+        int[] dstIndices = MappingOps.assignMappingIndices(srcLen, srcD, dstSModified);
+
+        int nbins = dstD[ndims];
+        int binStride = dstS[ndims];
+        int dstLenModified = dstLen / nbins;
+
+        for (int i = 0; i < srcLen; i++) {
+
+            int index = memV[srcIndices[i]];
+
+            Control.checkTrue(index >= 0 && index < nbins, //
+                    "Invalid membership index");
+
+            dstV[dstIndices[i] + dstOffset + index * binStride] = srcV[srcIndices[i]];
+        }
+
+        //
+
+        dstIndices = MappingOps.assignMappingIndices(dstLenModified, dstDModified, dstSModified);
+
+        for (int dim = 0, indexBlockIncrement = dstLenModified; dim < ndims; indexBlockIncrement /= dstDModified[dim++]) {
+
+            int size = dstDModified[dim];
+            int stride = dstSModified[dim];
+
+            for (int lower = 0, upper = indexBlockIncrement / size; //
+            lower < dstLenModified; //
+            lower += indexBlockIncrement, upper += indexBlockIncrement) {
+
+                for (int indexIndex = lower; indexIndex < upper; indexIndex++) {
+
+                    for (int binIndex = 0, binOffset = 0; binIndex < nbins; binIndex++, binOffset += binStride) {
+
+                        double acc = 0.0;
+
+                        for (int k = 0, physical = dstIndices[indexIndex] + binOffset; k < size; k++, physical += stride) {
+
+                            acc += dstV[physical];
+                            dstV[physical] = acc;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // Dummy constructor.
+    ImageOps() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/JavaImageKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/JavaImageKernel.java
new file mode 100755
index 0000000..7922f74
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/JavaImageKernel.java
@@ -0,0 +1,45 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.kernel;
+
+/**
+ * A pure Java implementation of {@link ImageKernel}.
+ * 
+ * @apiviz.uses shared.image.kernel.ImageOps
+ * @author Roy Liu
+ */
+public class JavaImageKernel implements ImageKernel {
+
+    /**
+     * Default constructor.
+     */
+    public JavaImageKernel() {
+    }
+
+    public void createIntegralImage( //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS) {
+        ImageOps.createIntegralImage(srcV, srcD, srcS, dstV, dstD, dstS);
+    }
+
+    public void createIntegralHistogram( //
+            double[] srcV, int[] srcD, int[] srcS, int[] memV, //
+            double[] dstV, int[] dstD, int[] dstS) {
+        ImageOps.createIntegralHistogram(srcV, srcD, srcS, memV, dstV, dstD, dstS);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ModalImageKernel.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ModalImageKernel.java
new file mode 100755
index 0000000..260e87c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/ModalImageKernel.java
@@ -0,0 +1,83 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.image.kernel;
+
+import shared.image.jni.NativeImageKernel;
+import shared.util.Services;
+
+/**
+ * An implementation of {@link ImageKernel} that has JNI and pure Java bindings.
+ * 
+ * @apiviz.owns shared.image.kernel.JavaImageKernel
+ * @author Roy Liu
+ */
+public class ModalImageKernel implements ImageKernel {
+
+    volatile ImageKernel imKernel;
+
+    /**
+     * Default constructor. Tries to create an underlying {@link NativeImageKernel}. Failing that, creates an underlying
+     * {@link JavaImageKernel}.
+     */
+    public ModalImageKernel() {
+
+        this.imKernel = Services.createService(ImageKernel.class);
+
+        if (this.imKernel == null) {
+            this.imKernel = new JavaImageKernel();
+        }
+    }
+
+    /**
+     * Uses the underlying {@link NativeImageKernel} obtained from {@link Services#createService(Class)}.
+     */
+    public boolean useNative() {
+
+        this.imKernel = Services.createService(ImageKernel.class);
+
+        if (this.imKernel == null) {
+
+            this.imKernel = new JavaImageKernel();
+
+            return false;
+
+        } else {
+
+            return true;
+        }
+    }
+
+    /**
+     * Uses the underlying {@link JavaImageKernel}.
+     */
+    public void useJava() {
+        this.imKernel = new JavaImageKernel();
+    }
+
+    public void createIntegralImage( //
+            double[] srcV, int[] srcD, int[] srcS, //
+            double[] dstV, int[] dstD, int[] dstS) {
+        this.imKernel.createIntegralImage(srcV, srcD, srcS, dstV, dstD, dstS);
+    }
+
+    public void createIntegralHistogram( //
+            double[] srcV, int[] srcD, int[] srcS, int[] memV, //
+            double[] dstV, int[] dstD, int[] dstS) {
+        this.imKernel.createIntegralHistogram(srcV, srcD, srcS, memV, dstV, dstD, dstS);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/package-info.java
new file mode 100755
index 0000000..402f14c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/kernel/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package for image processing operations.
+ */
+package shared.image.kernel;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/image/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/image/package-info.java
new file mode 100755
index 0000000..7eea2b7
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/image/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package for representing images and image statistics as matrices and arrays.
+ */
+package shared.image;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/log4j.xml b/contrib/applications/nxplot/sharedscientific/src/shared/log4j.xml
new file mode 100755
index 0000000..c47d835
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/log4j.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "classpath://org/apache/log4j/xml/log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="target" value="System.out" />
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="[%c{1}] %p - %m%n" />
+        </layout>
+    </appender>
+
+    <root>
+        <priority value="debug" />
+        <appender-ref ref="stdout" />
+    </root>
+
+</log4j:configuration>
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/FileSystemRegistry.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/FileSystemRegistry.java
new file mode 100755
index 0000000..8cac054
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/FileSystemRegistry.java
@@ -0,0 +1,108 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.metaclass;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+
+/**
+ * An implementation of {@link ResourceRegistry} that consults the file system for resources.
+ * 
+ * @author Roy Liu
+ */
+public class FileSystemRegistry implements ResourceRegistry {
+
+    final File folder;
+
+    /**
+     * Default constructor.
+     */
+    public FileSystemRegistry(File folder) {
+        this.folder = folder;
+    }
+
+    public URL getResource(String pathname) {
+
+        File resourceFile = new File(this.folder, pathname);
+
+        if (resourceFile.exists()) {
+
+            try {
+
+                return resourceFile.toURI().toURL();
+
+            } catch (MalformedURLException e) {
+
+                // Ah well.
+            }
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Enumeration<URL> getResources(String pathname) {
+
+        URL url = getResource(pathname);
+        return Collections.enumeration((url != null) ? Collections.singleton(url) : Collections.EMPTY_LIST);
+    }
+
+    public InputStream getResourceAsStream(String pathname) {
+
+        URL url = getResource(pathname);
+
+        if (url != null) {
+
+            try {
+
+                return url.openStream();
+
+            } catch (IOException e) {
+
+                // Ah well.
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a human-readable representation of this registry.
+     */
+    @Override
+    public String toString() {
+
+        URL url = null;
+
+        try {
+
+            url = this.folder.toURI().toURL();
+
+        } catch (MalformedURLException e) {
+
+            // Ah well.
+        }
+
+        return String.format("FileSystemRegistry[url = \"%s\"]", url);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/JarRegistry.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/JarRegistry.java
new file mode 100755
index 0000000..fba93d0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/JarRegistry.java
@@ -0,0 +1,205 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.metaclass;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+
+import shared.util.Control;
+import shared.util.TemporaryFiles;
+
+/**
+ * An implementation of {@link ResourceRegistry} that consults {@link JarFile}s and {@link JarInputStream}s for
+ * resources.
+ * 
+ * @author Roy Liu
+ */
+public class JarRegistry implements ResourceRegistry {
+
+    final Map<String, byte[]> dataMap;
+    final Map<String, File> fileMap;
+
+    /**
+     * Default constructor.
+     * 
+     * @throws IOException
+     *             when something goes awry.
+     */
+    public JarRegistry(JarFile jf) throws IOException {
+        this(createDataMap(jf));
+    }
+
+    /**
+     * Alternate constructor.
+     * 
+     * @throws IOException
+     *             when something goes awry.
+     */
+    public JarRegistry(JarInputStream jis) throws IOException {
+        this(createDataMap(jis));
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public JarRegistry() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Internal constructor.
+     */
+    protected JarRegistry(Map<String, byte[]> dataMap) {
+
+        this.dataMap = dataMap;
+        this.fileMap = new HashMap<String, File>();
+    }
+
+    /**
+     * Gets the {@link Map} of resource pathnames to {@code byte} arrays.
+     */
+    public Map<String, byte[]> getDataMap() {
+        return this.dataMap;
+    }
+
+    public URL getResource(String pathname) {
+
+        final byte[] data = this.dataMap.get(pathname);
+
+        if (data == null) {
+            return null;
+        }
+
+        synchronized (this) {
+
+            File f = this.fileMap.get(pathname);
+
+            try {
+
+                if (f != null) {
+                    return f.toURI().toURL();
+                }
+
+                f = File.createTempFile(pathname.replace("/", "_").concat("_"), "");
+
+                this.fileMap.put(pathname, f);
+                TemporaryFiles.deleteOnExit(f);
+
+                Control.transfer(data, f);
+
+                return f.toURI().toURL();
+
+            } catch (IOException e) {
+
+                // Return empty-handed if, for some reason, the temporary file could not be created.
+                return null;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public Enumeration<URL> getResources(String pathname) {
+
+        URL url = getResource(pathname);
+        return Collections.enumeration((url != null) ? Collections.singleton(url) : Collections.EMPTY_LIST);
+    }
+
+    public InputStream getResourceAsStream(String pathname) {
+
+        byte[] data = this.dataMap.get(pathname);
+
+        if (data == null) {
+            return null;
+        }
+
+        return new ByteArrayInputStream(data);
+    }
+
+    /**
+     * Gets the string "Jar Registry".
+     */
+    @Override
+    public String toString() {
+        return String.format("JarRegistry[size = %d]", this.dataMap.size());
+    }
+
+    /**
+     * Creates a mapping of pathnames to data from a {@link JarInputStream}.
+     * 
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final protected static Map<String, byte[]> createDataMap(JarInputStream jis) throws IOException {
+
+        HashMap<String, byte[]> map = new HashMap<String, byte[]>();
+
+        for (JarEntry je = null; (je = jis.getNextJarEntry()) != null;) {
+            map.put(je.getName(), Control.getBytes(jis));
+        }
+
+        return map;
+    }
+
+    /**
+     * Creates a mapping of pathnames to data from a {@link JarFile}.
+     * 
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final protected static Map<String, byte[]> createDataMap(JarFile jf) throws IOException {
+
+        HashMap<String, byte[]> map = new HashMap<String, byte[]>();
+
+        for (Enumeration<JarEntry> jes = jf.entries(); jes.hasMoreElements();) {
+
+            JarEntry je = jes.nextElement();
+            map.put(je.getName(), Control.getBytes(jf.getInputStream(je)));
+        }
+
+        return map;
+    }
+
+    // A finalizer guardian for deleting outstanding files.
+    final Object fileReaper = new Object() {
+
+        @Override
+        protected void finalize() {
+
+            JarRegistry jr = JarRegistry.this;
+
+            synchronized (jr) {
+
+                for (File f : jr.fileMap.values()) {
+
+                    Control.delete(f);
+                    TemporaryFiles.undelete(f);
+                }
+            }
+        }
+    };
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/Library.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/Library.java
new file mode 100755
index 0000000..c0b669e
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/Library.java
@@ -0,0 +1,58 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.metaclass;
+
+import java.io.File;
+
+/**
+ * A class for interacting with dynamically linked native code.
+ * 
+ * @author Roy Liu
+ */
+public class Library {
+
+    /**
+     * A flag set on load of the native library.
+     */
+    protected static boolean INITIALIZED = false;
+
+    /**
+     * Checks to see if the native library has been loaded.
+     */
+    final public static boolean isInitialized() {
+        return INITIALIZED;
+    }
+
+    /**
+     * Loads a native library from the given file.
+     */
+    final public static void load(File libFile) {
+        System.load(libFile.getAbsolutePath());
+    }
+
+    /**
+     * Loads a native library from dynamic linker resolution of the given name.
+     */
+    final public static void loadLibrary(String libName) {
+        System.loadLibrary(libName);
+    }
+
+    // Dummy constructor.
+    Library() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/Policy.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/Policy.java
new file mode 100755
index 0000000..c496ca9
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/Policy.java
@@ -0,0 +1,43 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.metaclass;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation class for directing package class loading policy.
+ * 
+ * @author Roy Liu
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.PACKAGE)
+public @interface Policy {
+
+    /**
+     * Whether this policy applies recursively to all subpackages.
+     */
+    boolean recursive() default true;
+
+    /**
+     * Gets the names of external classes and packages to include.
+     */
+    String[] includes() default {};
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/RegistryClassLoader.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/RegistryClassLoader.java
new file mode 100755
index 0000000..c73bbb1
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/RegistryClassLoader.java
@@ -0,0 +1,575 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.metaclass;
+
+import static shared.util.Control.NullRunnable;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.SecureClassLoader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import shared.util.Control;
+import shared.util.Finalizable;
+
+/**
+ * A subclass of {@link SecureClassLoader} that derives classes and resource {@link URL}s from a registry delegation
+ * chain.
+ * 
+ * @apiviz.composedOf shared.metaclass.RegistryClassLoader.PrefixNode
+ * @apiviz.owns shared.metaclass.JarRegistry
+ * @apiviz.owns shared.metaclass.FileSystemRegistry
+ * @apiviz.has shared.metaclass.Policy - - - argument
+ * @apiviz.uses shared.metaclass.Library
+ * @author Roy Liu
+ */
+public class RegistryClassLoader extends SecureClassLoader implements ResourceRegistry,
+        Finalizable<RegistryClassLoader> {
+
+    final Set<ResourceRegistry> delegates;
+    final Set<String> classNames;
+    final PrefixNode root;
+    final Class<? extends Annotation> policyClass;
+    final Method recursiveMethod, includesMethod, loadMethod, loadLibraryMethod;
+
+    volatile Runnable finalizer;
+
+    /**
+     * Default constructor.
+     */
+    public RegistryClassLoader() {
+        this(Thread.currentThread().getContextClassLoader());
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    @SuppressWarnings("unchecked")
+    public RegistryClassLoader(ClassLoader parent) {
+        super(parent);
+
+        this.classNames = new HashSet<String>();
+        this.root = new PrefixNode();
+
+        this.delegates = new LinkedHashSet<ResourceRegistry>();
+        this.finalizer = NullRunnable;
+
+        try {
+
+            this.policyClass = (Class<? extends Annotation>) loadClass("shared.metaclass.Policy", true);
+            this.recursiveMethod = this.policyClass.getDeclaredMethod("recursive");
+            this.includesMethod = this.policyClass.getDeclaredMethod("includes");
+
+            // Force loading of shared.metaclass.Library by this class loader to effectively make native
+            // libraries exclusive to it and not the parent class loader.
+            Class<?> clazz = findClass("shared.metaclass.Library");
+            this.loadMethod = clazz.getDeclaredMethod("load", File.class);
+            this.loadLibraryMethod = clazz.getDeclaredMethod("loadLibrary", String.class);
+
+        } catch (Exception e) {
+
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Attempts to derive a class first from this class loader's parent, and then from its {@link #findClass(String)}
+     * method.
+     * 
+     * @throws ClassNotFoundException
+     *             when the class could not be found.
+     */
+    @Override
+    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
+
+        Class<?> clazz = findLoadedClass(className);
+
+        if (clazz != null) {
+            return clazz;
+        }
+
+        final String[] prefixes;
+
+        if (className.contains(".")) {
+
+            String[] split = className.split("\\.", -1);
+            prefixes = Arrays.copyOf(split, split.length - 1);
+
+        } else {
+
+            prefixes = new String[] {};
+        }
+
+        // Check for truncated class name membership to deal with inner classes.
+        int index = className.indexOf("$");
+        String truncatedClassName = (index >= 0) ? className.substring(0, index) : className;
+
+        if (!this.root.containsPrefixes(prefixes, 0, false) && !this.classNames.contains(truncatedClassName)) {
+
+            return super.loadClass(className, resolve);
+
+        } else {
+
+            clazz = findClass(className);
+        }
+
+        if (resolve) {
+            resolveClass(clazz);
+        }
+
+        return clazz;
+    }
+
+    /**
+     * Attempts to derive a class from the registry delegation chain.
+     * 
+     * @throws ClassNotFoundException
+     *             when the class could not be found.
+     */
+    @Override
+    protected Class<?> findClass(String className) throws ClassNotFoundException {
+
+        byte[] classData = getClassBytes(className);
+
+        if (classData == null) {
+            throw new ClassNotFoundException(String.format("Class '%s' not found", className));
+        }
+
+        return defineClass(className, //
+                ByteBuffer.wrap(classData), //
+                RegistryClassLoader.class.getProtectionDomain());
+    }
+
+    @Override
+    public URL getResource(String pathname) {
+
+        ClassLoader parent = getParent();
+        URL url = (parent != null) ? parent.getResource(pathname) //
+                : getSystemResource(pathname);
+
+        if (url != null) {
+            return url;
+        }
+
+        for (ResourceRegistry delegate : this.delegates) {
+
+            url = delegate.getResource(pathname);
+
+            if (url != null) {
+                return url;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public Enumeration<URL> getResources(String pathname) throws IOException {
+
+        ClassLoader parent = getParent();
+        List<URL> urls = Collections.list((parent != null) ? parent.getResources(pathname) //
+                : getSystemResources(pathname));
+
+        for (ResourceRegistry delegate : this.delegates) {
+            urls.addAll(Collections.list(delegate.getResources(pathname)));
+        }
+
+        return Collections.enumeration(urls);
+    }
+
+    @Override
+    public InputStream getResourceAsStream(String pathname) {
+
+        ClassLoader parent = getParent();
+        InputStream in = (parent != null) ? parent.getResourceAsStream(pathname) //
+                : getSystemResourceAsStream(pathname);
+
+        if (in != null) {
+            return in;
+        }
+
+        for (ResourceRegistry delegate : this.delegates) {
+
+            in = delegate.getResourceAsStream(pathname);
+
+            if (in != null) {
+                return in;
+            }
+        }
+
+        return null;
+    }
+
+    public RegistryClassLoader setFinalizer(Runnable finalizer) {
+
+        Control.checkTrue(finalizer != null, //
+                "Finalizer must be non-null");
+
+        this.finalizer = finalizer;
+
+        return this;
+    }
+
+    /**
+     * Adds a registry to the delegation chain.
+     */
+    public RegistryClassLoader addRegistry(ResourceRegistry registry) {
+
+        this.delegates.add(registry);
+
+        return this;
+    }
+
+    /**
+     * Adds a class which requires, for linking purposes, resources exclusive to this class loader.
+     */
+    public RegistryClassLoader addClass(String className) {
+
+        Class<?> clazz = findLoadedClass(className);
+
+        try {
+
+            if (clazz == null) {
+                clazz = findClass(className);
+            }
+
+        } catch (ClassNotFoundException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        this.classNames.add(className);
+
+        return this;
+    }
+
+    /**
+     * Adds a package whose classes require, for linking purposes, resources exclusive to this class loader.
+     */
+    public RegistryClassLoader addPackage(String packageName) {
+
+        Control.checkTrue(packageName != null && !packageName.equals(""), //
+                "Invalid package name");
+
+        String className = packageName.concat(".package-info");
+        String[] prefixes = packageName.split("\\.", -1);
+
+        Class<?> clazz = findLoadedClass(className);
+
+        try {
+
+            if (clazz == null) {
+                clazz = findClass(className);
+            }
+
+        } catch (ClassNotFoundException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        Annotation policy = clazz.getAnnotation(this.policyClass);
+
+        Control.checkTrue(policy != null, //
+                "Package is not annotated with a class loading policy");
+
+        final String[] includes;
+
+        try {
+
+            includes = (String[]) this.includesMethod.invoke(policy);
+
+        } catch (Exception e) {
+
+            throw new RuntimeException(e);
+        }
+
+        for (String include : includes) {
+
+            String[] split = include.split("#", -1);
+
+            switch (split.length) {
+
+            case 1:
+                addPackage(split[0]);
+                break;
+
+            case 2:
+                addClass(!split[0].equals("") ? String.format("%s.%s", split[0], split[1]) : split[1]);
+                break;
+
+            default:
+                throw new IllegalArgumentException("Invalid include syntax");
+            }
+        }
+
+        this.root.addPrefixes(prefixes, 0, policy);
+
+        return this;
+    }
+
+    /**
+     * Loads a native library from the given file.
+     */
+    public RegistryClassLoader load(File libFile) {
+
+        try {
+
+            this.loadMethod.invoke(null, libFile);
+
+        } catch (Exception e) {
+
+            throw new RuntimeException(e);
+        }
+
+        return this;
+    }
+
+    /**
+     * Loads a native library from dynamic linker resolution of the given name.
+     */
+    public RegistryClassLoader loadLibrary(String libName) {
+
+        try {
+
+            this.loadLibraryMethod.invoke(null, libName);
+
+        } catch (Exception e) {
+
+            throw new RuntimeException(e);
+        }
+
+        return this;
+    }
+
+    /**
+     * Creates a human-readable representation of this class loader.
+     */
+    @Override
+    public String toString() {
+
+        Formatter f = new Formatter();
+
+        f.format("%s(%s)%n%n", //
+                RegistryClassLoader.class.getName(), getParent());
+
+        for (ResourceRegistry delegate : this.delegates) {
+            f.format("%s%n", delegate.toString());
+        }
+
+        f.format("%n%s", this.root.toString());
+
+        return f.toString();
+    }
+
+    /**
+     * Gets bytecodes associated with the given class name.
+     */
+    protected byte[] getClassBytes(String className) {
+
+        String pathname = className.replace(".", "/").concat(".class");
+        ClassLoader parent = getParent();
+
+        byte[] classBytes = getBytes((parent != null) ? parent.getResourceAsStream(pathname) //
+                : getSystemResourceAsStream(pathname));
+
+        if (classBytes != null) {
+            return classBytes;
+        }
+
+        for (ResourceRegistry delegate : this.delegates) {
+
+            classBytes = getBytes(delegate.getResourceAsStream(pathname));
+
+            if (classBytes != null) {
+                return classBytes;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets a {@code byte} array from the given {@link InputStream}.
+     */
+    final protected static byte[] getBytes(InputStream in) {
+
+        if (in == null) {
+            return null;
+        }
+
+        final byte[] classBytes;
+
+        try {
+
+            classBytes = Control.getBytes(in);
+
+        } catch (IOException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        return (classBytes != null && classBytes.length > 0) ? classBytes : null;
+    }
+
+    /**
+     * A node class for policy hierarchy lookups.
+     */
+    protected class PrefixNode {
+
+        final Map<String, PrefixNode> prefixMap;
+
+        Annotation policy;
+
+        /**
+         * Default constructor.
+         */
+        protected PrefixNode() {
+
+            this.prefixMap = new HashMap<String, PrefixNode>();
+            this.policy = null;
+        }
+
+        /**
+         * Adds the given series of prefixes to the policy hierarchy.
+         */
+        protected void addPrefixes(String[] prefixes, int index, Annotation policy) {
+
+            if (index < prefixes.length) {
+
+                String currentPrefix = prefixes[index];
+
+                for (Entry<String, PrefixNode> entry : this.prefixMap.entrySet()) {
+
+                    String prefix = entry.getKey();
+                    PrefixNode node = entry.getValue();
+
+                    if (currentPrefix.equals(prefix)) {
+
+                        node.addPrefixes(prefixes, index + 1, policy);
+
+                        return;
+                    }
+                }
+
+                PrefixNode node = new PrefixNode();
+                node.addPrefixes(prefixes, index + 1, policy);
+
+                this.prefixMap.put(currentPrefix, node);
+
+            } else {
+
+                this.policy = policy;
+            }
+        }
+
+        /**
+         * Checks if the given series of prefixes is contained in the policy hierarchy.
+         */
+        protected boolean containsPrefixes(String[] prefixes, int index, boolean recursive) {
+
+            if (index < prefixes.length) {
+
+                String currentPrefix = prefixes[index];
+
+                for (Entry<String, PrefixNode> entry : this.prefixMap.entrySet()) {
+
+                    String prefix = entry.getKey();
+                    PrefixNode node = entry.getValue();
+
+                    if (currentPrefix.equals(prefix)) {
+
+                        if (node.policy != null) {
+
+                            try {
+
+                                recursive = (Boolean) RegistryClassLoader.this.recursiveMethod //
+                                        .invoke(node.policy);
+
+                            } catch (Exception e) {
+
+                                throw new RuntimeException(e);
+                            }
+                        }
+
+                        return node.containsPrefixes(prefixes, index + 1, recursive);
+                    }
+                }
+
+                return recursive;
+
+            } else {
+
+                // Accept if the prefix search terminates at a policy node.
+                return (this.policy != null) || recursive;
+            }
+        }
+
+        /**
+         * Delegates to {@link PrefixNode#format(Formatter, String)}.
+         */
+        @Override
+        public String toString() {
+
+            Formatter f = new Formatter();
+            format(f, "");
+
+            return f.toString();
+        }
+
+        /**
+         * Gets a string representation of this node's descendants.
+         */
+        protected void format(Formatter f, String indent) {
+
+            for (Entry<String, PrefixNode> entry : this.prefixMap.entrySet()) {
+
+                String prefix = entry.getKey();
+                PrefixNode node = entry.getValue();
+
+                f.format("%s%s%s%n", indent, prefix, //
+                        (node.policy != null) ? ":".concat(node.policy.toString()) : "");
+
+                node.format(f, indent.concat("\t"));
+            }
+        }
+    }
+
+    // A finalizer guardian for the class loader.
+    final Object reaper = new Object() {
+
+        @Override
+        protected void finalize() {
+            RegistryClassLoader.this.finalizer.run();
+        }
+    };
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/ResourceRegistry.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/ResourceRegistry.java
new file mode 100755
index 0000000..d1fdd4e
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/ResourceRegistry.java
@@ -0,0 +1,60 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.metaclass;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+
+/**
+ * Defines a registry for looking up class path resources.
+ * 
+ * @author Roy Liu
+ */
+public interface ResourceRegistry {
+
+    /**
+     * Gets a resource {@link URL} corresponding to the given pathname.
+     * 
+     * @param pathname
+     *            the resource pathname.
+     * @return a resource {@link URL} or {@code null} if not found.
+     */
+    public URL getResource(String pathname);
+
+    /**
+     * Gets all resource {@link URL}s corresponding to the given pathname.
+     * 
+     * @param pathname
+     *            the resource pathname.
+     * @return an {@link Enumeration} of resource {@link URL}s.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    public Enumeration<URL> getResources(String pathname) throws IOException;
+
+    /**
+     * Gets an {@link InputStream} to the resource at the given pathname.
+     * 
+     * @param pathname
+     *            the resource pathname.
+     * @return an {@link InputStream} to the resource or {@code null} if not found.
+     */
+    public InputStream getResourceAsStream(String pathname);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/package-info.java
new file mode 100755
index 0000000..3fb1f76
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/metaclass/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of metaclass utilities.
+ */
+package shared.metaclass;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/package-info.java
new file mode 100755
index 0000000..ff680b9
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package denoting the SST hierarchy root.
+ */
+package shared;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Calculator.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Calculator.java
new file mode 100755
index 0000000..a391588
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Calculator.java
@@ -0,0 +1,46 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+import java.util.List;
+
+/**
+ * Defines an atomic calculation as part of a parallel dataflow graph.
+ * 
+ * @param <I>
+ *            the input type.
+ * @param <O>
+ *            the output type.
+ * @author Roy Liu
+ */
+public interface Calculator<I, O> {
+
+    /**
+     * Performs an atomic calculation.
+     * 
+     * @param inputs
+     *            the {@link List} of inputs.
+     * @return the calculation result.
+     */
+    public O calculate(List<? extends Handle<? extends I>> inputs);
+
+    /**
+     * Gets the label for this {@link Calculator} as it would appear in {@link Engine#toString()}.
+     */
+    public String toString();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Edge.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Edge.java
new file mode 100755
index 0000000..6af1089
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Edge.java
@@ -0,0 +1,48 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+/**
+ * Defines an edge relationship between two nodes.
+ * 
+ * @param <V>
+ *            the node type.
+ * @author Roy Liu
+ */
+public interface Edge<V> {
+
+    /**
+     * Gets the start node.
+     */
+    public V getU();
+
+    /**
+     * Sets the start node.
+     */
+    public void setU(V node);
+
+    /**
+     * Gets the end node.
+     */
+    public V getV();
+
+    /**
+     * Sets the end node.
+     */
+    public void setV(V node);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Engine.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Engine.java
new file mode 100755
index 0000000..58950f2
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Engine.java
@@ -0,0 +1,639 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import shared.util.Control;
+
+/**
+ * An execution engine class for pushing data through the guts of some parallel computation given as a directed, acyclic
+ * graph.
+ * 
+ * @apiviz.composedOf shared.parallel.Engine.ThrowableReferenceHandler
+ * @apiviz.composedOf shared.parallel.Engine.EngineEdge
+ * @apiviz.composedOf shared.parallel.Engine.EngineNode
+ * @apiviz.owns shared.parallel.TraversalPolicy
+ * @param <T>
+ *            the input type.
+ * @author Roy Liu
+ */
+public class Engine<T> {
+
+    final Semaphore guard, notifier;
+    final ThrowableReferenceHandler exceptionRef;
+    final Calculator<? super Object, ? extends T> startCalculator;
+    final Calculator<? super Object, ? extends Object> stopCalculator;
+    final Map<Calculator<?, ?>, EngineNode<?, ?>> nodeMap;
+    final TraversalPolicy<EngineNode<?, ?>, EngineEdge<?>> policy;
+    final ThreadPoolExecutor executor;
+
+    boolean valid;
+
+    T engineInput;
+
+    /**
+     * Alternate constructor. Creates an engine with the number of threads set to {@link Runtime#availableProcessors()}
+     * and {@link LimitedMemoryPolicy} for its {@link TraversalPolicy}.
+     */
+    public Engine() {
+        this(Runtime.getRuntime().availableProcessors());
+    }
+
+    /**
+     * Alternate constructor. Creates an engine with {@link LimitedMemoryPolicy} for its {@link TraversalPolicy}.
+     * 
+     * @param nthreads
+     *            the number of threads.
+     */
+    public Engine(int nthreads) {
+        this(nthreads, new LimitedMemoryPolicy<EngineNode<?, ?>, EngineEdge<?>>());
+    }
+
+    /**
+     * Default constructor.
+     * 
+     * @param nthreads
+     *            the number of threads.
+     * @param policy
+     *            the {@link TraversalPolicy} to apply when ordering nodes.
+     */
+    public Engine(int nthreads, TraversalPolicy<EngineNode<?, ?>, EngineEdge<?>> policy) {
+
+        this.exceptionRef = new ThrowableReferenceHandler();
+        this.executor = Control.createPool(nthreads, nthreads, //
+                new PriorityBlockingQueue<Runnable>(), //
+                this.exceptionRef);
+
+        this.policy = policy;
+
+        this.guard = new Semaphore(1);
+        this.notifier = new Semaphore(0);
+
+        this.nodeMap = new LinkedHashMap<Calculator<?, ?>, EngineNode<?, ?>>();
+
+        // The start calculation that merely propagates the engine's input.
+        this.startCalculator = new Calculator<Object, T>() {
+
+            public T calculate(List<? extends Handle<? extends Object>> inputVector) {
+                return Engine.this.engineInput;
+            }
+
+            @Override
+            public String toString() {
+                return "Start ()";
+            }
+        };
+
+        this.nodeMap.put(this.startCalculator, //
+                new EngineNode<Object, T>(this.startCalculator, false));
+
+        // The token stop calculation that releases the semaphore guard.
+        this.stopCalculator = new Calculator<Object, Object>() {
+
+            public T calculate(List<? extends Handle<? extends Object>> inputVector) {
+                return null;
+            }
+
+            @Override
+            public String toString() {
+                return "Stop ()";
+            }
+        };
+
+        this.nodeMap.put(this.stopCalculator, //
+
+                new EngineNode<Object, Object>(this.stopCalculator, false) {
+
+                    @Override
+                    public void run() {
+
+                        try {
+
+                            super.run();
+
+                        } finally {
+
+                            // Make sure that the notifier semaphore is released no matter
+                            // what.
+                            Engine.this.notifier.release();
+                        }
+                    }
+                });
+
+        this.valid = false;
+        this.engineInput = null;
+    }
+
+    /**
+     * Gets the initial {@link Calculator}, which does nothing aside from repeating input given to it.
+     */
+    public Calculator<? super Object, ? extends T> getInput() {
+        return this.startCalculator;
+    }
+
+    /**
+     * Adds a non-output {@link Calculator} along with its dependencies.
+     * 
+     * @see #add(Calculator, boolean, Collection)
+     */
+    public <I, O> void add( //
+            Calculator<I, O> calc, //
+            Calculator<?, ? extends I>... calcDeps //
+    ) {
+        add(calc, false, Arrays.asList(calcDeps));
+    }
+
+    /**
+     * Adds an output {@link Calculator} along with its dependencies.
+     * 
+     * @see #add(Calculator, boolean, Collection)
+     * @return a {@link Handle} from which potential output can be retrieved.
+     */
+    public <I, O> Handle<O> addOutput( //
+            Calculator<I, O> calc, //
+            Calculator<?, ? extends I>... calcDeps //
+    ) {
+        return add(calc, true, Arrays.asList(calcDeps));
+    }
+
+    /**
+     * Adds a {@link Calculator} along with its dependencies.
+     * 
+     * @param <I>
+     *            the {@link Calculator} input type.
+     * @param <O>
+     *            the {@link Calculator} output type.
+     * @param calc
+     *            the {@link Calculator}.
+     * @param hasOutput
+     *            whether this node has observable output.
+     * @param calcDeps
+     *            the dependencies.
+     * @return a {@link Handle} from which potential output can be retrieved.
+     */
+    @SuppressWarnings("unchecked")
+    public <I, O> Handle<O> add( //
+            Calculator<I, O> calc, boolean hasOutput, //
+            Collection<? extends Calculator<?, ? extends I>> calcDeps //
+    ) {
+
+        EngineNode<I, O> node = new EngineNode<I, O>(calc, hasOutput);
+
+        Control.checkTrue(calcDeps.size() > 0, //
+                "Please specify some dependencies");
+
+        try {
+
+            Control.checkTrue(this.guard.tryAcquire(), //
+                    "Operation in progress");
+
+            // The ordering is no longer valid.
+            invalidate();
+
+            // Check everything before inserts.
+            Control.checkTrue(!this.nodeMap.containsKey(calc), //
+                    "Node already exists");
+
+            for (Calculator<?, ? extends I> calcDep : calcDeps) {
+                Control.checkTrue(this.nodeMap.containsKey(calcDep), //
+                        "Node doesn't exist");
+            }
+
+            this.nodeMap.put(calc, node);
+
+            for (Calculator<?, ? extends I> calcDep : calcDeps) {
+                addEdge((EngineNode<?, ? extends I>) this.nodeMap.get(calcDep), node);
+            }
+
+        } finally {
+
+            this.guard.release();
+        }
+
+        return node.hasOutput ? node : null;
+    }
+
+    /**
+     * Executes with the given input.
+     * 
+     * @param engineInput
+     *            the input.
+     */
+    public void execute(final T engineInput) {
+
+        try {
+
+            Control.checkTrue(this.guard.tryAcquire(), //
+                    "Operation in progress");
+
+            validate();
+
+            // Reset reference counts in preparation for the new computation.
+            for (EngineNode<?, ?> node : this.nodeMap.values()) {
+
+                // Invariant: Both reference counts should have reached zero.
+                Control.assertTrue(node.outRefCount.getAndSet(node.outputs.size()) == 0 //
+                        && node.inRefCount.getAndSet(node.inputs.size()) == 0);
+
+                node.set(null);
+            }
+
+            // The queue size and the number of permits should be zero.
+            Control.assertTrue(this.notifier.availablePermits() == 0 //
+                    && this.executor.getQueue().isEmpty());
+
+            // Prime the priority queue with a single element -- the input calculator.
+            this.engineInput = engineInput;
+            this.executor.execute(this.nodeMap.get(this.startCalculator));
+
+            // Try to acquire a number of permits equal to the number of nodes, thus guaranteeing
+            // termination of the computation upon return.
+            this.notifier.acquireUninterruptibly();
+
+            Throwable t = this.exceptionRef.getAndSet(null);
+
+            // If the calculation internally encountered a problem.
+            if (t != null) {
+                Control.rethrow(t);
+            }
+
+        } finally {
+
+            this.guard.release();
+        }
+    }
+
+    /**
+     * Outputs human-readable directives for <a href="http://www.graphviz.org/">Dot</a> graph generation.
+     */
+    @Override
+    public String toString() {
+
+        try {
+
+            Control.checkTrue(this.guard.tryAcquire(), //
+                    "Operation in progress");
+
+            validate();
+
+            EngineNode<?, ?> root = this.nodeMap.get(this.startCalculator);
+            EngineNode<?, ?> sink = this.nodeMap.get(this.stopCalculator);
+
+            Formatter f = new Formatter();
+
+            f.format("%n/* Begin Node Specification */%n%n");
+            f.format("\"%s (%d)\" [shape = diamond, color = green];%n", root, root.order);
+            f.format("\"%s (%d)\" [shape = diamond, color = green];%n", sink, sink.order);
+
+            List<EngineNode<?, ?>> nodes = new ArrayList<EngineNode<?, ?>>(this.nodeMap.values());
+            Collections.sort(nodes);
+
+            for (EngineNode<?, ?> node : nodes) {
+
+                if (node.hasOutput) {
+
+                    f.format("\"%s (%d)\" [shape = octagon, color = red];%n", node, node.order);
+
+                } else if (!node.equals(root) && !node.equals(sink)) {
+
+                    f.format("\"%s (%d)\" [shape = rectangle, color = blue];%n", node, node.order);
+                }
+            }
+
+            f.format("%n/* Begin Edge Specification */%n%n");
+
+            for (EngineNode<?, ?> node : nodes) {
+
+                for (EngineEdge<?> edge : node.outputs) {
+
+                    for (int i = 0, n = node.depth; i < n; i++) {
+                        f.format("\t");
+                    }
+
+                    f.format("\"%s (%d)\" -> \"%s (%d)\"%n", //
+                            edge.getU(), edge.getU().order, //
+                            edge.getV(), edge.getV().order);
+                }
+            }
+
+            return f.toString();
+
+        } finally {
+
+            this.guard.release();
+        }
+    }
+
+    /**
+     * Computes a traversal ordering over the current configuration of {@link EngineNode}s.
+     */
+    @SuppressWarnings("unchecked")
+    protected void validate() {
+
+        if (!this.valid) {
+
+            Collection<EngineNode<?, ?>> nodes = this.nodeMap.values();
+
+            EngineNode<? super Object, ? extends Object> sink = //
+            (EngineNode<? super Object, ? extends Object>) this.nodeMap.get(this.stopCalculator);
+
+            // Unlink the output node. It had better be the case that a child knows about the output node.
+            for (EngineEdge<?> edge : sink.inputs) {
+                Control.assertTrue(edge.getU().outputs.remove(edge));
+            }
+
+            sink.inputs.clear();
+
+            // Attach everything that's a sink to the fake sink.
+            for (EngineNode<?, ?> node : nodes) {
+
+                if (node.outputs.size() == 0 && node != sink) {
+                    addEdge(node, sink);
+                }
+            }
+
+            // Assign priority order according to the traversal policy.
+            Control.assertTrue(this.policy.assign(sink) == nodes.size());
+
+            this.valid = true;
+        }
+    }
+
+    /**
+     * Invalidates the current traversal ordering.
+     */
+    protected void invalidate() {
+        this.valid = false;
+    }
+
+    /**
+     * Links two {@link EngineNode}s by an {@link EngineEdge}.
+     * 
+     * @param <O>
+     *            the output-input type.
+     */
+    protected <O> void addEdge(EngineNode<?, ? extends O> u, EngineNode<? super O, ?> v) {
+
+        EngineEdge<O> e = new EngineEdge<O>(u, v);
+
+        u.outputs.add(e);
+        v.inputs.add(e);
+    }
+
+    /**
+     * A computation node that is part of some topology of nodes.
+     * 
+     * @apiviz.owns shared.parallel.Calculator
+     * @param <I>
+     *            the input type.
+     * @param <O>
+     *            the output type.
+     */
+    protected class EngineNode<I, O> implements Handle<O>, Runnable, Traversable<EngineNode<?, ?>, EngineEdge<?>> {
+
+        final Calculator<? super I, ? extends O> calculator;
+        final List<EngineEdge<? extends I>> inputs;
+        final List<EngineEdge<? extends I>> inputsReadOnly;
+        final List<EngineEdge<? super O>> outputs;
+        final List<EngineEdge<? super O>> outputsReadOnly;
+
+        final AtomicInteger outRefCount, inRefCount;
+
+        final boolean hasOutput;
+
+        int order, depth;
+
+        O value;
+
+        /**
+         * Default constructor.
+         */
+        public EngineNode(Calculator<? super I, ? extends O> calculator, boolean hasOutput) {
+
+            this.calculator = calculator;
+            this.hasOutput = hasOutput;
+
+            this.inputs = new ArrayList<EngineEdge<? extends I>>();
+            this.inputsReadOnly = Collections.unmodifiableList(this.inputs);
+            this.outputs = new ArrayList<EngineEdge<? super O>>();
+            this.outputsReadOnly = Collections.unmodifiableList(this.outputs);
+
+            this.outRefCount = new AtomicInteger(0);
+            this.inRefCount = new AtomicInteger(0);
+
+            this.order = (this.depth = -1);
+
+            this.value = null;
+        }
+
+        /**
+         * Compares traversal orders to determine priority of execution.
+         */
+        public int compareTo(EngineNode<?, ?> node) {
+            return this.order - node.order;
+        }
+
+        public O get() {
+            return this.value;
+        }
+
+        public void set(O value) {
+            this.value = value;
+        }
+
+        public int getOrder() {
+            return this.order;
+        }
+
+        public void setOrder(int order) {
+            this.order = order;
+        }
+
+        public int getDepth() {
+            return this.depth;
+        }
+
+        public void setDepth(int depth) {
+            this.depth = depth;
+        }
+
+        public List<EngineEdge<? extends I>> getIn() {
+            return this.inputsReadOnly;
+        }
+
+        public List<EngineEdge<? super O>> getOut() {
+            return this.outputsReadOnly;
+        }
+
+        @Override
+        public String toString() {
+            return this.calculator.toString();
+        }
+
+        /**
+         * Executes the {@link Calculator#calculate(List)} method associated with this node.
+         */
+        public void run() {
+
+            try {
+
+                this.value = this.calculator.calculate(this.inputsReadOnly);
+
+            } catch (Throwable t) {
+
+                Engine.this.exceptionRef.compareAndSet(null, t);
+
+                Control.rethrow(t);
+
+            } finally {
+
+                for (int i = 0, n = this.inputs.size(), val; i < n; i++) {
+
+                    EngineNode<?, ? extends I> node = this.inputs.get(i).getU();
+
+                    // The node has all of its outputs observed; free its value.
+                    if ((val = node.outRefCount.decrementAndGet()) == 0) {
+
+                        if (!node.hasOutput) {
+                            node.set(null);
+                        }
+
+                    } else {
+
+                        Control.assertTrue(val > 0);
+                    }
+                }
+
+                for (int i = 0, n = this.outputs.size(), val; i < n; i++) {
+
+                    EngineNode<? super O, ?> node = this.outputs.get(i).getV();
+
+                    // The node in question has all of its inputs accounted for; insert it according
+                    // to its traversal order.
+                    if ((val = node.inRefCount.decrementAndGet()) == 0) {
+
+                        Engine.this.executor.execute(node);
+
+                    } else {
+
+                        Control.assertTrue(val > 0);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * An output-input relationship between two {@link Engine.EngineNode}s.
+     * 
+     * @param <O>
+     *            the output-input type.
+     */
+    protected class EngineEdge<O> implements Handle<O>, Edge<EngineNode<?, ?>> {
+
+        final EngineNode<?, ? extends O> u;
+        final EngineNode<? super O, ?> v;
+
+        /**
+         * Default constructor.
+         */
+        public EngineEdge(EngineNode<?, ? extends O> u, EngineNode<? super O, ?> v) {
+
+            this.u = u;
+            this.v = v;
+        }
+
+        public EngineNode<?, ? extends O> getU() {
+            return this.u;
+        }
+
+        public EngineNode<? super O, ?> getV() {
+            return this.v;
+        }
+
+        /**
+         * Delegates to the start {@link Engine.EngineNode}'s {@link #get()} method.
+         */
+        public O get() {
+            return this.u.get();
+        }
+
+        public void setU(EngineNode<?, ?> node) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void setV(EngineNode<?, ?> node) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(O output) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * A subclass of {@link AtomicReference} that doubles as an {@link UncaughtExceptionHandler}. It is set whenever an
+     * uncaught {@link Throwable} occurs.
+     */
+    protected static class ThrowableReferenceHandler extends AtomicReference<Throwable> implements
+            UncaughtExceptionHandler {
+
+        /**
+         * The UID for serialization purposes.
+         */
+        final protected static long serialVersionUID = 1L;
+
+        /**
+         * Default constructor.
+         */
+        protected ThrowableReferenceHandler() {
+        }
+
+        /**
+         * Sets this reference.
+         */
+        public void uncaughtException(Thread thread, Throwable throwable) {
+
+            // Set the exception only if one hasn't already occurred.
+            compareAndSet(null, throwable);
+        }
+    }
+
+    // A finalizer guardian for the thread pool.
+    final Object poolReaper = new Object() {
+
+        @Override
+        protected void finalize() {
+            Engine.this.executor.shutdownNow();
+        }
+    };
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Handle.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Handle.java
new file mode 100755
index 0000000..247d1fd
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Handle.java
@@ -0,0 +1,38 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+/**
+ * Defines a container for storing the results of {@link Calculator}s.
+ * 
+ * @param <O>
+ *            the storage type.
+ * @author Roy Liu
+ */
+public interface Handle<O> {
+
+    /**
+     * Gets the output.
+     */
+    public O get();
+
+    /**
+     * Sets the output.
+     */
+    public void set(O output);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/LimitedMemoryPolicy.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/LimitedMemoryPolicy.java
new file mode 100755
index 0000000..501fb20
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/LimitedMemoryPolicy.java
@@ -0,0 +1,158 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import shared.parallel.Engine.EngineNode;
+import shared.util.Control;
+
+/**
+ * An implementation of {@link TraversalPolicy} that attempts to conserve memory usage during parallel execution.
+ * 
+ * @apiviz.composedOf shared.parallel.LimitedMemoryPolicy.PolicyNode
+ * @param <V>
+ *            the node type.
+ * @param <E>
+ *            the edge type.
+ * @author Roy Liu
+ */
+public class LimitedMemoryPolicy<V extends Traversable<V, E>, E extends Edge<V>> implements TraversalPolicy<V, E> {
+
+    /**
+     * Default constructor.
+     */
+    public LimitedMemoryPolicy() {
+    }
+
+    public int assign(V root) {
+        return assignDepthFirst(longestPath( //
+                root, //
+                new LinkedHashMap<Traversable<V, E>, PolicyNode>()), //
+                new LinkedHashSet<PolicyNode>(), //
+                new LinkedHashSet<PolicyNode>(), 0 //
+        );
+    }
+
+    /**
+     * Sorts a {@link PolicyNode}'s children in decreasing order of maximum distance from the source.
+     */
+    final protected PolicyNode longestPath(Traversable<V, E> curr, Map<Traversable<V, E>, PolicyNode> visitedMap) {
+
+        // Visit the current node by adding a map entry.
+        PolicyNode currNode = new PolicyNode(curr);
+
+        visitedMap.put(curr, currNode);
+
+        for (Edge<V> edge : curr.getIn()) {
+
+            V child = edge.getU();
+
+            PolicyNode node = visitedMap.get(child);
+
+            if (node == null) {
+                node = longestPath(child, visitedMap);
+            }
+
+            currNode.maxDistance = Math.max(currNode.maxDistance, node.maxDistance);
+            currNode.children.add(node);
+        }
+
+        // Sort in order of decreasing distance.
+        Collections.sort(currNode.children);
+        Collections.reverse(currNode.children);
+
+        curr.setDepth(currNode.maxDistance++);
+
+        return currNode;
+    }
+
+    /**
+     * A recursive subroutine for assigning traversal orders while traversing the {@link PolicyNode} graph in a
+     * depth-first manner.
+     */
+    final protected int assignDepthFirst(PolicyNode node, //
+            Set<PolicyNode> partiallyVisited, //
+            Set<PolicyNode> completelyVisited, //
+            int dfsCtr) {
+
+        // Partially visit the current node.
+        partiallyVisited.add(node);
+
+        for (PolicyNode child : node.children) {
+
+            Control.checkTrue(!partiallyVisited.contains(child), //
+                    "Dependency cycle detected");
+
+            if (!completelyVisited.contains(child)) {
+                dfsCtr = assignDepthFirst(child, partiallyVisited, completelyVisited, dfsCtr);
+            }
+        }
+
+        // Completely visited the current node.
+        partiallyVisited.remove(node);
+        completelyVisited.add(node);
+
+        node.handle.setOrder(dfsCtr);
+
+        return dfsCtr + 1;
+    }
+
+    /**
+     * An {@link EngineNode} proxy class that aids in the computation of traversal orderings.
+     */
+    protected class PolicyNode implements Comparable<PolicyNode> {
+
+        final Traversable<V, E> handle;
+        final List<PolicyNode> children;
+
+        int maxDistance;
+
+        /**
+         * Default constructor.
+         */
+        protected PolicyNode(Traversable<V, E> handle) {
+
+            this.handle = handle;
+            this.children = new ArrayList<PolicyNode>();
+
+            this.maxDistance = 0;
+        }
+
+        /**
+         * Compares maximum distance from the source.
+         */
+        public int compareTo(PolicyNode rhs) {
+            return this.maxDistance - rhs.maxDistance;
+        }
+
+        /**
+         * Delegates to the {@link Traversable}'s {@link Traversable#toString()} method.
+         */
+        @Override
+        public String toString() {
+            return this.handle.toString();
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Traversable.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Traversable.java
new file mode 100755
index 0000000..77862f4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/Traversable.java
@@ -0,0 +1,68 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+import java.util.List;
+
+/**
+ * Defines a graph node as part of some total ordering on graph nodes.
+ * 
+ * @param <V>
+ *            the node type.
+ * @param <E>
+ *            the edge type.
+ * @author Roy Liu
+ */
+public interface Traversable<V extends Traversable<V, E>, E extends Edge<V>> extends Comparable<V> {
+
+    /**
+     * Gets the order.
+     */
+    public int getOrder();
+
+    /**
+     * Sets the order.
+     */
+    public void setOrder(int order);
+
+    /**
+     * Gets the depth.
+     */
+    public int getDepth();
+
+    /**
+     * Sets the depth.
+     */
+    public void setDepth(int depth);
+
+    /**
+     * Gets the incoming edges.
+     */
+    public List<? extends E> getIn();
+
+    /**
+     * Gets the outgoing edges.
+     */
+    public List<? extends E> getOut();
+
+    /**
+     * Creates a human-readable representation of this node.
+     */
+    @Override
+    public String toString();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/TraversalPolicy.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/TraversalPolicy.java
new file mode 100755
index 0000000..0e57696
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/TraversalPolicy.java
@@ -0,0 +1,42 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.parallel;
+
+/**
+ * Defines a total ordering and depth assignment to a collection of {@link Traversable}s via
+ * {@link Traversable#setOrder(int)} and {@link Traversable#setDepth(int)}. The modifications serve as a hint to
+ * {@link Engine} and do not affect the correctness of the calculation.
+ * 
+ * @apiviz.owns shared.parallel.Traversable
+ * @param <V>
+ *            the node type.
+ * @param <E>
+ *            the edge type.
+ * @author Roy Liu
+ */
+public interface TraversalPolicy<V extends Traversable<V, E>, E extends Edge<V>> {
+
+    /**
+     * Makes a total ordering and depth assignment to all nodes reachable from the given node.
+     * 
+     * @param root
+     *            the given node.
+     * @return the number of nodes visited.
+     */
+    public int assign(V root);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/parallel/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/package-info.java
new file mode 100755
index 0000000..0235f6b
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/parallel/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A framework for specifying and executing parallel dataflow engines.
+ */
+package shared.parallel;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/project.properties b/contrib/applications/nxplot/sharedscientific/src/shared/project.properties
new file mode 100755
index 0000000..29ceaa4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/project.properties
@@ -0,0 +1,3 @@
+### Properties with values specific to the SST. ###
+
+build.version   = 1.10
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/AbstractGMModel.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/AbstractGMModel.java
new file mode 100755
index 0000000..a1f76ae
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/AbstractGMModel.java
@@ -0,0 +1,138 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.ml;
+
+import shared.array.RealArray;
+
+/**
+ * An abstract base class for Gaussian mixture models characterized by their initialization and update rules.
+ * 
+ * @apiviz.owns shared.stat.ml.GMComponents
+ * @author Roy Liu
+ */
+abstract public class AbstractGMModel {
+
+    /**
+     * Default constructor.
+     */
+    protected AbstractGMModel() {
+    }
+
+    /**
+     * Trains the model.
+     * 
+     * @param points
+     *            the input.
+     * @param ncomps
+     *            the number of components.
+     * @param regularization
+     *            the regularization hint.
+     * @param delta
+     *            the change in likelihood required for termination.
+     * @return the mixture components trained.
+     */
+    public GMComponents train(final RealArray points, int ncomps, double regularization, double delta) {
+
+        // Convert to a list of points.
+        GMComponents gmc = initialize(points, ncomps, regularization);
+
+        int nrounds = 0;
+
+        for (double currentLL = -Double.MAX_VALUE / 4.0, previousLL = 2.0 * currentLL; //
+        currentLL - previousLL > delta;) {
+
+            previousLL = currentLL;
+            update(gmc, computePosterior(gmc, points), points, regularization);
+            currentLL = gmc.likelihood;
+
+            nrounds++;
+
+            gmc.nrounds = nrounds;
+        }
+
+        return gmc;
+    }
+
+    /**
+     * Computes the posterior distribution and updates the mean likelihood of the points.
+     * 
+     * @param gmc
+     *            the mixture components.
+     * @param points
+     *            the input.
+     * @return the posterior distribution <tt>p(components | points)</tt>.
+     */
+    public RealArray computePosterior(GMComponents gmc, RealArray points) {
+
+        int ncomps = gmc.weights.size(0);
+
+        // The log of the weighted densities has dimensions (ncomps, npoints).
+        RealArray logWeightedDensities = computeLogWeightedDensities(gmc, points);
+        RealArray rowMax = logWeightedDensities.rMax(0);
+
+        // Compute the normalized posterior for numerical stability.
+        RealArray posterior = logWeightedDensities.eSub(rowMax.tile(ncomps, 1)).uExp();
+        RealArray rowSum = posterior.rSum(0);
+
+        // Normalize the posterior.
+        posterior = posterior.lDiv(rowSum.tile(ncomps, 1));
+
+        // Calculate the total log-likelihood.
+        gmc.likelihood = (rowSum.clone().uAdd(1e-64).uLog()).lAdd(rowMax).aMean();
+
+        return posterior;
+    }
+
+    /**
+     * Performs the update rule.
+     * 
+     * @param gmc
+     *            the mixture components.
+     * @param posterior
+     *            the posterior distribution <tt>p(components | points)</tt>.
+     * @param points
+     *            the input.
+     * @param regularization
+     *            the regularization hint.
+     */
+    abstract protected void update(GMComponents gmc, RealArray posterior, RealArray points, double regularization);
+
+    /**
+     * Initializes the mixture components.
+     * 
+     * @param points
+     *            the input.
+     * @param ncomps
+     *            the number of components.
+     * @param regularization
+     *            the regularization hint.
+     * @return the initial mixture components.
+     */
+    abstract protected GMComponents initialize(RealArray points, int ncomps, double regularization);
+
+    /**
+     * Computes the log of the weighted densities.
+     * 
+     * @param gmc
+     *            the mixture components.
+     * @param points
+     *            the input.
+     * @return the log of <tt>p(points | components)</tt>.
+     */
+    abstract protected RealArray computeLogWeightedDensities(GMComponents gmc, RealArray points);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/GMComponents.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/GMComponents.java
new file mode 100755
index 0000000..0d4b5d0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/GMComponents.java
@@ -0,0 +1,104 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.ml;
+
+import shared.array.RealArray;
+
+/**
+ * A data structure containing information on Gaussian mixture components.
+ * 
+ * @author Roy Liu
+ */
+public class GMComponents {
+
+    /**
+     * The weights.
+     */
+    final public RealArray weights;
+
+    /**
+     * The centers.
+     */
+    final public RealArray centers;
+
+    /**
+     * The (diagonal) covariances.
+     */
+    final public RealArray covariances;
+
+    /**
+     * The likelihood. Updates every time one obtains a new likelihood from the <tt>M</tt> step.
+     */
+    public double likelihood;
+
+    /**
+     * The number of rounds so far.
+     */
+    public int nrounds;
+
+    /**
+     * Default constructor.
+     * 
+     * @param ncomponents
+     *            the number of components.
+     * @param ndims
+     *            the dimensionality expected of the data.
+     */
+    public GMComponents(int ncomponents, int ndims) {
+
+        this.weights = new RealArray(ncomponents, 1);
+        this.centers = new RealArray(ncomponents, ndims);
+        this.covariances = new RealArray(ncomponents, ndims);
+
+        this.likelihood = Double.NaN;
+        this.nrounds = -1;
+    }
+
+    /**
+     * Regularizes the covariances by setting a floor on what they can be.
+     * 
+     * @param regularization
+     *            the regularization hint.
+     */
+    public void regularize(double regularization) {
+
+        double[] values = this.covariances.values();
+
+        // Apply regularization.
+        for (int i = 0, n = values.length; i < n; i++) {
+            values[i] = Math.max(values[i], regularization);
+        }
+    }
+
+    /**
+     * Creates a human-readable representation of the mixture components.
+     */
+    @Override
+    public String toString() {
+        return String.format("%n" //
+                + "centers =%n" //
+                + "%s%n" //
+                + "sqrt(covariances) =%n" //
+                + "%s%n" //
+                + "weights =%n" //
+                + "%s%n" //
+                + "likelihood = %4.4e%n%n" //
+                + "nrounds = %d%n", //
+                this.centers, this.covariances.clone().uSqrt(), this.weights, this.likelihood, this.nrounds);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/GMModel.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/GMModel.java
new file mode 100755
index 0000000..985bbc9
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/GMModel.java
@@ -0,0 +1,121 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.ml;
+
+import java.util.List;
+
+import shared.array.RealArray;
+import shared.util.Control;
+
+/**
+ * An implementation of {@link AbstractGMModel} using EM updates on GMM's with diagonal covariances. Inspired by <a
+ * href="http://www.cs.ucsd.edu/~saul/">Lawrence Saul</a>'s EM code.
+ * 
+ * @apiviz.uses shared.stat.ml.KMeans
+ * @author Roy Liu
+ */
+public class GMModel extends AbstractGMModel {
+
+    /**
+     * Default constructor.
+     */
+    public GMModel() {
+    }
+
+    @Override
+    public GMComponents initialize(RealArray input, int ncomps, double regularization) {
+
+        int ndims = input.size(1);
+
+        GMComponents gmc = new GMComponents(ncomps, ndims);
+
+        List<RealArray> clusters = KMeans.cluster(ncomps, input);
+
+        // Assign the covariances to be the global covariance.
+        RealArray globalSum = input.rSum(0);
+        RealArray globalMean = input.rMean(0);
+
+        (globalSum.clone().uSqr().uMul(1.0 / input.size(0))) //
+                .lSub(globalMean.eMul(globalMean)).uAdd(regularization) //
+                .tile(ncomps, 1) //
+                .map(gmc.covariances, 0, 0, ncomps, 0, 0, ndims);
+
+        // Assign the means to be the cluster means.
+        for (int i = 0; i < ncomps; i++) {
+            clusters.get(i).rMean(0).map(gmc.centers, 0, i, 1, 0, 0, ndims);
+        }
+
+        // Every component starts out as equally likely.
+        gmc.weights.uFill(1.0 / ncomps);
+
+        return gmc;
+    }
+
+    @Override
+    public void update(GMComponents gmc, RealArray posterior, RealArray points, double regularization) {
+
+        int ncomps = gmc.weights.size(0);
+        int ndims = points.size(1);
+        int npoints = Control.checkEquals(points.size(0), posterior.size(1));
+
+        RealArray colSum = posterior.rSum(1);
+
+        // The normalization has dimensions (ncomps, ndims).
+        RealArray nrmp = colSum.tile(1, ndims).uAdd(1e-64);
+
+        // Update the means.
+
+        posterior.mMul(points).lDiv(nrmp) //
+                .map(gmc.centers, 0, 0, ncomps, 0, 0, ndims);
+
+        // Update the covariances.
+
+        posterior.mMul(points.clone().uSqr()).lDiv(nrmp) //
+                .lSub(gmc.centers.clone().uSqr()) //
+                .map(gmc.covariances, 0, 0, ncomps, 0, 0, ndims);
+
+        gmc.regularize(regularization);
+
+        // Update the weights.
+
+        colSum.map(gmc.weights, 0, 0, ncomps, 0, 0, 1).uMul(1.0 / npoints);
+    }
+
+    @Override
+    public RealArray computeLogWeightedDensities(GMComponents gmc, RealArray points) {
+
+        int npoints = points.size(0);
+
+        RealArray iCov = gmc.covariances.clone().uInv(1.0);
+
+        RealArray nrmTiled = //
+        (gmc.centers.clone().uSqr().lMul(iCov)) //
+                .lAdd(gmc.covariances.clone().uLog()) //
+                .rSum(1).tile(1, npoints);
+
+        RealArray pointsT = points.transpose(1, 0);
+
+        RealArray logWeightsTiled = gmc.weights.tile(1, npoints).uAdd(1e-64).uLog();
+
+        RealArray exponent = (iCov.mMul(pointsT.clone().uSqr())) //
+                .lAdd(gmc.centers.eMul(iCov).mMul(pointsT).uMul(-2.0)) //
+                .lAdd(nrmTiled).uMul(-0.5);
+
+        return exponent.lAdd(logWeightsTiled);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/KMeans.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/KMeans.java
new file mode 100755
index 0000000..dedaadd
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/KMeans.java
@@ -0,0 +1,197 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.ml;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import shared.array.RealArray;
+import shared.util.Arithmetic;
+import shared.util.Control;
+
+/**
+ * A class for K-Means clustering with subset furthest first initialization.
+ * 
+ * @author Roy Liu
+ */
+public class KMeans {
+
+    /**
+     * Computes point-to-point distances.
+     * 
+     * @param aPts
+     *            the origin points.
+     * @param bPts
+     *            the destination points.
+     * @return a {@link RealArray} of distances.
+     */
+    final public static RealArray distances(RealArray aPts, RealArray bPts) {
+
+        int ndims = Control.checkEquals(aPts.size(1), bPts.size(1));
+        int naPts = aPts.size(0), nbPts = bPts.size(0);
+
+        RealArray acc = new RealArray(naPts, nbPts);
+
+        for (int dim = 0; dim < ndims; dim++) {
+            acc = acc.lAdd(aPts.subarray(0, aPts.size(0), dim, dim + 1).tile(1, nbPts) //
+                    .lSub(bPts.subarray(0, bPts.size(0), dim, dim + 1) //
+                            .transpose(1, 0).tile(naPts, 1)).uSqr());
+        }
+
+        return acc.uSqrt();
+    }
+
+    /**
+     * Groups a set of points into the given number of clusters.
+     * 
+     * @param nclusters
+     *            the number of clusters.
+     * @param points
+     *            the input.
+     * @return a {@link List} of clusters.
+     */
+    final public static List<RealArray> cluster(int nclusters, RealArray points) {
+
+        int npoints = points.size(0);
+        int ndims = points.size(1);
+
+        Control.checkTrue(npoints >= nclusters);
+
+        // Subset furthest first initialization of centers.
+        RealArray centers = subsetFurthestFirst(nclusters, points);
+
+        int[] memberships = shared.util.Arrays.newArray(npoints, -1), newMemberships;
+
+        for (;;) {
+
+            newMemberships = distances(centers, points).iMin(0).subarray(0, 1, 0, points.size(0)).values();
+
+            int ncenters = centers.size(0);
+
+            // Create the clusters.
+
+            int[] counts = new int[ncenters];
+
+            for (int i = 0; i < npoints; i++) {
+                counts[newMemberships[i]]++;
+            }
+
+            RealArray[] clusters = new RealArray[ncenters];
+
+            for (int i = 0; i < ncenters; i++) {
+                clusters[i] = new RealArray(counts[i], ndims);
+            }
+
+            // Build clusters and increment counts.
+            counts = new int[ncenters];
+
+            for (int i = 0; i < npoints; i++) {
+
+                points.map(clusters[newMemberships[i]], //
+                        i, counts[newMemberships[i]], 1, //
+                        0, 0, ndims);
+
+                counts[newMemberships[i]]++;
+            }
+
+            // Compute new centers.
+
+            int nnonzero = 0;
+
+            for (int i = 0; i < ncenters; i++) {
+
+                if (clusters[i].size(0) > 0) {
+
+                    clusters[i].rMean(0).map(centers, //
+                            0, nnonzero, 1, //
+                            0, 0, ndims);
+
+                    nnonzero++;
+                }
+            }
+
+            // This should happen VERY rarely.
+            for (int i = nnonzero; i < ncenters; i++) {
+                centers.subarray(0, i, 0, centers.size(1)).rMean(0).map(centers, //
+                        0, i, 1, //
+                        0, 0, ndims);
+            }
+
+            // Check for convergence and return if necessary.
+
+            if (Arrays.equals(newMemberships, memberships)) {
+
+                return Arrays.asList(clusters);
+
+            } else {
+
+                memberships = newMemberships;
+            }
+        }
+    }
+
+    /**
+     * Performs subset furthest first initialization.
+     * 
+     * @param ncenters
+     *            the number of centers.
+     * @param points
+     *            the collection of points.
+     * @return a collection of centers.
+     */
+    final protected static RealArray subsetFurthestFirst(int ncenters, RealArray points) {
+
+        int ndims = points.size(1);
+        int nsamples = Math.min(points.size(0), 2 * ncenters * (int) (Math.log(ncenters + 1) + 1));
+
+        // Make the permutation predictable and sample from a subset.
+        int[] perm = Arithmetic.range(points.size(0));
+        Collections.shuffle(Arrays.asList(perm), new Random(Arrays.hashCode(points.values())));
+
+        RealArray samples = new RealArray(nsamples, ndims);
+
+        for (int i = 0; i < nsamples; i++) {
+            points.map(samples, //
+                    perm[i], i, 1, //
+                    0, 0, ndims);
+        }
+
+        //
+
+        RealArray res = samples.map(new RealArray(ncenters, ndims), //
+                0, 0, 1, //
+                0, 0, ndims);
+
+        for (int i = 1; i < ncenters; i++) {
+
+            RealArray d = distances(res.subarray(0, i, 0, res.size(1)), samples);
+
+            samples.map(res, //
+                    d.rMin(0).iMax(1).get(0, 0), i, 1, //
+                    0, 0, ndims);
+        }
+
+        return res;
+    }
+
+    // Dummy constructor.
+    KMeans() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/package-info.java
new file mode 100755
index 0000000..58be9c3
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/ml/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of machine learning algorithms.
+ */
+package shared.stat.ml;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/package-info.java
new file mode 100755
index 0000000..229147f
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of statistical tools for scientists and machine learners.
+ */
+package shared.stat;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/DataStyle.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/DataStyle.java
new file mode 100755
index 0000000..e20c672
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/DataStyle.java
@@ -0,0 +1,215 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.event.EnumType;
+import shared.util.Control;
+
+/**
+ * A container class for dataset rendering style information.
+ * 
+ * @apiviz.owns shared.stat.plot.DataStyle.DataStyleType
+ * @author Roy Liu
+ */
+public class DataStyle implements EnumType<DataStyle.DataStyleType> {
+
+    /**
+     * An enumeration of {@link DataStyle} types.
+     */
+    public enum DataStyleType {
+
+        /**
+         * Indicates lines.
+         */
+        LINES, //
+
+        /**
+         * Indicates points.
+         */
+        POINTS, //
+
+        /**
+         * Indicates lines and points.
+         */
+        LINESPOINTS, //
+
+        /**
+         * Indicates bars.
+         */
+        BARS, //
+
+        /**
+         * Indicates that the data induces a surface.
+         */
+        SURFACE;
+    };
+
+    /**
+     * The default style for {@link DataStyleType#LINES}.
+     */
+    final public static DataStyle Lines = new DataStyle(DataStyleType.LINES);
+
+    /**
+     * The default style for {@link DataStyleType#POINTS}.
+     */
+    final public static DataStyle Points = new DataStyle(DataStyleType.POINTS);
+
+    /**
+     * The default style for {@link DataStyleType#LINESPOINTS}.
+     */
+    final public static DataStyle LinesPoints = new DataStyle(DataStyleType.LINESPOINTS);
+
+    /**
+     * The default style for {@link DataStyleType#BARS}.
+     */
+    final public static DataStyle Bars = new DataStyle(DataStyleType.BARS);
+
+    /**
+     * The default style for {@link DataStyleType#SURFACE}.
+     */
+    final public static DataStyle Surface = new DataStyle(DataStyleType.SURFACE);
+
+    final DataStyleType type;
+
+    String lineStyle;
+    String lineColor;
+
+    Double lineSize;
+
+    String pointStyle;
+    String pointColor;
+
+    Double pointSize;
+
+    /**
+     * Default constructor.
+     */
+    public DataStyle(DataStyleType type) {
+
+        this.type = type;
+
+        Control.checkTrue(type != null, //
+                "Invalid arguments");
+    }
+
+    public DataStyleType getType() {
+        return this.type;
+    }
+
+    /**
+     * Gets the line style.
+     */
+    public String getLineStyle() {
+        return this.lineStyle;
+    }
+
+    /**
+     * Sets the line style.
+     */
+    public DataStyle setLineStyle(String lineStyle) {
+
+        this.lineStyle = lineStyle;
+
+        return this;
+    }
+
+    /**
+     * Gets the line color.
+     */
+    public String getLineColor() {
+        return this.lineColor;
+    }
+
+    /**
+     * Sets the line color.
+     */
+    public DataStyle setLineColor(String lineColor) {
+
+        this.lineColor = lineColor;
+
+        return this;
+    }
+
+    /**
+     * Gets the line size.
+     */
+    public Double getLineSize() {
+        return this.lineSize;
+    }
+
+    /**
+     * Sets the line size.
+     */
+    public DataStyle setLineSize(Double lineSize) {
+
+        this.lineSize = lineSize;
+
+        return this;
+    }
+
+    /**
+     * Gets the point style.
+     */
+    public String getPointStyle() {
+        return this.pointStyle;
+    }
+
+    /**
+     * Sets the point style.
+     */
+    public DataStyle setPointStyle(String pointStyle) {
+
+        this.pointStyle = pointStyle;
+
+        return this;
+    }
+
+    /**
+     * Gets the point color.
+     */
+    public String getPointColor() {
+        return this.pointColor;
+    }
+
+    /**
+     * Sets the point color.
+     */
+    public DataStyle setPointColor(String pointColor) {
+
+        this.pointColor = pointColor;
+
+        return this;
+    }
+
+    /**
+     * Gets the point size.
+     */
+    public Double getPointSize() {
+        return this.pointSize;
+    }
+
+    /**
+     * Sets the point size.
+     */
+    public DataStyle setPointSize(Double pointSize) {
+
+        this.pointSize = pointSize;
+
+        return this;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ErrorDistribution.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ErrorDistribution.java
new file mode 100755
index 0000000..db448fd
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ErrorDistribution.java
@@ -0,0 +1,183 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+import shared.stat.plot.Plot.AxisType;
+import shared.util.Arrays;
+import shared.util.Control;
+
+/**
+ * A base class for {@link PrecisionRecall} and {@link ROC}.
+ * 
+ * @author Roy Liu
+ */
+abstract public class ErrorDistribution implements Plottable {
+
+    /**
+     * The datasets.
+     */
+    final protected RealArray[] datasets;
+
+    /**
+     * The data titles.
+     */
+    final protected String[] dataTitles;
+
+    /**
+     * The {@link DataStyle}s.
+     */
+    final protected DataStyle[] dataStyles;
+
+    /**
+     * Default constructor.
+     * 
+     * @param confidencesArray
+     *            the array of prediction confidences.
+     * @param outcomesArray
+     *            the array of prediction outcomes.
+     */
+    public ErrorDistribution(double[][] confidencesArray, boolean[][] outcomesArray) {
+
+        int nclasses = Control.checkEquals(confidencesArray.length, outcomesArray.length);
+
+        this.datasets = new RealArray[nclasses];
+
+        for (int i = 0; i < nclasses; i++) {
+
+            int nexamples = Control.checkEquals(confidencesArray[i].length, outcomesArray[i].length);
+
+            double[] confidences = new double[nexamples];
+            boolean[] outcomes = new boolean[nexamples];
+
+            RealArray dataset = new RealArray(nexamples, 2);
+
+            int[] perm = new RealArray(confidencesArray[i]).clone().iSort(0).reverse(0).values();
+
+            for (int j = 0; j < nexamples; j++) {
+
+                confidences[j] = confidencesArray[i][perm[j]];
+                outcomes[j] = outcomesArray[i][perm[j]];
+            }
+
+            initDataset(dataset, outcomes);
+
+            this.datasets[i] = dataset;
+        }
+
+        this.dataTitles = PlotBase.createDefaultTitles(nclasses);
+        this.dataStyles = Arrays.newArray(DataStyle.class, nclasses, DataStyle.Lines);
+    }
+
+    /**
+     * Gets the AUC's (area under curves).
+     */
+    public double[] getAUCs() {
+
+        double[] aucs = new double[this.datasets.length];
+
+        for (int i = 0, n = this.datasets.length; i < n; i++) {
+
+            RealArray dataset = this.datasets[i];
+
+            RealArray xarr = dataset.subarray(0, dataset.size(0), 0, 1);
+            RealArray yarr = dataset.subarray(0, dataset.size(0), 1, 2);
+
+            aucs[i] = xarr.eSub(xarr.shift(1, 0)).eMul(yarr.eAdd(yarr.shift(1, 0))).uMul(0.5) //
+                    .subarray(1, dataset.size(0), 0, dataset.size(1)).rSum(0).get(0, 0);
+        }
+
+        return aucs;
+    }
+
+    public RealArray[] getDatasets() {
+        return this.datasets;
+    }
+
+    public String[] getDataTitles() {
+        return this.dataTitles;
+    }
+
+    public DataStyle[] getDataStyles() {
+        return this.dataStyles;
+    }
+
+    public boolean getPropertyEnabled(String property) {
+        return (property.equals("legend") || property.equals("grid"));
+    }
+
+    public String getAxisTitle(AxisType axisType) {
+
+        switch (axisType) {
+
+        case X:
+            return getXAxisTitle();
+
+        case Y:
+            return getYAxisTitle();
+
+        default:
+            throw new IllegalArgumentException("Invalid axis type");
+        }
+    }
+
+    public double[] getAxisRange(AxisType axisType) {
+
+        switch (axisType) {
+
+        case X:
+            return getXAxisRange();
+
+        case Y:
+            return getYAxisRange();
+
+        default:
+            throw new IllegalArgumentException("Invalid axis type");
+        }
+    }
+
+    /**
+     * Initializes the given dataset.
+     * 
+     * @param dataset
+     *            the dataset.
+     * @param outcomes
+     *            the prediction outcomes.
+     */
+    abstract protected void initDataset(RealArray dataset, boolean[] outcomes);
+
+    /**
+     * Gets the <tt>x</tt>-axis title.
+     */
+    abstract protected String getXAxisTitle();
+
+    /**
+     * Gets the <tt>y</tt>-axis title.
+     */
+    abstract protected String getYAxisTitle();
+
+    /**
+     * Gets the <tt>x</tt>-axis range.
+     */
+    abstract protected double[] getXAxisRange();
+
+    /**
+     * Gets the <tt>y</tt>-axis range.
+     */
+    abstract protected double[] getYAxisRange();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/GnuplotContext.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/GnuplotContext.java
new file mode 100755
index 0000000..836460f
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/GnuplotContext.java
@@ -0,0 +1,600 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.List;
+
+import shared.array.RealArray;
+import shared.stat.plot.Plot.AxisScaleType;
+import shared.stat.plot.Plot.AxisType;
+import shared.util.Control;
+
+/**
+ * A <a href="http://www.gnuplot.info/">Gnuplot</a>-backed implementation of {@link PlotContext}.
+ * 
+ * @apiviz.composedOf shared.stat.plot.GnuplotContext.Gnuplot
+ * @apiviz.uses shared.stat.plot.PlotBase
+ * @author Roy Liu
+ */
+public class GnuplotContext implements PlotContext<GnuplotContext, GnuplotContext.Gnuplot> {
+
+    /**
+     * An array of operating system dependent arguments to execute Gnuplot.
+     */
+    final protected static String[] GnuplotExecArgs;
+
+    /**
+     * The property that toggles the legend.
+     */
+    final public static String PROPERTY_LEGEND = "legend";
+
+    /**
+     * The property that toggles the grid.
+     */
+    final public static String PROPERTY_GRID = "grid";
+
+    /**
+     * The property that toggles the mesh.
+     */
+    final public static String PROPERTY_MESH = "mesh";
+
+    /**
+     * The property that toggles the colormap.
+     */
+    final public static String PROPERTY_COLORMAP = "colormap";
+
+    static {
+
+        boolean isWindows = System.getProperty("os.name").contains("Windows");
+
+        GnuplotExecArgs = isWindows ? new String[] { "cmd", "/C", "gnuplot.exe" } //
+                : new String[] { "gnuplot" };
+    }
+
+    final List<Gnuplot> plots;
+
+    String fontName;
+
+    int fontSize;
+
+    String outputFormat;
+
+    int outputWidth;
+    int outputHeight;
+
+    /**
+     * Default constructor.
+     */
+    public GnuplotContext() {
+
+        this.plots = new ArrayList<Gnuplot>();
+
+        this.fontName = "Helvetica";
+        this.fontSize = 8;
+        this.outputFormat = "svg";
+        this.outputWidth = 800;
+        this.outputHeight = 600;
+    }
+
+    public Gnuplot addPlot(Plottable plottable) {
+
+        final Gnuplot gp = new Gnuplot(plottable.getDatasets());
+
+        for (int dim = 0, ndims = gp.ndims; dim < ndims; dim++) {
+
+            AxisType axisType = AxisType.values()[dim];
+
+            double[] range = plottable.getAxisRange(axisType);
+
+            gp.setAxisRange(axisType, range[0], range[1]) //
+                    .setAxisTitle(axisType, plottable.getAxisTitle(axisType));
+        }
+
+        gp.setTitle(plottable.getTitle()) //
+                .setDataStyles(plottable.getDataStyles()) //
+                .setDataTitles(plottable.getDataTitles()) //
+                .setPropertyEnabled(PROPERTY_LEGEND, //
+                        plottable.getPropertyEnabled(PROPERTY_LEGEND)) //
+                .setPropertyEnabled(PROPERTY_GRID, //
+                        plottable.getPropertyEnabled(PROPERTY_GRID)) //
+                .setPropertyEnabled(PROPERTY_MESH, //
+                        plottable.getPropertyEnabled(PROPERTY_MESH)) //
+                .setPropertyEnabled(PROPERTY_COLORMAP, //
+                        plottable.getPropertyEnabled(PROPERTY_COLORMAP));
+
+        this.plots.add(gp);
+
+        return gp;
+    }
+
+    public Gnuplot addPlot(RealArray... datasets) {
+
+        final Gnuplot gp = new Gnuplot(datasets);
+
+        this.plots.add(gp);
+
+        return gp;
+    }
+
+    public void toFile(File file) throws IOException {
+
+        File errFile = new File(file.toString().concat(".log"));
+
+        FileOutputStream out = new FileOutputStream(file);
+        FileOutputStream errOut = new FileOutputStream(errFile);
+
+        try {
+
+            Control.execAndWaitFor(new ByteArrayInputStream(toString().getBytes()), out, errOut, //
+                    GnuplotExecArgs);
+
+        } catch (IOException e) {
+
+            e.printStackTrace(new PrintStream(errOut));
+
+        } finally {
+
+            Control.close(out);
+            Control.close(errOut);
+        }
+
+        if (errFile.length() == 0) {
+            Control.delete(errFile);
+        }
+    }
+
+    /**
+     * Creates Gnuplot directives for rendering this context.
+     */
+    @Override
+    public String toString() {
+
+        final String configStr;
+
+        if (this.outputFormat.equals("eps")) {
+
+            configStr = String.format("postscript eps color font \"%s\" %d", //
+                    this.fontName, this.fontSize);
+
+        } else if (this.outputFormat.equals("png")) {
+
+            configStr = String.format("png truecolor font \"%s\" %d size %d, %d", //
+                    this.fontName, this.fontSize, //
+                    this.outputWidth, this.outputHeight);
+
+        } else if (this.outputFormat.equals("svg")) {
+
+            configStr = String.format("svg fname \"%s\" fsize %d size %d, %d", //
+                    this.fontName, this.fontSize, //
+                    this.outputWidth, this.outputHeight);
+
+        } else {
+
+            throw new IllegalArgumentException( //
+                    String.format("Output format '%s' not recognized", this.outputFormat));
+        }
+
+        Formatter f = new Formatter();
+
+        f.format("set terminal %s%n", configStr);
+        f.format("set output%n");
+        f.format("set size 1.0, 1.0%n");
+        // Create a better-looking colormap.
+        f.format("set palette rgbformulae 22, 13, -31%n");
+        f.format("set multiplot%n");
+
+        int maxWidth = 1;
+        int maxHeight = 1;
+
+        for (Gnuplot plot : this.plots) {
+
+            maxWidth = Math.max(maxWidth, plot.panelX + plot.panelWidth);
+            maxHeight = Math.max(maxHeight, plot.panelY + plot.panelHeight);
+        }
+
+        for (Gnuplot plot : this.plots) {
+
+            int ndims = plot.ndims;
+            int nclasses = plot.datasets.length;
+
+            f.format("set origin %.4f, %.4f%n", //
+                    plot.panelX / (double) maxWidth, //
+                    (maxHeight - plot.panelY - plot.panelHeight) / (double) maxHeight);
+            f.format("set size %.4f, %.4f%n", //
+                    plot.panelWidth / (double) maxWidth, //
+                    plot.panelHeight / (double) maxHeight);
+            f.format("set title \"%s\"%n", plot.title);
+            f.format("%s%n", plot.isLegendEnabled ? "set key box below right" : "unset key");
+
+            int meshSize = 0;
+
+            if (plot.isMeshEnabled) {
+
+                for (RealArray data : plot.datasets) {
+                    meshSize = Math.max(data.size(0), meshSize);
+                }
+            }
+
+            meshSize = (int) Math.sqrt(meshSize) + 1;
+
+            f.format("%s%n", plot.isGridEnabled ? "set grid" : "unset grid");
+            f.format("%s%n", plot.isMeshEnabled ? String.format("set dgrid3d %d, %d", meshSize, meshSize)
+                    : "unset dgrid3d");
+            f.format("%s%n", plot.isColormapEnabled ? "set pm3d" : "unset pm3d");
+            f.format("%s%n", (plot.viewportParameters != null) ? String.format("set view %.2f, %.2f", //
+                    plot.viewportParameters[0], plot.viewportParameters[1]) : "unset view");
+
+            for (int dim = 0; dim < ndims; dim++) {
+
+                String axisName = AxisType.values()[dim].toString().toLowerCase();
+
+                f.format("set %srange [%.4e:%.4e]%n", axisName, //
+                        plot.axisRanges[2 * dim], plot.axisRanges[2 * dim + 1]);
+                f.format("set %slabel \"%s\"%n", axisName, plot.axisTitles[dim]);
+                f.format("%s logscale %s%n", //
+                        (plot.axisScaleTypes[dim] == AxisScaleType.LOG) ? "set" : "unset", //
+                        axisName);
+            }
+
+            for (int i = 0; i < nclasses; i++) {
+                f.format("set style line %d%s%n", i + 1, createLineStyleDefinition(plot.dataStyles[i]));
+            }
+
+            final String plotStr;
+
+            switch (plot.ndims) {
+
+            case 2:
+                plotStr = "plot";
+                break;
+
+            case 3:
+                plotStr = "splot";
+                break;
+
+            default:
+                throw new IllegalArgumentException();
+            }
+
+            f.format("%s ", plotStr);
+
+            for (int i = 0; i < nclasses; i++) {
+
+                DataStyle style = plot.dataStyles[i];
+
+                String styleStr;
+
+                switch (style.getType()) {
+
+                case LINES:
+                    styleStr = "lines";
+                    break;
+
+                case POINTS:
+                    styleStr = "points";
+                    break;
+
+                case LINESPOINTS:
+                    styleStr = "linespoints";
+                    break;
+
+                case BARS:
+                    styleStr = "boxes";
+                    break;
+
+                case SURFACE:
+                    styleStr = "pm3d";
+                    break;
+
+                default:
+                    throw new IllegalArgumentException();
+                }
+
+                f.format("\"-\" title \"%s\" with %s ls %d", plot.dataTitles[i], styleStr, i + 1);
+                f.format((i < nclasses - 1) ? ", " : "%n");
+            }
+
+            for (int i = 0; i < nclasses; i++) {
+
+                RealArray data = plot.datasets[i];
+
+                for (int j = 0, m = data.size(0); j < m; j++) {
+
+                    for (int dim = 0; dim < ndims; dim++) {
+
+                        f.format("%.4e", data.get(j, dim));
+                        f.format((dim < ndims - 1) ? " " : "%n");
+                    }
+                }
+
+                f.format("e%n");
+            }
+
+            f.format("unset style line%n");
+        }
+
+        f.format("unset multiplot%n");
+
+        return f.toString();
+    }
+
+    public GnuplotContext setFont(String fontName, int fontSize) {
+
+        this.fontName = fontName;
+        this.fontSize = fontSize;
+
+        return this;
+    }
+
+    public GnuplotContext setOutputFormat(String outputFormat) {
+
+        this.outputFormat = outputFormat;
+
+        return this;
+    }
+
+    public GnuplotContext setOutputSize(int outputWidth, int outputHeight) {
+
+        this.outputHeight = outputHeight;
+        this.outputWidth = outputWidth;
+
+        return this;
+    }
+
+    /**
+     * Creates a Gnuplot line style definition from the given {@link DataStyle}.
+     */
+    final protected static String createLineStyleDefinition(DataStyle style) {
+
+        Formatter f = new Formatter();
+
+        String lt = style.getLineStyle();
+        String lc = style.getLineColor();
+        Double lw = style.getLineSize();
+        String pt = style.getPointStyle();
+        Double ps = style.getPointSize();
+
+        if (lt != null) {
+            f.format(" lt %s", lt);
+        }
+
+        if (lc != null) {
+            f.format(" lc rgb \"%s\"", lc);
+        }
+
+        if (lw != null) {
+            f.format(" lw %.2f", lw);
+        }
+
+        if (pt != null) {
+            f.format(" pt %s", pt);
+        }
+
+        if (ps != null) {
+            f.format(" ps %.2f", ps);
+        }
+
+        String res = f.toString();
+        return !res.equals("") ? f.toString() : " default";
+    }
+
+    /**
+     * An internal implementation of {@link Plot}.
+     */
+    public static class Gnuplot implements Plot<Gnuplot> {
+
+        final String[] axisTitles;
+        final AxisScaleType[] axisScaleTypes;
+        final double[] axisRanges;
+
+        final int ndims;
+        final RealArray[] datasets;
+        final String[] dataTitles;
+        final DataStyle[] dataStyles;
+
+        double[] viewportParameters;
+
+        String title;
+
+        boolean isLegendEnabled;
+        boolean isGridEnabled;
+        boolean isMeshEnabled;
+        boolean isColormapEnabled;
+
+        int panelX;
+        int panelY;
+        int panelWidth;
+        int panelHeight;
+
+        /**
+         * Default constructor.
+         */
+        public Gnuplot(RealArray[] datasets) {
+
+            int nclasses = datasets.length;
+
+            this.ndims = PlotBase.inferDimensionality(datasets);
+
+            Control.checkTrue(this.ndims >= 2 && this.ndims <= 3, //
+                    "The dimensionality must be either two or three");
+
+            this.axisTitles = shared.util.Arrays.newArray(String.class, this.ndims, "");
+            this.axisScaleTypes = shared.util.Arrays.newArray(AxisScaleType.class, this.ndims, AxisScaleType.NORMAL);
+            this.axisRanges = new double[2 * this.ndims];
+
+            this.datasets = datasets;
+            this.dataTitles = shared.util.Arrays.newArray(String.class, nclasses, "");
+            this.dataStyles = shared.util.Arrays.newArray(DataStyle.class, nclasses, DataStyle.Points);
+
+            for (int i = 0, n = 2 * this.ndims; i < n; i += 2) {
+
+                this.axisRanges[i] = 0.0;
+                this.axisRanges[i + 1] = 1.0;
+            }
+
+            this.viewportParameters = null;
+            this.title = "";
+            this.isLegendEnabled = false;
+            this.isGridEnabled = false;
+            this.isMeshEnabled = false;
+            this.isColormapEnabled = false;
+            this.panelX = 0;
+            this.panelY = 0;
+            this.panelWidth = 1;
+            this.panelHeight = 1;
+        }
+
+        public Gnuplot setTitle(String title) {
+
+            this.title = title;
+
+            return this;
+        }
+
+        public Gnuplot setAxis(AxisType axisType, String axisTitle, double lower, double upper,
+                AxisScaleType axisScaleType) {
+
+            int dim = axisType.ordinal();
+
+            Control.checkTrue(dim < this.ndims, //
+                    "Invalid axis type");
+
+            this.axisTitles[dim] = axisTitle;
+            this.axisRanges[2 * dim] = lower;
+            this.axisRanges[2 * dim + 1] = upper;
+            this.axisScaleTypes[dim] = axisScaleType;
+
+            return this;
+        }
+
+        public Gnuplot setAxisTitle(AxisType axisType, String axisTitle) {
+
+            int dim = axisType.ordinal();
+
+            Control.checkTrue(dim < this.ndims, //
+                    "Invalid axis type");
+
+            this.axisTitles[dim] = axisTitle;
+
+            return this;
+        }
+
+        public Gnuplot setAxisRange(AxisType axisType, double lower, double upper) {
+
+            int dim = axisType.ordinal();
+
+            Control.checkTrue(dim < this.ndims, //
+                    "Invalid axis type");
+
+            this.axisRanges[2 * dim] = lower;
+            this.axisRanges[2 * dim + 1] = upper;
+
+            return this;
+        }
+
+        public Gnuplot setAxisScale(AxisType axisType, AxisScaleType axisScaleType) {
+
+            int dim = axisType.ordinal();
+
+            Control.checkTrue(dim < this.ndims, //
+                    "Invalid axis type");
+
+            this.axisScaleTypes[dim] = axisScaleType;
+
+            return this;
+        }
+
+        public Gnuplot setDataTitles(String... dataTitles) {
+
+            System.arraycopy(dataTitles, 0, this.dataTitles, 0, //
+                    Control.checkEquals(this.dataTitles.length, dataTitles.length));
+
+            return this;
+        }
+
+        public Gnuplot setDataStyles(DataStyle... dataStyles) {
+
+            System.arraycopy(dataStyles, 0, this.dataStyles, 0, //
+                    Control.checkEquals(this.dataStyles.length, dataStyles.length));
+
+            return this;
+        }
+
+        public Gnuplot setViewport(double... viewportParameters) {
+
+            Control.checkTrue(this.ndims == 3, //
+                    "Only three-dimensional plots may have their viewports specified");
+
+            Control.checkTrue(viewportParameters.length == 2, //
+                    "Invalid arguments");
+
+            this.viewportParameters = viewportParameters;
+
+            return this;
+        }
+
+        public Gnuplot setPropertyEnabled(String property, boolean isPropertyEnabled) {
+
+            if (property.equals(PROPERTY_LEGEND)) {
+
+                this.isLegendEnabled = isPropertyEnabled;
+
+            } else if (property.equals(PROPERTY_GRID)) {
+
+                this.isGridEnabled = isPropertyEnabled;
+
+            } else if (property.equals(PROPERTY_MESH)) {
+
+                this.isMeshEnabled = isPropertyEnabled;
+
+            } else if (property.equals(PROPERTY_COLORMAP)) {
+
+                this.isColormapEnabled = isPropertyEnabled;
+
+            } else {
+
+                throw new IllegalArgumentException("Invalid Gnuplot property");
+            }
+
+            return this;
+        }
+
+        public Gnuplot setPanelLocation(int panelX, int panelY) {
+
+            this.panelX = panelX;
+            this.panelY = panelY;
+
+            return this;
+        }
+
+        public Gnuplot setPanelSize(int panelWidth, int panelHeight) {
+
+            this.panelWidth = panelWidth;
+            this.panelHeight = panelHeight;
+
+            return this;
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Histogram.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Histogram.java
new file mode 100755
index 0000000..d4b0d56
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Histogram.java
@@ -0,0 +1,151 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+import shared.stat.plot.Plot.AxisType;
+
+/**
+ * A representation of histograms.
+ * 
+ * @author Roy Liu
+ */
+public class Histogram implements Plottable {
+
+    /**
+     * The datasets.
+     */
+    final protected RealArray[] datasets;
+
+    /**
+     * The data titles.
+     */
+    final protected String[] dataTitles;
+
+    /**
+     * The {@link DataStyle}s.
+     */
+    final protected DataStyle[] dataStyles;
+
+    /**
+     * The <tt>x</tt> range.
+     */
+    final protected double[] xrange;
+
+    /**
+     * The <tt>y</tt> range.
+     */
+    final protected double[] yrange;
+
+    /**
+     * Default constructor.
+     * 
+     * @param min
+     *            the range minimum.
+     * @param max
+     *            the range maximum.
+     * @param nbins
+     *            the number of bins.
+     * @param valuesArray
+     *            the array of values.
+     */
+    public Histogram(double min, double max, int nbins, double[]... valuesArray) {
+
+        int nclasses = valuesArray.length;
+
+        this.datasets = new RealArray[nclasses];
+
+        double increment = (max - min) / nbins;
+        double maxCount = 0.0;
+
+        for (int i = 0, n = valuesArray.length; i < n; i++) {
+
+            RealArray dataset = new RealArray(nbins, 2);
+
+            for (int bin = 0; bin < nbins; bin++) {
+                dataset.set(increment * (bin + 0.5) + min, bin, 0);
+            }
+
+            for (double value : valuesArray[i]) {
+
+                int bin = Math.max(0, Math.min(nbins - 1, (int) ((value - min) / increment)));
+                dataset.set(dataset.get(bin, 1) + 1.0d, bin, 1);
+            }
+
+            maxCount = Math.max(maxCount, dataset.subarray(0, nbins, 1, 2).aMax());
+
+            this.datasets[i] = dataset;
+        }
+
+        this.xrange = new double[] { min, max };
+        this.yrange = new double[] { 0, maxCount };
+
+        this.dataTitles = PlotBase.createDefaultTitles(nclasses);
+        this.dataStyles = shared.util.Arrays.newArray(DataStyle.class, nclasses, DataStyle.Bars);
+    }
+
+    public String getTitle() {
+        return "Histogram";
+    }
+
+    public RealArray[] getDatasets() {
+        return this.datasets;
+    }
+
+    public String[] getDataTitles() {
+        return this.dataTitles;
+    }
+
+    public DataStyle[] getDataStyles() {
+        return this.dataStyles;
+    }
+
+    public boolean getPropertyEnabled(String property) {
+        return false;
+    }
+
+    public double[] getAxisRange(AxisType axisType) {
+
+        switch (axisType) {
+
+        case X:
+            return this.xrange;
+
+        case Y:
+            return this.yrange;
+
+        default:
+            throw new IllegalArgumentException("Invalid axis type");
+        }
+    }
+
+    public String getAxisTitle(AxisType axisType) {
+
+        switch (axisType) {
+
+        case X:
+            return "bins";
+
+        case Y:
+            return "counts";
+
+        default:
+            throw new IllegalArgumentException("Invalid axis type");
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Plot.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Plot.java
new file mode 100755
index 0000000..a9e0407
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Plot.java
@@ -0,0 +1,176 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+/**
+ * Defines a plotting abstraction.
+ * 
+ * @apiviz.owns shared.stat.plot.Plottable
+ * @apiviz.owns shared.stat.plot.Plot.AxisType
+ * @apiviz.owns shared.stat.plot.Plot.AxisScaleType
+ * @apiviz.owns shared.stat.plot.DataStyle
+ * @param <T>
+ *            the parameterization lower bounded by {@link Plot} itself.
+ */
+public interface Plot<T extends Plot<T>> {
+
+    /**
+     * An enumeration of axis types.
+     */
+    public enum AxisType {
+
+        /**
+         * Indicates the <tt>x</tt>-axis.
+         */
+        X, //
+
+        /**
+         * Indicates the <tt>y</tt>-axis.
+         */
+        Y, //
+
+        /**
+         * Indicates the <tt>z</tt>-axis.
+         */
+        Z;
+    };
+
+    /**
+     * An enumeration of axis scale types.
+     */
+    public enum AxisScaleType {
+
+        /**
+         * Indicates a normal scale.
+         */
+        NORMAL, //
+
+        /**
+         * Indicates a logarithmic scale.
+         */
+        LOG;
+    };
+
+    /**
+     * Sets the title.
+     * 
+     * @param title
+     *            the title.
+     */
+    public T setTitle(String title);
+
+    /**
+     * Sets the axis information.
+     * 
+     * @param axisType
+     *            the {@link AxisType}.
+     * @param axisTitle
+     *            the axis title.
+     * @param lower
+     *            the lower bound.
+     * @param upper
+     *            the upper bound.
+     * @param axisScaleType
+     *            the {@link AxisScaleType}.
+     */
+    public T setAxis(AxisType axisType, String axisTitle, double lower, double upper, AxisScaleType axisScaleType);
+
+    /**
+     * Sets the axis title.
+     * 
+     * @param axisType
+     *            the {@link AxisType}.
+     * @param axisTitle
+     *            the axis title.
+     */
+    public T setAxisTitle(AxisType axisType, String axisTitle);
+
+    /**
+     * Sets the axis range.
+     * 
+     * @param axisType
+     *            the {@link AxisType}.
+     * @param lower
+     *            the lower bound.
+     * @param upper
+     *            the upper bound.
+     */
+    public T setAxisRange(AxisType axisType, double lower, double upper);
+
+    /**
+     * Sets the {@link AxisScaleType}.
+     * 
+     * @param axisType
+     *            the {@link AxisType}.
+     * @param axisScaleType
+     *            the {@link AxisScaleType}.
+     */
+    public T setAxisScale(AxisType axisType, AxisScaleType axisScaleType);
+
+    /**
+     * Sets the data titles.
+     * 
+     * @param dataTitles
+     *            the data titles.
+     */
+    public T setDataTitles(String... dataTitles);
+
+    /**
+     * Sets the {@link DataStyle}s.
+     * 
+     * @param dataStyles
+     *            the {@link DataStyle}s.
+     */
+    public T setDataStyles(DataStyle... dataStyles);
+
+    /**
+     * Sets the viewport.
+     * 
+     * @param viewportParameters
+     *            the viewport parameters.
+     */
+    public T setViewport(double... viewportParameters);
+
+    /**
+     * Sets whether the given property is enabled.
+     * 
+     * @param isPropertyEnabled
+     *            whether the given property is enabled.
+     */
+    public T setPropertyEnabled(String property, boolean isPropertyEnabled);
+
+    /**
+     * Sets the panel location.
+     * 
+     * @param panelX
+     *            the panel <tt>x</tt>-coordinate.
+     * @param panelY
+     *            the panel <tt>y</tt>-coordinate.
+     */
+    public T setPanelLocation(int panelX, int panelY);
+
+    /**
+     * Sets the panel size.
+     * 
+     * @param panelWidth
+     *            the panel width.
+     * @param panelHeight
+     *            the panel height.
+     */
+    public T setPanelSize(int panelWidth, int panelHeight);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PlotBase.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PlotBase.java
new file mode 100755
index 0000000..31ad582
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PlotBase.java
@@ -0,0 +1,78 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+import shared.util.Control;
+
+/**
+ * A collection of useful static methods for plotting.
+ */
+public class PlotBase {
+
+    /**
+     * Infers the dimensionality of the given datasets.
+     * 
+     * @param datasets
+     *            the datasets.
+     * @return the dimensionality.
+     */
+    final public static int inferDimensionality(RealArray... datasets) {
+
+        int nclasses = datasets.length;
+
+        Control.checkTrue(nclasses > 0, //
+                "Please specify some datasets");
+
+        for (int i = 0; i < nclasses; i++) {
+            Control.checkTrue(datasets[i].ndims() == 2, //
+                    "Invalid arguments");
+        }
+
+        int ndims = datasets[0].size(1);
+
+        for (int i = 1; i < nclasses; i++) {
+            Control.checkTrue(ndims == datasets[i].size(1), //
+                    "Dimensionality mismatch");
+        }
+
+        return ndims;
+    }
+
+    /**
+     * Creates a default array of titles.
+     * 
+     * @param length
+     *            the desired length.
+     * @return an array consisting of {@code 1}, {@code 2}, <tt>...</tt>, {@code length}.
+     */
+    final public static String[] createDefaultTitles(int length) {
+
+        String[] res = new String[length];
+
+        for (int i = 0; i < length; i++) {
+            res[i] = String.format("class %d", i + 1);
+        }
+
+        return res;
+    }
+
+    // Dummy constructor.
+    PlotBase() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PlotContext.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PlotContext.java
new file mode 100755
index 0000000..6c83c14
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PlotContext.java
@@ -0,0 +1,89 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import java.io.File;
+import java.io.IOException;
+
+import shared.array.RealArray;
+
+/**
+ * Defines a context for creating {@link Plot}s.
+ * 
+ * @apiviz.owns shared.stat.plot.Plot
+ * @param <T>
+ *            the parameterization lower bounded by {@link PlotContext} itself.
+ * @param <P>
+ *            the {@link Plot} type.
+ */
+public interface PlotContext<T extends PlotContext<T, P>, P extends Plot<P>> {
+
+    /**
+     * Creates a {@link Plot} at the given coordinates.
+     * 
+     * @param plottable
+     *            the {@link Plottable}.
+     */
+    public P addPlot(Plottable plottable);
+
+    /**
+     * Creates a {@link Plot} at the given coordinates.
+     * 
+     * @param datasets
+     *            the datasets.
+     */
+    public P addPlot(RealArray... datasets);
+
+    /**
+     * Exports to a file.
+     * 
+     * @param file
+     *            the file.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    public void toFile(File file) throws IOException;
+
+    /**
+     * Sets the font and size.
+     * 
+     * @param fontName
+     *            the font name.
+     * @param fontSize
+     *            the font size.
+     */
+    public T setFont(String fontName, int fontSize);
+
+    /**
+     * Sets the output format.
+     * 
+     * @param outputFormat
+     *            the output format.
+     */
+    public T setOutputFormat(String outputFormat);
+
+    /**
+     * Sets the output size.
+     * 
+     * @param outputWidth
+     *            the output width.
+     * @param outputHeight
+     *            the output height.
+     */
+    public T setOutputSize(int outputWidth, int outputHeight);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Plottable.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Plottable.java
new file mode 100755
index 0000000..ac774af
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Plottable.java
@@ -0,0 +1,72 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+import shared.stat.plot.Plot.AxisType;
+
+/**
+ * Defines something as suitable for having its values plotted.
+ */
+public interface Plottable {
+
+    /**
+     * Gets the datasets.
+     */
+    public RealArray[] getDatasets();
+
+    /**
+     * Gets the title.
+     */
+    public String getTitle();
+
+    /**
+     * Gets the axis title.
+     * 
+     * @param axisType
+     *            the {@link AxisType}.
+     */
+    public String getAxisTitle(AxisType axisType);
+
+    /**
+     * Gets the axis range.
+     * 
+     * @param axisType
+     *            the {@link AxisType}.
+     */
+    public double[] getAxisRange(AxisType axisType);
+
+    /**
+     * Gets the data titles.
+     */
+    public String[] getDataTitles();
+
+    /**
+     * Gets the {@link DataStyle}s.
+     */
+    public DataStyle[] getDataStyles();
+
+    /**
+     * Gets whether the given property is enabled.
+     * 
+     * @param property
+     *            the given property.
+     * @return whether the given property is enabled.
+     */
+    public boolean getPropertyEnabled(String property);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PrecisionRecall.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PrecisionRecall.java
new file mode 100755
index 0000000..a22baf7
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/PrecisionRecall.java
@@ -0,0 +1,99 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+
+/**
+ * A representation of precision-recall plots.
+ * 
+ * @author Roy Liu
+ */
+public class PrecisionRecall extends ErrorDistribution {
+
+    /**
+     * The <tt>x</tt>-axis range.
+     */
+    final protected static double[] XRange = new double[] { 1.0, 0.0 };
+
+    final double[] yrange;
+
+    /**
+     * Default constructor.
+     * 
+     * @see ErrorDistribution#ErrorDistribution(double[][], boolean[][])
+     */
+    public PrecisionRecall(double[][] confidencesArray, boolean[][] outcomesArray) {
+        super(confidencesArray, outcomesArray);
+
+        double precisionMin = 1.0;
+
+        for (RealArray dataset : this.datasets) {
+            precisionMin = Math.min(precisionMin, dataset.subarray(0, dataset.size(0), 1, 2).aMin());
+        }
+
+        this.yrange = new double[] { precisionMin, 1.0 };
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public PrecisionRecall(double[] confidences, boolean[] outcomes) {
+        this(new double[][] { confidences }, new boolean[][] { outcomes });
+    }
+
+    public String getTitle() {
+        return "Precision-Recall";
+    }
+
+    @Override
+    protected void initDataset(RealArray dataset, boolean[] outcomes) {
+
+        int nexamples = dataset.size(0);
+
+        for (int i = 0, ncorrect = 0; i < nexamples; i++) {
+
+            if (outcomes[i]) {
+                ncorrect++;
+            }
+
+            dataset.set(i / (double) nexamples, i, 0);
+            dataset.set((i > 0) ? ncorrect / (double) i : 1.0, i, 1);
+        }
+    }
+
+    @Override
+    protected double[] getXAxisRange() {
+        return XRange;
+    }
+
+    @Override
+    protected double[] getYAxisRange() {
+        return this.yrange;
+    }
+
+    @Override
+    protected String getXAxisTitle() {
+        return "recall";
+    }
+
+    @Override
+    protected String getYAxisTitle() {
+        return "precision";
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ProbabilityDistribution.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ProbabilityDistribution.java
new file mode 100755
index 0000000..fcd535c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ProbabilityDistribution.java
@@ -0,0 +1,158 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import java.util.Arrays;
+
+import shared.array.RealArray;
+import shared.stat.plot.Plot.AxisType;
+
+/**
+ * A representation of probability distributions.
+ * 
+ * @apiviz.owns shared.stat.plot.ProbabilityDistribution.Mode
+ * @author Roy Liu
+ */
+public class ProbabilityDistribution extends Histogram {
+
+    /**
+     * An enumeration of probability distribution modes.
+     */
+    public enum Mode {
+
+        /**
+         * Indicates a cumulative density function.
+         */
+        CDF {
+
+            @Override
+            protected void initDistribution(RealArray d) {
+                d.eDiv(d.rSum(0).tile(d.size(0), 1)).dSum(0) //
+                        .map(d, 0, 0, d.size(0), 1, 1, 1);
+            }
+        }, //
+
+        /**
+         * Indicates a probability density function.
+         */
+        PDF {
+
+            @Override
+            protected void initDistribution(RealArray d) {
+                d.eDiv(d.rSum(0).tile(d.size(0), 1)) //
+                        .map(d, 0, 0, d.size(0), 1, 1, 1);
+            }
+        };
+
+        /**
+         * Initializes the probability distribution.
+         */
+        abstract protected void initDistribution(RealArray distribution);
+    }
+
+    final Mode mode;
+
+    /**
+     * Default constructor.
+     * 
+     * @param mode
+     *            the display mode.
+     * @param min
+     *            the range minimum.
+     * @param max
+     *            the range maximum.
+     * @param nintervals
+     *            the number of sampling intervals.
+     */
+    public ProbabilityDistribution(Mode mode, double min, double max, int nintervals, double[] values) {
+        super(min, max, nintervals, values);
+
+        double maxDensity = 0.0;
+
+        for (RealArray dataset : this.datasets) {
+
+            mode.initDistribution(dataset);
+
+            maxDensity = Math.max(maxDensity, dataset.subarray(0, dataset.size(0), 1, 2).aMax());
+        }
+
+        Arrays.fill(this.dataStyles, DataStyle.Lines);
+
+        this.yrange[0] = 0.0;
+        this.yrange[1] = (mode == Mode.PDF) ? maxDensity : 1.0;
+
+        this.mode = mode;
+    }
+
+    /**
+     * Alternate constructor.
+     * 
+     * @param min
+     *            the range minimum.
+     * @param max
+     *            the range maximum.
+     * @param nintervals
+     *            the number of sampling intervals.
+     */
+    public ProbabilityDistribution(double min, double max, int nintervals, double[] values) {
+        this(Mode.CDF, min, max, nintervals, values);
+    }
+
+    @Override
+    public String getTitle() {
+
+        switch (this.mode) {
+
+        case PDF:
+            return "Probability Density Function";
+
+        case CDF:
+            return "Cumulative Density Function";
+
+        default:
+            throw new IllegalArgumentException("Invalid mode");
+        }
+    }
+
+    @Override
+    public String getAxisTitle(AxisType axisType) {
+
+        switch (axisType) {
+
+        case X:
+            return axisType.toString();
+
+        case Y:
+
+            switch (this.mode) {
+
+            case PDF:
+                return "density";
+
+            case CDF:
+                return "cumulative density";
+
+            default:
+                throw new IllegalArgumentException("Invalid mode");
+            }
+
+        default:
+            throw new IllegalArgumentException("Invalid axis type");
+        }
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ROC.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ROC.java
new file mode 100755
index 0000000..ed4f7b2
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/ROC.java
@@ -0,0 +1,128 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+
+/**
+ * A representation of ROC (receiver operating characteristic) plots.
+ * 
+ * @author Roy Liu
+ */
+public class ROC extends ErrorDistribution {
+
+    /**
+     * The <tt>x</tt>-axis range.
+     */
+    final protected static double[] XRange = new double[] { 0.0, 1.0 };
+
+    /**
+     * The <tt>y</tt>-axis range.
+     */
+    final protected static double[] YRange = new double[] { 0.0, 1.0 };
+
+    /**
+     * Default constructor.
+     * 
+     * @see ErrorDistribution#ErrorDistribution(double[][], boolean[][])
+     */
+    public ROC(double[][] confidencesArray, boolean[][] outcomesArray) {
+        super(confidencesArray, outcomesArray);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public ROC(double[] confidences, boolean[] outcomes) {
+        this(new double[][] { confidences }, new boolean[][] { outcomes });
+    }
+
+    public String getTitle() {
+        return "ROC";
+    }
+
+    @Override
+    protected void initDataset(RealArray dataset, boolean[] outcomes) {
+
+        int nexamples = dataset.size(0);
+
+        int ntrue = 0;
+        int nfalse = 0;
+
+        for (int i = 0; i < nexamples; i++) {
+
+            if (outcomes[i]) {
+
+                ntrue++;
+
+            } else {
+
+                nfalse++;
+            }
+
+            dataset.set(nfalse, i, 0);
+            dataset.set(ntrue, i, 1);
+        }
+
+        if (nfalse > 0) {
+
+            for (int i = 0; i < nexamples; i++) {
+                dataset.set(dataset.get(i, 0) / nfalse, i, 0);
+            }
+
+        } else {
+
+            for (int i = 0; i < nexamples; i++) {
+                dataset.set(0.0, i, 0);
+            }
+        }
+
+        if (ntrue > 0) {
+
+            for (int i = 0; i < nexamples; i++) {
+                dataset.set(dataset.get(i, 1) / ntrue, i, 1);
+            }
+
+        } else {
+
+            for (int i = 0; i < nexamples; i++) {
+                dataset.set(1.0, i, 1);
+            }
+        }
+    }
+
+    @Override
+    protected double[] getXAxisRange() {
+        return XRange;
+    }
+
+    @Override
+    protected double[] getYAxisRange() {
+        return YRange;
+    }
+
+    @Override
+    protected String getXAxisTitle() {
+        return "false rate";
+    }
+
+    @Override
+    protected String getYAxisTitle() {
+        return "true rate";
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Scatter.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Scatter.java
new file mode 100755
index 0000000..b3e0c83
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/Scatter.java
@@ -0,0 +1,84 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.plot;
+
+import shared.array.RealArray;
+import shared.stat.plot.Plot.AxisType;
+
+/**
+ * A representation of scatter plots.
+ * 
+ * @author Roy Liu
+ */
+public class Scatter implements Plottable {
+
+    /**
+     * The generic axis range.
+     */
+    final protected static double[] AxisRange = new double[] { 0.0, 1.0 };
+
+    final RealArray[] datasets;
+    final String[] dataTitles;
+    final DataStyle[] dataStyles;
+
+    /**
+     * Default constructor.
+     * 
+     * @param datasets
+     *            the datasets.
+     */
+    public Scatter(RealArray... datasets) {
+
+        int nclasses = datasets.length;
+
+        // Check for uniform dimensionality.
+        PlotBase.inferDimensionality(datasets);
+
+        this.datasets = datasets;
+        this.dataTitles = PlotBase.createDefaultTitles(nclasses);
+        this.dataStyles = shared.util.Arrays.newArray(DataStyle.class, nclasses, DataStyle.Points);
+    }
+
+    public RealArray[] getDatasets() {
+        return this.datasets;
+    }
+
+    public String getTitle() {
+        return "Scatter Plot";
+    }
+
+    public boolean getPropertyEnabled(String property) {
+        return property.equals("legend");
+    }
+
+    public double[] getAxisRange(AxisType axisType) {
+        return AxisRange;
+    }
+
+    public String getAxisTitle(AxisType axisType) {
+        return axisType.toString();
+    }
+
+    public String[] getDataTitles() {
+        return this.dataTitles;
+    }
+
+    public DataStyle[] getDataStyles() {
+        return this.dataStyles;
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/package-info.java
new file mode 100755
index 0000000..2a5bb3f
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/plot/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of plotting classes for reporting machine learning metrics.
+ */
+package shared.stat.plot;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/util/Combinatorics.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/util/Combinatorics.java
new file mode 100755
index 0000000..66e8b60
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/util/Combinatorics.java
@@ -0,0 +1,209 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.stat.util;
+
+import shared.util.Control;
+import shared.util.DynamicObjectArray;
+
+/**
+ * A collection of useful static methods for combinatorics.
+ * 
+ * @author Roy Liu
+ */
+public class Combinatorics {
+
+    /**
+     * A lookup table of coefficients in support of {@link #gammaLn(double)}.
+     */
+    final protected static double[] GammaLnCoefficients = new double[] {
+    //
+            76.18009172947146, -86.50532032941677, //
+            24.01409824083091, -1.231739572450155, //
+            0.1208650973866179e-2, -0.5395239384953e-5 //
+    };
+
+    /**
+     * A facade for {@link #partition(int, int, int)}.
+     * 
+     * @param n
+     *            the number of elements.
+     * @return the partitions.
+     */
+    final public static int[][] partition(int n) {
+        return partition(n, 1, n + 1);
+    }
+
+    /**
+     * Calculates all partitions of an {@code n} element set into at least {@code npartsLower} parts and at most
+     * (exclusive) {@code npartsUpper} parts.
+     * 
+     * @param n
+     *            the number of elements.
+     * @param npartsLower
+     *            the lower bound on the number of parts.
+     * @param npartsUpper
+     *            the upper bound (exclusive) on the number of parts.
+     * @return the partitions.
+     */
+    final public static int[][] partition(int n, int npartsLower, int npartsUpper) {
+
+        Control.checkTrue(npartsLower >= 1 && npartsUpper <= n + 1, //
+                "Invalid arguments");
+
+        DynamicObjectArray<int[]> acc = new DynamicObjectArray<int[]>(int[].class);
+
+        for (int nparts = npartsLower; nparts < npartsUpper; nparts++) {
+            partition(acc, new int[nparts], 0, 1, n);
+        }
+
+        return acc.values();
+    }
+
+    /**
+     * A helper method in support of {@link #partition(int, int, int)}.
+     * 
+     * @param acc
+     *            the partition accumulator.
+     * @param sizes
+     *            the partition sizes.
+     * @param nsizes
+     *            the number of parts so far.
+     * @param currentSize
+     *            the part size so far.
+     * @param nremaining
+     *            the number of remaining elements.
+     */
+    final protected static void partition(DynamicObjectArray<int[]> acc, //
+            int[] sizes, int nsizes, int currentSize, int nremaining) {
+
+        if (nremaining == 0 && sizes.length == nsizes) {
+            acc.push(sizes.clone());
+        }
+
+        if (sizes.length == nsizes) {
+            return;
+        }
+
+        for (int size = currentSize, maxSize = nremaining / (sizes.length - nsizes); size <= maxSize; size++) {
+
+            sizes[nsizes] = size;
+            partition(acc, sizes, nsizes + 1, size, nremaining - size);
+        }
+    }
+
+    /**
+     * A facade for {@link #orderedPartition(int, int, int)}.
+     * 
+     * @param n
+     *            the number of elements.
+     * @return the ordered partitions.
+     */
+    final public static int[][] orderedPartition(int n) {
+        return orderedPartition(n, 1, n + 1);
+    }
+
+    /**
+     * Calculates all ordered partitions of an {@code n} element set into at least {@code npartsLower} parts and at most
+     * (exclusive) {@code npartsUpper} parts.
+     * 
+     * @param n
+     *            the number of elements.
+     * @param npartsLower
+     *            the lower bound on the number of parts.
+     * @param npartsUpper
+     *            the upper bound (exclusive) on the number of parts.
+     * @return the ordered partitions.
+     */
+    final public static int[][] orderedPartition(int n, int npartsLower, int npartsUpper) {
+
+        Control.checkTrue(npartsLower < npartsUpper, //
+                "Invalid arguments");
+
+        DynamicObjectArray<int[]> acc = new DynamicObjectArray<int[]>(int[].class);
+
+        for (int nparts = npartsLower; nparts < npartsUpper; nparts++) {
+            orderedPartition(acc, new int[nparts], 0, n);
+        }
+
+        return acc.values();
+    }
+
+    /**
+     * A helper method in support of {@link #orderedPartition(int, int, int)}.
+     * 
+     * @param acc
+     *            the ordered partition accumulator.
+     * @param sizes
+     *            the ordered partition sizes.
+     * @param nsizes
+     *            the number of parts so far.
+     * @param nremaining
+     *            the number of remaining elements.
+     */
+    final protected static void orderedPartition(DynamicObjectArray<int[]> acc, //
+            int[] sizes, int nsizes, int nremaining) {
+
+        if (nremaining == 0 && sizes.length == nsizes) {
+            acc.push(sizes.clone());
+        }
+
+        if (sizes.length == nsizes) {
+            return;
+        }
+
+        for (int size = 0, maxSize = nremaining; size <= maxSize; size++) {
+
+            sizes[nsizes] = size;
+            orderedPartition(acc, sizes, nsizes + 1, nremaining - size);
+        }
+    }
+
+    /**
+     * The <a href="http://en.wikipedia.org/wiki/Gamma_function">gamma function</a>.
+     * 
+     * @param x
+     *            the input value.
+     * @return the gamma function evaluation.
+     */
+    final public static double gamma(double x) {
+        return Math.exp(gammaLn(x));
+    }
+
+    /**
+     * The log-gamma function.
+     * 
+     * @param x
+     *            the input value.
+     * @return the log-gamma function evaluation.
+     */
+    final public static double gammaLn(double x) {
+
+        double t = x + 4.5 - (x - 0.5) * Math.log(x + 4.5);
+        double sum = 1.000000000190015;
+
+        for (int j = 0, n = GammaLnCoefficients.length; j < n; j++, x++) {
+            sum += GammaLnCoefficients[j] / x;
+        }
+
+        return -t + Math.log(2.5066282746310005 * sum);
+    }
+
+    // Dummy constructor.
+    Combinatorics() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/stat/util/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/stat/util/package-info.java
new file mode 100755
index 0000000..450f3ac
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/stat/util/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of statistical utilities.
+ */
+package shared.stat.util;
+
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Arithmetic.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Arithmetic.java
new file mode 100755
index 0000000..d0a5812
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Arithmetic.java
@@ -0,0 +1,491 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.util.Random;
+
+/**
+ * A collection of very basic arithmetic operations on arrays.
+ * 
+ * @author Roy Liu
+ */
+public class Arithmetic {
+
+    /**
+     * The underlying, shared source of randomness.
+     */
+    final protected static Random RandomKernel = new Random(0xdeadbeefcacabeadL);
+
+    /**
+     * Computes the maximum.
+     * 
+     * @param values
+     *            the array.
+     * @return the maximum.
+     */
+    final public static double max(double... values) {
+
+        double acc = -Double.MAX_VALUE;
+
+        for (double v : values) {
+            acc = Math.max(acc, v);
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the minimum.
+     * 
+     * @param values
+     *            the array.
+     * @return the minimum.
+     */
+    final public static double min(double... values) {
+
+        double acc = Double.MAX_VALUE;
+
+        for (double v : values) {
+            acc = Math.min(acc, v);
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the sum.
+     * 
+     * @param values
+     *            the array.
+     * @return the sum.
+     */
+    final public static double sum(double... values) {
+
+        double acc = 0.0;
+
+        for (double v : values) {
+            acc += v;
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the product.
+     * 
+     * @param values
+     *            the array.
+     * @return the product.
+     */
+    final public static double product(double... values) {
+
+        double acc = 1.0;
+
+        for (double v : values) {
+            acc *= v;
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the variance.
+     * 
+     * @param values
+     *            the array.
+     * @return the variance.
+     */
+    final public static double variance(double... values) {
+
+        double len = values.length;
+        double mean = sum(values) / len;
+        double ssd = 0.0;
+
+        for (double v : values) {
+            ssd += ((v - mean) * (v - mean)) / len;
+        }
+
+        return ssd;
+    }
+
+    /**
+     * Computes the entropy.
+     * 
+     * @param values
+     *            the array.
+     * @return the entropy.
+     */
+    final public static double entropy(double... values) {
+
+        double sum = Math.max(0.0, sum(values)) + 1e-64;
+        double en = 0.0;
+
+        for (double v : values) {
+
+            double val = v / sum;
+            en += (val >= 1e-64) ? (val * Math.log(val)) : 0.0;
+        }
+
+        return -en;
+    }
+
+    /**
+     * Shuffles the given array.
+     * 
+     * @param values
+     *            the array.
+     * @return the array.
+     */
+    final public static int[] shuffle(int[] values) {
+
+        for (int i = values.length; i > 1; i--) {
+
+            int index = Arithmetic.nextInt(i);
+
+            int tmp = values[i - 1];
+            values[i - 1] = values[index];
+            values[index] = tmp;
+        }
+
+        return values;
+    }
+
+    /**
+     * Shuffles the given array.
+     * 
+     * @param values
+     *            the array.
+     * @return the array.
+     */
+    final public static double[] shuffle(double[] values) {
+
+        for (int i = values.length; i > 1; i--) {
+
+            int index = Arithmetic.nextInt(i);
+
+            double tmp = values[i - 1];
+            values[i - 1] = values[index];
+            values[index] = tmp;
+        }
+
+        return values;
+    }
+
+    /**
+     * Computes the product.
+     * 
+     * @param values
+     *            the array.
+     * @return the product.
+     */
+    final public static int product(int... values) {
+
+        int acc = 1;
+
+        for (int value : values) {
+            acc *= value;
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the sum.
+     * 
+     * @param values
+     *            the array.
+     * @return the sum.
+     */
+    final public static int sum(int... values) {
+
+        int acc = 0;
+
+        for (int value : values) {
+            acc += value;
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the maximum.
+     * 
+     * @param values
+     *            the array.
+     * @return the maximum.
+     */
+    final public static int max(int... values) {
+
+        int acc = Integer.MIN_VALUE;
+
+        for (int value : values) {
+            acc = Math.max(acc, value);
+        }
+
+        return acc;
+    }
+
+    /**
+     * Computes the minimum.
+     * 
+     * @param values
+     *            the array.
+     * @return the minimum.
+     */
+    final public static int min(int... values) {
+
+        int acc = Integer.MAX_VALUE;
+
+        for (int value : values) {
+            acc = Math.min(acc, value);
+        }
+
+        return acc;
+    }
+
+    /**
+     * Creates a <tt>[m, n)</tt> range of {@code int}s.
+     * 
+     * @param m
+     *            the (inclusive) lower bound.
+     * @param n
+     *            the (exclusive) upper bound.
+     * @return the range.
+     */
+    final public static int[] range(int m, int n) {
+
+        int[] res = new int[n - m];
+
+        for (int i = m, ii = 0; i < n; i++, ii++) {
+            res[ii] = i;
+        }
+
+        return res;
+    }
+
+    /**
+     * Creates a <tt>[0, n)</tt> range of {@code int}s.
+     * 
+     * @param n
+     *            the size of the range.
+     * @return the range.
+     */
+    final public static int[] range(int n) {
+        return range(0, n);
+    }
+
+    /**
+     * Creates a <tt>[m, n)</tt> range of {@code double}s.
+     * 
+     * @param m
+     *            the (inclusive) lower bound.
+     * @param n
+     *            the (exclusive) upper bound.
+     * @return the range.
+     */
+    final public static double[] doubleRange(int m, int n) {
+
+        double[] res = new double[n - m];
+
+        for (int i = m, ii = 0; i < n; i++, ii++) {
+            res[ii] = i;
+        }
+
+        return res;
+    }
+
+    /**
+     * Creates a <tt>[0, n)</tt> range of {@code double}s.
+     * 
+     * @param n
+     *            the size of the range.
+     * @return the range.
+     */
+    final public static double[] doubleRange(int n) {
+        return doubleRange(0, n);
+    }
+
+    /**
+     * Creates a <tt>[m, n)</tt> range of {@code long}s.
+     * 
+     * @param m
+     *            the (inclusive) lower bound.
+     * @param n
+     *            the (exclusive) upper bound.
+     * @return the range.
+     */
+    final public static long[] longRange(int m, int n) {
+
+        long[] res = new long[n - m];
+
+        for (int i = m, ii = 0; i < n; i++, ii++) {
+            res[ii] = i;
+        }
+
+        return res;
+    }
+
+    /**
+     * Creates a <tt>[0, n)</tt> range of {@code long}s.
+     * 
+     * @param n
+     *            the size of the range.
+     * @return the range.
+     */
+    final public static long[] longRange(int n) {
+        return longRange(0, n);
+    }
+
+    /**
+     * Finds the index of the given value.
+     * 
+     * @param values
+     *            the array.
+     * @param value
+     *            the value to search for.
+     * @return the index, or the array length if not found.
+     */
+    final public static int indexOf(int[] values, int value) {
+
+        for (int i = 0, n = values.length; i < n; i++) {
+
+            if (values[i] == value) {
+                return i;
+            }
+        }
+
+        return values.length;
+    }
+
+    /**
+     * Counts the number of times the given value appears.
+     * 
+     * @param values
+     *            the array.
+     * @param value
+     *            the value to count.
+     * @return the count.
+     */
+    final public static int count(int[] values, int value) {
+
+        int count = 0;
+
+        for (int i = 0, n = values.length; i < n; i++) {
+
+            if (values[i] == value) {
+                count++;
+            }
+        }
+
+        return count;
+    }
+
+    /**
+     * Retrieves the source of randomness behind the static methods of {@link Arithmetic}.
+     * 
+     * @return the random source.
+     */
+    final public static Random getRandomSource() {
+        return RandomKernel;
+    }
+
+    /**
+     * A wrapper for {@link Random#nextInt(int)}.
+     * 
+     * @param n
+     *            the upper bound.
+     * @return an integer in <tt>[0, n)</tt>.
+     */
+    final public static int nextInt(int n) {
+        return RandomKernel.nextInt(n);
+    }
+
+    /**
+     * A wrapper for {@link Random#nextInt()}.
+     * 
+     * @return an integer chosen uniformly at random.
+     */
+    final public static int nextInt() {
+        return RandomKernel.nextInt();
+    }
+
+    /**
+     * A wrapper for {@link Random#nextLong()}.
+     * 
+     * @return a long chosen uniformly at random.
+     */
+    final public static long nextLong() {
+        return RandomKernel.nextLong();
+    }
+
+    /**
+     * A wrapper for {@link Random#nextDouble()}.
+     * 
+     * @param a
+     *            the upper bound.
+     * @return a {@code double} in <tt>[0, a)</tt>.
+     */
+    final public static double nextDouble(double a) {
+        return a * RandomKernel.nextDouble();
+    }
+
+    /**
+     * A wrapper for {@link Random#nextGaussian()}.
+     * 
+     * @param a
+     *            the standard deviation.
+     * @return a sample drawn from a Gaussian with mean {@code 0} and standard deviation {@code a}.
+     */
+    final public static double nextGaussian(double a) {
+        return a * RandomKernel.nextGaussian();
+    }
+
+    /**
+     * A wrapper for {@link Random#nextBytes(byte[])}.
+     * 
+     * @param n
+     *            the size of the random {@code byte} array.
+     * @return a randomly generated {@code byte} array of length <tt>n</tt>.
+     */
+    final public static byte[] nextBytes(int n) {
+
+        byte[] res = new byte[n];
+
+        RandomKernel.nextBytes(res);
+
+        return res;
+    }
+
+    /**
+     * Seeds the underlying source of randomness with {@link System#nanoTime()}.
+     */
+    final public static void randomize() {
+        RandomKernel.setSeed(System.nanoTime());
+    }
+
+    /**
+     * Seeds the underlying source of randomness with {@code 0}.
+     */
+    final public static void derandomize() {
+        RandomKernel.setSeed(0);
+    }
+
+    // Dummy constructor.
+    Arithmetic() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Arrays.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Arrays.java
new file mode 100755
index 0000000..8e58b66
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Arrays.java
@@ -0,0 +1,772 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.lang.reflect.Array;
+import java.math.RoundingMode;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A collection of useful static methods for manipulating arrays.
+ * 
+ * @author Roy Liu
+ */
+public class Arrays {
+
+    /**
+     * Creates a new array initialized to the given value.
+     */
+    final public static int[] newArray(int length, int value) {
+
+        int[] res = new int[length];
+        java.util.Arrays.fill(res, value);
+
+        return res;
+    }
+
+    /**
+     * Creates a new array initialized to the given value.
+     */
+    final public static double[] newArray(int length, double value) {
+
+        double[] res = new double[length];
+        java.util.Arrays.fill(res, value);
+
+        return res;
+    }
+
+    /**
+     * Creates a new array initialized to the given value.
+     */
+    final public static Object[] newArray(int length, Object value) {
+
+        Object[] res = new Object[length];
+        java.util.Arrays.fill(res, value);
+
+        return res;
+    }
+
+    /**
+     * Creates a new array initialized to the given value.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <T> T[] newArray(Class<? extends T> clazz, int length, T value) {
+
+        T[] res = (T[]) Array.newInstance(clazz, length);
+        java.util.Arrays.fill(res, value);
+
+        return res;
+    }
+
+    /**
+     * A convenience array slicing method.
+     * 
+     * @param values
+     *            the values.
+     * @param indices
+     *            the slice indices.
+     * @return the sliced values.
+     */
+    final public static double[] slice(double[] values, int[] indices) {
+
+        int len = indices.length;
+
+        double[] res = new double[len];
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[indices[i]];
+        }
+
+        return res;
+    }
+
+    /**
+     * A convenience array slicing method.
+     * 
+     * @param values
+     *            the values.
+     * @param indices
+     *            the slice indices.
+     * @return the sliced values.
+     */
+    final public static int[] slice(int[] values, int[] indices) {
+
+        int len = indices.length;
+
+        int[] res = new int[len];
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[indices[i]];
+        }
+
+        return res;
+    }
+
+    /**
+     * A convenience array slicing method.
+     * 
+     * @param values
+     *            the values.
+     * @param indices
+     *            the slice indices.
+     * @param clazz
+     *            the component class.
+     * @param <T>
+     *            the component type.
+     * @return the sliced values.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <T> T[] slice(T[] values, int[] indices, Class<? extends T> clazz) {
+
+        int len = indices.length;
+
+        T[] res = (T[]) Array.newInstance(clazz, len);
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[indices[i]];
+        }
+
+        return res;
+    }
+
+    /**
+     * Boxes the given array of {@code double}s.
+     * 
+     * @param values
+     *            the values.
+     * @return the boxed values.
+     */
+    final public static Double[] box(double[] values) {
+
+        int len = values.length;
+
+        Double[] res = new Double[len];
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[i];
+        }
+
+        return res;
+    }
+
+    /**
+     * Boxes the given array of {@code int}s.
+     * 
+     * @param values
+     *            the values.
+     * @return the boxed values.
+     */
+    final public static Integer[] box(int[] values) {
+
+        int len = values.length;
+
+        Integer[] res = new Integer[len];
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[i];
+        }
+
+        return res;
+    }
+
+    /**
+     * Unboxes the given array of {@link Double}s.
+     * 
+     * @param values
+     *            the values.
+     * @return the unboxed values.
+     */
+    final public static double[] unbox(Double[] values) {
+
+        int len = values.length;
+
+        double[] res = new double[len];
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[i];
+        }
+
+        return res;
+    }
+
+    /**
+     * Unboxes the given array of {@link Integer}s.
+     * 
+     * @param values
+     *            the values.
+     * @return the unboxed values.
+     */
+    final public static int[] unbox(Integer[] values) {
+
+        int len = values.length;
+
+        int[] res = new int[len];
+
+        for (int i = 0; i < len; i++) {
+            res[i] = values[i];
+        }
+
+        return res;
+    }
+
+    /**
+     * Wraps the given value and trailing values as an array.
+     * 
+     * @param <T>
+     *            the component type.
+     * @param value
+     *            the head value.
+     * @param values
+     *            the trailing values.
+     * @return the array.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <T> T[] wrap(Class<T> clazz, T value, T... values) {
+
+        T[] res = (T[]) Array.newInstance(clazz, 1 + values.length);
+
+        res[0] = value;
+
+        System.arraycopy(values, 0, res, 1, values.length);
+
+        return res;
+    }
+
+    /**
+     * A facade for {@link #wrap(Class, Object, Object...)}.
+     */
+    @SuppressWarnings("unchecked")
+    final public static <T> T[] wrap(T value, T... values) {
+        return wrap((Class<T>) value.getClass(), value, values);
+    }
+
+    /**
+     * Compares two arrays of {@code double}s on the basis of lexicographic order.
+     * 
+     * @param lhs
+     *            the left hand side.
+     * @param rhs
+     *            the right hand side.
+     */
+    final public static int compare(double[] lhs, double[] rhs) {
+
+        for (int i = 0, n = Math.min(lhs.length, rhs.length); i < n; i++) {
+
+            int cmp = Double.compare(lhs[i], rhs[i]);
+
+            if (cmp != 0) {
+                return cmp;
+            }
+        }
+
+        return lhs.length - rhs.length;
+    }
+
+    /**
+     * Compares two arrays of {@code int}s on the basis of lexicographic order.
+     * 
+     * @param lhs
+     *            the left hand side.
+     * @param rhs
+     *            the right hand side.
+     */
+    final public static int compare(int[] lhs, int[] rhs) {
+
+        for (int i = 0, n = Math.min(lhs.length, rhs.length); i < n; i++) {
+
+            int cmp = lhs[i] - rhs[i];
+
+            if (cmp != 0) {
+                return cmp;
+            }
+        }
+
+        return lhs.length - rhs.length;
+    }
+
+    /**
+     * Compares two arrays of objects on the basis of lexicographic order.
+     * 
+     * @param lhs
+     *            the left hand side.
+     * @param rhs
+     *            the right hand side.
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T extends Comparable<? super T>> int compare(T[] lhs, T[] rhs) {
+
+        for (int i = 0, n = Math.min(lhs.length, rhs.length); i < n; i++) {
+
+            int cmp = lhs[i].compareTo(rhs[i]);
+
+            if (cmp != 0) {
+                return cmp;
+            }
+        }
+
+        return lhs.length - rhs.length;
+    }
+
+    /**
+     * Compares two arrays of objects on the basis of lexicographic order.
+     * 
+     * @param lhs
+     *            the left hand side.
+     * @param rhs
+     *            the right hand side.
+     * @param c
+     *            the {@link Comparator} to use.
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T> int compare(T[] lhs, T[] rhs, Comparator<? super T> c) {
+
+        for (int i = 0, n = Math.min(lhs.length, rhs.length); i < n; i++) {
+
+            int cmp = c.compare(lhs[i], rhs[i]);
+
+            if (cmp != 0) {
+                return cmp;
+            }
+        }
+
+        return lhs.length - rhs.length;
+    }
+
+    /**
+     * A variant of {@link java.util.Arrays#binarySearch(int[], int, int, int)} that finds the array index with value
+     * nearest to the given key, as determined by the provided {@link RoundingMode}.
+     * 
+     * @param values
+     *            the values.
+     * @param from
+     *            the search start index.
+     * @param to
+     *            the search end index.
+     * @param key
+     *            the key.
+     * @param rm
+     *            the {@link RoundingMode}.
+     * @return the "nearest" index.
+     */
+    final public static int binarySearchNearest(int[] values, int from, int to, int key, RoundingMode rm) {
+
+        Control.checkTrue(values.length > 0, //
+                "Array size must be positive");
+
+        int index = java.util.Arrays.binarySearch(values, from, to, key);
+
+        if (index >= 0) {
+
+            return index;
+
+        } else {
+
+            index = -index - 1;
+
+            int lower = Math.max(index - 1, 0);
+            int upper = Math.min(index, values.length - 1);
+
+            int diffLower = key - values[lower];
+            int diffUpper = values[upper] - key;
+
+            switch (rm) {
+
+            case DOWN:
+                return lower;
+
+            case UP:
+                return upper;
+
+            case HALF_DOWN:
+                return diffLower <= diffUpper ? lower : upper;
+
+            case HALF_UP:
+                return diffUpper <= diffLower ? upper : lower;
+
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+            }
+        }
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(int[], int, int, int, RoundingMode)}.
+     */
+    final public static int binarySearchNearest(int[] values, int to, int from, int key) {
+        return binarySearchNearest(values, to, from, key, RoundingMode.HALF_DOWN);
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(int[], int, int, int, RoundingMode)}.
+     */
+    final public static int binarySearchNearest(int[] values, int key, RoundingMode rm) {
+        return binarySearchNearest(values, 0, values.length, key, rm);
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(int[], int, int, int, RoundingMode)}.
+     */
+    final public static int binarySearchNearest(int[] values, int key) {
+        return binarySearchNearest(values, 0, values.length, key, RoundingMode.HALF_DOWN);
+    }
+
+    /**
+     * A variant of {@link java.util.Arrays#binarySearch(double[], int, int, double)} that finds the array index with
+     * value nearest to the given key, as determined by the provided {@link RoundingMode}.
+     * 
+     * @param values
+     *            the values.
+     * @param from
+     *            the search start index.
+     * @param to
+     *            the search end index.
+     * @param key
+     *            the key.
+     * @param rm
+     *            the {@link RoundingMode}.
+     * @return the "nearest" index.
+     */
+    final public static int binarySearchNearest(double[] values, int from, int to, double key, RoundingMode rm) {
+
+        Control.checkTrue(values.length > 0, //
+                "Array size must be positive");
+
+        int index = java.util.Arrays.binarySearch(values, from, to, key);
+
+        if (index >= 0) {
+
+            return index;
+
+        } else {
+
+            index = -index - 1;
+
+            int lower = Math.max(index - 1, 0);
+            int upper = Math.min(index, values.length - 1);
+
+            double diffLower = key - values[lower];
+            double diffUpper = values[upper] - key;
+
+            switch (rm) {
+
+            case DOWN:
+                return lower;
+
+            case UP:
+                return upper;
+
+            case HALF_DOWN:
+                return diffLower <= diffUpper ? lower : upper;
+
+            case HALF_UP:
+                return diffUpper <= diffLower ? upper : lower;
+
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+            }
+        }
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(double[], int, int, double, RoundingMode)}.
+     */
+    final public static int binarySearchNearest(double[] values, int to, int from, double key) {
+        return binarySearchNearest(values, to, from, key, RoundingMode.HALF_DOWN);
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(double[], int, int, double, RoundingMode)}.
+     */
+    final public static int binarySearchNearest(double[] values, double key, RoundingMode rm) {
+        return binarySearchNearest(values, 0, values.length, key, rm);
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(double[], int, int, double, RoundingMode)}.
+     */
+    final public static int binarySearchNearest(double[] values, double key) {
+        return binarySearchNearest(values, 0, values.length, key, RoundingMode.HALF_DOWN);
+    }
+
+    /**
+     * A variant of {@link java.util.Arrays#binarySearch(Object[], int, int, Object)} that finds the array index with
+     * value nearest to the given key, as determined by the provided {@link RoundingMode}.
+     * 
+     * @param values
+     *            the values.
+     * @param from
+     *            the search start index.
+     * @param to
+     *            the search end index.
+     * @param key
+     *            the key.
+     * @param rm
+     *            the {@link RoundingMode}.
+     * @param <T>
+     *            the component type.
+     * @return the "nearest" index.
+     */
+    final public static <T extends Comparable<? super T>> int binarySearchNearest(T[] values, int from, int to, //
+            T key, RoundingMode rm) {
+
+        Control.checkTrue(values.length > 0, //
+                "Array size must be positive");
+
+        int index = java.util.Arrays.binarySearch(values, from, to, key);
+
+        if (index >= 0) {
+
+            return index;
+
+        } else {
+
+            index = -index - 1;
+
+            int lower = Math.max(index - 1, 0);
+            int upper = Math.min(index, values.length - 1);
+
+            switch (rm) {
+
+            case DOWN:
+                return lower;
+
+            case UP:
+                return upper;
+
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+            }
+        }
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(Comparable[], int, int, Comparable, RoundingMode)}.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T extends Comparable<? super T>> int binarySearchNearest(T[] values, int to, int from, //
+            T key) {
+        return binarySearchNearest(values, to, from, key, RoundingMode.DOWN);
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(Comparable[], int, int, Comparable, RoundingMode)}.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T extends Comparable<? super T>> int binarySearchNearest(T[] values, T key, RoundingMode rm) {
+        return binarySearchNearest(values, 0, values.length, key, rm);
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(Comparable[], int, int, Comparable, RoundingMode)}.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T extends Comparable<? super T>> int binarySearchNearest(T[] values, T key) {
+        return binarySearchNearest(values, 0, values.length, key, RoundingMode.DOWN);
+    }
+
+    /**
+     * A variant of {@link java.util.Arrays#binarySearch(Object[], Object, Comparator)} that finds the array index with
+     * value nearest to the given key, as determined by the provided {@link RoundingMode}.
+     * 
+     * @param values
+     *            the values.
+     * @param key
+     *            the key.
+     * @param rm
+     *            the {@link RoundingMode}.
+     * @param c
+     *            the {@link Comparator} to use.
+     * @param <T>
+     *            the component type.
+     * @return the "nearest" index.
+     */
+    final public static <T> int binarySearchNearest(T[] values, T key, Comparator<? super T> c, RoundingMode rm) {
+
+        Control.checkTrue(values.length > 0, //
+                "Array size must be positive");
+
+        int index = java.util.Arrays.binarySearch(values, key, c);
+
+        if (index >= 0) {
+
+            return index;
+
+        } else {
+
+            index = -index - 1;
+
+            int lower = Math.max(index - 1, 0);
+            int upper = Math.min(index, values.length - 1);
+
+            switch (rm) {
+
+            case DOWN:
+                return lower;
+
+            case UP:
+                return upper;
+
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+            }
+        }
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(Object[], Object, Comparator)}.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T> int binarySearchNearest(T[] values, T key, Comparator<? super T> c) {
+        return binarySearchNearest(values, key, c, RoundingMode.DOWN);
+    }
+
+    /**
+     * A variant of {@link Collections#binarySearch(List, Object)} that finds the array index with value nearest to the
+     * given key, as determined by the provided {@link RoundingMode}.
+     * 
+     * @param values
+     *            the values.
+     * @param key
+     *            the key.
+     * @param rm
+     *            the {@link RoundingMode}.
+     * @param <T>
+     *            the component type.
+     * @return the "nearest" index.
+     */
+    final public static <T extends Comparable<? super T>> int binarySearchNearest(List<? extends T> values, T key, //
+            RoundingMode rm) {
+
+        Control.checkTrue(values.size() > 0, //
+                "List size must be positive");
+
+        int index = Collections.binarySearch(values, key);
+
+        if (index >= 0) {
+
+            return index;
+
+        } else {
+
+            index = -index - 1;
+
+            int lower = Math.max(index - 1, 0);
+            int upper = Math.min(index, values.size() - 1);
+
+            switch (rm) {
+
+            case DOWN:
+                return lower;
+
+            case UP:
+                return upper;
+
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+            }
+        }
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(List, Comparable, RoundingMode)}.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T extends Comparable<? super T>> int binarySearchNearest(List<? extends T> values, T key) {
+        return binarySearchNearest(values, key, RoundingMode.DOWN);
+    }
+
+    /**
+     * A variant of {@link Collections#binarySearch(List, Object, Comparator)} that finds the array index with value
+     * nearest to the given key, as determined by the provided {@link RoundingMode}.
+     * 
+     * @param values
+     *            the values.
+     * @param key
+     *            the key.
+     * @param rm
+     *            the {@link RoundingMode}.
+     * @param c
+     *            the {@link Comparator} to use.
+     * @param <T>
+     *            the component type.
+     * @return the "nearest" index.
+     */
+    final public static <T> int binarySearchNearest(List<? extends T> values, T key, Comparator<? super T> c, //
+            RoundingMode rm) {
+
+        Control.checkTrue(values.size() > 0, //
+                "List size must be positive");
+
+        int index = Collections.binarySearch(values, key, c);
+
+        if (index >= 0) {
+
+            return index;
+
+        } else {
+
+            index = -index - 1;
+
+            int lower = Math.max(index - 1, 0);
+            int upper = Math.min(index, values.size() - 1);
+
+            switch (rm) {
+
+            case DOWN:
+                return lower;
+
+            case UP:
+                return upper;
+
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+            }
+        }
+    }
+
+    /**
+     * A facade for {@link #binarySearchNearest(List, Object, Comparator, RoundingMode)}.
+     * 
+     * @param <T>
+     *            the component type.
+     */
+    final public static <T> int binarySearchNearest(List<? extends T> values, T key, Comparator<? super T> c) {
+        return binarySearchNearest(values, key, c, RoundingMode.DOWN);
+    }
+
+    // Dummy constructor.
+    Arrays() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Control.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Control.java
new file mode 100755
index 0000000..cf44b3d
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Control.java
@@ -0,0 +1,1053 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * A collection of useful static methods for control flow.
+ * 
+ * @author Roy Liu
+ */
+public class Control {
+
+    /**
+     * The bulk transfer size for {@link InputStream}s and {@link OutputStream}s.
+     */
+    final protected static int BULK_TRANSFER_SIZE = 1 << 16;
+
+    /**
+     * A null {@link OutputStream} to which writes have no effect.
+     */
+    final public static OutputStream NullOutputStream = new OutputStream() {
+
+        @Override
+        public void write(int b) throws IOException {
+        }
+    };
+
+    /**
+     * A null {@link InputStream} that has nothing to read.
+     */
+    final public static InputStream NullInputStream = new InputStream() {
+
+        @Override
+        public int read() throws IOException {
+            return -1;
+        }
+    };
+
+    /**
+     * A null {@link Runnable} that has an empty {@link Runnable#run()} method.
+     */
+    final public static Runnable NullRunnable = new Runnable() {
+
+        public void run() {
+        }
+    };
+
+    /**
+     * A timestamp local to the current thread in support of {@link #tick()} and {@link #tock()}.
+     */
+    final protected static ThreadLocal<Long> TimeStampLocal = new ThreadLocal<Long>();
+
+    /**
+     * A mapping of environment variables local to the current thread in support of {@link #beginEnvironment()} and
+     * {@link #endEnvironment()}.
+     */
+    final protected static ThreadLocal<Map<String, String>> EnvironmentLocal = new ThreadLocal<Map<String, String>>();
+
+    /**
+     * An implementation of {@link EntityResolver} that finds external entities on the class path of the current
+     * thread's context class loader.
+     */
+    final public static EntityResolver ClasspathResolver = new EntityResolver() {
+
+        public InputSource resolveEntity(String publicId, String systemId) {
+
+            String classpathStr = "classpath://";
+
+            if (!systemId.startsWith(classpathStr)) {
+                return null;
+            }
+
+            InputStream in = Thread.currentThread().getContextClassLoader() //
+                    .getResourceAsStream(systemId.substring(classpathStr.length()));
+            return (in != null) ? new InputSource(in) : null;
+        }
+    };
+
+    /**
+     * An implementation of {@link ErrorHandler} that immediately throws any {@link SAXException} passed to it,
+     * regardless of severity.
+     */
+    final public static ErrorHandler DefaultErrorHandler = new ErrorHandler() {
+
+        public void error(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+
+        public void fatalError(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+
+        public void warning(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+    };
+
+    /**
+     * A {@link DocumentBuilder} local to the current thread.
+     */
+    final protected static ThreadLocal<DocumentBuilder> BuilderLocal = new ThreadLocal<DocumentBuilder>() {
+
+        @Override
+        protected DocumentBuilder initialValue() {
+
+            final DocumentBuilder db;
+
+            try {
+
+                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+                dbf.setValidating(true);
+                dbf.setIgnoringElementContentWhitespace(true);
+
+                dbf.setFeature("http://apache.org/xml/features/validation/dynamic", true);
+
+                db = dbf.newDocumentBuilder();
+                db.setEntityResolver(ClasspathResolver);
+                db.setErrorHandler(DefaultErrorHandler);
+
+            } catch (ParserConfigurationException e) {
+
+                throw new RuntimeException(e);
+            }
+
+            return db;
+        }
+    };
+
+    /**
+     * A {@link Transformer} local to the current thread.
+     */
+    final protected static ThreadLocal<Transformer> TransformerLocal = new ThreadLocal<Transformer>() {
+
+        @Override
+        protected Transformer initialValue() {
+
+            try {
+
+                return TransformerFactory.newInstance().newTransformer();
+
+            } catch (TransformerConfigurationException e) {
+
+                throw new RuntimeException(e);
+            }
+        }
+    };
+
+    /**
+     * The system-dependent line separator.
+     */
+    final public static String LineSeparator = System.getProperty("line.separator");
+
+    /**
+     * A {@link Closeable#close()} convenience wrapper.
+     */
+    final public static void close(Closeable closeable) {
+
+        if (closeable != null) {
+
+            try {
+
+                closeable.close();
+
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Sleeps for the given number of milliseconds.
+     */
+    final public static void sleep(long millis) {
+
+        try {
+
+            Thread.sleep(millis);
+
+        } catch (InterruptedException e) {
+        }
+    }
+
+    /**
+     * Creates an unmodifiable {@link Iterator} from a possibly modifiable one.
+     * 
+     * @param <T>
+     *            the parameterization.
+     * @param itr
+     *            the original {@link Iterator}.
+     * @return an unmodifiable {@link Iterator} view.
+     */
+    final public static <T> Iterator<T> unmodifiableIterator(final Iterator<T> itr) {
+
+        return new Iterator<T>() {
+
+            public boolean hasNext() {
+                return itr.hasNext();
+            }
+
+            public T next() {
+                return itr.next();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Iterator is unmodifiable");
+            }
+        };
+    }
+
+    /**
+     * Starts the timer for {@link Thread#currentThread()}.
+     */
+    final public static void tick() {
+
+        Control.checkTrue(TimeStampLocal.get() == null, //
+                "Must call tock() before tick()");
+
+        TimeStampLocal.set(System.currentTimeMillis());
+    }
+
+    /**
+     * Stops the timer for {@link Thread#currentThread()}.
+     * 
+     * @return the (wall clock) time elapsed.
+     */
+    final public static long tock() {
+
+        Long timeStamp = TimeStampLocal.get();
+
+        Control.checkTrue(timeStamp != null, //
+                "Must call tick() before tock()");
+
+        TimeStampLocal.set(null);
+
+        return System.currentTimeMillis() - timeStamp;
+    }
+
+    /**
+     * Deletes a file or directory. If a directory, then recursively deletes the contents while not following symbolic
+     * links.
+     * 
+     * @param f
+     *            the file or directory.
+     * @return whether the file or directory was deleted.
+     */
+    final public static boolean delete(File f) {
+
+        if (f.isDirectory()) {
+
+            try {
+
+                File absoluteFile = f.getAbsoluteFile();
+                File canonicalFile = f.getCanonicalFile();
+                File absoluteParent = absoluteFile.getParentFile().getCanonicalFile();
+                File canonicalParent = canonicalFile.getParentFile();
+
+                // The file is a symbolic link if and only if the names don't match and/or the parent
+                // directories don't match.
+                if (!absoluteParent.equals(canonicalParent) //
+                        || !absoluteFile.getName().equals(canonicalFile.getName())) {
+                    return false;
+                }
+
+                for (File file : f.listFiles()) {
+                    delete(file);
+                }
+
+            } catch (IOException e) {
+
+                return false;
+            }
+        }
+
+        return f.delete();
+    }
+
+    /**
+     * Transfers the contents of one stream into another.
+     * 
+     * @param in
+     *            the {@link InputStream}.
+     * @param out
+     *            the {@link OutputStream}.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(InputStream in, OutputStream out) throws IOException {
+
+        byte[] transferBuf = new byte[BULK_TRANSFER_SIZE];
+
+        for (int size; (size = in.read(transferBuf)) >= 0;) {
+            out.write(transferBuf, 0, size);
+        }
+
+        out.flush();
+    }
+
+    /**
+     * Transfers the contents of a file into a stream.
+     * 
+     * @param inFile
+     *            the input {@link File}.
+     * @param out
+     *            the {@link OutputStream}.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(File inFile, OutputStream out) throws IOException {
+
+        InputStream in = new FileInputStream(inFile);
+
+        transfer(in, out);
+
+        close(in);
+    }
+
+    /**
+     * Transfers the contents of a stream into a file.
+     * 
+     * @param in
+     *            the {@link InputStream}.
+     * @param outFile
+     *            the output {@link File}.
+     * @param append
+     *            whether this operation overwrites the file, or merely appends onto the end.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(InputStream in, File outFile, boolean append) throws IOException {
+
+        OutputStream out = new FileOutputStream(outFile, append);
+
+        transfer(in, out);
+
+        close(out);
+    }
+
+    /**
+     * Transfers the contents of a file into a file.
+     * 
+     * @param inFile
+     *            the input {@link File}.
+     * @param outFile
+     *            the output {@link File}.
+     * @param append
+     *            whether this operation overwrites the file, or merely appends onto the end.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(File inFile, File outFile, boolean append) throws IOException {
+
+        InputStream in = new FileInputStream(inFile);
+
+        transfer(in, outFile, append);
+
+        close(in);
+    }
+
+    /**
+     * Transfers the contents of a stream into a file without appending.
+     * 
+     * @param in
+     *            the {@link InputStream}.
+     * @param outFile
+     *            the output {@link File}.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(InputStream in, File outFile) throws IOException {
+        transfer(in, outFile, false);
+    }
+
+    /**
+     * Transfers the contents of a file into a file without appending.
+     * 
+     * @param inFile
+     *            the input {@link File}.
+     * @param outFile
+     *            the output {@link File}.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(File inFile, File outFile) throws IOException {
+
+        InputStream in = new FileInputStream(inFile);
+
+        transfer(in, outFile, false);
+
+        close(in);
+    }
+
+    /**
+     * Transfers the contents of a {@code byte} array into a stream.
+     * 
+     * @param bytes
+     *            the {@code byte} array.
+     * @param out
+     *            the {@link OutputStream}.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(byte[] bytes, OutputStream out) throws IOException {
+
+        InputStream in = new ByteArrayInputStream(bytes);
+
+        transfer(in, out);
+
+        close(in);
+    }
+
+    /**
+     * Transfers the contents of a {@code byte} array into a file.
+     * 
+     * @param bytes
+     *            the {@code byte} array.
+     * @param outFile
+     *            the output {@link File}.
+     * @param append
+     *            whether this operation overwrites the file, or merely appends onto the end.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(byte[] bytes, File outFile, boolean append) throws IOException {
+
+        InputStream in = new ByteArrayInputStream(bytes);
+
+        transfer(in, outFile, append);
+
+        close(in);
+    }
+
+    /**
+     * Transfers the contents of a {@code byte} array into a file without appending.
+     * 
+     * @param bytes
+     *            the {@code byte} array.
+     * @param outFile
+     *            the output {@link File}.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static void transfer(byte[] bytes, File outFile) throws IOException {
+
+        InputStream in = new ByteArrayInputStream(bytes);
+
+        transfer(in, outFile, false);
+
+        close(in);
+    }
+
+    /**
+     * Gets a {@code byte} array from the given stream.
+     * 
+     * @param in
+     *            the {@link InputStream}.
+     * @return the {@code byte} array.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static byte[] getBytes(InputStream in) throws IOException {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        transfer(in, out);
+
+        return out.toByteArray();
+    }
+
+    /**
+     * Gets a {@code byte} array from the given file.
+     * 
+     * @param inFile
+     *            the input {@link File}.
+     * @return the {@code byte} array.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static byte[] getBytes(File inFile) throws IOException {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        transfer(inFile, out);
+
+        return out.toByteArray();
+    }
+
+    /**
+     * Checks if a condition is {@code true}.
+     */
+    final public static void checkTrue(boolean value) {
+        ensureTrue(value, false, "Check failed");
+    }
+
+    /**
+     * Asserts that a condition is {@code true}.
+     */
+    final public static void assertTrue(boolean value) {
+        ensureTrue(value, true, "Assertion failed");
+    }
+
+    /**
+     * Checks if two {@code int}s are equal.
+     * 
+     * @param a
+     *            the first argument.
+     * @param b
+     *            the second argument.
+     * @return the equality value, if success.
+     */
+    final public static int checkEquals(int a, int b) {
+        return checkEquals(a, b, "Check failed");
+    }
+
+    /**
+     * Checks if two objects are equal.
+     * 
+     * @param <T>
+     *            the object parameterization.
+     * @param a
+     *            the first argument.
+     * @param b
+     *            the second argument.
+     * @return the equality value, if success.
+     */
+    final public static <T> T checkEquals(T a, T b) {
+        return checkEquals(a, b, "Check failed");
+    }
+
+    /**
+     * Checks if a condition is {@code true}.
+     * 
+     * @param value
+     *            the truth value to check.
+     * @param message
+     *            the failure message.
+     */
+    final public static void checkTrue(boolean value, String message) {
+        ensureTrue(value, false, message);
+    }
+
+    /**
+     * Checks if two {@code int}s are equal.
+     * 
+     * @param a
+     *            the first argument.
+     * @param b
+     *            the second argument.
+     * @param message
+     *            the failure message.
+     * @return the equality value, if success.
+     */
+    final public static int checkEquals(int a, int b, String message) {
+
+        final int n;
+
+        ensureTrue((n = a) == b, false, message);
+
+        return n;
+    }
+
+    /**
+     * Checks if two objects are equal.
+     * 
+     * @param <T>
+     *            the object parameterization.
+     * @param a
+     *            the first argument.
+     * @param b
+     *            the second argument.
+     * @param message
+     *            the failure message.
+     * @return the equality value, if success.
+     */
+    final public static <T> T checkEquals(T a, T b, String message) {
+
+        final T val;
+
+        ensureTrue(((val = a) != null) ? a.equals(b) : (b == null), false, message);
+
+        return val;
+    }
+
+    /**
+     * An internal check/assert method that backs the likes of {@link #checkTrue(boolean)} and
+     * {@link #assertTrue(boolean)}.
+     * 
+     * @param value
+     *            the truth value.
+     * @param isAssertion
+     *            if a failed check results in an {@link AssertionError}.
+     * @param message
+     *            the failure message.
+     * @throws RuntimeException
+     *             when a check fails.
+     * @throws AssertionError
+     *             when an assertion fails.
+     */
+    final protected static void ensureTrue(boolean value, boolean isAssertion, String message) //
+            throws RuntimeException, AssertionError {
+
+        if (!value) {
+
+            if (isAssertion) {
+
+                throw new AssertionError(message);
+
+            } else {
+
+                throw new RuntimeException(message);
+            }
+        }
+    }
+
+    /**
+     * Rethrows the given exception. Checked exceptions are wrapped with a {@link RuntimeException}.
+     * 
+     * @param t
+     *            the exception.
+     * @throws RuntimeException
+     *             when a {@link RuntimeException} has occurred.
+     * @throws Error
+     *             when an {@link Error} has occurred.
+     */
+    final public static void rethrow(Throwable t) throws RuntimeException, Error {
+
+        if (t instanceof RuntimeException) {
+
+            throw (RuntimeException) t;
+
+        } else if (t instanceof Error) {
+
+            throw (Error) t;
+
+        } else {
+
+            throw new RuntimeException(t);
+        }
+    }
+
+    /**
+     * Forks and waits on a new {@link Process}.
+     * 
+     * @param parentIn
+     *            the {@link InputStream} that contains the child's input.
+     * @param parentOut
+     *            the {@link OutputStream} that receives the child's output.
+     * @param parentError
+     *            the {@link OutputStream} that receives the child's error output.
+     * @param execArgs
+     *            the command and arguments to execute.
+     * @return the return code of the child process.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static int execAndWaitFor(final InputStream parentIn, //
+            final OutputStream parentOut, final OutputStream parentError, String... execArgs) throws IOException {
+
+        ProcessBuilder pb = new ProcessBuilder(execArgs);
+
+        Process p = null;
+
+        final AtomicReference<IOException> childThreadException = new AtomicReference<IOException>(null);
+
+        try {
+
+            Map<String, String> env = EnvironmentLocal.get();
+
+            if (env != null) {
+                pb.environment().putAll(env);
+            }
+
+            p = pb.start();
+
+            final OutputStream out = p.getOutputStream();
+            final InputStream in = p.getInputStream();
+            final InputStream error = p.getErrorStream();
+
+            Thread t1 = new Thread("Process Writer") {
+
+                @Override
+                public void run() {
+
+                    try {
+
+                        transfer(parentIn, out);
+
+                    } catch (IOException e) {
+
+                        childThreadException.compareAndSet(null, e);
+
+                    } finally {
+
+                        // Close the child's input.
+                        Control.close(out);
+                    }
+                }
+            };
+
+            t1.start();
+
+            Thread t2 = new Thread("Process Reader") {
+
+                @Override
+                public void run() {
+
+                    try {
+
+                        transfer(in, parentOut);
+
+                    } catch (IOException e) {
+
+                        childThreadException.compareAndSet(null, e);
+                    }
+                }
+
+            };
+
+            t2.start();
+
+            Thread t3 = new Thread("Process Error Reader") {
+
+                @Override
+                public void run() {
+
+                    try {
+
+                        transfer(error, parentError);
+
+                    } catch (IOException e) {
+
+                        childThreadException.compareAndSet(null, e);
+                    }
+                }
+
+            };
+
+            t3.start();
+
+            retry: for (;;) {
+
+                try {
+
+                    int rc = p.waitFor();
+
+                    // Join with the thread that writes to the child's input.
+                    t1.join();
+
+                    // Join with the thread that reads from the child's output.
+                    t2.join();
+
+                    // Join with the thread that reads from the child's error output.
+                    t3.join();
+
+                    IOException ex = childThreadException.get();
+
+                    if (ex != null) {
+                        throw ex;
+                    }
+
+                    return rc;
+
+                } catch (InterruptedException e) {
+
+                    continue retry;
+                }
+            }
+
+        } finally {
+
+            if (p != null) {
+                p.destroy();
+            }
+        }
+    }
+
+    /**
+     * Forks and waits on a new {@link Process}.
+     * 
+     * @param execArgs
+     *            the command and arguments to execute.
+     * @return the return code of the child process.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static int execAndWaitFor(String... execArgs) throws IOException {
+        return execAndWaitFor(NullInputStream, NullOutputStream, NullOutputStream, execArgs);
+    }
+
+    /**
+     * Forks and waits on a new {@link Process}.
+     * 
+     * @param parentIn
+     *            the {@link InputStream} that contains the child's input.
+     * @param execArgs
+     *            the command and arguments to execute.
+     * @return the return code of the child process.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static int execAndWaitFor(InputStream parentIn, String... execArgs) throws IOException {
+        return execAndWaitFor(parentIn, NullOutputStream, NullOutputStream, execArgs);
+    }
+
+    /**
+     * Forks and waits on a new {@link Process}.
+     * 
+     * @param parentOut
+     *            the {@link OutputStream} that receives the child's output.
+     * @param execArgs
+     *            the command and arguments to execute.
+     * @return the return code of the child process.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static int execAndWaitFor(OutputStream parentOut, String... execArgs) throws IOException {
+        return execAndWaitFor(NullInputStream, parentOut, parentOut, execArgs);
+    }
+
+    /**
+     * Forks and waits on a new {@link Process}.
+     * 
+     * @param parentIn
+     *            the {@link InputStream} that contains the child's input.
+     * @param parentOut
+     *            the {@link OutputStream} that receives the child's output.
+     * @param execArgs
+     *            the command and arguments to execute.
+     * @return the return code of the child process.
+     * @throws IOException
+     *             when something goes awry.
+     */
+    final public static int execAndWaitFor(InputStream parentIn, OutputStream parentOut, String... execArgs)
+            throws IOException {
+        return execAndWaitFor(parentIn, parentOut, parentOut, execArgs);
+    }
+
+    /**
+     * Begins building the mapping of environment variables for {@link Thread#currentThread()}.
+     */
+    final public static Map<String, String> beginEnvironment() {
+
+        Control.checkTrue(EnvironmentLocal.get() == null, //
+                "Must call endEnvironment() before beginEnvironment()");
+
+        Map<String, String> env = new HashMap<String, String>();
+
+        EnvironmentLocal.set(env);
+
+        return env;
+    }
+
+    /**
+     * Ends building the mapping of environment variables for {@link Thread#currentThread()}.
+     */
+    final public static void endEnvironment() {
+
+        Control.checkTrue(EnvironmentLocal.get() != null, //
+                "Must call beginEnvironment() before endEnvironment()");
+
+        EnvironmentLocal.set(null);
+    }
+
+    /**
+     * Creates a pool of daemon worker threads.
+     * 
+     * @param ncoreThreads
+     *            the number of core threads.
+     * @param nmaxThreads
+     *            the maximum number of threads.
+     * @param workQueue
+     *            the {@link BlockingQueue} to which work is submitted.
+     * @param h
+     *            the handler to invoke when a worker thread dies horribly.
+     * @return the pool.
+     */
+    final public static ThreadPoolExecutor createPool(int ncoreThreads, int nmaxThreads, //
+            BlockingQueue<Runnable> workQueue, final UncaughtExceptionHandler h) {
+
+        return new ThreadPoolExecutor(ncoreThreads, nmaxThreads, //
+                (ncoreThreads < nmaxThreads) ? 60000L : 0L, //
+                TimeUnit.MILLISECONDS, workQueue, //
+
+                new ThreadFactory() {
+
+                    volatile int threadCount = 0;
+
+                    public Thread newThread(Runnable r) {
+
+                        Thread t = new Thread(r, String.format("Thread Pool Worker #%d", this.threadCount++));
+                        t.setDaemon(true);
+                        t.setUncaughtExceptionHandler(h);
+
+                        return t;
+                    }
+                } //
+        );
+    }
+
+    /**
+     * Creates a pool of daemon worker threads.
+     * 
+     * @param ncoreThreads
+     *            the number of core threads.
+     * @return the pool.
+     */
+    final public static ThreadPoolExecutor createPool(int ncoreThreads) {
+        return createPool(ncoreThreads, ncoreThreads, //
+                new LinkedBlockingQueue<Runnable>(), null);
+    }
+
+    /**
+     * Creates a pool of daemon worker threads of size {@link Runtime#availableProcessors()}.
+     * 
+     * @return the pool.
+     */
+    final public static ThreadPoolExecutor createPool() {
+
+        int ncoreThreads = Runtime.getRuntime().availableProcessors();
+        return createPool(ncoreThreads, ncoreThreads, //
+                new LinkedBlockingQueue<Runnable>(), null);
+    }
+
+    /**
+     * Creates a {@link Document}.
+     */
+    final public static Document createDocument() {
+        return BuilderLocal.get().newDocument();
+    }
+
+    /**
+     * Creates a {@link Document} from the given {@code byte} array.
+     */
+    final public static Document createDocument(byte[] array) {
+        return createDocument(new ByteArrayInputStream(array));
+    }
+
+    /**
+     * Creates a {@link Document} from the given string.
+     */
+    final public static Document createDocument(String data) {
+        return createDocument(new ByteArrayInputStream(data.getBytes()));
+    }
+
+    /**
+     * Creates a {@link Document} from the given file.
+     */
+    final public static Document createDocument(File file) {
+
+        final FileInputStream fin;
+
+        try {
+
+            fin = new FileInputStream(file);
+
+        } catch (IOException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        return createDocument(fin);
+    }
+
+    /**
+     * Creates a {@link Document} from the given {@link InputStream}.
+     */
+    final public static Document createDocument(InputStream in) {
+
+        try {
+
+            return BuilderLocal.get().parse(in);
+
+        } catch (Exception e) {
+
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Converts the given {@link Document} to a string.
+     */
+    final public static String toString(Node node) {
+
+        StringWriter sw = new StringWriter();
+
+        try {
+
+            TransformerLocal.get().transform(new DOMSource(node), new StreamResult(sw));
+
+        } catch (TransformerException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        return sw.toString();
+    }
+
+    // Dummy constructor.
+    Control() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/CoreThread.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/CoreThread.java
new file mode 100755
index 0000000..72a008d
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/CoreThread.java
@@ -0,0 +1,80 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+/**
+ * A thread convenience class that has a {@code try}-{@code catch}-{@code finally} pattern built into its
+ * {@link Runnable#run()} method.
+ * 
+ * @author Roy Liu
+ */
+abstract public class CoreThread extends Thread {
+
+    /**
+     * Default constructor.
+     * 
+     * @param name
+     *            the name of this thread.
+     */
+    public CoreThread(String name) {
+        super(name);
+    }
+
+    /**
+     * Houses the {@code try}-{@code catch}-{@code finally} pattern.
+     */
+    @Override
+    public void run() {
+
+        try {
+
+            runUnchecked();
+
+        } catch (Throwable t) {
+
+            runCatch(t);
+
+        } finally {
+
+            runFinalizer();
+        }
+    }
+
+    /**
+     * Runs the main body of code and passes any uncaught exceptions up to the {@link Runnable#run()} method.
+     * 
+     * @throws Exception
+     *             the deferred exception.
+     */
+    abstract protected void runUnchecked() throws Exception;
+
+    /**
+     * Runs the exception handler. The default behavior is wrap the given {@link Throwable} in a
+     * {@link RuntimeException} and throw that.
+     */
+    protected void runCatch(Throwable t) {
+        Control.rethrow(t);
+    }
+
+    /**
+     * Runs the finalizer. Guaranteed to execute on termination of {@link #runUnchecked()}. The default behavior is to
+     * do nothing.
+     */
+    protected void runFinalizer() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicArray.java
new file mode 100755
index 0000000..9f4792e
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicArray.java
@@ -0,0 +1,84 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+/**
+ * Defines an array that can grow and shrink dynamically.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link DynamicArray} itself.
+ * @param <V>
+ *            the storage array type.
+ * @param <E>
+ *            the component type.
+ * @author Roy Liu
+ */
+public interface DynamicArray<T extends DynamicArray<T, V, E>, V, E> extends Cloneable {
+
+    /**
+     * Clears this array.
+     * 
+     * @return this array.
+     */
+    public T clear();
+
+    /**
+     * Ensures that this array has at least the given capacity.
+     * 
+     * @param capacity
+     *            the desired capacity.
+     * @return this array.
+     */
+    public T ensureCapacity(int capacity);
+
+    /**
+     * Gets the number of elements.
+     * 
+     * @return the number of elements.
+     */
+    public int size();
+
+    /**
+     * Gets the capacity.
+     * 
+     * @return the capacity.
+     */
+    public int capacity();
+
+    /**
+     * Gets the storage array truncated to the current size.
+     * 
+     * @return a truncated copy of the storage array.
+     */
+    public V values();
+
+    /**
+     * Gets the component type.
+     */
+    public Class<E> getComponentType();
+
+    /**
+     * Creates a human-readable representation of this array.
+     */
+    public String toString();
+
+    /**
+     * Clones this array.
+     */
+    public T clone();
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicDoubleArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicDoubleArray.java
new file mode 100755
index 0000000..e692048
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicDoubleArray.java
@@ -0,0 +1,158 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.util.Arrays;
+
+/**
+ * An implementation of {@link DynamicArray} for {@code double}s.
+ * 
+ * @author Roy Liu
+ */
+public class DynamicDoubleArray implements DynamicArray<DynamicDoubleArray, double[], Double> {
+
+    /**
+     * The initial capacity.
+     */
+    final public static int INITIAL_CAPACITY = 127;
+
+    double[] values;
+
+    int size;
+
+    /**
+     * Default constructor.
+     */
+    public DynamicDoubleArray() {
+        this(INITIAL_CAPACITY);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public DynamicDoubleArray(int capacity) {
+
+        this.values = new double[capacity];
+        this.size = 0;
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    protected DynamicDoubleArray(double[] values, int size) {
+
+        this.values = values;
+        this.size = size;
+    }
+
+    /**
+     * Gets the value at the given index.
+     */
+    public double get(int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        return this.values[index];
+    }
+
+    /**
+     * Sets a value at the given index.
+     */
+    public DynamicDoubleArray push(double value, int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        this.values[index] = value;
+
+        return this;
+    }
+
+    /**
+     * Pops off the last pushed on value.
+     */
+    public double pop() {
+
+        Control.checkTrue(this.size > 0, //
+                "No more elements");
+
+        if (this.size <= (this.values.length + 1) >>> 2) {
+            this.values = Arrays.copyOf(this.values, this.values.length >>> 1);
+        }
+
+        return this.values[--this.size];
+    }
+
+    /**
+     * Pushes on a value.
+     */
+    public DynamicDoubleArray push(double value) {
+
+        if (this.size == this.values.length) {
+            this.values = Arrays.copyOf(this.values, 2 * this.values.length + 1);
+        }
+
+        this.values[this.size++] = value;
+
+        return this;
+    }
+
+    public DynamicDoubleArray clear() {
+
+        this.values = new double[INITIAL_CAPACITY];
+        this.size = 0;
+
+        return this;
+    }
+
+    public DynamicDoubleArray ensureCapacity(int capacity) {
+
+        this.values = (this.values.length < capacity) ? Arrays.copyOf(this.values, capacity) : this.values;
+
+        return this;
+    }
+
+    public int size() {
+        return this.size;
+    }
+
+    public int capacity() {
+        return this.values.length;
+    }
+
+    public double[] values() {
+        return Arrays.copyOf(this.values, this.size);
+    }
+
+    public Class<Double> getComponentType() {
+        return Double.class;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s[size = %d, capacity = %d, values = %s]", //
+                DynamicDoubleArray.class.getSimpleName(), //
+                size(), capacity(), Arrays.toString(values()));
+    }
+
+    @Override
+    public DynamicDoubleArray clone() {
+        return new DynamicDoubleArray(this.values.clone(), this.size);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicIntArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicIntArray.java
new file mode 100755
index 0000000..610113a
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicIntArray.java
@@ -0,0 +1,158 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.util.Arrays;
+
+/**
+ * An implementation of {@link DynamicArray} for {@code int}s.
+ * 
+ * @author Roy Liu
+ */
+public class DynamicIntArray implements DynamicArray<DynamicIntArray, int[], Integer> {
+
+    /**
+     * The initial capacity.
+     */
+    final public static int INITIAL_CAPACITY = 255;
+
+    int[] values;
+
+    int size;
+
+    /**
+     * Default constructor.
+     */
+    public DynamicIntArray() {
+        this(INITIAL_CAPACITY);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public DynamicIntArray(int capacity) {
+
+        this.values = new int[capacity];
+        this.size = 0;
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    protected DynamicIntArray(int[] values, int size) {
+
+        this.values = values;
+        this.size = size;
+    }
+
+    /**
+     * Gets the value at the given index.
+     */
+    public double get(int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        return this.values[index];
+    }
+
+    /**
+     * Sets a value at the given index.
+     */
+    public DynamicIntArray push(int value, int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        this.values[index] = value;
+
+        return this;
+    }
+
+    /**
+     * Pops off the last pushed on value.
+     */
+    public int pop() {
+
+        Control.checkTrue(this.size > 0, //
+                "No more elements");
+
+        if (this.size <= (this.values.length + 1) >>> 2) {
+            this.values = Arrays.copyOf(this.values, this.values.length >>> 1);
+        }
+
+        return this.values[--this.size];
+    }
+
+    /**
+     * Pushes on a value.
+     */
+    public DynamicIntArray push(int value) {
+
+        if (this.size == this.values.length) {
+            this.values = Arrays.copyOf(this.values, 2 * this.values.length + 1);
+        }
+
+        this.values[this.size++] = value;
+
+        return this;
+    }
+
+    public DynamicIntArray clear() {
+
+        this.values = new int[INITIAL_CAPACITY];
+        this.size = 0;
+
+        return this;
+    }
+
+    public DynamicIntArray ensureCapacity(int capacity) {
+
+        this.values = (this.values.length < capacity) ? Arrays.copyOf(this.values, capacity) : this.values;
+
+        return this;
+    }
+
+    public int size() {
+        return this.size;
+    }
+
+    public int capacity() {
+        return this.values.length;
+    }
+
+    public int[] values() {
+        return Arrays.copyOf(this.values, this.size);
+    }
+
+    public Class<Integer> getComponentType() {
+        return Integer.class;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s[size = %d, capacity = %d, values = %s]", //
+                DynamicIntArray.class.getSimpleName(), //
+                size(), capacity(), Arrays.toString(values()));
+    }
+
+    @Override
+    public DynamicIntArray clone() {
+        return new DynamicIntArray(this.values.clone(), this.size);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicLongArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicLongArray.java
new file mode 100755
index 0000000..a78c817
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicLongArray.java
@@ -0,0 +1,158 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.util.Arrays;
+
+/**
+ * An implementation of {@link DynamicArray} for {@code long}s.
+ * 
+ * @author Roy Liu
+ */
+public class DynamicLongArray implements DynamicArray<DynamicLongArray, long[], Long> {
+
+    /**
+     * The initial capacity.
+     */
+    final public static int INITIAL_CAPACITY = 127;
+
+    long[] values;
+
+    int size;
+
+    /**
+     * Default constructor.
+     */
+    public DynamicLongArray() {
+        this(INITIAL_CAPACITY);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    public DynamicLongArray(int capacity) {
+
+        this.values = new long[capacity];
+        this.size = 0;
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    protected DynamicLongArray(long[] values, int size) {
+
+        this.values = values;
+        this.size = size;
+    }
+
+    /**
+     * Gets the value at the given index.
+     */
+    public long get(int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        return this.values[index];
+    }
+
+    /**
+     * Sets a value at the given index.
+     */
+    public DynamicLongArray push(long value, int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        this.values[index] = value;
+
+        return this;
+    }
+
+    /**
+     * Pops off the last pushed on value.
+     */
+    public long pop() {
+
+        Control.checkTrue(this.size > 0, //
+                "No more elements");
+
+        if (this.size <= (this.values.length + 1) >>> 2) {
+            this.values = Arrays.copyOf(this.values, this.values.length >>> 1);
+        }
+
+        return this.values[--this.size];
+    }
+
+    /**
+     * Pushes on a value.
+     */
+    public DynamicLongArray push(long value) {
+
+        if (this.size == this.values.length) {
+            this.values = Arrays.copyOf(this.values, 2 * this.values.length + 1);
+        }
+
+        this.values[this.size++] = value;
+
+        return this;
+    }
+
+    public DynamicLongArray clear() {
+
+        this.values = new long[INITIAL_CAPACITY];
+        this.size = 0;
+
+        return this;
+    }
+
+    public DynamicLongArray ensureCapacity(int capacity) {
+
+        this.values = (this.values.length < capacity) ? Arrays.copyOf(this.values, capacity) : this.values;
+
+        return this;
+    }
+
+    public int size() {
+        return this.size;
+    }
+
+    public int capacity() {
+        return this.values.length;
+    }
+
+    public long[] values() {
+        return Arrays.copyOf(this.values, this.size);
+    }
+
+    public Class<Long> getComponentType() {
+        return Long.class;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s[size = %d, capacity = %d, values = %s]", //
+                DynamicLongArray.class.getSimpleName(), //
+                size(), capacity(), Arrays.toString(values()));
+    }
+
+    @Override
+    public DynamicLongArray clone() {
+        return new DynamicLongArray(this.values.clone(), this.size);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicObjectArray.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicObjectArray.java
new file mode 100755
index 0000000..7787bff
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/DynamicObjectArray.java
@@ -0,0 +1,164 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+/**
+ * An implementation of {@link DynamicArray} for objects.
+ * 
+ * @param <T>
+ *            the component type.
+ * @author Roy Liu
+ */
+public class DynamicObjectArray<T> implements DynamicArray<DynamicObjectArray<T>, T[], T> {
+
+    /**
+     * The initial capacity.
+     */
+    final public static int INITIAL_CAPACITY = 127;
+
+    T[] values;
+
+    int size;
+
+    /**
+     * Default constructor.
+     */
+    public DynamicObjectArray(Class<T> clazz) {
+        this(clazz, INITIAL_CAPACITY);
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    @SuppressWarnings("unchecked")
+    public DynamicObjectArray(Class<T> clazz, int capacity) {
+
+        this.values = (T[]) Array.newInstance(clazz, capacity);
+        this.size = 0;
+    }
+
+    /**
+     * Alternate constructor.
+     */
+    protected DynamicObjectArray(T[] values, int size) {
+
+        this.values = values;
+        this.size = size;
+    }
+
+    /**
+     * Gets the value at the given index.
+     */
+    public T get(int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        return this.values[index];
+    }
+
+    /**
+     * Sets a value at the given index.
+     */
+    public DynamicObjectArray<T> push(T value, int index) {
+
+        Control.checkTrue(index >= 0 && index < this.size, //
+                "Invalid index");
+
+        this.values[index] = value;
+
+        return this;
+    }
+
+    /**
+     * Pops off the last pushed on value.
+     */
+    public T pop() {
+
+        Control.checkTrue(this.size > 0, //
+                "No more elements");
+
+        if (this.size <= (this.values.length + 1) >>> 2) {
+            this.values = Arrays.copyOf(this.values, this.values.length >>> 1);
+        }
+
+        return this.values[--this.size];
+    }
+
+    /**
+     * Pushes on a value.
+     */
+    public DynamicObjectArray<T> push(T value) {
+
+        if (this.size == this.values.length) {
+            this.values = Arrays.copyOf(this.values, 2 * this.values.length + 1);
+        }
+
+        this.values[this.size++] = value;
+
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public DynamicObjectArray<T> clear() {
+
+        this.values = (T[]) Array.newInstance(getComponentType(), INITIAL_CAPACITY);
+        this.size = 0;
+
+        return this;
+    }
+
+    public DynamicObjectArray<T> ensureCapacity(int capacity) {
+
+        this.values = (this.values.length < capacity) ? Arrays.copyOf(this.values, capacity) : this.values;
+
+        return this;
+    }
+
+    public int size() {
+        return this.size;
+    }
+
+    public int capacity() {
+        return this.values.length;
+    }
+
+    public T[] values() {
+        return Arrays.copyOf(this.values, this.size);
+    }
+
+    @SuppressWarnings("unchecked")
+    public Class<T> getComponentType() {
+        return (Class<T>) this.values.getClass().getComponentType();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s[size = %d, capacity = %d, values = %s]", //
+                DynamicObjectArray.class.getSimpleName(), //
+                size(), capacity(), Arrays.toString(values()));
+    }
+
+    @Override
+    public DynamicObjectArray<T> clone() {
+        return new DynamicObjectArray<T>(this.values.clone(), this.size);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Finalizable.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Finalizable.java
new file mode 100755
index 0000000..79df76a
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Finalizable.java
@@ -0,0 +1,37 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+/**
+ * Defines something that requires special processing during the finalization stage of the object life cycle.
+ * 
+ * @param <T>
+ *            the parameterization lower bounded by {@link Finalizable} itself.
+ * @author Roy Liu
+ */
+public interface Finalizable<T extends Finalizable<T>> {
+
+    /**
+     * Sets the finalizer.
+     * 
+     * @param finalizer
+     *            the finalizer.
+     * @return this object.
+     */
+    public T setFinalizer(Runnable finalizer);
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/LoadableResources.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/LoadableResources.java
new file mode 100755
index 0000000..2c3e8e4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/LoadableResources.java
@@ -0,0 +1,90 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation in support of {@link Loader} resource loading.
+ * 
+ * @apiviz.owns shared.util.LoadableResources.Resource
+ * @author Roy Liu
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface LoadableResources {
+
+    /**
+     * An enumeration of the types of loadable resources.
+     */
+    public enum ResourceType {
+
+        /**
+         * Denotes a native library.
+         */
+        NATIVE, //
+
+        /**
+         * Denotes a Jar file.
+         */
+        JAR, //
+
+        /**
+         * Denotes a file system folder.
+         */
+        FILE_SYSTEM;
+    }
+
+    /**
+     * Gets the resource descriptions.
+     */
+    public Resource[] resources();
+
+    /**
+     * Gets the names of packages whose classes require said resources for linking.
+     */
+    public String[] packages();
+
+    /**
+     * An annotation describing the whereabouts and type of a resource.
+     * 
+     * @apiviz.owns shared.util.LoadableResources.ResourceType
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public @interface Resource {
+
+        /**
+         * Gets the resource type.
+         */
+        public ResourceType type();
+
+        /**
+         * Gets the resource name.
+         */
+        public String name();
+
+        /**
+         * Gets the resource path.
+         */
+        public String path();
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Loader.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Loader.java
new file mode 100755
index 0000000..01ed192
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Loader.java
@@ -0,0 +1,325 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.jar.JarInputStream;
+
+import shared.metaclass.FileSystemRegistry;
+import shared.metaclass.JarRegistry;
+import shared.metaclass.RegistryClassLoader;
+import shared.util.LoadableResources.Resource;
+
+/**
+ * A facility providing a way for programs to take advantage of Jars and native libraries found on the class path. To
+ * use it, one annotates a target class with {@link LoadableResources.Resource}s specifying the Jars and native
+ * libraries to be loaded, as well as the {@link Service}s to be registered.
+ * 
+ * @apiviz.has shared.util.LoadableResources - - - argument
+ * @apiviz.has shared.util.Loader.EntryPoint - - - argument
+ * @apiviz.uses shared.util.TemporaryFiles
+ * @author Roy Liu
+ */
+public class Loader {
+
+    /**
+     * A marker annotation for the entry point of a program <i>after</i> {@link Loader} has acquired the required
+     * resources.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface EntryPoint {
+    }
+
+    /**
+     * The entry point for {@link Loader} when invoked as a Java process.
+     * 
+     * @exception Exception
+     *                when something goes awry.
+     */
+    public static void main(String[] args) throws Exception {
+
+        Control.checkTrue(args.length > 0, //
+                "Please specify class to load");
+
+        start(args[0], Arrays.copyOfRange(args, 1, args.length), true);
+    }
+
+    /**
+     * Delegates to {@link #start(String, Object, boolean)} with the class loader delegation flag set to {@code true}.
+     * 
+     * @exception Exception
+     *                when something goes awry.
+     */
+    public static void start(String targetName, Object invocationArg) throws Exception {
+        start(targetName, invocationArg, true);
+    }
+
+    /**
+     * The entry point for {@link Loader} when invoked programmatically.
+     * 
+     * @param targetName
+     *            the target class.
+     * @param invocationArg
+     *            the invocation argument.
+     * @param useDelegation
+     *            whether to use the class loader gotten by {@link Thread#getContextClassLoader()} or {@code null} as
+     *            the underlying {@link RegistryClassLoader}'s parent.
+     * @throws Exception
+     *             when something goes awry.
+     */
+    @SuppressWarnings("unchecked")
+    public static void start(String targetName, Object invocationArg, boolean useDelegation) throws Exception {
+
+        List<Resource> jars = new ArrayList<Resource>();
+        List<Resource> folders = new ArrayList<Resource>();
+        List<Resource> libraries = new ArrayList<Resource>();
+
+        //
+
+        Thread currentThread = Thread.currentThread();
+        ClassLoader cl = currentThread.getContextClassLoader();
+
+        // Retrieve the annotations WITHOUT initializing the class, which may depend on stuff yet to be loaded.
+        LoadableResources resources = Class.forName(targetName, false, cl) //
+                .getAnnotation(LoadableResources.class);
+
+        Control.checkTrue(resources != null, //
+                "Resource annotations not declared");
+
+        for (Resource resource : resources.resources()) {
+
+            switch (resource.type()) {
+
+            case NATIVE:
+                libraries.add(resource);
+                break;
+
+            case JAR:
+                jars.add(resource);
+                break;
+
+            case FILE_SYSTEM:
+                folders.add(resource);
+                break;
+
+            default:
+                throw new AssertionError("Control should never reach here");
+            }
+        }
+
+        //
+
+        final List<File> cleanups = new ArrayList<File>();
+
+        RegistryClassLoader bootstrapCL = new RegistryClassLoader(useDelegation ? cl : null) //
+                .setFinalizer(new Runnable() {
+
+                    public void run() {
+
+                        for (File f : cleanups) {
+
+                            Control.delete(f);
+                            TemporaryFiles.undelete(f);
+                        }
+                    }
+                });
+
+        for (Resource jar : jars) {
+
+            String pathname = String.format("%s/%s.jar", jar.path(), jar.name());
+
+            InputStream in = cl.getResourceAsStream(pathname);
+
+            Control.checkTrue(in != null, //
+                    String.format("Resource '%s' not found", pathname));
+
+            bootstrapCL.addRegistry(new JarRegistry(new JarInputStream(in)));
+        }
+
+        //
+
+        for (Resource folder : folders) {
+
+            Control.checkTrue(folder.name().equals(""), //
+                    "Folders do not have names");
+
+            bootstrapCL.addRegistry(new FileSystemRegistry(new File(folder.path())));
+        }
+
+        //
+
+        for (String packageName : resources.packages()) {
+            bootstrapCL.addPackage(packageName);
+        }
+
+        //
+
+        for (Resource library : libraries) {
+
+            String libName = library.name();
+            String pathname = String.format("%s/%s", //
+                    library.path(), System.mapLibraryName(libName));
+
+            URL url = cl.getResource(pathname);
+
+            // Attempt to load from a file, if found.
+            if (url != null) {
+
+                final File f;
+
+                if (url.getProtocol().equals("file")) {
+
+                    try {
+
+                        f = new File(url.toURI());
+
+                    } catch (URISyntaxException e) {
+
+                        throw new RuntimeException(e);
+                    }
+
+                } else {
+
+                    InputStream in = cl.getResourceAsStream(pathname);
+
+                    Control.checkTrue(in != null, //
+                            String.format("Resource '%s' not found", pathname));
+
+                    try {
+
+                        f = File.createTempFile(pathname.replace("/", "_").concat("_"), "");
+
+                        cleanups.add(f);
+                        TemporaryFiles.deleteOnExit(f);
+
+                        Control.transfer(in, f);
+
+                    } catch (IOException e) {
+
+                        throw new RuntimeException(e);
+
+                    } finally {
+
+                        Control.close(in);
+                    }
+                }
+
+                bootstrapCL.load(f);
+            }
+            // Fall back on the dynamic linker for resolution.
+            else {
+
+                try {
+
+                    bootstrapCL.loadLibrary(libName);
+
+                } catch (RuntimeException e) {
+
+                    throw new RuntimeException(String.format("The native library resource '%s' was not found " //
+                            + "and dynamic linker resolution of '%s' failed", pathname, libName), e);
+                }
+            }
+        }
+
+        //
+
+        Class<? extends Annotation> entryPointClass = //
+        (Class<? extends Annotation>) Class.forName(EntryPoint.class.getName(), true, bootstrapCL);
+
+        Class<?> targetClass = Class.forName(targetName, false, bootstrapCL);
+
+        Method method = null;
+
+        // Find any annotated methods.
+        for (Method m : targetClass.getMethods()) {
+
+            if (m.isAnnotationPresent(entryPointClass)) {
+
+                Control.checkTrue(method == null, //
+                        "Duplicate entry points");
+
+                method = m;
+            }
+        }
+
+        Control.checkTrue(method != null, //
+                "Annotated entry point method not found");
+
+        try {
+
+            currentThread.setContextClassLoader(bootstrapCL);
+
+            method.invoke(null, invocationArg);
+
+        } finally {
+
+            currentThread.setContextClassLoader(cl);
+        }
+    }
+
+    /**
+     * Registers a {@link Service}.
+     * 
+     * @param <A>
+     *            the service type.
+     * @param serviceSpec
+     *            the service to register.
+     */
+    @SuppressWarnings("unchecked")
+    public static <A extends Service> void registerService(String[] serviceSpec) {
+
+        final Class<A> specClass;
+        final Class<? extends A> implClass;
+
+        try {
+
+            specClass = (Class<A>) Class.forName(serviceSpec[0]);
+            implClass = (Class<? extends A>) Class.forName(serviceSpec[1]);
+
+        } catch (ClassNotFoundException e) {
+
+            throw new RuntimeException(e);
+        }
+
+        Control.checkTrue(Service.class.isAssignableFrom(specClass), //
+                "Specification class is not marked as a service");
+
+        Control.checkTrue(specClass.isAssignableFrom(implClass), //
+                "Specification class is not a superclass of the implementation class");
+
+        Services.registerService(specClass, implClass);
+    }
+
+    // Dummy constructor.
+    Loader() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/ReferenceReaper.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/ReferenceReaper.java
new file mode 100755
index 0000000..53e0f0c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/ReferenceReaper.java
@@ -0,0 +1,207 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu, The Regents of the University of California <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A utility class for reaping {@link SoftReference}s and {@link WeakReference}s.
+ * 
+ * @apiviz.composedOf shared.util.ReferenceReaper.ReaperThread
+ * @apiviz.has shared.util.ReferenceReaper.ReferenceType - - - argument
+ * @param <T>
+ *            the referent type.
+ * @author Roy Liu
+ */
+public class ReferenceReaper<T> {
+
+    /**
+     * An enumeration of {@link Reference} types.
+     */
+    public enum ReferenceType {
+
+        /**
+         * Indicates a {@link SoftReference}.
+         */
+        SOFT, //
+
+        /**
+         * Indicates a {@link WeakReference}.
+         */
+        WEAK;
+    }
+
+    final ReaperThread<T> thread;
+
+    /**
+     * Default constructor.
+     */
+    public ReferenceReaper() {
+        this.thread = new ReaperThread<T>();
+    }
+
+    /**
+     * Registers a referent with this reaper.
+     * 
+     * @param type
+     *            the type of {@link Reference} desired.
+     * @param referent
+     *            the referent.
+     * @param cache
+     *            the {@link ConcurrentMap} to register with and clean up from.
+     * @param cacheKey
+     *            the key used to retrieve the referent.
+     * @param <K>
+     *            the key type.
+     * @return a {@link Reference} to the referent.
+     */
+    public <K> Reference<T> register(ReferenceType type, T referent, //
+            final ConcurrentMap<K, Reference<T>> cache, final K cacheKey) {
+
+        Runnable cleanup = new Runnable() {
+
+            public void run() {
+                cache.remove(cacheKey);
+            }
+        };
+
+        final Reference<T> ref;
+
+        // Synchronization ensures that insertion happens BEFORE removal.
+        synchronized (this.thread) {
+
+            switch (type) {
+
+            case SOFT:
+
+                ref = new SoftReference<T>(referent, this.thread.rq) {
+
+                    @Override
+                    public String toString() {
+                        return String.valueOf(get());
+                    }
+                };
+
+                break;
+
+            case WEAK:
+
+                ref = new WeakReference<T>(referent, this.thread.rq) {
+
+                    @Override
+                    public String toString() {
+                        return String.valueOf(get());
+                    }
+                };
+
+                break;
+
+            default:
+                throw new IllegalArgumentException("Invalid reference type");
+            }
+
+            cache.put(cacheKey, ref);
+            this.thread.map.put(ref, cleanup);
+        }
+
+        return ref;
+    }
+
+    /**
+     * A worker thread class for reaping {@link Reference}s.
+     * 
+     * @param <T>
+     *            the referent type.
+     */
+    final protected static class ReaperThread<T> extends CoreThread {
+
+        final ReferenceQueue<T> rq;
+        final ConcurrentMap<Reference<T>, Runnable> map;
+
+        volatile boolean run;
+
+        /**
+         * Default constructor.
+         */
+        protected ReaperThread() {
+            super("Reaper");
+
+            this.rq = new ReferenceQueue<T>();
+            this.map = new ConcurrentHashMap<Reference<T>, Runnable>();
+
+            this.run = true;
+
+            setDaemon(true);
+            start();
+        }
+
+        /**
+         * Runs the reference reaping loop.
+         */
+        @Override
+        public void runUnchecked() {
+
+            loop: for (; this.run;) {
+
+                final Reference<? extends T> ref;
+
+                try {
+
+                    ref = this.rq.remove();
+
+                } catch (InterruptedException e) {
+
+                    continue loop;
+                }
+
+                // Synchronization ensures that removal happens AFTER insertion.
+                synchronized (this) {
+                }
+
+                try {
+
+                    this.map.remove(ref).run();
+
+                } catch (NullPointerException e) {
+
+                    // In case the key-value relationship was not successfully added to the map.
+
+                } catch (Throwable t) {
+
+                    // In case the cleanup stub acts up.
+                }
+            }
+        }
+    }
+
+    // A finalizer guardian for the reaper thread.
+    final Object threadReaper = new Object() {
+
+        @Override
+        protected void finalize() {
+
+            ReferenceReaper.this.thread.run = false;
+            ReferenceReaper.this.thread.interrupt();
+        }
+    };
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/RequestFuture.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/RequestFuture.java
new file mode 100755
index 0000000..a2904ff
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/RequestFuture.java
@@ -0,0 +1,53 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.util.concurrent.FutureTask;
+
+/**
+ * A subclass of {@link FutureTask} specially geared toward asynchronous request-response patterns.
+ * 
+ * @param <T>
+ *            the result type.
+ * @author Roy Liu
+ */
+public class RequestFuture<T> extends FutureTask<T> {
+
+    /**
+     * Default constructor.
+     */
+    public RequestFuture() {
+        super(Control.NullRunnable, null);
+    }
+
+    /**
+     * Gives public visibility to the {@link FutureTask#set(Object)} method.
+     */
+    @Override
+    public void set(T v) {
+        super.set(v);
+    }
+
+    /**
+     * Gives public visibility to the {@link FutureTask#setException(Throwable)} method.
+     */
+    @Override
+    public void setException(Throwable t) {
+        super.setException(t);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Service.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Service.java
new file mode 100755
index 0000000..4ef1c87
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Service.java
@@ -0,0 +1,26 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2008 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+/**
+ * Defines something as providing a service.
+ * 
+ * @author Roy Liu
+ */
+public interface Service {
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/Services.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/Services.java
new file mode 100755
index 0000000..7fb924c
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/Services.java
@@ -0,0 +1,98 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2007 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.lang.ref.Reference;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import shared.util.ReferenceReaper.ReferenceType;
+
+/**
+ * A global registry of various {@link Service}s and their implementing classes.
+ * 
+ * @apiviz.owns shared.util.Service
+ * @author Roy Liu
+ */
+public class Services {
+
+    /**
+     * A global instance.
+     */
+    final protected static Services Instance = new Services();
+
+    final ConcurrentMap<Class<? extends Service>, Reference<Class<? extends Service>>> serviceMap;
+    final ReferenceReaper<Class<? extends Service>> rr;
+
+    /**
+     * Default constructor.
+     */
+    protected Services() {
+
+        this.serviceMap = new ConcurrentHashMap<Class<? extends Service>, Reference<Class<? extends Service>>>();
+        this.rr = new ReferenceReaper<Class<? extends Service>>();
+    }
+
+    /**
+     * Creates an implementing class instance from the given specification superclass.
+     * 
+     * @param <A>
+     *            the implementing class type, which is a lower bound on the superclass type.
+     * @param specClass
+     *            the specification superclass.
+     * @return an instance of the implementing class.
+     */
+    @SuppressWarnings("unchecked")
+    public static <A extends Service> A createService(Class<? super A> specClass) {
+
+        try {
+
+            Reference<Class<? extends Service>> ref = Instance.serviceMap.get(specClass);
+
+            if (ref == null) {
+                return null;
+            }
+
+            Class<? extends Service> implClass = ref.get();
+
+            if (implClass == null) {
+                return null;
+            }
+
+            return ((Class<? extends A>) implClass).newInstance();
+
+        } catch (Exception e) {
+
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Registers an implementing class with the given specification superclass.
+     * 
+     * @param <A>
+     *            the superclass type, which is an upper bound on the implementation class type.
+     * @param specClass
+     *            the specification superclass.
+     * @param implClass
+     *            the implementing class.
+     */
+    public static <A extends Service> void registerService(Class<A> specClass, Class<? extends A> implClass) {
+        Instance.rr.register(ReferenceType.WEAK, implClass, Instance.serviceMap, specClass);
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/TemporaryFiles.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/TemporaryFiles.java
new file mode 100755
index 0000000..938feb0
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/TemporaryFiles.java
@@ -0,0 +1,104 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+package shared.util;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A class whose static methods allow (de)registration of files for deletion upon JVM shutdown.
+ * 
+ * @author Roy Liu
+ */
+public class TemporaryFiles {
+
+    /**
+     * The set of temporary files under consideration for deletion.
+     */
+    protected static Set<File> Deletions = new HashSet<File>();
+
+    static {
+
+        Runtime.getRuntime().addShutdownHook(new CoreThread("Temporary File Deletion Hook") {
+
+            @Override
+            protected void runUnchecked() {
+
+                synchronized (TemporaryFiles.class) {
+
+                    for (File deletion : Deletions) {
+                        Control.delete(deletion);
+                    }
+
+                    Deletions = null;
+                }
+            }
+        });
+    }
+
+    /**
+     * Adds the given file for deletion and serves as an alternative to {@link File#deleteOnExit()}.
+     * 
+     * @param file
+     *            the file.
+     * @return the file.
+     */
+    final public static File deleteOnExit(File file) {
+
+        synchronized (TemporaryFiles.class) {
+
+            if (Deletions != null) {
+
+                Deletions.add(file);
+
+                return file;
+
+            } else {
+
+                throw new IllegalStateException("Shutdown imminent");
+            }
+        }
+    }
+
+    /**
+     * Removes the given file from consideration for deletion.
+     * 
+     * @param file
+     *            the file.
+     * @return whether the file was under consideration for deletion.
+     */
+    final public static boolean undelete(File file) {
+
+        synchronized (TemporaryFiles.class) {
+
+            if (Deletions != null) {
+
+                return Deletions.remove(file);
+
+            } else {
+
+                throw new IllegalStateException("Shutdown imminent");
+            }
+        }
+    }
+
+    // Dummy constructor.
+    TemporaryFiles() {
+    }
+}
diff --git a/contrib/applications/nxplot/sharedscientific/src/shared/util/package-info.java b/contrib/applications/nxplot/sharedscientific/src/shared/util/package-info.java
new file mode 100755
index 0000000..638b9c4
--- /dev/null
+++ b/contrib/applications/nxplot/sharedscientific/src/shared/util/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * This file is part of the Shared Scientific Toolbox in Java ("this library"). <br />
+ * <br />
+ * Copyright (C) 2009 Roy Liu <br />
+ * <br />
+ * This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version. <br />
+ * <br />
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <br />
+ * <br />
+ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <a
+ * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
+ */
+
+/**
+ * A package of convenience classes.
+ */
+package shared.util;
+
diff --git a/contrib/bindings/Makefile.am b/contrib/bindings/Makefile.am
new file mode 100644
index 0000000..d87e30d
--- /dev/null
+++ b/contrib/bindings/Makefile.am
@@ -0,0 +1,36 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#
+#  Makefile for coordinating the generation of language bindings
+#  
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+
+#if HAVE_JAVAC
+#JAVASUB = java
+#endif
+if HAVE_PYTHON
+PYSUB = python
+endif
+SUBDIRS = $(PYSUB) # $(JAVASUB)
diff --git a/contrib/bindings/README b/contrib/bindings/README
new file mode 100644
index 0000000..c897ad0
--- /dev/null
+++ b/contrib/bindings/README
@@ -0,0 +1,7 @@
+This directory contains NeXus language bindings contributed by the 
+neutron community that are not (yet) part of the official NeXus 
+distribution. 
+
+See the individual directories for further details.
+
+$Id$
diff --git a/contrib/bindings/java/org/nexusformat/utils/NXutil.java b/contrib/bindings/java/org/nexusformat/utils/NXutil.java
new file mode 100644
index 0000000..90e2808
--- /dev/null
+++ b/contrib/bindings/java/org/nexusformat/utils/NXutil.java
@@ -0,0 +1,771 @@
+/*
+ * Copyright (c) 2003, P.F.Peterson <petersonpf at ornl.gov>
+ *               Spallation Neutron Source at Oak Ridge National Laboratory
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.nexusformat.util;
+
+import java.lang.Math;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.nexusformat.AttributeEntry;
+import org.nexusformat.NeXusFileInterface;
+import org.nexusformat.NexusFile;
+import org.nexusformat.NexusException;
+import ncsa.hdf.hdflib.HDFConstants;
+
+/**
+ * This is a class of utility functions for accessing information in a
+ * nexus file.
+ */
+public class NXutil{
+  private static final int CHAR      = HDFConstants.DFNT_CHAR;
+  private static final int SH_SHORT  = HDFConstants.DFNT_INT8;
+  private static final int SH_USHORT = HDFConstants.DFNT_UINT8;
+  private static final int SHORT     = HDFConstants.DFNT_INT16;
+  private static final int USHORT    = HDFConstants.DFNT_UINT16;
+  private static final int INT       = HDFConstants.DFNT_INT32;
+  private static final int UINT      = HDFConstants.DFNT_UINT32;
+  private static final int FLOAT     = HDFConstants.DFNT_FLOAT32;
+  private static final int DOUBLE    = HDFConstants.DFNT_FLOAT64;
+
+  private static final int MAX_BLOB_SIZE=20000;
+  private static final boolean DEBUG=false;
+
+  /**
+   * Like the name says, this is a utility class. Do not allow anyone
+   * to instantiate this class.
+   */
+  private NXutil(){}
+
+  /**
+   * Get the list of attributes on the current level of the file
+   * given.
+   */
+  public static Hashtable getAttrList(NeXusFileInterface file)
+                                   throws NexusException, NullPointerException{
+    // don't know what to do with a null file pointer
+    if(file==null) throw new NullPointerException("null CNexusFile");
+
+    // get the initial hashtable
+    Hashtable table=file.attrdir();
+    
+    // collect the keys
+    Enumeration keys=table.keys();
+
+    // go through and replace the values with a string version
+    String key=null;
+    //System.out.println("getAttrList"); // REMOVE
+    while(keys.hasMoreElements()){
+      key=(String)keys.nextElement();
+      table.put(key,getAttr(file,table,key));
+      //System.out.println("  "+key+"="+table.get(key)); // REMOVE
+    }
+
+    return table;
+  }
+
+  /**
+   * Method for converting the AttributeEntry objects into real
+   * Atributes. The currently supported Attribute types are CHAR,
+   * FLOAT, DOUBLE, INT and UINT.
+   */
+  private static Object getAttr(NeXusFileInterface file, Hashtable attrlist,
+                       String key) throws NexusException, NullPointerException{
+    // null pointers are bad
+    if(file==null) throw new NullPointerException("null CNexusFile");
+    if(attrlist==null) throw new NullPointerException("null Hashtable");
+    if(key==null) throw new NullPointerException("null key");
+
+    // get the current value
+    Object val=attrlist.get(key);
+
+    // if it is a String the conversion is already done
+    if(val instanceof String)  return val;
+    if(val instanceof Float)   return val;
+    if(val instanceof Integer) return val;
+
+    // initialize some quick arrays to convert with
+    int type=((AttributeEntry)val).type;
+    int[] lentype={((AttributeEntry)val).length,type};
+    if(type==CHAR) lentype[0]++;
+
+    // create the value array
+    Object data=null;
+    if(type==CHAR)
+      data=new byte[lentype[0]];
+    else if(type==USHORT || type==SHORT)
+      data=getShortArray(lentype[0]);
+    else if(type==UINT || type==INT)
+      data=getIntArray(lentype[0]);
+    else if(type==FLOAT)
+      data=getFloatArray(lentype[0]);
+    else if(type==DOUBLE)
+      data=getDoubleArray(lentype[0]);
+    else{
+      return "";
+    }
+
+    // get the attribute value from the file
+    file.getattr(key,data,lentype);
+
+    // return a string version
+    if(type==USHORT || type==SHORT){
+      if(((short[])data).length==1)
+        return new Short(((short[])data)[0]);
+      else
+        return data;
+    }else if(type==UINT || type==INT){
+      if(((int[])data).length==1)
+        return new Integer(((int[])data)[0]);
+      else
+        return data;
+    }else if(type==FLOAT){
+      if(((float[])data).length==1)
+        return new Float(((float[])data)[0]);
+      else
+        return data;
+    }else if(type==DOUBLE){
+      if(((double[])data).length==1)
+        return new Double(((double[])data)[0]);
+      else
+        return data;
+    }else if(type==CHAR){
+      String result=new String((byte[])data);
+      return result.substring(0,lentype[0]);
+    }else{
+      return new String("");
+    }
+  }
+
+  public static Object getData(NeXusFileInterface file, String key)
+                                   throws NexusException, NullPointerException{
+    // null pointers are bad
+    if(file==null) throw new NullPointerException("null CNexusFile");
+    if(key==null) throw new NullPointerException("null key");
+
+    file.opendata(key);
+    //long zero=System.currentTimeMillis();
+    Object result=getData(file);
+    //System.out.println("TIME:"+(System.currentTimeMillis()-zero));
+    file.closedata();
+
+    return result;
+  }
+
+  /**
+   * This is another version of the R.Mikkelson's code that I
+   * understand better. When in doesn't work it calls that code.
+   */
+  private static Object getData(NeXusFileInterface file)
+                                   throws NexusException, NullPointerException{
+    // null pointers are bad
+    if(file==null) throw new NullPointerException("null CNexusFile");
+
+    // only allow data up to four dimensions
+    int[] dim=new int[4];
+    int[] ranktype=new int[2];
+
+    // determine the dimensions and type
+    file.getinfo(dim,ranktype);
+    int rank=ranktype[0];
+    int type=ranktype[1];
+
+    // check that the rank makes sense
+    if(rank<=0) return null;
+
+    // determine the total length
+    int tot_length=1;
+    for( int i=0 ; i<rank ; i++ )
+      tot_length*=dim[i];
+
+    // check if this is a zero length array (mean trick)
+    if(tot_length==0){
+      return "";
+    }
+
+    Object array=null;
+
+    // do something special for character arrays
+    if(type==CHAR){
+      array=getArray(type,tot_length);
+      file.getdata(array);
+      String result=new String((byte[])array);
+      return result.substring(0,dim[0]);
+    }
+
+    // "Seemed like a good idea at the time..."  ;-)
+    // read in smaller arrays
+    // if(tot_length<MAX_BLOB_SIZE){
+      // allocate full array to fill
+      // array=getArray(type,tot_length);
+      // read in the data b/c it is small
+      // file.getdata(array);
+    // }else
+    if(rank==1){ // code for 1D arrays works
+      // allocate full array to fill
+      array=getArray(type,tot_length);
+
+      int[] start={0};
+      int[] end={Math.min(MAX_BLOB_SIZE,dim[0])};
+      Object subarray;
+      while(true){
+        subarray=getArray(type,end);
+        file.getslab(start,end,subarray);
+        System.arraycopy(subarray,0,array,start[0],end[0]);
+        if(end[0]>=dim[0])
+          break;
+        start[0]+=end[0];
+        end[0]=Math.min(MAX_BLOB_SIZE,dim[0]-start[0]);
+        if(end[0]<=0)
+          break;
+      }
+    }else if(rank==2){ // 2-dimensional arrays
+      // allocate arrays to use
+      array=getArray(type,dim);
+
+      // set up what to read
+      int[] start={0,0};
+      int[] end={1,dim[1]};
+
+      for(int i=0 ; i<dim[0] ; i++ ){
+        Object inner=Array.get(array,i);
+        file.getslab(start,end,inner);
+        start[0]++;
+      }
+    }else if(rank==3){ // 3-dimensional arrays
+      // allocate arrays to use
+      array=getArray(type,dim);
+      
+      // set up what to read
+      int[] start={0,0,0};
+      int[] end={1,1,dim[2]};
+
+      for(int i=0 ; i<dim[0] ; i++ ){
+        Object inner_i=Array.get(array,i);
+        for( int j=0 ; j<dim[1] ; j++ ){
+          Object inner_j=Array.get(inner_i,j);
+          file.getslab(start,end,inner_j);
+          start[1]++;
+        }
+        start[0]++;
+        start[1]=0;
+      }
+    }else if(rank==4){ // 4-dimensional arrays
+      // allocate arrays to use
+      array=getArray(type,dim);
+      
+      // set up what to read
+      int[] start={0,0,0,0};
+      int[] end={1,1,1,dim[3]};
+
+      for(int i=0 ; i<dim[0] ; i++ ){
+        Object inner_i=Array.get(array,i);
+        for( int j=0 ; j<dim[1] ; j++ ){
+          Object inner_j=Array.get(inner_i,j);
+          for( int k=0 ; k<dim[2] ; k++ ){
+            Object inner_k=Array.get(inner_j,k);
+            file.getslab(start,end,inner_k);
+            start[2]++;
+          }
+          start[1]++;
+          start[2]=0;
+        }
+        start[0]++;
+        start[1]=0;
+      }
+    }else{ // give up and use Ruth's code
+      //System.out.println("Ruth"); // REMOVE
+      array=ruth_getData(file);
+    }
+
+    return array;
+  }
+
+  /**
+   * This is an attempt to take R.Mikkelson's code for loading data.
+   */
+  private static Object ruth_getData(NeXusFileInterface file)
+                                   throws NexusException, NullPointerException{
+    //System.out.println("00:"); // REMOVE
+    // null pointers are bad
+    if(file==null) throw new NullPointerException("null CNexusFile");
+
+    // only allow data up to four dimensions
+    int[] dim=new int[4];
+    int[] ranktype=new int[2];
+
+    // determine the dimensions and type
+    file.getinfo(dim,ranktype);
+    int rank=ranktype[0];
+    int type=ranktype[1];
+
+    // check that the rank makes sense
+    if(rank<=0) return null;
+
+    // declare variables for grabbing sub-arrays
+    int pos=-1; // position in dim where sub-elements start
+    int step=-1; // number of blocks in that position that can be
+                 // retrieved before getting above MAX_BLOB_SIZE
+    int lenn=-1; // the number of array elements that will be
+                 // retrieved in each blob
+
+    //System.out.println("01:"); // REMOVE
+    // initialize variables for grabbing sub-arrays
+    if(dim[rank-1]>=MAX_BLOB_SIZE){
+      pos=rank-2;
+      step=1;
+      lenn=1;
+    }else if(rank==1){
+      pos=-1;
+      step=1;
+      lenn=1;
+    }else{
+      int prod=dim[rank-1];
+      pos=rank-1;
+      lenn=dim[rank-1];
+      while( (prod<MAX_BLOB_SIZE) && (pos>0) ){
+        pos--;
+        prod=prod*dim[pos];
+        if(prod<MAX_BLOB_SIZE)
+          lenn=prod;
+      }
+      if(prod>=MAX_BLOB_SIZE){
+        prod=prod/dim[pos];
+        step=MAX_BLOB_SIZE/prod;
+        if(step<1) step=1;
+      }else{
+        step=dim[0];
+        lenn=lenn/dim[0];
+      }
+    }
+
+    //System.out.println("02:"); // REMOVE
+    // set up the full array to put information into
+    int tot_length=1;
+    for( int i=0 ; i<rank ; i++ )
+      tot_length*=dim[i];
+    Object array=getArray(type,tot_length);
+
+    //System.out.println("03:"); // REMOVE
+    // set up information for stepping through the slabs
+    int k_array=0;
+    int[] start=new int[rank];
+    int[] size=new int[rank];
+    for( int i=0 ; i<rank ; i++ )
+      start[i]=0;
+    if(pos>=0){
+      for( int i=0 ; i<pos ; i++ )
+        size[i]=1;
+      size[pos]=step;
+      for( int i=pos+1 ; i<rank ; i++ )
+        size[i]=dim[i];
+    }else{
+      for( int i=0 ; i<rank ; i++ )
+        size[i]=dim[i];
+      lenn=1;
+    }
+    Object subarray=getArray(type,tot_length);
+
+    //System.out.println("04:"); // REMOVE
+
+    // step through the subarrays and copy into full array
+    while(true){
+      //System.out.println(StringUtil.toString(start)+"->"+StringUtil.toString(size)); // REMOVE
+      file.getslab(start,size,subarray); // ruth's line 606
+
+      System.arraycopy(subarray,0,array,k_array,lenn*size[(int)Math.max(pos,0)]);
+      k_array+=lenn*size[(int)Math.max(pos,0)];
+      if(pos>=0){
+        start[pos]+=size[pos];
+        if(start[pos]>=dim[pos]){
+          start[pos]=0;
+          int i;
+          for( i=pos-1 ; (i>=0)&&(start[i]+1>=dim[i]) ; i-- )
+            start[i]=0;
+          if(i<0)
+            break;
+          else if(i<pos)
+            start[i]+=1;
+        }
+        size[pos]=(int)Math.min(step,dim[pos]-start[pos]);
+      }else{ // case where all are done
+        break;
+      }
+    }
+
+    //System.out.println("05:"); // REMOVE
+
+    return array;
+  }
+
+  private static int[] getDimensions(Object array){
+    Vector vec_dim=new Vector();
+
+    int length=Array.getLength(array);
+    vec_dim.add(new Integer(length));
+    Object inner=Array.get(array,0);
+    while(inner.getClass().isArray()){
+      length=Array.getLength(inner);
+      vec_dim.add(new Integer(length));
+      inner=Array.get(inner,0);
+    }
+
+
+    // convert the vector to an integer array
+    int[] dim=new int[vec_dim.size()];
+    for( int i=0 ; i<vec_dim.size() ; i++ )
+      dim[i]=((Integer)vec_dim.elementAt(i)).intValue();
+
+    return dim;
+  }
+
+  private static Object getArray(int type, int length){
+    Object array=null;
+    int[] dim={length};
+
+    if(type==USHORT||type==SHORT)
+      array=getIntArray(dim);
+    else if(type==SH_USHORT || type==SH_SHORT)
+      array=getIntArray(dim);
+    else if(type==UINT||type==INT)
+      array=getIntArray(dim);
+    else if(type==FLOAT)
+      array=getFloatArray(dim);
+    else if(type==DOUBLE)
+      array=getDoubleArray(dim);
+    else if(type==CHAR)
+      array=new byte[length];
+    else
+      throw new IllegalArgumentException("Cannot deal with type in getArray("
+                                     +type+","+length+")");
+
+    return array;
+  }
+
+  /**
+   * Basically does a malloc for an n-dimensional array. The "type"
+   * passed to this function must be one of those defined in NeXus.
+   *
+   * @param type the type as defined in NeXus API
+   * @param dim the length of the array in each dimension. Zero
+   * elements are ignored.
+   */
+  public static Object getArray(int type, int[] dim){
+    Object array=null;
+
+    if(type==USHORT||type==SHORT)
+      array=getIntArray(dim);
+    else if(type==SH_USHORT || type==SH_SHORT)
+      array=getIntArray(dim);
+    else if(type==UINT||type==INT)
+      array=getIntArray(dim);
+    else if(type==FLOAT)
+      array=getFloatArray(dim);
+    else if(type==DOUBLE)
+      array=getDoubleArray(dim);
+    else if(type==CHAR)
+      array=new byte[dim[0]];
+
+    return array;
+  }
+
+  /**
+   * Basically does a malloc for an n-dimensional integer array.
+   *
+   * @param dim the length of the array in each dimension. Zero
+   * elements are ignored.
+   */
+  public static Object getIntArray(int[] dim){
+    // get the dimension of the array to allocate
+    int size=dim.length;
+    for(int i=size-1 ; i>0 ; i-- ){
+      if(dim[i]<=0)
+        size--;
+      else
+        break;
+    }
+
+    // allocate the array
+    if(size==1)
+      return new int[dim[0]];
+    else if(size==2)
+      return new int[dim[0]][dim[1]];
+    else if(size==3)
+      return new int[dim[0]][dim[1]][dim[2]];
+    else if(size==4)
+      return new int[dim[0]][dim[1]][dim[2]][dim[3]];
+    else
+      return null;
+  }
+
+  public static Object getShortArray(int[] dim){
+    // get the dimension of the array to allocate
+    int size=dim.length;
+    for(int i=size-1 ; i>0 ; i-- ){
+      if(dim[i]<=0)
+        size--;
+      else
+        break;
+    }
+
+    // allocate the array
+    if(size==1)
+      return new short[dim[0]];
+    else if(size==2)
+      return new short[dim[0]][dim[1]];
+    else if(size==3)
+      return new short[dim[0]][dim[1]][dim[2]];
+    else if(size==4)
+      return new short[dim[0]][dim[1]][dim[2]][dim[3]];
+    else
+      return null;
+  }
+
+  public static Object getFloatArray(int[] dim){
+    // get the dimension of the array to allocate
+    int size=dim.length;
+    for(int i=size-1 ; i>0 ; i-- ){
+      if(dim[i]<=0)
+        size--;
+      else
+        break;
+    }
+
+    // allocate the array
+    if(size==1)
+      return new float[dim[0]];
+    else if(size==2)
+      return new float[dim[0]][dim[1]];
+    else if(size==3)
+      return new float[dim[0]][dim[1]][dim[2]];
+    else if(size==4)
+      return new float[dim[0]][dim[1]][dim[2]][dim[3]];
+    else
+      return null;
+  }
+
+  public static Object getDoubleArray(int[] dim){
+    // get the dimension of the array to allocate
+    int size=dim.length;
+    for(int i=size-1 ; i>0 ; i-- ){
+      if(dim[i]<=0)
+        size--;
+      else
+        break;
+    }
+
+    // allocate the array
+    if(size==1)
+      return new double[dim[0]];
+    else if(size==2)
+      return new double[dim[0]][dim[1]];
+    else if(size==3)
+      return new double[dim[0]][dim[1]][dim[2]];
+    else if(size==4)
+      return new double[dim[0]][dim[1]][dim[2]][dim[3]];
+    else
+      return null;
+  }
+
+  public static short[] getShortArray(int length){
+    int[] dim={length};
+    return (short[])getShortArray(dim);
+  }
+
+  public static int[] getIntArray(int length){
+    int[] dim={length};
+    return (int[])getIntArray(dim);
+  }
+
+  public static float[] getFloatArray(int length){
+    int[] dim={length};
+    return (float[])getFloatArray(dim);
+  }
+
+  public static double[] getDoubleArray(int length){
+    int[] dim={length};
+    return (double[])getDoubleArray(dim);
+  }
+
+  public static void printArray(Object array){
+    int maxmax=10;
+    if(array instanceof float[]){
+      int maxI=((float[])array).length;
+      if(maxI>maxmax) maxI=maxmax;
+      System.out.print("[");
+      for( int i=0 ; i<maxI ; i++ ){
+        System.out.print(((float[])array)[i]);
+        if(i<maxI-1)
+          System.out.print(", ");
+        else if(i==maxI-1)
+          System.out.println(", ... ]");
+      }
+    }else if(array instanceof int[]){
+      int maxI=((int[])array).length;
+      if(maxI>maxmax) maxI=maxmax;
+      System.out.print("[");
+      for( int i=0 ; i<maxI ; i++ ){
+        System.out.print(((int[])array)[i]);
+        if(i<maxI-1)
+          System.out.print(", ");
+        else if(i==maxI-1)
+          System.out.println(", ... ]");
+      }
+    }else if(array instanceof float[][]){
+      int maxI=((float[][])array).length;
+      if(maxI>maxmax) maxI=maxmax;
+      System.out.print("[");
+      for( int i=0 ; i<maxI ; i++ ){
+        printArray(((float[][])array)[i]);
+        if(i<maxI-1)
+          System.out.print(", ");
+        else if(i==maxI-1)
+          System.out.println(", ... ]");
+      }
+    }else if(array instanceof int[][]){
+      int maxI=((int[][])array).length;
+      if(maxI>maxmax) maxI=maxmax;
+      System.out.print("[");
+      for( int i=0 ; i<maxI ; i++ ){
+        printArray(((int[][])array)[i]);
+        if(i<maxI-1)
+          System.out.print(", ");
+        else if(i==maxI-1)
+          System.out.println(", ... ]");
+      }
+    }else{
+      System.out.println("NOT PRINTING");
+    }
+  }
+
+  public static String getNXfileSummary(String filename){
+    filename=StringUtil.setForwardSlash(filename);
+    String result=null;
+    NeXusFileInterface file=null;
+
+    String fname = null;
+    String date  = null;
+    String name  = null;
+    String title = null;
+
+    int index=0;
+
+    try{
+      Hashtable attrlist=null;
+      Hashtable direc=null;
+      Hashtable inner_direc=null;
+      Enumeration keys=null;
+      Enumeration inner_keys=null;
+
+
+      file=new NexusFile(filename,NexusFile.NXACC_READ);
+      attrlist=getAttrList(file);
+
+      // create some defaults
+      String defFile=filename;
+      String defDate=(String)attrlist.get("file_time");
+      String defName=(String)attrlist.get("user");
+      String defTitl="";
+
+      // useful local variables
+      String key=null;
+      String val=null;
+
+      // find the right group to be in
+      direc=file.groupdir();
+      keys=direc.keys();
+      while(keys.hasMoreElements()){
+        key=(String)keys.nextElement();
+        if( "NXentry".equals((String)direc.get(key)) ){
+          file.opengroup(key,"NXentry");
+          inner_direc=file.groupdir();
+          if( inner_direc.get("title")!=null )
+            break;
+          else
+            file.closegroup();
+        }else{
+          key=null;
+        }
+      }
+
+      // now start looking for the good stuff
+      attrlist=file.groupdir();
+      // first the date;
+      val=(String)attrlist.get("start_time");
+      if(val!=null && val.equals("SDS"))
+        date=(String)getData(file,"start_time");
+      // next the user name
+      keys=attrlist.keys();
+      while(keys.hasMoreElements()){
+        key=(String)keys.nextElement();
+        if("NXuser".equals(attrlist.get(key))){
+          file.opengroup(key,"NXuser");
+          name=(String)getData(file,"name");
+          file.closegroup();
+          break;
+        }
+      }
+      // finally the title
+      val=(String)attrlist.get("title");
+      if(val!=null && val.equals("SDS"))
+        title=(String)getData(file,"title");
+
+      // use the defaults if there isn't another choice
+      if(fname==null || fname.length()==0) fname=defFile;
+      if(date==null  || date.length()==0)  date=defDate;
+      if(name==null  || name.length()==0)  name=defName;
+      if(title==null || title.length()==0) title=defTitl;
+
+      // chop down the filename
+      fname=StringUtil.setForwardSlash(fname);
+      index=fname.lastIndexOf("/");
+      if(index>=0) fname=fname.substring(index+1);
+      // chop down the date
+      index=date.indexOf(" ");
+      if(index>=0) date=date.substring(0,index);
+
+      // format this stuff
+      StringBuffer sb=new StringBuffer(80);
+      sb.append(fname+"                              ");
+      sb.delete(30,sb.length());
+      sb.append(date+" ");
+      sb.append(name+"                    ");
+      sb.delete(55,sb.length());
+      sb.append(title+"                                   ");
+      result=sb.substring(0,80);
+    }catch(NexusException e){
+      System.out.println("ENCOUNTERED EXCEPTION"+e.getMessage());
+      // let it drop on the floor
+    }
+
+    try{
+      if(file!=null) file.finalize(); // close the file
+    }catch(Throwable e){
+      // let it drop on the floor
+    }
+
+    return result;
+  }
+}
diff --git a/contrib/bindings/python/Makefile.am b/contrib/bindings/python/Makefile.am
new file mode 100755
index 0000000..17bacf1
--- /dev/null
+++ b/contrib/bindings/python/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 715 2005-12-16 18:11:19Z faa59 $
+#  
+#  Makefile for NeXus python bindings
+#
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+pydocdir 	= $(NXDOCDIR)/python
+### pydoc_DATA	= README.html
+### pkgpython_PYTHON = nxs.py setup.py nxstest.py nexus.py nxsunit.py
+### EXTRA_DIST	= README.html
+
+### install-data-hook :
+### 	sed -e "s|nxprefix = .*|nxprefix = \'${prefix}\'|" < ${srcdir}/nxs.py > $(DESTDIR)${pkgpythondir}/nxs.py
+
+# python setup.py install --root=$(DESTDIR)
+
+include $(top_srcdir)/build_rules.am
diff --git a/dir_syntax.cmake b/dir_syntax.cmake
new file mode 100644
index 0000000..c201a84
--- /dev/null
+++ b/dir_syntax.cmake
@@ -0,0 +1,5 @@
+#
+# syntax:    cmake -DNATIVE:PATH="something" -P dir_syntax.cmake
+#
+file(TO_CMAKE_PATH "${NATIVE}" TRANS)
+file(WRITE "dir_syntax.txt" "${TRANS}")
\ No newline at end of file
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..0ee35dc
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,37 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_subdirectory (api)
+add_subdirectory (doxygen)
+#add_subdirectory (howto)
+add_subdirectory (nxdict)
+add_subdirectory (tech_ref)
+#add_subdirectory (tutorial)
+
+install (FILES README.doc DESTINATION ${NXDOCDIR} COMPONENT Documentation)
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..692769c
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,15 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id$
+#
+
+# documenttion subdirectories
+SUBDIRS=api nxdict tech_ref doxygen
+
+nxdocdir		= $(NXDOCDIR)
+
+# add files and example code here from this directory
+nxdoc_DATA		= README.doc
+
+EXTRA_DIST		= README.doc
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..063133b
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,9 @@
+*
+* This file is part of CVS only and not part of the install
+* kit. Put comments for the install kit into README.doc
+*
+Documentation is installed into $(NXDOCDIR) which is specified
+in configure.ac - usually /usr/local/nexus/doc/{api,tutorial,...}
+
+--
+$Id$
diff --git a/doc/README.doc b/doc/README.doc
new file mode 100644
index 0000000..614185a
--- /dev/null
+++ b/doc/README.doc
@@ -0,0 +1,10 @@
+Various bits of NeXus documentation
+
+api: 		NeXus API documentation
+definitions:	NeXus definitions documentation
+howto:		NeXus howto and FAQs
+nxdict:		NXdict (NXD) API reference
+tutorial:	NeXus tutorial
+
+--
+$Id: README,v 1.1 2005/06/07 11:11:14 faa59 Exp $
diff --git a/doc/api/CMakeLists.txt b/doc/api/CMakeLists.txt
new file mode 100644
index 0000000..baaafdf
--- /dev/null
+++ b/doc/api/CMakeLists.txt
@@ -0,0 +1,30 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+install (FILES napi.tex DESTINATION ${NXDOCDIR}/api COMPONENT Documentation)
+
diff --git a/doc/api/Makefile.am b/doc/api/Makefile.am
new file mode 100644
index 0000000..720a8e5
--- /dev/null
+++ b/doc/api/Makefile.am
@@ -0,0 +1,11 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id$
+#
+nxapidocdir		= $(NXDOCDIR)/api
+
+# add files and example code here
+nxapidoc_DATA		= napi.tex
+
+EXTRA_DIST		= napi.tex
diff --git a/doc/api/NeXusIntern.html b/doc/api/NeXusIntern.html
new file mode 100644
index 0000000..63d4115
--- /dev/null
+++ b/doc/api/NeXusIntern.html
@@ -0,0 +1,497 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head><title>NeXusIntern.radi</title>
+<base href="file:///afs/psi.ch/user/k/koennecke/src/trunk/doc/api/">
+<LINK rel="stylesheet" type="text/css" href="radi.css"></head><body>
+<center>
+<h1>NeXus Programmers Reference </h1>
+<p>Mark Koennecke<br>
+January 2007
+</center>
+</p><p>This is a description of the internal working of the ANSI-C language NeXus-API.
+This is required reading for everyone who attempts to make changes to the 
+NeXus core API. But be warned: this is not for the faint hearted. A successfull 
+NeXus-API hacker needs a solid understanding of advanced C programming techniques 
+and the HDF-4, HDF-5 and Mini-XML API's. Including their quirks and limitations.
+And for writing language bindings one needs to know about the foreign function 
+interface conventions of the target language of the binding.      
+ 
+</p><h1>The Top Level NeXus API </h1>
+<p>The NeXus-API consists of a set of functions for creating NeXus files and storing 
+data and attributes in them. All user visible NeXus data types and functions are 
+protoyped in the header file: napi.h. besides the normal function protoypes, there 
+als exists prototypes for function names adjusted in such a way that they can 
+be called from FORTRAN. Also several internal support functions for the FORTRAN 
+interface are defined.   
+</p><p>As of 2007, the NeXus-API supports three different file 
+formats: HDF-4, HDF-5 and XML. This has a couple of implications:
+One of them is that there are two categories of functions in the NeXus-API:
+</p><ul><li>Most functions are specific to the actual file format used.
+</li><li>Some functions can be expressed in terms of the more primitive file 
+ access functions. Such functions are directly implemented in napi.c.
+</li></ul><p>In an object oriented world the issue with the file type specific funtions would 
+be solved through ploymorphy: there would be a base class specifying the interface and 
+file type specific derived classes  which overload the methods with appropriate ones.
+For reasons of portability the NeXus group choose to implement the NeXus-API in C. Thus 
+polymoprhy had to be implemented in plain C. In order to do this all NeXus functions 
+either create or take a pointer to a NeXus private data structure as a parameter. 
+The current implementation of this data structure looks like this:
+<pre>
+typedef struct {
+   NXhandle *pNexusData;   
+   int stripFlag;
+   NXstatus ( *nxclose)(NXhandle* pHandle);
+   NXstatus ( *nxflush)(NXhandle* pHandle);
+   NXstatus ( *nxmakegroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+   NXstatus ( *nxopengroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+   NXstatus ( *nxclosegroup)(NXhandle handle);
+   NXstatus ( *nxmakedata) (NXhandle handle, CONSTCHAR* label, int datatype, 
+                            int rank, int dim[]);
+   NXstatus ( *nxcompmakedata) (NXhandle handle, CONSTCHAR* label, int datatype, 
+                                int rank, int dim[], int comp_typ, int bufsize[]);
+   NXstatus ( *nxcompress) (NXhandle handle, int compr_type);
+   NXstatus ( *nxopendata) (NXhandle handle, CONSTCHAR* label);
+   NXstatus ( *nxclosedata)(NXhandle handle);
+   NXstatus ( *nxputdata)(NXhandle handle, void* data);
+   NXstatus ( *nxputattr)(NXhandle handle, CONSTCHAR* name, void* data, int iDataLen, 
+                          int iType);
+   NXstatus ( *nxputslab)(NXhandle handle, void* data, int start[], int size[]);    
+   NXstatus ( *nxgetdataID)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxmakelink)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxmakenamedlink)(NXhandle handle, CONSTCHAR *newname, NXlink* pLink);
+   NXstatus ( *nxgetdata)(NXhandle handle, void* data);
+   NXstatus ( *nxgetinfo)(NXhandle handle, int* rank, int dimension[], int* datatype);
+   NXstatus ( *nxgetnextentry)(NXhandle handle, NXname name, NXname nxclass, 
+                              int* datatype);
+   NXstatus ( *nxgetslab)(NXhandle handle, void* data, int start[], int size[]);
+   NXstatus ( *nxgetnextattr)(NXhandle handle, NXname pName, int *iLength, int *iType);
+   NXstatus ( *nxgetattr)(NXhandle handle, char* name, void* data, int* iDataLen, 
+                          int* iType);
+   NXstatus ( *nxgetattrinfo)(NXhandle handle, int* no_items);
+   NXstatus ( *nxgetgroupID)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxgetgroupinfo)(NXhandle handle, int* no_items, NXname name, 
+                              NXname nxclass);
+   NXstatus ( *nxsameID)(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID);
+   NXstatus ( *nxinitgroupdir)(NXhandle handle);
+   NXstatus ( *nxinitattrdir)(NXhandle handle);
+   NXstatus ( *nxsetnumberformat)(NXhandle handle, int type, char *format);
+   NXstatus ( *nxprintlink)(NXhandle handle, NXlink* link);
+} NexusFunction, *pNexusFunction;</pre>
+Basically this structure holds another pointer to a file type specific data structure and a 
+lot of function pointers for the NeXus functions. A typical top level NeXus-API function 
+implementation then looks like this:
+<pre>
+NXstatus  NXmakegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
+{
+     pNexusFunction pFunc = handleToNexusFunc(fid);
+     return pFunc->nxmakegroup(pFunc->pNexusData, name, nxclass);   
+}</pre>
+It just exchanges the fid against a pointer to the NexusFunction structure described above and 
+calls the appropriate file type specific function.   
+</p><p>Now a careful reader should ask how the NexusFunction structure is initialized to point to  
+applicable functions for each file type. This happens in the NXopen function. NXopen figures the 
+file type out by either looking at file creation flags or through inspection of the actual NeXus 
+file to be openend. It then initializes the NexusFunction structure and proceeds to call the 
+file type specific nxopen function in the NexusFunction structure.    
+</p><p>NXopen has to implement another complication: the NeXus-API searches NeXus files in a NeXus search path 
+defined through the environment variable NX_LOAD_PATH. This is done in NXopen; the located file is 
+then opened through NXinternalopen.
+</p><p>The NeXus-API has an external file linking feauture. When the NeXus-API encounters a group with the 
+attribute <i>napimount</i> it looks for a URL to a group in another file and opens the group in the 
+other file without the user noticing anything. If such a special group is closed, the external file 
+must be closed and the original file reenterd.  This had to be implemented at the top level as 
+the external linking feauture is supposed to work on top of any of the supported file formats. The 
+functions NXopengroup and NXclosegroup have been instrumented in a suitable way to support external 
+linking. But in order to do this some information is needed:
+</p><ul><li>The nesting hierarchy of files
+</li><li>The information when to close an external file and step back into the source file of an 
+ external link.
+</li></ul><p>This information is held in a file stack which is implemented in nxstack.h and nxstack.c. When 
+entering a file the files name and corresponding NexusFunction structure is pushed onto the stack. 
+When a file is closed, this data is popped again. For the test when an externally linked  file is 
+to be closed, the NXlink IDs as returned by NXgetgroupID are used. A pointer to such a file stack 
+is currently the actual structure to which the NeXus file handle NXhandle points to. External 
+linking is also the cause for the call to handleToNexusFunc in the function example above: this
+function retrieves the appropriate NexusFunction structure from the file stack.    
+</p><p>Thus the NeXus-API can be approached as consisting of three different layers:
+</p><ol><li>The file stack layer
+</li><li>The NexusFunction layer which implements file type polymorphy
+</li><li>A driver layer implementing the functions to access files in the different file 
+ formats of NeXus. 
+</li></ol> <h2>NeXus-API Error Handling </h2>
+<p>All API's throw errors any now and then. Most are caused by the user, the rest are more serious...
+Whatever, the NeXus-API programmer needs a way to process such errors. In many cases the NeXus default: 
+printing the error to stdout is good enough. But in a GUI one might pop up a message box or in a Java 
+wrapper one might want to convert the error into an exception. The good news is that the NeXus-API is 
+designed to support this. All errors are reported through a function NXIReportError. NXIReportError has 
+the signature:
+<pre>
+	void NXIReportError(void *pData, char *errorText);</pre>
+A NeXus-API user now can replace the default error reporting function through an own implementation with the 
+function NXMSetError. NXMSetError also allows to pass in a pointer to a user defined data structure which is 
+passed as pData to the error reporting function.  
+</p><h1>NeXus File Drivers </h1>
+<h2>NeXus HDF File Drivers </h2>
+<p>The NeXus file drivers for the HDF file formats HDF-4 and HDF-5 share common features. I recall that 
+NeXus uses a hierarchy in order to organize information storage. But both HDF-API's are not tree based 
+but use an interface which allows to open and close groups and datasets. This is sensible as HDF is designed 
+to support very large data sets which may not necessarily fit into a computers memory in one go. But this also 
+implies that the current position in the hierarchy of a given NeXus file has to be maintained by the NeXus-API.
+Such information is maintained in a stack which is pushed an popped while moving through the hierarchy. This 
+stack also has to hold the positions within pending group and attribute searches through the NXgetnextentry and 
+NXgetnextattr functions. Otherwise recursive searches would break.  
+</p><p>Both HDF APIs make extensive use of integer ID's which act as handles to file interfaces and HDF objects. Of 
+course the HDF NeXus file data structures must maintain a fair share of such ID's too. Great care has to be 
+taken to release all used ID's at the appropriate time. Otherwise memory may be leaked. Or worse things 
+may happen.  
+  
+</p><h2>HDF-4 NeXus File Driver </h2>
+<p>It is worthwhile to know that each HDF-4 object in a HDF-4 file is unambigously identified through its tag and 
+reference (ref) ID.  Which happen to be integer numbers. For the following discussions it is also worth to
+know that Vgroups in HDF-4 are implemented as lists of reference and tag IDs of the objects contained in the 
+Vgroup. The HDF-4 API is very rich. NeXus only uses a subset of the HDF-4 API, namely the Vgroup , the SDS  and 
+the annotation interface.   
+</p><p>The HDF-4 NeXus file driver internally uses this data structure:
+<pre>
+  typedef struct __NexusFile {
+    struct iStack {
+      int32 *iRefDir;
+      int32 *iTagDir;
+      int32 iVref;
+      int32 __iStack_pad;               
+      int iNDir;
+      int iCurDir;
+    } iStack[NXMAXSTACK];
+    struct iStack iAtt;
+    int32 iVID;
+    int32 iSID;
+    int32 iCurrentVG;
+    int32 iCurrentSDS;
+    int iNXID;
+    int iStackPtr;
+    char iAccess[2];
+  } NexusFile, *pNexusFile;</pre>
+</p><dl><dt>iStack
+<dd> The hierarchy stack.
+</dd><dt>iStackPtr
+<dd> a pointer into the hierarchy stack.
+</dd><dt>iAtt
+<dd> for storing the state of an attribute search. 
+</dd><dt>iVID
+<dd> The ID for the Vgroup interface. To be used when interacting with Vgroups.
+</dd><dt>ISID
+<dd> The ID for the SDS interface. To be used when interacting with datasets.
+</dd><dt>iCurrentVG
+<dd> The Id of the currently open Vgroup
+</dd><dt>iCurrentSDS
+<dd> the ID of the currently open SDS. Must be 0 if no SDS open.
+</dd><dt>iNXID
+<dd> an identifier for this data structure. 
+</dd><dt>iAccess
+<dd> The access code (read or write) for this file.
+</dd></dl><p>The hierarchy stack has the following fields:
+</p><dl><dt>iVref
+<dd> The reference ID's of previous Vgroups.
+</dd><dt>iRefDir
+<dd> an array of reference numbers used during searches with NXgetnextentry.
+</dd><dt>iTagDir
+<dd> an array of tag numbers used during searches.
+</dd><dt>iCurDir
+<dd> the current index into iRefDir and iTagDir.
+</dd><dt>iNDir
+<dd> the length of iRefDir and iTagDir.
+</dd><dt>__iStack_pad
+<dd> This makes compilers on 64-bit operating systems happy. 
+</dd></dl><p>At this point it is convenient to discuss how group searches with NXgetnextentry work. On the 
+first call to NXgetnextentry, all reference and tag ID's in the current group are read and 
+copied into iRefDir and iTagDir. iNDir is set to the total number of objects held. iCurDir 
+is set to 0 and data for the first object returned. Subsequent calls to NXgetexentry increment 
+iCurDir and return appropriate data. Until the directory is exhausted and NX_EOD is returned. 
+The internal functions NXIInitDir and NXIKillDir help with the management of this.  
+</p><p>All group and SDS search code in the NeXus-HDF-4 driver suffer from the fact that different 
+search functions have to be used when searching at root level or within a Vgroup. 
+NXIFindVGroup and NXIFindSDS are helper functions for locating the appropriate objects. Both 
+return the reference ID of a suitable object on success or NX_EOD in the case of failure. 
+</p><p>Attribute searches are simpler: HDF-4 objects have arrays of attributes. And the ID of an attribute is 
+simply the index into that array. Thus the total number of attributes is stored in iNDir at the start 
+of an attribute search and iCurDir set to 0. Further calls increment iCurDir and return appropriate 
+data until the attributes are exhausted. (NOTE: Here is a subtle bug waiting to happen: when a group 
+search is mixed with an attribute search, things may go wrong. It would be better to have separate 
+fields for the attribute search. That this has not been noticed yet is partly due to the fact that
+group attributes were introduced only recently).
+</p><p>Another issue is the implementation of named links. This is links to other objects in the NeXus file 
+which appear under a different name in the linking Vgroup. This is not supported by the HDF-4 API:
+objects are identified by their reference ID and tags and names and class names are attributes to the 
+object. This was solved by creating SDSs and Vgroups with the required name. Such objects then have an 
+attribute <i>NAPIlink</i> which holds the tag and reference IDs of the linked item. The internal function 
+findNapiClass and NX4opengroup and NX4opendata check for the existence of this attribute and act 
+accordingly.
+</p>   
+<p>The initializations in NX4open and NXclose  have to happen in the order as implemented. 
+Otherwise  ugly things may happen. It just does not work.
+</p><p>NX4flush is implemented as a close and a open of the file. This is because HDF-4 has no proper flush.
+</p><h2>HDF-5 NeXus File Driver </h2>
+<p>The HDF-5 API addresses objects in HDF-5 files through unix like path strings. This requires some string 
+processing in the file driver implementation. HDF-5 does not support class names for groups as HDF-4 did. The 
+HDF-5 NeXus file driver solves this problem through the use of a group attribute called NX_class. There are 
+also no file global attributes as in HDF-4. Such attributes are implemented as attributes to the root (/) 
+group in the HDF-5 file driver.
+</p><p>Searches in HDF-5 work differently too: HDF-5 provides iterators which call a user supplied function for each 
+element to be searched. The user supplied function then must store the data it needs about the element in an own 
+data structure. The return value of the user supplied function also determines how the iteration proceeds. 
+</p><p>Another source of complexity is HDF-5 data transfer. HDF-5 transfers data between a file data space and an in memory 
+data space. Each of these data spaces has its own type, size etc. And each of these items has its own ID. This 
+causes an proliferation of IDs. The nice thing about the scheme though is that the HDF-5 library takes care of 
+all necessary conversions which need to happen between the various data spaces. 
+</p><p>A special topic is closing files. In any other API closing a file also removes all resources associated with the 
+file. This is by default not the case with HDF-5: if any ID is not released the HDF-5 library will keep the file
+open somehow. The HDF-5 team told me that some (paying) customer wanted this. Anyway: with the call to 
+H5Pset_fclose_degree in NX5open proper operation is reestablished again: i.e. a call to NX5close really closes the 
+file. Additioannly there is some code in NX5open which can print the number of handles left open. This can be 
+useful for debugging.
+</p><p>The HDF-5 NeXus driver private data structure is this:
+<pre>
+  typedef struct __NexusFile5 {
+        struct iStack5 {
+          char irefn[1024];
+          int iVref;
+          int iCurrentIDX;
+        } iStack5[NXMAXSTACK];
+        struct iStack5 iAtt5;
+        int iVID;
+        int iFID;
+        int iCurrentG;
+        int iCurrentD;
+        int iCurrentS;
+        int iCurrentT;
+        int iCurrentA;
+        int iNX;
+        int iNXID;
+        int iStackPtr;
+        char *iCurrentLGG;
+        char *iCurrentLD;
+        char name_ref[1024];
+        char name_tmp[1024];
+        char iAccess[2];
+  } NexusFile5, *pNexusFile5;</pre> 
+</p><dl><dt>iAtt
+<dd> The hierarchy stack
+</dd><dt>iStackPtr
+<dd> the pointer into the hierarchy stack. 
+</dd><dt>iFID
+<dd> HDF-5 file handle
+</dd><dt>iCurrentG
+<dd> handle of the current open group.
+</dd><dt>iCurrentD
+<dd> handle of currently open dataset
+</dd><dt>iCurrentT
+<dd> handle to type of currently open dataset
+</dd><dt>iCurrentS
+<dd> handle to data space of currently open dataset
+</dd><dt>iCurrentA
+<dd> temporary handle of an open attribute.
+</dd><dt>iNX
+<dd>  used in group searches
+</dd><dt>iNXID
+<dd> signature of data structure
+</dd><dt>iCurrentLGG
+<dd> name of last openened group
+</dd><dt>iCurrentLD
+<dd> name of last openen dataset. Has length 0 when no dataset open.
+</dd><dt>name_ref
+<dd> path to current group
+</dd><dt>name_tmp
+<dd> some group path
+</dd><dt>iAccess
+<dd> file access code
+</dd></dl><p>The hierarchy stack has the fields:
+</p><dl><dt>irefn
+<dd> The name of the group
+</dd><dt>iVref
+<dd> handle to group 
+</dd><dt>iCurrentIDX
+<dd> the current position in a group search
+</dd></dl><h2>XML Nexus-API Driver </h2>
+<p>The XML format for NeXus was demanded for two reasons:
+</p><ul><li>XML is the buzzword of the day
+</li><li>People want a format where they can edit their data with an editor.
+</li></ul><p>In due course a NeXus-XML file format had been defined. However, XML has one problem: 
+it is not designed to handle large amounts of numeric data well. This showed during a survey 
+of XML parsing libraries: most would handle a large block of numbers as a large block
+of text which is very unwieldly for handling numbers. The implementation in Mike Sweets 
+Mini-XML library was slightly better: a node would be created for each number. Still this 
+is difficult for copying data in and wastes a lot of space. This is another difference to 
+the HDF data formats: for XML the whole tree would have to be read into memory for reading 
+ or created in memory before it could be written to file. This is because XML has no way 
+to address single objects in a file as HDF has. A way to circumvent this problem was to 
+introduce a custom data node into Mini-XML together with user definable callback functions 
+for reading and writing such data. This was done and was included into the standard 
+Mini-XML library by its author: Mike Sweet. The custom data which is used to keep data in 
+memory is an own abstraction of a multi dimensional dataset. This is implemented in 
+nxdataset.h and nxdataset.c. Most of the functions there are straight forward. The custom 
+I/O functions required to interface to Mini-XML live in the files nxio.h and nxio.c. The 
+heart of this are the callback functions:
+</p><dl><dt>nexusTypeCallback
+<dd> callback to determine the type of a node when reading.
+</dd><dt>nexusLoadcallback
+<dd> a callback function for reading numeric data.
+</dd><dt>nexusWriteCallback
+<dd> a callback function to write numeric data. 
+</dd></dl><p>Then there are some pretty self explaining support functions.
+</p><p>With this out of the way most of the NeXus-API could be expressed in terms of the Mini-XML 
+tree navigation and creation functions. Data transfer works through the nxdataset functions.
+But there is a limitation: unlimted dimensions are not supported for XML. 
+</p><p>But there is another complication: XML does not know a thing about links. For links a "
+special node with the name NAPIlink was introduced. 
+An attribute <i>target</i> to such a node points to the target of the link. If the link is a named link 
+the NAPIlink node will also have an attribute <i>name</i>. The 
+implementations of NXXopengroup, NXXopendata NXXclosegroup and NXXclosedata check for NAPIlink 
+nodes and silently follow them. However this means that the XML driver jumps criss and cross 
+through the Mini-XML tree structure when following links. In order to remember to which node to 
+go back a stack was once again needed in the XML-NeXus driver data structure.
+</p><pre>
+typedef struct {
+    mxml_node_t *current;
+    mxml_node_t *currentChild;
+    int currentAttribute;
+}xmlStack;
+/*---------------------------------------------------------------------*/
+typedef struct {
+  mxml_node_t *root;           /* root node */
+  int readOnly;                /* read only flag */
+  int stackPointer;            /* stack pointer */
+  char filename[1024];         /* file name, for NXflush, NXclose */
+  xmlStack stack[NXMAXSTACK];  /* stack */
+}XMLNexus, *pXMLNexus;</pre> 
+<p>The stack structures fields are:
+</p><dl><dt>current
+<dd> the current node
+</dd><dt>currentChild
+<dd> The current child from which to continue in a group search
+</dd><dt>currentAttribute
+<dd> The number of the current attribute in an attribute search.
+ 
+</dd></dl><p>The XMLNexus structure has:
+</p><dl><dt>root
+<dd> The root of the Mini-XML node tree
+</dd><dt>readOnly
+<dd> a flag for a read only file
+</dd><dt>stack
+<dd> The stack
+</dd><dt>stackPointer
+<dd> The current position in the stack
+</dd><dt>filename
+<dd> the filename of the XML-neXus file
+</dd></dl><p>To make this explicitly  clear: Reading and writing NeXus-XML files works as operations on in 
+memory trees. This has a couple of consequences:
+</p><ul><li>NeXus-XML is not suitable for large datasets. If you have very large datsets: use HDF-5!
+</li><li>A file will only be writen when a NXflush or a NXclose is called.  
+</li></ul><p>Another limitation is that dataset compression does not make sense in XML. The 
+compression related functions are empty. 
+</p><h1>NeXus Language Bindings </h1>
+<p>Various bindings exist from the C-language NeXus-API to other programming languages. 
+This section discusses implementation details for some of the supoorted language bindings.
+</p><h2>FORTRAN 77 </h2>
+<p>The F77 language bindings reside in the files napif.inc and napif.f. Napif.inc must be included by 
+all programs using the NeXus F77 language bindings. Napif.f defines various constants and all 
+NeXus functions as functions returning integers. Napif.f then implements the actual F77-API. Mostly 
+it is a very thin layer around the NeXus functions but there are a few twists.
+</p><p>All functions using or returning strings must take care to convert F77 strings to C-strings and vice 
+versa. For this support functions are provided. 
+</p><p>The NeXus-API stores data in C-storage order but F77 requires fortan storage order. In order to 
+achieve this dimensions have to be reversed. This happens through support functions in napi.c.
+</p><p>The NeXus API requires some structures to be passed around, most notably the NXhandle and the 
+NXlink structures. This is done by copying such items onto F77 arrays large enough to 
+hold the data.
+</p><h2>Scripting Language Bindings through SWIG </h2>
+<p>Many popular scripting languages have a foreign function call interface. This allows them to 
+interface to user supplied functions written in ANSI-C and packaged as a shared library. 
+There is a tool called Software Wrapper and Interface Generator (SWIG) which takes as input an 
+API description file and the ID of a scripting language and the goes away and generates wrapper 
+code for the scripting languages foreign function call interface.  Such an API description file 
+has been generated for the NeXus-API in order to support all scripting languages for which suitable 
+SWIG drivers exist. See the SWIG WWW-site (http://www.swig.org) for details.  
+</p><p>Most scripting languages have bad support for multi dimensional arrays. This is why the NeXus SWIG 
+interface supplies its own abstraction for such datasets. This is implemented in nxdataset.h and 
+nxdataset.c. Nxdataset.i is the SWIG interface definition for the dataset API.
+</p><p>The raw NeXus-API proved to be difficult to wrap with SWIG. It became necessary to wrap most 
+NeXus-API functions with a SWIG helper wrapper. Those helpers live in   nxinterhelper.h and 
+nxinterhelper.c. The helper functions basically make functions modifying pointers return 
+pointers and data handling functions use the nxdataset abstraction. 
+</p><p>The SWIG wrapped NeXus-API functions either return integer error codes or, when pointers are desired, 
+NULL pointers when errors occur. In such cases the text message for the error can be inquired with an 
+additional function: nx_getlasterror.
+</p><p>How the SWIG wrappers for the NeXus-API work is of course slightly different for each scripting 
+language. The description in nxinter.tex for Tcl together with the SWIG documentation for your 
+target scripting language of choice should get you started. 
+</p><h2>NeXus-Java Binding </h2>
+<p>The ANSI-C NeXus-API was wrapped with the Java Native Methods Interface (JNI) for use in Java 
+programs. The Java-NeXus code consists basically of two parts:
+</p><ul><li>Some Java code implementing a Java interface
+</li><li>Some C code which translates Java JNI calls into NeXus-API functions and maps return values back 
+ to Java values. This code together with the base NeXus-API and the required libraries is used to 
+ build a shared library which is loaded into the Java Virtual Machine at runtime prior to the first 
+ use of the Java-NeXus bindings.
+</li></ul><p>The Java-NeXus wrapper had to solve a couple of problems:
+</p><ul><li>Design issues
+</li><li>Java has no pointers
+</li><li>Data handling
+</li><li>Error handling
+</li><li>Link data handling
+</li></ul><p>In order to go with the Java look and file one might expect that the Java-NeXus binding 
+would consist of Java classes for files, groups, datasets and attributes. After careful 
+consideration this idea was discarded in favour of a plain Java class implementing a 
+NeXus file object. One reason is that such objects are not really idependent objects in a 
+NeXus file but are part of a complex state machine withing the NeXus and HDF-APIs. Keeping 
+such objects in sync with a NeXus file would have caused a nightmare. Instead such a more 
+object oriented Java NeXus-API may be implemented on top of the basic Java-NeXus binding. 
+No one cared enough to do this until now. Thus we are left with a Java interface where we 
+have the NexusFile as the base interface objects. This implements a NexusFileInterface. 
+This layer of abstraction was added to support future NexusFileInterface implementations 
+ based perhaps on a networked access to NeXus files. Which never was implemented. But no one
+complained about this too. Further classes are a helper class for links and 
+an exception class.
+</p><p>The Java language has no pointers but the NeXus-API requires pointers as file handles. This 
+problem was solved through a little dictionary which maps integer handles to real  pointers.
+Java thus only has to deal with the integer handles which get translated into pointers at 
+each call in the JNI-interface. This looks like this:
+<pre>
+    nxhandle =  (NXhandle)HHGetPointer(handle);</pre>  
+The dictionary implementation lives in the files handle.h and handle.c. The current implementation 
+supports 8192 files open at the same time only. But this proved enough so far. 
+</p><p>The data in the NeXus-API is provided as arrays of native number types. But Java uses network byte 
+order as its own binary representation of numbers in the Java Virtual Machine. A conversion was 
+required. For reasons of laziness and admiration, the conversion routines were copied from the 
+HDF-4 Java API. The conversion code lives in the  ncsa/hdf/hdflib directory and its JNI 
+counterpart in hdfnativeImp.c. The conversion happens in the Java code sections acting upon 
+an HDFArray.
+</p><p>The NeXus-API prints errors to stdout. Java handles errors by throwing exceptions all over the 
+place. In order to achieve this the Java-NeXus API replaces the standard NeXus-API error handler 
+with an own one which throws NexusExceptions. This is implemented in the function JapiError in
+NexusFile.c.
+</p><p>In order to implement linking of objects in NeXus files some information about the objects to link 
+must be carried around. In the NeXus-API this happens in the NXlink structure. This structure is 
+mapped to a NXlink class in the Java-NeXus API. This has to have corresponding fields to the 
+C-language structure. The JNI wrapper copies the data required for this structure back and forth.
+</p><p>Otherwise most of the wrapper routines in NexusFile.c just contain the stuff required to access 
+Java data types from C, invoke the NeXus-API routine, and copy data from C back into Java. See the 
+JNI documentation for details. 
+</p><h1>New NeXus Functions </h1>
+<p>With all this, extending the NeXus-API with a new function involves a lot of steps. I assume the function 
+requires driver layer functionality, else the first few steps may be disregarded.
+</p><ol><li>Implement the new function in each driver layer
+</li><li>Add the new function to the NeXusFunction structure
+</li><li>Make sure that new function is assigned properly in the driver implementations.
+</li><li>Make a new protoype for the function in napi.h
+</li><li>Implement the function in napi.c
+</li><li>Add the new function to the lists in napif.inc and provide a wrapper in napif.f
+</li><li>Create a new SWIG helper function in nxinterhelper.h and nxinterhelper.c
+</li><li>Edit nxinter.i to have a SWIG wrapper generated for the new function.
+</li><li>Add the new function to the NexusFileInterface and NexusFile classes in the Java-API
+</li><li>Write a JNI wrapper in NexusFile.c: take care of the convoluted function names required by JNI 
+ and the JNI conventions.  
+</li><li>Make sure the new function also appears in language bindings not mentioned in this document.
+</li></ol> <h1>Summary </h1>
+<p>Congratulations! You made it to the end of this boring and lengthy article.     
+</p>  
+</body></html>
+
diff --git a/doc/api/NeXusIntern.pdf b/doc/api/NeXusIntern.pdf
new file mode 100644
index 0000000..ceca224
Binary files /dev/null and b/doc/api/NeXusIntern.pdf differ
diff --git a/doc/api/NeXusIntern.radi b/doc/api/NeXusIntern.radi
new file mode 100755
index 0000000..d9d9024
--- /dev/null
+++ b/doc/api/NeXusIntern.radi
@@ -0,0 +1,509 @@
+::
+= NeXus Programmers Reference =
+Mark Koennecke%%%
+January 2007
+::
+
+
+
+This is a description of the internal working of the ANSI-C language NeXus-API.
+This is required reading for everyone who attempts to make changes to the 
+NeXus core API. But be warned: this is not for the faint hearted. A successfull 
+NeXus-API hacker needs a solid understanding of advanced C programming techniques 
+and the HDF-4, HDF-5 and Mini-XML API's. Including their quirks and limitations.
+And for writing language bindings one needs to know about the foreign function 
+interface conventions of the target language of the binding.      
+ 
+= The Top Level NeXus API =
+The NeXus-API consists of a set of functions for creating NeXus files and storing 
+data and attributes in them. All user visible NeXus data types and functions are 
+protoyped in the header file: napi.h. besides the normal function protoypes, there 
+als exists prototypes for function names adjusted in such a way that they can 
+be called from FORTRAN. Also several internal support functions for the FORTRAN 
+interface are defined.   
+
+
+As of 2007, the NeXus-API supports three different file 
+formats: HDF-4, HDF-5 and XML. This has a couple of implications:
+One of them is that there are two categories of functions in the NeXus-API:
+* Most functions are specific to the actual file format used.
+* Some functions can be expressed in terms of the more primitive file 
+ access functions. Such functions are directly implemented in napi.c.
+
+In an object oriented world the issue with the file type specific funtions would 
+be solved through ploymorphy: there would be a base class specifying the interface and 
+file type specific derived classes  which overload the methods with appropriate ones.
+For reasons of portability the NeXus group choose to implement the NeXus-API in C. Thus 
+polymoprhy had to be implemented in plain C. In order to do this all NeXus functions 
+either create or take a pointer to a NeXus private data structure as a parameter. 
+The current implementation of this data structure looks like this:
+{{{
+typedef struct {
+   NXhandle *pNexusData;   
+   int stripFlag;
+   NXstatus ( *nxclose)(NXhandle* pHandle);
+   NXstatus ( *nxflush)(NXhandle* pHandle);
+   NXstatus ( *nxmakegroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+   NXstatus ( *nxopengroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+   NXstatus ( *nxclosegroup)(NXhandle handle);
+   NXstatus ( *nxmakedata) (NXhandle handle, CONSTCHAR* label, int datatype, 
+                            int rank, int dim[]);
+   NXstatus ( *nxcompmakedata) (NXhandle handle, CONSTCHAR* label, int datatype, 
+                                int rank, int dim[], int comp_typ, int bufsize[]);
+   NXstatus ( *nxcompress) (NXhandle handle, int compr_type);
+   NXstatus ( *nxopendata) (NXhandle handle, CONSTCHAR* label);
+   NXstatus ( *nxclosedata)(NXhandle handle);
+   NXstatus ( *nxputdata)(NXhandle handle, void* data);
+   NXstatus ( *nxputattr)(NXhandle handle, CONSTCHAR* name, void* data, int iDataLen, 
+                          int iType);
+   NXstatus ( *nxputslab)(NXhandle handle, void* data, int start[], int size[]);    
+   NXstatus ( *nxgetdataID)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxmakelink)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxmakenamedlink)(NXhandle handle, CONSTCHAR *newname, NXlink* pLink);
+   NXstatus ( *nxgetdata)(NXhandle handle, void* data);
+   NXstatus ( *nxgetinfo)(NXhandle handle, int* rank, int dimension[], int* datatype);
+   NXstatus ( *nxgetnextentry)(NXhandle handle, NXname name, NXname nxclass, 
+                              int* datatype);
+   NXstatus ( *nxgetslab)(NXhandle handle, void* data, int start[], int size[]);
+   NXstatus ( *nxgetnextattr)(NXhandle handle, NXname pName, int *iLength, int *iType);
+   NXstatus ( *nxgetattr)(NXhandle handle, char* name, void* data, int* iDataLen, 
+                          int* iType);
+   NXstatus ( *nxgetattrinfo)(NXhandle handle, int* no_items);
+   NXstatus ( *nxgetgroupID)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxgetgroupinfo)(NXhandle handle, int* no_items, NXname name, 
+                              NXname nxclass);
+   NXstatus ( *nxsameID)(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID);
+   NXstatus ( *nxinitgroupdir)(NXhandle handle);
+   NXstatus ( *nxinitattrdir)(NXhandle handle);
+   NXstatus ( *nxsetnumberformat)(NXhandle handle, int type, char *format);
+   NXstatus ( *nxprintlink)(NXhandle handle, NXlink* link);
+} NexusFunction, *pNexusFunction;
+}}}
+Basically this structure holds another pointer to a file type specific data structure and a 
+lot of function pointers for the NeXus functions. A typical top level NeXus-API function 
+implementation then looks like this:
+{{{
+NXstatus  NXmakegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
+{
+     pNexusFunction pFunc = handleToNexusFunc(fid);
+     return pFunc->nxmakegroup(pFunc->pNexusData, name, nxclass);   
+}
+}}}
+It just exchanges the fid against a pointer to the NexusFunction structure described above and 
+calls the appropriate file type specific function.   
+
+Now a careful reader should ask how the NexusFunction structure is initialized to point to  
+applicable functions for each file type. This happens in the NXopen function. NXopen figures the 
+file type out by either looking at file creation flags or through inspection of the actual NeXus 
+file to be openend. It then initializes the NexusFunction structure and proceeds to call the 
+file type specific nxopen function in the NexusFunction structure.    
+
+NXopen has to implement another complication: the NeXus-API searches NeXus files in a NeXus search path 
+defined through the environment variable NX_LOAD_PATH. This is done in NXopen; the located file is 
+then opened through NXinternalopen.
+
+The NeXus-API has an external file linking feauture. When the NeXus-API encounters a group with the 
+attribute ~~napimount~~ it looks for a URL to a group in another file and opens the group in the 
+other file without the user noticing anything. If such a special group is closed, the external file 
+must be closed and the original file reenterd.  This had to be implemented at the top level as 
+the external linking feauture is supposed to work on top of any of the supported file formats. The 
+functions NXopengroup and NXclosegroup have been instrumented in a suitable way to support external 
+linking. But in order to do this some information is needed:
+* The nesting hierarchy of files
+* The information when to close an external file and step back into the source file of an 
+ external link.
+This information is held in a file stack which is implemented in nxstack.h and nxstack.c. When 
+entering a file the files name and corresponding NexusFunction structure is pushed onto the stack. 
+When a file is closed, this data is popped again. For the test when an externally linked  file is 
+to be closed, the NXlink IDs as returned by NXgetgroupID are used. A pointer to such a file stack 
+is currently the actual structure to which the NeXus file handle NXhandle points to. External 
+linking is also the cause for the call to handleToNexusFunc in the function example above: this
+function retrieves the appropriate NexusFunction structure from the file stack.    
+
+Thus the NeXus-API can be approached as consisting of three different layers:
+# The file stack layer
+# The NexusFunction layer which implements file type polymorphy
+# A driver layer implementing the functions to access files in the different file 
+ formats of NeXus. 
+
+== NeXus-API Error Handling ==
+All API's throw errors any now and then. Most are caused by the user, the rest are more serious...
+Whatever, the NeXus-API programmer needs a way to process such errors. In many cases the NeXus default: 
+printing the error to stdout is good enough. But in a GUI one might pop up a message box or in a Java 
+wrapper one might want to convert the error into an exception. The good news is that the NeXus-API is 
+designed to support this. All errors are reported through a function NXIReportError. NXIReportError has 
+the signature:
+{{{
+	void NXIReportError(void *pData, char *errorText);
+}}}
+A NeXus-API user now can replace the default error reporting function through an own implementation with the 
+function NXMSetError. NXMSetError also allows to pass in a pointer to a user defined data structure which is 
+passed as pData to the error reporting function.  
+
+= NeXus File Drivers =
+
+== NeXus HDF File Drivers ==
+The NeXus file drivers for the HDF file formats HDF-4 and HDF-5 share common features. I recall that 
+NeXus uses a hierarchy in order to organize information storage. But both HDF-API's are not tree based 
+but use an interface which allows to open and close groups and datasets. This is sensible as HDF is designed 
+to support very large data sets which may not necessarily fit into a computers memory in one go. But this also 
+implies that the current position in the hierarchy of a given NeXus file has to be maintained by the NeXus-API.
+Such information is maintained in a stack which is pushed an popped while moving through the hierarchy. This 
+stack also has to hold the positions within pending group and attribute searches through the NXgetnextentry and 
+NXgetnextattr functions. Otherwise recursive searches would break.  
+
+Both HDF APIs make extensive use of integer ID's which act as handles to file interfaces and HDF objects. Of 
+course the HDF NeXus file data structures must maintain a fair share of such ID's too. Great care has to be 
+taken to release all used ID's at the appropriate time. Otherwise memory may be leaked. Or worse things 
+may happen.  
+  
+== HDF-4 NeXus File Driver ==
+It is worthwhile to know that each HDF-4 object in a HDF-4 file is unambigously identified through its tag and 
+reference (ref) ID.  Which happen to be integer numbers. For the following discussions it is also worth to
+know that Vgroups in HDF-4 are implemented as lists of reference and tag IDs of the objects contained in the 
+Vgroup. The HDF-4 API is very rich. NeXus only uses a subset of the HDF-4 API, namely the Vgroup , the SDS  and 
+the annotation interface.   
+
+The HDF-4 NeXus file driver internally uses this data structure:
+{{{
+  typedef struct __NexusFile {
+    struct iStack {
+      int32 *iRefDir;
+      int32 *iTagDir;
+      int32 iVref;
+      int32 __iStack_pad;               
+      int iNDir;
+      int iCurDir;
+    } iStack[NXMAXSTACK];
+    struct iStack iAtt;
+    int32 iVID;
+    int32 iSID;
+    int32 iCurrentVG;
+    int32 iCurrentSDS;
+    int iNXID;
+    int iStackPtr;
+    char iAccess[2];
+  } NexusFile, *pNexusFile;
+}}}
+;iStack: The hierarchy stack.
+;iStackPtr: a pointer into the hierarchy stack.
+;iAtt: for storing the state of an attribute search. 
+;iVID: The ID for the Vgroup interface. To be used when interacting with Vgroups.
+;ISID: The ID for the SDS interface. To be used when interacting with datasets.
+;iCurrentVG: The Id of the currently open Vgroup
+;iCurrentSDS: the ID of the currently open SDS. Must be 0 if no SDS open.
+;iNXID: an identifier for this data structure. 
+;iAccess: The access code (read or write) for this file.
+
+The hierarchy stack has the following fields:
+;iVref: The reference ID's of previous Vgroups.
+;iRefDir: an array of reference numbers used during searches with NXgetnextentry.
+;iTagDir: an array of tag numbers used during searches.
+;iCurDir: the current index into iRefDir and iTagDir.
+;iNDir: the length of iRefDir and iTagDir.
+;__iStack_pad: This makes compilers on 64-bit operating systems happy. 
+At this point it is convenient to discuss how group searches with NXgetnextentry work. On the 
+first call to NXgetnextentry, all reference and tag ID's in the current group are read and 
+copied into iRefDir and iTagDir. iNDir is set to the total number of objects held. iCurDir 
+is set to 0 and data for the first object returned. Subsequent calls to NXgetexentry increment 
+iCurDir and return appropriate data. Until the directory is exhausted and NX_EOD is returned. 
+The internal functions NXIInitDir and NXIKillDir help with the management of this.  
+
+All group and SDS search code in the NeXus-HDF-4 driver suffer from the fact that different 
+search functions have to be used when searching at root level or within a Vgroup. 
+NXIFindVGroup and NXIFindSDS are helper functions for locating the appropriate objects. Both 
+return the reference ID of a suitable object on success or NX_EOD in the case of failure. 
+
+
+Attribute searches are simpler: HDF-4 objects have arrays of attributes. And the ID of an attribute is 
+simply the index into that array. Thus the total number of attributes is stored in iNDir at the start 
+of an attribute search and iCurDir set to 0. Further calls increment iCurDir and return appropriate 
+data until the attributes are exhausted. (NOTE: Here is a subtle bug waiting to happen: when a group 
+search is mixed with an attribute search, things may go wrong. It would be better to have separate 
+fields for the attribute search. That this has not been noticed yet is partly due to the fact that
+group attributes were introduced only recently).
+
+Another issue is the implementation of named links. This is links to other objects in the NeXus file 
+which appear under a different name in the linking Vgroup. This is not supported by the HDF-4 API:
+objects are identified by their reference ID and tags and names and class names are attributes to the 
+object. This was solved by creating SDSs and Vgroups with the required name. Such objects then have an 
+attribute ~~NAPIlink~~ which holds the tag and reference IDs of the linked item. The internal function 
+findNapiClass and NX4opengroup and NX4opendata check for the existence of this attribute and act 
+accordingly.
+
+   
+The initializations in NX4open and NXclose  have to happen in the order as implemented. 
+Otherwise  ugly things may happen. It just does not work.
+
+NX4flush is implemented as a close and a open of the file. This is because HDF-4 has no proper flush.
+
+== HDF-5 NeXus File Driver ==
+The HDF-5 API addresses objects in HDF-5 files through unix like path strings. This requires some string 
+processing in the file driver implementation. HDF-5 does not support class names for groups as HDF-4 did. The 
+HDF-5 NeXus file driver solves this problem through the use of a group attribute called NX_class. There are 
+also no file global attributes as in HDF-4. Such attributes are implemented as attributes to the root (/) 
+group in the HDF-5 file driver.
+
+Searches in HDF-5 work differently too: HDF-5 provides iterators which call a user supplied function for each 
+element to be searched. The user supplied function then must store the data it needs about the element in an own 
+data structure. The return value of the user supplied function also determines how the iteration proceeds. 
+
+Another source of complexity is HDF-5 data transfer. HDF-5 transfers data between a file data space and an in memory 
+data space. Each of these data spaces has its own type, size etc. And each of these items has its own ID. This 
+causes an proliferation of IDs. The nice thing about the scheme though is that the HDF-5 library takes care of 
+all necessary conversions which need to happen between the various data spaces. 
+
+A special topic is closing files. In any other API closing a file also removes all resources associated with the 
+file. This is by default not the case with HDF-5: if any ID is not released the HDF-5 library will keep the file
+open somehow. The HDF-5 team told me that some (paying) customer wanted this. Anyway: with the call to 
+H5Pset_fclose_degree in NX5open proper operation is reestablished again: i.e. a call to NX5close really closes the 
+file. Additioannly there is some code in NX5open which can print the number of handles left open. This can be 
+useful for debugging.
+
+The HDF-5 NeXus driver private data structure is this:
+{{{
+  typedef struct __NexusFile5 {
+        struct iStack5 {
+          char irefn[1024];
+          int iVref;
+          int iCurrentIDX;
+        } iStack5[NXMAXSTACK];
+        struct iStack5 iAtt5;
+        int iVID;
+        int iFID;
+        int iCurrentG;
+        int iCurrentD;
+        int iCurrentS;
+        int iCurrentT;
+        int iCurrentA;
+        int iNX;
+        int iNXID;
+        int iStackPtr;
+        char *iCurrentLGG;
+        char *iCurrentLD;
+        char name_ref[1024];
+        char name_tmp[1024];
+        char iAccess[2];
+  } NexusFile5, *pNexusFile5;
+}}} 
+;iAtt: The hierarchy stack
+;iStackPtr: the pointer into the hierarchy stack. 
+;iFID: HDF-5 file handle
+;iCurrentG: handle of the current open group.
+;iCurrentD: handle of currently open dataset
+;iCurrentT: handle to type of currently open dataset
+;iCurrentS: handle to data space of currently open dataset
+;iCurrentA: temporary handle of an open attribute.
+;iNX:  used in group searches
+;iNXID: signature of data structure
+;iCurrentLGG: name of last openened group
+;iCurrentLD: name of last openen dataset. Has length 0 when no dataset open.
+;name_ref: path to current group
+;name_tmp: some group path
+;iAccess: file access code
+
+The hierarchy stack has the fields:
+;irefn: The name of the group
+;iVref: handle to group 
+;iCurrentIDX: the current position in a group search
+
+== XML Nexus-API Driver ==
+The XML format for NeXus was demanded for two reasons:
+* XML is the buzzword of the day
+* People want a format where they can edit their data with an editor.
+In due course a NeXus-XML file format had been defined. However, XML has one problem: 
+it is not designed to handle large amounts of numeric data well. This showed during a survey 
+of XML parsing libraries: most would handle a large block of numbers as a large block
+of text which is very unwieldly for handling numbers. The implementation in Mike Sweets 
+Mini-XML library was slightly better: a node would be created for each number. Still this 
+is difficult for copying data in and wastes a lot of space. This is another difference to 
+the HDF data formats: for XML the whole tree would have to be read into memory for reading 
+ or created in memory before it could be written to file. This is because XML has no way 
+to address single objects in a file as HDF has. A way to circumvent this problem was to 
+introduce a custom data node into Mini-XML together with user definable callback functions 
+for reading and writing such data. This was done and was included into the standard 
+Mini-XML library by its author: Mike Sweet. The custom data which is used to keep data in 
+memory is an own abstraction of a multi dimensional dataset. This is implemented in 
+nxdataset.h and nxdataset.c. Most of the functions there are straight forward. The custom 
+I/O functions required to interface to Mini-XML live in the files nxio.h and nxio.c. The 
+heart of this are the callback functions:
+;nexusTypeCallback: callback to determine the type of a node when reading.
+;nexusLoadcallback: a callback function for reading numeric data.
+;nexusWriteCallback: a callback function to write numeric data. 
+Then there are some pretty self explaining support functions.
+
+With this out of the way most of the NeXus-API could be expressed in terms of the Mini-XML 
+tree navigation and creation functions. Data transfer works through the nxdataset functions.
+But there is a limitation: unlimted dimensions are not supported for XML. 
+
+But there is another complication: XML does not know a thing about links. For links a \
+special node with the name NAPIlink was introduced. 
+An attribute ~~target~~ to such a node points to the target of the link. If the link is a named link 
+the NAPIlink node will also have an attribute ~~name~~. The 
+implementations of NXXopengroup, NXXopendata NXXclosegroup and NXXclosedata check for NAPIlink 
+nodes and silently follow them. However this means that the XML driver jumps criss and cross 
+through the Mini-XML tree structure when following links. In order to remember to which node to 
+go back a stack was once again needed in the XML-NeXus driver data structure.
+
+{{{
+typedef struct {
+    mxml_node_t *current;
+    mxml_node_t *currentChild;
+    int currentAttribute;
+}xmlStack;
+/*---------------------------------------------------------------------*/
+typedef struct {
+  mxml_node_t *root;           /* root node */
+  int readOnly;                /* read only flag */
+  int stackPointer;            /* stack pointer */
+  char filename[1024];         /* file name, for NXflush, NXclose */
+  xmlStack stack[NXMAXSTACK];  /* stack */
+}XMLNexus, *pXMLNexus;
+}}} 
+
+The stack structures fields are:
+;current: the current node
+;currentChild: The current child from which to continue in a group search
+;currentAttribute: The number of the current attribute in an attribute search.
+ 
+The XMLNexus structure has:
+;root: The root of the Mini-XML node tree
+;readOnly: a flag for a read only file
+;stack: The stack
+;stackPointer: The current position in the stack
+;filename: the filename of the XML-neXus file
+
+To make this explicitly  clear: Reading and writing NeXus-XML files works as operations on in 
+memory trees. This has a couple of consequences:
+* NeXus-XML is not suitable for large datasets. If you have very large datsets: use HDF-5!
+* A file will only be writen when a NXflush or a NXclose is called.  
+
+Another limitation is that dataset compression does not make sense in XML. The 
+compression related functions are empty. 
+
+= NeXus Language Bindings =
+Various bindings exist from the C-language NeXus-API to other programming languages. 
+This section discusses implementation details for some of the supoorted language bindings.
+
+== FORTRAN 77 ==
+The F77 language bindings reside in the files napif.inc and napif.f. Napif.inc must be included by 
+all programs using the NeXus F77 language bindings. Napif.f defines various constants and all 
+NeXus functions as functions returning integers. Napif.f then implements the actual F77-API. Mostly 
+it is a very thin layer around the NeXus functions but there are a few twists.
+
+All functions using or returning strings must take care to convert F77 strings to C-strings and vice 
+versa. For this support functions are provided. 
+
+The NeXus-API stores data in C-storage order but F77 requires fortan storage order. In order to 
+achieve this dimensions have to be reversed. This happens through support functions in napi.c.
+
+The NeXus API requires some structures to be passed around, most notably the NXhandle and the 
+NXlink structures. This is done by copying such items onto F77 arrays large enough to 
+hold the data.
+
+== Scripting Language Bindings through SWIG ==
+Many popular scripting languages have a foreign function call interface. This allows them to 
+interface to user supplied functions written in ANSI-C and packaged as a shared library. 
+There is a tool called Software Wrapper and Interface Generator (SWIG) which takes as input an 
+API description file and the ID of a scripting language and the goes away and generates wrapper 
+code for the scripting languages foreign function call interface.  Such an API description file 
+has been generated for the NeXus-API in order to support all scripting languages for which suitable 
+SWIG drivers exist. See the SWIG WWW-site (http://www.swig.org) for details.  
+
+Most scripting languages have bad support for multi dimensional arrays. This is why the NeXus SWIG 
+interface supplies its own abstraction for such datasets. This is implemented in nxdataset.h and 
+nxdataset.c. Nxdataset.i is the SWIG interface definition for the dataset API.
+
+The raw NeXus-API proved to be difficult to wrap with SWIG. It became necessary to wrap most 
+NeXus-API functions with a SWIG helper wrapper. Those helpers live in   nxinterhelper.h and 
+nxinterhelper.c. The helper functions basically make functions modifying pointers return 
+pointers and data handling functions use the nxdataset abstraction. 
+
+The SWIG wrapped NeXus-API functions either return integer error codes or, when pointers are desired, 
+NULL pointers when errors occur. In such cases the text message for the error can be inquired with an 
+additional function: nx_getlasterror.
+
+How the SWIG wrappers for the NeXus-API work is of course slightly different for each scripting 
+language. The description in nxinter.tex for Tcl together with the SWIG documentation for your 
+target scripting language of choice should get you started. 
+
+== NeXus-Java Binding ==
+The ANSI-C NeXus-API was wrapped with the Java Native Methods Interface (JNI) for use in Java 
+programs. The Java-NeXus code consists basically of two parts:
+* Some Java code implementing a Java interface
+* Some C code which translates Java JNI calls into NeXus-API functions and maps return values back 
+ to Java values. This code together with the base NeXus-API and the required libraries is used to 
+ build a shared library which is loaded into the Java Virtual Machine at runtime prior to the first 
+ use of the Java-NeXus bindings.
+The Java-NeXus wrapper had to solve a couple of problems:
+* Design issues
+* Java has no pointers
+* Data handling
+* Error handling
+* Link data handling
+
+In order to go with the Java look and file one might expect that the Java-NeXus binding 
+would consist of Java classes for files, groups, datasets and attributes. After careful 
+consideration this idea was discarded in favour of a plain Java class implementing a 
+NeXus file object. One reason is that such objects are not really idependent objects in a 
+NeXus file but are part of a complex state machine withing the NeXus and HDF-APIs. Keeping 
+such objects in sync with a NeXus file would have caused a nightmare. Instead such a more 
+object oriented Java NeXus-API may be implemented on top of the basic Java-NeXus binding. 
+No one cared enough to do this until now. Thus we are left with a Java interface where we 
+have the NexusFile as the base interface objects. This implements a NexusFileInterface. 
+This layer of abstraction was added to support future NexusFileInterface implementations 
+ based perhaps on a networked access to NeXus files. Which never was implemented. But no one
+complained about this too. Further classes are a helper class for links and 
+an exception class.
+
+The Java language has no pointers but the NeXus-API requires pointers as file handles. This 
+problem was solved through a little dictionary which maps integer handles to real  pointers.
+Java thus only has to deal with the integer handles which get translated into pointers at 
+each call in the JNI-interface. This looks like this:
+{{{
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+}}}  
+The dictionary implementation lives in the files handle.h and handle.c. The current implementation 
+supports 8192 files open at the same time only. But this proved enough so far. 
+
+The data in the NeXus-API is provided as arrays of native number types. But Java uses network byte 
+order as its own binary representation of numbers in the Java Virtual Machine. A conversion was 
+required. For reasons of laziness and admiration, the conversion routines were copied from the 
+HDF-4 Java API. The conversion code lives in the  ncsa/hdf/hdflib directory and its JNI 
+counterpart in hdfnativeImp.c. The conversion happens in the Java code sections acting upon 
+an HDFArray.
+
+The NeXus-API prints errors to stdout. Java handles errors by throwing exceptions all over the 
+place. In order to achieve this the Java-NeXus API replaces the standard NeXus-API error handler 
+with an own one which throws NexusExceptions. This is implemented in the function JapiError in
+NexusFile.c.
+
+In order to implement linking of objects in NeXus files some information about the objects to link 
+must be carried around. In the NeXus-API this happens in the NXlink structure. This structure is 
+mapped to a NXlink class in the Java-NeXus API. This has to have corresponding fields to the 
+C-language structure. The JNI wrapper copies the data required for this structure back and forth.
+
+Otherwise most of the wrapper routines in NexusFile.c just contain the stuff required to access 
+Java data types from C, invoke the NeXus-API routine, and copy data from C back into Java. See the 
+JNI documentation for details. 
+
+= New NeXus Functions =
+With all this, extending the NeXus-API with a new function involves a lot of steps. I assume the function 
+requires driver layer functionality, else the first few steps may be disregarded.
+# Implement the new function in each driver layer
+# Add the new function to the NeXusFunction structure
+# Make sure that new function is assigned properly in the driver implementations.
+# Make a new protoype for the function in napi.h
+# Implement the function in napi.c
+# Add the new function to the lists in napif.inc and provide a wrapper in napif.f
+# Create a new SWIG helper function in nxinterhelper.h and nxinterhelper.c
+# Edit nxinter.i to have a SWIG wrapper generated for the new function.
+# Add the new function to the NexusFileInterface and NexusFile classes in the Java-API
+# Write a JNI wrapper in NexusFile.c: take care of the convoluted function names required by JNI 
+ and the JNI conventions.  
+# Make sure the new function also appears in language bindings not mentioned in this document.
+
+= Summary =
+Congratulations! You made it to the end of this boring and lengthy article.     
+
+  
diff --git a/doc/api/NeXusIntern.tex b/doc/api/NeXusIntern.tex
new file mode 100644
index 0000000..827b576
--- /dev/null
+++ b/doc/api/NeXusIntern.tex
@@ -0,0 +1,618 @@
+\documentclass[a4paper]{article}
+\begin{document}
+\begin{center}
+\section{NeXus Programmers Reference }\label{NeXusIntern}
+
+Mark Koennecke\linebreak
+January 2007
+\end{center}
+
+
+This is a description of the internal working of the ANSI-C language NeXus-API.
+This is required reading for everyone who attempts to make changes to the 
+NeXus core API. But be warned: this is not for the faint hearted. A successfull 
+NeXus-API hacker needs a solid understanding of advanced C programming techniques 
+and the HDF-4, HDF-5 and Mini-XML API's. Including their quirks and limitations.
+And for writing language bindings one needs to know about the foreign function 
+interface conventions of the target language of the binding.      
+ 
+
+
+\section{The Top Level NeXus API }
+The NeXus-API consists of a set of functions for creating NeXus files and storing 
+data and attributes in them. All user visible NeXus data types and functions are 
+protoyped in the header file: napi.h. besides the normal function protoypes, there 
+als exists prototypes for function names adjusted in such a way that they can 
+be called from FORTRAN. Also several internal support functions for the FORTRAN 
+interface are defined.   
+
+
+As of 2007, the NeXus-API supports three different file 
+formats: HDF-4, HDF-5 and XML. This has a couple of implications:
+One of them is that there are two categories of functions in the NeXus-API:
+
+
+\begin{itemize}\item Most functions are specific to the actual file format used.
+\item Some functions can be expressed in terms of the more primitive file 
+ access functions. Such functions are directly implemented in napi.c.
+\end{itemize}In an object oriented world the issue with the file type specific funtions would 
+be solved through ploymorphy: there would be a base class specifying the interface and 
+file type specific derived classes  which overload the methods with appropriate ones.
+For reasons of portability the NeXus group choose to implement the NeXus-API in C. Thus 
+polymoprhy had to be implemented in plain C. In order to do this all NeXus functions 
+either create or take a pointer to a NeXus private data structure as a parameter. 
+The current implementation of this data structure looks like this:
+\begin{verbatim}
+typedef struct {
+   NXhandle *pNexusData;   
+   int stripFlag;
+   NXstatus ( *nxclose)(NXhandle* pHandle);
+   NXstatus ( *nxflush)(NXhandle* pHandle);
+   NXstatus ( *nxmakegroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+   NXstatus ( *nxopengroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+   NXstatus ( *nxclosegroup)(NXhandle handle);
+   NXstatus ( *nxmakedata) (NXhandle handle, CONSTCHAR* label, int datatype, 
+                            int rank, int dim[]);
+   NXstatus ( *nxcompmakedata) (NXhandle handle, CONSTCHAR* label, int datatype, 
+                                int rank, int dim[], int comp_typ, int bufsize[]);
+   NXstatus ( *nxcompress) (NXhandle handle, int compr_type);
+   NXstatus ( *nxopendata) (NXhandle handle, CONSTCHAR* label);
+   NXstatus ( *nxclosedata)(NXhandle handle);
+   NXstatus ( *nxputdata)(NXhandle handle, void* data);
+   NXstatus ( *nxputattr)(NXhandle handle, CONSTCHAR* name, void* data, int iDataLen, 
+                          int iType);
+   NXstatus ( *nxputslab)(NXhandle handle, void* data, int start[], int size[]);    
+   NXstatus ( *nxgetdataID)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxmakelink)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxmakenamedlink)(NXhandle handle, CONSTCHAR *newname, NXlink* pLink);
+   NXstatus ( *nxgetdata)(NXhandle handle, void* data);
+   NXstatus ( *nxgetinfo)(NXhandle handle, int* rank, int dimension[], int* datatype);
+   NXstatus ( *nxgetnextentry)(NXhandle handle, NXname name, NXname nxclass, 
+                              int* datatype);
+   NXstatus ( *nxgetslab)(NXhandle handle, void* data, int start[], int size[]);
+   NXstatus ( *nxgetnextattr)(NXhandle handle, NXname pName, int *iLength, int *iType);
+   NXstatus ( *nxgetattr)(NXhandle handle, char* name, void* data, int* iDataLen, 
+                          int* iType);
+   NXstatus ( *nxgetattrinfo)(NXhandle handle, int* no_items);
+   NXstatus ( *nxgetgroupID)(NXhandle handle, NXlink* pLink);
+   NXstatus ( *nxgetgroupinfo)(NXhandle handle, int* no_items, NXname name, 
+                              NXname nxclass);
+   NXstatus ( *nxsameID)(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID);
+   NXstatus ( *nxinitgroupdir)(NXhandle handle);
+   NXstatus ( *nxinitattrdir)(NXhandle handle);
+   NXstatus ( *nxsetnumberformat)(NXhandle handle, int type, char *format);
+   NXstatus ( *nxprintlink)(NXhandle handle, NXlink* link);
+} NexusFunction, *pNexusFunction;
+\end{verbatim}
+Basically this structure holds another pointer to a file type specific data structure and a 
+lot of function pointers for the NeXus functions. A typical top level NeXus-API function 
+implementation then looks like this:
+\begin{verbatim}
+NXstatus  NXmakegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
+{
+     pNexusFunction pFunc = handleToNexusFunc(fid);
+     return pFunc->nxmakegroup(pFunc->pNexusData, name, nxclass);   
+}
+\end{verbatim}
+It just exchanges the fid against a pointer to the NexusFunction structure described above and 
+calls the appropriate file type specific function.   
+
+
+Now a careful reader should ask how the NexusFunction structure is initialized to point to  
+applicable functions for each file type. This happens in the NXopen function. NXopen figures the 
+file type out by either looking at file creation flags or through inspection of the actual NeXus 
+file to be openend. It then initializes the NexusFunction structure and proceeds to call the 
+file type specific nxopen function in the NexusFunction structure.    
+
+
+NXopen has to implement another complication: the NeXus-API searches NeXus files in a NeXus search path 
+defined through the environment variable NX\_LOAD\_PATH. This is done in NXopen; the located file is 
+then opened through NXinternalopen.
+
+
+The NeXus-API has an external file linking feauture. When the NeXus-API encounters a group with the 
+attribute {\it  napimount} it looks for a URL to a group in another file and opens the group in the 
+other file without the user noticing anything. If such a special group is closed, the external file 
+must be closed and the original file reenterd.  This had to be implemented at the top level as 
+the external linking feauture is supposed to work on top of any of the supported file formats. The 
+functions NXopengroup and NXclosegroup have been instrumented in a suitable way to support external 
+linking. But in order to do this some information is needed:
+
+
+\begin{itemize}\item The nesting hierarchy of files
+\item The information when to close an external file and step back into the source file of an 
+ external link.
+\end{itemize}This information is held in a file stack which is implemented in nxstack.h and nxstack.c. When 
+entering a file the files name and corresponding NexusFunction structure is pushed onto the stack. 
+When a file is closed, this data is popped again. For the test when an externally linked  file is 
+to be closed, the NXlink IDs as returned by NXgetgroupID are used. A pointer to such a file stack 
+is currently the actual structure to which the NeXus file handle NXhandle points to. External 
+linking is also the cause for the call to handleToNexusFunc in the function example above: this
+function retrieves the appropriate NexusFunction structure from the file stack.    
+
+
+Thus the NeXus-API can be approached as consisting of three different layers:
+
+
+\begin{enumerate}\item The file stack layer
+\item The NexusFunction layer which implements file type polymorphy
+\item A driver layer implementing the functions to access files in the different file 
+ formats of NeXus. 
+\end{enumerate}\subsection{NeXus-API Error Handling }
+All API's throw errors any now and then. Most are caused by the user, the rest are more serious...
+Whatever, the NeXus-API programmer needs a way to process such errors. In many cases the NeXus default: 
+printing the error to stdout is good enough. But in a GUI one might pop up a message box or in a Java 
+wrapper one might want to convert the error into an exception. The good news is that the NeXus-API is 
+designed to support this. All errors are reported through a function NXIReportError. NXIReportError has 
+the signature:
+\begin{verbatim}
+	void NXIReportError(void *pData, char *errorText);
+\end{verbatim}
+A NeXus-API user now can replace the default error reporting function through an own implementation with the 
+function NXMSetError. NXMSetError also allows to pass in a pointer to a user defined data structure which is 
+passed as pData to the error reporting function.  
+
+
+\section{NeXus File Drivers }
+\subsection{NeXus HDF File Drivers }
+The NeXus file drivers for the HDF file formats HDF-4 and HDF-5 share common features. I recall that 
+NeXus uses a hierarchy in order to organize information storage. But both HDF-API's are not tree based 
+but use an interface which allows to open and close groups and datasets. This is sensible as HDF is designed 
+to support very large data sets which may not necessarily fit into a computers memory in one go. But this also 
+implies that the current position in the hierarchy of a given NeXus file has to be maintained by the NeXus-API.
+Such information is maintained in a stack which is pushed an popped while moving through the hierarchy. This 
+stack also has to hold the positions within pending group and attribute searches through the NXgetnextentry and 
+NXgetnextattr functions. Otherwise recursive searches would break.  
+
+
+Both HDF APIs make extensive use of integer ID's which act as handles to file interfaces and HDF objects. Of 
+course the HDF NeXus file data structures must maintain a fair share of such ID's too. Great care has to be 
+taken to release all used ID's at the appropriate time. Otherwise memory may be leaked. Or worse things 
+may happen.  
+  
+
+
+\subsection{HDF-4 NeXus File Driver }
+It is worthwhile to know that each HDF-4 object in a HDF-4 file is unambigously identified through its tag and 
+reference (ref) ID.  Which happen to be integer numbers. For the following discussions it is also worth to
+know that Vgroups in HDF-4 are implemented as lists of reference and tag IDs of the objects contained in the 
+Vgroup. The HDF-4 API is very rich. NeXus only uses a subset of the HDF-4 API, namely the Vgroup , the SDS  and 
+the annotation interface.   
+
+
+The HDF-4 NeXus file driver internally uses this data structure:
+\begin{verbatim}
+  typedef struct __NexusFile {
+    struct iStack {
+      int32 *iRefDir;
+      int32 *iTagDir;
+      int32 iVref;
+      int32 __iStack_pad;               
+      int iNDir;
+      int iCurDir;
+    } iStack[NXMAXSTACK];
+    struct iStack iAtt;
+    int32 iVID;
+    int32 iSID;
+    int32 iCurrentVG;
+    int32 iCurrentSDS;
+    int iNXID;
+    int iStackPtr;
+    char iAccess[2];
+  } NexusFile, *pNexusFile;
+\end{verbatim}
+
+
+\begin{description}\item[iStack
+]  The hierarchy stack.
+\item[iStackPtr
+]  a pointer into the hierarchy stack.
+\item[iAtt
+]  for storing the state of an attribute search. 
+\item[iVID
+]  The ID for the Vgroup interface. To be used when interacting with Vgroups.
+\item[ISID
+]  The ID for the SDS interface. To be used when interacting with datasets.
+\item[iCurrentVG
+]  The Id of the currently open Vgroup
+\item[iCurrentSDS
+]  the ID of the currently open SDS. Must be 0 if no SDS open.
+\item[iNXID
+]  an identifier for this data structure. 
+\item[iAccess
+]  The access code (read or write) for this file.
+\end{description}The hierarchy stack has the following fields:
+
+
+\begin{description}\item[iVref
+]  The reference ID's of previous Vgroups.
+\item[iRefDir
+]  an array of reference numbers used during searches with NXgetnextentry.
+\item[iTagDir
+]  an array of tag numbers used during searches.
+\item[iCurDir
+]  the current index into iRefDir and iTagDir.
+\item[iNDir
+]  the length of iRefDir and iTagDir.
+\item[\_\_iStack\_pad
+]  This makes compilers on 64-bit operating systems happy. 
+\end{description}At this point it is convenient to discuss how group searches with NXgetnextentry work. On the 
+first call to NXgetnextentry, all reference and tag ID's in the current group are read and 
+copied into iRefDir and iTagDir. iNDir is set to the total number of objects held. iCurDir 
+is set to 0 and data for the first object returned. Subsequent calls to NXgetexentry increment 
+iCurDir and return appropriate data. Until the directory is exhausted and NX\_EOD is returned. 
+The internal functions NXIInitDir and NXIKillDir help with the management of this.  
+
+
+All group and SDS search code in the NeXus-HDF-4 driver suffer from the fact that different 
+search functions have to be used when searching at root level or within a Vgroup. 
+NXIFindVGroup and NXIFindSDS are helper functions for locating the appropriate objects. Both 
+return the reference ID of a suitable object on success or NX\_EOD in the case of failure. 
+
+
+Attribute searches are simpler: HDF-4 objects have arrays of attributes. And the ID of an attribute is 
+simply the index into that array. Thus the total number of attributes is stored in iNDir at the start 
+of an attribute search and iCurDir set to 0. Further calls increment iCurDir and return appropriate 
+data until the attributes are exhausted. (NOTE: Here is a subtle bug waiting to happen: when a group 
+search is mixed with an attribute search, things may go wrong. It would be better to have separate 
+fields for the attribute search. That this has not been noticed yet is partly due to the fact that
+group attributes were introduced only recently).
+
+
+Another issue is the implementation of named links. This is links to other objects in the NeXus file 
+which appear under a different name in the linking Vgroup. This is not supported by the HDF-4 API:
+objects are identified by their reference ID and tags and names and class names are attributes to the 
+object. This was solved by creating SDSs and Vgroups with the required name. Such objects then have an 
+attribute {\it  NAPIlink} which holds the tag and reference IDs of the linked item. The internal function 
+findNapiClass and NX4opengroup and NX4opendata check for the existence of this attribute and act 
+accordingly.
+
+
+   
+The initializations in NX4open and NXclose  have to happen in the order as implemented. 
+Otherwise  ugly things may happen. It just does not work.
+
+
+NX4flush is implemented as a close and a open of the file. This is because HDF-4 has no proper flush.
+
+
+\subsection{HDF-5 NeXus File Driver }
+The HDF-5 API addresses objects in HDF-5 files through unix like path strings. This requires some string 
+processing in the file driver implementation. HDF-5 does not support class names for groups as HDF-4 did. The 
+HDF-5 NeXus file driver solves this problem through the use of a group attribute called NX\_class. There are 
+also no file global attributes as in HDF-4. Such attributes are implemented as attributes to the root (/) 
+group in the HDF-5 file driver.
+
+
+Searches in HDF-5 work differently too: HDF-5 provides iterators which call a user supplied function for each 
+element to be searched. The user supplied function then must store the data it needs about the element in an own 
+data structure. The return value of the user supplied function also determines how the iteration proceeds. 
+
+
+Another source of complexity is HDF-5 data transfer. HDF-5 transfers data between a file data space and an in memory 
+data space. Each of these data spaces has its own type, size etc. And each of these items has its own ID. This 
+causes an proliferation of IDs. The nice thing about the scheme though is that the HDF-5 library takes care of 
+all necessary conversions which need to happen between the various data spaces. 
+
+
+A special topic is closing files. In any other API closing a file also removes all resources associated with the 
+file. This is by default not the case with HDF-5: if any ID is not released the HDF-5 library will keep the file
+open somehow. The HDF-5 team told me that some (paying) customer wanted this. Anyway: with the call to 
+H5Pset\_fclose\_degree in NX5open proper operation is reestablished again: i.e. a call to NX5close really closes the 
+file. Additioannly there is some code in NX5open which can print the number of handles left open. This can be 
+useful for debugging.
+
+
+The HDF-5 NeXus driver private data structure is this:
+\begin{verbatim}
+  typedef struct __NexusFile5 {
+        struct iStack5 {
+          char irefn[1024];
+          int iVref;
+          int iCurrentIDX;
+        } iStack5[NXMAXSTACK];
+        struct iStack5 iAtt5;
+        int iVID;
+        int iFID;
+        int iCurrentG;
+        int iCurrentD;
+        int iCurrentS;
+        int iCurrentT;
+        int iCurrentA;
+        int iNX;
+        int iNXID;
+        int iStackPtr;
+        char *iCurrentLGG;
+        char *iCurrentLD;
+        char name_ref[1024];
+        char name_tmp[1024];
+        char iAccess[2];
+  } NexusFile5, *pNexusFile5;
+\end{verbatim} 
+
+
+\begin{description}\item[iAtt
+]  The hierarchy stack
+\item[iStackPtr
+]  the pointer into the hierarchy stack. 
+\item[iFID
+]  HDF-5 file handle
+\item[iCurrentG
+]  handle of the current open group.
+\item[iCurrentD
+]  handle of currently open dataset
+\item[iCurrentT
+]  handle to type of currently open dataset
+\item[iCurrentS
+]  handle to data space of currently open dataset
+\item[iCurrentA
+]  temporary handle of an open attribute.
+\item[iNX
+]   used in group searches
+\item[iNXID
+]  signature of data structure
+\item[iCurrentLGG
+]  name of last openened group
+\item[iCurrentLD
+]  name of last openen dataset. Has length 0 when no dataset open.
+\item[name\_ref
+]  path to current group
+\item[name\_tmp
+]  some group path
+\item[iAccess
+]  file access code
+\end{description}The hierarchy stack has the fields:
+
+
+\begin{description}\item[irefn
+]  The name of the group
+\item[iVref
+]  handle to group 
+\item[iCurrentIDX
+]  the current position in a group search
+\end{description}\subsection{XML Nexus-API Driver }
+The XML format for NeXus was demanded for two reasons:
+
+
+\begin{itemize}\item XML is the buzzword of the day
+\item People want a format where they can edit their data with an editor.
+\end{itemize}In due course a NeXus-XML file format had been defined. However, XML has one problem: 
+it is not designed to handle large amounts of numeric data well. This showed during a survey 
+of XML parsing libraries: most would handle a large block of numbers as a large block
+of text which is very unwieldly for handling numbers. The implementation in Mike Sweets 
+Mini-XML library was slightly better: a node would be created for each number. Still this 
+is difficult for copying data in and wastes a lot of space. This is another difference to 
+the HDF data formats: for XML the whole tree would have to be read into memory for reading 
+ or created in memory before it could be written to file. This is because XML has no way 
+to address single objects in a file as HDF has. A way to circumvent this problem was to 
+introduce a custom data node into Mini-XML together with user definable callback functions 
+for reading and writing such data. This was done and was included into the standard 
+Mini-XML library by its author: Mike Sweet. The custom data which is used to keep data in 
+memory is an own abstraction of a multi dimensional dataset. This is implemented in 
+nxdataset.h and nxdataset.c. Most of the functions there are straight forward. The custom 
+I/O functions required to interface to Mini-XML live in the files nxio.h and nxio.c. The 
+heart of this are the callback functions:
+
+
+\begin{description}\item[nexusTypeCallback
+]  callback to determine the type of a node when reading.
+\item[nexusLoadcallback
+]  a callback function for reading numeric data.
+\item[nexusWriteCallback
+]  a callback function to write numeric data. 
+\end{description}Then there are some pretty self explaining support functions.
+
+
+With this out of the way most of the NeXus-API could be expressed in terms of the Mini-XML 
+tree navigation and creation functions. Data transfer works through the nxdataset functions.
+But there is a limitation: unlimted dimensions are not supported for XML. 
+
+
+But there is another complication: XML does not know a thing about links. For links a \
+special node with the name NAPIlink was introduced. 
+An attribute {\it  target} to such a node points to the target of the link. If the link is a named link 
+the NAPIlink node will also have an attribute {\it  name}. The 
+implementations of NXXopengroup, NXXopendata NXXclosegroup and NXXclosedata check for NAPIlink 
+nodes and silently follow them. However this means that the XML driver jumps criss and cross 
+through the Mini-XML tree structure when following links. In order to remember to which node to 
+go back a stack was once again needed in the XML-NeXus driver data structure.
+
+
+\begin{verbatim}
+typedef struct {
+    mxml_node_t *current;
+    mxml_node_t *currentChild;
+    int currentAttribute;
+}xmlStack;
+/*---------------------------------------------------------------------*/
+typedef struct {
+  mxml_node_t *root;           /* root node */
+  int readOnly;                /* read only flag */
+  int stackPointer;            /* stack pointer */
+  char filename[1024];         /* file name, for NXflush, NXclose */
+  xmlStack stack[NXMAXSTACK];  /* stack */
+}XMLNexus, *pXMLNexus;
+\end{verbatim} 
+The stack structures fields are:
+
+
+\begin{description}\item[current
+]  the current node
+\item[currentChild
+]  The current child from which to continue in a group search
+\item[currentAttribute
+]  The number of the current attribute in an attribute search.
+ 
+\end{description}The XMLNexus structure has:
+
+
+\begin{description}\item[root
+]  The root of the Mini-XML node tree
+\item[readOnly
+]  a flag for a read only file
+\item[stack
+]  The stack
+\item[stackPointer
+]  The current position in the stack
+\item[filename
+]  the filename of the XML-neXus file
+\end{description}To make this explicitly  clear: Reading and writing NeXus-XML files works as operations on in 
+memory trees. This has a couple of consequences:
+
+
+\begin{itemize}\item NeXus-XML is not suitable for large datasets. If you have very large datsets: use HDF-5!
+\item A file will only be writen when a NXflush or a NXclose is called.  
+\end{itemize}Another limitation is that dataset compression does not make sense in XML. The 
+compression related functions are empty. 
+
+
+\section{NeXus Language Bindings }
+Various bindings exist from the C-language NeXus-API to other programming languages. 
+This section discusses implementation details for some of the supoorted language bindings.
+
+
+\subsection{FORTRAN 77 }
+The F77 language bindings reside in the files napif.inc and napif.f. Napif.inc must be included by 
+all programs using the NeXus F77 language bindings. Napif.f defines various constants and all 
+NeXus functions as functions returning integers. Napif.f then implements the actual F77-API. Mostly 
+it is a very thin layer around the NeXus functions but there are a few twists.
+
+
+All functions using or returning strings must take care to convert F77 strings to C-strings and vice 
+versa. For this support functions are provided. 
+
+
+The NeXus-API stores data in C-storage order but F77 requires fortan storage order. In order to 
+achieve this dimensions have to be reversed. This happens through support functions in napi.c.
+
+
+The NeXus API requires some structures to be passed around, most notably the NXhandle and the 
+NXlink structures. This is done by copying such items onto F77 arrays large enough to 
+hold the data.
+
+
+\subsection{Scripting Language Bindings through SWIG }
+Many popular scripting languages have a foreign function call interface. This allows them to 
+interface to user supplied functions written in ANSI-C and packaged as a shared library. 
+There is a tool called Software Wrapper and Interface Generator (SWIG) which takes as input an 
+API description file and the ID of a scripting language and the goes away and generates wrapper 
+code for the scripting languages foreign function call interface.  Such an API description file 
+has been generated for the NeXus-API in order to support all scripting languages for which suitable 
+SWIG drivers exist. See the SWIG WWW-site (http://www.swig.org) for details.  
+
+
+Most scripting languages have bad support for multi dimensional arrays. This is why the NeXus SWIG 
+interface supplies its own abstraction for such datasets. This is implemented in nxdataset.h and 
+nxdataset.c. Nxdataset.i is the SWIG interface definition for the dataset API.
+
+
+The raw NeXus-API proved to be difficult to wrap with SWIG. It became necessary to wrap most 
+NeXus-API functions with a SWIG helper wrapper. Those helpers live in   nxinterhelper.h and 
+nxinterhelper.c. The helper functions basically make functions modifying pointers return 
+pointers and data handling functions use the nxdataset abstraction. 
+
+
+The SWIG wrapped NeXus-API functions either return integer error codes or, when pointers are desired, 
+NULL pointers when errors occur. In such cases the text message for the error can be inquired with an 
+additional function: nx\_getlasterror.
+
+
+How the SWIG wrappers for the NeXus-API work is of course slightly different for each scripting 
+language. The description in nxinter.tex for Tcl together with the SWIG documentation for your 
+target scripting language of choice should get you started. 
+
+
+\subsection{NeXus-Java Binding }
+The ANSI-C NeXus-API was wrapped with the Java Native Methods Interface (JNI) for use in Java 
+programs. The Java-NeXus code consists basically of two parts:
+
+
+\begin{itemize}\item Some Java code implementing a Java interface
+\item Some C code which translates Java JNI calls into NeXus-API functions and maps return values back 
+ to Java values. This code together with the base NeXus-API and the required libraries is used to 
+ build a shared library which is loaded into the Java Virtual Machine at runtime prior to the first 
+ use of the Java-NeXus bindings.
+\end{itemize}The Java-NeXus wrapper had to solve a couple of problems:
+
+
+\begin{itemize}\item Design issues
+\item Java has no pointers
+\item Data handling
+\item Error handling
+\item Link data handling
+\end{itemize}In order to go with the Java look and file one might expect that the Java-NeXus binding 
+would consist of Java classes for files, groups, datasets and attributes. After careful 
+consideration this idea was discarded in favour of a plain Java class implementing a 
+NeXus file object. One reason is that such objects are not really idependent objects in a 
+NeXus file but are part of a complex state machine withing the NeXus and HDF-APIs. Keeping 
+such objects in sync with a NeXus file would have caused a nightmare. Instead such a more 
+object oriented Java NeXus-API may be implemented on top of the basic Java-NeXus binding. 
+No one cared enough to do this until now. Thus we are left with a Java interface where we 
+have the NexusFile as the base interface objects. This implements a NexusFileInterface. 
+This layer of abstraction was added to support future NexusFileInterface implementations 
+ based perhaps on a networked access to NeXus files. Which never was implemented. But no one
+complained about this too. Further classes are a helper class for links and 
+an exception class.
+
+
+The Java language has no pointers but the NeXus-API requires pointers as file handles. This 
+problem was solved through a little dictionary which maps integer handles to real  pointers.
+Java thus only has to deal with the integer handles which get translated into pointers at 
+each call in the JNI-interface. This looks like this:
+\begin{verbatim}
+    nxhandle =  (NXhandle)HHGetPointer(handle);
+\end{verbatim}  
+The dictionary implementation lives in the files handle.h and handle.c. The current implementation 
+supports 8192 files open at the same time only. But this proved enough so far. 
+
+
+The data in the NeXus-API is provided as arrays of native number types. But Java uses network byte 
+order as its own binary representation of numbers in the Java Virtual Machine. A conversion was 
+required. For reasons of laziness and admiration, the conversion routines were copied from the 
+HDF-4 Java API. The conversion code lives in the  ncsa/hdf/hdflib directory and its JNI 
+counterpart in hdfnativeImp.c. The conversion happens in the Java code sections acting upon 
+an HDFArray.
+
+
+The NeXus-API prints errors to stdout. Java handles errors by throwing exceptions all over the 
+place. In order to achieve this the Java-NeXus API replaces the standard NeXus-API error handler 
+with an own one which throws NexusExceptions. This is implemented in the function JapiError in
+NexusFile.c.
+
+
+In order to implement linking of objects in NeXus files some information about the objects to link 
+must be carried around. In the NeXus-API this happens in the NXlink structure. This structure is 
+mapped to a NXlink class in the Java-NeXus API. This has to have corresponding fields to the 
+C-language structure. The JNI wrapper copies the data required for this structure back and forth.
+
+
+Otherwise most of the wrapper routines in NexusFile.c just contain the stuff required to access 
+Java data types from C, invoke the NeXus-API routine, and copy data from C back into Java. See the 
+JNI documentation for details. 
+
+
+\section{New NeXus Functions }
+With all this, extending the NeXus-API with a new function involves a lot of steps. I assume the function 
+requires driver layer functionality, else the first few steps may be disregarded.
+
+
+\begin{enumerate}\item Implement the new function in each driver layer
+\item Add the new function to the NeXusFunction structure
+\item Make sure that new function is assigned properly in the driver implementations.
+\item Make a new protoype for the function in napi.h
+\item Implement the function in napi.c
+\item Add the new function to the lists in napif.inc and provide a wrapper in napif.f
+\item Create a new SWIG helper function in nxinterhelper.h and nxinterhelper.c
+\item Edit nxinter.i to have a SWIG wrapper generated for the new function.
+\item Add the new function to the NexusFileInterface and NexusFile classes in the Java-API
+\item Write a JNI wrapper in NexusFile.c: take care of the convoluted function names required by JNI 
+ and the JNI conventions.  
+\item Make sure the new function also appears in language bindings not mentioned in this document.
+\end{enumerate}\section{Summary }
+Congratulations! You made it to the end of this boring and lengthy article.     
+
+
+  
+
+\end{document}
+
diff --git a/doc/api/README b/doc/api/README
new file mode 100644
index 0000000..8b8cb54
--- /dev/null
+++ b/doc/api/README
@@ -0,0 +1,7 @@
+  NeXus API Documentation
+
+  napi.tex is outdated and left here for historical reference
+  
+  NeXusInter.* is current. The file to edit is NeXusFile.radi which 
+  is in a wiki like syntax
+
diff --git a/doc/api/napi.tex b/doc/api/napi.tex
new file mode 100644
index 0000000..74d0834
--- /dev/null
+++ b/doc/api/napi.tex
@@ -0,0 +1,1850 @@
+%  Copyleft (c) 1997 by Mark Koennecke at PSI, Switzerland.
+%
+%
+%  This software is distributed in the hope that it will be useful,
+%  but WITHOUT ANY WARRANTY; without even the implied warranty of
+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%  GNU General Public License for more details.
+%
+%  You may already have a copy of the GNU General Public License; if
+%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+%  Cambridge, MA 02139, USA.
+%
+
+\documentclass[12pt]{article}
+\usepackage[dvips]
+
+\setlength{\oddsidemargin}{-.1in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.2in}
+\setlength{\marginparwidth}{0.5in}
+
+\begin{document}
+\title{The NeXus Application Programmer's Interface}
+
+\author{Mark K\"onnecke\\
+  Labor f\"ur Neutronenstreuung\\
+  Paul Scherrer Institut\\
+  CH-5232 Villigen PSI\\
+  Switzerland\\       
+  Mark.Koennecke at psi.ch \\
+  Przemek K\l{}osowski\\
+  U. of Maryland \& NIST \\       
+  przemek.klosowski at nist.gov 
+}
+
+}
+
+\maketitle
+\tableofcontents
+
+\vskip.3in
+\centerline{\large\bf Abstract}
+\vskip.2in
+\begin{center}
+\parbox{.8\textwidth}{
+  There is a proposed portable data exchange format for neutron and
+  X-ray scattering communities, NeXus (described in a separate
+  publication).  The present document supplements the NeXus proposal,
+  by defining a simplified, NeXus-compliant programming interface for
+  reading and writing NeXus files.
+}
+\end{center}
+
+\section{Introduction}
+\label{chap:intro}
+
+This file defines an Application Programmer's Interface (API) to HDF
+library as used for the NeXus data format. It encapsulates a subset of
+HDF and provides some helper routines to simplify creating and reading
+NeXus data files.
+
+The API is designed to be modal; there is a hidden state that
+determines which groups and datasets (Vgroups and SDSes) are open at
+any given moment, and subsequent operations are implicitly performed
+on these entities. This cuts down the number of parameters to pass
+around in API calls, at the cost of forcing certain pre-approved {\em
+mode d'emploi}. This mode d'emploi will be familiar to most: it is very
+similar to navigating a directory hierarchy. In our case HDF--VGroups are
+the directories, which can hold other directories and data items which are
+restricted to being HDF--scientific data sets (SDS).
+
+The API comprises the following functional groups:
+
+\begin{enumerate}
+\item General initialization and shutdown: opening and closing the file,
+      creating or opening an existing group or dataset,  and closing them.
+\item Reading and writing data and attributes to previously opened datasets.
+\item Routines to obtain meta-data and to iterate over component datasets and attributes.
+\item Handling of linking and group hierarchy.
+\end{enumerate}
+
+
+
+\section{Implementation}
+
+\subsection{Data Structures}
+The approach used in this version is to maintain a datastructure for each
+open file. This datastructure will hold a stack of Vgroups traversed and
+will thus allow stepping back and forth in the NeXus file structure. The
+stack is implemented using an array. The datastructure looks like this: 
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap1}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@    typedef struct __NexusFile {@\\
+\mbox{}\verb@                                 int   iNXID;@\\
+\mbox{}\verb@                                 int32 iVID;@\\
+\mbox{}\verb@                                 int32 iSID;@\\
+\mbox{}\verb@                                 int32 iCurrentVG;@\\
+\mbox{}\verb@                                 int32 iCurrentSDS;@\\
+\mbox{}\verb@                                 int32 iStack[NXMAXSTACK];@\\
+\mbox{}\verb@                                 int   iStackPtr; @\\
+\mbox{}\verb@                                 int iNDir;@\\
+\mbox{}\verb@                                 int iCurDir;@\\
+\mbox{}\verb@                                 int *iRefDir;@\\
+\mbox{}\verb@                                 int *iTagDir;@\\
+\mbox{}\verb@                                } NexusFile, *pNexusFile;@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The fields in more detail: \begin{itemize}
+\item iNXID is a test value against memory corruption.
+\item iVID is the file ID to use for the Vgroup interface.
+\item iSID is the file ID to use for the SDS interface.
+\item iCurrentVG is the ID of the current open Vgroup. Is 0, if there is 
+ no Vgroup open.
+\item iCurrentSDS is the ID of the current open SDS. Is 0, if there is 
+ no SDS open.
+\item iStack is the stack array.
+\item iStackPtr is the pointer to the current Vgroup in iStack.
+\item iNDir, iCurDir, iRefDir, iTagDir are data fields used during an
+directory search with NXgetnextentry. They are:
+\begin{itemize}
+\item iNDir: number of directory entries.
+\item iCurDir current directory entry.
+\item iRefDir array of reference numbers.
+\item iTagDir array of tag numbers.
+
+\end{itemize}
+\end{itemize} 
+
+The other datastructure used is NXlink. It encapsulates all information
+necessary to do a link between Vgroups and SDS's. This is easy:
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap2}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@    typedef struct {@\\
+\mbox{}\verb@                    int32 iTag;@\\
+\mbox{}\verb@                    int32 iRef;@\\
+\mbox{}\verb@                   } NXlink;@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Before diving into code, it may be helpful to highlight a few pecularities
+of the HDF interface which help confuse the code. The first is, that there
+is no single ID to refer to a given file. The Vgroup interface and the SDS
+interface use two different ID's which have to be initialised at file
+opening and used apropriatetly.
+
+The other feature is the plethora of integer ID's associated with each
+HDF--object. First there is something called a reference ID which seems to
+be an ID which identifies an object within an HDF file. Coming with it there
+is a tag, which denotes the type of the object. When things need to be done
+to an object, HDF requires to attach or open the object. These calls usually
+return another ID which can than be used furtheron. This becomes invalid
+once you close the object again. So much bookeeping is needed to keep track
+of all these ID's. \label{ididid}
+
+
+
+\subsection{General initialization and shutdown}
+\label{ss:gen}
+
+
+The routines in this group are for opening and closing the NeXus/HDF file,
+creating or opening an existing group or dataset,  and closing them.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap3}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb at NXhandle  NXopen(char * filename, NXaccess access_method);@\\
+\mbox{}\verb at NXstatus  NXclose(NXhandle fileid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb at NXstatus  NXmakegroup (NXhandle fileid, char* Vgroup, char* NXclass);@\\
+\mbox{}\verb at NXstatus  NXopengroup (NXhandle fileid, char* Vgroup, char* NXclass);@\\
+\mbox{}\verb at NXstatus  NXclosegroup(NXhandle fileid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb at NXstatus  NXmakedata (NXhandle fileid, char* label, int datatype, int rank, int dim[]);@\\
+\mbox{}\verb at NXstatus  NXopendata (NXhandle fileid, char* label);@\\
+\mbox{}\verb at NXstatus  NXclosedata(NXhandle fileid);@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXopen}
+NXopen opens the HDF--file filename and creates and initialises a NexusFile
+structure. The returned handle is actually the pointer to this structure.
+This danger of this aproach is, that somebody might try arithemetic on the
+handle and thereby  corrupt the system. In order to test for this the
+NexusFile structure contains the NXID field which can be checked against a
+predefined value. 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap4}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  NXhandle NXopen(char *filename, NXaccess am)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     pNexusFile pNew = NULL;@\\
+\mbox{}\verb@     char pBuffer[512];@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* get memory */@\\
+\mbox{}\verb@     pNew = (pNexusFile)malloc(sizeof(NexusFile));@\\
+\mbox{}\verb@     if(!pNew)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData, "ERROR: no memory to create File datastructure");@\\
+\mbox{}\verb@        return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     memset(pNew,0,sizeof(NexusFile));@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* start SDS interface */@\\
+\mbox{}\verb@     pNew->iSID = SDstart(filename,am);@\\
+\mbox{}\verb@     if(pNew->iSID <= 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       sprintf(pBuffer,"ERROR: cannot open file: %s",filename);@\\
+\mbox{}\verb@       NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@       free(pNew);@\\
+\mbox{}\verb@       return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* otherwise we try to create the file two times which makes HDF@\\
+\mbox{}\verb@        Trow up on us.@\\
+\mbox{}\verb@     */@\\
+\mbox{}\verb@     if(am == NXACC_CREATE)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        am = NXACC_RDWR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* start Vgroup API */@\\
+\mbox{}\verb@     pNew->iVID = Hopen(filename,am,100);@\\
+\mbox{}\verb@     if(pNew->iVID <= 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       sprintf(pBuffer,"ERROR: cannot open file: %s",filename);@\\
+\mbox{}\verb@       NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@       free(pNew);@\\
+\mbox{}\verb@       return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     iRet = Vstart(pNew->iVID);@\\
+\mbox{}\verb@     if(iRet < 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF cannot initalise Vgroup interface");@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     pNew->iNXID = NXSIGNATURE;@\\
+\mbox{}\verb@     pNew->iStack[0] = 0; /* root! */@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     return (NXhandle)pNew;   @\\
+\mbox{}\verb@  }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXclose}
+NXclose closes an Nexus file and deletes all associated datastructures from
+memory. The handle fileid will no longer be valid after this.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap5}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  NXstatus NXclose(NXhandle fid)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@      pNexusFile pFile = NULL;@\\
+\mbox{}\verb@      int iRet; @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* close links into vGroups or SDS */@\\
+\mbox{}\verb@      if(pFile->iCurrentVG != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         Vdetach(pFile->iCurrentVG);@\\
+\mbox{}\verb@      }    @\\
+\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = SDendaccess(pFile->iCurrentSDS);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@          NXIReportError(NXpData,"ERROR: ending access to SDS");@\\
+\mbox{}\verb@      }    @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  @\\
+\mbox{}\verb@      /* close the SDS and Vgroup API's */@\\
+\mbox{}\verb@      Vend(pFile->iVID);@\\
+\mbox{}\verb@      iRet = SDend(pFile->iSID);@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@          NXIReportError(NXpData,"ERROR: HDF cannot close SDS interface");@\\
+\mbox{}\verb@      }    @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      iRet = Hclose(pFile->iVID);@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@          NXIReportError(NXpData,"ERROR: HDF cannot close HDF file");@\\
+\mbox{}\verb@      }    @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* release memory */@\\
+\mbox{}\verb@      NXIKillDir(pFile);@\\
+\mbox{}\verb@      free(pFile);@\\
+\mbox{}\verb@      return NX_OK; @\\
+\mbox{}\verb@  }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXmakegroup}
+NXmakegroup creates a new Vgroup at the current level in the Vgroup
+hierarchy. The new Vgroup will have the name Vgroup and have the class
+descriptor NXclass. This call does not open the new group automatically.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap6}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXmakegroup(NXhandle fid, char *name, char *class)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     pNexusFile pFile;@\\
+\mbox{}\verb@     int32 iNew, iRet;@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@     pFile = NXIassert(fid);     @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* create and configure the group */@\\
+\mbox{}\verb@     iNew = Vattach(pFile->iVID,-1,"w");     @\\
+\mbox{}\verb@     if(iNew < 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF could not create Vgroup");@\\
+\mbox{}\verb@        return NX_ERROR;       @\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     Vsetname(iNew,name);@\\
+\mbox{}\verb@     Vsetclass(iNew,class);@\\
+\mbox{}\verb@   @\\
+\mbox{}\verb@     /* insert it into the hierarchy, when apropriate */@\\
+\mbox{}\verb@     if(pFile->iCurrentVG != 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       iRet = Vinsert(pFile->iCurrentVG,iNew);@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     Vdetach(iNew);@\\
+\mbox{}\verb@     if(iRet < 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF failed to insert Vgroup");@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXopengroup}
+NXopengroup opens an existing Vgroup for writing and reading data to it.
+This routine maintains the Vgroup stack. There are several possible
+situations. The first is that we are at root level (iCurrentVG = 0). The
+vGroup must be found and attatched to. Than the Stack has to be incremented.
+The next situation is, that we are already in a Vgroup. Than we have to find
+the new Vgroup, detach the current Vgroup and attach to the new one, thereby
+incrementing the stack.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap7}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@   NXstatus NXopengroup(NXhandle fid, char *name, char *class)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int32 iNew, iRef;@\\
+\mbox{}\verb@      char pBuffer[256];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      iRef = NXIFindVgroup(pFile,name,class);@\\
+\mbox{}\verb@      if(iRef < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sprintf(pBuffer,"ERROR: Vgroup %s, class %s NOT found",name,class);@\\
+\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      } @\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* are we at root level ? */@\\
+\mbox{}\verb@      if(pFile->iCurrentVG == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@          pFile->iCurrentVG = Vattach(pFile->iVID,iRef,"w");@\\
+\mbox{}\verb@          if(pFile->iCurrentVG < 0)@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@            sprintf(pBuffer,"ERROR: cannot attach to vGroup %s",name);@\\
+\mbox{}\verb@            NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@            return NX_ERROR;@\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@          pFile->iStackPtr++;@\\
+\mbox{}\verb@          pFile->iStack[pFile->iStackPtr] = iRef;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@          Vdetach(pFile->iCurrentVG);@\\
+\mbox{}\verb@          pFile->iStackPtr++;@\\
+\mbox{}\verb@          pFile->iStack[pFile->iStackPtr] = iRef;@\\
+\mbox{}\verb@          pFile->iCurrentVG = Vattach(pFile->iVID,@\\
+\mbox{}\verb@                                      pFile->iStack[pFile->iStackPtr],@\\
+\mbox{}\verb@                                      "w");@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      NXIKillDir(pFile);@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@ }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXclosegroup}
+NXclosegroup closes an open Vgroup and travels one back in the Vgroup
+hierarchy. The usual hassle with the tons of different indices again.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap8}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXclosegroup(NXhandle fid)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* first catch the trivial case: we are at root and cannot get @\\
+\mbox{}\verb@         deeper into a negative directory hierarchy (anti-directory)@\\
+\mbox{}\verb@      */@\\
+\mbox{}\verb@      if(pFile->iCurrentVG = 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIKillDir(pFile);@\\
+\mbox{}\verb@         return NX_OK;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else  /* Sighhh. Some work to do */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         /* close the current VG and decrement stack */@\\
+\mbox{}\verb@         Vdetach(pFile->iCurrentVG);@\\
+\mbox{}\verb@         pFile->iStackPtr--;@\\
+\mbox{}\verb@         if(pFile->iStackPtr <= 0) /* we hit root */@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            pFile->iStackPtr = 0;@\\
+\mbox{}\verb@            pFile->iCurrentVG = 0;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         else@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            /* attach to the lower Vgroup */@\\
+\mbox{}\verb@            pFile->iCurrentVG = Vattach(pFile->iVID,@\\
+\mbox{}\verb@                                        pFile->iStack[pFile->iStackPtr],@\\
+\mbox{}\verb@                                        "w");@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      NXIKillDir(pFile);@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXmakedata}
+NXmakedata creates a new scientific datset. As argument it takes the usual filehandle,
+Than there is an integer denoting the datatype. This needs to be one of the
+HDF defined type identifiers. Commonly used types are: DFNT\_FLOAT for 32 bit
+floats, DFNT\_INT32 for 32-bit integers, DFNT\_UINT8 for unsigned bytes (or
+characters). rank is the dimensionality of the data. The parameter dims is
+an integer array which has rank values. Each value denotes the length of the
+data in the dimensions. Note that this function does not open a dataset.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap9}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXmakedata(NXhandle fid, char *name, int datatype, int rank, @\\
+\mbox{}\verb@                       int dimensions[])@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int32 iNew;@\\
+\mbox{}\verb@      char pBuffer[256];@\\
+\mbox{}\verb@      int i, iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* do some argument checking */@\\
+\mbox{}\verb@      if( (datatype != DFNT_FLOAT32) && (datatype != DFNT_FLOAT64) &&@\\
+\mbox{}\verb@          (datatype != DFNT_INT8)    && (datatype != DFNT_UINT8)  &&@\\
+\mbox{}\verb@          (datatype != DFNT_INT16)    && (datatype != DFNT_UINT16)  &&@\\
+\mbox{}\verb@          (datatype != DFNT_INT32)    && (datatype != DFNT_UINT32))@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sprintf(pBuffer,"ERROR: unknown datatype specified for SDS %s",@\\
+\mbox{}\verb@                name);@\\
+\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(rank <= 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sprintf(pBuffer,"ERROR: invalid rank specified for SDS %s",@\\
+\mbox{}\verb@                name);@\\
+\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      for(i = 0; i < rank; i++)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          if(dimensions[i] <= 0 )@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@              sprintf(pBuffer,@\\
+\mbox{}\verb@              "ERROR: invalid dimension %d, value %d given for SDS %s",@\\
+\mbox{}\verb@               i,dimensions[i], name);@\\
+\mbox{}\verb@              NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@              return NX_ERROR;@\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* behave nicely, if there is still an SDS open */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         SDendaccess(pFile->iCurrentSDS);@\\
+\mbox{}\verb@         pFile->iCurrentSDS = 0;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* dataset creation */@\\
+\mbox{}\verb@      iNew = SDcreate(pFile->iSID,name,datatype,rank,dimensions);@\\
+\mbox{}\verb@      if(iNew < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sprintf(pBuffer,"ERROR: cannot create SDS %s, check argumenst",@\\
+\mbox{}\verb@                 name);@\\
+\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@         return NX_ERROR; @\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      /* link into Vgroup, if in one */@\\
+\mbox{}\verb@      if(pFile->iCurrentVG != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = Vaddtagref(pFile->iCurrentVG,DFTAG_SDG,SDidtoref(iNew));@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      iRet = SDendaccess(iNew);@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF cannot end access to SDS");@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXopendata}
+NXopendata opens a scientific data set for further manipulation, i.e. reading
+and writing of data or getting information about it. The scientific dataset
+must exist. 
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap10}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@    NXstatus NXopendata(NXhandle fid, char *name)@\\
+\mbox{}\verb@    {@\\
+\mbox{}\verb@        pNexusFile pFile;@\\
+\mbox{}\verb@        int32 iNew;  @\\
+\mbox{}\verb@        char pBuffer[256];@\\
+\mbox{}\verb@        int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        /* first find the reference number of the SDS */@\\
+\mbox{}\verb@        iNew = NXIFindSDS(fid,name);@\\
+\mbox{}\verb@        if(iNew < 0) @\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@          sprintf(pBuffer,"ERROR: SDS %s not found at this level",name);@\\
+\mbox{}\verb@          NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        /* be nice: properly close the old open SDS silently if there is@\\
+\mbox{}\verb@           still an SDS open.@\\
+\mbox{}\verb@        */@\\
+\mbox{}\verb@        if(pFile->iCurrentSDS)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           iRet = SDendaccess(pFile->iCurrentSDS);@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        else@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           iRet = 1;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        if(iRet < 0)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           NXIReportError(NXpData,"ERROR: HDF cannot end access to SDS");@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* clear pending attribute directories first */@\\
+\mbox{}\verb@        NXIKillDir(pFile);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        /* open the SDS */@\\
+\mbox{}\verb@        iNew = SDreftoindex(pFile->iSID, iNew);@\\
+\mbox{}\verb@        pFile->iCurrentSDS = SDselect(pFile->iSID,iNew);@\\
+\mbox{}\verb@        if(pFile->iCurrentSDS < 0)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           NXIReportError(NXpData,"ERROR: HDF error opening SDS");@\\
+\mbox{}\verb@           pFile->iCurrentSDS = 0;@\\
+\mbox{}\verb@           return NX_ERROR;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        return NX_OK;@\\
+\mbox{}\verb@    }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXclosedata}
+NXclosedata ends the access to the currently active scientific dataset.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap11}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXclosedata(NXhandle fid)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       pNexusFile pFile;@\\
+\mbox{}\verb@       int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@           iRet = SDendaccess(pFile->iCurrentSDS);@\\
+\mbox{}\verb@           pFile->iCurrentSDS = 0;@\\
+\mbox{}\verb@           if(iRet < 0)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@              NXIReportError(NXpData,"ERROR: HDF cannot end access to SDS");@\\
+\mbox{}\verb@              return NX_ERROR;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@             NXIReportError(NXpData,"ERROR: no SDS open --> nothing to do");@\\
+\mbox{}\verb@             return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       NXIKillDir(pFile); /* for attribute data */@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Reading and writing}
+\label{ss:rw}
+
+Routines to read and write data and attributes to previously opened datasets:
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap12}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb at NXstatus  NXgetdata(NXhandle fileid, void* data);@\\
+\mbox{}\verb at NXstatus  NXgetslab(NXhandle fileid, void* data, int start[], int size[]);@\\
+\mbox{}\verb at NXstatus  NXgetattr(NXhandle fileid, char* name, char* data, int datalen);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb at NXstatus  NXputdata(NXhandle fileid, void* data);@\\
+\mbox{}\verb at NXstatus  NXputslab(NXhandle fileid, void* data, int start[], int size[]);@\\
+\mbox{}\verb at NXstatus  NXputattr(NXhandle fileid, char* name, char* data, int datalen);@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Please note, that all data reading and writing routines require that the
+scientific dataset has been opened beforehand with NXopenadata. 
+
+\subsubsection{NXgetdata}
+NXgetdata reads data from the currently open scientific data set into
+data. Please note, that memory overwrite occurs if the caller has not
+allocated enough memory to hold all the data available. There are functions
+in the section \ref{ss:meta} which allow to inquire the data size first.
+
+Note as well that the scientific dataset must have been opened with
+NXopendata before this function can succeed. Before it can do its job,
+NXgetdata has to get dimension information first.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap13}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXgetdata(NXhandle fid, void *data)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int32 iStart[MAX_VAR_DIMS], iEnd[MAX_VAR_DIMS];@\\
+\mbox{}\verb@      NXname pBuffer;@\\
+\mbox{}\verb@      int32 iRank, iAtt, iType;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* check if there is an SDS open */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* first read dimension information */@\\
+\mbox{}\verb@      memset(iStart,0,MAX_VAR_DIMS*sizeof(int32));@\\
+\mbox{}\verb@      SDgetinfo(pFile->iCurrentSDS,pBuffer,&iRank,iEnd,&iType,&iAtt);@\\
+\mbox{}\verb@      /* actually read */@\\
+\mbox{}\verb@      SDreaddata(pFile->iCurrentSDS,iStart,NULL,iEnd,data);@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetslab}
+NXgetslab reads a subset of the data in the current scientific data set.
+The start dimensions to read from are specified in iStart, the end in iEnd.
+The caller is responsable for allocation enough memory for data.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap14}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXgetslab(NXhandle fid, void *data, int iStart[], int iEnd[])@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* check if there is an SDS open */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* actually read */@\\
+\mbox{}\verb@      SDreaddata(pFile->iCurrentSDS,iStart,NULL,iEnd,data);@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetattr}
+HDF has the concept of attributes. This is additional data which goes with
+usually an SDS. Such attributes are used to denotes axis, units etc. The
+other class of attributes are global attributes. This function reads such
+attributes. If an SDS is open, it reads the attributes associated with the SDS, else
+the it tries to find a global attribute. The data read is transfered to
+data, but maximum datalen bytes. The caller is responsible for allocating at
+least datalen bytes for data. In order to enable this scheme, NXgetattr
+has to read the first into an internal temporary buffer before it copies the
+data to the datat buffer provided. And discards with the temporary buffer.
+Note that searching for attributes is handled differently if attributes at
+global level are searched compared to searching attributes in an SDS.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap15}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXgetattr(NXhandle fid, char *name, char *data, int datalen)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int32 iNew;@\\
+\mbox{}\verb@      void *pData = NULL;@\\
+\mbox{}\verb@      int32 iLen, iType, iRet;@\\
+\mbox{}\verb@      char pBuffer[256];@\\
+\mbox{}\verb@      NXname pNam;      @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* find attribute */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        /* SDS attribute */@\\
+\mbox{}\verb@        iNew = SDfindattr(pFile->iCurrentSDS,name);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        /* global attribute */@\\
+\mbox{}\verb@        iNew = SDfindattr(pFile->iSID,name);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(iNew < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        sprintf(pBuffer,"ERROR: attribute %s not found",name);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }  @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* get more info, allocate temporary data space */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = SDattrinfo(pFile->iCurrentSDS,iNew,pNam,&iType,&iLen);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = SDattrinfo(pFile->iSID,iNew,pNam,&iType,&iLen);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        sprintf(pBuffer,"ERROR: HDF could not read attribute info");@\\
+\mbox{}\verb@        NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      iLen = iLen*DFKNTsize(iType);  @\\
+\mbox{}\verb@      pData = (void *)malloc(iLen);@\\
+\mbox{}\verb@      if(!pData)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: allocating memory in NXgetattr");@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      memset(pData,0,iLen);@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* finally read the data */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = SDreadattr(pFile->iCurrentSDS,iNew,pData);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = SDreadattr(pFile->iSID,iNew,pData);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        sprintf(pBuffer,"ERROR: HDF could not read attribute data");@\\
+\mbox{}\verb@        NXIReportError(NXpData,pBuffer);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* copy data to caller */@\\
+\mbox{}\verb@      memset(data,0,datalen);@\\
+\mbox{}\verb@      if(datalen < iLen)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        iLen = datalen - 1;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      memcpy(data,pData,iLen);@\\
+\mbox{}\verb@      free(pData);@\\
+\mbox{}\verb@      return NX_OK; @\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXputdata}
+NXputdata copies  data into the currently open scientific data set in the
+HDF file. 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap16}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXputdata(NXhandle fid, void *data)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int32 iStart[MAX_VAR_DIMS], iEnd[MAX_VAR_DIMS], iStride[MAX_VAR_DIMS];@\\
+\mbox{}\verb@      NXname pBuffer;@\\
+\mbox{}\verb@      int32 iRank, iAtt, iType, iRet, i;@\\
+\mbox{}\verb@      char pError[512];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* check if there is an SDS open */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@           @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* first read dimension information */@\\
+\mbox{}\verb@      memset(iStart,0,MAX_VAR_DIMS*sizeof(int32));@\\
+\mbox{}\verb@      SDgetinfo(pFile->iCurrentSDS,pBuffer,&iRank,iEnd,&iType,&iAtt);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* initialise stride to 1 */@\\
+\mbox{}\verb@      for(i = 0; i < iRank; i++)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        iStride[i] = 1;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* actually write */@\\
+\mbox{}\verb@      iRet = SDwritedata(pFile->iCurrentSDS,iStart,iStride,iEnd,data);@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sprintf(pError,"ERROR: failure to write data to %s",pBuffer);@\\
+\mbox{}\verb@         NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@         return NX_ERROR; @\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXputslab}
+NXputslab writes an subset of data as specified by iStart to iEnd into the
+currently open SDS.
+ 
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap17}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXputslab(NXhandle fid, void *data, int iStart[], int iEnd[])@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int iRet;@\\
+\mbox{}\verb@      int iStride[MAX_VAR_DIMS], i;@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* check if there is an SDS open */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* initialise stride to 1 */@\\
+\mbox{}\verb@      for(i = 0; i < MAX_VAR_DIMS; i++)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iStride[i] = 1;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* actually write */@\\
+\mbox{}\verb@      iRet = SDwritedata(pFile->iCurrentSDS,iStart,iStride,iEnd,data);@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: writing slab failed");@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXputattr}
+Nxputattr puts an attribute into an Nexus file.If an SDS is open, the SDS
+will get the attribute. If not, a global attribute will be generated.
+Attributes are name = value pairs. 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap18}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXputattr(NXhandle fid, char *name, char *data, int datalen)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         /* SDS attribute */@\\
+\mbox{}\verb@         iRet = SDsetattr(pFile->iCurrentSDS,name,DFNT_UINT8,@\\
+\mbox{}\verb@                          datalen,data);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         /* global attribute */@\\
+\mbox{}\verb@         iRet = SDsetattr(pFile->iSID,name,DFNT_UINT8,@\\
+\mbox{}\verb@                          datalen, data);@\\
+\mbox{}\verb@   @\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(iRet < 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDf failed to store attribute ");@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Meta-data} 
+\label{ss:meta}
+
+Routines to obtain meta-data and to iterate over component datasets and attributes.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap19}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb at NXstatus  NXgetinfo     (NXhandle fileid, int* rank, int dimension[], int* datatype);@\\
+\mbox{}\verb at NXstatus  NXgetnextentry     (NXhandle fileid, NXname name, NXname class, int* datatype);@\\
+\mbox{}\verb at NXstatus  NXgetnextattr(NXhandle fileid, NXname pName, int *iLength, int *iType);@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetinfo}
+NXgetinfo gets information about an SDS. rank is the dimesionality of the
+data, dimension will contain the size of the data in each dimension and
+datatype results to one of the HDF--datatypes. The SDS has to be open in
+order for this routine to work.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap20}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXgetinfo(NXhandle fid, int *rank,int dimension[], int *iType)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      NXname pBuffer;@\\
+\mbox{}\verb@      int32  iAtt;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* check if there is an SDS open */@\\
+\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      /* read information */@\\
+\mbox{}\verb@      SDgetinfo(pFile->iCurrentSDS,pBuffer,rank,dimension,iType,&iAtt);@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetnextentry}
+NXgetnextentry  implements a directory search facility on the current Vgroup
+level. The first call will initialize Vgroup searching facilities and return
+information on the first data item in the list. Subsequent calls will yield
+information about the next item in the Vgroup. If the end of the list is
+reached, NXgetentry will return NX\_EOD. Before, the usual NX\_ERROR or NX\_OK
+are returned. Information returned is different for each type of data. For
+Vgroups the name and class of the Vgroup will be returned, iType will be 0.
+For scientific data sets, the name field will be the name, class will be SDS
+and iType will denote the number type of the scientific data set. For types
+not known to Nexus (but to HDF) both name and class will be set to
+"UNKNOWN". 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap21}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   int NXgetnextentry(NXhandle fid, NXname name, NXname class, int *datatype)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      int iRet;   @\\
+\mbox{}\verb@      int32 iTemp, iD1, iD2, iA;@\\
+\mbox{}\verb@      int32 iDim[MAX_VAR_DIMS];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* first case to check for: no directory entry */@\\
+\mbox{}\verb@      if(pFile->iRefDir == NULL)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iRet = NXIInitDir(pFile);@\\
+\mbox{}\verb@         if(iRet < 0)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@           NXIReportError(NXpData, @\\
+\mbox{}\verb@            "ERROR: no memory to store directory info");@\\
+\mbox{}\verb@           return -1;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* next case: end of directory */@\\
+\mbox{}\verb@      if(pFile->iCurDir >= pFile->iNDir)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         NXIKillDir(pFile);@\\
+\mbox{}\verb@         return NX_EOD;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* next case: we have data! suppy it and increment counter */@\\
+\mbox{}\verb@      if(pFile->iCurrentVG == 0) /* root level */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        iTemp = Vattach(pFile->iVID,pFile->iRefDir[pFile->iCurDir],@\\
+\mbox{}\verb@                        "r");@\\
+\mbox{}\verb@        if(iTemp < 0)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           NXIReportError(NXpData,"ERROR: HDF cannot attach to Vgroup");@\\
+\mbox{}\verb@           return NX_ERROR;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        Vgetname(iTemp,name);@\\
+\mbox{}\verb@        Vgetclass(iTemp,class);@\\
+\mbox{}\verb@        *datatype = DFTAG_VG;@\\
+\mbox{}\verb@        pFile->iCurDir++;@\\
+\mbox{}\verb@        Vdetach(iTemp);@\\
+\mbox{}\verb@        return NX_OK;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else /* in Vgroup */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        if(pFile->iTagDir[pFile->iCurDir] == DFTAG_VG) /* Vgroup */@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           iTemp = Vattach(pFile->iVID,pFile->iRefDir[pFile->iCurDir],@\\
+\mbox{}\verb@                           "r");@\\
+\mbox{}\verb@           if(iTemp < 0)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@              NXIReportError(NXpData,"ERROR: HDF cannot attach to Vgroup");@\\
+\mbox{}\verb@              return NX_ERROR;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@           Vgetname(iTemp,name);@\\
+\mbox{}\verb@           Vgetclass(iTemp,class);@\\
+\mbox{}\verb@           *datatype = DFTAG_VG;@\\
+\mbox{}\verb@           pFile->iCurDir++;@\\
+\mbox{}\verb@           Vdetach(iTemp);@\\
+\mbox{}\verb@           return NX_OK;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        else if( (pFile->iTagDir[pFile->iCurDir] == DFTAG_SDG) ||@\\
+\mbox{}\verb@                 (pFile->iTagDir[pFile->iCurDir] == DFTAG_NDG) )@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@            iTemp = SDreftoindex(pFile->iSID, @\\
+\mbox{}\verb@                                pFile->iRefDir[pFile->iCurDir]);@\\
+\mbox{}\verb@            iTemp = SDselect(pFile->iSID,iTemp);@\\
+\mbox{}\verb@            SDgetinfo(iTemp,name,&iA,iDim,&iD1, &iD2);@\\
+\mbox{}\verb@            strcpy(class,"SDS");@\\
+\mbox{}\verb@            *datatype = iD1;@\\
+\mbox{}\verb@            SDendaccess(iTemp);@\\
+\mbox{}\verb@            pFile->iCurDir++;@\\
+\mbox{}\verb@            return NX_OK;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        else /* unidentified */@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@          strcpy(name,"UNKNOWN");@\\
+\mbox{}\verb@          strcpy(class,"UNKNOWN");@\\
+\mbox{}\verb@          pFile->iCurDir++;@\\
+\mbox{}\verb@          return NX_OK;@\\
+\mbox{}\verb@        }      @\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_ERROR; /* not reached */@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetnextattr}
+NXgetnextattr works very much like NXgetnextentry except, that it works on
+SDS attributes and not on Vgroup entries. This function allows to scan the
+names of attributes available. iLength will be filled with the length of the
+attributes data in byte. iType will be filled with the HDF type of the
+attribute. Be warned: this routine returns global attributes when no SDS is
+currently open.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap22}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@  NXstatus  NXgetnextattr(NXhandle fileid, NXname pName, @\\
+\mbox{}\verb@                          int *iLength, int *iType)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     pNexusFile pFile;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@     int32 iPType, iCount;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pFile = NXIassert(fileid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* first check if we have to start a new attribute search */@\\
+\mbox{}\verb@     if(pFile->iNDir == 0) @\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        iRet = NXIInitAttDir(pFile);@\\
+\mbox{}\verb@        if(iRet == NX_ERROR)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           return NX_ERROR;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* are we done ? */@\\
+\mbox{}\verb@     if(pFile->iCurDir >= pFile->iNDir)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIKillDir(pFile);@\\
+\mbox{}\verb@        return NX_EOD;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* well, there must be data to copy */@\\
+\mbox{}\verb@     if(pFile->iCurrentSDS == 0) /* global attribute */@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        iRet = SDattrinfo(pFile->iSID,pFile->iCurDir, pName, &iPType,&iCount); @\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     else@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        iRet = SDattrinfo(pFile->iCurrentSDS,pFile->iCurDir,@\\
+\mbox{}\verb@                          pName, &iPType,&iCount);@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     if(iRet < 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF cannot read attribute info");@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     *iLength = iCount*DFKNTsize(iPType);@\\
+\mbox{}\verb@     *iType =   iPType;@\\
+\mbox{}\verb@     pFile->iCurDir++;@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{ Handling of linking and group hierarchy}
+\label{ss:link}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap23}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb at NXlink      NXgetgroupID(NXhandle fileid);@\\
+\mbox{}\verb at NXlink      NXgetdataID(NXhandle fileid);@\\
+\mbox{}\verb at NXstatus    NXmakelink(NXhandle fileid, NXlink link);@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{  NXgetgroupID}
+NXgetgroupID retrieves the ID and tag of the currently open
+Vgroup in an NXlink strcuture. In case of an error the iTag field of this
+structure will contain NX\_ERROR.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap24}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXlink NXgetgroupID(NXhandle fileid)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      NXlink sRes;@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@      pFile = NXIassert(fileid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      if(pFile->iCurrentVG == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        sRes.iTag = NX_ERROR;@\\
+\mbox{}\verb@        return sRes;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        sRes.iTag = DFTAG_VG;@\\
+\mbox{}\verb@        sRes.iRef = pFile->iCurrentVG;@\\
+\mbox{}\verb@        return  sRes;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      /* not reached */@\\
+\mbox{}\verb@      sRes.iTag = NX_ERROR;@\\
+\mbox{}\verb@      return sRes;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetdataID}
+NXgetdataID retrieves the tag and reference number of the current data
+object. Returns NX\_ERROR if none is open.
+ 
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap25}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXlink NXgetdataID(NXhandle fid)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@      NXlink sRes;@\\
+\mbox{}\verb@   @\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sRes.iTag = NX_ERROR;@\\
+\mbox{}\verb@         return sRes;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@          sRes.iTag = DFTAG_SDS;@\\
+\mbox{}\verb@          sRes.iRef = SDidtoref(pFile->iCurrentSDS);@\\
+\mbox{}\verb@          return sRes;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      sRes.iTag = NX_ERROR;@\\
+\mbox{}\verb@      return sRes; /* not reached */@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{ NXlink}
+NXlink links a Vgroup or SDS into a Vgroup.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap26}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXmakelink(NXhandle fid, NXlink sLink)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pFile;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      pFile = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      if(pFile->iCurrentVG == 0) /* root level, can not link here */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      if(sLink.iTag == DFTAG_VG)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         Vinsert(pFile->iCurrentVG,sLink.iRef);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      else @\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         Vaddtagref(pFile->iCurrentVG, sLink.iTag,sLink.iRef);@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Internal routines}
+There are a couple of internal Nexus API routines which are declared
+static and are not visible outside of the module. First a few
+defines.
+
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap27}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@#include <stdlib.h>@\\
+\mbox{}\verb@#include <assert.h>@\\
+\mbox{}\verb@#include <string.h>@\\
+\mbox{}\verb@#include "fortify.h"@\\
+\mbox{}\verb@#include "napi.h"@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#define NXMAXSTACK 50@\\
+\mbox{}\verb@#define NXSIGNATURE 959697@\\
+\mbox{}\verb@@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+MAXSTACK denotes the maximum depth of Vgroup stacking permissible. If there
+are problems, feel free to increase this value and recompile. 50 is probably
+fairly generous.
+
+NXSIGNATURE is just the signature which the Nexus API will check for on
+handles in order to prevent against tampering with the handles.
+
+NXMAXNAME is the number of characters permitted for names and Vgroup names.
+
+The internal function NXIassert will convert a filehandle to a pointer
+to a NexusFile datastructure. Furthermore, it will check the signature and
+throw an assertion, when the signature does not match.
+
+
+\subsubsection{NX error handling}
+
+As each piece of non trivial software the Nexus API needs a error handling
+policy. The policy implemented is as follows: The NX routines terminate when
+an invalid NXhandle has been specified. This is a serious programmer error.
+In any other case the NX routines are meant to complain, recover and present
+an NX-ERROR return to the higher level code. That code is than responsible
+to deal with the problem. The problem left is error reporting. This is done
+througout the code by a call to NXIReportError. This function takes as first
+parameter a pointer to void and as next parameter the string with the
+complaint. The default implementation of NXIReportError will print to
+stdout. However, there are environments where this strategy is not feasible
+because stdout is supported only in a very  strange way. Think about
+operating system like MS-Windows, MAC-OS (going to die anyway) or other
+windowing systems. In order to cater for this there is an inofficial support
+function which allows to set both a pointer to a datastructure and a new
+function for error reporting. This is called NXMSetError.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap28}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
+\mbox{}\verb@   static void NXNXNXReportError(void *pData, char *string)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       printf("%s \n",string);@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
+\mbox{}\verb@   static void *NXpData = NULL;@\\
+\mbox{}\verb@   static void (*NXIReportError)(void *pData, char *string) =@\\
+\mbox{}\verb@                NXNXNXReportError;@\\
+\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
+\mbox{}\verb@   void NXMSetError(void *pData, void (*NewError)(void *pD, char *text))@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      NXpData = pData;@\\
+\mbox{}\verb@      NXIReportError = NewError;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap29}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*--------------------------------------------------------------------*/@\\
+\mbox{}\verb@   static pNexusFile NXIassert(NXhandle fid)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile pRes;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      assert(fid);@\\
+\mbox{}\verb@      pRes = (pNexusFile)fid;@\\
+\mbox{}\verb@      assert(pRes->iNXID == NXSIGNATURE);@\\
+\mbox{}\verb@      return pRes;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{ Object finding dunctions}
+
+Routines for finding objects in an HDF file have to cope with two quirks in
+the HDF interface. The first is that the root level is no Vgroup. This
+implies that the root level is searched for objects using different routines
+than searching for objects in a Vgroup. The last one uses, of course, Vgroup
+interface routines.
+
+Finding routines have  to cope with the plethora of different integer
+ID's for any given HDF object. See \ref{ididid} for more details. 
+
+
+NXIFindVgroup searches the current Vgroup level in the file for the
+occurence of a Vgroup with a specified name and of a specified class. If no
+suitable Vgroup can be found NIXFinfVgroup returns -1, else the ID of the
+Vgroup. 
+NXIFindVgroup has to cope with the plethora of different integer
+ID's for any give Vgroup. There is the Vgroup ID, than there is the
+reference number which can be obtained by Vgettagref and which can refer to
+any object in the HDF file. Additionally there is a Tag which denotes the
+type of the object.  
+
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap30}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
+\mbox{}\verb@  static int32 NXIFindVgroup(pNexusFile pFile, char *name, char *class)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@      int32 iNew, iRef, iTag;@\\
+\mbox{}\verb@      int iN, i;@\\
+\mbox{}\verb@      int32 *pArray = NULL;@\\
+\mbox{}\verb@      NXname pText;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      assert(pFile);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      if(pFile->iCurrentVG == 0) /* root level */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         /* get the number and ID's of all lone Vgroups in the file */@\\
+\mbox{}\verb@         iN = Vlone(pFile->iVID,NULL,0);@\\
+\mbox{}\verb@         pArray = (int32 *)malloc(iN*sizeof(int32));@\\
+\mbox{}\verb@         if(!pArray)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            NXIReportError(NXpData,"ERROR: out of memory in NXIFindVgroup");@\\
+\mbox{}\verb@            return -1;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         Vlone(pFile->iVID,pArray,iN);@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@         /* loop and check */@\\
+\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            iNew = Vattach(pFile->iVID,pArray[i],"r");@\\
+\mbox{}\verb@            Vgetname(iNew, pText);@\\
+\mbox{}\verb@            if(strcmp(pText,name) == 0)@\\
+\mbox{}\verb@            {@\\
+\mbox{}\verb@               Vgetclass(iNew,pText);@\\
+\mbox{}\verb@               if(strcmp(pText,class) == 0)@\\
+\mbox{}\verb@               {@\\
+\mbox{}\verb@                  /* found !*/@\\
+\mbox{}\verb@                  Vdetach(iNew);@\\
+\mbox{}\verb@                  iNew = pArray[i];@\\
+\mbox{}\verb@                  free(pArray);@\\
+\mbox{}\verb@                  return iNew;@\\
+\mbox{}\verb@               }@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            Vdetach(iNew);@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         /* nothing found */@\\
+\mbox{}\verb@         free(pArray); @\\
+\mbox{}\verb@         return -1;        @\\
+\mbox{}\verb@      } @\\
+\mbox{}\verb@      else /* case in Vgroup */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iN = Vntagrefs(pFile->iCurrentVG);@\\
+\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            Vgettagref(pFile->iCurrentVG,i,&iTag, &iRef);@\\
+\mbox{}\verb@            if(iTag == DFTAG_VG)@\\
+\mbox{}\verb@            {@\\
+\mbox{}\verb@               iNew = Vattach(pFile->iVID,iRef,"r");@\\
+\mbox{}\verb@               Vgetname(iNew, pText);@\\
+\mbox{}\verb@               if(strcmp(pText,name) == 0)@\\
+\mbox{}\verb@               {@\\
+\mbox{}\verb@                  Vgetclass(iNew,pText);@\\
+\mbox{}\verb@                  if(strcmp(pText,class) == 0)@\\
+\mbox{}\verb@                  {@\\
+\mbox{}\verb@                     /* found !*/@\\
+\mbox{}\verb@                     Vdetach(iNew);@\\
+\mbox{}\verb@                     return iRef;@\\
+\mbox{}\verb@                   }@\\
+\mbox{}\verb@                }@\\
+\mbox{}\verb@                Vdetach(iNew);@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@         } /* end for */ @\\
+\mbox{}\verb@      } /* end else */    @\\
+\mbox{}\verb@      /* not found */@\\
+\mbox{}\verb@      return -1;@\\
+\mbox{}\verb@  }  @\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXIFindSDS searches the current Vgroup level for an SDS  name. It returns
+the reference ID of the SDS when found and -1 when no SDS of this name can 
+be found on this level.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap31}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int32 NXIFindSDS(NXhandle fid, char *name)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      pNexusFile self;@\\
+\mbox{}\verb@      int32 iNew, iRet, iTag, iRef;@\\
+\mbox{}\verb@      int32 i, iN, iA, iD1, iD2;@\\
+\mbox{}\verb@      NXname pNam;@\\
+\mbox{}\verb@      int32 iDim[MAX_VAR_DIMS];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      self = NXIassert(fid);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* root level search */@\\
+\mbox{}\verb@      if(self->iCurrentVG == 0)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         i = SDfileinfo(self->iSID,&iN,&iA);@\\
+\mbox{}\verb@         if(i < 0)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            NXIReportError(NXpData, "ERROR: failure to read file information");@\\
+\mbox{}\verb@            return -1;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@           iNew = SDselect(self->iSID,i);@\\
+\mbox{}\verb@           SDgetinfo(iNew,pNam,&iA,iDim,&iD2, &iD2);@\\
+\mbox{}\verb@           if(strcmp(pNam,name) == 0)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@              iRet = SDidtoref(iNew);@\\
+\mbox{}\verb@              SDendaccess(iNew);@\\
+\mbox{}\verb@              return iRet;@\\
+\mbox{}\verb@           } @\\
+\mbox{}\verb@           else@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@               SDendaccess(iNew);@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         /* not found */@\\
+\mbox{}\verb@         return -1;@\\
+\mbox{}\verb@      }/* end root level */@\\
+\mbox{}\verb@      else /* search in a Vgroup */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         iN = Vntagrefs(self->iCurrentVG);@\\
+\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            Vgettagref(self->iCurrentVG,i,&iTag, &iRef);@\\
+\mbox{}\verb@            if( (iTag == DFTAG_SDG) || (iTag == DFTAG_NDG) || @\\
+\mbox{}\verb@                (iTag == DFTAG_SDS) )@\\
+\mbox{}\verb@            {@\\
+\mbox{}\verb@               iNew = SDreftoindex(self->iSID, iRef);@\\
+\mbox{}\verb@               iNew = SDselect(self->iSID,iNew);@\\
+\mbox{}\verb@               SDgetinfo(iNew,pNam,&iA,iDim,&iD2, &iD2);@\\
+\mbox{}\verb@               if(strcmp(pNam,name) == 0)@\\
+\mbox{}\verb@               {@\\
+\mbox{}\verb@                  SDendaccess(iNew);@\\
+\mbox{}\verb@                  return iRef;@\\
+\mbox{}\verb@               }@\\
+\mbox{}\verb@               SDendaccess(iNew);@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@         } /* end for */ @\\
+\mbox{}\verb@      }   /* end Vgroup */@\\
+\mbox{}\verb@      /* we get here, only if nothing found */@\\
+\mbox{}\verb@      return -1;      @\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Helper routines for directory search}
+NXIInitDir initialises the directory data fields in the Nexus File structure
+for a subsequent directory request. Please note, that at root level only
+Vgroups will be searched. When searching SDS's at root level, all SDS's in 
+the whole
+file seem to be returned.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap32}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int NXIInitDir(pNexusFile self)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       int i;@\\
+\mbox{}\verb@       int32 iTag, iRef;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       if(self->iCurrentVG == 0) /* root level */@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         /* get the number and ID's of all lone Vgroups in the file */@\\
+\mbox{}\verb@         self->iNDir = Vlone(self->iVID,NULL,0);@\\
+\mbox{}\verb@         self->iRefDir  = (int32 *)malloc(self->iNDir*sizeof(int32));@\\
+\mbox{}\verb@         if(!self->iRefDir)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            NXIReportError(NXpData,"ERROR: out of memory in NXIInitDir");@\\
+\mbox{}\verb@            return -1;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         Vlone(self->iVID,self->iRefDir,self->iNDir);@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          /* Vgroup level */@\\
+\mbox{}\verb@         self->iNDir  = Vntagrefs(self->iCurrentVG);@\\
+\mbox{}\verb@         self->iRefDir = (int32 *)malloc(self->iNDir*sizeof(int32));@\\
+\mbox{}\verb@         self->iTagDir = (int32 *)malloc(self->iNDir*sizeof(int32));@\\
+\mbox{}\verb@         if( (!self->iRefDir) || (!self->iTagDir))@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            NXIReportError(NXpData,"ERROR: out of memory in NXIInitDir");@\\
+\mbox{}\verb@            return -1;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         for(i = 0; i < self->iNDir; i++)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            Vgettagref(self->iCurrentVG,i,&iTag, &iRef);@\\
+\mbox{}\verb@            self->iRefDir[i] = iRef;@\\
+\mbox{}\verb@            self->iTagDir[i] = iTag;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@       }       @\\
+\mbox{}\verb@       self->iCurDir = 0;@\\
+\mbox{}\verb@       return 1;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXIKillDir removes all data associated with a directory search from 
+ memory.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap33}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static void NXIKillDir(pNexusFile self)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      if(self->iRefDir)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         free(self->iRefDir);@\\
+\mbox{}\verb@         self->iRefDir = NULL;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      if(self->iTagDir)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         free(self->iTagDir);@\\
+\mbox{}\verb@         self->iTagDir = NULL;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      self->iCurDir = 0;@\\
+\mbox{}\verb@      self->iNDir = 0;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXIInitAttDir will initialise the counters for reading either SDS or global 
+attribute data. 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap34}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@   static int NXIInitAttDir(pNexusFile pFile)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       int iRet;@\\
+\mbox{}\verb@       int32 iData, iAtt, iRank, iType;@\\
+\mbox{}\verb@       int32 iDim[MAX_VAR_DIMS];@\\
+\mbox{}\verb@       NXname pNam;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       pFile->iCurDir = 0;@\\
+\mbox{}\verb@       if(pFile->iCurrentSDS != 0) /* SDS level */@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         iRet = SDgetinfo(pFile->iCurrentSDS,pNam, &iRank, iDim,&iType, @\\
+\mbox{}\verb@                          &iAtt); @\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else /* global level */@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         iRet = SDfileinfo(pFile->iSID,&iData,&iAtt);  @\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       if(iRet < 0)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         NXIReportError(NXpData,"ERROR: HDF cannot read attribute numbers");@\\
+\mbox{}\verb@         pFile->iNDir = 0;@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       pFile->iNDir = iAtt;@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap35}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------------------------------------------------------------------@\\
+\mbox{}\verb@                            Nexus API header file@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland@\\
+\mbox{}\verb@             Przemek Klosowski, U. of Maryland & NIST, USA       @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   No warranties of any kind taken.@\\
+\mbox{}\verb at ----------------------------------------------------------------------------*/@\\
+\mbox{}\verb@#ifndef NEXUSAPI@\\
+\mbox{}\verb@#define NEXUSAPI@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#include <mfhdf.h>@\\
+\mbox{}\verb@@\\
+\mbox{}\verb at typedef enum {NXACC_READ = DFACC_READ, @\\
+\mbox{}\verb@              NXACC_RDWR = DFACC_RDWR, @\\
+\mbox{}\verb@              NXACC_CREATE = DFACC_CREATE } NXaccess;@\\
+\mbox{}\verb at typedef void *  NXhandle;@\\
+\mbox{}\verb at typedef int  NXstatus;@\\
+\mbox{}\verb at typedef char NXname[VGNAMELENMAX];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#define NX_OK 1@\\
+\mbox{}\verb@#define NX_ERROR 0@\\
+\mbox{}\verb@#define NX_EOD -1@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------@\\
+\mbox{}\verb@                HDF Datatype values for datatype parameters @\\
+\mbox{}\verb@                       in the Nexus API@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  DFNT_FLOAT32     32 bit float@\\
+\mbox{}\verb@  DFNT_FLOAT64     64 nit float == double@\\
+\mbox{}\verb@  DFNT_INT8        8 bit integer ==char, byte@\\
+\mbox{}\verb@  DFNT_UINT8       8 bit unsigned integer@\\
+\mbox{}\verb@  DFNT_INT16       16 bit integer@\\
+\mbox{}\verb@  DFNT_UINT16      16 bit unsigned integer@\\
+\mbox{}\verb@  DFNT_INT32       32 bit integer@\\
+\mbox{}\verb@  DFNT_UINT32      32 bit unsigned integer@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  This list is a edited version of the one found in the HDF header file@\\
+\mbox{}\verb@  htndefs.h. That source will always be the real reference, this is@\\
+\mbox{}\verb@  documented here for your convenience.@\\
+\mbox{}\verb at --------------------------------------------------------------------------*/ @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------@\\
+\mbox{}\verb@    A non Nexus standars function to set an error handler @\\
+\mbox{}\verb@*/@\\
+\mbox{}\verb@  void NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text));@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@@\\
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap36}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------------------------------------------------------------------@\\
+\mbox{}\verb@                         Nexus API implementation file.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  For documentation see the Napi.tex file which comes with this @\\
+\mbox{}\verb@  distribution.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  copyleft: Mark Koennecke@\\
+\mbox{}\verb@            Labor fuer Neutronenstreuung@\\
+\mbox{}\verb@            Paul Scherrer Institut@\\
+\mbox{}\verb@            CH-5232 Villigen-PSI@\\
+\mbox{}\verb@            Switzerland@\\
+\mbox{}\verb@            Mark.Koenencke@{\tt @}\verb at psi.ch@\\
+\mbox{}\verb@            Przemek Klosowski@\\
+\mbox{}\verb@            U. of Maryland & NIST        @\\
+\mbox{}\verb@            przemek.klosowski@{\tt @}\verb at nist.gov @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  no warranties of any kind, whether explicit or implied, taken.@\\
+\mbox{}\verb@  Distributed under the GNU copyleft license as documented elsewhere.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  March 1997@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  Version: 1.0@\\
+\mbox{}\verb at ----------------------------------------------------------------------------*/@\\
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{document}
diff --git a/doc/doxygen/CMakeLists.txt b/doc/doxygen/CMakeLists.txt
new file mode 100644
index 0000000..a43dddb
--- /dev/null
+++ b/doc/doxygen/CMakeLists.txt
@@ -0,0 +1,94 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+if (DOXYGEN_FOUND AND DOXYGEN_DOT_FOUND)
+
+    SET (ENV{TOPSRC} ${CMAKE_SOURCE_DIR})
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    html-c latex-c c-api.tag
+        COMMAND   ${DOXYGEN_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/doxygen/Doxyfile_c
+        DEPENDS   ${javaclass}
+        COMMENT   "C DOXYGEN"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    html-cpp latex-cpp
+        COMMAND   ${DOXYGEN_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/doxygen/Doxyfile_cpp
+        DEPENDS   html-c latex-c c-api.tag
+        COMMENT   "CPP DOXYGEN"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    html-java latex-java
+        COMMAND   ${DOXYGEN_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/doxygen/Doxyfile_java
+        DEPENDS   html-cpp latex-cpp
+        COMMENT   "Java DOXYGEN"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    html-python latex-python
+        COMMAND   ${DOXYGEN_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/doxygen/Doxyfile_python
+        DEPENDS   html-java latex-java
+        COMMENT   "Python DOXYGEN"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    html-f90 latex-f90
+        COMMAND   ${DOXYGEN_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/doxygen/Doxyfile_f90
+        DEPENDS   html-python latex-python
+        COMMENT   "F90 DOXYGEN"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    html-f77 latex-f77
+        COMMAND   ${DOXYGEN_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/doxygen/Doxyfile_f77
+        DEPENDS   html-f90 latex-f90
+        COMMENT   "F77 DOXYGEN"
+    )
+
+    ADD_CUSTOM_TARGET(NexusDoxygenBuild ALL echo
+        DEPENDS   html-f77 latex-f77
+    )
+
+    install (DIRECTORY ${CMAKE_BINARY_DIR}/doc/doxygen/html-c
+                       ${CMAKE_BINARY_DIR}/doc/doxygen/html-cpp
+                       ${CMAKE_BINARY_DIR}/doc/doxygen/html-java
+                       ${CMAKE_BINARY_DIR}/doc/doxygen/html-python
+                       ${CMAKE_BINARY_DIR}/doc/doxygen/html-f90
+                       ${CMAKE_BINARY_DIR}/doc/doxygen/html-f77
+                       DESTINATION ${NXDOCDIR}/doxygen COMPONENT Documentation)
+
+endif (DOXYGEN_FOUND AND DOXYGEN_DOT_FOUND)
+
diff --git a/doc/doxygen/Doxyfile_c b/doc/doxygen/Doxyfile_c
new file mode 100644
index 0000000..dcfc32f
--- /dev/null
+++ b/doc/doxygen/Doxyfile_c
@@ -0,0 +1,1727 @@
+# Doxyfile 1.7.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = CAPI
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/src \
+                         $(TOPSRC)/include \
+                         preamble.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.c \
+                         *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = $(TOPSRC)/test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.c \
+                         *.h
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-c
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is adviced to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-c
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = c-api.tag
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_c_brief b/doc/doxygen/Doxyfile_c_brief
new file mode 100644
index 0000000..44ed343
--- /dev/null
+++ b/doc/doxygen/Doxyfile_c_brief
@@ -0,0 +1,1727 @@
+# Doxyfile 1.7.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus Data Format
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = NeXus C API
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = CAPI
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = NO
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = NO
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/src \
+                         $(TOPSRC)/include \
+                         preamble.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.c \
+                         *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = $(TOPSRC)/test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.c \
+                         *.h
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-c
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is adviced to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-c
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = c-api.tag
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = NO
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = NO
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_cpp b/doc/doxygen/Doxyfile_cpp
new file mode 100644
index 0000000..18108a6
--- /dev/null
+++ b/doc/doxygen/Doxyfile_cpp
@@ -0,0 +1,1532 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = CPPAPI
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/bindings/cpp \
+			 preamble.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = $(TOPSRC)/test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.cpp *.cxx *.hpp
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-cpp
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-cpp
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = c-api.tag=../html-c
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_f77 b/doc/doxygen/Doxyfile_f77
new file mode 100644
index 0000000..455692e
--- /dev/null
+++ b/doc/doxygen/Doxyfile_f77
@@ -0,0 +1,1535 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = YES
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/bindings/f77
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.f \
+			 *.f77 \
+		  	 *.inc \
+			 *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-f77
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-f77
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_f90 b/doc/doxygen/Doxyfile_f90
new file mode 100644
index 0000000..56b7482
--- /dev/null
+++ b/doc/doxygen/Doxyfile_f90
@@ -0,0 +1,1535 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = YES
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/bindings/f90
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.f90 \
+			 *.inc \
+			 *.f \
+			 *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-f90
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-f90
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_java b/doc/doxygen/Doxyfile_java
new file mode 100644
index 0000000..07fd861
--- /dev/null
+++ b/doc/doxygen/Doxyfile_java
@@ -0,0 +1,1532 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus Java Bindings
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/bindings/java/org $(TOPSRC)/bindings/java/ncsa $(TOPSRC)/bindings/java/native
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.java \
+			 *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = $(TOPSRC)/bindings/java/test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.java
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-java
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-java
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_nxvalidate b/doc/doxygen/Doxyfile_nxvalidate
new file mode 100644
index 0000000..ef3ed15
--- /dev/null
+++ b/doc/doxygen/Doxyfile_nxvalidate
@@ -0,0 +1,1532 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NXvalidate
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/applications/NXvalidate/src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.java \
+			 *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = $(TOPSRC)/applications/NXvalidate/test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.java
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-nxvalidate
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-nxvalidate
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile_python b/doc/doxygen/Doxyfile_python
new file mode 100644
index 0000000..33b0cca
--- /dev/null
+++ b/doc/doxygen/Doxyfile_python
@@ -0,0 +1,1522 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NeXus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = $(TOPSRC)
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = $(TOPSRC)
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = $(TOPSRC)/bindings/python/nxs
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.py
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = $(TOPSRC)/bindings/python
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.py
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           = /usr/bin/doxypy.py
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html-python
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex-python
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = HDF4=1 \
+                         HDF5=1 \
+                         NXXML=1 \
+                         NXDLL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
new file mode 100644
index 0000000..455a4b3
--- /dev/null
+++ b/doc/doxygen/Makefile.am
@@ -0,0 +1,77 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id: Makefile.am 515 2005-06-22 08:33:09Z faa59 $
+#
+
+# documenttion subdirectories
+nxdoxydir	= $(NXDOCDIR)/doxygen
+CLEANFILES =  doxy.remove_me_to_remake c-api.tag
+
+all : doxy.remove_me_to_remake
+
+doxy.remove_me_to_remake :
+if HAVE_DOXYGEN
+if HAVE_PDFLATEX
+if HAVE_DOT
+	rm -fr latex html latex-* html-*
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_c_brief
+	( cd latex-c; make pdf )
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_cpp
+	( cd latex-cpp; ) # ( cd latex-cpp; make pdf )
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_java
+	( cd latex-java; ) # ( cd latex-java; make pdf )
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_python
+	( cd latex-python; ) # ( cd latex-python; make pdf )
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_f90
+	( cd latex-f90; ) # ( cd latex-f90; make pdf )
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_f77
+	( cd latex-f77; ) # ( cd latex-f77; make pdf )
+	env TOPSRC=$(top_srcdir) $(DOXYGEN) $(srcdir)/Doxyfile_nxvalidate
+	( cd latex-nxvalidate; ) # ( cd latex-nxvalidate; make pdf )
+	rm -f refman.pdf
+	ln -s latex-c/refman.pdf .
+endif
+endif
+endif
+	touch doxy.remove_me_to_remake
+
+dist-hook :
+if HAVE_DOXYGEN
+if HAVE_PDFLATEX
+if HAVE_DOT
+	if test -f $(srcdir)/refman.pdf; then \
+	    cp $(srcdir)/refman.pdf $(distdir); \
+	fi
+	if test -d $(srcdir)/html-c; then \
+	  for i in $(srcdir)/html-*; do \
+	    if test -d $$i; then \
+		cp -r $$i $(distdir); \
+	    fi; \
+	  done; \
+	  find $(distdir)/html-* -depth -type d -name '.svn' -exec rm -fr {} \; ; \
+	fi
+endif
+endif
+endif
+
+install-data-local :
+	$(mkinstalldirs) $(DESTDIR)$(nxdoxydir)
+	if test -f $(srcdir)/refman.pdf; then \
+	    cp $(srcdir)/refman.pdf $(DESTDIR)$(nxdoxydir); \
+        fi
+	if test -d $(srcdir)/html-c; then \
+	  for i in $(srcdir)/html-*; do \
+		cp -r $$i $(DESTDIR)$(nxdoxydir); \
+	  done; \
+	  find $(DESTDIR)$(nxdoxydir) -type f -exec chmod 0644 {} \; ;\
+	  find $(DESTDIR)$(nxdoxydir) -type d -exec chmod 0755 {} \; ;\
+	fi
+
+clean-local :
+	rm -fr html-* latex-* refman.pdf
+
+uninstall-local :
+	rm -fr $(DESTDIR)$(nxdoxydir)
+
+EXTRA_DIST=$(srcdir)/Doxyfile_*
diff --git a/doc/doxygen/preamble.h b/doc/doxygen/preamble.h
new file mode 100644
index 0000000..519d4ed
--- /dev/null
+++ b/doc/doxygen/preamble.h
@@ -0,0 +1,91 @@
+/**
+ * \if CAPI
+ *  \mainpage NeXus API documentation
+ * \endif
+ * \if CPPAPI
+ *  \mainpage NeXus C++ API
+ *    \author Peter Peterson
+ *    \author Freddie Akeroyd
+ * \endif
+ *
+ * 2000-2008 NeXus Group
+ * 
+
+ * \if CAPI
+ * \section sec_purpose Purpose of API
+ *  The NeXus Application Program Interface is a suite of subroutines, written 
+ *  in C but with wrappers in C++, JAVA, PYTHON, Fortran 77 and 90. 
+ *  The subroutines call HDF routines to read and write the NeXus files with 
+ *  the correct structure. 
+ * \endif
+ * \if CPPAPI
+ * \section sec_purpose_cpp Purpose of API
+ *  This provides a C++ like interface to the NeXus C API. It adds:
+ *  \li Exceptions
+ *  \li Suport for std::vector<type> and std::string
+ *  \li Can directly obtain a container of entry/attribute details rather than 
+ *      needing to iterate via getNext calls.
+ * \endif
+ * 
+ * An API serves a number of useful purposes: 
+ * \li It simplifies the reading and writing of NeXus files. 
+ * \li It ensures a certain degree of compliance with the NeXus standard. 
+ * \li It allows the development of sophisticated input/output features such 
+ *     as automatic unit conversion. This has not been implemented yet. 
+ * \li It hides the implementation details of the format. In particular, the 
+ *     API can read and write HDF4, HDF5 (and shortly XML) files using the 
+ *     same routines. 
+ * For these reasons, we request that all NeXus files are written using the 
+ * supplied API. We cannot be sure that anything written using the underlying 
+ * HDF API will be recognized by NeXus-aware utilities. 
+ *
+ * \if CAPI
+ * \section sec_core Core API
+ * \endif
+ * \if CPPAPI
+ * \section sec_core_cpp Core API
+ * \endif
+ * The core API provides the basic routines for reading, writing and 
+ * navigating NeXus files. It is designed to be modal; there is a hidden 
+ * state that determines which groups and data sets are open at any given 
+ * moment, and subsequent operations are implicitly performed on these 
+ * entities. This cuts down the number of parameters to pass around in API 
+ * calls, at the cost of forcing a certain pre-approved mode d'emploi. This 
+ * mode d'emploi will be familiar to most: it is very similar to navigating a 
+ * directory hierarchy; in our case, NeXus groups are the directories, which 
+ * contain data sets and/or other directories. 
+ *
+ * \if CAPI
+ *   The core API comprises several functional groups which are listed on the 
+ *   \b Modules tab. 
+ * 
+ *   C programs that call the above routines should include the following 
+ *   header file: 
+ *     \code
+ *       #include "napi.h"
+ *     \endcode
+ *   \sa napi_test.c
+ * \endif
+ * \if CPPAPI
+ *   C++ programs that call the above routines should include the following 
+ *   header file: 
+ *     \code
+ *       #include "NeXusFile.hpp"
+ *     \endcode
+ *   \sa napi_test_cpp.cxx
+ * \endif
+ */
+
+/**
+ * \if CAPI
+ * \example napi_test.c
+ *   This is the test program for the NeXus C API.
+ *   It illustrates calling most functions to read and write a file.
+ * \endif
+ * \if CPPAPI
+ * \example napi_test_cpp.cxx
+ *   Test program for the NeXus C++ Interface.
+ *   This illustrates calling most of the functions for reading and writing a 
+ *   file
+ * \endif 
+ */
diff --git a/doc/howto/README b/doc/howto/README
new file mode 100644
index 0000000..b33b9b4
--- /dev/null
+++ b/doc/howto/README
@@ -0,0 +1,3 @@
+Various bits of NeXus documentation
+--
+$Id$
diff --git a/doc/nxdict/CMakeLists.txt b/doc/nxdict/CMakeLists.txt
new file mode 100644
index 0000000..8502663
--- /dev/null
+++ b/doc/nxdict/CMakeLists.txt
@@ -0,0 +1,30 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+install (FILES NXdict.tex DESTINATION ${NXDOCDIR}/nxdict COMPONENT Documentation)
+
diff --git a/doc/nxdict/Makefile.am b/doc/nxdict/Makefile.am
new file mode 100644
index 0000000..536ab0b
--- /dev/null
+++ b/doc/nxdict/Makefile.am
@@ -0,0 +1,11 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id$
+#
+nxdictdocdir		= $(NXDOCDIR)/nxdict
+
+# add files and example code here
+nxdictdoc_DATA		= NXdict.tex
+
+EXTRA_DIST		= NXdict.tex
diff --git a/doc/nxdict/NXdict.tex b/doc/nxdict/NXdict.tex
new file mode 100644
index 0000000..474d609
--- /dev/null
+++ b/doc/nxdict/NXdict.tex
@@ -0,0 +1,351 @@
+%  Copyleft (c) 1997 by Mark Koennecke at PSI, Switzerland.
+%
+%
+%  This software is distributed in the hope that it will be useful,
+%  but WITHOUT ANY WARRANTY; without even the implied warranty of
+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%  GNU General Public License for more details.
+%
+%  You may already have a copy of the GNU General Public License; if
+%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+%  Cambridge, MA 02139, USA.
+%
+
+\documentclass[12pt]{article}
+
+\setlength{\oddsidemargin}{-.1in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.2in}
+\setlength{\marginparwidth}{0.5in}
+
+\begin{document}
+\title{The NeXus Dictionary API}
+
+\author{Mark K\"onnecke\\
+  Labor f\"ur Neutronenstreuung\\
+  Paul Scherrer Institut\\
+  CH-5232 Villigen PSI\\
+  Switzerland\\       
+  Mark.Koennecke at psi.ch \\
+}
+
+
+
+\maketitle
+
+\vskip.3in
+\centerline{\large\bf Abstract}
+\vskip.2in
+\begin{center}
+\parbox{.8\textwidth}{
+  There is a proposed portable data exchange format for neutron and
+  X-ray scattering communities, NeXus (described in a separate
+  publication).   Another document describes an application programmers
+ interface to NeXus. This is a base level API which hides many of the
+ hideous details of the HDF interface from the NeXus programmer. The
+ present document   introduces a higher level application programmers
+ interface sitting on top of the NeXus API. This API (the NEXDICT-API),
+ reads all file structure interface from a dictionary data file and creates
+ the structure automatically from that information. The NEXDICT user only
+ needs to specify the data to write.
+}
+\end{center}
+
+\clearpage
+
+\section{Introduction}
+ There exists a proposal for a portable data exchange format for neutron and
+ X--ray scattering communities, NeXus. NeXus is fully described
+ elsewhere$^{1}$. NeXus sits on top of the hierarchical data format (HDF) as
+ defined and specified by the National Center for Supercomputer Applications, 
+ NCSA, USA. HDF comes with a library of access functions. On top of the
+ HDF-library an application programmers interface (API) for NeXus was
+ defined which hides many of the low level details and idiosyncracies of
+ the HDF interface form the NeXus programmer. However, writing NeXus files stays
+ hideous even with this interface due to the amount of repetitive code
+ required to implement the NeXus structure. Now, performing repetitive tasks is one
+ area a computer is good at. So, why not have the computer take care of all
+ the structure associated with the NeXus format? In order to do this two
+ components are needed:
+\begin{itemize}
+\item A language which describes the NeXus file structure to the computer.
+  This language will be called the NeXus Data Definition Language (NXDDL).
+  NXDDL might also be used as a tool for discussing and defining NeXus
+  data structures.
+\item An API which works with the NeXus Data Definition Language.
+\end{itemize}
+Both of the above will be detailed in this document.
+
+\section{The NeXus Data Definition Language}
+The NeXus Data Definition Language(NXDDL) has the purpose of defining the structure
+and data items in a NeXus file in a form which can be understood by a human
+programmer and which can be parsed by the computer in order to create the 
+structure. 
+For this, a dictionary--based approach will be used. This dictionary
+will contain pairs of short aliases for data items and definition strings 
+which hold the structure information. This dictionary will
+be initialized from a data file, the NXDDL-file. Such a dictionary can be
+used in the following way: given an appropriate API function, a NXDICT
+programmer  needs to specify only the alias and the data to write and 
+everything else is taken care of by the API: Vgroup creation, opening,
+SDS definition etc. Another use may involve the creation of a definition string
+completely or partly at run time which can then be used by an API function
+in order to create the structures defined by the definition string. The same
+holds for writing as well.
+
+
+A NXDDL dictionary is preferably initialized from a file.
+Such a NXDDL file has to follow these general structure guidelines:
+\begin{itemize}
+\item All input is in US--ASCII.
+\item A \verb+#+ in the first column denotes a comment and will be ignored.
+\item A \verb+\+ at the end of the line means that the current text will be 
+ continued with the next non-blank character for the next line.
+\item All other entries follow the form: alias = definition string.
+ This defines \verb+alias+ as a short form for the definition string  after the
+ equality sign.
+\end{itemize}         
+The addition of a special global Vgroup of class NXdict to the
+NeXus API, in order to hold the dictionary information within a NeXus file, might be considered.
+
+ The next thing to define is the content of the definition string. A
+ definition string will have the general form: \\
+\centerline{\bf PATH/TerminalSymbol}
+ This means a definition string will consist of a path specifier which
+ describes the position of a data item in the Vgroup hierarchy and a
+ terminal symbol which describes the nature of the data item. 
+
+ The path through the Vgroup hierarchy to a data item will be described in a
+ manner analog to a Unix directory hierarchy. However, NeXus requires two
+ pieces of data in order to fully qualify a Vgroup. This is it's name and
+ class. Consequently, both name and class name will be given for each Vgroup,
+ separated by a comma. A valid path string then looks like: \\
+\begin{verbatim} 
+     /scan1,NXentry/DMC,NXinstrument/big_detector,NXdetector/TerminalSymbol
+\end{verbatim}
+ This translates into: TerminalSymbol in Vgroup big\_detector, class
+ NXdetector, which resides in Vgroup DMC of class NXinstrument, which in
+ turn is situated in the Vgroup scan1 of class NXentry.
+
+ The terminal symbol in a definition string is used to define the data item
+ at the end of the definition. NeXus currently supports only three types of
+ data items at the end of the chain: these are scientific data sets (SDS),
+ Vgroups and links to other data items or Vgroups. The terminal symbol for a link
+ is specified by the keyword \verb+NXLINK+  
+ followed
+ by a valid alias of another data item or Vgroup. For example the terminal 
+ symbol: \\
+ \centerline{\bf NXLINK counts}
+ would define a link to the data item which is defined by the alias
+ \verb+counts+.
+
+ A Vgroup would be denoted by the keyword VGROUP. By then, the Vgroup has
+ already been defined by the path string. This form of alias is only useful
+ for the definition of links to Vgroups.
+
+ A SDS is more involved. The definition of an SDS starts with the keyword
+ \verb+SDS+. This keyword is followed by option value pairs which define the 
+  details of the SDS. The following options exist:
+ \begin{itemize}
+  \item {\bf -rank} defines the rank of the SDS.
+  \item {\bf -dim \{dim0,dim1,dim2,...., dimn\} } defines the dimensions of the
+       SDS. Exactly the number of rank numbers defining the dimensions
+ length is required inside the curly braces. 
+  \item {\bf -type} defines the data type of the SDS as a string corresponding
+  to the HDF data types.
+  \item {\bf -name} Specifies the name of the SDS.
+  \item {\bf -attr \{name,value\} } defines an attribute. In the curly braces
+   there must be the name and value of the attribute separated by a comma.
+  \end{itemize}
+  If no options are given a default is used. This will be a single floating
+  point number, as this is the most frequently written data item. As an 
+  example see the definition of a 3d array of 32 bit integers:
+  \begin{verbatim}
+   PATHSTRING/SDS -name counts -rank 3 -dim {64,64,712} -type DFNT_INT32 \
+                  -attr {Units,Counts}      
+
+  \end{verbatim}
+
+  \section{The NXDICT--API}
+  In order to interface with the NeXus dictionary API a set of
+  API--functions is needed. All functions and data types belonging to
+  this API start with the letters: NXD. The functions belonging to this API
+  fall into three groups:
+  \begin{itemize}
+   \item Dictionary maintainance functions.
+   \item Data writing and reading functions.
+   \item Utility functions.
+  \end{itemize}
+  
+  One additional data type is needed for this API:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap1}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   typedef void *NXDdict;@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXDdict will be used as a handle for the dictionary currently in use.
+
+\subsubsection{Dictionary Maintainance Function}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap2}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXDdict NXDinitfromfile(char *filename);@\\
+\mbox{}\verb@   NXstatus NXDclose(NXDdict handle, char *filename);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDadd(NXDdict handle, char *alias, char *DefString);@\\
+\mbox{}\verb@   NXstatus NXDget(NXDdict handle, char *alias, char *pBuffer, int iBufLen);@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+{\bf NXDinitfromfile} creates a new NeXus dictionary. If filename is NULL, this
+  is all that happens. If filename is not NULL, it will be opened and the
+  dictionary will be initialized from the file specified.  The return value
+  is either 0 for failure or non zero for success. 
+
+  {\bf NXDclose} deletes and writes a NeXus dictionary. If filename is not NULL,
+  the dictionary specified by handle is written to the file specified by
+  filename. In any case the dictionary specified by handle will be deleted.
+
+  {\bf NXDadd} adds a new alias -- Definition String pair to the dictionary
+  specified by handle.
+
+  {\bf NXget} retrieves the definition string for the alias specified as
+  the second parameter from the dictionary handle. The definition string
+  is copied to pBuffer. Maximum iBufLen characters will be copied.
+  
+  If a special dictionary Vgroup as extension to NeXus would be accepted,
+  two more functions need to be defined which read and write the dictionary 
+  from the NeXus file.
+
+\subsubsection{Data Handling functions}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap3}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDputalias(NXhandle file, NXDdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDputdef(NXhandle file, char *pDefString, void *pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDopenalias(NXhandle file, NXDdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDopendef(NXhandle file, char *pDefString, void *pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDgetalias(NXhandle file, NXDdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDgetdef(NXhandle file, char *pDefString, void *pData);@\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The NXDICT data handling functions go in pairs. The version ending in
+ alias expects an NXDdict and an alias as input. These routines work
+ out the pass from that. The other version ending on def acts upon 
+ a definition string specified as second parameter. Using this scheme
+ both full dictionary operation is possible, as well as operation with
+ program generated definition strings. All routines return the
+ usual NeXus status returns. All these routines start at the current Vgroup
+ level and return back to it.  
+
+ NXDputalias, NXDputdef write the data element specified by the alias or
+ the definition string to the NeXus file specified as first parameter. 
+ pData is a pointer to the data to be written. These routines will check for
+ the existence of all Vgroups required in the path part of the definition
+ string. If a Vgroup  is missing it will be created. 
+
+ NXDopenalias, NXDopendef open the specified data items specified by the
+ alias or the definition string. Then the usual NeXus functions can be 
+ used to interact with the data. These routines use the same scheme for
+ creating Vgroups on the fly as the put routines above.
+
+ NXDgetalias, NXDgetdef read a data item from file. pData MUST point to a
+ data area large enough to hold the data read. If a Vgroup is missing in
+ the path for one of these routines an error is generated because it is 
+ assumed that the data is present if a program wants to read it.  
+  
+  \subsection{NXCDICT Utility Functions}
+  This section list a couple of functions which either perform common 
+   tasks on NeXus files or relate
+  to aspects of error handling and debugging.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap4}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDwriteglobals(NXhandle file, @\\
+\mbox{}\verb@                            char *filename,@\\
+\mbox{}\verb@                            char *owner,@\\
+\mbox{}\verb@                            char *address,@\\
+\mbox{}\verb@                            char *phone,@\\
+\mbox{}\verb@                            char *e-mail,@\\
+\mbox{}\verb@                            char *place);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDmakeentry(NXhandle file, char *pName);@\\
+\mbox{}\verb@                            @\\
+\mbox{}\verb@   NXstatus NXDsetverbosity(int iLevel);   @\\
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+{\bf NXDwriteglobals} writes the global attributes to a newly opened 
+ NeXus file. The parameters should be self explaining. In addition 
+ the file creation date is automatically written.
+
+ {\bf NXDmakeentry} creates a new entry Vgroup at root level with the
+  name specified. The group creation date is automatically written.
+
+  {\bf NXDsetverbosity} sets a verbosity level. Currently only two are
+  supported: NXDquiet and NXDalot. If NXDquiet is set (the default) the
+  NXD routines perform their tasks quietly, only complaining about
+  fatal error conditions. If NXDalot is set, the NXD routines will comment
+  on any step they do. This facility will help to debug dictionary files
+  and the software. The output happens through the same scheme which
+  is used for NeXus error handling, i.e. a configurable error output
+  function. 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap5}
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------------------------------------------------------------------@\\
+\mbox{}\verb@                            NXDICT API header file@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   No warranties of any kind taken.@\\
+\mbox{}\verb at ----------------------------------------------------------------------------*/@\\
+\mbox{}\verb@#ifndef NXDICTAPI@\\
+\mbox{}\verb@#define NXDICTAPI@\\
+\mbox{}\verb@#include "napi.h" /* make sure, napi is included */@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-------------------- NXDict data types & defines ----------------------*/@\\
+\mbox{}\verb@#define NXquiet 0@\\
+\mbox{}\verb@#define NXalot  1@\\
+\mbox{}\verb@/*-------------------- Dictionary Maintainance ----------------------------*/@\\
+\mbox{}\verb@/*----------------- Dictionary added data transfer -----------------------*/ @\\
+\mbox{}\verb@/*-------------------- Utility Functions --------------------------------*/@\\
+\mbox{}\verb@#endif@\\
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{document}
diff --git a/doc/tech_ref/CMakeLists.txt b/doc/tech_ref/CMakeLists.txt
new file mode 100644
index 0000000..ab27723
--- /dev/null
+++ b/doc/tech_ref/CMakeLists.txt
@@ -0,0 +1,61 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+if(DOCBOOKUTILS_FOUND)
+
+    SET(DOC_SRC NeXus_definitions.docbook terminology.docbook methods.docbook base_classes.docbook tofnpd.docbook tofnref.docbook monoref.docbook tofdgs.docbook monotas.docbook)
+    SET(IMAGES tofnpd.jpg tofnpd.gif)
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    NeXus_definitions.pdf
+        COMMAND   ${DOCBOOK2PDF_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/tech_ref/NeXus_definitions.docbook
+        DEPENDS   ${DOC_SRC} ${IMAGES}
+        COMMENT   "PDF NeXus Definitions"
+    )
+
+    ADD_CUSTOM_COMMAND( 
+        OUTPUT    NeXus_definitions.txt
+        COMMAND   ${DOCBOOK2TXT_EXECUTABLE}
+        ARGS      ${CMAKE_SOURCE_DIR}/doc/tech_ref/NeXus_definitions.docbook
+        DEPENDS   NeXus_definitions.pdf
+        COMMENT   "TEXT NeXus Definitions"
+    )
+
+    ADD_CUSTOM_TARGET(NexusDocbookBuild ALL echo
+        DEPENDS   NeXus_definitions.txt
+    )
+
+	install (FILES ${CMAKE_BINARY_DIR}/doc/tech_ref/NeXus_definitions.pdf
+                       ${CMAKE_BINARY_DIR}/doc/tech_ref/NeXus_definitions.txt
+                       DESTINATION ${NXDOCDIR}/tech_ref COMPONENT Documentation)
+
+endif(DOCBOOKUTILS_FOUND)
+
+
+
diff --git a/doc/tech_ref/Makefile.am b/doc/tech_ref/Makefile.am
new file mode 100644
index 0000000..de670a5
--- /dev/null
+++ b/doc/tech_ref/Makefile.am
@@ -0,0 +1,26 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id$
+#
+IMAGES=tofnpd.jpg tofnpd.gif
+DOC_SRC=NeXus_definitions.docbook terminology.docbook methods.docbook base_classes.docbook tofnpd.docbook tofnref.docbook monoref.docbook tofdgs.docbook monotas.docbook
+DOC_OUTPUT=NeXus_definitions.pdf NeXus_definitions.txt
+
+nxtechrefdocdir		= $(NXDOCDIR)/tech_ref
+nxtechrefdoc_DATA		= $(DOC_OUTPUT)
+EXTRA_DIST 			= $(DOC_OUTPUT) $(DOC_SRC) $(IMAGES)
+
+if HAVE_DOCBOOK
+NeXus_definitions.pdf: $(DOC_SRC) $(IMAGES)
+	$(DOCBOOK2PDF) NeXus_definitions.docbook
+
+NeXus_definitions.txt: $(DOC_SRC)
+	$(DOCBOOK2TXT) NeXus_definitions.docbook
+else
+NeXus_definitions.pdf:
+	touch NeXus_definitions.pdf
+
+NeXus_definitions.txt:
+	touch NeXus_definitions.txt
+endif
diff --git a/doc/tech_ref/NeXus_definitions.docbook b/doc/tech_ref/NeXus_definitions.docbook
new file mode 100644
index 0000000..e2b0b8f
--- /dev/null
+++ b/doc/tech_ref/NeXus_definitions.docbook
@@ -0,0 +1,87 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.0//EN" [
+ <!ENTITY terminology  SYSTEM "terminology.docbook">
+ <!ENTITY methods      SYSTEM "methods.docbook">
+ <!ENTITY base-classes SYSTEM "base_classes.docbook">
+ <!ENTITY monoref      SYSTEM "monoref.docbook">
+ <!ENTITY monotas      SYSTEM "monotas.docbook">
+ <!ENTITY tofdgs       SYSTEM "tofdgs.docbook">
+ <!ENTITY tofnpd       SYSTEM "tofnpd.docbook">
+ <!ENTITY tofnref      SYSTEM "tofnref.docbook">
+ <!ENTITY nxtranslate  "<application>NXtranslate</application>">
+ <!ENTITY napi         "<acronym>napi</acronym>">
+ <!ENTITY mime-type    "<parameter>NXS:mime_type</parameter>">
+ <!ENTITY source       "<parameter>NXS:source</parameter>">
+ <!ENTITY location     "<parameter>NXS:location</parameter>">
+ <!ENTITY make-link    "<parameter>target</parameter>">
+ <!ENTITY link-tag     "<parameter>NAPIlink</parameter>">
+]>
+ 
+<book id="NXtranslate" lang="en">
+
+<bookinfo>
+<title>NeXus Technical Reference Manual</title>
+<date>11 May, 2005</date>
+<authorgroup>
+<editor>
+<firstname>Peter</firstname>
+<othername role="mi">F</othername>
+<surname>Peterson</surname>
+<affiliation>
+<orgname>NeXus International Advisory Committee</orgname>
+</affiliation>
+</editor>
+</authorgroup>
+
+<!--
+<abstract>
+
+<para>&nxtranslate is an anything to NeXus converter. This is
+accomplished by using translation files and a plugin style of
+architecture where &nxtranslate can read from new formats as plugins
+become available. This document describes the usage of &nxtranslate by
+three types of individuals: the person using existing translation
+files to create NeXus files, the person creating translation files,
+and the person writing new Retrievers. All of these concepts are
+discussed in detail.</para>
+
+</abstract>
+-->
+</bookinfo>
+
+<!-- ******************** OVERVIEW ******************** -->
+<chapter id="overview"><title>Overview</title>
+<para>An overview of NeXus goes here.</para>
+</chapter>
+
+<!-- ******************** TERMINOLOGY ******************** -->
+&terminology
+
+<!-- ******************** METHODOLGY ******************** -->
+&methods
+
+<!-- ******************** BASE CLASSES ******************** -->
+&base-classes
+
+<!-- ******************** DEFINITIONS ******************** -->
+<chapter id="definitions"><title>Definitions</title>
+&monoref
+&monotas
+&tofdgs
+&tofnpd
+&tofnref
+</chapter>
+
+<!-- ******************** APPENDICES ******************** -->
+<!--
+<chapter id="appendices"><title>Appendices</title>
+<para>hi there</para>
+</chapter>
+-->
+
+<!--
+&overview
+&translation
+&retrievers
+-->
+
+</book>
diff --git a/doc/tech_ref/base_classes.docbook b/doc/tech_ref/base_classes.docbook
new file mode 100644
index 0000000..ad1b0ec
--- /dev/null
+++ b/doc/tech_ref/base_classes.docbook
@@ -0,0 +1,1670 @@
+<!-- ******************** BASE CLASSES ******************** -->
+<chapter id="base-classes"><title>Base Classes</title>
+
+<para>This chapter will list all of the base classes and their
+contents. </para>
+
+<example id="NXaperture.xml"><title><filename>NXaperture.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXaperture.xml
+Editor:  NIAC
+$Id$
+
+Template of a beamline aperture.-->
+<NXaperture name="{Name of aperture}">
+  <NXgeometry name="">
+    {location and shape of aperture}?
+  </NXgeometry>
+  <material type="NX_CHAR">
+    {Absorbing material of the aperture}?
+  </material>
+  <description type="NX_CHAR">
+    {Description of aperture}?
+  </description>
+</NXaperture>]]>
+</programlisting>
+</example>
+
+<example id="NXattenuator.xml"><title><filename>NXattenuator.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXaperture.xml
+Editor:  NIAC
+$Id$
+
+Template of a beamline attenuator.-->
+<NXattenuator name="{Name of attenuator}">
+  <distance units="m" type="NX_FLOAT">
+    {Distance from sample}?
+  </distance>
+  <type type="NX_CHAR">
+    {Type of attenuator, e.g. polythene}?
+  </type>
+  <thickness units="cm" type="NX_FLOAT">
+    {Thickness of attenuator along beam direction}?
+  </thickness>
+  <scattering_cross_section units="barns" type="NX_FLOAT">
+    {Scattering cross section (coherent+incoherent)}?
+  </scattering_cross_section>
+  <absorption_cross_section units="barns" type="NX_FLOAT">
+    {Absorption cross section}?
+  </absorption_cross_section>
+  <attenuator_transmission type="NX_FLOAT">
+    {The nominal amount of the beam that gets through (transmitted 
+    intensity)/(incident intensity)}?
+  </attenuator_transmission>
+</NXattenuator>]]>
+</programlisting>
+</example>
+
+<example id="NXbeam-stop.xml"><title><filename>NXbeam_stop.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXbeam_stop.xml
+Editor:  Mark Koennecke
+$Id$
+
+A class for a beamstop. Beamstops and their positions are important for SANS 
+and SAXS experiments.
+-->
+<NXbeam_stop name="">
+  <NXgeometry name="">
+    {engineering shape, orientation and position of the beam stop.}?
+  </NXgeometry>
+  <description type="NX_CHAR">
+    {description of beamstop: circular | rectangular}?
+  </description>
+  <size units="cm" type="NX_FLOAT">
+    {size of beamstop}?
+  </size>
+  <x units="cm" type="NX_FLOAT">
+    {x position of the beamstop in relation to the detector}?
+  </x>
+  <y units="cm" type="NX_FLOAT">
+    {y position of the beamstop in relation to the detector}?
+  </y>
+  <distance_to_detector units="cm" type="NX_FLOAT">
+    {distance of the beamstop to the detector}
+  </distance_to_detector>
+  <status type="NX_CHAR">
+    {in|out}?
+  </status>
+</NXbeam_stop>]]>
+</programlisting>
+</example>
+
+<example id="NXbeam.xml"><title><filename>NXbeam.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXbeam.xml
+Editor:  NIAC
+$Id$
+
+Template of the state of the neutron or X-ray beam at any location. It will be 
+referenced by beamline component groups within the NXinstrument group or by the 
+NXsample group. Note that variables such as the incident energy could be scalar 
+values or arrays. This group is especially valuable in storing the results of 
+instrument simulations in which it is useful to specify the beam profile, time 
+distribution etc. at each beamline component. Otherwise, its most likely use is 
+in the NXsample group in which it defines the results of the neutron scattering 
+by the sample, e.g., energy transfer, polarizations.
+-->
+<NXbeam name="{Name of beam plane}">
+  <distance units="m" type="NX_FLOAT">
+    {Distance from sample}?
+  </distance>
+  <incident_energy units="meV" type="NX_FLOAT[:]">
+    {Energy on entering beamline component}?
+  </incident_energy>
+  <final_energy units="meV" type="NX_FLOAT[:]">
+    {Energy on leaving beamline component}?
+  </final_energy>
+  <energy_transfer units="meV" type="NX_FLOAT[:]">
+    {Energy change caused by beamline component }?
+  </energy_transfer>
+  <incident_wavelength units="Angstroms" type="NX_FLOAT[:]">
+    {Wavelength on entering beamline component}?
+  </incident_wavelength>
+  <incident_wavelength_spread units="Angstroms" type="NX_FLOAT[:]">
+    {Wavelength spread FWHM on entering component}?
+  </incident_wavelength_spread>
+  <incident_beam_divergence units="degree" type="NX_FLOAT[2,:]">
+    {Divergence of beam entering this component}?
+  </incident_beam_divergence>
+  <final_wavelength type="NX_FLOAT[:]">
+    {Wavelength on leaving beamline component}?
+  </final_wavelength>
+  <incident_polarization type="NX_FLOAT[3,:]">
+    {Polarization vector on entering beamline component}?
+  </incident_polarization>
+  <final_polarization type="NX_FLOAT[3,:]">
+    {Polarization vector on leaving beamline component}?
+  </final_polarization>
+  <final_wavelength_spread units="Angstroms" type="NX_FLOAT[:]">
+    {Wavelength spread FWHM of beam leaving this component}?
+  </final_wavelength_spread>
+  <final_beam_divergence units="degrees" type="NX_FLOAT[2,:]">
+    {Divergence FWHM of beam leaving this component}?
+  </final_beam_divergence>
+  <flux units="s-1cm-2" type="NX_FLOAT[i]">
+    {flux incident on beam plane area}?
+  </flux>
+  <NXdata name="{spectrum}">
+    {Distribution of beam with respect to relevant variable e.g. wavelength. 
+    This is mainly useful for simulations which need to store plottable 
+    information at each beamline component. }?
+  </NXdata>
+</NXbeam>]]>
+</programlisting>
+</example>
+
+<example id="NXcharacterizations.xml"><title><filename>NXcharacterizations.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXentry.xml
+Editor:  NIAC
+$Id$
+
+Template of the top-level NeXus group which contains all the data and 
+associated information that comprise a single measurement. It is mandatory that 
+there is at least one group of this type in the NeXus file.
+-->
+<NXcharacterization NXS:location="" NXS:source="{If missing the source file is 
+    the current file}?" 
+    name="empty_environment|empty_environment_background|empty_container
+    |empty_container_background|isotropic_scatterer           
+    |isotropic_scatterer_background" NXS:mime_type="{If missing the       
+    source file is NAPI readable}?">
+  <definition URL="?" version="?">?
+  </definition>
+</NXcharacterization>
+]]>
+</programlisting>
+</example>
+
+<example id="NXcollimator.xml"><title><filename>NXcollimator.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXcollimator.xml
+Editor:  NIAC
+$Id$
+
+Template of a beamline collimator.-->
+<NXcollimator name="{Name of collimator}">
+  <NXgeometry name="">
+    {position, shape and size}?
+  </NXgeometry>
+  <type type="NX_CHAR">
+    "Soller"|"radial"|"oscillating"|"honeycomb"?
+  </type>
+  <soller_angle units="minutes" type="NX_FLOAT">
+    {Angular divergence of Soller collimator}?
+  </soller_angle>
+  <divergence_x type="NX_FLOAT">
+    {divergence of collimator in local x direction}?
+  </divergence_x>
+  <divergence_y type="NX_FLOAT">
+    {divergence of collimator in local y direction}?
+  </divergence_y>
+  <frequency type="NX_FLOAT">
+    {Frequency of oscillating collimator}?
+  </frequency>
+  <NXlog name="frequency">
+    {Log of frequency}?
+  </NXlog>
+  <blade_thickness type="NX_FLOAT">
+  </blade_thickness>
+  <blade_spacing type="NX_FLOAT">
+  </blade_spacing>
+  <absorbing_material type="NX_CHAR">
+  </absorbing_material>
+  <transmitting_material type="NX_CHAR">
+  </transmitting_material>
+</NXcollimator>]]>
+</programlisting>
+</example>
+
+<example id="NXcrystal.xml"><title><filename>NXcrystal.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXcrystal.xml
+Editor:  NIAC
+$Id$
+
+Template of a crystal monochromator or analyzer. Permits double bent 
+monochromator comprised of multiple segments with anisotropic  Gaussian mosaic. 
+If curvatures are set to zero or are absent, array  is considered to be flat.  
+Scattering vector is perpendicular to surface. Crystal is oriented parallel to 
+beam incident on crystal before rotation, and lies in vertical plane.
+-->
+<NXcrystal name="{Name of crystal}">
+  <NXgeometry name="">
+    {Position of crystal}?
+  </NXgeometry>
+  <type type="NX_CHAR">
+    { "PG (Highly Oriented Pyrolytic Graphite)" | "Ge" | "Si" | "Cu" | "Fe3Si" 
+    | "CoFe" | "Cu2MnAl (Heusler)" | "Multilayer" }?
+  </type>
+  <cut_angle units="degrees" type="NXFLOAT">
+    {Cut angle of reflecting Bragg plane and plane of crystal surface}?
+  </cut_angle>
+  <unit_cell type="NX_FLOAT[6])">
+    {Unit cell parameters (lengths and angles)}?
+  </unit_cell>
+  <unit_cell_volume units="Angstroms3" type="NX_FLOAT" rank="1">
+    {Volume of the unit cell}?
+  </unit_cell_volume>
+  <orientation_matrix type="NX_FLOAT[3,3]">
+    {Orientation matrix of single crystal sample using Busing-Levy convention}?
+  </orientation_matrix>
+  <wavelength units="Angstroms" type="NX_FLOAT[i]">
+    {Optimum diffracted wavelength}?
+  </wavelength>
+  <lattice_parameter units="Angstrom" type="NX_FLOAT">
+    {Lattice parameter of the nominal reflection}?
+  </lattice_parameter>
+  <scattering_vector units="Angstrom^-1" type="NX_FLOAT">
+    {Scattering vector, Q, of nominal reflection}?
+  </scattering_vector>
+  <reflection type="NX_INT[3]">
+    {[hkl] values of nominal reflection}?
+  </reflection>
+  <segment_width units="m" type="NX_FLOAT">
+    {Horizontal width of individual segment}?
+  </segment_width>
+  <segment_height units="m" type="NX_FLOAT">
+    {Vertical height of individual segment}?
+  </segment_height>
+  <segment_thickness units="m" type="NX_FLOAT">
+    {Thickness of individual segment}?
+  </segment_thickness>
+  <segment_gap units="m" type="NX_FLOAT">
+    {Typical gap between adjacent segments}?
+  </segment_gap>
+  <segment_columns units="m" type="NXFLOAT">
+    {number of segment columns in horizontal direction}?
+  </segment_columns>
+  <segment_rows units="m" type="NXFLOAT">
+    {number of segment rows in vertical direction}?
+  </segment_rows>
+  <mosaic_horizontal units="arc minutes" type="NXFLOAT">
+    {horizontal mosaic Full Width Half Maximum}?
+  </mosaic_horizontal>
+  <mosaic_vertical units="arc minutes" type="NXFLOAT">
+    {vertical mosaic Full Width Half Maximum}?
+  </mosaic_vertical>
+  <curvature_horizontal units="degrees" type="NX_FLOAT">
+    {Horizontal curvature of focusing crystal}?
+  </curvature_horizontal>
+  <curvature_vertical units="degrees" type="NX_FLOAT">
+    {Vertical curvature of focusing crystal}?
+  </curvature_vertical>
+  <polar_angle units="degrees" type="NX_FLOAT[i]">
+    {Polar (scattering) angle at which crystal assembly is positioned}?
+  </polar_angle>
+  <azimuthal_angle units="degrees" type="NX_FLOAT[i]">
+    {Azimuthal angle at which crystal assembly is positioned}?
+  </azimuthal_angle>
+  <bragg_angle units="degrees" type="NX_FLOAT[i]">
+    {Bragg angle of nominal reflection}?
+  </bragg_angle>
+  <temperature Units="Kelvin" type="NX_FLOAT">
+    {average/nominal crystal temperature}
+  </temperature>
+  <temperature_log type="NXlog">
+    {log file of crystal temperature}
+  </temperature_log>
+  <reflectivity type="NXdata">
+    {crystal reflectivity versus wavelength }
+  </reflectivity>
+  <transmission type="NXdata">
+    {crystal transmission versus wavelength }
+  </transmission>
+</NXcrystal>]]>
+</programlisting>
+</example>
+
+<example id="NXdata.xml"><title><filename>NXdata.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXdata.xml
+Editor:  NIAC
+$Id$
+
+Template of plottable data and their dimension scales. It is mandatory that 
+there is at least one group of this type in each NXentry group.  Note that 
+"variable" and "data" can be defined with different names.  The "signal" and 
+"axes" attribute of the "data" item define which items are plottable data and 
+which are dimension scales.
+-->
+<NXdata name="{Name of data block}">
+  <variable long_name="{Axis label}" distribution="0|1" first_good="{Index of 
+      first good value}" type="NX_FLOAT[:]|NX_INT[:]" last_good="{Index of last 
+      good value}">
+    {Dimension scale defining an axis of the data}?
+  </variable>
+  <variable_errors type="NX_FLOAT[:]|NX_INT[:]">
+    {Errors associated with axis "variable"}?
+  </variable_errors>
+  <data long_name="{Title of data}" signal="1" axes="[...]" 
+      type="NX_FLOAT[:...]|NX_INT[:...]">
+    {Data values}?
+  </data>
+  <errors type="NX_FLOAT[:...]">
+    {Standard deviations of data values - the data array is identified by the 
+    attribute signal="1". This array must have the same dimensions as the data}?
+  </errors>
+</NXdata>]]>
+</programlisting>
+</example>
+
+<example id="NXdetector.xml"><title><filename>NXdetector.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXdetector.xml
+Editor:  NIAC
+$Id$
+
+Template of a detector, detector bank, or multidetector.-->
+<NXdetector name="{Name of detector bank}">
+  <time_of_flight primary="1?" long_name="{Axis label}" link="{absolute path to 
+      location in NXdetector}" units="10^-6 second|10^-7 second" 
+      type="NX_FLOAT[j+1]" axis="1">
+    {Total time of flight}
+  </time_of_flight>
+  <detector_number link="{absolute path to location in NXdetector}" 
+      long_name="{Axis label}" type="NX_INT[i]" primary="1?" axis="2">
+    {Identifier for detector}?
+  </detector_number>
+  <data check_sum="{Integral of data as check of data       integrity} 
+      (NX_INT)?" signal="1" 
+      axes="[time_of_flight,detector_number,x_offset?,y_offset?]?" 
+      long_name="{Title of measurement}?" link="{absolute path to location in 
+      NXdetector}" units="number" type="NX_FLOAT[i,j,k?,l?]|NX_INT[i,j,k?,l?]">
+    {Data values}?
+  </data>
+  <data_error units="number" link="{absolute path to location in NXdetector}" 
+      type="NX_FLOAT[i,j,k?,l?]|NX_INT[i,j,k?,l?]">
+    {Data values}
+  </data_error>
+  <x_offset primary="1?" long_name="{Axis label}" link="{absolute path to 
+      location in NXdetector}" units="10^-3 meter|10^-2 meter" 
+      type="NX_FLOAT[k+1]" axis="3">
+    {offset from the detector center in x-direction}?
+  </x_offset>
+  <y_offset primary="1?" long_name="{Axis label}" link="{absolute path to 
+      location in NXdetector}" units="10^-3 meter|10^-2 meter" 
+      type="NX_FLOAT[l+1]" axis="4">
+    {offset from the detector center in the y-direction}?
+  </y_offset>
+  <distance axes="detector_number,x_offset?,y_offset?" 
+      type="NX_FLOAT[j,k?,l?]">
+  </distance>
+  <polar_angle axes="detector_number,x_offset?,y_offset?" 
+      type="NX_FLOAT[j,k?,l?]">
+  </polar_angle>
+  <azimuthal_angle axes="detector_number,x_offset?,y_offset?" 
+      type="NX_FLOAT[j,k?,l?]">
+  </azimuthal_angle>
+  <description type="NX_CHAR">
+    {name/manufacturer/model/etc. information}?
+  </description>
+  <NXgeometry name="">
+    {Position and orientation of detector element}?
+  </NXgeometry>
+  <translation units="centimeter" type="NX_FLOAT[2]">
+    {translation normal to direct beam}?
+  </translation>
+  <solid_angle units="steradians" type="NX_FLOAT[i]">
+    {Solid angle subtended by the detector at the sample}?
+  </solid_angle>
+  <x_pixelsize units="mili*metre" type="NX_FLOAT[i?]">
+    {Size of each detector pixel. If it is scalar all pixels are the same 
+    size}?
+  </x_pixelsize>
+  <y_pixelsize units="mili*metre" type="NX_FLOAT[i?]">
+    {Size of each detector pixel. If it is scalar all pixels are the same 
+    size}?
+  </y_pixelsize>
+  <dead_time type="NX_FLOAT[i]">
+    {Detector dead time}?
+  </dead_time>
+  <hold_off units="micro.second" type="NX_FLOAT[i]">
+    {Delay in detector registering an event}?
+  </hold_off>
+  <gas_pressure units="bars" type="NX_FLOAT[i]">
+    {Detector gas pressure}?
+  </gas_pressure>
+  <detection_gas_path units="cm" type="NX_FLOAT">
+    {maximum drift space dimension}?
+  </detection_gas_path>
+  <crate type="NX_INT[i]" local_name="{Equivalent local term}">
+    {Crate number of detector}?
+  </crate>
+  <slot type="NX_INT[i]" local_name="{Equivalent local term}">
+    {Slot number of detector}?
+  </slot>
+  <input type="NX_INT[i]" local_name="{Equivalent local term}">
+    {Input number of detector}?
+  </input>
+  <type type="NX_CHAR">
+    "He3 gas cylinder"|He3 PSD"|"He3 planar multidetector"| "He3 curved 
+    multidetector"| "multi-tube He3 PSD"|"BF3 gas"|"scintillator"|"fission 
+    chamber"?
+  </type>
+  <NXdata name="efficiency">
+    {Efficiency of detector with respect to e.g. wavelength}?
+  </NXdata>
+  <calibration_date type="ISO8601">
+    {date of last calibration (geometry and/or efficiency) measurements}?
+  </calibration_date>
+  <calibration_method type="NXnote">
+    {summary of conversion of array data to pixels (e.g. polynomial 
+    approximations) and location of details of the calibrations}?
+  </calibration_method>
+</NXdetector>]]>
+</programlisting>
+</example>
+
+<example id="NXdisk-chopper.xml"><title><filename>NXdisk_chopper.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXdisc_chopper.xml
+Editor:  Mark Koennecke
+$Id$
+
+Template of NXdisc_chopper.-->
+<NXdisk_chopper name="{chopper_name}">
+  <type type="NX_CHAR">
+    {Chopper type single|contra_rotating_pair|synchro_pair}?
+  </type>
+  <rotation_speed units="rpm|hertz" type="NX_FLOAT">
+    {chopper rotation speed}?
+  </rotation_speed>
+  <slits type="NX_INT">
+    {Number of slits}
+  </slits>
+  <slit_angle units="degree" type="NX_FLOAT">
+    {angular opening}
+  </slit_angle>
+  <pair_separation units="cm" type="NX_FLOAT">
+    {disc spacing in direction of beam}?
+  </pair_separation>
+  <radius units="cm" type="NX_FLOAT">
+    {radius to centre of slit}
+  </radius>
+  <slit_height units="cm" type="NX_FLOAT">
+    {total slit height}
+  </slit_height>
+  <phase units="degree" type="NX_FLOAT">
+    {chopper phase angle}?
+  </phase>
+  <ratio type="NX_INT">
+    {pulse reduction factor of this chopper in relation to other 
+    choppers/fastest pulse in the instrument}?
+  </ratio>
+  <distance units="cm" type="NX_FLOAT">
+    {Effective distance to the origin}?
+  </distance>
+  <wavelength_range units="nm" type="NX_FLOAT[2]">
+    {low and high values of wavelength range transmitted}?
+  </wavelength_range>
+  <NXgeometry name="">
+    {geometry of the disk chopper}?
+  </NXgeometry>
+</NXdisk_chopper>]]>
+</programlisting>
+</example>
+
+<example id="NXentry.xml"><title><filename>NXentry.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXentry.xml
+Editor:  NIAC
+$Id$
+
+Template of the top-level NeXus group which contains all the data and 
+associated information that comprise a single measurement. It is mandatory that 
+there is at least one group of this type in the NeXus file.
+-->
+<NXentry name="{Entry Name}">
+  <title>
+    {Extended title for entry}?
+  </title>
+  <definition URL="{URL of DTD file}" version="{DTD version number}">
+    {Name of entry DTD}?
+  </definition>
+  <start_time type="ISO8601">
+    {Starting time of measurement}?
+  </start_time>
+  <end_time type="ISO8601">
+    {Ending time of measurement}?
+  </end_time>
+  <duration units="seconds" type="NX_INT">
+    {Duration of measurement}?
+  </duration>
+  <experiment_identifier type="NX_CHAR[]">
+    {}?
+  </experiment_identifier>
+  <run_number type="NX_INT">
+    {Number of run or scan stored in this entry}?
+  </run_number>
+  <run_cycle type="NX_CHAR[]">
+    {}?
+  </run_cycle>
+  <program_name version="{Program version number}">
+    {Name of program used to generate this file}?
+  </program_name>
+  <command_line>
+    {Name of command line used to generate this file}?
+  </command_line>
+  <notes>
+    {Notes describing entry}?
+  </notes>
+  <thumbnail type="NXnote" mime_type="{image/*}">
+    {An small image that is representative of the entry.} {An example of this 
+    is a 640x480 jpeg image automatically produced by a low resolution plot of 
+    the NXdata.}?
+  </thumbnail>
+  <NXcharacterization name="">*
+  </NXcharacterization>
+  <NXuser name="{user}">
+  </NXuser>
+  <NXsample name="{sample}">
+  </NXsample>
+  <NXinstrument name="{Name of instrument}">
+  </NXinstrument>
+  <NXmonitor name="{Name of monitor}">
+  </NXmonitor>
+  <NXdata name="{Name of data block}">
+  </NXdata>
+  <NXprocess name="{Name of the process}">
+  </NXprocess>
+</NXentry>]]>
+</programlisting>
+</example>
+
+<example id="NXenvironment.xml"><title><filename>NXenvironment.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXenvironment.xml
+Editor:  NIAC
+$Id$
+
+This class describes an external condition applied to the sample-->
+<NXenvironment name="{Name of sample environment}">
+  <name type="NX_CHAR">
+    {Apparatus identification code/model number; e.g. OC100 011 }?
+  </name>
+  <short_name type="NX_CHAR">
+    {Alternative short name, perhaps for dashboard display like a present 
+    Seblock name}?
+  </short_name>
+  <type type="NX_CHAR">
+    {Type of apparatus. This could be the SE codes in scheduling database; e.g. 
+    OC/100}?
+  </type>
+  <description type="NX_CHAR">
+    {Description of the apparatus; e.g. 100mm bore orange cryostat with Roots 
+    pump }?
+  </description>
+  <program type="NX_CHAR">
+    {Program controlling the apparatus; e.g. LabView VI name}?
+  </program>
+  <position type="NXgeometry">
+    {The position and orientation of the apparatus}?
+  </position>
+  <NXnote name="{name of note}">
+    {Additional information, LabView logs, digital photographs, etc}*
+  </NXnote>
+  <NXsensor name="{name of sensor}">
+  </NXsensor>
+</NXenvironment>]]>
+</programlisting>
+</example>
+
+<example id="NXevent-data.xml"><title><filename>NXevent_data.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXevent_data.xml
+Editor:  NIAC
+$Id$
+
+Template of NXevent_data-->
+<NXevent_data name="">
+  <time_of_flight units="10^n second" type="NX_INT[i]">
+    {A list of time of flight for each event as it comes in. This list is for 
+    all pulses with information to attach to a particular pulse located in 
+    events_per_pulse.}?
+  </time_of_flight>
+  <pixel_number type="NX_INT[i]">
+    {There will be extra information in the NXdetector to convert pixel_number 
+    to detector_number. This list is for all pulses with information to attach 
+    to a particular pulse located in events_per_pulse.}?
+  </pixel_number>
+  <pulse_time units="10^n second" type="NX_INT[j]" offset="{ISO8601}">
+    {The time that each pulse started with respect to the offset}?
+  </pulse_time>
+  <events_per_pulse type="NX_INT[j]">
+    {This connects the index "i" to the index "j". The jth element is the 
+    number of events in "i" that occured during the jth pulse.}?
+  </events_per_pulse>
+  <pulse_height units="" type="FLOAT[i,k?]">
+    {If voltages from the ends of the detector are read out this is where they 
+    go. This list is for all events with information to attach to a particular 
+    pulse height. The information to attach to a particular pulse is located in 
+    events_per_pulse.}?
+  </pulse_height>
+</NXevent_data>]]>
+</programlisting>
+</example>
+
+<example id="NXfermi-chopper.xml"><title><filename>NXfermi_chopper.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXfermi_chopper.xml
+Editor:  Ron Ghosh
+$Id$
+
+This is the description for a  Fermi chopper, possibly with curved slits.-->
+<NXfermi_chopper name="chopper_name">
+  <type type="NX_CHAR">
+    {fchopper type}?
+  </type>
+  <rotation_speed units="rpm" type="NX_FLOAT">
+    {chopper rotation speed}?
+  </rotation_speed>
+  <radius units="cm" type="NX_FLOAT">
+    {radius of chopper}?
+  </radius>
+  <slit units="cm" type="NX_FLOAT">
+    {width of an individual slit}?
+  </slit>
+  <r_slit units="cm" type="NX_FLOAT">
+    {radius of curvature of slits}?
+  </r_slit>
+  <num type="NX_INT">
+    {number of slits}?
+  </num>
+  <height units="cm" type="NX_FLOAT">
+    {input beam height}?
+  </height>
+  <width units="cm" type="NX_FLOAT">
+    {input beam width}?
+  </width>
+  <wavelength type="NX_FLOAT">
+    {Wavelength transmitted by chopper}?
+  </wavelength>
+  <NXgeometry name="">
+    {geometry of the fermi chopper}?
+  </NXgeometry>
+  <absorbing_material type="NX_CHAR">
+    {absorbing material}?
+  </absorbing_material>
+  <transmitting_material type="NX_CHAR">
+    {transmitting material}?
+  </transmitting_material>
+</NXfermi_chopper>]]>
+</programlisting>
+</example>
+
+<example id="NXfilter.xml"><title><filename>NXfilter.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXfilter.xml
+Editor:  NIAC
+$Id$
+
+Template for specifying the state of band pass filters.-->
+<NXfilter name="filter_name">
+  <NXgeometry name="">
+    {Geometry of the filter}?
+  </NXgeometry>
+  <description type="NX_CHAR">
+    {"Beryllium" | "Pyrolytic Graphite" | "Graphite" | "Sapphire" | "Silicon" | 
+    "Supermirror"}?
+  </description>
+  <status type="NX_CHAR">
+    {in | out}?
+  </status>
+  <transmission type="NXdata">
+    {Wavelength transmission profile of filter}?
+  </transmission>
+  <temperature Units="Kelvin" type="NX_FLOAT">
+    {average/nominal filter temperature}
+  </temperature>
+  <temperature_log type="NXlog">
+    {Linked temperature_log for the filter}?
+  </temperature_log>
+  <sensor_type type="NXsensor">
+    {Sensor(s)used to monitor the filter temperature}?
+  </sensor_type>
+  <unit_cell type="NX_FLOAT[n_comp,6])">
+    {Unit cell parameters for single crystal filter(lengths and angles)}?
+  </unit_cell>
+  <unit_cell_volume units="Angstroms3" type="NX_FLOAT[n_comp]" rank="1">
+    {Unit cell}?
+  </unit_cell_volume>
+  <orientation_matrix type="NX_FLOAT[n_comp,3,3]">
+    {Orientation matrix of single crystal filter}?
+  </orientation_matrix>
+  <m_value type="NX_FLOAT">
+    {m value of supermirror filter}
+  </m_value>
+  <substrate_material type="NX_FLOAT">
+    {substrate material of supermirror filter}
+  </substrate_material>
+  <substrate_thickness type="NX_FLOAT">
+    {substrate thickness of supermirror filter}
+  </substrate_thickness>
+  <coating_material type="NX_FLOAT">
+    {coating material of supermirror filter}
+  </coating_material>
+  <substrate_roughness type="NX_FLOAT">
+    {substrate rougness of supermirror filter}
+  </substrate_roughness>
+  <coating_roughness type="NX_FLOAT[nsurf]">
+    {coating roughness of supermirror filter}
+  </coating_roughness>
+</NXfilter>]]>
+</programlisting>
+</example>
+
+<example id="NXflipper.xml"><title><filename>NXflipper.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXflipper.xml
+Editor:  Nick Maliszewskyj <nickm at nist.gov>
+$Id$
+
+Template of a beamline spin flipper.-->
+<NXflipper name="{Name of flipper}">
+  <type type="NX_CHAR">
+    {coil|current-sheet}?
+  </type>
+  <flip_turns type="NX_FLOAT">
+    {Number of turns/cm in flipping field coils}?
+  </flip_turns>
+  <comp_turns type="NX_FLOAT">
+    {Number of turns/cm in compensating field coils}?
+  </comp_turns>
+  <guide_turns type="NX_FLOAT">
+    {Number of turns/cm in guide field coils}?
+  </guide_turns>
+  <flip_current units="amperes" type="NX_FLOAT">
+    {Flipping field coil current in "on" state"}?
+  </flip_current>
+  <comp_current units="amperes" type="NX_FLOAT">
+    {Compensating field coil current in "on" state"}?
+  </comp_current>
+  <guide_current units="amperes" type="NX_FLOAT">
+    {Guide field coil current in "on" state"}?
+  </guide_current>
+  <thickness units="cm" type="NX_FLOAT">
+    {thickness along path of neutron travel}?
+  </thickness>
+</NXflipper>]]>
+</programlisting>
+</example>
+
+<example id="NXgeometry.xml"><title><filename>NXgeometry.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXgeometry.xml
+Editor:  NIAC
+$Id$
+
+This is the description for a general position of a component. Note that every 
+instance of an NXgeometry should be  named "geometry" so that it can be linked 
+to (linked items  must share the same name in HDF)
+-->
+<NXgeometry name="">
+  <NXshape name="{shape}">
+    {shape/size information of component}?
+  </NXshape>
+  <NXtranslation name="{translation}">
+    {translation of component}?
+  </NXtranslation>
+  <NXorientation name="{orientation}">
+    {orientation of component}?
+  </NXorientation>
+  <description type="NX_CHAR">
+    {Optional description/label}{Probably only present if we are an additional 
+    reference point for components rather than the location of a real 
+    component}?
+  </description>
+  <component_index type="NX_INT">
+    {Position of the component along the beam path.}{The sample is at 0, 
+    components upstream have negative component_index, components downstream 
+    have positive component_index.}?
+  </component_index>
+</NXgeometry>]]>
+</programlisting>
+</example>
+
+<example id="NXguide.xml"><title><filename>NXguide.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXguide.xml
+Editor:  NIAC
+$Id$
+
+Template of NXguide-->
+<NXguide name="">
+  <NXgeometry name="">
+  </NXgeometry>
+  <description type="NX_CHAR">
+  </description>
+  <incident_angle type="NX_FLOAT">
+  </incident_angle>
+  <reflectivity type="NXdata">
+    {Reflectivity as function of wavelength [nsurf,i]}
+  </reflectivity>
+  <bend_angle_x type="NX_FLOAT">
+  </bend_angle_x>
+  <bend_angle_y type="NX_FLOAT">
+  </bend_angle_y>
+  <interior_atmosphere type="NX_CHAR">
+    "vacuum"|"helium"|"argon"
+  </interior_atmosphere>
+  <external_material type="NX_CHAR">
+    {external material outside substrate}
+  </external_material>
+  <m_value type="NX_FLOAT[nsurf]">
+  </m_value>
+  <substrate_material type="NX_FLOAT[nsurf]">
+  </substrate_material>
+  <substrate_thickness type="NX_FLOAT[nsurf]">
+  </substrate_thickness>
+  <coating_material type="NX_FLOAT[nsurf]">
+  </coating_material>
+  <substrate_roughness type="NX_FLOAT[nsurf]">
+  </substrate_roughness>
+  <coating_roughness type="NX_FLOAT[nsurf]">
+  </coating_roughness>
+  <number_sections type="NX_INT">
+    {number of substrate sections}
+  </number_sections>
+</NXguide>]]>
+</programlisting>
+</example>
+
+<example id="NXinstrument.xml"><title><filename>NXinstrument.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXinstrument.xml
+Editor:  NIAC
+$Id$
+
+Template of instrument descriptions comprising various beamline  components. 
+Each component will also be a NeXus group defined by its  distance from the 
+sample. Negative distances represent beamline  components that are before the 
+sample while positive distances  represent components that are after the 
+sample. This device allows  the unique identification of beamline components in 
+a way that is  valid for both reactor and pulsed instrumentation.
+-->
+<NXinstrument name="{Name of instrument}">
+  <name short_name="{abbreviated name of instrument}">
+    {Name of instrument}?
+  </name>
+  <NXsource name="{Name of facility}">
+  </NXsource>
+  <NXdisk_chopper name="{Name of chopper}">
+  </NXdisk_chopper>
+  <NXfermi_chopper name="">
+  </NXfermi_chopper>
+  <NXvelocity_selector name="">
+  </NXvelocity_selector>
+  <NXguide name="">
+  </NXguide>
+  <NXcrystal name="{Name of crystal monochromator or analyzer}">
+  </NXcrystal>
+  <NXaperture name="{Name of beamline aperture}">
+  </NXaperture>
+  <NXfilter name="">
+  </NXfilter>
+  <NXcollimator name="{Name of collimator}">
+  </NXcollimator>
+  <NXattenuator name="{Name of beam attenuator}">
+  </NXattenuator>
+  <NXpolarizer name="{Name of beam polarizer}">
+  </NXpolarizer>
+  <NXflipper name="{Name of beam polarization flipper}">
+  </NXflipper>
+  <NXmirror name="{Name of beam guide mirror}">
+  </NXmirror>
+  <NXdetector name="{Name of detector, bank of detectors, or multidetector}">
+  </NXdetector>
+  <NXbeam_stop name="">
+  </NXbeam_stop>
+</NXinstrument>]]>
+</programlisting>
+</example>
+
+<example id="NXlog.xml"><title><filename>NXlog.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXlog.xml
+Editor:  NIAC
+$Id$
+
+Definition of logged information, i.e. information monitored during the run. 
+They contain the logged values and the times at which they were measured as 
+elapsed time since a starting time recorded in ISO8601 format. This method of 
+storing logged data helps to distinguish instances in which a variable is a 
+dimension scale of the data, in which case it is stored in an NXdata group, and 
+instances in which it is logged during the run, when it should be stored in an 
+NXlog group.
+-->
+<NXlog name="{Name of logged measurements}">
+  <time units="" start="{ISO8601}" type="NX_FLOAT">
+    {Time of logged entry}{The times are relative to the "start" attribute and 
+    in the units specified in the "units" attribute.}
+  </time>
+  <value units="{units of logged value}" type="NX_FLOAT|NX_INT">
+    {Array of logged value, such as temperature}
+  </value>
+  <raw_value units="{units of raw values}" type="NX_FLOAT|NX_INT">
+    {Array of raw information, such as voltage on a thermocouple}?
+  </raw_value>
+  <description type="NX_CHAR">
+    {Description of logged value}?
+  </description>
+  <average_value units="" type="NX_FLOAT">
+  </average_value>
+  <average_value_error units="" type="NX_FLOAT">
+    {standard deviation of average_value}?
+  </average_value_error>
+  <minimum_value units="" type="NX_FLOAT">
+  </minimum_value>
+  <maximum_value units="" type="NX_FLOAT">
+  </maximum_value>
+  <duration units="" type="NX_FLOAT">
+    {Total time log was taken}?
+  </duration>
+</NXlog>]]>
+</programlisting>
+</example>
+
+<example id="NXmirror.xml"><title><filename>NXmirror.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXmirror.xml
+Editor:  
+$Id$
+
+Template of a beamline supermirror.-->
+<NXmirror name="{Name of supermirror}">
+  <NXgeometry name="">
+  </NXgeometry>
+  <description type="NX_CHAR">
+  </description>
+  <incident_angle type="NX_FLOAT">
+  </incident_angle>
+  <reflectivity type="NXdata">
+    {Reflectivity as function of wavelength}
+  </reflectivity>
+  <bend_angle_x type="NX_FLOAT">
+  </bend_angle_x>
+  <bend_angle_y type="NX_FLOAT">
+  </bend_angle_y>
+  <interior_atmosphere type="NX_CHAR">
+    "vacuum"|"helium"|"argon"
+  </interior_atmosphere>
+  <external_material type="NX_CHAR">
+    {external material outside substrate}
+  </external_material>
+  <m_value type="NX_FLOAT">
+  </m_value>
+  <substrate_material type="NX_CHAR">
+  </substrate_material>
+  <substrate_thickness type="NX_FLOAT">
+  </substrate_thickness>
+  <coating_material type="NX_CHAR">
+  </coating_material>
+  <substrate_roughness type="NX_FLOAT">
+  </substrate_roughness>
+  <coating_roughness type="NX_FLOAT">
+  </coating_roughness>
+</NXmirror>]]>
+</programlisting>
+</example>
+
+<example id="NXmoderator.xml"><title><filename>NXmoderator.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXmoderator.xml
+Editor:  NIAC
+$Id$
+
+This is the description for a general moderator-->
+<NXmoderator name="{Name of moderator}">
+  <NXgeometry name="">
+    {"Engineering" position of moderator}?
+  </NXgeometry>
+  <distance type="NX_FLOAT">
+    {Effective distance as seen by measuring radiation}?
+  </distance>
+  <type type="NX_CHAR">
+    { "H20" | "D20" | "Liquid H2" | "Liquid CH4" | "Liquid D2" | "Solid D2" | 
+    "C" |"Solid CH4" | "Solid H2"}?
+  </type>
+  <poison_depth units="cm" type="NX_FLOAT">
+    {Poison depth}?
+  </poison_depth>
+  <coupled type="NX_BOOLEAN">
+    {whether the moderator is coupled}?
+  </coupled>
+  <poison_material type="NX_CHAR">
+    { Gd | Cd |...}
+  </poison_material>
+  <temperature Units="Kelvin" type="NX_FLOAT">
+    {average/nominal moderator temperature}
+  </temperature>
+  <temperature_log type="NXlog">
+    {log file of moderator temperature}
+  </temperature_log>
+  <pulse_shape type="NXdata">
+    {moderator pulse shape}
+  </pulse_shape>
+</NXmoderator>]]>
+</programlisting>
+</example>
+
+<example id="NXmonitor.xml"><title><filename>NXmonitor.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXmonitor.xml
+Editor:  NIAC
+$Id$
+
+Template of monitor data. It is similar to the NXdata groups containing monitor 
+data and its associated dimension scale, e.g. time_of_flight or wavelength in 
+pulsed neutron instruments. However, it may also include integrals, or scalar 
+monitor counts, which are often used in both in both pulsed and steady-state 
+instrumentation.
+-->
+<NXmonitor name="{Name of monitor}">
+  <mode type="NX_CHAR">
+    "monitor"|"timer"?
+  </mode>
+  <preset type="NX_FLOAT">
+    {preset value for time or monitor}?
+  </preset>
+  <distance units="m" type="NX_FLOAT">
+    {Distance of monitor from sample}?
+  </distance>
+  <range type="NX_FLOAT[2]">
+    {Time-of-flight range over which the integral was calculated}?
+  </range>
+  <integral units="" type="NX_FLOAT">
+    {Total integral monitor counts}?
+  </integral>
+  <integral_log units="" type="NXlog">
+    {Time variation of monitor counts}?
+  </integral_log>
+  <type type="NX_CHAR">
+    "Fission Chamber"|"Scintillator"?
+  </type>
+  <time_of_flight units="microseconds" type="NX_FLOAT[i]">
+    {Time-of-flight}?
+  </time_of_flight>
+  <efficiency type="NX_FLOAT[i]">
+    {Monitor efficiency}?
+  </efficiency>
+  <data units="" signal="1" axes="" type="NX_INT[i]">
+    {Monitor data}?
+  </data>
+  <sampled_fraction units="dimensionless" type="NX_FLOAT">
+    {Proportion of incident beam sampled by the monitor (0<x<1)}
+  </sampled_fraction>
+  <NXgeometry name="">
+    {Geometry of the monitor}?
+  </NXgeometry>
+</NXmonitor>]]>
+</programlisting>
+</example>
+
+<example id="NXnote.xml"><title><filename>NXnote.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXnote.xml
+Editor:  NIAC
+$Id$
+
+This class can be used to store additional information in a NeXus file e.g. 
+pictures, movies, audio, additonal text logs
+-->
+<NXnote name="{name of note}">
+  <author type="NX_CHAR">
+    {Author or creator of note}?
+  </author>
+  <date type="ISO8601">
+    {Date note created/added}?
+  </date>
+  <type type="NX_CHAR">
+    {Mime content type of note data field e.g. image/jpeg, text/plain, 
+    text/html}?
+  </type>
+  <file_name type="NX_CHAR">
+    {Name of original file name if note was read from an external source}?
+  </file_name>
+  <description type="NX_CHAR">
+    {Title of an image or other details of the note}?
+  </description>
+  <data type="NX_BINARY">
+    {Binary note data - if text, line terminator is \r\n.}?
+  </data>
+</NXnote>]]>
+</programlisting>
+</example>
+
+<example id="NXorientation.xml"><title><filename>NXorientation.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXorientation.xml
+Editor:  NIAC
+$Id$
+
+This is the description for a general orientation of a component - it is used 
+by the NXgeometry class
+-->
+<NXorientation name="{name of orientation}">
+  <NXgeometry name="">
+    {Link to another object if we are using relative positioning, else absent}?
+  </NXgeometry>
+  <value type="NX_FLOAT[numobj,6]">
+    {The orientation information is stored as direction cosines.}{The direction 
+    cosines will be between the local coordinate directions and the reference 
+    directions (to origin or relative NXgeometry). Calling the local unit 
+    vectors (x',y',z') and the reference unit vectors (x,y,z) the six numbers 
+    will be [x' dot x, x' dot y, x' dot z, y' dot x, y' dot y, y' dot z] where 
+    "dot" is the scalar dot product (cosine of the angle between the unit 
+    vectors). The unit vectors in both the local and reference coordinates are 
+    right-handed and orthonormal.}?
+  </value>
+</NXorientation>]]>
+</programlisting>
+</example>
+
+<example id="NXprocess.xml"><title><filename>NXprocess.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXlog.xml
+Editor:  NIAC
+$Id$
+
+Template for a process.-->
+<NXprocess name="">
+  <NXnote name="{numbered name to allow for ordering steps}">
+    {}{The note will contain information about how the data was processed. The 
+    contents of the note can be anything that the processing code can 
+    understand, or simple text.}+
+  </NXnote>
+</NXprocess>]]>
+</programlisting>
+</example>
+
+<example id="NXroot.xml"><title><filename>NXroot.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXroot.xml
+Editor:  NIAC
+$Id$
+
+Definition of the root NeXus group.-->
+<NXroot NeXus_version="{Version of NeXus API used in writing the file}" 
+    HDF5_version="?" creator="{facility or program where file originated}?" 
+    file_name="{File name of original NeXus file}" HDF_version="?" 
+    file_time="{Date and time of file creation}" file_update_time="{Date and 
+    time of last file change at close}">
+  <NXentry name="{entry name}">
+  </NXentry>
+</NXroot>]]>
+</programlisting>
+</example>
+
+<example id="NXsample.xml"><title><filename>NXsample.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXsample.xml
+Editor:  NIAC
+$Id$
+
+Template of the state of the sample. This could include scanned variables that 
+are associated with one of the data dimensions, e.g. the magnetic field, or 
+logged data, e.g. monitored temperature vs elapsed time.
+-->
+<NXsample name="{name of the sample}">
+  <name type="NX_CHAR">
+    {Descriptive name of sample}?
+  </name>
+  <chemical_formula type="NX_CHAR">
+    {The chemical formula specified using CIF conventions.}{Abbreviated version 
+    of CIF standard: 1. Only recognized element symbols may be used. 2. Each 
+    element symbol is followed by a 'count' number. A count of '1' may be 
+    omitted. 3. A space or parenthesis must separate each cluster of (element 
+    symbol + count). 4. Where a group of elements is enclosed in parentheses, 
+    the multiplier for the group must follow the closing parentheses. That is, 
+    all element and group multipliers are assumed to be printed as subscripted 
+    numbers. 5. Unless the elements are ordered in a manner that corresponds to 
+    their chemical structure, the order of the elements within any group or 
+    moiety depends on whether or not carbon is present. If carbon is present, 
+    the order should be: C, then H, then the other elements in alphabetical 
+    order of their symbol. If carbon is not present, the elements are listed 
+    purely in alphabetic order of their symbol. This is the 'Hill' system used 
+    by Chemical Abstracts.}?
+  </chemical_formula>
+  <temperature type="NX_FLOAT[:]">
+    {Sample temperature. This could be a scanned variable}?
+  </temperature>
+  <electric_field direction="x|y|z" type="NX_FLOAT[:]">
+    {Applied electric field}*
+  </electric_field>
+  <magnetic_field direction="x|y|z" type="NX_FLOAT[:]">
+    {Applied magnetic field}*
+  </magnetic_field>
+  <stress_field direction="x|y|z" type="NX_FLOAT[:]">
+    {External stress}*
+  </stress_field>
+  <pressure type="NX_FLOAT[:]">
+    {Applied pressure}?
+  </pressure>
+  <changer_position type="NX_INT">
+    {Sample changer position}?
+  </changer_position>
+  <unit_cell type="NX_FLOAT[n_comp,6])">
+    {Unit cell parameters (lengths and angles)}?
+  </unit_cell>
+  <unit_cell_volume units="Angstroms3" type="NX_FLOAT[n_comp]" rank="1">
+    {Volume of the unit cell}?
+  </unit_cell_volume>
+  <sample_orientation units="degree" type="NX_FLOAT[3]">
+    {This will follow the Busing and Levy convention from Acta.Crysta v22, p457 
+    (1967)}?
+  </sample_orientation>
+  <orientation_matrix type="NX_FLOAT[n_comp,3,3]">
+    {Orientation matrix of single crystal sample}{The is the orientation matrix 
+    using Busing-Levy convention}?
+  </orientation_matrix>
+  <mass units="g" type="NX_FLOAT[n_comp]">
+    {Mass of sample}?
+  </mass>
+  <density units="g cm-3" type="NX_FLOAT[n_comp]">
+    {Density of sample}?
+  </density>
+  <relative_molecular_mass type="NX_FLOAT[n_comp]">
+    {Relative Molecular Mass of sample}?
+  </relative_molecular_mass>
+  <type type="NX_CHAR">
+    { sample | sample+can | can | calibration sample | normalisation sample | 
+    simulated data | none | sample environment }?
+  </type>
+  <situation type="NX_CHAR">
+    { air | vacuum | inert atmosphere | oxidising atmosphere | reducing 
+    atmosphere | sealed can | other }{The atmosphere will be one of the 
+    components, which is where its details will be stored; the relevant 
+    components will be indicated by the entry in the sample_component member.}?
+  </situation>
+  <description type="NX_CHAR">
+    {Description of the sample}?
+  </description>
+  <preparation_date type="ISO8601">
+    {Date of preparation of the sample}?
+  </preparation_date>
+  <geometry type="NXgeometry">
+    {The position and orientation of the center of mass of the sample}?
+  </geometry>
+  <beam type="NXbeam">
+    {Details of beam incident on sample - used to calculate sample/beam 
+    interaction point}?
+  </beam>
+  <component type="NX_CHAR[n_comp]">
+    {Details of the component of the sample and/or can}?
+  </component>
+  <sample_component type="NX_CHAR[n_comp]">
+    { What type of component we are "sample | can | atmosphere | kit" }?
+  </sample_component>
+  <concentration units="g.cm-3" type="NX_FLOAT[n_comp]">
+    {Concentration of each component}?
+  </concentration>
+  <volume_fraction type="NX_FLOAT[n_comp]">
+    {Volume fraction of each component}?
+  </volume_fraction>
+  <scattering_length_density type="NX_FLOAT[n_comp]">
+    {Scattering length density of each component (cm-2)}?
+  </scattering_length_density>
+  <unit_cell_class type="NX_CHAR[n_comp]">
+    { In case it is all we know and we want to record it "cubic | tetragonal | 
+    orthorhombic | monoclinic | triclinic" }?
+  </unit_cell_class>
+  <unit_cell_group type="NX_CHAR[n_comp]">
+    {Crystallographic point or space group}?
+  </unit_cell_group>
+  <path_length type="NX_FLOAT">
+    {Path length through sample/can for simple case when it does not vary with 
+    scattering direction}?
+  </path_length>
+  <path_length_window type="NX_FLOAT">
+    {Thickness of a beam entry/exit window on the can (mm) - assumed same for 
+    entry and exit}?
+  </path_length_window>
+  <transmission type="NXdata">
+    {As a function of Wavelength}?
+  </transmission>
+  <temperature_log type="NXlog">
+    {temperature_log.value is a link to e.g. 
+    temperature_env.sensor1.value_log.value}?
+  </temperature_log>
+  <temperature_env type="NXenvironment">
+    {Additional sample environment information}?
+  </temperature_env>
+  <magnetic_field_log type="NXlog">
+    {magnetic_field_log.value is a link to e.g. 
+    magnetic_field_env.sensor1.value_log.value}?
+  </magnetic_field_log>
+  <magnetic_field_env type="NXenvironment">
+    {Additional sample environment information}?
+  </magnetic_field_env>
+  <external_DAC type="NX_FLOAT">
+    {value sent to user's sample setup}?
+  </external_DAC>
+  <external_ADC type="NXlog">
+    {logged value (or logic state) read from user's setup}?
+  </external_ADC>
+  <short_title type="NX_CHAR">
+    {20 character fixed length sample description for legends}?
+  </short_title>
+</NXsample>]]>
+</programlisting>
+</example>
+
+<example id="NXsensor.xml"><title><filename>NXsensor.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXsensor.xml
+Editor:  NIAC
+$Id$
+
+This class describes a sensor used to monitor an external condition - the 
+condition itself in described in NXenvironment
+-->
+<NXsensor name="{Name of sensor}">
+  <model type="NX_CHAR">
+    {Sensor identification code/model number}?
+  </model>
+  <name type="NX_CHAR">
+    {Name for the sensor}?
+  </name>
+  <short_name type="NX_CHAR">
+    {Short name of sensor used e.g. on monitor display program}?
+  </short_name>
+  <attached_to type="NX_CHAR">
+    { where sensor is attached to ("sample" | "can") }?
+  </attached_to>
+  <NXgeometry name="">
+    {Defines the axes for logged vector quantities if they are not the global 
+    instrument axes}?
+  </NXgeometry>
+  <measurement type="NX_CHAR">
+    { what we measure "temperature | pH | magnetic_field | electric field | 
+    conductivity | resistance | voltage | pressure | flow | stress | strain | 
+    shear | surface_pressure" }?
+  </measurement>
+  <type type="NX_CHAR">
+    { The type of hardware we use for the measurement e.g. Temperature: "J | K 
+    | T | E | R | S | Pt100 | Rh/Fe" pH: "Hg/Hg2Cl2 | Ag/AgCl | ISFET" Ion 
+    selective electrode: "specify species; e.g. Ca2+" Magnetic field: "Hall" 
+    Surface pressure: "wilhelmy plate" }?
+  </type>
+  <run_control type="NX_BOOLEAN">
+    { Is data collection controlled/synchronised to this quantity: 1=no, 0=to 
+    "value", 1=to "value_deriv1" etc.}?
+  </run_control>
+  <high_trip_value units="{}" type="NX_FLOAT">
+    {Upper control bound of sensor reading if using run_control}?
+  </high_trip_value>
+  <low_trip_value units="{}" type="NX_FLOAT">
+    {Lower control bound of sensor reading if using run_control}?
+  </low_trip_value>
+  <value units="{}" type="NX_FLOAT[n]">
+    {nominal setpoint or average value - need [n] as may be a vector}?
+  </value>
+  <value_deriv1 units="{}" type="NX_FLOAT[n]">
+    {Nominal/average first derivative of value e.g. strain rate - need [n] as 
+    may be a vector}?
+  </value_deriv1>
+  <value_deriv2 units="{}" type="NX_FLOAT[n]">
+    {Nominal/average second derivative of value - need [n] as may be a vector}?
+  </value_deriv2>
+  <value_log type="NXlog">
+    {Time history of sensor readings}?
+  </value_log>
+  <value_deriv1_log type="NXlog">
+    {Time history of sensor readings}?
+  </value_deriv1_log>
+  <value_deriv2_log type="NXlog">
+    {Time history of sensor readings}?
+  </value_deriv2_log>
+  <external_field_brief type="NX_CHAR">
+    { along beam | across beam | transverse | solenoidal | flow shear gradient 
+    | flow vorticity }?
+  </external_field_brief>
+  <external_field_full type="NXorientation">
+    {For complex external fields not satisfied by External_field_brief}?
+  </external_field_full>
+</NXsensor>]]>
+</programlisting>
+</example>
+
+<example id="NXshape.xml"><title><filename>NXshape.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXshape.xml
+Editor:  NIAC
+$Id$
+
+This is the description of the general shape and size of a  component, which 
+may be made up of "numobj" separate elements -  it is used by the 
+NXgeometry.xml class
+-->
+<NXshape name="{name of shape}">
+  <shape type="NX_CHAR">
+    {"nxcylinder", "nxbox", "nxsphere", ...}?
+  </shape>
+  <size units="meter" type="NX_FLOAT[numobj,nshapepar]">
+    {physical extent of the object along its local axes (after NXorientation) 
+    with the center of mass at the local origin (after NXtranslate).}{The 
+    meaning and location of these axes will vary according to the value of the 
+    "shape" variable. nshapepar defines how many parameters. For the 
+    "nxcylinder" type the paramters are (diameter,height). For the "nxbox" type 
+    the parameters are (length,width,height). For the "nxsphere" type the 
+    parameters are (diameter).}?
+  </size>
+</NXshape>]]>
+</programlisting>
+</example>
+
+<example id="NXsource.xml"><title><filename>NXsource.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXsource.xml
+Editor:  NIAC
+$Id$
+
+Template of the neutron or x-ray source, insertion devices and/or moderators.-->
+<NXsource name="source">
+  <distance units="m" type="NX_FLOAT">
+    {Effective distance from sample}{Distance as seen by radiation from sample. 
+    This number should be negative to signify that it is upstream of the 
+    sample.}?
+  </distance>
+  <name type="NX_CHAR">
+    {Name of source}?
+  </name>
+  <type type="NX_CHAR">
+    "Spallation Neutron Source"|"Pulsed Reactor Neutron Source"|"Reactor 
+    Neutron Source"|"Synchrotron X-ray Source"|"Pulsed Muon Source"|"Rotating 
+    Anode X-ray"|Fixed Tube X-ray"?
+  </type>
+  <probe type="NX_CHAR">
+    neutron|x-ray|muon|electron?
+  </probe>
+  <power units="MW" type="NX_FLOAT">
+    {Source power}?
+  </power>
+  <current units="microamps" type="NX_FLOAT">
+    {Accelerator proton current}?
+  </current>
+  <voltage units="MeV" type="NX_FLOAT">
+    {Accelerator proton voltage}?
+  </voltage>
+  <frequency units="Hz" type="NX_FLOAT">
+    {Frequency of pulsed source}?
+  </frequency>
+  <period units="microseconds" type="NX_FLOAT">
+    {Period of pulsed source}?
+  </period>
+  <target_material type="NX_CHAR">
+    {Pulsed source target material} 
+    {"Ta"|"W"|"depleted_U"|"enriched_U"|"Hg"|"Pb"|"C"}?
+  </target_material>
+  <notes type="NX_CHAR">
+    {any source/facility related messages/events that occurred during the 
+    experiment}?
+  </notes>
+  <pulse_width units="micro.second" type="NX_FLOAT">
+    {width of source pulse}?
+  </pulse_width>
+  <pulse_shape type="NXdata">
+    {source pulse shape}?
+  </pulse_shape>
+  <NXgeometry name="">
+    {"Engineering" location of source}?
+  </NXgeometry>
+</NXsource>]]>
+</programlisting>
+</example>
+
+<example id="NXtranslation.xml"><title><filename>NXtranslation.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXtranslation.xml
+Editor:  NIAC
+$Id$
+
+This is the description for the general spatial location of a component - it is 
+used by the NXgeometry.xml class
+-->
+<NXtranslation name="{name of translation}">
+  <NXgeometry name="{geometry}">
+    {Link to other object if we are relative , else absent}?
+  </NXgeometry>
+  <distances units="" type="NX_FLOAT[numobj,3]">
+    {(x,y,z)}{This field and the angle field describe the position of a 
+    component. For absolute position, the origin is the scattering center 
+    (where a perfectly aligned sample would be) with the z-axis pointing 
+    downstream and the y-axis pointing gravitationally up. For a relative 
+    position the NXtranslation is taken into account before the NXorientation. 
+    The axes are right-handed and orthonormal.}?
+  </distances>
+</NXtranslation>]]>
+</programlisting>
+</example>
+
+<example id="NXuser.xml"><title><filename>NXuser.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXuser.xml
+Editor:  NIAC
+$Id$
+
+Template of user's contact information.  The format allows more than  one user 
+with the same affiliation and contact information, but a  second NXuser group 
+should be used if they have different  affiliations, etc.
+-->
+<NXuser name="">
+  <name type="NX_CHAR">
+    {Name of user responsible for this entry}?
+  </name>
+  <role type="NX_CHAR">
+    {role of user responsible for this entry}{Suggested roles are 
+    "local_contact", "principal_investigator", and "proposer"}?
+  </role>
+  <affiliation type="NX_CHAR">
+    {Affiliation of user}?
+  </affiliation>
+  <address type="NX_CHAR">
+    {Address of user}?
+  </address>
+  <telephone_number type="NX_CHAR">
+    {Telephone number of user}?
+  </telephone_number>
+  <fax_number type="NX_CHAR">
+    {Fax number of user}?
+  </fax_number>
+  <email type="NX_CHAR">
+    {Email of user}?
+  </email>
+  <facility_user_id type="NX_CHAR">
+    {facility based unique identifier for this person e.g. their identification 
+    code on the facility address/contact database}?
+  </facility_user_id>
+</NXuser>]]>
+</programlisting>
+</example>
+
+<example id="NXvelocity-selector.xml"><title><filename>NXvelocity_selector.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXvelocity_selector.xml
+Editor:  Ron Ghosh
+$Id$
+
+This is the description for a velocity selector. Proposed by: Ron Ghosh-->
+<NXvelocity_selector name="selector_name">
+  <type type="NX_CHAR">
+    {Vselect type}?
+  </type>
+  <rotation_speed units="rpm" type="NX_FLOAT">
+    {selector rotation speed}?
+  </rotation_speed>
+  <radius units="cm" type="NX_FLOAT">
+    {radieus at beam centre}?
+  </radius>
+  <spwidth units="cm" type="NX_FLOAT">
+    {spoke width at beam centre}?
+  </spwidth>
+  <length units="cm" type="NX_FLOAT">
+    {rotor length}?
+  </length>
+  <num type="NX_INT">
+    {number of spokes/lamella}?
+  </num>
+  <twist units="degrees" type="NX_FLOAT">
+    {twist angle along axis}?
+  </twist>
+  <table units="degrees" type="NX_FLOAT">
+    {offset vertical angle}?
+  </table>
+  <height units="cm" type="NX_FLOAT">
+    {input beam height}?
+  </height>
+  <width units="cm" type="NX_FLOAT">
+    {input beam width}?
+  </width>
+  <wavelength units="nm" type="NX_FLOAT">
+    {wavelength}
+  </wavelength>
+  <wavelength_spread type="NX_FLOAT">
+    {% deviation FWHM /Wavelength}?
+  </wavelength_spread>
+  <NXgeometry name="">
+    {geometry of the velocity selector}?
+  </NXgeometry>
+</NXvelocity_selector>]]>
+</programlisting>
+</example>
+
+</chapter>
diff --git a/doc/tech_ref/methods.docbook b/doc/tech_ref/methods.docbook
new file mode 100644
index 0000000..14770e6
--- /dev/null
+++ b/doc/tech_ref/methods.docbook
@@ -0,0 +1,47 @@
+<!-- ******************** METHODOLGY ******************** -->
+<chapter id="methods"><title>Methodology</title>
+
+<para>To send out a call to the instrument editors to assist in
+writing instrument and other specialized NeXus file definitions by
+following these steps:
+
+<orderedlist numeration="loweralpha">
+
+<listitem id="method.ol.draw"><para>Draw a schematic diagram of the
+instrument (line art, not a CAD style drawing).</para></listitem>
+
+<listitem id="method.ol.write"><para>Write a brief document outlining
+the purpose of the instrument. In the summary, list existing packages
+that perform data reduction and/or analysis for this type of
+data. Also list the information that will (and will not) exist in the
+file including, but not limited to, characterization measurements used
+for subtracting a background or normalizing to an incident
+spectrum.</para></listitem>
+
+<listitem id="method.ol.ask"><para>Ask the people that maintain the
+packages listed in step <xref linkend="method.ol.write"> to provide a
+list of essential variables that the data file should
+contain.</para></listitem>
+
+<listitem id="method.ol.send"><para>Send the document and the diagram
+to the NIAC who will nominate someone to construct a XML
+definition.</para></listitem>
+
+<listitem id="method.ol.niac"><para>The NIAC will construct the XML
+definition.</para></listitem>
+
+<listitem id="method.ol.write-file"><para>Write a sample NeXus file
+conforming to the instrument definition (for example, using
+NXtranslate).</para></listitem>
+
+<listitem id="method.ol.test"><para>Test the file, repeating steps
+<xref linkend="method.ol.niac"> and <xref
+linkend="method.ol.write-file"> as appropriate.</para></listitem>
+
+<listitem id="method.ol.ratify"><para>Request ratification once the
+testing phase is complete.</para></listitem>
+
+</orderedlist>
+</para>
+
+</chapter>
diff --git a/doc/tech_ref/monoref.docbook b/doc/tech_ref/monoref.docbook
new file mode 100644
index 0000000..24dc0e4
--- /dev/null
+++ b/doc/tech_ref/monoref.docbook
@@ -0,0 +1,530 @@
+<sect1><title>Monochromatic Reflectometry</title>
+
+<!--
+<mediaobject>
+<imageobject><imagedata fileref="tofnpd.gif" format="gif"></imageobject>
+<imageobject><imagedata fileref="tofnpd.jpg" format="jpg"></imageobject>
+<caption> <para>Schematic diagram of the generic time of flight
+neutron powder diffractometer.  </para> </caption>
+</mediaobject>
+
+<para>The time of flight powder diffractometer (TOFNPD) is an
+instrument used with a couple of different types of analysis. For that
+reason the composite TOFNPD definition is made up of three separate
+definitions.</para>
+
+<sect2><title>TOFNPD:Time Focus</title>
+
+<para>To time focus data there is little information required. The parameters needed in the file are
+
+<orderedlist>
+
+<listitem><para>unique detector pixel identifier</para></listitem>
+
+<listitem><para>primary flight path</para></listitem>
+
+<listitem><para>detector pixel position</para></listitem>
+
+<listitem><para>detector pixel solid angle covered</para></listitem>
+
+</orderedlist>
+
+In addition, the software needs to have some additional information
+that is specified by the user.
+
+<orderedlist>
+
+<listitem><para>mapping of detector pixel identifiers to focused
+detector pixel identifier</para></listitem>
+
+<listitem><para>focused detector position</para></listitem>
+
+<listitem><para>unique focused detector identifier</para></listitem>
+
+</orderedlist>
+
+</para>
+-->
+
+<example id="monoref.xml"><title><filename>monoref.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+Instrument Definition for Monochromatic Source Reflectometers.
+
+Editor: Paul Kienzle <pkienzle at nist.gov>
+Mangled_by: Nick Maliszewskyj <nickm at nist.gov>
+$Id$
+
+See http://www.neutron.anl.gov:8080/NeXus/5 for component definitions.-->
+<NXentry>
+  <definition URL="http://www.nexus.anl.gov/instruments/xml/monoref.xml" 
+      version="1.0">
+    MONOREF
+  </definition>
+  <start_time type="ISO8601">
+  </start_time>
+  <tag polarization="++|+-|-+|--|+|-?" magnetic_field="NX_FLOAT?" 
+      userfield="..." scan="slit|background+|background-|specular|rock|...">
+    {Empty.}
+    <!--
+    *** HDF may not allow empty blocks, so maybe a single integer
+    *** to distinguish the various conditions.
+    -->
+  </tag>
+  <NXsample>
+    <rotation_angle units="degrees" type="NX_FLOAT[i]">
+    </rotation_angle>
+  </NXsample>
+  <!--
+  *** link to spectrum measurement for intensity vs. wavelength
+  *** for a given slit setting 
+
+  *** warning: beam profile is not regular, but this effect is
+  *** accomodated in the spectrum measurement
+  -->
+  <NXinstrument>
+    <!-- wavelength selection -->
+    <NXcrystal name="monochromator">
+      <wavelength units="Angstroms" type="NX_FLOAT">
+        { Wavelength of beam exiting component - take this as wavelength of 
+        beam incident on samples }
+      </wavelength>
+      <wavelength_spread type="NX_FLOAT">
+        {% deviation FWHM /Wavelength - need this to compute resolution}
+      </wavelength_spread>
+    </NXcrystal>
+    <!-- collimation -->
+    <NXaperture name="pre[sample|detector]_slit[|y]#">
+      <opening units="mm" filter="Qx|Qy" type="NX_FLOAT">
+        <!-- *** This is not part of standard NXaperture -->
+        { Slit opening; this is a scan parameter, so cannot be recorded as part 
+        of the aperture size. }
+      </opening>
+      <NXgeometry name="geometry">
+        <NXtranslation name="translation">
+          <distances units="mm" type="NX_FLOAT">
+            { Location of slit along beamline (midway between slits if slits 
+            are not coplanar). This is required to compute instrument 
+            resolution. }
+          </distances>
+          <angles>
+            { Only need angles if slits are not centered on beam wrt sample. }?
+          </angles>
+        </NXtranslation>
+        <NXshape name="shape">
+          <type type="NX_CHAR">
+            nxslit
+          </type>
+          <size units="mm" type="NX_FLOAT[2]">
+            { size[1] is thickness of material (actual slits can be more 
+            complicated in practice, being composed of different materials that 
+            are not aligned, but these can be simulated with sets of slits). 
+            size[2] is zero if slits are coplanar, otherwise it is the distance 
+            between slits. each half of the slit is considered to be a 
+            semi-infinite plane cutting neutrons in Qx if they are in the 
+            scattering plane, or Qy if they are normal to the scattering plane 
+            as defined by
+            <opening filter="...">
+            </opening>
+            above. }
+          </size>
+        </NXshape>
+      </NXgeometry>
+    </NXaperture>
+    <!--
+    The polarizer-flipper-guidefield combination selects polarization vectors 
+    in and out of the sample. A number of scans are required to tune the 
+    instrument so that polarization is either 'up' or 'down' on the sample. On 
+    correctly tuned instruments the polarization angle selected should be 
+    recorded by the flipper using polar_angle relative to the surface (0/180 
+    for +/-, or with out of plane polarization, 90/270 for +/-). The 
+    polarization efficiency must be determined from a spectrum scan and the 
+    appropriate correction applied to the data. Raw values from the instrument, 
+    such as time dependent field applied to flipper coils or current on the 
+    current sheet can be recorded for specialized reduction programs which know 
+    how to handle them.
+    -->
+    <NXpolarizer name="presample_polarizer">
+    </NXpolarizer>
+    <NXflipper name="presample_flipper">
+      <polar_angle units="degree" type="NX_FLOAT">
+      </polar_angle>
+    </NXflipper>
+    <NXpolarizer name="predetector_polarizer">
+    </NXpolarizer>
+    <NXflipper name="predetector_flipper">
+      <polar_angle units="degree" type="NX_FLOAT">
+      </polar_angle>
+    </NXflipper>
+    <!-- detector may be protected by an attenuator and/or a beam stop -->
+    <NXattenuator>
+      <attenuator_transmission type="NX_FLOAT">
+        { The nominal amount of the beam that gets through (transmitted 
+        intensity)/(incident intensity) }
+      </attenuator_transmission>
+    </NXattenuator>
+    <NXbeam_stop name="stop">
+      ? { Need all fields so that we can calculate shadow of beam stop on 
+      detector. }
+    </NXbeam_stop>
+    <NXdetector name="detector">
+      <!-- 
+      polar_angle and azimuthal_angle define the location of the detector 
+      relative to the beamzero
+      -->
+      <distance units="mm" type="NX_FLOAT">
+        { distance from sample }
+      </distance>
+      <translation units="centimeter" type="NX_FLOAT[2]">
+        { translation normal to direct beam }?
+      </translation>
+      <polar_angle units="degrees" type="NX_FLOAT[i]">
+        { angular position of detector relative to beamzero through sample -- 
+        known to practitioners as "A4" or "two theta" }
+      </polar_angle>
+      <azimuthal_angle units="degrees" type="NX_FLOAT">
+        { Indicate sense of scattering: 0 is front surface of sample, 180 is 
+        back surface of sample. If 180, change the sign of the reflected angle 
+        in the data. It is also possible for the beam to enter the substrate 
+        from the side and reflect off the back surface of a film, in which case 
+        negative angles can be interpreted as inverting the scattering length 
+        density profile of the film (after accounting for absorption in the 
+        substrate. }
+      </azimuthal_angle>
+      <x_offset units="mm" type="NX_FLOAT[j]">
+        {pixel edges in x}?
+      </x_offset>
+      <y_offset units="mm" type="NX_FLOAT[k]">
+        {pixel edges in x}?
+      </y_offset>
+      <counts signal="1" axes="x_offset?,y_offset?,polar_angle" 
+          type="NX_INT[k,? j,? i]">
+        { raw detector counts }
+      </counts>
+      <!--
+      *** Raw counts are meaningless to the user if they are counting
+      *** against detector since all values will be the same. The data
+      *** only become meaningful when divided by counting time or monitor
+      *** as specified by the ratio field. The generic plotting program
+      *** will need to sort this out.
+
+      *** In general, n-D data should contain k-D summary statistics
+      *** for all 0<=k<n. That way a really dumb plotting program can
+      *** still display info from a 3-D result as a line.
+
+      *** Some control systems have data windows. Windows may be
+      *** defined in terms of pixel ranges or in terms of
+      *** theta_in-theta_out relationships (i.e., Qx). Each scan
+      *** point should have start/end positions and summary
+      *** statistics for every window defined. Window size may be
+      *** dynamic. Store windows in separate data blocks.
+      -->
+    </NXdetector>
+  </NXinstrument>
+  <NXmonitor name="monitor">
+    <mode type="NX_CHAR">
+      monitor
+    </mode>
+    <preset type="NX_FLOAT">
+      { preset value for monitor }?
+    </preset>
+    <data units="counts" type="NX_INT[i]">
+      { record of monitor counts }?
+    </data>
+    <efficiency type="Nxdata">
+      { Monitor efficiency as a function of wavelength }?
+    </efficiency>
+    <sampled_fraction units="dimensionless" type="NX_FLOAT">
+      { Proportion of incident beam sampled by the monitor }
+    </sampled_fraction>
+  </NXmonitor>
+  <NXmonitor name="timer">
+    <mode type="NX_CHAR">
+      timer
+    </mode>
+    <preset type="NX_FLOAT">
+      { preset value for timer }?
+    </preset>
+    <data units="seconds" type="NX_INT[i]">
+      { record of times for individual points }?
+    </data>
+  </NXmonitor>
+  <NXdata>
+    <attenuator_transmission NAPIlink="NXentry/NXinstrument/NXattenuator">
+    </attenuator_transmission>
+    <theta NAPIlink="NXentry/NXsample/rotation_angle">
+    </theta>
+    <twotheta NAPIlink="NXentry/detector/polar_angle">
+    </twotheta>
+    <presample_slit1 NAPIlink="NXentry/presample_slit1/opening">
+    </presample_slit1>
+    <presample_slit2 NAPIlink="NXentry/presample_slit2/opening">
+    </presample_slit2>
+    <predetector_slit1 NAPIlink="NXentry/predetector_slit1/opening">
+    </predetector_slit1>
+    <predetector_slit2 NAPIlink="NXentry/predetector_slit2/opening">
+    </predetector_slit2>
+    <counts NAPIlink="NXentry/detector/counts">
+    </counts>
+    <count_start units="second" type="NX_FLOAT[i]">
+      <!-- probably shouldn't store any real data here, but where else? -->
+      { start time of each measurement point relative to start time of entry. }
+    </count_start>
+    <timer NAPIlink="NXentry/timer/data">
+    </timer>
+    <monitor NAPIlink="NXentry/monitor/data">
+    </monitor>
+  </NXdata>
+  <NXlog name="??">
+    { Various logs for temperature, field, etc. which are assumed to be 
+    constant over the duration of the run. The reduction program should be able 
+    to display their values on a parallel graph. Note that logs are not 
+    necessarily sampled synchronously with the data points. }*
+  </NXlog>
+</NXentry>
+<!--
+Reflectometry requires several different data scans.  After reduction
+it will all be reduced to normalized reflected intensity as a function
+of Q but how it gets there depends on the nature of the instrument and
+how the data are taken.
+
+A reflectometry data point is parameterized by theta_in (the angle of
+incidence relative to the sample surface) and theta_out (the angle of
+the detector relative to the beam).  The reflectivity is is a count of the
+neutrons reflected in the specular condition (theta_out = theta_in)
+minus the background measured in an off-specular condition and
+divided by the number of neutrons incident on the sample.
+
+You also need to know the wavelength of the source in order to convert 
+from real space to reciprocal space and to calculate absorption in models
+of the reflected signal.
+
+The common scan types are alignment scans, intensity scans,
+specular scans, and +/- offset background scans. With polarized beam
+these scan types are repeated for each polarization cross-section.
+
+Even though scans may be interleaved and the points may not be taken
+in order, each logical scan will be stored in a separate entry in the
+file with 
+
+Alignment scans
+===============
+
+The sample goniometer has six degrees of freedom: rotation about x,y,z
+and translation along x,y and z.  Alignment consists of centering the
+sample in the beam and adjusting the x,y,z angles until the reflected
+signal is maximized.  At this point theta_in is defined to be theta_out.
+
+The incident angle theta_in is undefined until the sample is aligned. 
+Once the sample is aligned, all subsequent theta_in values are 
+measured relative to those values on the goniometer.
+
+Data in the NeXus file should record theta_in relative to the aligned
+sample rather than recording raw goniometer positions.  Alignment scans
+can record raw goniometer rotations.  
+
+Slit scans
+==========
+
+As the sample is rotated the portion of the beam that it intercepts
+changes, with shallower angles having fewer neutrons per unit time.
+A reflectometer will have slits that can be adjusted to eliminate
+any beam that does not fall on the sample.  This reduces background
+which is important when measuring small signals, and provides a means
+for counting the neutrons hitting the sample: Simply remove the sample
+from the beam and count the neutrons that come through the slits.
+
+Some instruments have a monitor between the slits and the sample, with
+a fixed ratio between detector counts and monitor counts.  For those
+instruments a single point slit scan is adequate for determining the
+detector to monitor ratio.
+
+With small samples and at low angles, the slits are usually fixed, and
+the beam spills over the edges of the sample.  In this case a
+footprint correction is required to correct for the changing ratio
+of neutrons on the sample to neutrons missing the sample.
+
+*** Link to or include the intensity scan within every file that needs it?
+
+
+Point detectors
+===============
+
+Each theta_in-theta_out pair has a single data value associated with
+it.  If theta_in is equal to theta_out, then it is a specular
+scan.  If it is a little bit off, it is a background scan (either
+plus or minus).  There are various reasons for offsetting theta_in
+vs. theta_out.  If the detector is fixed and the sample is rocked,
+then it is a rocking curve, from which you might recover the structure
+of the beam, or study off specular details of the reflection. It would
+even be possible to do a complete Qx-Qz scan if the beam rates are
+high enough, such as from an X-ray machine.
+
+There are a variety of ways to perform background scans depending
+on the source of the background.  The most common ways are to offset
+from theta_in and offset from theta_out.  This is a property of the
+experiment rather than the particular instrument configuration, and
+so it is the responsibility of the control program to record the
+correct type.  The reduction program should have the flexibility to
+interpret data in either way.
+
+Linear detectors
+================
+
+A linear detector simultaneously samples multiple theta_out values
+for a given theta_in-theta_out setting of the instrument. The data
+will therefore be two dimensional, with (theta_in,theta_out) on the
+primary axis, and theta distances (dtheta) on the second axis.
+
+The detector entry in the instrument definition should indicate the
+location of the edges of each pixel on the detector and the detector
+position.  Using this information the NeXus file writer can easily
+translate this to dtheta values for the detector ( for a detector 
+at distance D from the sample, dtheta=atan(d/D)*180/pi ).
+
+Specular reflection need not be centered on the linear detector.  As
+a result of the alignment process, the appropriate pixel to theta 
+mapping must be stored in the NXdetector entry and copied to/linked
+from the dtheta vector in the data block.  This will also require
+details of the electronics controlling e.g., bin widths.
+
+Area detectors
+==============
+
+Area detectors are like linear detectors except that they can also
+measure angle zeta normal to the scattering plane.  This yields 
+3-D data, with (theta_in,theta_out) on the primary axis, dtheta on 
+the second axis, and zeta on the third axis.  Normally the zeta data 
+is vertically integrated, possibly by the DAQ software.  The reduction
+software may need to compensate for rotations of the detector as
+measured from a narrow beam scan.
+
+Polarized neutrons
+==================
+
+Some instruments have neutron spin polarizers.  This is not a separate
+data dimension, however, since each polarization cross section is a
+separate measurement with different flipper states.  Instead each
+point is characterized by the triple (theta_in,theta_out,polarization)
+where polarization is ++, +-, -+, - -.  If only one polarizer is present 
+the polarization would be + or - depending on which is present (look
+for flipper_in or flipper_out in the data block).
+
++ for the incident neutron is that state which comes from the polarizer
+in the absence of a front flipper.  + for the reflected neutron is the
+state detected in the absence of a rear flipper.
+
+Polarization itself can, depending on instrument, be in an arbitrary
+direction relative to the sample.  This direction is defined relative
+to the absolute coordinate system given by NXgeometry.  NXpolarizer
+class needs to be extended with this field.
+
+It may be possible to scan polarization angle, but the current 
+definition doesn't support this.
+
+Attenuators
+===========
+
+Some instruments may have well calibrated attenuators under instrument
+control.  Others will have poorly calibrated attenuators, and
+attenuators not under instrument control.  Values taken with different
+attenuators need to be sorted into different scans so that the
+reduction program can set the attenuation independent of the nominal
+value.
+
+Scans
+=====
+
+Reflectometers are scan based instrument.  Rather than measuring a set
+of detectors for a time in an entry, they measure one point, move to
+another configuration, measure, and so on.  The configuration space
+need not be measured on a mesh. For example, the specular scan may be
+sampled more densely than the background scans.  Because of this we
+can't use a dense array to represent our data.
+
+With good control software, the sequence of measurements need not
+correspond to logical scans being constructed.  For example, it is
+very sensible to measure all four polarization cross sections at
+several different fields for a particular geometry before moving to
+the next geometry.  It is also sensible to measure specular and +/-
+background interleaved rather than measuring them in different scans.
+
+With adaptive scanning the control software may decide to fill in
+parts of the scan where the values are changing most rapidly meaning
+that the sequence of measurements is not increasing along the primary
+axis.  Data should probably be recorded in the order it is taken 
+otherwise we are constrained to only ever write NeXus files after the 
+fact rather than point by point as the data arrives.  Reduction and 
+viewing software should sort the data before plotting.
+
+The NeXus format could be organized by the physical scan.  That is, an
+NXdata element is just a set of tuples representing the machine
+configuration for those tuples and the counts at those configurations.
+However, an automatic NeXus file plotter would not be able to make
+sense of the data and automatically plot something reasonable.
+
+Instead we chose to organize by the logical scan.  An NXdata element is
+still a set of tuples representing the machine configuration and
+counts, but tuples from different scans are stored in a separate NXdata
+blocks within an NXentry.
+
+One consequence of this organization is that each NXdata block needs
+its own NXmonitor for the source monitor and NXlog to record the
+start time and duration of the measurement at each point relative to
+the NXentry.
+
+Regardless of the file layout, each separate scan must be tagged so
+the user can organize their data.  The tag is a set of field, value
+pairs which together make up the condition.  When viewing their data,
+the user should be able to organize it by various fields.  For
+example, by scan type, by polarization cross section, or by magnetic
+field if the data was taken under different field conditions.  This is
+done with a condition block within NXdata.  E.g.,
+
+    <tag
+     scan="align|slit|back+|back-|specular|rock|..."
+     polarization="++|+-|-+|- -|+|-?"
+     magnetic_field="NX_FLOAT32?"
+     ...
+    ></tag>
+
+An individual NXentry does not exist in isolation, but is instead part of
+a larger dataset.  This may include more conditions such as solvent
+concentration or temperature which is not varied within the course of
+a run.  Users must be free to add field,value pairs to the condition
+as they see fit since many of the variables important to them when
+organizing their data are set when they are building the sample and are
+not part of the instrument configuration.  This is true not only for 
+reflectivity, so this should be a generic mechanism which is part of 
+the NXdata class, and can be used by all viewing and reduction software 
+as part of the data selection mechanism.
+
+Each data element has a primary axis for the data and covers a range
+of values along that axis.  For scan instruments the primary axis
+is the axis being scanned.  As a convenience to the data selection
+software, the range of values along the primary axis should be
+available as an attribute of the NXdata element rather than having
+to first determine the primary axis then query it for the data range.
+
+Motors
+======
+
+Record raw motor values as well.  These will be instrument
+specific.  Where standard dimensions do not correspond to
+raw motors, the standard dimension will have a 
+derivation="expression"  attribute with expression defined 
+in terms of the field names of the raw motors.  dtheta should also
+have an expression based on pixel number, the bin widths stored
+in entry/instrument/detector, and the total distance to the
+detector.  Store the zero of the raw motor as well as the
+motor value.
+
+-->]]>
+</programlisting>
+</example>
+
+
+<!--
+</sect2>
+-->
+</sect1>
diff --git a/doc/tech_ref/monotas.docbook b/doc/tech_ref/monotas.docbook
new file mode 100644
index 0000000..7ca0ce6
--- /dev/null
+++ b/doc/tech_ref/monotas.docbook
@@ -0,0 +1,240 @@
+<sect1><title>Monochromatic Triple Axis Spectrometer</title>
+
+<!--
+<mediaobject>
+<imageobject><imagedata fileref="tofnpd.gif" format="gif"></imageobject>
+<imageobject><imagedata fileref="tofnpd.jpg" format="jpg"></imageobject>
+<caption> <para>Schematic diagram of the generic time of flight
+neutron powder diffractometer.  </para> </caption>
+</mediaobject>
+
+<para>The time of flight powder diffractometer (TOFNPD) is an
+instrument used with a couple of different types of analysis. For that
+reason the composite TOFNPD definition is made up of three separate
+definitions.</para>
+
+<sect2><title>TOFNPD:Time Focus</title>
+
+<para>To time focus data there is little information required. The parameters needed in the file are
+
+<orderedlist>
+
+<listitem><para>unique detector pixel identifier</para></listitem>
+
+<listitem><para>primary flight path</para></listitem>
+
+<listitem><para>detector pixel position</para></listitem>
+
+<listitem><para>detector pixel solid angle covered</para></listitem>
+
+</orderedlist>
+
+In addition, the software needs to have some additional information
+that is specified by the user.
+
+<orderedlist>
+
+<listitem><para>mapping of detector pixel identifiers to focused
+detector pixel identifier</para></listitem>
+
+<listitem><para>focused detector position</para></listitem>
+
+<listitem><para>unique focused detector identifier</para></listitem>
+
+</orderedlist>
+
+</para>
+-->
+
+<example id="NXmonotas.xml"><title><filename>NXmonotas.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.nexus.anl.gov/classes/xml/NXmonotas.xml
+Editor:  NIAC
+NIAC Version: 0.1
+$Id$
+
+Template of a generic NeXus file containing neutron or x-ray triple-axis data.-->
+<NXentry name="{Name of entry}">
+  <title>
+    {Extended title for entry}
+  </title>
+  <definition URL="http://www.nexus.anl.gov/instruments/xml/NXmonotas.xml" 
+      version="1.0">
+    NXmonotas
+  </definition>
+  <start_time type="ISO8601">
+    {Starting time of measurement}
+  </start_time>
+  <NXsample name="sample">
+    <name type="NX_CHAR">
+      {Descriptive name of sample}?
+    </name>
+    <unit_cell type="NX_FLOAT32[1,6])">
+      {Unit cell parameters (lengths and angles)}?
+    </unit_cell>
+    <plane_vector_0 type="NX_FLOAT32[3]">
+      {Reciprocal space vector of primary reflection in the scattering plane}
+    </plane_vector_0>
+    <plane_vector_1 type="NX_FLOAT32[3]">
+      {Reciprocal space vector of secondary reflection in the scattering plane}
+    </plane_vector_1>
+    <polar_angle units="degree" type="NX_FLOAT32[:]">
+      {Polar angle of the sample with respect to the beam incident on the 
+      monochromator}
+    </polar_angle>
+    <azimuthal_angle units="degree" type="NX_FLOAT32">
+      {Azimuthal angle of the sample with respect to the beam incident on the 
+      monochromator}
+    </azimuthal_angle>
+    <rotation_angle units="degree" type="NX_FLOAT32[:]">
+      {Rotation angle of the sample}
+    </rotation_angle>
+    <Qh type="NX_FLOAT32[:]">
+      {Reciprocal space component of scan}
+    </Qh>
+    <Qk type="NX_FLOAT32[:]">
+      {Reciprocal space component of scan}
+    </Qk>
+    <Ql type="NX_FLOAT32[:]">
+      {Reciprocal space component of scan}
+    </Ql>
+    <energy_transfer units="meV" type="NX_FLOAT32[:]">
+      {Energy transfer of scan}
+    </energy_transfer>
+  </NXsample>
+  <NXinstrument name="{Name of instrument}">
+    <NXcollimator name="premonochromator_collimator">
+      <type type="NX_CHAR">
+        "Soller"|"radial"
+      </type>
+      <soller_angle units="minute" type="NX_FLOAT32">
+        {Angular divergence of Soller collimator}
+      </soller_angle>
+    </NXcollimator>
+    <NXfilter name="premonochromator_filter">
+      <description type="NX_CHAR">
+        {"Beryllium" | "Pyrolytic Graphite" | "Graphite"}
+      </description>
+    </NXfilter>
+    <NXcrystal name="monochromator">
+      <type type="NX_CHAR">
+        {"PG (Highly Oriented Pyrolytic Graphite)" | "Ge" | "Si" | "Cu" | 
+        "Fe3Si" | "CoFe" | "Cu2MnAl (Heusler)" | "Multilayer"}
+      </type>
+      <energy units="meV" type="NX_FLOAT32[:]">
+        {Optimum diffracted energy}
+      </energy>
+      <d_spacing units="Angstrom" type="NX_FLOAT32">
+        {The planar spacing of the nominal reflection}
+      </d_spacing>
+      <rotation_angle units="degree" type="NX_FLOAT32[:]">
+        {Rotation angle of the monochromator}
+      </rotation_angle>
+    </NXcrystal>
+    <NXcollimator name="presample_collimator">
+      <type type="NX_CHAR">
+        "Soller"|"radial"
+      </type>
+      <soller_angle units="minute" type="NX_FLOAT32">
+        {Angular divergence of Soller collimator}
+      </soller_angle>
+    </NXcollimator>
+    <NXfilter name="presample_filter">
+      <description type="NX_CHAR">
+        {"Beryllium" | "Pyrolytic Graphite" | "Graphite"}
+      </description>
+    </NXfilter>
+    <NXcollimator name="preanalyzer_collimator">
+      <type type="NX_CHAR">
+        "Soller"|"radial"
+      </type>
+      <soller_angle units="minute" type="NX_FLOAT32">
+        {Angular divergence of Soller collimator}
+      </soller_angle>
+    </NXcollimator>
+    <NXfilter name="preanalyzer_filter">
+      <description type="NX_CHAR">
+        {"Beryllium" | "Pyrolytic Graphite" | "Graphite"}
+      </description>
+    </NXfilter>
+    <NXcrystal name="analyzer">
+      <type type="NX_CHAR">
+        {"PG (Highly Oriented Pyrolytic Graphite)" | "Ge" | "Si" | "Cu" | 
+        "Fe3Si" | "CoFe" | "Cu2MnAl (Heusler)" | "Multilayer"}
+      </type>
+      <energy units="meV" type="NX_FLOAT32[:]">
+        {Optimum diffracted energy}
+      </energy>
+      <d_spacing units="Angstrom" type="NX_FLOAT32">
+        {The planar spacing of the nominal reflection}
+      </d_spacing>
+      <polar_angle units="degree" type="NX_FLOAT32[:]">
+        {Polar angle of the analyzer with respect to the beam incident on the 
+        monochromator}
+      </polar_angle>
+      <azimuthal_angle units="degree" type="NX_FLOAT32">
+        {Azimuthal angle of the analyzer with respect to the beam incident on 
+        the monochromator}
+      </azimuthal_angle>
+      <rotation_angle units="degree" type="NX_FLOAT32[:]">
+        {Rotation angle of the monochromator}
+      </rotation_angle>
+    </NXcrystal>
+    <NXcollimator name="predetector_collimator">
+      <type type="NX_CHAR">
+        "Soller"|"radial"
+      </type>
+      <soller_angle units="minute" type="NX_FLOAT32">
+        {Angular divergence of Soller collimator}
+      </soller_angle>
+    </NXcollimator>
+    <NXdetector name="detector">
+      <counts signal="1" axes="energy_transfer|Qh|Qk|Ql" type="NX_INT32[:]">
+        {Integer counts}
+      </counts>
+      <polar_angle units="degree" type="NX_FLOAT32[:]">
+        {Polar angle of the detector with respect to the beam incident on the 
+        monochromator}
+      </polar_angle>
+      <azimuthal_angle units="degree" type="NX_FLOAT32">
+        {Azimuthal angle of the detector with respect to the beam incident on 
+        the analyzer}
+      </azimuthal_angle>
+    </NXdetector>
+  </NXinstrument>
+  <NXmonitor name="monitor">
+    <mode type="NX_CHAR">
+      "monitor"|"timer"
+    </mode>
+    <preset type="NX_FLOAT32[1]">
+      {preset value for time or monitor}
+    </preset>
+    <data type="NX_INT[:]">
+      {Monitor data}?
+    </data>
+  </NXmonitor>
+  <NXdata name="data">
+    <Qh NAPIlink="NXentry/NXsample/Qh">
+    </Qh>
+    <Qk NAPIlink="NXentry/NXsample/Qk">
+    </Qk>
+    <Ql NAPIlink="NXentry/NXsample/Ql">
+    </Ql>
+    <energy_transfer NAPIlink="NXentry/NXsample/energy_transfer">
+    </energy_transfer>
+    <counts NAPIlink="NXentry/NXinstrument/detector/counts">
+    </counts>
+    <energy NAPIlink="NXentry/NXinstrument/analyzer/energy">
+    </energy>
+  </NXdata>
+</NXentry>
+]]>
+</programlisting>
+</example>
+
+
+<!--
+</sect2>
+-->
+</sect1>
diff --git a/doc/tech_ref/terminology.docbook b/doc/tech_ref/terminology.docbook
new file mode 100644
index 0000000..9ad4d1e
--- /dev/null
+++ b/doc/tech_ref/terminology.docbook
@@ -0,0 +1,92 @@
+<chapter id="terms"><title>Terminology</title>
+
+<sect1><title>The NeXus XML Meta-DTD Format</title>
+
+<para>The contents of NeXus files are defined using XML. The hierarchical structure of NeXus files maps very conveniently into XML files with NeXus groups and items as the XML entities, and data attributes as XML attributes. NeXus utilities are being developed to help people determine whether their files are standard-conforming. However, formal XML format definitions (DTDs) are difficult for the non-expert to read, so we have produced a much simpler meta-DTD format, which produces well-f [...]
+Meta-DTD Definition</para>
+
+<orderedlist>
+
+<listitem><para>
+Each meta-DTD file should begin with a standard XML document tag, i.e. 
+<programlisting><![CDATA[<?xml version="1.0" ?>]]></programlisting>
+</para></listitem>
+
+<listitem><para> This should be followed by a comment block giving the
+URL of the XML file, the name of the editor, the keyword $Id$, which
+will generate a revision number when the file is committed to the
+NeXus CVS server, and a brief description of the file, e.g.
+
+<programlisting><![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXgroup.xml
+Editor:  Jean Dupont <JDupont at some.where>
+$Id$
+Definition of a fake but well-formed NeXus group.
+-->]]></programlisting></para></listitem>
+
+<listitem><para> Each NeXus group is an XML entity defined by its
+class, e.g. NXuser, NXdata, ....</para></listitem>
+
+<listitem><para>The name of the group is given by the name attribute
+of the entity. N.B. XML attributes are the name="value" pairs located
+within the opening tag of the XML entity,
+e.g. <programlisting><![CDATA[<NXsample name="sample">]]></programlisting>.
+</para></listitem>
+
+
+<listitem><para>All other data items are XML entities defined by their name,
+e.g. <programlisting><![CDATA[<temperature>]]></programlisting></para></listitem>
+
+<listitem><para>Data attributes are stored as XML attributes. The data
+type is defined as an XML attribute although it is not defined as an
+HDF attribute in the NeXus file itself, e.g.
+<programlisting><![CDATA[<temperature type="NX_FLOAT32" units="K">]]>
+</programlisting></para></listitem>
+
+<listitem><para> If the value of an attribute is not defined by the
+DTD, a short description is enclosed within quotes and curly braces,
+e.g.
+<programlisting><![CDATA[<NXdetector name="{Name of detector bank}">]]>
+</programlisting></para></listitem>
+
+<listitem><para> Similarly, the value of a data item which is not
+defined by the DTD should be placed within curly braces between the
+opening and closing tag, e.g.
+<programlisting><![CDATA[<temperature>{Temperature of sample}</temperature>]]>
+</programlisting></para></listitem>
+
+<listitem><para>Following the opening tag of a group entity and before
+the closing tag of a data entity, there may be one of three symbols,
+which have the same meanings that they have in regular expressions.
+<programlisting><![CDATA[*   May occur 0 or more times
++   May occur one or more times (i.e. at least once)
+?   May occur 0 or one times (i.e. no more than once)]]>
+</programlisting>
+e.g. 
+<programlisting><![CDATA[<NXsample>?
+   <temperature>{Temperature of sample}?</temperature> 
+</NXsample>]]></programlisting>
+If no symbol is given, the item is mandatory. </para></listitem>
+
+<listitem><para>If a data item is an array, add the array dimensions
+in square brackets to the type attribute. Use a colon if the dimension
+length is not defined by the DTD, e.g.
+<programlisting><![CDATA[<polar_angle type="NX_FLOAT32[:]">]]></programlisting>
+Replace the colon with i, j, ... if you wish to match the dimension
+length to other data items within the same group.</para></listitem>
+
+<listitem><para> If no data type is specified, it is assumed to be a
+character string (NX_CHAR).  </para></listitem>
+
+<listitem><para> The "version" attribute of the "analysis" entity,
+defined in each NXentry group should be set to $Revision$ when the
+file is first written so that the CVS revision number is substituted
+when the XML file is committed to the CVS server, e.g.
+<programlisting><![CDATA[<analysis version="$Revision$">]]></programlisting>
+</para></listitem>
+
+</orderedlist>
+
+</sect1>
+
+</chapter>
diff --git a/doc/tech_ref/tofdgs.docbook b/doc/tech_ref/tofdgs.docbook
new file mode 100644
index 0000000..e9d14d0
--- /dev/null
+++ b/doc/tech_ref/tofdgs.docbook
@@ -0,0 +1,239 @@
+<sect1><title>Time of Flight Neutron Direct Geometry Spectrometer</title>
+
+<!--
+<mediaobject>
+<imageobject><imagedata fileref="tofnpd.gif" format="gif"></imageobject>
+<imageobject><imagedata fileref="tofnpd.jpg" format="jpg"></imageobject>
+<caption> <para>Schematic diagram of the generic time of flight
+neutron powder diffractometer.  </para> </caption>
+</mediaobject>
+
+<para>The time of flight powder diffractometer (TOFNPD) is an
+instrument used with a couple of different types of analysis. For that
+reason the composite TOFNPD definition is made up of three separate
+definitions.</para>
+
+<sect2><title>TOFNPD:Time Focus</title>
+
+<para>To time focus data there is little information required. The parameters needed in the file are
+
+<orderedlist>
+
+<listitem><para>unique detector pixel identifier</para></listitem>
+
+<listitem><para>primary flight path</para></listitem>
+
+<listitem><para>detector pixel position</para></listitem>
+
+<listitem><para>detector pixel solid angle covered</para></listitem>
+
+</orderedlist>
+
+In addition, the software needs to have some additional information
+that is specified by the user.
+
+<orderedlist>
+
+<listitem><para>mapping of detector pixel identifiers to focused
+detector pixel identifier</para></listitem>
+
+<listitem><para>focused detector position</para></listitem>
+
+<listitem><para>unique focused detector identifier</para></listitem>
+
+</orderedlist>
+
+</para>
+<sect2><title>TOFNPD:Time Focus</title>
+-->
+
+<example id="NXtofndgs.xml"><title><filename>NXtofndgs.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.nexus.anl.gov/classes/xml/NXtofndgs.xml
+Editor:  NIAC
+NIAC Version: 0.1
+$Id$
+
+Template of a generic NeXus file containing data from a direct geometry 
+time-of-flight spectrometer.
+-->
+<NXentry name="{Name of entry}">
+  <title>
+    {Extended title for entry}
+  </title>
+  <definition URL="http://www.nexus.anl.gov/instruments/xml/NXtofndgs.xml" 
+      version="1.0">
+    NXtofndgs
+  </definition>
+  <start_time type="ISO8601">
+    {Starting time of measurement}
+  </start_time>
+  <NXsample name="sample">
+    <name type="NX_CHAR">
+      {Descriptive name of sample}?
+    </name>
+    <unit_cell type="NX_FLOAT32[1,6])">
+      {Unit cell parameters (lengths and angles)}?
+    </unit_cell>
+    <sample_orientation type="NX_FLOAT[3]">
+      {This will follow the Busing and Levy convention from Acta.Crysta v22, 
+      p457 (1967)}?
+    </sample_orientation>
+    <orientation_matrix type="NX_FLOAT[3,3]">
+      {Orientation matrix of single crystal sample}{The is the orientation 
+      matrix using Busing-Levy convention}?
+    </orientation_matrix>
+    <mass type="NX_FLOAT">
+      {Mass of sample}?
+    </mass>
+    <NXgeometry>
+      <NXshape>
+        {Shape of sample}
+      </NXshape>
+    </NXgeometry>
+  </NXsample>
+  <NXinstrument name="{Name of instrument}">
+    <NXmoderator name="{Name of moderator}">
+      <distance type="NX_FLOAT">
+        {Effective distance as seen by measuring radiation}?
+      </distance>
+    </NXmoderator>
+    <NXchopper name="monochromator">
+      <distance>
+        {Distance of the centre of the chopper to the sample.}
+      </distance>
+      <energy type="NX_FLOAT">
+        {Optimum energy transmitted by the chopper.}
+      </energy>
+      <type type="NX_CHAR">
+        {fermi|disk|counter-rotating|statistical}
+      </type>
+      <rotation_speed type="NX_FLOAT">
+        {Chopper rotation speed}
+      </rotation_speed>
+    </NXchopper>
+    <NXcrystal name="monochromator">
+      <distance>
+        {Distance of the centre of the crystal monochromator to the sample.}
+      </distance>
+      <type type="NX_CHAR">
+        {"PG (Highly Oriented Pyrolytic Graphite)" | "Ge" | "Si" | "Cu" | 
+        "Fe3Si" | "CoFe" | "Cu2MnAl (Heusler)" | "Multilayer"}
+      </type>
+      <energy units="meV" type="NX_FLOAT32[:]">
+        {Optimum diffracted energy}
+      </energy>
+      <d_spacing units="Angstrom" type="NX_FLOAT32">
+        {The planar spacing of the nominal reflection}
+      </d_spacing>
+    </NXcrystal>
+    <NXdetector name="{Name of detector bank}">
+      <data signal="1" axes="x_angle:y_angle:time_of_flight" 
+          type="NX_FLOAT[i,j,k]|NX_INT[i,j,k]">
+        {Data values}?
+      </data>
+      <time_of_flight type="NX_FLOAT[k+1]">
+        {Total time of flight}
+      </time_of_flight>
+      <distance type="NX_FLOAT[i,j]">
+        {distance from the sample
+      </distance>
+      <data_errors type="NX_FLOAT[i,j,...]|NX_INT[i,j,...]">
+        {Data errors}
+      </data_errors>
+      <x_offset type="NX_FLOAT[i]">
+        {offset from the detector center in x-direction}?
+      </x_offset>
+      <y_offset type="NX_FLOAT[j]">
+        {offset from the detector center in the y-direction}?
+      </y_offset>
+      <x_angle type="NX_FLOAT[i]">
+        {angle of detector in x-direction with respect to unscattered beam}?
+      </x_angle>
+      <y_angle type="NX_FLOAT[j]">
+        {angle of detector in y-direction with respect to unscattered beam}?
+      </y_angle>
+      <polar_angle type="NX_FLOAT[i,j]">
+        {polar angle of a detector pixel}
+      </polar_angle>
+      <azimuthal_angle type="NX_FLOAT[i,j]">
+        {azimuthal angle of a detector pixel}
+      </azimuthal_angle>
+      <solid_angle type="NX_FLOAT[i,j]">
+        {Solid angle subtended by the detector pixel at the sample}?
+      </solid_angle>
+      <x_pixelsize type="NX_FLOAT[i,j]">
+        {Size of each detector pixel}?
+      </x_pixelsize>
+      <y_pixelsize type="NX_FLOAT[i,j]">
+        {Size of each detector pixel}?
+      </y_pixelsize>
+      <gas_pressure type="NX_FLOAT[i]">
+        {Detector gas pressure}?
+      </gas_pressure>
+      <type type="NX_CHAR">
+        "He3 gas cylinder"|He3 PSD"|?
+      </type>
+      <NXgeometry name="geometry">
+        {Position and orientation of detectors}?
+      </NXgeometry>
+    </NXdetector>
+  </NXinstrument>
+  <NXmonitor name="whitebeam_monitor">
+    <distance type="NX_FLOAT">
+      {Distance of monitor from sample}
+    </distance>
+    <time_of_flight type="NX_FLOAT[i]">
+      {Time-of-flight}
+    </time_of_flight>
+    <data signal="1" axes="time_of_flight" type="NX_INT[i]">
+      {Monitor data}
+    </data>
+  </NXmonitor>
+  <NXmonitor name="presample_monitor">
+    <distance type="NX_FLOAT">
+      {Distance of monitor from sample}
+    </distance>
+    <time_of_flight type="NX_FLOAT[i]">
+      {Time-of-flight}
+    </time_of_flight>
+    <data signal="1" axes="time_of_flight" type="NX_INT[i]">
+      {Monitor data}
+    </data>
+  </NXmonitor>
+  <NXmonitor name="beamstop_monitor">
+    <distance type="NX_FLOAT">
+      {Distance of monitor from sample}
+    </distance>
+    <time_of_flight type="NX_FLOAT[i]">
+      {Time-of-flight}
+    </time_of_flight>
+    <data signal="1" axes="time_of_flight" type="NX_INT[i]">
+      {Monitor data}
+    </data>
+  </NXmonitor>
+  <NXdata name="{Name of data bank}">
+    <data NAPIlink="NXentry/NXinstrument/NXdetector/data">
+    </data>
+    <x_angle NAPIlink="NXentry/NXinstrument/NXdetector/x_angle">
+    </x_angle>
+    <y_angle NAPIlink="NXentry/NXinstrument/NXdetector/y_angle">
+    </y_angle>
+    <x_offset NAPIlink="NXentry/NXinstrument/NXdetector/x_offset">
+    </x_offset>
+    <y_offset NAPIlink="NXentry/NXinstrument/NXdetector/y_offset">
+    </y_offset>
+    <time_of_flight NAPIlink="NXentry/NXinstrument/NXdetector/time_of_flight">
+    </time_of_flight>
+  </NXdata>
+</NXentry>
+]]>
+</programlisting>
+</example>
+
+
+<!--
+</sect2>
+-->
+</sect1>
diff --git a/doc/tech_ref/tofnpd.docbook b/doc/tech_ref/tofnpd.docbook
new file mode 100644
index 0000000..40d0130
--- /dev/null
+++ b/doc/tech_ref/tofnpd.docbook
@@ -0,0 +1,141 @@
+<sect1><title>Time of Flight Neutron  Powder Diffractometer</title>
+
+<mediaobject>
+<imageobject><imagedata fileref="tofnpd.gif" format="gif"></imageobject>
+<imageobject><imagedata fileref="tofnpd.jpg" format="jpg"></imageobject>
+<caption> <para>Schematic diagram of the generic time of flight
+neutron powder diffractometer.  </para> </caption>
+</mediaobject>
+
+<para>The time of flight powder diffractometer (TOFNPD) is an
+instrument used with a couple of different types of analysis. For that
+reason the composite TOFNPD definition is made up of three separate
+definitions.</para>
+
+<sect2><title>TOFNPD:Time Focus</title>
+
+<para>To time focus data there is little information required. The parameters needed in the file are
+
+<orderedlist>
+
+<listitem><para>unique detector pixel identifier</para></listitem>
+
+<listitem><para>primary flight path</para></listitem>
+
+<listitem><para>detector pixel position</para></listitem>
+
+<listitem><para>detector pixel solid angle covered</para></listitem>
+
+</orderedlist>
+
+In addition, the software needs to have some additional information
+that is specified by the user.
+
+<orderedlist>
+
+<listitem><para>mapping of detector pixel identifiers to focused
+detector pixel identifier</para></listitem>
+
+<listitem><para>focused detector position</para></listitem>
+
+<listitem><para>unique focused detector identifier</para></listitem>
+
+</orderedlist>
+
+</para>
+
+<example id="TOFNPD-time-focus.xml"><title><filename>TOFNPD:time_focus.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXtofnpd.xml
+Editor:  NIAC
+$Id$
+
+Instrument definition for a time-of-flight neutron powder diffractometer that 
+can be time focused.
+-->
+<NXentry name="{Entry Name}">
+  <definition URL="http://www.neutron.anl.gov/nexus/xml/NXtofnpd-timefocus.xml" 
+      version="$Revision$" type="NX_CHAR[]" instrument="TOFNPD">
+    Time Focus
+  </definition>
+  <NXsample name="">
+     <chemical_formula type="NX_CHAR"></chemical_formula>
+  </NXsample>
+  <NXinstrument name="{name of the instrument}">
+    <name long_name="{full name of instrument}?" type="NX_CHAR[]">
+      {Abbreviated name of instrument}
+    </name>
+    <NXmoderator name="">
+      <distance units="metre" type="NX_FLOAT">
+        {distance from the sample (should be negative)}
+      </distance>
+    </NXmoderator>
+    <NXdetector name="{Name of detector bank}">+
+      <time_of_flight link="{absolute path to location in NXdetector}" 
+          units="10^-6 second|10^-7 second" type="NX_FLOAT[i+1]">
+        {Total time of flight}
+      </time_of_flight>
+      <pixel_id link="{absolute path to location in NXdetector}" 
+          type="NX_INT[j]">
+        {Identifier for detector}
+      </pixel_id>
+      <counts signal="1" axes="[time_of_flight,pixel_id]" 
+          link="{absolute path to location in NXdetector}" 
+          units="number" type="NX_FLOAT[i,j]">
+        {Data values}
+      </counts>
+      <distance axes="pixel_id" type="NX_FLOAT[j]">
+      </distance>
+      <polar_angle axes="pixel_id" type="NX_FLOAT[j]">
+      </polar_angle>
+      <azimuthal_angle axes="pixel_id" type="NX_FLOAT[j]">
+      </azimuthal_angle>
+      <solid_angle axes="pixel_id" type="NX_FLOAT[j]"></solid_angle>
+      <TOF_to_d method="linear|quadradic" type="NX_FLOAT[j,k]">
+         {Calibrated conversion factors to be used for time focusing}
+      </TOF_to_d>
+    </NXdetector>
+  </NXinstrument>
+  <NXdata name="">
+      <time_of_flight 
+          NAPIlink="/NXentry/NXinstrument/NXdetector/time_of_flight"/>
+      <pixel_id 
+          NAPIlink="/NXentry/NXinstrument/NXdetector/pixel_id"/>
+      <counts
+          NAPIlink="/NXentry/NXinstrument/NXdetector/data"/>
+  </NXdata>
+</NXentry>]]>
+</programlisting>
+</example>
+
+<example id="TOFNPD-rietveld.xml"><title><filename>TOFNPD:rietveld.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+URL:     http://www.neutron.anl.gov/nexus/xml/NXtofnpd.xml
+Editor:  NIAC
+$Id$
+
+Instrument definition for a time-of-flight neutron powder diffractometer that 
+can be time focused.
+-->
+<NXentry name="{Entry Name}">
+  <conforms_to>
+    <definition URL="" version="">TOFNPD:Time Focus</definition>
+  </conforms_to>
+  <definition URL="http://www.neutron.anl.gov/nexus/xml/NXtofnpd-timefocus.xml" 
+      version="$Revision$" type="NX_CHAR[]" >
+    TOFNPD:Rietveld
+  </definition>
+  <NXcharacterization
+     name="isotropic_scatterer"
+     NXS:location="" instrument="TOFNPD" version="" URL="" 
+     definition="Time Focus">{Should be same scales as this entry}
+  </NXcharacterization>
+</NXentry>]]>
+</programlisting>
+</example>
+
+</sect2>
+
+</sect1>
diff --git a/doc/tech_ref/tofnpd.gif b/doc/tech_ref/tofnpd.gif
new file mode 100644
index 0000000..6c192f4
Binary files /dev/null and b/doc/tech_ref/tofnpd.gif differ
diff --git a/doc/tech_ref/tofnpd.jpg b/doc/tech_ref/tofnpd.jpg
new file mode 100755
index 0000000..5b52e22
Binary files /dev/null and b/doc/tech_ref/tofnpd.jpg differ
diff --git a/doc/tech_ref/tofnref.docbook b/doc/tech_ref/tofnref.docbook
new file mode 100644
index 0000000..d9cba06
--- /dev/null
+++ b/doc/tech_ref/tofnref.docbook
@@ -0,0 +1,356 @@
+<sect1><title>Time of Flight Neutron  Reflectometer</title>
+
+<!--
+<mediaobject>
+<imageobject><imagedata fileref="tofnpd.gif" format="gif"></imageobject>
+<imageobject><imagedata fileref="tofnpd.jpg" format="jpg"></imageobject>
+<caption> <para>Schematic diagram of the generic time of flight
+neutron powder diffractometer.  </para> </caption>
+</mediaobject>
+
+<para>The time of flight powder diffractometer (TOFNPD) is an
+instrument used with a couple of different types of analysis. For that
+reason the composite TOFNPD definition is made up of three separate
+definitions.</para>
+
+<sect2><title>TOFNPD:Time Focus</title>
+
+<para>To time focus data there is little information required. The parameters needed in the file are
+
+<orderedlist>
+
+<listitem><para>unique detector pixel identifier</para></listitem>
+
+<listitem><para>primary flight path</para></listitem>
+
+<listitem><para>detector pixel position</para></listitem>
+
+<listitem><para>detector pixel solid angle covered</para></listitem>
+
+</orderedlist>
+
+In addition, the software needs to have some additional information
+that is specified by the user.
+
+<orderedlist>
+
+<listitem><para>mapping of detector pixel identifiers to focused
+detector pixel identifier</para></listitem>
+
+<listitem><para>focused detector position</para></listitem>
+
+<listitem><para>unique focused detector identifier</para></listitem>
+
+</orderedlist>
+
+</para>
+-->
+
+<example id="tofnref.xml"><title><filename>tofnref.xml</filename></title>
+<programlisting role="XML">
+<![CDATA[<!--
+Instrument Definition for a Time of Flight Neutron Reflectometer
+
+Editor: Robert Dalgliesh <r.m.dalgliesh at rl.ac.uk>
+Initial version: October 2004
+$Id$
+
+See http://www.neutron.anl.gov:8080/NeXus/5 for component definitions.  
+2005-04-28 Paul Kienzle <pkienzle at nist.gov> * Only include information that may 
+be used for reduction/analysis * Make consistent with monoref and monotas
+-->
+<NXentry>
+  <definition URL="http://www.nexus.anl.gov/instruments/xml/tofnref.xml" 
+      version="1.0">
+    TOFNREF
+  </definition>
+  <start_time type="ISO8601">
+  </start_time>
+  <tag polarization="++|+-|-+|--|+|-?" magnetic_field="NX_FLOAT?" 
+      userfield="..." scan="spectrum|background+|background-|specular|rock|...">
+    {Empty.}
+    <!--
+    *** HDF may not allow empty blocks, so maybe a single integer
+    *** to distinguish the various conditions.
+    -->
+  </tag>
+  <NXsample>
+    <rotation_angle units="degrees" type="NX_FLOAT[i]">
+    </rotation_angle>
+  </NXsample>
+  <!--
+  *** link to spectrum measurement for intensity vs. wavelength
+  *** for a given slit setting
+
+  *** warning: beam profile is not regular, but this effect is
+  *** accomodated in the spectrum measurement
+  -->
+  <NXinstrument>
+    <NXmoderator name="{Name of moderator}">
+      <distance units="metre" type="NX_FLOAT">
+        { Distance from T_o to sample along beam-path. To calculate wavelength: 
+        L[i] = wavelength at time T[i] T[i] = time of flight for point i. d1 = 
+        distance from moderator to sample along beam path d2 = distance from 
+        detector to sample along beam path h = Planck's constant m_n = mass of 
+        the neutron L[i] = h/m_n * T[i]/(d1+d2) }
+      </distance>
+      <pulse_shape type="NXdata">
+        { Find the center of mass of the pulse shape and use that as the T0 
+        offset with respect to the protons hitting the target. The TOF from 
+        target (which is the real T0) to the moderator is insignficant compared 
+        to the uncertainty from the pulse shape and so can be ignored. }
+      </pulse_shape>
+    </NXmoderator>
+    <NXguide name="{Name of guide section}">
+      { Guides in total or in segments thgrough to sample position; may be 
+      interspersed between other components - Check component index. Can be 
+      nested for guides with multiple straight segments. Affects wavelength 
+      spectrum, both in divergence and intensity. The spectrum scan will 
+      automatically compensate for intensity effects. To compute divergence 
+      effects, detailed information about the guide geometry will be required. 
+      
+    </NXguide>
+    <!--
+    Some instruments will require gravitational corrections. Neutrons travel on 
+    a parabolic trajectory. For long wavelength neutrons this changes incident 
+    and reflected angle and results in the neutron appearing on a lower 
+    detector pixel than expected. The information required for these 
+    corrections comes from the instrument geometry.
+    -->
+    <NXchopper name="[T0_chopper|frame_overlap_chopper]">
+      <wavelength_range units="Angstrom" type="NX_FLOAT[2]">
+        { Reduction software needs to ignore Q values outside the range defined 
+        by the choppers. The T0 chopper is phased to the source to block fast 
+        neutron and gamma flash. The frame overlap chopper is set to select low 
+        wavelength neutrons (those from the current pulse) or high wavelength 
+        neutrons (those from the previous pulse. On a properly tuned 
+        instrument, the time bins recorded in the detector will reflect the 
+        actions of the choppers and these fields can be ignored. }
+      </wavelength_range>
+    </NXchopper>
+    <NXmirror name="frame_overlap_mirror">
+      <cutoff_wavelength mode="above|below">
+        <!-- *** This is not part of standard NXmirror -->
+        { The frame overlap mirror is used to eliminate very long wavelength 
+        neutrons from previous pulses. Together with the choppers, this helps 
+        to choose which pulse to use in the TOF calculations. On a properly 
+        tuned instrument the time bins recorded in the detector will account 
+        for the actions of the mirror. There will be some attenuation but this 
+        will be compensated for when correcting for the spectrum scan. For an 
+        ab initio calculation, you would need to store the angle wrt the beam 
+        to compute the cutoff angle but often this will not be explicit since 
+        the instrument is simply tuned to have the correct cutoff. } }
+      </cutoff_wavelength>
+    </NXmirror>
+    <!-- collimation -->
+    <NXaperture name="pre[sample|detector]_slit[|y]#">
+      <opening units="mm" filter="Qx|Qy" type="NX_FLOAT">
+        <!-- *** This is not part of standard NXaperture -->
+        { Slit opening; this is a scan parameter, so cannot be recorded as part 
+        of the aperture size. }
+      </opening>
+      <NXgeometry name="geometry">
+        <NXtranslation name="translation">
+          <distances units="mm" type="NX_FLOAT">
+            { Location of slit along beamline (midway between slits if slits 
+            are not coplanar). This is required to compute instrument 
+            resolution. }
+          </distances>
+          <angles>
+            { Only need angles if slits are not centered on beam wrt sample. }?
+          </angles>
+        </NXtranslation>
+        <NXshape name="shape">
+          <type type="NX_CHAR">
+            nxslit
+          </type>
+          <size units="mm" type="NX_FLOAT[2]">
+            { size[1] is thickness of material (actual slits can be more 
+            complicated in practice, being composed of different materials that 
+            are not aligned, but these can be simulated with sets of slits). 
+            size[2] is zero if slits are coplanar, otherwise it is the distance 
+            between slits. each half of the slit is considered to be a 
+            semi-infinite plane cutting neutrons in Qx if they are in the 
+            scattering plane, or Qy if they are normal to the scattering plane 
+            as defined by
+            <opening filter="...">
+            </opening>
+            above. }
+          </size>
+        </NXshape>
+      </NXgeometry>
+    </NXaperture>
+    <!--
+    The polarizer-flipper-guidefield combination selects polarization vectors 
+    in and out of the sample. A number of scans are required to tune the 
+    instrument so that polarization is either 'up' or 'down' on the sample. On 
+    correctly tuned instruments the polarization angle selected should be 
+    recorded by the flipper using polar_angle relative to the surface (0/180 
+    for +/-, or with out of plane polarization, 90/270 for +/-). The 
+    polarization efficiency must be determined from a spectrum scan and the 
+    appropriate correction applied to the data. Raw values from the instrument, 
+    such as time dependent field applied to flipper coils or current on the 
+    current sheet can be recorded for specialized reduction programs which know 
+    how to handle them.
+    -->
+    <NXpolarizer name="presample_polarizer">
+    </NXpolarizer>
+    <NXflipper name="presample_flipper">
+      <polar_angle units="degree" type="NX_FLOAT">
+      </polar_angle>
+    </NXflipper>
+    <NXpolarizer name="predetector_polarizer">
+    </NXpolarizer>
+    <NXflipper name="predetector_flipper">
+      <polar_angle units="degree" type="NX_FLOAT">
+      </polar_angle>
+    </NXflipper>
+    <!-- detector may be protected by an attenuator and/or a beam stop -->
+    <NXattenuator>
+      <attenuator_transmission type="NX_FLOAT">
+        { The nominal amount of the beam that gets through (transmitted 
+        intensity)/(incident intensity) }
+      </attenuator_transmission>
+    </NXattenuator>
+    <NXbeam_stop name="stop">
+      ? { Need all fields so that we can calculate shadow of beam stop on 
+      detector. }
+    </NXbeam_stop>
+    <NXdetector name="detector">
+      <!--
+      polar_angle and azimuthal_angle define the location of the detector 
+      relative to the beamzero
+      -->
+      <distance units="mm" type="NX_FLOAT">
+        { distance from sample }
+      </distance>
+      <translation units="centimeter" type="NX_FLOAT[2]">
+        { translation normal to direct beam }?
+      </translation>
+      <time_of_flight units="10^-6 second|10^-7 second" type="NX_FLOAT[l+1]">
+        { Total time of flight }
+      </time_of_flight>
+      <polar_angle units="degrees" type="NX_FLOAT[i]">
+        { angular position of detector relative to beamzero through sample -- 
+        known to practitioners as "A4" or "two theta" }
+      </polar_angle>
+      <azimuthal_angle units="degrees" type="NX_FLOAT">
+        { Indicate sense of scattering: 0 is front surface of sample, 180 is 
+        back surface of sample. If 180, change the sign of the reflected angle 
+        in the data. It is also possible for the beam to enter the substrate 
+        from the side and reflect off the back surface of a film, in which case 
+        negative angles can be interpreted as inverting the scattering length 
+        density profile of the film (after accounting for absorption in the 
+        substrate. }
+      </azimuthal_angle>
+      <x_offset units="mm" type="NX_FLOAT[j]">
+        {pixel edges in x}?
+      </x_offset>
+      <y_offset units="mm" type="NX_FLOAT[k]">
+        {pixel edges in x}?
+      </y_offset>
+      <counts signal="1" axes="time_of_flight,x_offset?,y_offset?,polar_angle?" 
+          type="NX_INT[l,k,? j,? i]">
+        { raw detector counts }
+      </counts>
+      <!-- 
+      Time bins are logarithmic, but identical for each pixel on the detector 
+      this keeps constant resolution in Q. If not, then save things in 
+      different bins. Time bins are set for the lowest angle and with 
+      resolution improving at higher angles. Since dtheta/theta dominates, 
+      there's little benefit to changing time bins at higher angles. 
+      Regardless, lots of rebinning is required because the Q steps are too 
+      fine.
+
+      *** Raw counts are meaningless to the user if they are counting
+      *** against detector since all values will be the same. The data
+      *** only become meaningful when divided by counting time or monitor
+      *** as specified by the ratio field. The generic plotting program
+      *** will need to sort this out.
+
+      *** In general, n-D data should contain k-D summary statistics
+      *** for all 0<=k<n. That way a really dumb plotting program can
+      *** still display info from a 3-D result as a line.
+
+      *** Some control systems have data windows. Windows may be
+      *** defined in terms of pixel ranges or in terms of
+      *** theta_in-theta_out relationships (i.e., Qx). Each scan
+      *** point should have start/end positions and summary
+      *** statistics for every window defined. Window size may be
+      *** dynamic. Store windows in separate data blocks.
+      -->
+    </NXdetector>
+  </NXinstrument>
+  <NXmonitor name="monitor">
+    <mode type="NX_CHAR">
+      monitor
+    </mode>
+    <preset type="NX_FLOAT">
+      { preset value for monitor }?
+    </preset>
+    <data units="counts" type="NX_INT[i]">
+      { record of monitor counts }?
+    </data>
+    <efficiency type="Nxdata">
+      { Monitor efficiency as a function of wavelength }?
+    </efficiency>
+    <sampled_fraction units="dimensionless" type="NX_FLOAT">
+      { Proportion of incident beam sampled by the monitor }
+    </sampled_fraction>
+  </NXmonitor>
+  <NXmonitor name="timer">
+    <mode type="NX_CHAR">
+      timer
+    </mode>
+    <preset type="NX_FLOAT">
+      { preset value for timer }?
+    </preset>
+    <data units="seconds" type="NX_INT[i]">
+      { record of times for individual points }?
+    </data>
+  </NXmonitor>
+  <NXdata>
+    <time_of_flight units="second" 
+        NAPIlink="entry/instrument/detector/time_of_flight" type="NX_FLOAT[k]">
+    </time_of_flight>
+    <attenuator_transmission NAPIlink="NXentry/NXinstrument/NXattenuator">
+    </attenuator_transmission>
+    <theta NAPIlink="NXentry/NXsample/rotation_angle">
+    </theta>
+    <twotheta NAPIlink="NXentry/detector/polar_angle">
+    </twotheta>
+    <presample_slit1 NAPIlink="NXentry/presample_slit1/opening">
+    </presample_slit1>
+    <presample_slit2 NAPIlink="NXentry/presample_slit2/opening">
+    </presample_slit2>
+    <predetector_slit1 NAPIlink="NXentry/predetector_slit1/opening">
+    </predetector_slit1>
+    <predetector_slit2 NAPIlink="NXentry/predetector_slit2/opening">
+    </predetector_slit2>
+    <counts NAPIlink="NXentry/detector/counts">
+    </counts>
+    <count_start units="second" type="NX_FLOAT[i]">
+      <!-- probably shouldn't store any real data here, but where else? -->
+      { start time of each measurement point relative to start time of entry. }
+    </count_start>
+    <timer NAPIlink="NXentry/timer/data">
+    </timer>
+    <monitor NAPIlink="NXentry/monitor/data">
+    </monitor>
+  </NXdata>
+  <NXlog name="??">
+    { Various logs for temperature, field, etc. which are assumed to be 
+    constant over the duration of the run. The reduction program should be able 
+    to display their values on a parallel graph. Note that logs are not 
+    necessarily sampled synchronously with the data points. }*
+  </NXlog>
+</NXentry>
+]]>
+</programlisting>
+</example>
+
+
+<!--
+</sect2>
+-->
+</sect1>
diff --git a/doc/tutorial/README b/doc/tutorial/README
new file mode 100644
index 0000000..b33b9b4
--- /dev/null
+++ b/doc/tutorial/README
@@ -0,0 +1,3 @@
+Various bits of NeXus documentation
+--
+$Id$
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..432f0f8
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,31 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+
+install (FILES README.examples DESTINATION ${NXEXAMPLEDIR}/ COMPONENT Examples)
+
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..be89e36
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,11 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#
+# $Id$
+#
+nxexampledir		= $(NXEXAMPLEDIR)
+
+# add files and example code here
+nxexample_DATA		= README.examples
+
+EXTRA_DIST		= README.examples
diff --git a/examples/README b/examples/README
new file mode 100644
index 0000000..21ad62e
--- /dev/null
+++ b/examples/README
@@ -0,0 +1,8 @@
+NeXus example programs and files
+--------------------------------
+These are installed to the location specified by the
+NXEXAMPLEDIR variable in configure.ac, whihc is usually
+/usr/local/nexus/examples
+
+--
+$Id$
diff --git a/examples/README.examples b/examples/README.examples
new file mode 100644
index 0000000..d91a49e
--- /dev/null
+++ b/examples/README.examples
@@ -0,0 +1,14 @@
+NeXus example programs and files
+--------------------------------
+
+napi_test.c uses the name of the executable file
+it is compiled into to determine what type of file to create
+i.e. HDF5 if it is called napi_test-hdf5  etc.
+
+You can build these examples using the  nxbuild  script
+that is installed into /usr/local/bin e.g.
+
+    nxbuild -o napi_test-hdf5 napi_test.c
+
+--
+$Id$
diff --git a/file.MinGW b/file.MinGW
new file mode 100755
index 0000000..b496bf8
--- /dev/null
+++ b/file.MinGW
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# $Id$
+#
+
+# hack to get round the problem that libtool 1.5 uses the "file"
+# command and MinGW does not provide one (see README.MinGW)
+
+# install this as  /usr/local/bin/file   and chmod +x it
+ 
+ while $(echo "$1" | grep --silent "^-")
+ do
+ 	shift
+ done
+ 
+ case "$1" in
+ 	*.exe) echo "MS Windows PE 32-bit Intel 80386 console executable not relocatable" ;; # libtool doesn"t match the "32-bit"
+ 	*.dll) echo "MS Windows PE 32-bit Intel 80386 console DLL" ;;
+ 	*.dll.a) echo "ar archive import library" ;; # <-- import library for relocatable library
+ 	*.a | *.lib) echo "ar archive" ;; # <-- could be static library or import library for relocatable library; libtool will use objdump to find out
+ 	*) echo "unknown" ;;
+ esac
diff --git a/gnu_license.txt b/gnu_license.txt
new file mode 100755
index 0000000..42d5094
--- /dev/null
+++ b/gnu_license.txt
@@ -0,0 +1,515 @@
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
new file mode 100644
index 0000000..bc7283a
--- /dev/null
+++ b/include/CMakeLists.txt
@@ -0,0 +1,33 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+
+SET(INCLUDE_FILES napi.h napiu.h)
+
+INSTALL (FILES napi.h napiu.h DESTINATION ${NXINCLUDE}/ COMPONENT Development)
+INSTALL (FILES napi.h napiu.h DESTINATION ${NX_INCLUDE}/ COMPONENT Development)
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..7f8cfbe
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,11 @@
+# nxincludedir=$(includedir)/nexus
+nxincludedir=$(pkgincludedir)
+
+# CPP headers go into nxinclude. Traditionally 
+# nexus C headers went into include so we put
+# them in both places for now
+nxinclude_HEADERS = napi.h napiu.h
+
+include_HEADERS   = napi.h napiu.h
+
+noinst_HEADERS = napi4.h napi5.h nxxml.h napiconfig.h nxconfig_vms.h
diff --git a/include/napi.h b/include/napi.h
new file mode 100644
index 0000000..f6928c4
--- /dev/null
+++ b/include/napi.h
@@ -0,0 +1,964 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  Application Program Interface Header File
+  
+  Copyright (C) 2000-2011 Mark Koennecke, Uwe Filges
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+  
+  $Id$
+
+ ----------------------------------------------------------------------------*/
+/** \file 
+ * Documentation for the NeXus-API version 4.3
+ * 2000-2011, the NeXus International Advisory Commitee
+ * \defgroup c_main C API 
+ * \defgroup c_types Data Types
+ * \ingroup c_main
+ * \defgroup c_init General Initialisation and shutdown
+ * \ingroup c_main
+ * \defgroup c_group Reading and Writing Groups
+ * \ingroup c_main
+ * \defgroup c_readwrite Reading and Writing Data
+ * \ingroup c_main
+ * \defgroup c_navigation General File navigation
+ * \ingroup c_main
+ * \defgroup c_metadata Meta data routines
+ * \ingroup c_main
+ * \defgroup c_linking Linking 
+ * \ingroup c_main
+ * \defgroup c_memory Memory allocation
+ * \ingroup c_main
+ * \defgroup c_external External linking
+ * \ingroup c_main
+ */
+  
+#ifndef NEXUSAPI
+#define NEXUSAPI
+
+#ifdef __cplusplus
+//#include <cstdint>   // needs c++11 support
+#include <stdint.h>
+#else
+#include <stdint.h>
+#endif /* __cplusplus */
+
+/* NeXus HDF45 */
+#define NEXUS_VERSION   "4.3.2"                /* major.minor.patch */
+
+#define CONSTCHAR       const char
+
+typedef void* NXhandle;         /* really a pointer to a NexusFile structure */
+typedef int NXstatus;
+typedef char NXname[128];
+
+/* 
+ * Any new NXaccess_mode options should be numbered in 2^n format 
+ * (8, 16, 32, etc) so that they can be bit masked and tested easily.
+ *
+ * To test older non bit masked options (values below 8) use e.g.
+ *
+ *       if ( (mode & NXACCMASK_REMOVEFLAGS) == NXACC_CREATE )
+ *
+ * To test new (>=8) options just use normal bit masking e.g.
+ * 
+ *       if ( mode & NXACC_NOSTRIP )
+ *
+ */
+#define NXACCMASK_REMOVEFLAGS (0x7) /* bit mask to remove higher flag options */
+
+/** \enum NXaccess_mode 
+ * NeXus file access codes.
+ * \li NXACC_READ read-only
+ * \li NXACC_RDWR open an existing file for reading and writing.
+ * \li NXACC_CREATE create a NeXus HDF-4 file
+ * \li NXACC_CREATE4 create a NeXus HDF-4 file
+ * \li NXACC_CREATE5 create a NeXus HDF-5 file.
+ * \li NXACC_CREATEXML create a NeXus XML file.
+ * \li NXACC_CHECKNAMESYNTAX Check names conform to NeXus allowed characters.
+ */
+typedef enum {NXACC_READ=1, NXACC_RDWR=2, NXACC_CREATE=3, NXACC_CREATE4=4, 
+	      NXACC_CREATE5=5, NXACC_CREATEXML=6, NXACC_TABLE=8, NXACC_NOSTRIP=128, NXACC_CHECKNAMESYNTAX=256 } NXaccess_mode;
+
+/**
+ * A combination of options from #NXaccess_mode
+ */
+typedef int NXaccess;
+
+typedef struct {
+                char *iname;
+                int   type;
+               }info_type, *pinfo;  
+ 
+#define NX_OK 1
+#define NX_ERROR 0
+#define NX_EOD -1
+
+#define NX_UNLIMITED -1
+
+#define NX_MAXRANK 32
+#define NX_MAXNAMELEN 64
+#define NX_MAXPATHLEN 1024
+
+
+/**
+ * \ingroup c_types
+ * \def NX_FLOAT32     
+ * 32 bit float
+ * \def NX_FLOAT64     
+ * 64 bit float == double
+ * \def NX_INT8        
+ * 8 bit integer == byte
+ * \def NX_UINT8       
+ * 8 bit unsigned integer
+ * \def NX_INT16       
+ * 16 bit integer
+ * \def NX_UINT16      
+ * 16 bit unsigned integer
+ * \def NX_INT32       
+ * 32 bit integer
+ * \def NX_UINT32      
+ * 32 bit unsigned integer
+ * \def NX_CHAR        
+ * 8 bit character
+ * \def NX_BINARY      
+ * lump of binary data == NX_UINT8
+*/
+/*--------------------------------------------------------------------------*/ 
+
+/* Map NeXus to HDF types */
+#define NX_FLOAT32   5
+#define NX_FLOAT64   6
+#define NX_INT8     20  
+#define NX_UINT8    21
+#define NX_BOOLEAN NX_UINT
+#define NX_INT16    22  
+#define NX_UINT16   23
+#define NX_INT32    24
+#define NX_UINT32   25
+#define NX_INT64    26
+#define NX_UINT64   27
+#define NX_CHAR      4
+#define NX_BINARY   21
+
+/* Map NeXus compression methods to HDF compression methods */
+#define NX_CHUNK     0
+#define NX_COMP_NONE 100
+#define NX_COMP_LZW 200
+#define NX_COMP_RLE 300
+#define NX_COMP_HUF 400  
+
+/* levels for deflate - to test for these we use ((value / 100) == NX_COMP_LZW) */
+#define NX_COMP_LZW_LVL0 (100*NX_COMP_LZW + 0)
+#define NX_COMP_LZW_LVL1 (100*NX_COMP_LZW + 1)
+#define NX_COMP_LZW_LVL2 (100*NX_COMP_LZW + 2)
+#define NX_COMP_LZW_LVL3 (100*NX_COMP_LZW + 3)
+#define NX_COMP_LZW_LVL4 (100*NX_COMP_LZW + 4)
+#define NX_COMP_LZW_LVL5 (100*NX_COMP_LZW + 5)
+#define NX_COMP_LZW_LVL6 (100*NX_COMP_LZW + 6)
+#define NX_COMP_LZW_LVL7 (100*NX_COMP_LZW + 7)
+#define NX_COMP_LZW_LVL8 (100*NX_COMP_LZW + 8)
+#define NX_COMP_LZW_LVL9 (100*NX_COMP_LZW + 9)
+
+typedef struct {
+                long iTag;          /* HDF4 variable */
+                long iRef;          /* HDF4 variable */
+                char targetPath[1024]; /* path to item to link */
+                int linkType;          /* HDF5: 0 for group link, 1 for SDS link */
+               } NXlink;
+
+#define NXMAXSTACK 50
+
+#define CONCAT(__a,__b) __a##__b        /* token concatenation */
+
+#    ifdef __VMS
+#        define MANGLE(__arg)	__arg 
+#    else
+#        define MANGLE(__arg)   CONCAT(__arg,_)
+#    endif
+
+#    define NXopen              MANGLE(nxiopen)
+#    define NXreopen            MANGLE(nxireopen)
+#    define NXclose             MANGLE(nxiclose)
+#    define NXmakegroup         MANGLE(nximakegroup)
+#    define NXopengroup         MANGLE(nxiopengroup)
+#    define NXopenpath          MANGLE(nxiopenpath)
+#    define NXgetpath           MANGLE(nxigetpath)
+#    define NXopengrouppath     MANGLE(nxiopengrouppath)
+#    define NXclosegroup        MANGLE(nxiclosegroup)
+#    define NXmakedata          MANGLE(nximakedata)
+#    define NXmakedata64        MANGLE(nximakedata64)
+#    define NXcompmakedata      MANGLE(nxicompmakedata)
+#    define NXcompmakedata64    MANGLE(nxicompmakedata64)
+#    define NXcompress          MANGLE(nxicompress)
+#    define NXopendata          MANGLE(nxiopendata)
+#    define NXclosedata         MANGLE(nxiclosedata)
+#    define NXputdata           MANGLE(nxiputdata)
+#    define NXputslab           MANGLE(nxiputslab)
+#    define NXputslab64         MANGLE(nxiputslab64)
+#    define NXputattr           MANGLE(nxiputattr)
+#    define NXgetdataID         MANGLE(nxigetdataid)
+#    define NXmakelink          MANGLE(nximakelink)
+#    define NXmakenamedlink     MANGLE(nximakenamedlink)
+#    define NXopensourcegroup   MANGLE(nxiopensourcegroup)
+#    define NXmalloc            MANGLE(nximalloc)
+#    define NXmalloc64          MANGLE(nximalloc64)
+#    define NXfree              MANGLE(nxifree)
+#    define NXflush             MANGLE(nxiflush)
+
+#    define NXgetinfo           MANGLE(nxigetinfo)
+#    define NXgetinfo64         MANGLE(nxigetinfo64)
+#    define NXgetrawinfo        MANGLE(nxigetrawinfo)
+#    define NXgetrawinfo64      MANGLE(nxigetrawinfo64)
+#    define NXgetnextentry      MANGLE(nxigetnextentry)
+#    define NXgetdata           MANGLE(nxigetdata)
+
+#    define NXgetslab           MANGLE(nxigetslab)
+#    define NXgetslab64         MANGLE(nxigetslab64)
+#    define NXgetnextattr       MANGLE(nxigetnextattr)
+#    define NXgetattr           MANGLE(nxigetattr)
+#    define NXgetattrinfo       MANGLE(nxigetattrinfo)
+#    define NXgetgroupID        MANGLE(nxigetgroupid)
+#    define NXgetgroupinfo      MANGLE(nxigetgroupinfo)
+#    define NXsameID            MANGLE(nxisameid)
+#    define NXinitgroupdir      MANGLE(nxiinitgroupdir)
+#    define NXinitattrdir       MANGLE(nxiinitattrdir)
+#    define NXsetnumberformat   MANGLE(nxisetnumberformat)
+#    define NXsetcache          MANGLE(nxisetcache)
+#    define NXinquirefile       MANGLE(nxiinquirefile) 
+#    define NXisexternalgroup   MANGLE(nxiisexternalgroup)
+#    define NXisexternaldataset   MANGLE(nxiisexternaldataset)
+#    define NXlinkexternal      MANGLE(nxilinkexternal)
+#    define NXlinkexternaldataset      MANGLE(nxilinkexternaldataset)
+#    define NXgetversion        MANGLE(nxigetversion)
+
+/* 
+ * FORTRAN helpers - for NeXus internal use only 
+ */
+#    define NXfopen             MANGLE(nxifopen)
+#    define NXfclose            MANGLE(nxifclose)
+#    define NXfflush            MANGLE(nxifflush)
+#    define NXfmakedata         MANGLE(nxifmakedata)
+#    define NXfcompmakedata     MANGLE(nxifcompmakedata)
+#    define NXfcompress         MANGLE(nxifcompress)
+#    define NXfputattr          MANGLE(nxifputattr)
+#    define NXfgetpath          MANGLE(nxifgetpath)
+
+/* 
+ * Standard interface 
+ *
+ * Functions added here are not automatically exported from 
+ * a shared library/dll - the symbol name must also be added
+ * to the file   src/nexus_symbols.txt
+ * 
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+  /** 
+   * Open a NeXus file.
+   * NXopen honours full path file names. But it also searches 
+   * for files in all the paths given in the NX_LOAD_PATH environment variable. 
+   * NX_LOAD_PATH is supposed to hold a list of path string separated by the platform 
+   * specific path separator. For unix this is the : , for DOS the ; . Please note 
+   * that crashing on an open NeXus file will result in corrupted data. Only after a NXclose 
+   * or a NXflush will the data file be valid. 
+   * \param filename The name of the file to open
+   * \param access_method The file access method. This can be:
+   * \li NXACC__READ read access 
+   * \li NXACC_RDWR read write access 
+   * \li NXACC_CREATE, NXACC_CREATE4 create a new HDF-4 NeXus file
+   * \li NXACC_CREATE5 create a new HDF-5 NeXus file
+   * \li NXACC_CREATEXML create an XML NeXus file. 
+   * see #NXaccess_mode
+   * Support for HDF-4 is deprecated.
+   * \param pHandle A file handle which will be initialized upon successfull completeion of NXopen.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_init
+   */
+extern  NXstatus  NXopen(CONSTCHAR * filename, NXaccess access_method, NXhandle* pHandle);
+
+  /** 
+   * Opens an existing NeXus file a second time for e.g. access from another thread.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_init
+   */
+extern  NXstatus  NXreopen(NXhandle pOrigHandle, NXhandle* pNewHandle);
+
+  /**
+   * close a NeXus file
+   * \param pHandle A NeXus file handle as returned from NXopen. pHandle is invalid after this 
+   * call.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_init
+   */
+extern  NXstatus  NXclose(NXhandle* pHandle);
+
+  /**
+   * flush data to disk
+   * \param pHandle A NeXus file handle as initialized by NXopen. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXflush(NXhandle* pHandle);
+
+  /**
+   * NeXus groups are NeXus way of structuring information into a hierarchy. 
+   * This function creates a group but does not open it.
+   * \param handle A NeXus file handle as initialized NXopen. 
+   * \param name The name of the group
+   * \param NXclass the class name of the group. Should start with the prefix NX
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_group
+   */
+extern  NXstatus  NXmakegroup (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+
+  /**
+   * Step into a group. All further access will be within the opened group.
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param name The name of the group
+   * \param NXclass the class name of the group. Should start with the prefix NX
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_group
+   */
+extern  NXstatus  NXopengroup (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+
+  /**
+   * Open the NeXus object with the path specified
+   * \param handle A NeXus file handle as returned from NXopen. 
+   * \param path A unix like path string to a NeXus group or dataset. The path string 
+   * is a list of group names and SDS names separated with / (slash). 
+   * Example: /entry1/sample/name 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_navigation 
+   */
+extern  NXstatus  NXopenpath (NXhandle handle, CONSTCHAR *path);
+
+  /**
+   * Opens the group in which the NeXus object with the specified path exists
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param path A unix like path string to a NeXus group or dataset. The path string 
+   * is a list of group names and SDS names separated with / (slash). 
+   * Example: /entry1/sample/name 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_navigation 
+   */
+extern  NXstatus  NXopengrouppath (NXhandle handle, CONSTCHAR *path);
+
+  /**
+   * Retrieve the current path in the NeXus file
+   * \param handle a NeXus file handle
+   * \param path A buffer to copy the path too
+   * \param  pathlen The maximum number of characters to copy into path
+   * \return NX_OK or NX_ERROR
+   * \ingroup c_navigation
+   */
+extern NXstatus NXgetpath(NXhandle handle, char *path, int pathlen);
+
+  /**
+   * Closes the currently open group and steps one step down in the NeXus file 
+   * hierarchy.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_group 
+   */
+extern  NXstatus  NXclosegroup(NXhandle handle);
+
+  /**
+   * Create a multi dimensional data array or dataset. The dataset is NOT opened. 
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param label The name of the dataset
+   * \param datatype The data type of this data set. 
+   * \param rank The number of dimensions this dataset is going to have
+   * \param dim An array of size rank holding the size of the dataset in each dimension. The first dimension 
+   * can be NX_UNLIMITED. Data can be appended to such a dimension using NXputslab. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXmakedata (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[]);
+
+
+  /**
+   * @copydoc NXmakedata()
+   */
+extern  NXstatus  NXmakedata64 (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[]);
+
+
+/**
+   * Create a compressed dataset. The dataset is NOT opened. Data from this set will automatically be compressed when 
+   * writing and decompressed on reading. 
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param label The name of the dataset
+   * \param datatype The data type of this data set. 
+   * \param rank The number of dimensions this dataset is going to have
+   * \param comp_typ The compression scheme to use. Possible values:
+   * \li NX_COMP_NONE no compression 
+   * \li NX_COMP_LZW (recommended) despite the name this enabled zlib compression (of various levels, see above)
+   * \li NX_COMP_RLE run length encoding (only HDF-4)
+   * \li NX_COMP_HUF Huffmann encoding (only HDF-4)
+   * \param dim An array of size rank holding the size of the dataset in each dimension. The first dimension 
+   * can be NX_UNLIMITED. Data can be appended to such a dimension using NXputslab. 
+   * \param bufsize The dimensions of the subset of the data which usually be writen in one go. 
+   * This is a parameter used by HDF for performance optimisations. If you write your data in one go, this 
+   * should be the same as the data dimension. If you write it in slabs, this is your preferred slab size. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXcompmakedata (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[], int comp_typ, int bufsize[]);
+
+
+/**
+  * @copydoc NXcompmakedata() 
+  */
+extern  NXstatus NXcompmakedata64 (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[], int comp_typ, int64_t chunk_size[]);
+
+
+  /**
+   * Switch compression on. This routine is superseeded by NXcompmakedata and thus 
+   * is deprecated.
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param compr_type The compression scheme to use. Possible values:
+   * \li NX_COMP_NONE no compression 
+   * \li NX_COMP_LZW (recommended) despite the name this enabled zlib compression (of various levels, see above)
+   * \li NX_COMP_RLE run length encoding (only HDF-4)
+   * \li NX_COMP_HUF Huffmann encoding (only HDF-4)
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXcompress (NXhandle handle, int compr_type);
+
+  /**
+   * Open access to a dataset. After this call it is possible to write and read data or 
+   * attributes to and from the dataset.
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param label The name of the dataset
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite 
+   */
+extern  NXstatus  NXopendata (NXhandle handle, CONSTCHAR* label);
+
+  /**
+   * Close access to a dataset. 
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite 
+   */
+extern  NXstatus  NXclosedata(NXhandle handle);
+
+  /**
+   * Write data to a datset which has previouly been opened with NXopendata. 
+   * This writes all the data in one go. Data should be a pointer to a memory 
+   * area matching the datatype and dimensions of the dataset.
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param data Pointer to data to write.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXputdata(NXhandle handle, const void* data);
+
+  /**
+   * Write an attribute. The kind of attribute written depends on the  
+   * poistion in the file: at root level, a global attribute is written, if 
+   * agroup is open but no dataset, a group attribute is written, if a dataset is 
+   * open, a dataset attribute is written.
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param name The name of the attribute.
+   * \param data A pointer to the data to write for the attribute.
+   * \param iDataLen The length of the data in data in bytes.
+   * \param iType The NeXus data type of the attribute. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXputattr(NXhandle handle, CONSTCHAR* name, const void* data, int iDataLen, int iType);
+
+  /**
+   * Write  a subset of a multi dimensional dataset.
+   * \param handle A NeXus file handle as initialized by NXopen. 
+   * \param data A pointer to a memory area holding the data to write.
+   * \param start An array holding the start indices where to start the data subset.
+   * \param size An array holding the size of the data subset to write in each dimension.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXputslab(NXhandle handle, const void* data, const int start[], const int size[]);    
+
+  /**
+   * @copydoc NXputdata()
+   */
+extern  NXstatus  NXputslab64(NXhandle handle, const void* data, const int64_t start[], const int64_t size[]);    
+
+  /**
+   * Retrieve link data for a dataset. This link data can later on be used to link this 
+   * dataset into a different group. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param pLink A link data structure which will be initialized with the required information
+   * for linking. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_linking
+   */
+extern  NXstatus  NXgetdataID(NXhandle handle, NXlink* pLink);
+
+  /**
+   * Create a link to the group or dataset described by pLink in the currently open 
+   * group. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param pLink A link data structure describing the object to link. This must have been initialized
+   * by either a call to NXgetdataID or NXgetgroupID.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_linking
+   */
+extern  NXstatus  NXmakelink(NXhandle handle, NXlink* pLink);
+
+  /**
+   * Create a link to the group or dataset described by pLink in the currently open 
+   * group. But give the linked item a new name.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param newname The new name of the item in the currently open group. 
+   * \param pLink A link data structure describing the object to link. This must have been initialized
+   * by either a call to NXgetdataID or NXgetgroupID.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_linking
+   */
+extern  NXstatus  NXmakenamedlink(NXhandle handle, CONSTCHAR* newname, NXlink* pLink);
+
+  /**
+   * Open the source group of a linked group or dataset. Returns an error when the item is 
+   * not a linked item.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_navigation
+   */
+extern  NXstatus  NXopensourcegroup(NXhandle handle);
+
+  /**
+   * Read a complete dataset from the currently open dataset into memory. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param data A pointer to the memory area where to read the data, too. Data must point to a memory 
+   * area large enough to accomodate the data read. Otherwise your program may behave in unexpected
+   * and unwelcome ways.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXgetdata(NXhandle handle, void* data);
+
+  /**
+   * Retrieve information about the curretly open dataset.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param rank A pointer to an integer which will be filled with the rank of 
+   * the dataset.
+   * \param dimension An array which will be initialized with the size of the dataset in any of its 
+   * dimensions. The array must have at least the size of rank.
+   * \param datatype A pointer to an integer which be set to the NeXus data type code for this dataset.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_metadata
+   */
+extern  NXstatus  NXgetinfo(NXhandle handle, int* rank, int dimension[], int* datatype);
+
+  /**
+   * @copydoc NXgetinfo()
+   */
+extern  NXstatus  NXgetinfo64(NXhandle handle, int* rank, int64_t dimension[], int* datatype);
+
+  /**
+   * Get the next entry in the currently open group. This is for retrieving infromation about the 
+   * content of a NeXus group. In order to search a group #NXgetnextentry is called in a loop until 
+   * #NXgetnextentry returns NX_EOD which indicates that there are no further items in the group.
+   * Reset search using #NXinitgroupdir
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param name The name of the object
+   * \param nxclass The NeXus class name for a group or the string SDS for a dataset.
+   * \param datatype The NeXus data type if the item is a SDS. 
+   * \return NX_OK on success, NX_ERROR in the case of an error, NX_EOD when there are no more items.   
+   * \ingroup c_navigation
+   */
+extern  NXstatus  NXgetnextentry(NXhandle handle, NXname name, NXname nxclass, int* datatype);
+
+  /**
+   * Read a subset of data from file into memory. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param data A pointer to the memory data where to copy the data too. The pointer must point 
+   * to a memory area large enough to accomodate the size of the data read.
+   * \param start An array holding the start indices where to start reading the data subset.
+   * \param size An array holding the size of the data subset to read for each dimension.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXgetslab(NXhandle handle, void* data, const int start[], const int size[]);
+
+
+  /**
+   * @copydoc NXgetslab()
+   */
+extern  NXstatus  NXgetslab64(NXhandle handle, void* data, const int64_t start[], const int64_t size[]);
+
+/**
+   * Iterate over global, group or dataset attributes depending on the currently open group or 
+   * dataset. In order to search attributes multiple calls to #NXgetnextattr are performed in a loop 
+   * until #NXgetnextattr returns NX_EOD which indicates that there are no further attributes.
+   * reset search using #NXinitattrdir
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param pName The name of the attribute
+   * \param iLength A pointer to an integer which be set to the length of the attribute data.
+   * \param iType A pointer to an integer which be set to the NeXus data type of the attribute.
+   * \return NX_OK on success, NX_ERROR in the case of an error, NX_EOD when there are no more items.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXgetnextattr(NXhandle handle, NXname pName, int *iLength, int *iType);
+
+  /**
+   * Read an attribute. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param name The name of the atrribute to read.
+   * \param data A pointer to a memory area large enough to hold the attributes value.
+   * \param iDataLen The length of data in bytes.
+   * \param iType A pointer to an integer which will had been set to the NeXus data type of the attribute.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXgetattr(NXhandle handle, char* name, void* data, int* iDataLen, int* iType);
+
+  /**
+   * Get the count of attributes in the currently open dataset, group or global attributes when at root level.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param no_items A pointer to an integer which be set to the number of attributes available.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_metadata
+   */
+extern  NXstatus  NXgetattrinfo(NXhandle handle, int* no_items);
+
+  /**
+   * Retrieve link data for the currently open group. This link data can later on be used to link this 
+   * group into a different group. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param pLink A link data structure which will be initialized with the required information
+   * for linking. 
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_linking
+   */
+extern  NXstatus  NXgetgroupID(NXhandle handle, NXlink* pLink);
+
+  /**
+   * Retrieve information about the currently open group.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param no_items A pointer to an integer which will be set to the count 
+   *   of group elements available. This is the count of other groups and 
+   * data sets in this group.  
+   * \param name The name of the group.
+   * \param nxclass The NeXus class name of the group.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_metadata
+   */
+extern  NXstatus  NXgetgroupinfo(NXhandle handle, int* no_items, NXname name, NXname nxclass);
+
+  /**
+   * Tests if two link data structures describe the same item.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param pFirstID The first link data for the test.
+   * \param pSecondID The second link data structure.
+   * \return NX_OK when both link data structures describe the same item, NX_ERROR else.   
+   * \ingroup c_linking
+   */
+extern  NXstatus  NXsameID(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID);
+
+  /**
+   * Resets a pending group search to the start again. To be called in a #NXgetnextentry loop when 
+   * a group search has to be restarted.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_navigation 
+   */
+extern  NXstatus  NXinitgroupdir(NXhandle handle);
+
+  /**
+   * Resets a pending attribute search to the start again. To be called in a #NXgetnextattr loop when 
+   * an attribute search has to be restarted.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_navigation
+   */
+extern  NXstatus  NXinitattrdir(NXhandle handle);
+
+  /**
+   * Sets the format for number printing. This call has only an effect when using the XML physical file 
+   * format. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param type The NeXus data type to set the format for.
+   * \param format The C-language format string to use for this data type.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_readwrite
+   */
+extern  NXstatus  NXsetnumberformat(NXhandle handle, int type, char *format);
+
+  /**
+   * Inquire the filename of the currently open file. FilenameBufferLength of the file name 
+   * will be copied into the filename buffer.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param filename The buffer to hold the filename.
+   * \param  filenameBufferLength The length of the filename buffer.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_metadata
+   */
+extern  NXstatus  NXinquirefile(NXhandle handle, char *filename, int filenameBufferLength);
+
+  /**
+   * Test if a group is actually pointing to an external file. If so, retrieve the URL of the 
+   * external file.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param name The name of the group to test.
+   * \param nxclass The class name of the group to test.
+   * \param url A buffer to copy the URL too.
+   * \param urlLen The length of the Url buffer. At maximum urlLen bytes will be copied to url.
+   * \return NX_OK when the group is pointing to an external file, NX_ERROR else.
+   * \ingroup c_external
+   */
+extern  NXstatus  NXisexternalgroup(NXhandle handle, CONSTCHAR *name, CONSTCHAR *nxclass, char *url, int urlLen); 
+
+
+  /**
+   * Test if a dataset is actually pointing to an external file. If so, retrieve the URL of the 
+   * external file.
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param name The name of the dataset to test.
+   * \param url A buffer to copy the URL too.
+   * \param urlLen The length of the Url buffer. At maximum urlLen bytes will be copied to url.
+   * \return NX_OK when the dataset is pointing to an external file, NX_ERROR else.
+   * \ingroup c_external
+   */
+extern  NXstatus  NXisexternaldataset(NXhandle handle, CONSTCHAR *name, char *url, int urlLen); 
+
+  /**
+   * Create a link to a group in an external file. This works by creating a NeXus group under the current level in 
+   * the hierarchy which actually points to a group in another file. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param name The name of the group which points to the external file.
+   * \param nxclass The class name of the group which points to the external file.
+   * \param url The URL of the external file. Currently only one URL format is supported: nxfile://path-tofile\#path-in-file. 
+   * This consists of two parts: the first part is of course the path to the file. The second part, path-in-file, is the 
+   * path to the group in the external file which appears in the first file.  
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_external
+   */
+extern  NXstatus  NXlinkexternal(NXhandle handle, CONSTCHAR *name, CONSTCHAR *nxclass, CONSTCHAR *url);
+
+
+  /**
+   * Create a link to a dataset in an external file. This works by creating a dataset under the current level in 
+   * the hierarchy which actually points to a dataset in another file. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param name The name of the dataset which points to the external file.
+   * \param url The URL of the external file. Currently only one URL format is supported: nxfile://path-tofile\#path-in-file. 
+   * This consists of two parts: the first part is of course the path to the file. The second part, path-in-file, is the 
+   * path to the dataset in the external file which appears in the first file.  
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_external
+   */
+extern  NXstatus  NXlinkexternaldataset(NXhandle handle, CONSTCHAR *name, CONSTCHAR *url);
+
+  /**
+   * Utility function which allocates a suitably sized memory area for the dataset characteristics specified.
+   * \param data A pointer to a pointer which will be initialized with a pointer to a suitably sized memory area.
+   * \param rank the rank of the data.
+   * \param dimensions An array holding the size of the data in each dimension.
+   * \param datatype The NeXus data type of the data.
+   * \return NX_OK when allocation succeeds, NX_ERROR in the case of an error.   
+   * \ingroup c_memory
+   */ 
+extern  NXstatus  NXmalloc(void** data, int rank, const int dimensions[], int datatype);
+
+  /**
+   * @copydoc NXmalloc()
+   */ 
+extern  NXstatus  NXmalloc64(void** data, int rank, const int64_t dimensions[], int datatype);
+
+
+  /**
+   * Utility function to return NeXus version
+   * \return pointer to string in static storage. Version in
+   * same format as NEXUS_VERSION string in napi.h i.e. "major.minor.patch"
+   * \ingroup c_metadata
+   */
+extern  const char* NXgetversion();
+
+  /**
+   * Utility function to release the memory for data.
+   * \param data A pointer to a pointer to free.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_memory
+   */
+extern  NXstatus  NXfree(void** data);
+
+
+/*-----------------------------------------------------------------------
+    NAPI internals 
+------------------------------------------------------------------------*/
+  /**
+   * Retrieve information about the currently open dataset. In contrast to the main function below, 
+   * this function does not try to find out about the size of strings properly. 
+   * \param handle A NeXus file handle as initialized by NXopen.
+   * \param rank A pointer to an integer which will be filled with the rank of 
+   * the dataset.
+   * \param dimension An array which will be initialized with the size of the dataset in any of its 
+   * dimensions. The array must have at least the size of rank.
+   * \param datatype A pointer to an integer which be set to the NeXus data type code for this dataset.
+   * \return NX_OK on success, NX_ERROR in the case of an error.   
+   * \ingroup c_metadata
+   */
+extern  NXstatus  NXgetrawinfo(NXhandle handle, int* rank, int dimension[], int* datatype);
+
+ /**
+  * @copydoc NXgetrawinfo
+  */
+extern  NXstatus  NXgetrawinfo64(NXhandle handle, int* rank, int64_t dimension[], int* datatype);
+
+/** \typedef void (*ErrFunc)(void *data, char *text)
+ * All NeXus error reporting happens through this special function, the 
+ * ErrFunc. The NeXus-API allows to replace this error reporting function
+ * through a user defined implementation. The default error function prints to stderr. User 
+ * defined ones may pop up dialog boxes or whatever.
+ * \param data A pointer to some user defined data structure
+ * \param text The text of the error message to display. 
+ */
+typedef void (*ErrFunc)(void *data, char *text);
+
+  /**
+   * Set a global error function.
+   * Not threadsafe.
+   * \param pData A pointer to a user defined data structure which be passed to 
+   * the error display function.
+   * \param newErr The new error display function.
+   */
+extern  void  NXMSetError(void *pData, ErrFunc newErr);
+
+  /**
+   * Set an error function for the current thread.
+   * When used this overrides anything set in NXMSetError (for the current thread).
+   * Use this method in threaded applications.
+   * \param pData A pointer to a user defined data structure which be passed to 
+   * the error display function.
+   * \param newErr The new error display function.
+   */
+extern  void  NXMSetTError(void *pData, ErrFunc newErr);
+
+  /**
+   * Retrieve the current error display function
+   * \return The current error display function.
+   */
+extern ErrFunc NXMGetError();
+
+  /**
+   * Suppress error reports from the NeXus-API
+   */
+extern  void  NXMDisableErrorReporting();
+
+  /**
+   * Enable error reports from the NeXus-API
+   */
+extern  void  NXMEnableErrorReporting();
+
+ /**
+  * Dispatches the error message to the error function defined by NXMSetTError
+  */
+extern void NXReportError(char *text);
+
+ /**
+  * Do not use, first parameter should be set by NXMSetTError
+  */
+extern void NXIReportError(void *pData,char *text);
+/* extern void *NXpData; */
+extern char *NXIformatNeXusTime();
+extern  NXstatus  NXIprintlink(NXhandle fid, NXlink* link);
+
+/**
+ * A function for setting the default cache size for HDF-5
+ * \ingroup c_init
+ */
+extern  NXstatus  NXsetcache(long newVal);
+
+  typedef struct {
+        NXhandle pNexusData;   
+        NXstatus ( *nxreopen)(NXhandle pOrigHandle, NXhandle* pNewHandle);
+        NXstatus ( *nxclose)(NXhandle* pHandle);
+        NXstatus ( *nxflush)(NXhandle* pHandle);
+        NXstatus ( *nxmakegroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+        NXstatus ( *nxopengroup) (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+        NXstatus ( *nxclosegroup)(NXhandle handle);
+        NXstatus ( *nxmakedata64) (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[]);
+        NXstatus ( *nxcompmakedata64) (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[], int comp_typ, int64_t bufsize[]);
+        NXstatus ( *nxcompress) (NXhandle handle, int compr_type);
+        NXstatus ( *nxopendata) (NXhandle handle, CONSTCHAR* label);
+        NXstatus ( *nxclosedata)(NXhandle handle);
+        NXstatus ( *nxputdata)(NXhandle handle, const void* data);
+        NXstatus ( *nxputattr)(NXhandle handle, CONSTCHAR* name, const void* data, int iDataLen, int iType);
+        NXstatus ( *nxputslab64)(NXhandle handle, const void* data, const int64_t start[], const int64_t size[]);    
+        NXstatus ( *nxgetdataID)(NXhandle handle, NXlink* pLink);
+        NXstatus ( *nxmakelink)(NXhandle handle, NXlink* pLink);
+        NXstatus ( *nxmakenamedlink)(NXhandle handle, CONSTCHAR *newname, NXlink* pLink);
+        NXstatus ( *nxgetdata)(NXhandle handle, void* data);
+        NXstatus ( *nxgetinfo64)(NXhandle handle, int* rank, int64_t dimension[], int* datatype);
+        NXstatus ( *nxgetnextentry)(NXhandle handle, NXname name, NXname nxclass, int* datatype);
+        NXstatus ( *nxgetslab64)(NXhandle handle, void* data, const int64_t start[], const int64_t size[]);
+        NXstatus ( *nxgetnextattr)(NXhandle handle, NXname pName, int *iLength, int *iType);
+        NXstatus ( *nxgetattr)(NXhandle handle, char* name, void* data, int* iDataLen, int* iType);
+        NXstatus ( *nxgetattrinfo)(NXhandle handle, int* no_items);
+        NXstatus ( *nxgetgroupID)(NXhandle handle, NXlink* pLink);
+        NXstatus ( *nxgetgroupinfo)(NXhandle handle, int* no_items, NXname name, NXname nxclass);
+        NXstatus ( *nxsameID)(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID);
+        NXstatus ( *nxinitgroupdir)(NXhandle handle);
+        NXstatus ( *nxinitattrdir)(NXhandle handle);
+        NXstatus ( *nxsetnumberformat)(NXhandle handle, int type, char *format);
+        NXstatus ( *nxprintlink)(NXhandle handle, NXlink* link);
+        NXstatus ( *nxnativeexternallink)(NXhandle handle, CONSTCHAR* name, CONSTCHAR* externalfile, CONSTCHAR* remotetarget);
+        NXstatus ( *nxnativeinquirefile)(NXhandle handle, char* externalfile, const int filenamelength);
+        NXstatus ( *nxnativeisexternallink)(NXhandle handle, CONSTCHAR* name, char* url, int urllen);
+        int stripFlag;
+        int checkNameSyntax;
+  } NexusFunction, *pNexusFunction;
+  /*---------------------*/
+  extern long nx_cacheSize;
+
+/* FORTRAN internals */
+
+  extern NXstatus  NXfopen(char * filename, NXaccess* am, 
+					NXhandle pHandle);
+  extern NXstatus  NXfclose (NXhandle pHandle);
+  extern NXstatus  NXfputattr(NXhandle fid, const char *name, const void *data, 
+                                   int *pDatalen, int *pIType);
+  extern NXstatus  NXfcompress(NXhandle fid, int *compr_type);
+  extern NXstatus  NXfcompmakedata(NXhandle fid, char *name, 
+                int *pDatatype,
+		int *pRank, int dimensions[],
+                int *compression_type, int chunk[]);
+  extern NXstatus  NXfmakedata(NXhandle fid, char *name, int *pDatatype,
+		int *pRank, int dimensions[]);
+  extern NXstatus  NXfflush(NXhandle pHandle);
+  extern NXstatus  NXfgetpath(NXhandle fid, char *path, int *pathlen);
+#ifdef __cplusplus
+};
+#endif /* __cplusplus */
+
+/**
+ * Freddie Akeroyd 11/8/2009
+ * Add NeXus schema support - this uses BASE.xsd as the initial file
+ */
+#define NEXUS_SCHEMA_VERSION	"3.1" 	/**< version of NeXus definition schema */
+#define NEXUS_SCHEMA_ROOT 	"http://definition.nexusformat.org/schema/" 	/**< XML schema namespace specified by xmlns */
+#define NEXUS_SCHEMA_NAMESPACE 	NEXUS_SCHEMA_ROOT NEXUS_SCHEMA_VERSION 	/**< XML schema namespace specified by xmlns */
+#define NEXUS_SCHEMA_BASE 	"BASE"
+#define NEXUS_SCHEMA_FILE 	NEXUS_SCHEMA_BASE ".xsd" /**< default schema file for namespace */
+#define NEXUS_SCHEMA_URL 	NEXUS_SCHEMA_NAMESPACE "/" NEXUS_SCHEMA_FILE /**< location of default schema file for namespace */
+
+#endif /*NEXUSAPI*/
diff --git a/include/napi4.h b/include/napi4.h
new file mode 100644
index 0000000..af354a5
--- /dev/null
+++ b/include/napi4.h
@@ -0,0 +1,60 @@
+#ifndef NAPI4_H
+#define NAPI4_H
+
+#define NXSIGNATURE 959697
+
+#include "mfhdf.h"
+/* #include "napi4.c" */
+
+/* 
+ * HDF4 interface 
+ */
+
+extern  NXstatus  NX4open(CONSTCHAR *filename, NXaccess access_method, NXhandle* pHandle);
+extern  NXstatus  NX4close(NXhandle* pHandle);
+extern  NXstatus  NX4flush(NXhandle* pHandle);
+  
+extern  NXstatus  NX4makegroup (NXhandle handle, CONSTCHAR* Vgroup, CONSTCHAR* NXclass);
+extern  NXstatus  NX4opengroup (NXhandle handle, CONSTCHAR* Vgroup, CONSTCHAR* NXclass);
+extern  NXstatus  NX4closegroup(NXhandle handle);
+  
+extern  NXstatus  NX4makedata64 (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[]);
+extern  NXstatus  NX4compmakedata64 (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[], int comp_typ, int64_t bufsize[]);
+extern  NXstatus  NX4compress (NXhandle handle, int compr_type);
+extern  NXstatus  NX4opendata (NXhandle handle, CONSTCHAR* label);
+
+extern  NXstatus  NX4closedata(NXhandle handle);
+  
+extern  NXstatus  NX4getdata(NXhandle handle, void* data);
+extern  NXstatus  NX4getslab64(NXhandle handle, void* data, const int64_t start[], const int64_t size[]);
+extern  NXstatus  NX4getattr(NXhandle handle, char* name, void* data, int* iDataLen, int* iType);
+  
+extern  NXstatus  NX4putdata(NXhandle handle, const void* data);
+extern  NXstatus  NX4putslab64(NXhandle handle, const void* data, const int64_t start[], const int64_t size[]);
+extern  NXstatus  NX4putattr(NXhandle handle, CONSTCHAR* name, const void* data, int iDataLen, int iType);
+  
+extern  NXstatus  NX4getinfo64(NXhandle handle, int* rank, int64_t dimension[], int* datatype);
+extern  NXstatus  NX4getgroupinfo(NXhandle handle, int* no_items, NXname name, NXname nxclass);
+extern  NXstatus  NX4initgroupdir(NXhandle handle);
+extern  NXstatus  NX4getnextentry(NXhandle handle, NXname name, NXname nxclass, int* datatype);
+extern  NXstatus  NX4getattrinfo(NXhandle handle, int* no_items);
+extern  NXstatus  NX4initattrdir(NXhandle handle);
+extern  NXstatus  NX4getnextattr(NXhandle handle, NXname pName, int *iLength, int *iType);
+  
+extern  NXstatus  NX4getgroupID(NXhandle handle, NXlink* pLink);
+extern  NXstatus  NX4getdataID(NXhandle handle, NXlink* pLink);
+extern  NXstatus  NX4makelink(NXhandle handle, NXlink* pLink);
+extern  NXstatus  NX4printlink(NXhandle handle, NXlink* pLink);
+
+void NX4assignFunctions(pNexusFunction fHandle);
+
+  
+/*
+ *  HDF changed from MAX_VAR_DIMS to H4_MAX_VAR_DIMS aronud 9/5/2007 
+ *  to avoid potential conflicts with NetCDF-3 library
+ */
+#ifndef H4_MAX_VAR_DIMS
+#define H4_MAX_VAR_DIMS	MAX_VAR_DIMS
+#endif
+
+#endif /* NAPI4_H */
diff --git a/include/napi5.h b/include/napi5.h
new file mode 100644
index 0000000..7949078
--- /dev/null
+++ b/include/napi5.h
@@ -0,0 +1,54 @@
+#ifndef NAPI5_H
+#define NAPI5_H
+
+#define NX5SIGNATURE 959695
+
+#include <hdf5.h>
+
+/* HDF5 interface */
+
+extern  NXstatus  NX5open(CONSTCHAR *filename, NXaccess access_method, NXhandle* pHandle);
+extern  NXstatus  NX5reopen(NXhandle pOrigHandle, NXhandle* pNewHandle);
+
+extern  NXstatus  NX5close(NXhandle* pHandle);
+extern  NXstatus  NX5flush(NXhandle* pHandle);
+  
+extern  NXstatus  NX5makegroup (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+extern  NXstatus  NX5opengroup (NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass);
+extern  NXstatus  NX5closegroup(NXhandle handle);
+  
+extern  NXstatus  NX5makedata64 (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[]);
+extern  NXstatus  NX5compmakedata64 (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int64_t dim[], int comp_typ, int64_t bufsize[]);
+extern  NXstatus  NX5compress (NXhandle handle, int compr_type);
+extern  NXstatus  NX5opendata (NXhandle handle, CONSTCHAR* label);
+extern  NXstatus  NX5closedata(NXhandle handle);
+extern  NXstatus  NX5putdata(NXhandle handle, const void* data);
+
+extern  NXstatus  NX5putattr(NXhandle handle, CONSTCHAR* name, const void* data, int iDataLen, int iType);
+extern  NXstatus  NX5putslab64(NXhandle handle, const void* data, const int64_t start[], const int64_t size[]);    
+
+extern  NXstatus  NX5getdataID(NXhandle handle, NXlink* pLink);
+extern  NXstatus  NX5makelink(NXhandle handle, NXlink* pLink);
+extern  NXstatus  NX5printlink(NXhandle handle, NXlink* pLink);
+
+extern  NXstatus  NX5getdata(NXhandle handle, void* data);
+extern  NXstatus  NX5getinfo64(NXhandle handle, int* rank, int64_t dimension[], int* datatype);
+extern  NXstatus  NX5getnextentry(NXhandle handle, NXname name, NXname nxclass, int* datatype);
+
+extern  NXstatus  NX5getslab64(NXhandle handle, void* data, const int64_t start[], const int64_t size[]);
+extern  NXstatus  NX5getnextattr(NXhandle handle, NXname pName, int *iLength, int *iType);
+extern  NXstatus  NX5getattr(NXhandle handle, char* name, void* data, int* iDataLen, int* iType);
+extern  NXstatus  NX5getattrinfo(NXhandle handle, int* no_items);
+extern  NXstatus  NX5getgroupID(NXhandle handle, NXlink* pLink);
+extern  NXstatus  NX5getgroupinfo(NXhandle handle, int* no_items, NXname name, NXname nxclass);
+
+extern  NXstatus  NX5initgroupdir(NXhandle handle);
+extern  NXstatus  NX5initattrdir(NXhandle handle);
+
+void NX5assignFunctions(pNexusFunction fHandle);
+
+herr_t attr_info(hid_t loc_id, const char *name, const H5A_info_t *unused, void *opdata);
+herr_t group_info(hid_t loc_id, const char *name, const H5L_info_t *unused, void *opdata);
+herr_t nxgroup_info(hid_t loc_id, const char *name, const H5L_info_t *unused, void *op_data);
+
+#endif /* NAPI5_H */
diff --git a/include/napiconfig.h b/include/napiconfig.h
new file mode 100644
index 0000000..4282838
--- /dev/null
+++ b/include/napiconfig.h
@@ -0,0 +1,28 @@
+#ifndef NAPICONFIG_H
+#define NAPICONFIG_H
+
+#ifdef _WIN32
+#include <windows.h>
+#endif /* _WIN32 */
+
+#ifdef __VMS
+#include <nxconfig_vms.h>
+#else
+#include <nxconfig.h>
+#endif /* __VMS */
+
+
+/*
+ * Integer type definitions
+ * 
+ * int32_t etc will be defined by configure in nxconfig.h 
+ * if they exist; otherwise include an appropriate header
+ */
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif /* HAVE_STDINT_H */
+
+
+#endif /* NAPICONFIG_H */
diff --git a/include/napiu.h b/include/napiu.h
new file mode 100644
index 0000000..efc223f
--- /dev/null
+++ b/include/napiu.h
@@ -0,0 +1,72 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  NeXus Utility (NXU) Application Program Interface Header File
+  
+  Copyright (C) 2005 Freddie Akeroyd
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexus.anl.gov/>
+  
+  $Id$
+
+ ----------------------------------------------------------------------------*/
+  
+#ifndef NEXUSAPIU
+#define NEXUSAPIU
+
+#include "napi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern  NXstatus  NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* phone, const char* fax, const char* email);
+
+extern  NXstatus  NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class);
+
+extern NXstatus  NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[]);
+
+extern NXstatus  NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[]);
+
+extern NXstatus  NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units);
+
+extern NXstatus  NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units);
+
+extern NXstatus  NXUsetcompress(NXhandle file_id, int comp_type, int comp_size);
+
+extern NXstatus  NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class);
+
+extern NXstatus  NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index);
+
+extern NXstatus  NXUfinddata(NXhandle file_id, const char* data_name);
+
+extern NXstatus  NXUfindattr(NXhandle file_id, const char* attr_name);
+
+extern NXstatus  NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[]);
+
+extern NXstatus  NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[]);
+
+extern NXstatus  NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class);
+
+extern NXstatus  NXUresumelink(NXhandle file_id, NXlink group_id);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*NEXUSAPIU*/
+
diff --git a/include/nxconfig_h_cmake.in b/include/nxconfig_h_cmake.in
new file mode 100644
index 0000000..0aeba7d
--- /dev/null
+++ b/include/nxconfig_h_cmake.in
@@ -0,0 +1,37 @@
+/* $Id:$ */
+
+#cmakedefine HAVE_HDF4
+
+#cmakedefine HAVE_HDF5
+
+#cmakedefine HAVE_MXML
+
+#cmakedefine HAVE_FTIME
+
+#cmakedefine HAVE_TZSET
+
+#cmakedefine HAVE_STRDUP
+
+#cmakedefine01 HAVE_LIBREADLINE
+
+#cmakedefine01 HAVE_LONG_LONG_INT
+
+#cmakedefine01 HAVE_UNSIGNED_LONG_LONG_INT
+
+#cmakedefine01 HAVE_STDINT_H
+
+#cmakedefine01 HAVE_INTTYPES_H
+
+#define PRINTF_INT64			@PRINTF_INT64@
+
+#define PRINTF_UINT64			@PRINTF_UINT64@
+
+#define SIZEOF_VOIDP 			@CMAKE_SIZEOF_VOID_P@
+
+#define SIZEOF_INT 				@SIZEOF_INT@ 
+
+#define SIZEOF_LONG_INT 		@SIZEOF_LONG_INT@ 
+
+#define SIZEOF_LONG_LONG_INT 	@SIZEOF_LONG_LONG_INT@ 
+
+#define SIZEOF_SIZE_T 			@SIZEOF_SIZE_T@
diff --git a/include/nxconfig_vms.h b/include/nxconfig_vms.h
new file mode 100644
index 0000000..94acd66
--- /dev/null
+++ b/include/nxconfig_vms.h
@@ -0,0 +1,201 @@
+/* include/nxconfig.h.  Generated from nxconfig_h.in by configure.  */
+/* include/nxconfig_h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `df' library (-ldf). */
+/* #undef HAVE_LIBDF */
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+/* #undef HAVE_LIBDL */
+
+/* Define to 1 if you have the `hdf5' library (-lhdf5). */
+/* #undef HAVE_LIBHDF5 */
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+/* #undef HAVE_LIBJPEG */
+
+/* Define to 1 if you have the `m' library (-lm). */
+/* #undef HAVE_LIBM */
+
+/* Define to 1 if you have the `mfhdf' library (-lmfhdf). */
+/* #undef HAVE_LIBMFHDF */
+
+/* Define to 1 if you have the `rpc' library (-lrpc). */
+/* #undef HAVE_LIBRPC */
+
+/* Define to 1 if you have the `SystemStubs' library (-lSystemStubs). */
+/* #undef HAVE_LIBSYSTEMSTUBS */
+
+/* Define to 1 if you have the `sz' library (-lsz). */
+/* #undef HAVE_LIBSZ */
+
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+/* #undef HAVE_LIBXML2 */
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "nexus"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "nexus-developers at nexusformat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "NeXus Library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "NeXus Library trunk_r1077"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "nexus"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "trunk_r1077"
+
+/* Set to printf format for int64_t */
+#define PRINTF_INT64 "lld"
+
+/* Set to printf format for uint64_t */
+#define PRINTF_UINT64 "llu"
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long int', as computed by sizeof. */
+#define SIZEOF_LONG_INT 4
+
+/* The size of `long long int', as computed by sizeof. */
+#define SIZEOF_LONG_LONG_INT 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Version number of package */
+#define VERSION "trunk_r1077"
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to the type of a signed integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int16_t */
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int64_t */ 
+
+/* Define to the type of a signed integer type of width exactly 8 bits if such
+   a type exists and the standard includes do not define it. */
+/* #undef int8_t */
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint16_t  */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef  uint64_t */ 
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint8_t  */
+
diff --git a/include/nxxml.h b/include/nxxml.h
new file mode 100644
index 0000000..04ca7ab
--- /dev/null
+++ b/include/nxxml.h
@@ -0,0 +1,78 @@
+/*
+ * This is the header file for the NeXus XML file driver. 
+ *
+ *   Copyright (C) 2004 Mark Koennecke
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  For further information, see <http://www.nexusformat.org>
+ */
+#ifndef NEXUSXML
+#define NEXUSXML
+
+extern  NXstatus  NXXopen(CONSTCHAR *filename, 
+					    NXaccess access_method, 
+					    NXhandle* pHandle);
+extern  NXstatus  NXXclose(NXhandle* pHandle);
+extern  NXstatus  NXXflush(NXhandle* pHandle);
+
+NXstatus  NXXmakegroup (NXhandle fid, CONSTCHAR *name, 
+				     CONSTCHAR *nxclass);
+NXstatus  NXXopengroup (NXhandle fid, CONSTCHAR *name, 
+				     CONSTCHAR *nxclass);
+NXstatus  NXXclosegroup (NXhandle fid);
+
+NXstatus  NXXcompmakedata64 (NXhandle fid, CONSTCHAR *name, 
+					int datatype, 
+					int rank, 
+					int64_t dimensions[],
+					int compress_type, int64_t chunk_size[]);
+NXstatus  NXXmakedata64 (NXhandle fid, 
+				    CONSTCHAR *name, int datatype, 
+				    int rank, int64_t dimensions[]);
+NXstatus  NXXopendata (NXhandle fid, CONSTCHAR *name);
+NXstatus  NXXclosedata (NXhandle fid);
+NXstatus  NXXputdata (NXhandle fid, const void *data);
+NXstatus  NXXgetdata (NXhandle fid, void *data);
+NXstatus  NXXgetinfo64 (NXhandle fid, int *rank, 
+				   int64_t dimension[], int *iType);
+NXstatus  NXXputslab64 (NXhandle fid, const void *data, 
+				   const int64_t iStart[], const int64_t iSize[]);
+NXstatus  NXXgetslab64 (NXhandle fid, void *data, 
+				   const int64_t iStart[], const int64_t iSize[]);
+NXstatus  NXXputattr (NXhandle fid, CONSTCHAR *name, const void *data, 
+				   int datalen, int iType);
+NXstatus  NXXgetattr (NXhandle fid, char *name, 
+				   void *data, int* datalen, int* iType);
+
+NXstatus  NXXgetnextentry (NXhandle fid,NXname name, 
+					NXname nxclass, int *datatype);
+extern  NXstatus  NXXgetnextattr(NXhandle handle, 
+				NXname pName, int *iLength, int *iType);
+extern  NXstatus  NXXinitgroupdir(NXhandle handle);
+extern  NXstatus  NXXinitattrdir(NXhandle handle);
+extern  NXstatus  NXXgetattrinfo (NXhandle fid, int *iN);
+extern  NXstatus  NXXgetgroupinfo (NXhandle fid, int *iN, 
+					NXname pName, NXname pClass);
+
+extern NXstatus  NXXgetdataID (NXhandle fid, NXlink* sRes);
+extern NXstatus  NXXgetgroupID (NXhandle fid, NXlink* sRes);
+extern NXstatus  NXXmakelink (NXhandle fid, NXlink* sLink);
+extern NXstatus  NXXprintlink (NXhandle fid, NXlink* sLink);
+extern NXstatus  NXXsameID (NXhandle fileid, 
+					      NXlink* pFirstID, NXlink* pSecondID);
+
+void NXXassignFunctions(pNexusFunction fHandle);
+#endif
diff --git a/install_nexus_dep_rpm b/install_nexus_dep_rpm
new file mode 100755
index 0000000..edda0d8
--- /dev/null
+++ b/install_nexus_dep_rpm
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# $Id$
+#
+# Install additional libraries for NeXus
+#
+rpm -Uvh http://nexus.isis.rl.ac.uk/kits/rpm/szip-2.0-1.i386.rpm
+rpm -Uvh http://nexus.isis.rl.ac.uk/kits/rpm/hdf-4.2.1-1.i386.rpm
+rpm -Uvh http://nexus.isis.rl.ac.uk/kits/rpm/hdf5-1.6.4-1.i386.rpm
+rpm -Uvh http://nexus.isis.rl.ac.uk/kits/rpm/mxml-2.2.2-1.i386.rpm
+#
diff --git a/macosx_install_kit/Makefile.am b/macosx_install_kit/Makefile.am
new file mode 100644
index 0000000..b145937
--- /dev/null
+++ b/macosx_install_kit/Makefile.am
@@ -0,0 +1,37 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1251 2009-05-01 15:41:53Z Freddie Akeroyd $
+#  
+#  Makefile for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+EXTRA_DIST=build_mac_kit.sh pkg.config.in ReadMe.txt \
+	$(srcdir)/bin/*.sh \
+	Resources/postflight Resources/preflight \
+	Resources/English.lproj/background.jpg \
+	Resources/English.lproj/Conclusion.txt \
+	Resources/English.lproj/Description.plist \
+	Resources/English.lproj/License.txt \
+	Resources/English.lproj/ReadMe.txt \
+	Resources/English.lproj/Welcome.txt
diff --git a/macosx_install_kit/ReadMe.txt b/macosx_install_kit/ReadMe.txt
new file mode 100644
index 0000000..843bd1d
--- /dev/null
+++ b/macosx_install_kit/ReadMe.txt
@@ -0,0 +1,11 @@
+NeXus is a common data format for neutron, x-ray, and muon science. It is being developed as an international standard by scientists and programmers representing major scientific facilities in Europe, Asia, Australia, and North America in order to facilitate greater cooperation in the analysis and visualization of neutron, x-ray, and muon data.
+
+This package provides libraries for interacting with NeXus files, with bindings for C, C++, Fortran, Python, Java and IDL.
+
+NeXus is distributed under the LGPL licence; this binary is linked to 
+other packages that have different, but compatible, licences. For more
+information see the files in /usr/local/share/nexus
+  
+For futher information on NeXus see http://www.nexusformat.org/
+
+To begin the install, just double click on NeXus.pkg
diff --git a/macosx_install_kit/Resources/English.lproj/Conclusion.txt b/macosx_install_kit/Resources/English.lproj/Conclusion.txt
new file mode 100644
index 0000000..a5d0833
--- /dev/null
+++ b/macosx_install_kit/Resources/English.lproj/Conclusion.txt
@@ -0,0 +1,9 @@
+A note on pre-10.5 Macintosh
+
+You may need to add /Library/Python/2.5/site-packages to your python path.
+If you are using the python.org distribution of python-2.5 this is already 
+done for you.  Otherwise, add the following file to your site-packages
+directory:
+
+--Library_Python.pth--
+/Library/Python/2.5/site-packages
diff --git a/macosx_install_kit/Resources/English.lproj/Description.plist b/macosx_install_kit/Resources/English.lproj/Description.plist
new file mode 100644
index 0000000..5b70875
--- /dev/null
+++ b/macosx_install_kit/Resources/English.lproj/Description.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IFPkgDescriptionDescription</key>
+	<string>NeXus is a common data format for neutron, x-ray, and muon science. It is being developed as an international standard by scientists and programmers representing major scientific facilities in Europe, Asia, Australia, and North America in order to facilitate greater cooperation in the analysis and visualization of neutron, x-ray, and muon data.
+
+This package provides libraries for interacting with NeXus files, with bindings for C, C++, Fortran, Python, Java and IDL.</string>
+	<key>IFPkgDescriptionTitle</key>
+	<string>NeXus</string>
+</dict>
+</plist>
diff --git a/macosx_install_kit/Resources/English.lproj/License.txt b/macosx_install_kit/Resources/English.lproj/License.txt
new file mode 100644
index 0000000..a12246d
--- /dev/null
+++ b/macosx_install_kit/Resources/English.lproj/License.txt
@@ -0,0 +1,526 @@
+License Information
+-------------------
+
+The NeXus library and utilities are distributed under the terms on the GNU Lesser General Public License (LGPL) - see the enclosed COPYING_NeXus.txt file or http://www.opensource.org/licenses/lgpl-license.php for further details. The NeXus library is linked statically against several other libraries and these are detailed below. All licence files are installed in /usr/local/share/nexus
+
+* Michael Sweet's Mini-XML parsing library (http://www.easysw.com/~mike/mxml/) which is also governed by the LGPL.
+
+* HDF4 libraries developed at the National Center for Supercomputing Applications (NCSA) at the University of Illinois at Urbana-Champaign (http://hdf.ncsa.uiuc.edu/). Their distribution is covered by the license detailed in the enclosed COPYING_hdf4.txt file and at ftp://ftp.ncsa.uiuc.edu/HDF/HDF/HDF_Current/src/unpacked/COPYING 
+
+* HDF5 library developed at the National Center for Supercomputing Applications (NCSA) at the University of Illinois at Urbana-Champaign (http://hdf.ncsa.uiuc.edu/). Distribution is covered by the license detailed in the enclosed COPYING_hdf5.txt file and at ftp://ftp.ncsa.uiuc.edu/HDF/HDF5/current/src/unpacked/COPYING 
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
diff --git a/macosx_install_kit/Resources/English.lproj/ReadMe.txt b/macosx_install_kit/Resources/English.lproj/ReadMe.txt
new file mode 100644
index 0000000..33a19a9
--- /dev/null
+++ b/macosx_install_kit/Resources/English.lproj/ReadMe.txt
@@ -0,0 +1,379 @@
+Version 4.2.0
+=============
+
+For the latest information see 
+
+    http://www.nexusformat.org/Nexus_42_Release_Notes
+
+==System Requirements==
+'''MXML XML Parsing Library'''
+
+Version 2.2.2 or higher of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in [http://www.easysw.com/~mike/mxml/software.php both source and binary rpm form] and is also available as part of [http://fedoraproject.org/wiki/Extras/UsingExtras Fedora Extras]. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly.
+
+'''Python Interface'''
+You will need both the numpy and ctypes modules to be available.  These are provided in both the Fedora and EPEL repositories.
+
+==Building Notes==
+===NAG F90/F95 Compiler===
+The NAG compiler needs the '''-mismatch''' flag to be specified or else it will not compile NXmodule.f90 This is achieve by running configure with the '''FCFLAGS''' environment variable set to contain the flag e.g.
+<pre>
+env FCFLAGS="-mismatch" ./configure --with-f90=f95
+</pre>
+===HDF4 on Intel Macs===
+There is a problem with the include file, hdfi.h (normally in /usr/local/include).  See http://coastwatch.noaa.gov/helparc/software/msg00069.html for details of the modifications necessary to fix it.
+
+==New Features==
+===C++ Interface===
+See the [http://download.nexusformat.org/doxygen/html/classNeXus_1_1File.html doxygen documentation] and
+[http://svn.nexusformat.org/code/branches/4.2/test/napi_test_cpp.cxx NeXus API test program]
+
+===C++ Stream Like interface===
+The idea is to provide an IOSteam like interface and allow you to type 
+<pre>
+    // create an entry and a data item
+    File nf(fname, NXACC_CREATE);
+    nf << Group("entry1", "NXentry") << Data("dat1", w, "int_attr", 3);
+    nf.close();
+
+    File nf1(fname, NXACC_RDWR);
+    // add a double_attr to an existing setup
+    nf1 >> Group("entry1", "NXentry") >> Data("dat1") << Attr("double_attr", 6.0);
+    nf1.close();
+
+    // read back data items
+    File nf2(fname, NXACC_READ);
+    nf2 >> Group("entry1", "NXentry") >> Data("dat1", w1, "int_attr", i, "double_attr", d);
+    // alternative way to read d1
+    nf2 >> Data("dat1") >> Attr("double_attr", d1);
+</pre>
+See also the [http://svn.nexusformat.org/code/branches/4.2/test/napi_test_cpp.cxx NeXus API test program]
+
+===IDL Interface===
+There is a new interface to RSI's Interactive Data Language, IDL for NeXus. This 
+interface has to be considered beta. Nevertheless it is working most of the time. 
+Known issues include:
+* Compressed reading and writing do not work for HDF-4 files, probably because of a library version conflict on libz. 
+* There is an issue using NXgetslab on 64 bit operating systems; expect a fix for this pretty soon.
+
+===Python Interface===
+There is now, thanks to Paul Kienzle, a supported interface for the python scripting language. Arrays are stored in numpy arrays and thus allow for efficient data manipulations.
+
+==Changed Features==
+
+==Known Issues==
+See the comments on the IDL interface.
+
+==Miscellaneous bug fixes==
+The following items are bugs reported in previous releases and resolved in
+the 4.2 release.
+
+==Upcoming Features==
+
+Version 4.1.0
+=============
+
+For the latest information see 
+
+    http://www.nexusformat.org/Nexus_41_Release_Notes
+
+==System Requirements==
+'''MXML XML Parsing Library'''
+
+Version 2.2.2 or higher of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in [http://www.easysw.com/~mike/mxml/software.php both source and binary rpm form] and is also available as part of [http://fedoraproject.org/wiki/Extras/UsingExtras Fedora Extras]. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly.
+
+==Building Notes==
+===NAG F90/F95 Compiler===
+The NAG compiler needs the '''-mismatch''' flag to be specified or else it will not compile NXmodule.f90 This is achieve by running configure with the '''FCFLAGS''' environment variable set to contain the flag e.g.
+<pre>
+env FCFLAGS="-mismatch" ./configure --with-f90=f95
+</pre>
+===HDF4 on Intel Macs===
+There is a problem with the include file, hdfi.h (normally in /usr/local/include).  See http://coastwatch.noaa.gov/helparc/software/msg00069.html for details of the modifications necessary to fix it.
+
+==New Features==
+* New types NX_INT64 and NX_UINT64 to suppport 64 bit integers (only available in HDF5 and XML) [http://trac.nexusformat.org/code/ticket/87 details].
+* Python bindings are now included in the Windows install kit [http://trac.nexusformat.org/code/ticket/86 details]
+
+==Miscellaneous bug fixes==
+The following items are bugs reported in previous releases and resolved in
+the 4.1 release.
+* The Fortran 90 part of testsuite failed with the Absoft compiler on MacOSX (it passed with g95 and gfortran (4.2)) [http://trac.nexusformat.org/code/ticket/68 details here]
+* NXputattr assumed NULL termination of NX_CHAR attributes, which is usually the case in C but not true for JAVA. A workaround is to add '\0' manually [http://trac.nexusformat.org/code/ticket/83 bug report]
+* pkgconfig issue [http://trac.nexusformat.org/code/ticket/84 bug report]
+* Build issue with MXML-2.3 [http://trac.nexusformat.org/code/ticket/91 bug report]
+* XML buffer resizing performance issue [http://trac.nexusformat.org/code/ticket/92 bug report]
+* Documentation is now installed to "datadir" (/usr/share) [http://trac.nexusformat.org/code/ticket/93 bug report]
+
+Version 4.0.0
+=============
+
+For the latest information see 
+
+    http://www.nexusformat.org/Nexus_4_Release_Notes
+
+==System Requirements==
+'''MXML XML Parsing Library'''
+
+Version 2.2.2 of mxml is required. Earlier versions have a bug and the XML API will not work. This package can be downloded in [http://www.easysw.com/~mike/mxml/software.php both source and binary rpm form] and is also available as part of [http://fedoraproject.org/wiki/Extras/UsingExtras Fedora Extras]. IMPORTANT NOTE: Debian also provides the mxml package, but it based on 2.0 and will not work properly.
+
+==Building Notes==
+===NAG F90/F95 Compiler===
+The NAG compiler needs the '''-mismatch''' flag to be specified or else it will not compile NXmodule.f90 This is achieve by running configure with the '''FCFLAGS''' environment variable set to contain the flag e.g.
+<pre>
+env FCFLAGS="-mismatch" ./configure --with-f90=f95
+</pre>  
+==New Features==
+The following items are features added to the NeXus API to provide new
+functionality to the core library or to assist in the build process.
+*Extended XML-API to handle unlimited dimensions
+*Add building of Doxygen documentation
+*Add support for two dimensional character arrays (HDF4 and HDF5 only)
+*Added group attribute support to HDF4 (2006/05/02). Requires HDF4 version (???)
+*Add NXmakenamedlink (2007/01/09) to all three file formats (external linking)
+*Add NXprintlink
+*Improved link testing in test suite
+*API can now read generic HDF5 files, such as those produced by matlab
+*Add facility to enable/disable error reporting
+*New NXsummary tool for summarising contentes of a NeXus file
+*Fortran 90 API now works with gfortran 4.2 and above as well as with G95
+*PYTHON and TCL bindings provided via a [http://www.swig.org/ SWIG interface]
+*Additional NXtranslate translators: SPEC, ESRF-EDF
+
+==Changed Features==
+The following aspects of the API have changed in a potentially non-backward compatible way
+*The JAVA API now uses org.nexusformat rather than gov.anl.neutron.nexus
+
+==Known Issues==
+* The Fortran 90 part of testsuite fails with the Absoft compiler on MacOSX (it passes with g95 and gfortran (4.2)) [http://trac.nexusformat.org/code/ticket/68 details here]
+
+==Miscellaneous bug fixes==
+The following items are bugs reported in the 3.x releases and resolved for
+the 4.0 release.
+*Leading and trailing whitespace is stripped from char data on a read; this can be disabled by passing the NXACC_NOSTRIP option to NXopen
+*Fix problems with MXML (what problems?)
+*Improve test procedures when not all libraries are present
+*Correct sourcepath for javadoc
+*Updated makefiles for swig bindings (python, tcl)
+
+Changes in Version 3.0.0
+========================
+
+- GNU Autotools are now used for building the API and programs
+
+- XML files can be written by the NeXus API by specifying NXACC_XML to NXopen
+
+- The NXtoXML, NXtoNX4 and NXtoNX5 utilities have been combined into a single utility nxconvert. To make a DTD definition file use nxtodtd
+
+- New utilities nxdir and nxtranslate
+
+- g95 compiler supported by FORTRAN90 bindings. To specify another
+  compiler use the  --with-f90   option of configure
+
+Changes in Version 2.0.0
+========================
+
+- NeXus library updated to allow the reading and writing of HDF5 files
+  using the same API calls.  In creating a file, use NXACC_CREATE4 for
+  HDF4 and NXACC_CREATE5 for HDF5.  As long as both HDF4 and HDF5 
+  libraries are linked, the API will read both HDF4 and HDF5 files 
+  transparently.
+
+- The Makefiles have been reorganized to allow HDF4 and/or HDF5 files to 
+  be linked into the NeXus library, with compile and link options stored
+  in "makefile_options".
+
+- Rearranged the NeXus libraries so that libNeXus.a contains the standard
+  C and F77 interfaces and libNeXus90.a contains the C and F90 interfaces.
+
+- Added the routine NXsameID to the C interface to compare the ID of
+  NeXus groups and data sets.
+
+- Added NXtoXML and NXtoDTD, utilities that translate a NeXus file to 
+  XML, respectively with and without the data.  Note that NXtoDTD does not
+  produce a true XML DTD file.  Instead, it produces a metaDTD as defined
+  on the NeXus web pages (although it will lack proper annotation). 
+
+- Changed NXUmodule.f90 so that NXUfindaxis uses the two accepted methods
+  of defining dimension scales, i.e. adding the "axis" attribute to the
+  axis data or adding the "axes" attribute to the signal data
+
+Changes in Version 1.3.3
+========================
+
+- Added NXflush routine to flush data to the output file.
+
+- Added support for unlimited dimensions.
+
+- Used the NX_EXTERNAL macro to prefix callable NeXus functions and defined
+  this to do the appropriate DLL import/export operation on Windows.
+  README.WIN32 has been updated with instructions on how to make and
+  use a NEXUS.DLL.
+
+- NeXus errors now directed to MessageBox() in a Windows DLL.
+
+- Modified timezone selection to use difftime/gmtime method on all
+  systems except VMS 6.2 (where gmtime() always returns NULL).
+  
+- Corrected spurious overflow errors in NXGETCHARDATA.
+
+- Added some unix-style commands, e.g. ls, cd, cat, as equivalents of
+  standard commands in NXbrowse.
+
+Changes in Version 1.3.2
+========================
+
+- NXbrowse now reads a filename as command line argument and only prompts if
+  none is specified.
+
+- Added "dump <data_name> <file_name>" command to NXbrowse, which dumps a 
+  NeXus data array into an ASCII file.
+  
+- Added a toggle command to NXbrowse, called "byteaschar", which forces 
+  NX_INT8, NX_UINT8 variables to be printed as character strings.  This is 
+  for backward compatibility with files created before the definition of the
+  NX_CHAR data type.  8-byte global attributes will be treated as characters
+  when the program begins, but, after that, the default is to treat NX_INT8
+  and NX_UINT8's as integers.
+  
+- Introduced proper typecasts for dimensions in data access routines.  This 
+  is to correct problems with systems that do not have 4-byte int's.
+
+- Added in the CALLING_STYLE macro to napi.h to allow correct calling of the
+  FORTRAN interface under WINDOWS.  Corrected definition of NXcompress() on 
+  PC.
+  
+- Added README.WIN32 to distribution discussing WINDOWS-specific compilation.
+
+
+Changes in Version 1.3.1
+========================
+
+- Added NXgetgroupinfo, NXinitgroupdir, NXgetattrinfo, and NXinitattrdir
+  to the core C and F77 API's.  They were already present in the F90 API.
+
+- Updated the above routines in NXmodule.f90 so that they called the C
+  versions directly.  This removes the need for the F90 code to know the
+  internal details of the NXhandle C struct.
+
+- Released a new version of NXbrowse written in ISO C.  It is the version
+  that is now installed with the "make NXbrowse" command (on unix systems).
+  The ordering of array indices uses the C convention i.e. it is reversed
+  from the original F90 version.
+
+- Corrected the calculation of time zone offsets when compiled by
+  Metrowerks CodeWarrior for PowerPC Macs.
+
+Changes in Version 1.3.0
+========================
+
+- Added NXcompress to the C, F77, and F90 API's. Compression works only with
+  Release 3 of the HDF-4.1 libraries or better. Note: on my DigitalUnix 4.0D
+  installation I had to link against the jpeg library supplied with HDF 
+  directly due to a conflict with a system shared library. Replace -ljpeg
+  by $HDFROOT/lib/libjpeg.a.
+
+- Added NXUsetcompress to F90 utility API to set default compression 
+  parameters, and added call to NXcompress in NXUwritedata.
+
+- Changed attribute arguments in the F90 routine NXUwriteglobals to optional. 
+
+Changes in Version 1.2.1
+========================
+
+- Released NeXus API under the terms of the GNU Lesser General Public
+  License.
+
+Changes in Version 1.2.0
+========================
+
+- NXGETCHARDATA, NXGETCHARATTR, NXPUTCHARDATA and NXPUTCHARATTR added 
+  to Fortran 77 interface to correct problems with handling character data 
+  and attributes.
+
+- Reversed dimension order and adjusted starting indices in NXGETSLAB 
+  and NXPUTSLAB in Fortran 77 interface for improved compatibility with the 
+  C interface.
+
+- All SDSes created with the DFTAG_NDG tag, rather than DFTAG_SDG,
+  which is now deprecated by HDF.
+
+- Expanded number of NeXus routines and data types checked by the test 
+  programs "napi_test.c", "napif_test.f" and "NXtest.f90". 
+  
+- Excluded null terminator from string length check in REPLACE_STRING to
+  prevent error messages when the string is exactly the right length.
+
+- Added definitions of NX_MAXRANK (max. no. of dataset dimensions = 32) to 
+  and NX_MAXNAMELEN (max. length of dataset name = 64) to header files.
+
+- Made NXIReportError globally visible.
+
+- Improved determination of local time zone when writing the global file
+  attribute "file_time".
+
+- Added option to NXbrowse.f90 to allow display of individual array elements
+  of the specified index.
+
+- Added check for __ABSOFT macro in "napi.h" to make compatible with 
+  Absoft Pro Fortran for Linux.
+
+- Add __stdcall definition to C prototypes under WIN32 so they can link 
+  to FORTRAN. 
+
+Changes in Version 1.1.0
+========================
+
+- First appearance of the Fortran 90 API.
+
+- Added reading and writing of non-character attributes to the Fortran 77 
+  interface.
+
+- Corrected problems with linking groups by making NXgetgroupID 
+  and NXmakelink use the HDF tag/ref pair in NXlink structures.
+
+- Added VMS build file MAKE_VMS.COM.
+
+- Added NEXUS_VERSION CHARACTER constant to NAPIF.INC, with value as defined 
+  in napi.h.
+
+- Made the Fortran 77 interface treat both NX_UINT8 and NX_CHAR as strings, for
+  consistency with the C implementation and also for backward compatability 
+  reasons.
+
+- Fixed memory leak on Fortran 77 side on NXclose.
+
+- NXdict added to the normal distribution.
+
+- Added casts to HDF API calling parameters to eliminate type-mismatch
+  compiler warnings.
+
+- Modified time creation functions to handle non-working gmtime()
+  function on VMS 6.2. 
+
+
+Changes in Version 1.0.0
+========================
+
+- Reversed array dimensions on going from C to FORTRAN, so that the 
+  "fastest varying index" is kept consistent.
+
+- Incorporated fixes suggested by Markus Zolliker (markus.zolliker at psi.ch)
+  for the following problems with the FORTRAN interface:
+
+  (1) NXopen ends with a "Segmentation fault" if the file is not HDF.
+  (2) NXgetentry gives an error message when NAME and CLASS are not
+    initialised to blank.
+
+- Changed "data" from char* to void* in NXgetattr.
+
+- Changed value for NXACC_CREATE to be DFACC_CREATE rather than DFACC_ALL
+  in NAPIF.INC for consistency with C interface.
+
+- Added the following global attributes :
+  NeXus_version - updated whenever a file is opened "read/write", so it
+                  will always contain the latest version of the interface
+                  the file was written with
+  file_name     - set on file creation, then left unchanged
+  file_time     - set on file creation, then left unchanged
+
+$Id: NEWS 1228 2009-04-14 17:41:25Z Freddie Akeroyd $
diff --git a/macosx_install_kit/Resources/English.lproj/Welcome.txt b/macosx_install_kit/Resources/English.lproj/Welcome.txt
new file mode 100644
index 0000000..bb1e86c
--- /dev/null
+++ b/macosx_install_kit/Resources/English.lproj/Welcome.txt
@@ -0,0 +1,10 @@
+This installer will guide you through the steps necessary to 
+install the NeXus API for Mac OS 10.4 or higher on your machine. 
+This version is able to access HDF4, HDF5 and XML NeXus files.
+
+NeXus file utilities will be placed in /usr/local/bin, libraries 
+in /usr/local/include and /usr/local/lib, documentation and 
+examples in /usr/local/share and python bindings 
+in /Library/Python/2.5/site-packages.
+
+Licence information will be placed in /usr/local/share/nexus
diff --git a/macosx_install_kit/Resources/English.lproj/background.jpg b/macosx_install_kit/Resources/English.lproj/background.jpg
new file mode 100644
index 0000000..1863603
Binary files /dev/null and b/macosx_install_kit/Resources/English.lproj/background.jpg differ
diff --git a/macosx_install_kit/Resources/postflight b/macosx_install_kit/Resources/postflight
new file mode 100755
index 0000000..d2d164c
--- /dev/null
+++ b/macosx_install_kit/Resources/postflight
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Add /Library/Python/2.5/site-packages to the python site-packages path
+# This is necessary for pre-10.5 OS X where python is installed differently
+SITEPKGS=/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages
+if test -d $SITEPKGS; then
+    echo /Library/Python/2.5/site-packages > $SITEPKGS/Library_Python.pth
+fi
diff --git a/macosx_install_kit/Resources/preflight b/macosx_install_kit/Resources/preflight
new file mode 100755
index 0000000..bd5932d
--- /dev/null
+++ b/macosx_install_kit/Resources/preflight
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Xcode 2.5+ installer is broken and will create an infinite symlink
+# in /usr/local/lib.  We try to detect and fix this, becuase it
+# caused just too many failed installations.
+
+if [ -L /usr/local/lib -a -d /usr/local/lib\ 1 ]; then
+    # excuse me for being paranoid, but I want to make sure it's
+    # not some other (intentional) symlink that we are about to remove
+    if ls -l /usr/local/lib|grep '/usr/local/lib -> /usr/local/lib$' >/dev/null; then
+      	rm -f /usr/local/lib && mv /usr/local/lib\ 1 /usr/.local/lib
+    fi
+fi 
diff --git a/macosx_install_kit/bin/dmgpack.sh b/macosx_install_kit/bin/dmgpack.sh
new file mode 100755
index 0000000..ac39f29
--- /dev/null
+++ b/macosx_install_kit/bin/dmgpack.sh
@@ -0,0 +1,65 @@
+#! /bin/bash
+
+# dmgpack diskname [file|dir]+
+#
+#    Copy a group of files/directories to a compressed disk image.
+#    The resulting image is stored in diskname.dmg 
+#
+#    Files are copied with 'ditto' to preserve resource forks.  For
+#    convenience we also call FixupResourceForks after copying.  This
+#    allows you to use /Developer/Tools/SplitFork on your tree and 
+#    manipulate it with CVS, tar, etc.  Don't forget the -kb option 
+#    when adding or committing app and ._app files to CVS!
+#
+#    This command will fail if a volume of the given name is already
+#    mounted.  It could also fail if the size of the resource forks
+#    is large compared to the size of the data forks. Change the
+#    scale factor internally from 11/10 to a more appropriate number
+#    if it complains it is running out of space.
+#
+#    It is possible to add a license agreement to a dmg file.  See
+#    the "Software License Agreements for UDIFs" sdk available at
+#    http://developer.apple.com/sdk/index.html
+
+test $# -lt 2 && echo "usage: $0 diskname [file|dir]+" && exit 1
+#set -x
+NAME="${1%.dmg}" ; shift
+DISK=/tmp/dmgpack$$.dmg
+COMPRESSED="$NAME.dmg"
+VOLUME="$NAME"
+
+# compute needed image size; scale it by 10%
+SIZE=$(du -ck "$@" | tail -1 | sed -e 's/ *total//')
+SIZE=$(echo $SIZE*11/10 | bc)
+test $SIZE -lt 4200 && SIZE=4200
+
+# create the disk
+rm -f $DISK
+hdiutil create -size ${SIZE}k $DISK -layout NONE
+
+# create a file system on the disk; last line of output is
+# the device on which the disk was attached.
+DEVICE=$(hdiutil attach $DISK -nomount | tail -1)
+newfs_hfs -v "$VOLUME" $DEVICE
+
+# mount the file system
+mkdir $DISK-mount
+mount -t hfs $DEVICE $DISK-mount || (echo "mount $DISK-mount failed" && exit 1)
+
+# copy stuff to the disk and fixup resource forks
+for f in "$@"; do 
+    f=${f%/}		;# strip trailing /
+    dest="$DISK-mount/${f##*/}"
+    ditto -rsrc "$f" "$dest" 
+    test -d "$f" && /System/Library/CoreServices/FixupResourceForks "$dest"
+done
+
+# eject the disk
+umount $DISK-mount
+rmdir $DISK-mount
+hdiutil eject $DEVICE
+
+# compress the disk and make it read only
+rm -f "$COMPRESSED"
+hdiutil convert -format UDZO $DISK -imagekey zlib-level=9 -o "$COMPRESSED"
+rm -f $DISK
diff --git a/macosx_install_kit/bin/makepkg.sh b/macosx_install_kit/bin/makepkg.sh
new file mode 100755
index 0000000..68b499e
--- /dev/null
+++ b/macosx_install_kit/bin/makepkg.sh
@@ -0,0 +1,272 @@
+#!/bin/sh
+
+if test "$1" = "-?"; then
+    cat <<EOF
+Usage:
+
+  VERSION=major.minor RELEASE=.patch mkpkg.sh Config
+
+
+=== Config file ===
+
+The Package configuration file is a set of bash script defines 
+
+Required Keys
+  PACKAGE=""           Name of package file
+  BUNDLE=""            Bundle identifier such as org.nexusformat.napi
+  VERSION=""           Major.minor version number
+                       Use shell commands to extract the VERSION and RELEASE 
+                       from your source
+
+Optional Keys
+  ROOT="Root"          See Installed Files below
+  RESOURCES="Resources" See Resource Files below
+  RELEASE=""           Patch level such as ".2" or "rc1" or "a1"
+  COPYRIGHT=""         Name of copyright holder (ignored if not present)
+  YEAR="start-stop"    Use "2001-`date +%Y`" to go from 2001 to this year
+  InfoString="$VERSION$RELEASE, (C) $YEAR $COPYRIGHT"
+                       Package info
+  MajorVersion="VERSION up to the first dot"
+  MinorVersion="VERSION after the last dot"
+                       Major.Minor version number integers
+  BackgroundAlignment="center"
+                       Alignment of background picture, which should be one of
+                       center left right top bottom (top|bottom)(left|right)
+  BackgroundScaling="tofit"
+                       Scaling of background picture, which should be one of
+                       none proportional tofit
+  AuthorizationAction="NoAuthorization"
+                       Required authorization, which should be one of
+                       (Admin|Root|No)Authorization
+  RestartAction="NoRestart"
+                       Require restart?  Should be one of NoRestart Shutdown
+                       RecommendedRestart RequiredRestart RequiredLogout
+  DefaultLocation="/"  Default location
+  Relocatable=false    true if package is relocatable
+  FollowLinks=true     false if links should be replaced with file content
+  InstallFat=false     true if distributing development libraries
+  IsRequired=false     true if package is not optional
+  OverwritePermissions=false   
+                       true if you want to mess with system permissions
+  RootVolumeOnly=false
+                       true if you need to install on the root volume
+  UpdateInstalledLanguages=false
+                       true if only install resources for the current languages
+  AllowBackRev=false   true if old versions can replace new
+
+=== Installed Files ===
+
+The Root directory contains the complete package layout as expected from
+the install location.
+
+The ownership of all files will be changed to root and permissions to 
+world readable.  Make sure executables already have the executable bit set.
+
+=== Resource Files ===
+
+Resources contains install scripts and texts.  All resources are optional.
+
+Scripts can be run at various stages in the install process.  They should
+be named as follows:
+
+    preflight preinstall/preupgrade postinstall/postupgrade postflight
+
+Within the script files, the following are defined:
+     
+   $1: package source directory
+       e.g., /Volumes/Users/michelle/Desktop/Levon.pkg
+   $2: installation destination  
+       e.g., /Applications
+   $3: destination volume  
+       e.g., /Volumes/Tools  or  /
+   $4: system root directory
+       e.g., /
+   $PACKAGE_PATH: package source directory
+       = $1
+   $SCRIPT_NAME: currently running script
+       e.g., preflight
+   $INSTALLER_TEMP: working directory
+       e.g., /private/tmp/.Levon.pkg.897.install
+   $RECEIPT_PATH: directory containing the script
+       e.g., $INSTALLER_TEMP/Receipts/Levon.pkg/Contents/Resources
+    
+Be sure to mark the scripts as executables.
+
+Texts can be in the Resources directory for the package, or in a language
+specific subdirectory such as English.proj. The texts include:
+
+   Welcome.{rtf,rtfd,html,txt} - first page of the installer
+   Readme.{rtf,rtfd,html,txt}  - second page of the installer
+   License.{rtf,rtfd,html,txt} - license description
+   Conclusion.{rtf,rtfd,html,txt} - final page 
+   Description.plist  - package description (see below)
+   Background.{tiff,jpg,gif,pict,eps,pdf} - installer image
+
+Description.plist is a property list which should contain keys for
+IFPkgDescriptionTitle and IFPkgDescriptionVersion
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd ">
+<plist version="1.0">
+<dict>
+   <key>IFPkgDescriptionTitle</key>
+   <string> insert title here </string>
+   <key>IFPkgDescriptionDescription</key>
+   <string> insert description here </string>
+</dict>
+</plist>
+
+=== References ===
+
+  Software Delivery Guide - Managed Installs
+  http://developer.apple.com/documentation/DeveloperTools/Conceptual/SoftwareDistribution/Managed_Installs/Managed_Installs.htm
+
+  PackageMaker How-to
+  http://s.sudre.free.fr/Stuff/PackageMaker_Howto.html
+
+  Installer Keys
+  http://developer.apple.com/documentation/DeveloperTools/Conceptual/SoftwareDistribution4/Concepts/sd_pkg_flags.html
+
+EOF
+    exit
+fi
+
+
+function err { echo $* && exit; }
+test -n "$1" || err "usage: makepkg [-? | pkg.config]"
+source $1
+test -n "$PACKAGE" -a -n "$VERSION" -a -n "$BUNDLE" || err "required keywords missing. use 'makepkg -?' for help"
+
+# Check that sources exist
+: ${ROOT:=Root}
+: ${RESOURCES:=Resources}
+
+test -d "$ROOT" -a -d "$RESOURCES" || err "need to create $ROOT and $RESOURCES"
+
+# Prepare package directory, removing existing package directory first
+test -d "$PACKAGE.pkg" && rm -rf "$PACKAGE.pkg"
+target="$PACKAGE.pkg/Contents"
+echo "creating $target"
+mkdir -p "$target"
+cp -Rpv $RESOURCES "$target/Resources"
+echo "Purging .svn directories from $target"
+find -d "$target" -type d -name ".svn" -exec rm -fr "{}" \; -print
+
+# Purge .DS_STORE; protect against spaces if filename
+echo "Purging .DS_Store files from install files (requires root) ..."
+find "$ROOT" -name ".DS_Store" | sed '-es/^/sudo rm -f "/;s/$/"/' | sh
+
+# Reset permissions on the distribution files
+echo "Setting permissions on install files (requires root) ..."
+set -x
+# Files readable by everybody, writable by ownder
+sudo chmod -R a+r,go-w $ROOT/*
+# Extend executable bit to all users; protect against spaces in filename
+find "$ROOT" -perm +u=x | sed '-es/^/sudo chmod a+x "/;s/$/"/' | sh
+# Most directories are owned by root:admin
+sudo chown -R root:admin $ROOT/*
+# /usr directory is owned by root:wheel
+test -d $ROOT/usr && sudo chown -R root:wheel $ROOT/usr
+# Turn on sticky bit for /Library directory
+test -d $ROOT/Library && sudo chmod u+t $ROOT/Library
+set +x
+
+# Build the archives and bill of materials
+echo "building archives"
+( cd $ROOT; pax -w . | gzip -9 -c ) > "$target/Archive.pax.gz"  || err "Could not create pax"
+mkbom $ROOT "$target/Archive.bom" || err "Could not create bom"
+
+SIZE=`du -sk $ROOT | sed -e"s,^\([0-9]*\)[^0-9].*$,\1,"`
+# Build the Info.plist file
+: ${RELEASE:=}
+: ${BundleIdentifier:=$BUNDLE}
+: ${BackgroundAlignment:=left}
+: ${BackgroundScaling:=none}
+: ${AllowBackRev:=false}
+: ${AuthorizationAction:=NoAuthorization}
+: ${DefaultLocation:=/}
+: ${Relocatable:=false}
+: ${FollowLinks:=true}
+: ${InstallFat:=false}
+: ${IsRequired:=false}
+: ${RestartAction:=NoRestart}
+: ${OverwritePermissions:=false}
+: ${RootVolumeOnly:=false}
+: ${UpdateInstalledLanguages:=false}
+if test -z "$InfoString"; then
+    : ${YEAR:=`date +%Y`}
+    InfoString="$VERSION$RELEASE, (c) $YEAR $COPYRIGHT"
+    test -z "$YEAR" -a -z "$COPYRIGHT" && InfoString="$VERSION$RELEASE"
+fi
+: ${InstalledSize:=${SIZE}}
+: ${MajorVersion:=${VERSION%.*}}
+: ${MinorVersion:=${VERSION#*.}}
+: ${ShortVersionString:=$VERSION$RELEASE}
+
+cat <<EOF >"$target/Info.plist"
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleGetInfoString</key>
+	<string>$InfoString</string>
+	<key>CFBundleIdentifier</key>
+	<string>$BundleIdentifier</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$ShortVersionString</string>
+	<key>IFMajorVersion</key>
+	<integer>$MajorVersion</integer>
+	<key>IFMinorVersion</key>
+	<integer>$MinorVersion</integer>
+	<key>IFPkgFlagAllowBackRev</key>
+	<$AllowBackRev/>
+	<key>IFPkgFlagAuthorizationAction</key>
+	<string>$AuthorizationAction</string>
+	<key>IFPkgFlagBackgroundAlignment</key>
+	<string>$BackgroundAlignment</string>
+	<key>IFPkgFlagBackgroundScaling</key>
+	<string>$BackgroundScaling</string>
+	<key>IFPkgFlagDefaultLocation</key>
+	<string>$DefaultLocation</string>
+	<key>IFPkgFlagFollowLinks</key>
+	<$FollowLinks/>
+	<key>IFPkgFlagInstallFat</key>
+	<$InstallFat/>
+	<key>IFPkgFlagInstalledSize</key>
+	<integer>$InstalledSize</integer>
+	<key>IFPkgFlagIsRequired</key>
+	<$IsRequired/>
+	<key>IFPkgFlagOverwritePermissions</key>
+	<$OverwritePermissions/>
+	<key>IFPkgFlagRelocatable</key>
+	<$Relocatable/>
+	<key>IFPkgFlagRestartAction</key>
+	<string>$RestartAction</string>
+	<key>IFPkgFlagRootVolumeOnly</key>
+	<$RootVolumeOnly/>
+	<key>IFPkgFlagUpdateInstalledLanguages</key>
+	<$UpdateInstalledLanguages/>
+	<key>IFPkgFormatVersion</key>
+	<real>0.10000000149011612</real>
+</dict>
+</plist>
+EOF
+
+# Create PkgInfo file, etc
+echo pmkrpkg1 > "$target/PkgInfo"
+cat <<EOF > "$target/Resources/package_version"
+major: $MajorVersion
+minor: $MinorVersion
+EOF
+cat <<EOF > "$target/Resources/BundleVersions.plist"
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>
+EOF
+
+# Set permissions on the package files
+chmod -R a+r,a-w "$target"
+(cd "$target" && find . -perm +u=x | xargs chmod a+x)
+(cd "$target" && find . -type d | xargs chmod u+w)
diff --git a/macosx_install_kit/build_mac_kit.sh b/macosx_install_kit/build_mac_kit.sh
new file mode 100755
index 0000000..15f4dd1
--- /dev/null
+++ b/macosx_install_kit/build_mac_kit.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# at the moment hdf4 only support -arch i386 -arch ppc 
+# and nexus tests fail if hdf5 is build with -arch x86_64 -arch ppc64
+# so leave as just "-arch i386 -arch ppc" for the moment
+
+
+echo "Removing old package root (require root privileges)"
+test -d package_root && sudo rm -fr package_root
+
+cd ..
+echo "Building NeXus"
+make distclean # needed as we disable dependency tracking
+arch_flags="-arch i386 -arch ppc"
+export MACOSX_DEPLOYMENT_TARGET=10.4
+env CFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk $arch_flags" \
+    CXXFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk $arch_flags" \
+    LDFLAGS="-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk $arch_flags" \
+    ./configure --with-hdf4=/usr/local/hdf4.2r4 \
+    --with-hdf5=/usr/local/hdf5-1.8.2 --with-python \
+    --disable-dependency-tracking
+make
+make install DESTDIR=`pwd`/macosx_install_kit/package_root
+cp InstallerBits/Licences/*.txt macosx_install_kit/package_root/usr/local/share/nexus
+
+cd macosx_install_kit
+
+# Use pkg.config to fetch the package name and version number
+. pkg.config
+rm -rf "$PACKAGE.pkg" "$PACKAGE-$VERSION$RELEASE"
+
+cp ../NEWS Resources/English.lproj/ReadMe.txt
+
+echo "Building the package (requires root to set permissions)"
+ROOT=package_root bin/makepkg.sh pkg.config
+
+echo "Building the disk image"
+bin/dmgpack.sh "$PACKAGE-$VERSION$RELEASE" ReadMe.txt "$PACKAGE.pkg"
+
+echo "Enabling internet install"
+hdiutil internet-enable -yes "$PACKAGE-$VERSION$RELEASE.dmg"
+
+echo "Cleaning NeXus build (as we configured without dependency tracing)"
+( cd ..; make distclean; ) > /dev/null
+
+echo "Removing temporary files (requires root to clear)"
+#sudo rm -fr package_root
+#rm -rf "$PACKAGE.pkg"
diff --git a/macosx_install_kit/pkg.config.in b/macosx_install_kit/pkg.config.in
new file mode 100644
index 0000000..70885f9
--- /dev/null
+++ b/macosx_install_kit/pkg.config.in
@@ -0,0 +1,15 @@
+# This file contains definitions required to fill out the
+# Info.plist of the NeXus package.  It is sourced as part
+# of bin/makepkg.sh during build_mac_kit.sh
+PACKAGE="NeXus"
+BUNDLE="org.nexusformat.napi"
+COPYRIGHT="NeXus International Advisory Committee"
+YEAR="1999-`date +%Y`"
+AuthorizationAction="AdminAuthorization"
+InstallFat="true"
+BackgroundAlignment="bottomleft"
+
+# The following grabs VERSION=x.y and RELEASE=.z
+nx_version=@PACKAGE_VERSION@
+RELEASE=.${nx_version#*.*.}
+VERSION=${nx_version%.*}
diff --git a/make_mingw_links b/make_mingw_links
new file mode 100755
index 0000000..9270782
--- /dev/null
+++ b/make_mingw_links
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# $Id$
+#
+# Create links needed by MinGW to various libraries that exist on
+# the windows file system. The basic idea is that we link in the Windows
+# installed versions of these libraries and make then look like 
+# standard unix libraries for configure to pick up. An alternative would be
+# to build the HDF etc. libraries from source under MinGW
+#
+# first create the /usr/local hierarchy 
+#
+for i in /usr/local /usr/local/include /usr/local/bin /usr/local/lib \
+         /usr/local/hdf4 /usr/local/hdf4/lib \
+         /usr/local/hdf5 /usr/local/hdf5/lib ; do
+    [ -d $i ] || mkdir $i
+done
+#
+### BEGIN USER CONFIGURATION ###
+#
+# CHANGE THESE TO THE LOCATIONS OF THE VARIOUS LIBRARIES
+# ON THE WINDOWS SYSTEM
+#
+# For Mini-XML you should download the source from 
+# http://www.easysw.com/~mike/mxml/ and then compile directly 
+# under MinGW to install the library into /usr/local/lib
+#
+# HDF4 windows binary install (from http://hdf.ncsa.uiuc.edu)
+#
+ln -sf "/c/program files/hdf/42r1-win/release/include" /usr/local/hdf4/include
+ln -sf "/c/program files/hdf/42r1-win/release/dll/hd421m.dll" /usr/local/hdf4/lib/libdf.dll
+ln -sf "/c/program files/hdf/42r1-win/release/dll/hm421m.dll" /usr/local/hdf4/lib/libmfhdf.dll
+#
+# HDF5 windows binary install  (from http://hdf.ncsa.uiuc.edu)
+#
+ln -sf "/c/program files/hdf/5-165-win/include" /usr/local/hdf5/include
+ln -sf "/c/program files/hdf/5-165-win/dll/hdf5dll.dll" /usr/local/hdf5/lib/libhdf5.dll
+#
+# ZLIB (from http://www.gzip.org/zlib/)
+#
+ln -sf "/c/program files/hdf/zlib122-windows/zlib1.dll" /usr/local/lib/libz.dll
+#
+# SZIP from http://hdf.ncsa.uiuc.edu/
+#
+ln -sf "/c/program files/hdf/szip20-win-xp-noenc/dll/szlibdll.dll" /usr/local/lib/libsz.dll
+#
+# LIBXML2 (optional; only needed for NXtranslate) from http://xmlsoft.org/
+#
+ln -sf "/c/program files/libxml2-2.6.20.win32/bin/libxml2.dll" /usr/local/lib/libxml2.dll
+ln -sf "/c/program files/libxml2-2.6.20.win32/include/libxml" /usr/local/include/libxml
+#
+# LIBICONV (optional; only needed for NXtranslate)
+#
+ln -sf "/c/program files/iconv-1.9.1.win32/include/iconv.h" /usr/local/include/iconv.h
+ln -sf "/c/program files/iconv-1.9.1.win32/bin/iconv.dll" /usr/local/lib/libiconv.dll
+#
+### END OF USER CONFIGURATION ###
+#
diff --git a/nexus_spec.in b/nexus_spec.in
new file mode 100644
index 0000000..35a2de1
--- /dev/null
+++ b/nexus_spec.in
@@ -0,0 +1,222 @@
+# @configure_input@
+# $Id$
+# Template for NeXus RPM SPEC file
+# Copyright (C) 2004 Freddie Akeroyd <freddie.akeroyd at stfc.ac.uk>
+#
+Summary: Libraries and utilities for using NeXus format data files
+Name: @PACKAGE_TARNAME@
+Version: @NEXUS_VERSION@
+# Release is the number of times this version of the software was 
+# built into an RPM file; it should be incremented each RPM build and
+# then reset to 1 when a new version of the software is released
+%if "@NEXUS_RELEASE@" == ""
+%else
+%define nexusrelease . at NEXUS_RELEASE@
+%endif
+Release: @PACKAGE_RELEASE@%{?nexusrelease}%{?dist}
+License: LGPL
+# Group: there is more than one choice for this - maybe we need to split
+# nexus into separate packages (libraries + apps)
+Group: Development/Libraries
+#Group: Development/Tools
+Source: http://download.nexusformat.org/kits/@PACKAGE_TARNAME@-@PACKAGE_VERSION@.tar.gz
+URL: http://www.nexusformat.org/
+Distribution: @DISTRIBUTION@
+#Icon: nexus.xpm
+Vendor: NeXus International Advisory Committee (NIAC)
+Packager: NeXus Developers <nexus-developers at nexusformat.org>
+# Prefix allows our package to be relocatable i.e. installable in 
+# other than just the /usr/local directory
+#Prefix: /usr
+# BuildRoot is the root for software installation
+# this value will not usually be used, but something must
+# be specified here to allow   rpm --buildroot   to be used later
+# (it will get used for a   rpmbuild --recompile  of the the src.rpm)
+%if 0%{?rhel} == 5
+%define is_rhel5 1
+%endif
+%if 0%{?el5}
+%define is_rhel5 1
+%endif
+%if "0%{?dist}" == "0.el5"
+%define is_rhel5 1
+%endif
+
+%if 0%{?rhel} == 6
+%define is_rhel6 1
+%endif
+%if 0%{?el6}
+%define is_rhel6 1
+%endif
+%if "0%{?dist}" == "0.el6"
+%define is_rhel6 1
+%endif
+
+BuildRoot: %{_tmppath}/@PACKAGE_TARNAME at -@PACKAGE_VERSION@
+BuildRequires: python numpy
+BuildRequires: hdf5-devel hdf-devel 
+BuildRequires: libxml2-devel
+#BuildRequires: java-1.6.0-openjdk-devel
+BuildRequires: readline-devel
+# mxml is not in rhel or epel as yet
+# ant on rhel5 is too old to build NXvalidate
+%if 0%{?fedora}
+BuildRequires: mxml-devel
+BuildRequires: ant
+%endif
+%if 0%{?is_rhel5}
+BuildRequires: python-ctypes
+%endif
+%if 0%{?is_rhel6}
+BuildRequires: ant ant-nodeps
+%endif
+
+%description
+NeXus is an international standard for exchanging data files
+among Neutron, Muon and X-ray science facilities. The underlying
+data is stored using the HDF format from NCSA. This package provides
+access routines, documentation, examples and a basic NeXus file browser.
+
+%package devel
+Summary: Libraries and utilities for using NeXus format data files
+Group: Development/Libraries
+
+%description devel
+NeXus is an international standard for exchanging data files
+among Neutron, Muon and X-ray science facilities. The underlying
+data is stored using the HDF format from NCSA. This package provides
+
+%package tools
+Summary: Libraries and utilities for using NeXus format data files
+Group: Development/Libraries
+
+%description tools
+NeXus is an international standard for exchanging data files
+among Neutron, Muon and X-ray science facilities. The underlying
+data is stored using the HDF format from NCSA. This package provides
+
+%package doc
+Summary: Libraries and utilities for using NeXus format data files
+Group: Development/Libraries
+
+%description doc
+NeXus is an international standard for exchanging data files
+among Neutron, Muon and X-ray science facilities. The underlying
+data is stored using the HDF format from NCSA. This package provides
+
+ at HAVE_PYTHON_TRUE@%package python
+ at HAVE_PYTHON_TRUE@Summary: Libraries and utilities for using NeXus format data files
+ at HAVE_PYTHON_TRUE@Group: Development/Libraries
+ at HAVE_PYTHON_TRUE@
+ at HAVE_PYTHON_TRUE@%description python
+ at HAVE_PYTHON_TRUE@NeXus is an international standard for exchanging data files
+ at HAVE_PYTHON_TRUE@among Neutron, Muon and X-ray science facilities. The underlying
+ at HAVE_PYTHON_TRUE@data is stored using the HDF format from NCSA. This package provides
+
+ at HAVE_JAVAC_TRUE@%package java
+ at HAVE_JAVAC_TRUE@Summary: Libraries and utilities for using NeXus format data files
+ at HAVE_JAVAC_TRUE@Group: Development/Libraries
+ at HAVE_JAVAC_TRUE@
+ at HAVE_JAVAC_TRUE@%description java
+ at HAVE_JAVAC_TRUE@NeXus is an international standard for exchanging data files
+ at HAVE_JAVAC_TRUE@among Neutron, Muon and X-ray science facilities. The underlying
+ at HAVE_JAVAC_TRUE@data is stored using the HDF format from NCSA. This package provides
+
+%prep
+%setup -q -n @PACKAGE_TARNAME at -@PACKAGE_VERSION@
+
+%build
+# RPM_INSTALL_PREFIX - where to install software
+# do --prefix last in case also present in passed config options
+if ! test -z "$RPM_INSTALL_PREFIX"; then
+    ./configure %{?nexus_config_options} --prefix="$RPM_INSTALL_PREFIX"
+else
+    ./configure %{?nexus_config_options} --prefix=%{_prefix} --libdir=%{_libdir}
+fi
+make
+
+%install
+# RPM_BUILD_ROOT is where to install software to
+if test "$RPM_BUILD_ROOT" != "/"; then rm -fr "$RPM_BUILD_ROOT"; fi
+make DESTDIR="$RPM_BUILD_ROOT" install
+find "$RPM_BUILD_ROOT" -name '*.la' -exec rm -f {} \;
+
+%files
+%defattr(-,root,root)
+%doc README NEWS ChangeLog AUTHORS COPYING INSTALL
+# %docdir /usr/local/doc
+%{_libdir}/libNeXus*.so*
+%{_libdir}/libnxconvert*.so*
+#%ifarch x86_64
+#/usr/lib/*.so*
+#%endif
+
+%files devel
+%defattr(-,root,root)
+%{_libdir}/libNeXus*.a
+%{_libdir}/libnxconvert*.a
+%{_libdir}/pkgconfig
+%{_includedir}/*
+
+%files tools
+%defattr(-,root,root)
+%{_bindir}/*
+%{_datadir}/man
+
+%files doc
+%defattr(-,root,root)
+%{_datadir}/nexus
+
+ at HAVE_PYTHON_TRUE@%files python
+ at HAVE_PYTHON_TRUE@%defattr(-,root,root)
+ at HAVE_PYTHON_TRUE@/usr/lib/python*/site-packages/nxs
+
+ at HAVE_JAVAC_TRUE@%files java
+ at HAVE_JAVAC_TRUE@%defattr(-,root,root)
+ at HAVE_JAVAC_TRUE@%{_datadir}/java
+ at HAVE_JAVAC_TRUE@%{_libdir}/libjnexus.so*
+ at HAVE_JAVAC_TRUE@%{_libdir}/libjnexus.a
+
+%clean
+if test "$RPM_BUILD_ROOT" != "/"; then rm -fr "$RPM_BUILD_ROOT"; fi
+
+%post
+if test `whoami` = root; then ldconfig; fi
+
+%post tools
+if [ "$RPM_INSTALL_PREFIX" != "" ]; then
+    INSTALL_PREFIX=$RPM_INSTALL_PREFIX
+else
+    INSTALL_PREFIX=%{_prefix}
+fi
+
+( cd $INSTALL_PREFIX/bin; for i in nxbuild; do \
+  sed -i -e "s|^prefix=.*|prefix=$INSTALL_PREFIX|" $i; done )
+
+%postun
+if test `whoami` = root; then ldconfig; fi
+#
+# %changelog date format as per  `date +"%a %d %b %Y"`
+# first line should be   date  user  email
+%changelog
+* Sat Oct 22 2011 Freddie Akeroyd <freddie.akeroyd at stfc.ac.uk> - 4.3.0
+- Split into subpackages
+* Thu May 24 2007 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk> - 4.0.0
+- Tag and build 4.0.0
+* Wed May 16 2007 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk> - 4.0rc3
+- Tag and build 4.0rc3
+* Fri Mar 30 2007 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk> - 4.0rc2
+- Tag and build 4.0rc2
+* Thu Mar 15 2007 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk> - 4.0rc1
+- Tag and build 4.0rc1
+* Wed Jul 27 2005 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+- Change Copyright: to License: and add PACKAGE_RELEASE
+* Mon Jun  6 2005 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+- Add extra documentation and example files to distribution
+* Wed May 12 2004 Jens Krueger <jens.krueger at frm2.tum.de>
+- Change the License entry to LGPL
+- remove /usr/local/nexus /usr/local/doc from the file list
+* Wed Mar 24 2004 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+- Fix up prefix in nxbuild after an install so the RPM is now relocatable
+* Sun Feb 22 2004 Freddie Akeroyd <F.A.Akeroyd at rl.ac.uk>
+- Initial RPM kit version
diff --git a/nsis_install.nsh b/nsis_install.nsh
new file mode 100644
index 0000000..6ba40d0
--- /dev/null
+++ b/nsis_install.nsh
@@ -0,0 +1,9 @@
+;;;;;;;;; !include "EnvVarUpdate.nsh"
+${EnvVarUpdate} $0 "NEXUSDIR" "A" "HKLM" "$INSTDIR"
+${EnvVarUpdate} $0 "NEXUSDIR${NEXUSDIRENVSUFFIX}" "A" "HKLM" "$INSTDIR"
+${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin"
+${EnvVarUpdate} $0 "LIB" "A" "HKLM" "$INSTDIR\lib"
+${EnvVarUpdate} $0 "INCLUDE" "A" "HKLM" "$INSTDIR\include"
+${EnvVarUpdate} $0 "PYTHONPATH" "A" "HKLM" "$INSTDIR\python"
+${EnvVarUpdate} $0 "PYTHONPATH" "A" "HKLM" "$INSTDIR\bin"
+${EnvVarUpdate} $0 "CLASSPATH" "A" "HKLM" "$INSTDIR\java\jnexus.jar"
\ No newline at end of file
diff --git a/nsis_uninstall.nsh b/nsis_uninstall.nsh
new file mode 100644
index 0000000..8da92be
--- /dev/null
+++ b/nsis_uninstall.nsh
@@ -0,0 +1,9 @@
+;;;;;;;; !include "EnvVarUpdate.nsh"
+${un.EnvVarUpdate} $0 "NEXUSDIR" "R" "HKLM" "$INSTDIR"
+${un.EnvVarUpdate} $0 "NEXUSDIR${NEXUSDIRENVSUFFIX}" "R" "HKLM" "$INSTDIR"
+${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin"
+${un.EnvVarUpdate} $0 "LIB" "R" "HKLM" "$INSTDIR\lib"
+${un.EnvVarUpdate} $0 "INCLUDE" "R" "HKLM" "$INSTDIR\include"
+${un.EnvVarUpdate} $0 "PYTHONPATH" "R" "HKLM" "$INSTDIR\python"
+${un.EnvVarUpdate} $0 "PYTHONPATH" "R" "HKLM" "$INSTDIR\bin"
+${un.EnvVarUpdate} $0 "CLASSPATH" "R" "HKLM" "$INSTDIR\java\jnexus.jar"
\ No newline at end of file
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
new file mode 100644
index 0000000..c60b380
--- /dev/null
+++ b/scripts/Makefile.am
@@ -0,0 +1,10 @@
+pkgconfigdir		= ${libdir}/pkgconfig
+nodist_bin_SCRIPTS 	= nxbuild nexus-config
+
+EXTRA_DIST		= nxbuild.in nexus.pc.in nexus-cpp.pc.in nexus-config.in
+
+pkgconfig_DATA		= nexus.pc
+
+if HAVE_CPP
+pkgconfig_DATA		+= nexus-cpp.pc
+endif
diff --git a/scripts/nexus-config.in b/scripts/nexus-config.in
new file mode 100755
index 0000000..3556b39
--- /dev/null
+++ b/scripts/nexus-config.in
@@ -0,0 +1,35 @@
+#!/bin/sh
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#
+#  @configure_input@
+#  
+#  Script for building NeXus applications
+#
+#  Copyright (C) 2010 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+#====================================================================
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+
+env PKG_CONFIG_PATH=${libdir}/pkgconfig pkg-config $* nexus
diff --git a/scripts/nexus-cpp.pc.in b/scripts/nexus-cpp.pc.in
new file mode 100644
index 0000000..9e60508
--- /dev/null
+++ b/scripts/nexus-cpp.pc.in
@@ -0,0 +1,14 @@
+#
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name:@PACKAGE_NAME@ CPP bindings
+Description:Libraries and utilities for using NeXus format data files from C++
+Version:@PACKAGE_VERSION at -@PACKAGE_RELEASE@
+Requires:
+Conflicts:
+Libs:	-L${libdir} -lNeXusCPP -lNeXus
+Libs.private:	@HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ @LIBS@
+Cflags:	-I${includedir}/nexus -I${includedir}
diff --git a/scripts/nexus.pc.in b/scripts/nexus.pc.in
new file mode 100644
index 0000000..2277272
--- /dev/null
+++ b/scripts/nexus.pc.in
@@ -0,0 +1,14 @@
+#
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name:@PACKAGE_NAME@
+Description:Libraries and utilities for using NeXus format data files
+Version:@PACKAGE_VERSION at -@PACKAGE_RELEASE@
+Requires:
+Conflicts:
+Libs:	-L${libdir} -lNeXus
+Libs.private:	@HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ @LIBS@
+Cflags:	-I${includedir}/nexus -I${includedir}
diff --git a/scripts/nxbuild.in b/scripts/nxbuild.in
new file mode 100644
index 0000000..e1d074c
--- /dev/null
+++ b/scripts/nxbuild.in
@@ -0,0 +1,109 @@
+#!/bin/sh
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#
+#  @configure_input@
+#  
+#  Script for building NeXus applications
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+SHELL="@SHELL@"
+srcdir="@srcdir@"
+top_srcdir="@top_srcdir@"
+VPATH="@srcdir@"
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+bindir="@bindir@"
+sbindir="@sbindir@"
+libexecdir="@libexecdir@"
+datadir="@datadir@"
+datarootdir="@datarootdir@"
+libdir="@libdir@"
+infodir="@infodir@"
+mandir="@mandir@"
+includedir="@includedir@"
+#pkgdatadir=$(datadir)/@PACKAGE@
+#pkglibdir=$(libdir)/@PACKAGE@
+#pkgincludedir=$(includedir)/@PACKAGE@
+#top_builddir=..
+host_alias="@host_alias@"
+host_triplet="@host@"
+CC="@CC@"
+F77="@F77@"
+F90="@F90@"
+F90FLAGS="@F90FLAGS@"
+H4ROOT="@H4ROOT@"
+H5ROOT="@H5ROOT@"
+PACKAGE="@PACKAGE@"
+RANLIB="@RANLIB@"
+STRIP="@STRIP@"
+VERSION="@VERSION@"
+LIBNEXUS="${prefix}/lib/libNeXus.a"
+LIBNEXUS77="${prefix}/lib/libNeXus77.a"
+LIBNEXUS90="${prefix}/lib/libNeXus90.a"
+CFLAGS="@CFLAGS@"
+FFLAGS="@FFLAGS@"
+DEFS="@DEFS@"
+CPPFLAGS="@CPPFLAGS@ -I${prefix}/include"
+LDFLAGS="@LDFLAGS@"
+LIBS="@LIBS@"
+
+OBJS=""
+TARGET="a.out"
+while [ $# -ne 0 ]; do
+    case $1 in
+	-o)
+	    shift
+	    TARGET=$1
+	    ;;
+	*.f90)
+	    $F90 $F90FLAGS -c $1
+	    OBJS="$OBJS `basename $1 .f90`.o"
+            ;;
+	*.c)
+	    $CC $CPPFLAGS $DEFS $CFLAGS -c $1
+	    OBJS="$OBJS `basename $1 .c`.o"
+            ;;
+	*.f)
+	    $F77 $F77FLAGS -c $1
+	    OBJS="$OBJS `basename $1 .f`.o"
+            ;;
+	--help|-h)
+	    echo "usage: nxbuild [-o target] file [file...]"
+	    echo "usage: nxbuild --help"
+	    echo "usage: nxbuild --version"
+	    exit
+	    ;;
+	--version|-V)
+	    echo 'nxbuild $Revision$ for NeXus release' $VERSION
+	    echo "Type   nxbuild --help   for usage"
+	    exit
+	    ;;
+	*)		# *.o, *.a etc
+	    OBJS="$OBJS $1"
+	    ;;
+    esac
+    shift
+done
+$CC -o $TARGET $LDFLAGS $OBJS $LIBNEXUS $LIBS
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..0fb95c3
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,139 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#  MA  02111-1307  USA
+#
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_definitions(-DIN_NEXUS_LIBRARY=1 ${NX_CPP})
+
+set (NAPISRC napi.c napiu.c nxstack.c nxstack.h stptok.c  nxdataset.c nxdataset.h nx_stptok.h)
+
+if (HAVE_HDF4)
+  set (NAPISRC ${NAPISRC} napi4.c)
+  add_definitions(-DHDF4 ${HDF4_DEFINITIONS} ${HDF4_CPP})
+  include_directories(${HDF4_INCLUDE_DIRS})
+  file(GLOB HDF4DLLS "${HDF4_ROOT_DIR}/bin/*.dll") 
+  install (FILES ${HDF4DLLS} DESTINATION bin COMPONENT Runtime)
+endif (HAVE_HDF4)
+
+if (HAVE_HDF5)
+  set (NAPISRC ${NAPISRC} napi5.c)
+  add_definitions(-DHDF5 ${HDF5_DEFINITIONS} ${HDF5_CPP})
+  include_directories(${HDF5_INCLUDE_DIRS})
+  file(GLOB HDF5DLLS "${HDF5_ROOT_DIR}/bin/*.dll") 
+  install (FILES ${HDF5DLLS} DESTINATION bin COMPONENT Runtime)
+endif (HAVE_HDF5)
+
+if(HAVE_MXML)
+    set (NAPISRC ${NAPISRC} nxxml.c nxio.c nxio.h)
+    add_definitions(-DNXXML ${MXML_DEFINITIONS} ${MXML_CPP})
+	include_directories(${MXML_INCLUDE_DIRS})
+endif(HAVE_MXML)
+
+# need napi_exports2.c  on win32 but not win64
+if (WIN32)
+    if (CMAKE_CL_64)
+        set(NAPISRC ${NAPISRC} napi_exports2.c napi_exports.h)
+    else()
+        set(NAPISRC ${NAPISRC} napi_exports.c napi_exports2.c napi_exports.h)
+	endif()
+endif (WIN32)
+
+set_property(SOURCE ${NAPISRC} APPEND PROPERTY COMPILE_FLAGS ${NX_CFLAGS})
+
+file(STRINGS ${PROJECT_SOURCE_DIR}/src/nexus_symbols.txt NEXUS_SYMBOLS)
+
+set (NX_LIBS  ${HDF4_LINK} ${READLINE_LINK} ${M_LINK} ${DL_LINK} ${PTHREAD_LINK} ${DF_LINK}
+                      ${TERMCAP_LINK} ${HISTORY_LINK} ${JPEG_LIBRARIES} ${SZIP_LIBRARIES} ${ZLIB_LIBRARIES}  )
+#if (MINGW_MSYS)
+#  set (MINGW_SRC napi_exports.c napi_exports2.c napi_exports.h)
+#  file(STRINGS ${PROJECT_SOURCE_DIR}/src/nexus_symbols_win.txt
+#       NEXUS_SYMBOLS_WIN)
+#  file(WRITE ${PROJECT_SOURCE_DIR}/src/nexus_symbols.sym ${NEXUS_SYMBOLS}
+#       ${NEXUS_SYMBOLS_WIN})
+#
+#  if (HAVE_MS_LIB)
+#    file(REMOVE libNeXus.dll.lib libNeXus.dll.exp)
+#    execute_process(
+#      COMMAND ${MS_LIB} /MACHINE:I386 /DEF:libNeXus.def /OUT:libNeXus.dll.lib)
+#  endif (HAVE_MS_LIB)
+#
+#else (MINGW_MSYS)
+#  file(WRITE ${PROJECT_SOURCE_DIR}/src/nexus_symbols.sym ${NEXUS_SYMBOLS})
+#endif (MINGW_MSYS)
+
+#Make NeXus Static Library
+add_library (NeXus_Static_Library STATIC ${NAPISRC})
+
+set_target_properties(NeXus_Static_Library PROPERTIES OUTPUT_NAME NeXusStatic)
+
+target_link_libraries(NeXus_Static_Library ${HDF5_STATIC_LIBRARIES} ${HDF4_STATIC_LIBRARIES} ${MXML_STATIC_LIBRARIES}  ${NX_LIBS})
+
+#Make NeXus Shared Library
+
+add_library (NeXus_Shared_Library SHARED ${NAPISRC})
+
+#set_property(TARGET NeXus_Shared_Library APPEND PROPERTY COMPILE_DEFINITIONS _HDF5USEDLL_ _HDFDLL_)
+set_property(TARGET NeXus_Shared_Library APPEND PROPERTY COMPILE_DEFINITIONS H4_BUILT_AS_STATIC_LIB)
+set_property(TARGET NeXus_Static_Library APPEND PROPERTY COMPILE_DEFINITIONS H4_BUILT_AS_STATIC_LIB)
+
+if (CMAKE_CL_64)
+   set(DEF_FILE ${PROJECT_SOURCE_DIR}/Windows_extra/libNeXus-0-x64.def)
+else()
+   set(DEF_FILE ${PROJECT_SOURCE_DIR}/Windows_extra/libNeXus-0-Win32.def)
+endif()
+
+#Note - library version needs to be got from somewhere?
+if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    set_target_properties(NeXus_Shared_Library PROPERTIES OUTPUT_NAME libNeXus-0
+                      VERSION 1.0 SOVERSION 4 )
+	if (MSVC)
+	    set_property(TARGET NeXus_Shared_Library APPEND PROPERTY LINK_FLAGS /def:${DEF_FILE})
+	endif(MSVC)
+else(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    set_target_properties(NeXus_Shared_Library PROPERTIES OUTPUT_NAME NeXus
+                      VERSION 1.0 SOVERSION 4)
+endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+
+target_link_libraries(NeXus_Shared_Library ${HDF5_STATIC_LIBRARIES} ${HDF4_STATIC_LIBRARIES} ${MXML_STATIC_LIBRARIES} ${NX_LIBS})
+
+#if(HAVE_MXML)
+#if(MXMLLIB_FOUND)
+#    target_link_libraries(NeXus_Static_Library ${MXML})
+#    target_link_libraries(NeXus_Shared_Library ${MXML})
+#else()
+#    target_link_libraries(NeXus_Static_Library MXML_Static_Library)
+#    target_link_libraries(NeXus_Shared_Library MXML_Shared_Library)
+#endif(MXMLLIB_FOUND)
+#endif(HAVE_MXML)
+
+install (TARGETS NeXus_Static_Library NeXus_Shared_Library
+         RUNTIME DESTINATION bin COMPONENT Runtime
+         LIBRARY DESTINATION lib COMPONENT Runtime
+         ARCHIVE DESTINATION lib/nexus COMPONENT Development)
+
+#if(WIN32)
+#install_pdb (NeXus_Shared_Library)
+#endif()
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..563ce11
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,98 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile for building the core NeXus library
+#
+#  $Id$
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+AM_CPPFLAGS=-I$(top_srcdir)/include @HDF4_CPPFLAGS@ @HDF5_CPPFLAGS@ @XML_CPPFLAGS@ -DIN_NEXUS_LIBRARY=1
+AM_CFLAGS=-prefer-pic
+
+if HAVE_HDF4
+H4SRC = napi4.c
+endif
+
+if HAVE_HDF5
+H5SRC = napi5.c
+endif
+
+if HAVE_XML
+XMLSRC = nxxml.c nxio.c nxio.h
+endif
+##  the LIBS variable should contain all needed libs for the HDF support
+##  It will be filled during the configuration run
+
+lib_LTLIBRARIES = libNeXus.la
+
+if MINGW_MSYS
+nexus_symbols.sym : $(srcdir)/nexus_symbols.txt $(srcdir)/nexus_symbols_win.txt
+	cat $(srcdir)/nexus_symbols.txt $(srcdir)/nexus_symbols_win.txt >> nexus_symbols.sym
+else
+nexus_symbols.sym : $(srcdir)/nexus_symbols.txt
+	cp $(srcdir)/nexus_symbols.txt nexus_symbols.sym
+endif
+
+# Windows import library for DLL
+
+if MINGW_MSYS
+MINGW_SRC=napi_exports.c napi_exports2.c napi_exports.h
+msimplibdir = ${libdir}
+libNeXus.def: libNeXus.la
+	pexports .libs/libNeXus-0.dll > libNeXus.def
+if HAVE_MS_LIB
+msimplib_DATA = libNeXus.dll.lib libNeXus.dll.exp libNeXus.def
+libNeXus.dll.exp: libNeXus.dll.lib
+libNeXus.dll.lib: libNeXus.def
+	rm -f libNeXus.dll.lib libNeXus.dll.exp
+	$(MS_LIB) /MACHINE:I386 /DEF:libNeXus.def /OUT:libNeXus.dll.lib
+else
+msimplib_DATA = libNeXus.def
+endif
+endif
+
+#SUBDIRS=nxdict
+
+libNeXus_la_SOURCES = napi.c napiu.c nxstack.c nxstack.h stptok.c  nxdataset.c nxdataset.h nx_stptok.h $(H4SRC) $(H5SRC) $(XMLSRC) $(MINGW_SRC)
+libNeXus_la_LDFLAGS = -export-symbols nexus_symbols.sym @SHARED_LDFLAGS@ @HDF4_LDFLAGS@ @HDF5_LDFLAGS@ @XML_LDFLAGS@ -version-info $(NXLTVERSINFO)
+libNeXus_la_DEPENDENCIES = nexus_symbols.sym
+
+## The following part is the solution for automake >= 1.7
+## 
+## libNeXus_la_LIBADD = -lz
+## if HAVE_HDF4 
+## libNeXus_la_SOURCES += napi4.c
+## libNeXus_la_LIBADD += -lmfhdf -ldf -ljpeg
+## endif
+
+## if HAVE_HDF5
+## libNeXus_la_SOURCES += napi5.c
+## libNeXus_la_LIBADD += -lhdf5 
+## endif
+
+EXTRA_DIST=nexus_symbols.txt nexus_symbols_win.txt SConscript
+CLEANFILES=libNeXus.def libNeXus.dll.lib libNeXus.dll.exp nexus_symbols.sym
+
+include $(top_srcdir)/build_rules.am
diff --git a/src/SConscript b/src/SConscript
new file mode 100644
index 0000000..0a11cf2
--- /dev/null
+++ b/src/SConscript
@@ -0,0 +1,71 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 961 2007-09-04 12:31:49Z Freddie Akeroyd $
+#
+#  Top level scons file for coordinating NeXus build
+#  
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+######################## Subversion Reposity details ########################
+# Repository Location     $HeadURL$
+# Revision of last commit $LastChangedRevision$ 
+# Date of last commit     $LastChangedDate$
+# Author of last commit   $LastChangedBy$
+############################################################################
+
+import os
+import platform
+import sys
+import shutil
+import re
+import os
+import nexus_scons_utils
+
+source_files = Split("""napi4.c
+                        napi5.c
+                        nxxml.c
+                        nxio.c
+                        napi.c
+                        napiu.c
+                        nxdataset.c
+                        nxstack.c
+                        stptok.c""")
+
+
+#Import environment
+Import('env')
+myenv = env.Clone()
+myenv.Append(CPPDEFINES=[('IN_NEXUS_LIBRARY',1),('H5_USE_16_API',1)])
+myenv.Append(CPPPATH=['#/include'])
+#print myenv.Dump()
+
+if os.name == 'nt': 
+    source_files.extend(['napi_exports.c','napi_exports2.c'])
+    mydef=File('#/Windows_extra/libNeXus-0.def')
+    myenv.Append(SHLINKFLAGS=['/DEF:'+str(mydef)])
+
+shared_objects = nexus_scons_utils.getSharedObjects(source_files, myenv)
+
+#BUILD CODE
+static = myenv.StaticLibrary('libstatic/libNeXus-0', source_files, LIBS=env['MYLIBLIST'], LIBPATH=env['MYLIBDIRLIST'], PDB='libstatic/libNeXus-0.pdb')
+shared = myenv.SharedLibrary('lib/libNeXus-0', source_files, LIBS=env['MYSHLIBLIST'], LIBPATH=env['MYSHLIBDIRLIST'], PDB='lib/libNeXus-0.pdb')
+retval = { 'shared': shared, 'static': static, 'sharedobjs' : shared_objects, 'libs': [ 'libNeXus-0' ] }
+Return('retval')
diff --git a/src/make_vms.com b/src/make_vms.com
new file mode 100644
index 0000000..660551c
--- /dev/null
+++ b/src/make_vms.com
@@ -0,0 +1,20 @@
+$!
+$! $Id: make_vms.com,v 1.7 2000/08/09 13:48:11 faa Exp $
+$!
+$! Build command file for VMS
+$!
+$! Freddie Akeroyd, STFC ISIS facility, GB
+$!
+$!
+$ SET VERIFY
+$ DEFINE HDF5_ROOT AXPLIB$DISK:[HDF5.]  ! where you installed HDF5, trailing "." is needed
+$ copt := /prefix=all /float=ieee /include=([-.include],hdf5_root:[include]) /define=(IN_NEXUS_LIBRARY=1,HDF5,H5_USE_16_API)
+$!
+$ CC 'copt napi5.c
+$ CC 'copt napi.c
+$ CC 'copt napiu.c
+$ CC 'copt nxdataset.c
+$ CC 'copt nxstack.c
+$ CC 'copt stptok.c
+$ delete/noconfirm libnexus.olb;*
+$ lib/create/object libnexus.olb napi5,napi,napiu,nxdataset,nxstack,stptok
diff --git a/src/makefile_f90 b/src/makefile_f90
new file mode 100644
index 0000000..a90e99c
--- /dev/null
+++ b/src/makefile_f90
@@ -0,0 +1,73 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile for building Fortran 90 version of NeXus libraries
+#  
+#  Copyright (C) 2002 Mark Koennecke
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+# $Id$
+#
+#====================================================================
+
+#Edit "makefile_options" to set compiler flags
+include makefile_options
+
+ifdef H4ROOT
+	H4LIBS=-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg
+else
+	H4LIBS=
+endif
+ifdef H5ROOT
+	H5LIBS=-L$(H5ROOT)/lib -lhdf5
+else
+	H5LIBS=
+endif
+
+LIBNEXUS90_OBJ=NXUmodule.o NXmodule.o
+NXTEST_OBJ=NXtest.o
+NXDUMP_OBJ=NXdump.o
+
+all: libNeXus90.a NXtest NXdump
+
+NXmodule.o: NXmodule.f90
+	$(F90) $(F90FLAGS) -c $(FROOT)/NXmodule.f90
+
+NXUmodule.o: NXUmodule.f90 NXmodule.o
+	$(F90) $(F90FLAGS) -c $(FROOT)/NXUmodule.f90
+
+NXtest.o: NXtest.f90
+	$(F90) $(F90FLAGS) -c $(FROOT)/NXtest.f90
+
+NXdump.o: NXdump.f90
+	$(F90) $(F90FLAGS) -c $(FROOT)/NXdump.f90
+
+libNeXus90.a : $(LIBNEXUS90_OBJ)
+	@echo "*** Creating Fortran 90 NeXus interface  ***"
+	cp libNeXus.a $@
+	ar -r $@ $(LIBNEXUS90_OBJ)
+	ranlib $@
+
+NXtest: libNeXus90.a $(NXTEST_OBJ)
+	$(F90) $(F90FLAGS) $(LDFLAGS) -o NXtest $(NXTEST_OBJ) $(FROOT)/libNeXus90.a \
+	$(H4LIBS) $(H5LIBS) -lz 
+
+NXdump: libNeXus90.a $(NXDUMP_OBJ)
+	$(F90) $(F90FLAGS) $(LDFLAGS) -o NXdump $(NXDUMP_OBJ) $(FROOT)/libNeXus90.a \
+	$(H4LIBS) $(H5LIBS) -lz 
diff --git a/src/makefile_hdf4 b/src/makefile_hdf4
new file mode 100644
index 0000000..e269b4e
--- /dev/null
+++ b/src/makefile_hdf4
@@ -0,0 +1,71 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile for building the NeXus library with the HDF4 libraries
+#  
+#  Copyright (C) 2002 Mark Koennecke
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+# $Id$
+#
+#====================================================================
+
+#Edit "makefile_options" to set compiler flags
+include makefile_options
+
+LIBNEXUS_OBJ=napi.o napif.o
+TEST4_OBJ=napi4_test.o
+NXBROWSE_OBJ=NXbrowse.o
+NXTOXML_OBJ=NXtoXML.o
+NXTODTD_OBJ=NXtoDTD.o
+NOPT=-DHDF4
+
+all: libNeXus.a napi4_test napif_test NXbrowse NXtoXML NXtoDTD
+
+.c.o :
+	$(CC) $(CFLAGS) $(NOPT) -I$(H4ROOT)/include -c $(FROOT)/$*.c
+.f.o:
+	$(FC) $(FFLAGS) -c $(FROOT)/$*.f
+
+libNeXus.a : $(LIBNEXUS_OBJ)
+	@echo "*** Creating NeXus interface based on HDF4 library (libNeXus.a) ***"
+	- rm $@
+	ar -cr $@ $(LIBNEXUS_OBJ)
+	ranlib $@
+	
+napi4_test: libNeXus.a $(TEST4_OBJ)
+	$(CC) $(CFLAGS) -o napi4_test $(TEST4_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -lz 
+
+napif_test: libNeXus.a napif_test.o
+	$(FC) $(FFLAGS) -o napif_test napif_test.o $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -lz
+	
+NXbrowse: libNeXus.a $(NXBROWSE_OBJ) 
+	$(CC) $(CFLAGS) -o NXbrowse $(NXBROWSE_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -lz 
+
+NXtoXML: libNeXus.a $(NXTOXML_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoXML $(NXTOXML_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -lz 
+
+NXtoDTD: libNeXus.a $(NXTODTD_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoDTD $(NXTODTD_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -lz 
+
diff --git a/src/makefile_hdf45 b/src/makefile_hdf45
new file mode 100644
index 0000000..d1e697a
--- /dev/null
+++ b/src/makefile_hdf45
@@ -0,0 +1,87 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile for building NeXus libraries with both HDF4 and HDF5
+#  
+#  Copyright (C) 2002 Mark Koennecke
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+# $Id: Makefile,v 2.00 2001/27/07 11:00:02
+#
+#====================================================================
+
+#Edit "makefile_options" to set compiler flags
+include makefile_options
+
+LIBNEXUS_OBJ=napi.o napif.o
+TEST4_OBJ=napi4_test.o
+TEST5_OBJ=napi5_test.o
+NXBROWSE_OBJ=NXbrowse.o
+NXTOXML_OBJ=NXtoXML.o
+NXTODTD_OBJ=NXtoDTD.o
+NXTONX4_OBJ=NXtoNX4.o
+NXTONX5_OBJ=NXtoNX5.o
+NOPT=-DHDF4 -DHDF5
+
+all: libNeXus.a napi4_test napi5_test napif_test NXbrowse NXtoXML NXtoDTD NXtoNX4 NXtoNX5
+
+.c.o :
+	$(CC) $(CFLAGS) $(NOPT) -I$(H4ROOT)/include -I$(H5ROOT)/include -c $(FROOT)/$*.c 
+
+.f.o:
+	$(FC) $(FFLAGS) -c $(FROOT)/$*.f
+
+libNeXus.a : $(LIBNEXUS_OBJ)
+	@echo "*** Creating NeXus interface based on HDF4/HDF5 library libNeXus.a ***"
+	- rm $@
+	ar -cr $@ $(LIBNEXUS_OBJ)
+	ranlib $@
+
+napi4_test: libNeXus.a $(TEST4_OBJ) 
+	$(CC) $(CFLAGS) $(LDFLAGS) -o napi4_test $(TEST4_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg  -L$(H5ROOT)/lib -lhdf5 -lz 
+
+napi5_test: libNeXus.a $(TEST5_OBJ) 
+	$(CC) $(CFLAGS) $(LDFLAGS) -o napi5_test $(TEST5_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+	
+napif_test: libNeXus.a
+	$(FC) $(FFLAGS) $(LDFLAGS) -o napif_test napif_test.f $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+
+NXbrowse: libNeXus.a $(NXBROWSE_OBJ) 
+	$(CC) $(CFLAGS) -o NXbrowse $(NXBROWSE_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+
+NXtoXML: libNeXus.a $(NXTOXML_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoXML $(NXTOXML_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+	
+NXtoDTD: libNeXus.a $(NXTODTD_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoDTD $(NXTODTD_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+
+NXtoNX4: libNeXus.a $(NXTONX4_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoNX4 $(NXTONX4_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+
+NXtoNX5: libNeXus.a $(NXTONX5_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoNX5 $(NXTONX5_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H4ROOT)/lib -lmfhdf -ldf -ljpeg -L$(H5ROOT)/lib -lhdf5 -lz 
+
diff --git a/src/makefile_hdf5 b/src/makefile_hdf5
new file mode 100644
index 0000000..92346cb
--- /dev/null
+++ b/src/makefile_hdf5
@@ -0,0 +1,72 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile for building the NeXus library with the HDF5 libraries
+#  
+#  Copyright (C) 2002 Mark Koennecke
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+# $Id: Makefile,v 2.00 2001/27/07 11:00:02
+#
+#====================================================================
+
+#Edit "makefile_options" to set compiler flags
+include makefile_options
+
+LIBNEXUS_OBJ=napi.o napif.o
+TEST5_OBJ=napi5_test.o
+NXBROWSE_OBJ=NXbrowse.o
+NXTOXML_OBJ=NXtoXML.o
+NXTODTD_OBJ=NXtoDTD.o
+NOPT=-DHDF5
+
+all: libNeXus.a napi5_test napif_test NXbrowse NXtoXML NXtoDTD
+
+.c.o :
+	$(CC) $(CFLAGS) $(NOPT) -I$(H5ROOT)/include -c $(FROOT)/$*.c
+.f.o:
+	$(FC) $(FFLAGS) -c $(FROOT)/$*.f
+
+libNeXus.a : $(LIBNEXUS_OBJ)
+	@echo "*** Creating NeXus interface based on HDF5 library (libNeXus.a) ***"
+	- rm $@
+	ar -cr $@ $(LIBNEXUS_OBJ)
+	ranlib $@
+
+napi5_test: libNeXus.a $(TEST5_OBJ) 
+	$(CC) $(CFLAGS) -o napi5_test $(TEST5_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H5ROOT)/lib -lhdf5 -lz 
+		
+napif_test: libNeXus.a napif_test.o
+	$(FC) $(FFLAGS) -o napif_test napif_test.o $(FROOT)/libNeXus.a \
+	-L$(H5ROOT)/lib -lhdf5 -lz
+
+NXbrowse: libNeXus.a $(NXBROWSE_OBJ) 
+	$(CC) $(CFLAGS) -o NXbrowse $(NXBROWSE_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H5ROOT)/lib -lhdf5 -lz
+
+NXtoXML: libNeXus.a $(NXTOXML_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoXML $(NXTOXML_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H5ROOT)/lib -lhdf5 -lz
+
+NXtoDTD: libNeXus.a $(NXTODTD_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoDTD $(NXTODTD_OBJ) $(FROOT)/libNeXus.a \
+	-L$(H5ROOT)/lib -lhdf5 -lz 
+
+	
diff --git a/src/makefile_options b/src/makefile_options
new file mode 100644
index 0000000..e547d67
--- /dev/null
+++ b/src/makefile_options
@@ -0,0 +1,67 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile compiler and directory options
+#  
+#  Copyright (C) 2002 Ray Osborn
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+# $Id$
+#
+#====================================================================
+#Edit the compiler flags as necessary
+#CC=cc
+#FC=g77
+#CFLAGS=-g 
+#FFLAGS=-g
+#F90=f90
+#F90FLAGS=
+#LDFLAGS=-g
+#====================================================================
+#Compiler flags on DEC TRU64 UNIX
+CC=cc
+FC=f77
+CFLAGS= -I. -I../include -g -non_shared
+FFLAGS=-g
+F90=f90
+F90FLAGS=
+LDFLAGS=
+#====================================================================
+#Compiler flags for Absoft Pro Fortran 77 and 90 on Mac OS X
+#CC=cc
+#FC=g77
+#CFLAGS=-g -no-cpp-precomp -D__unix
+#FFLAGS=-g -Wno-globals
+#F90=f95
+#F90FLAGS=-g -cons -YEXT_NAMES=LCS -YEXT_SFX=_
+#LDFLAGS=-flat_namespace
+#====================================================================
+#Compiler flags for Absoft Pro Fortran 90 on Linux
+#CC=cc
+#FC=f77
+#CFLAGS=-gdwarf -D__ABSOFT
+#FFLAGS=-f
+#F90=f90
+#F90FLAGS=-YEXT_NAMES=LCS
+#LDFLAGS=
+#====================================================================
+#Specify locations of the NeXus source files and HDF libraries
+FROOT=/data/koenneck/src/nexus/src
+H4ROOT=/usr/local
+H5ROOT=/data/lnslib
diff --git a/src/napi.c b/src/napi.c
new file mode 100644
index 0000000..4acdc39
--- /dev/null
+++ b/src/napi.c
@@ -0,0 +1,2131 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  Application Program Interface Routines
+  
+  Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+
+----------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+
+#include "napi.h"
+#include "nxstack.h"
+
+/*---------------------------------------------------------------------
+ Recognized and handled napimount URLS
+ -----------------------------------------------------------------------*/
+#define NXBADURL 0
+#define NXFILE 1
+
+/*--------------------------------------------------------------------*/
+/* static int iFortifyScope; */
+/*----------------------------------------------------------------------
+  This is a section with code for searching the NX_LOAD_PATH
+  -----------------------------------------------------------------------*/
+#ifdef _WIN32
+#define LIBSEP ";"
+#define PATHSEP "\\"
+#define THREAD_LOCAL __declspec(thread)
+#else
+#define LIBSEP ":"
+#define PATHSEP "/"
+#define THREAD_LOCAL __thread
+#endif
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif /* _MSC_VER */
+
+#include "nx_stptok.h"
+
+#if defined(_WIN32)
+/*
+ *  HDF5 on windows does not do locking for multiple threads conveniently so we will implement it ourselves.
+ *  Freddie Akeroyd, 16/06/2011
+ */
+#include <windows.h>
+
+
+static CRITICAL_SECTION nx_critical;
+
+static int nxilock()
+{
+    static int first_call = 1;
+    if (first_call)
+    {
+        first_call = 0;
+	InitializeCriticalSection(&nx_critical);
+    }
+    EnterCriticalSection(&nx_critical);
+    return NX_OK;
+}
+
+static int nxiunlock(int ret)
+{
+    LeaveCriticalSection(&nx_critical);
+    return ret;
+}
+
+#define LOCKED_CALL(__call) \
+    ( nxilock() , nxiunlock(__call) )
+
+#elif HAVE_LIBPTHREAD
+
+#include <pthread.h>
+
+static pthread_mutex_t nx_mutex;
+
+#ifdef PTHREAD_MUTEX_RECURSIVE
+#define RECURSIVE_LOCK PTHREAD_MUTEX_RECURSIVE
+#else
+#define RECURSIVE_LOCK PTHREAD_MUTEX_RECURSIVE_NP
+#endif /* PTHREAD_MUTEX_RECURSIVE */
+
+static void nx_pthread_init()
+{
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, RECURSIVE_LOCK);
+    pthread_mutex_init(&nx_mutex, &attr);
+}
+
+static int nxilock()
+{
+    static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+    if (pthread_once(&once_control, nx_pthread_init) != 0)
+    {
+        NXReportError("pthread_once failed");
+	return NX_ERROR;
+    }
+    if (pthread_mutex_lock(&nx_mutex) != 0)
+    {
+        NXReportError("pthread_mutex_lock failed");
+        return NX_ERROR;
+    }
+    return NX_OK;
+}
+
+static int nxiunlock(int ret)
+{
+    if (pthread_mutex_unlock(&nx_mutex) != 0)
+    {
+        NXReportError("pthread_mutex_unlock failed");
+        return NX_ERROR;
+    }
+    return ret;
+}
+
+#define LOCKED_CALL(__call) \
+    ( nxilock() , nxiunlock(__call) )
+
+#else
+
+#define LOCKED_CALL(__call) \
+	   __call
+
+#endif /* _WIN32 */
+
+/**
+ * valid NeXus names
+ */
+int validNXName(const char* name, int allow_colon)
+{
+    int i;
+    if (name == NULL)
+    {
+	return 0;
+    }
+    for(i=0; i<(int)strlen(name); ++i)
+    {
+	if ( (name[i] >= 'a' && name[i] <= 'z') ||
+	     (name[i] >= 'A' && name[i] <= 'Z') ||
+	     (name[i] >= '0' && name[i] <= '9') ||
+	     (name[i] == '_') )
+	{
+	    ;
+	}
+	else if (allow_colon && name[i] == ':')
+	{
+	    ;
+	}
+	else
+	{
+	    return 0;
+	}
+    }
+    return 1;
+}
+
+static int64_t* dupDimsArray(int* dims_array, int rank)
+{
+	int i;
+	int64_t* dims64 = (int64_t*)malloc(rank * sizeof(int64_t));
+	if (dims64 != NULL)
+	{
+		for(i=0; i<rank; ++i)
+		{
+	    		dims64[i] = dims_array[i];
+		}
+	}
+	return dims64;
+}
+
+/*---------------------------------------------------------------------
+ wrapper for getenv. This is a future proofing thing for porting to OS
+ which have different ways of accessing environment variables
+ --------------------------------------------------------------------*/ 
+static char *nxgetenv(const char *name){
+  return getenv(name);
+}
+/*----------------------------------------------------------------------*/
+static int canOpen(char *filename){
+  FILE *fd = NULL;
+
+  fd = fopen(filename,"r");
+  if(fd != NULL){
+    fclose(fd);
+    return 1;
+  } else {
+    return 0;
+  }
+} 
+/*--------------------------------------------------------------------*/
+static char *locateNexusFileInPath(char *startName){
+  char *loadPath = NULL, *testPath = NULL, *pPtr = NULL;
+  char pathPrefix[256];
+  int length;
+
+  if(canOpen(startName)){
+    return strdup(startName);
+  }
+
+  loadPath = nxgetenv("NX_LOAD_PATH");
+  if(loadPath == NULL){
+    /* file not found will be issued by upper level code */
+    return strdup(startName);
+  }
+
+  pPtr = stptok(loadPath,pathPrefix,255,LIBSEP);
+  while(pPtr != NULL){
+    length = (int)strlen(pathPrefix) + (int)strlen(startName) + (int)strlen(PATHSEP) + 2;
+    testPath = (char*)malloc(length*sizeof(char));
+    if(testPath == NULL){
+      return strdup(startName);
+    }
+    memset(testPath,0,length*sizeof(char));
+    strcpy(testPath, pathPrefix);
+    strcat(testPath,PATHSEP);
+    strcat(testPath,startName);
+    if(canOpen(testPath)){
+      return(testPath);
+    }
+    free(testPath);
+    pPtr = stptok(pPtr,pathPrefix,255,LIBSEP);
+  }
+  return  strdup(startName);
+}
+/*------------------------------------------------------------------------
+  HDF-5 cache size special stuff
+  -------------------------------------------------------------------------*/
+long nx_cacheSize =  1024000; /* 1MB, HDF-5 default */
+
+NXstatus NXsetcache(long newVal)
+{
+  if(newVal > 0)
+  {
+    nx_cacheSize = newVal;
+    return NX_OK;
+  }
+  return NX_ERROR;
+}
+
+#ifdef NXXML
+/*-----------------------------------------------------------------------*/
+static NXstatus NXisXML(CONSTCHAR *filename)
+{
+  FILE *fd = NULL;
+  char line[132];
+
+  fd = fopen(filename,"r");
+  if(fd) {
+    int fgets_ok = (fgets(line,131,fd) != NULL);
+    fclose(fd);
+    if (fgets_ok) {
+      if(strstr(line,"?xml") != NULL){
+	return NX_OK;
+      }
+    }
+    else {
+      return NX_ERROR;
+    }
+  }
+  return NX_ERROR;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+  static void NXNXNXReportError(void *pData, char *string)
+  {
+    fprintf(stderr, "%s \n", string);
+  }
+  /*---------------------------------------------------------------------*/
+
+  static void *NXEHpData = NULL;
+  static void (*NXEHIReportError)(void *pData, char *string) = NXNXNXReportError;
+#ifdef HAVE_TLS
+  static THREAD_LOCAL void *NXEHpTData = NULL;
+  static THREAD_LOCAL void (*NXEHIReportTError)(void *pData, char *string) = NULL;
+#endif
+
+  void NXIReportError(void *pData, char *string) {
+	fprintf(stderr, "Your application uses NXIReportError, but its first parameter is ignored now - you should use NXReportError.");
+	NXReportError(string);
+  }
+
+  void NXReportError(char *string) {
+#ifdef HAVE_TLS
+	if (NXEHIReportTError) {
+		(*NXEHIReportTError)(NXEHpTData, string);
+		return;
+	} 
+#endif
+	if (NXEHIReportError) {
+	    (*NXEHIReportError)(NXEHpData, string);
+	}
+  }
+
+  /*---------------------------------------------------------------------*/
+  extern void NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
+  {
+    NXEHpData = pData;
+    NXEHIReportError = NewError;
+  }
+/*----------------------------------------------------------------------*/
+  extern void NXMSetTError(void *pData, void (*NewError)(void *pD, char *text))
+  {
+#ifdef HAVE_TLS
+    NXEHpTData = pData;
+    NXEHIReportTError = NewError;
+#else
+    NXMSetError(pData, NewError);
+#endif
+  }
+/*----------------------------------------------------------------------*/
+extern ErrFunc NXMGetError(){
+#ifdef HAVE_TLS
+	if (NXEHIReportTError) {
+		return NXEHIReportTError;
+	}
+#endif
+  return NXEHIReportError;
+}
+
+/*----------------------------------------------------------------------*/
+static void NXNXNoReport(void *pData, char *string){
+  /* do nothing */
+}  
+/*----------------------------------------------------------------------*/
+
+static ErrFunc last_global_errfunc = NXNXNXReportError;
+#ifdef HAVE_TLS
+static THREAD_LOCAL ErrFunc last_thread_errfunc = NULL;
+#endif
+
+extern void NXMDisableErrorReporting()
+{
+#ifdef HAVE_TLS
+	if (NXEHIReportTError) {
+		last_thread_errfunc = NXEHIReportTError;
+		NXEHIReportTError = NXNXNoReport;
+	 	return;
+	} 
+#endif
+	if (NXEHIReportError) {
+	    last_global_errfunc = NXEHIReportError;
+	    NXEHIReportError = NXNXNoReport;
+	}
+}
+
+extern void NXMEnableErrorReporting()
+{
+#ifdef HAVE_TLS
+	if (last_thread_errfunc) {
+		NXEHIReportTError = last_thread_errfunc;
+		last_thread_errfunc = NULL;
+	 	return;
+	} 
+#endif
+	if (last_global_errfunc) {
+	    NXEHIReportError = last_global_errfunc;
+	    last_global_errfunc = NULL;
+	}
+}
+
+/*----------------------------------------------------------------------*/
+#ifdef HDF5
+#include "napi5.h"
+#endif
+#ifdef HDF4
+#include "napi4.h"
+#endif
+#ifdef NXXML
+#include "nxxml.h"
+#endif  
+  /* ---------------------------------------------------------------------- 
+  
+                          Definition of NeXus API
+
+   ---------------------------------------------------------------------*/
+static int determineFileTypeImpl(CONSTCHAR *filename)
+{
+  FILE *fd = NULL;
+  int iRet;
+  
+  /*
+    this is for reading, check for existence first
+  */
+  fd = fopen(filename,"r");
+  if(fd == NULL){
+    return -1;
+  }
+  fclose(fd);
+#ifdef HDF5
+  iRet=H5Fis_hdf5((const char*)filename);
+  if( iRet > 0){
+    return 2;
+  }
+#endif  
+#ifdef HDF4
+  iRet=Hishdf((const char*)filename);
+  if( iRet > 0){
+    return 1;
+  }
+#endif
+#ifdef NXXML
+  iRet = NXisXML(filename);
+  if(iRet == NX_OK){
+    return 3;
+  }
+#endif
+  /*
+    file type not recognized
+  */
+  return 0;
+}
+
+static int determineFileType(CONSTCHAR *filename)
+{
+    return LOCKED_CALL(determineFileTypeImpl(filename));
+}
+
+/*---------------------------------------------------------------------*/
+static pNexusFunction handleToNexusFunc(NXhandle fid){
+  pFileStack fileStack = NULL;
+  fileStack = (pFileStack)fid;
+  if(fileStack != NULL){
+    return peekFileOnStack(fileStack);
+  } else {
+    return NULL;
+  }
+}
+/*--------------------------------------------------------------------*/
+static NXstatus   NXinternalopen(CONSTCHAR *userfilename, NXaccess am, 
+           pFileStack fileStack);
+/*----------------------------------------------------------------------*/
+NXstatus   NXopen(CONSTCHAR *userfilename, NXaccess am, NXhandle *gHandle){
+  int status;
+  pFileStack fileStack = NULL;
+
+  *gHandle = NULL;
+  fileStack = makeFileStack();
+  if(fileStack == NULL){
+    NXReportError("ERROR: no memory to create filestack");
+      return NX_ERROR;
+  }
+  status = NXinternalopen(userfilename,am,fileStack);
+  if(status == NX_OK){
+    *gHandle = fileStack;
+  }
+
+  return status;
+}
+/*-----------------------------------------------------------------------*/
+static NXstatus   NXinternalopenImpl(CONSTCHAR *userfilename, NXaccess am, pFileStack fileStack)
+  {
+    int hdf_type=0;
+    int iRet=0;
+    NXhandle hdf5_handle = NULL;
+    pNexusFunction fHandle = NULL;
+    NXstatus retstat = NX_ERROR;
+    char error[1024];
+    char *filename = NULL;
+    int my_am = (am & NXACCMASK_REMOVEFLAGS);
+        
+    /* configure fortify 
+    iFortifyScope = Fortify_EnterScope();
+    Fortify_CheckAllMemory();
+    */
+    
+    /*
+      allocate data
+    */
+    fHandle = (pNexusFunction)malloc(sizeof(NexusFunction));
+    if (fHandle == NULL) {
+      NXReportError("ERROR: no memory to create Function structure");
+      return NX_ERROR;
+    }
+    memset(fHandle, 0, sizeof(NexusFunction)); /* so any functions we miss are NULL */
+       
+    /*
+      test the strip flag. Elimnate it for the rest of the tests to work
+    */
+    fHandle->stripFlag = 1;
+    if(am & NXACC_NOSTRIP){
+      fHandle->stripFlag = 0;
+      am = (NXaccess)(am & ~NXACC_NOSTRIP);
+    }
+    fHandle->checkNameSyntax = 0;
+    if (am & NXACC_CHECKNAMESYNTAX) {
+        fHandle->checkNameSyntax = 1;
+        am = (NXaccess)(am & ~NXACC_CHECKNAMESYNTAX);
+    }
+
+
+    if (my_am==NXACC_CREATE) {
+      /* HDF4 will be used ! */
+      hdf_type=1;
+      filename = strdup(userfilename);
+    } else if (my_am==NXACC_CREATE4) {
+      /* HDF4 will be used ! */
+      hdf_type=1;   
+      filename = strdup(userfilename);
+    } else if (my_am==NXACC_CREATE5) {
+      /* HDF5 will be used ! */
+      hdf_type=2;   
+      filename = strdup(userfilename);
+    } else if (my_am==NXACC_CREATEXML) {
+      /* XML will be used ! */
+      hdf_type=3;   
+      filename = strdup(userfilename);
+    } else {
+      filename = locateNexusFileInPath((char *)userfilename);
+      if(filename == NULL){
+	NXReportError("Out of memory in NeXus-API");
+	free(fHandle);
+	return NX_ERROR;
+      }
+      /* check file type hdf4/hdf5/XML for reading */
+      iRet = determineFileType(filename);
+      if(iRet < 0) {
+	snprintf(error,1023,"failed to open %s for reading",
+		 filename);
+	NXReportError(error);
+	free(filename);
+	return NX_ERROR;
+      }
+      if(iRet == 0){
+	snprintf(error,1023,"failed to determine filetype for %s ",
+		 filename);
+	NXReportError(error);
+	free(filename);
+	free(fHandle);
+	return NX_ERROR;
+      }
+      hdf_type = iRet;
+    }
+    if(filename == NULL){
+	NXReportError("Out of memory in NeXus-API");
+	return NX_ERROR;
+    }
+
+    if (hdf_type==1) {
+      /* HDF4 type */
+#ifdef HDF4
+    NXhandle hdf4_handle = NULL;
+      retstat = NX4open((const char *)filename,am,&hdf4_handle);
+      if(retstat != NX_OK){
+	free(fHandle);
+	free(filename);
+	return retstat;
+      }
+      fHandle->pNexusData=hdf4_handle;
+      NX4assignFunctions(fHandle);
+      pushFileStack(fileStack,fHandle,filename);
+#else
+      NXReportError(
+         "ERROR: Attempt to create HDF4 file when not linked with HDF4");
+      retstat = NX_ERROR;
+#endif /* HDF4 */
+      free(filename);
+      return retstat; 
+    } else if (hdf_type==2) {
+      /* HDF5 type */
+#ifdef HDF5
+      retstat = NX5open(filename,am,&hdf5_handle);
+      if(retstat != NX_OK){
+	free(fHandle);
+	free(filename);
+	return retstat;
+      }
+      fHandle->pNexusData=hdf5_handle;
+      NX5assignFunctions(fHandle);
+      pushFileStack(fileStack,fHandle, filename);
+#else
+      NXReportError(
+	 "ERROR: Attempt to create HDF5 file when not linked with HDF5");
+      retstat = NX_ERROR;
+#endif /* HDF5 */
+      free(filename);
+      return retstat;
+    } else if(hdf_type == 3){
+      /*
+	XML type
+      */
+#ifdef NXXML
+    NXhandle xmlHandle = NULL;
+      retstat = NXXopen(filename,am,&xmlHandle);
+      if(retstat != NX_OK){
+	free(fHandle);
+	free(filename);
+	return retstat;
+      }
+      fHandle->pNexusData=xmlHandle;
+      NXXassignFunctions(fHandle);
+      pushFileStack(fileStack,fHandle, filename);
+#else
+      NXReportError(
+	 "ERROR: Attempt to create XML file when not linked with XML");
+      retstat = NX_ERROR;
+#endif
+    } else {
+      NXReportError(
+          "ERROR: Format not readable by this NeXus library");
+      retstat = NX_ERROR;
+    }
+    if (filename != NULL) {
+ 	free(filename); 
+    }
+    return retstat;
+  }
+
+static NXstatus   NXinternalopen(CONSTCHAR *userfilename, NXaccess am, pFileStack fileStack)
+{
+    return LOCKED_CALL(NXinternalopenImpl(userfilename, am, fileStack));
+}
+
+
+NXstatus  NXreopen(NXhandle pOrigHandle, NXhandle* pNewHandle)
+{
+      pFileStack newFileStack;
+	  pFileStack origFileStack = (pFileStack)pOrigHandle;
+	pNexusFunction fOrigHandle = NULL, fNewHandle = NULL;
+	  *pNewHandle = NULL;
+	  newFileStack = makeFileStack();
+	  if(newFileStack == NULL){
+          NXReportError ("ERROR: no memory to create filestack");
+          return NX_ERROR;
+      }
+	  // The code below will only open the last file on a stack
+	  // for the moment raise an error, but this behaviour may be OK
+	  if (fileStackDepth(origFileStack) > 0)    
+	  {
+		NXReportError (
+          "ERROR: handle stack referes to many files - cannot reopen");
+		  return NX_ERROR;
+	  }
+	  fOrigHandle = peekFileOnStack(origFileStack);
+	  if (fOrigHandle->nxreopen == NULL)
+	  {
+		NXReportError (
+          "ERROR: NXreopen not implemented for this underlying file format");
+		  return NX_ERROR;
+	  }
+	  fNewHandle = (NexusFunction*)malloc(sizeof(NexusFunction));
+	  memcpy(fNewHandle, fOrigHandle, sizeof(NexusFunction));
+	  LOCKED_CALL(fNewHandle->nxreopen( fOrigHandle->pNexusData, &(fNewHandle->pNexusData) ));
+	  pushFileStack( newFileStack, fNewHandle, peekFilenameOnStack(origFileStack) );
+	  *pNewHandle = newFileStack;
+	  return NX_OK;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+  NXstatus  NXclose (NXhandle *fid)
+  { 
+    NXhandle hfil; 
+    int status;
+    pFileStack fileStack = NULL;
+    pNexusFunction pFunc=NULL;
+    if (*fid == NULL)
+    {
+	return NX_OK;
+    }
+    fileStack = (pFileStack)*fid;
+    pFunc = peekFileOnStack(fileStack);
+    hfil = pFunc->pNexusData;
+    status = LOCKED_CALL(pFunc->nxclose(&hfil));
+    pFunc->pNexusData = hfil;
+    free(pFunc);
+    popFileStack(fileStack);
+    if(fileStackDepth(fileStack) < 0){
+      killFileStack(fileStack);
+      *fid = NULL;
+    }
+    /* we can't set fid to NULL always as the handle points to a stack of files for external file support */
+    /* 
+    Fortify_CheckAllMemory();
+    */
+
+    return status;   
+  }
+
+  /*-----------------------------------------------------------------------*/   
+
+  NXstatus  NXmakegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
+  {
+     char buffer[256];
+     pNexusFunction pFunc = handleToNexusFunc(fid);
+     if ( pFunc->checkNameSyntax && (nxclass != NULL) /* && !strncmp("NX", nxclass, 2) */ && !validNXName(name, 0) )
+     {
+        sprintf(buffer, "ERROR: invalid characters in group name \"%s\"", name);
+        NXReportError(buffer);
+	return NX_ERROR;
+     }
+     return LOCKED_CALL(pFunc->nxmakegroup(pFunc->pNexusData, name, nxclass));   
+  }
+  /*------------------------------------------------------------------------*/
+static int analyzeNapimount(char *napiMount, char *extFile, int extFileLen, 
+			    char *extPath, int extPathLen){
+  char *pPtr = NULL, *path = NULL;
+  int length;
+
+  memset(extFile,0,extFileLen);
+  memset(extPath,0,extPathLen);
+  pPtr = strstr(napiMount,"nxfile://");
+  if(pPtr == NULL){
+    return NXBADURL;
+  }
+  path = strrchr(napiMount,'#');
+  if(path == NULL){
+    length = (int)strlen(napiMount) - 9;
+    if(length > extFileLen){
+      NXReportError("ERROR: internal errro with external linking");
+      return NXBADURL;
+    }
+    memcpy(extFile,pPtr+9,length);
+    strcpy(extPath,"/");
+    return NXFILE;
+  } else {
+    pPtr += 9;
+    length = (int)(path - pPtr);
+    if(length > extFileLen){
+      NXReportError("ERROR: internal errro with external linking");
+      return NXBADURL;
+    }
+    memcpy(extFile,pPtr,length);
+    length = (int)strlen(path-1);
+    if(length > extPathLen){
+      NXReportError("ERROR: internal error with external linking");
+      return NXBADURL;
+    }
+    strcpy(extPath,path+1);
+    return NXFILE;
+  }
+  return NXBADURL;
+}
+  /*------------------------------------------------------------------------*/
+
+  NXstatus  NXopengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
+  {
+    int status, attStatus, type = NX_CHAR, length = 1023;
+    NXaccess access = NXACC_READ;
+    NXlink breakID;
+    pFileStack fileStack;    
+    char nxurl[1024], exfile[512], expath[512];
+    pNexusFunction pFunc = NULL;
+
+    fileStack = (pFileStack)fid;
+    pFunc = handleToNexusFunc(fid);
+
+    status = LOCKED_CALL(pFunc->nxopengroup(pFunc->pNexusData, name, nxclass));  
+    if(status == NX_OK){
+      pushPath(fileStack,name);
+    }
+    NXMDisableErrorReporting();
+    attStatus = NXgetattr(fid,"napimount",nxurl,&length, &type);
+    NXMEnableErrorReporting();
+    if(attStatus == NX_OK){
+      /*
+	this is an external linking group
+      */
+      status = analyzeNapimount(nxurl,exfile,511,expath,511);
+      if(status == NXBADURL){
+	return NX_ERROR;
+      }
+      status = NXinternalopen(exfile, access, fileStack);
+      if(status == NX_ERROR){
+	return status;
+      }
+      status = NXopenpath(fid, expath);
+      NXgetgroupID(fid,&breakID);
+      setCloseID(fileStack,breakID);
+    }
+    
+    return status;
+  } 
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXclosegroup (NXhandle fid)
+  {
+    int status;
+    pFileStack fileStack = NULL;
+    NXlink closeID, currentID;
+
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    fileStack = (pFileStack)fid;
+    if(fileStackDepth(fileStack) == 0){
+      status = LOCKED_CALL(pFunc->nxclosegroup(pFunc->pNexusData));  
+      if(status == NX_OK){
+	popPath(fileStack);
+      }
+      return status;
+    } else {
+      /* we have to check for leaving an external file */
+      NXgetgroupID(fid,&currentID);
+      peekIDOnStack(fileStack,&closeID);
+      if(NXsameID(fid,&closeID,&currentID) == NX_OK){
+	NXclose(&fid);
+	status = NXclosegroup(fid);
+      } else {
+	status = LOCKED_CALL(pFunc->nxclosegroup(pFunc->pNexusData));
+	if(status == NX_OK){
+	  popPath(fileStack);
+	}
+      }
+      return status;
+    }
+  }   
+
+  /* --------------------------------------------------------------------- */
+  
+  NXstatus  NXmakedata (NXhandle fid, CONSTCHAR *name, int datatype, 
+                                  int rank, int dimensions[])
+  {
+	  int status;
+	  int64_t* dims64 = dupDimsArray(dimensions, rank);
+      status = NXmakedata64(fid, name, datatype, rank, dims64);
+	  free(dims64);
+	  return status;
+  }
+
+  NXstatus  NXmakedata64 (NXhandle fid, CONSTCHAR *name, int datatype, 
+                                  int rank, int64_t dimensions[])
+  {
+    char buffer[256];
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    if ( pFunc->checkNameSyntax && !validNXName(name, 0) )
+    {
+        sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
+        NXReportError(buffer);
+	return NX_ERROR;
+    }
+    return LOCKED_CALL(pFunc->nxmakedata64(pFunc->pNexusData, name, datatype, rank, dimensions)); 
+  }
+
+ /* --------------------------------------------------------------------- */
+  
+  NXstatus  NXcompmakedata (NXhandle fid, CONSTCHAR *name, int datatype, 
+                           int rank, int dimensions[], int compress_type, int chunk_size[])
+  {
+	  int status;
+	  int64_t* dims64 = dupDimsArray(dimensions, rank);
+	  int64_t* chunk64 = dupDimsArray(chunk_size, rank);
+      status = NXcompmakedata64(fid, name, datatype, rank, dims64, compress_type, chunk64);
+	  free(dims64);
+	  free(chunk64);
+	  return status;
+  } 
+  
+  NXstatus  NXcompmakedata64 (NXhandle fid, CONSTCHAR *name, int datatype, 
+                           int rank, int64_t dimensions[], int compress_type, int64_t chunk_size[])
+  {
+    char buffer[256];
+    pNexusFunction pFunc = handleToNexusFunc(fid); 
+    if ( pFunc->checkNameSyntax && !validNXName(name, 0) )
+    {
+        sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
+        NXReportError(buffer);
+	return NX_ERROR;
+    }
+    return LOCKED_CALL(pFunc->nxcompmakedata64 (pFunc->pNexusData, name, datatype, rank, dimensions, compress_type, chunk_size)); 
+  } 
+ 
+  /* --------------------------------------------------------------------- */
+
+  NXstatus  NXcompress (NXhandle fid, int compress_type)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid); 
+    return LOCKED_CALL(pFunc->nxcompress (pFunc->pNexusData, compress_type)); 
+  }
+  
+ 
+  /* --------------------------------------------------------------------- */
+  
+  NXstatus  NXopendata (NXhandle fid, CONSTCHAR *name)
+  {
+    int status, attStatus, type = NX_CHAR, length = 1023;
+    NXaccess access = NXACC_READ;
+    NXlink breakID;
+    pFileStack fileStack;
+    char nxurl[1024], exfile[512], expath[512];
+    pNexusFunction pFunc = NULL;
+
+    fileStack = (pFileStack)fid;
+    pFunc = handleToNexusFunc(fid);
+    status = LOCKED_CALL(pFunc->nxopendata(pFunc->pNexusData, name)); 
+
+    if(status == NX_OK){
+      pushPath(fileStack,name);
+    }
+
+    NXMDisableErrorReporting();
+    attStatus = NXgetattr(fid,"napimount",nxurl,&length, &type);
+    NXMEnableErrorReporting();
+    if(attStatus == NX_OK){
+      /*
+        this is an external linking group
+      */
+      status = analyzeNapimount(nxurl,exfile,511,expath,511);
+      if(status == NXBADURL){
+        return NX_ERROR;
+      }
+      status = NXinternalopen(exfile, access, fileStack);
+      if(status == NX_ERROR){
+        return status;
+      }
+      status = NXopenpath(fid,expath);
+      NXgetdataID(fid,&breakID);
+      setCloseID(fileStack,breakID);
+    }
+
+    return status;
+  } 
+
+  /* ----------------------------------------------------------------- */
+    
+  NXstatus NXclosedata (NXhandle fid)
+  { 
+    int status;
+    pFileStack fileStack = NULL;
+    NXlink closeID, currentID;
+
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    fileStack = (pFileStack)fid;
+
+    if(fileStackDepth(fileStack) == 0){
+      status = LOCKED_CALL(pFunc->nxclosedata(pFunc->pNexusData));
+      if(status == NX_OK){
+        popPath(fileStack);
+      }
+      return status;
+    } else {
+      /* we have to check for leaving an external file */
+      NXgetdataID(fid,&currentID);
+      peekIDOnStack(fileStack,&closeID);
+      if(NXsameID(fid,&closeID,&currentID) == NX_OK){
+        NXclose(&fid);
+        status = NXclosedata(fid);
+      } else {
+        status = LOCKED_CALL(pFunc->nxclosedata(pFunc->pNexusData));
+        if(status == NX_OK){
+          popPath(fileStack);
+        }
+      }
+      return status;
+    }
+  }
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXputdata (NXhandle fid, const void *data)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxputdata(pFunc->pNexusData, data));
+  }
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXputattr (NXhandle fid, CONSTCHAR *name, const void *data, 
+                                  int datalen, int iType)
+  {
+    char buffer[256];
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    if (datalen > 1 && iType != NX_CHAR)
+    {
+	NXReportError("NXputattr: numeric arrays are not allowed as attributes - only character strings and single numbers");
+	return NX_ERROR;
+    }
+    if ( pFunc->checkNameSyntax && !validNXName(name, 0) )
+    {
+        sprintf(buffer, "ERROR: invalid characters in attribute name \"%s\"", name);
+        NXReportError(buffer);
+	return NX_ERROR;
+    }
+    return LOCKED_CALL(pFunc->nxputattr(pFunc->pNexusData, name, data, datalen, iType));
+  }
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXputslab (NXhandle fid, const void *data, const int iStart[], const int iSize[])
+  {
+	  int i, iType, rank;
+	  int64_t iStart64[NX_MAXRANK], iSize64[NX_MAXRANK];
+	  if (NXgetinfo64(fid, &rank, iStart64, &iType) != NX_OK)
+	  {
+		  return NX_ERROR;
+	  }
+	  for(i=0; i < rank; ++i)
+	  {
+		  iStart64[i] = iStart[i];
+		  iSize64[i] = iSize[i];
+	  }
+	  return NXputslab64(fid, data, iStart64, iSize64);
+  }
+
+  NXstatus  NXputslab64 (NXhandle fid, const void *data, const int64_t iStart[], const int64_t iSize[])
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxputslab64(pFunc->pNexusData, data, iStart, iSize));
+  }
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXgetdataID (NXhandle fid, NXlink* sRes)
+  {  
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetdataID(pFunc->pNexusData, sRes));
+  }
+
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXmakelink (NXhandle fid, NXlink* sLink)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxmakelink(pFunc->pNexusData, sLink));
+  }
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NXmakenamedlink (NXhandle fid, CONSTCHAR *newname,  NXlink* sLink)
+  {
+    char buffer[256];
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    if ( pFunc->checkNameSyntax && !validNXName(newname, 0) )
+    {
+        sprintf(buffer, "ERROR: invalid characters in link name \"%s\"", newname);
+        NXReportError(buffer);
+	return NX_ERROR;
+    }
+    return LOCKED_CALL(pFunc->nxmakenamedlink(pFunc->pNexusData, newname, sLink));
+  }
+  /* --------------------------------------------------------------------*/
+  NXstatus  NXopensourcegroup(NXhandle fid)
+  {
+    char target_path[512];
+    int status, type = NX_CHAR, length = 511;
+
+    status = NXgetattr(fid,"target",target_path,&length,&type);
+    if(status != NX_OK)
+    {
+      NXReportError("ERROR: item not linked");
+      return NX_ERROR;
+    }
+    return NXopengrouppath(fid,target_path);
+  }
+  /*----------------------------------------------------------------------*/
+
+  NXstatus  NXflush(NXhandle *pHandle)
+  {
+    NXhandle hfil; 
+    pFileStack fileStack = NULL;
+    int status;
+   
+    pNexusFunction pFunc=NULL;
+    fileStack = (pFileStack)*pHandle;
+    pFunc = peekFileOnStack(fileStack);
+    hfil = pFunc->pNexusData;
+    status =  LOCKED_CALL(pFunc->nxflush(&hfil));
+    pFunc->pNexusData = hfil;
+    return status; 
+  }
+
+
+  /*-------------------------------------------------------------------------*/
+  
+  
+  NXstatus  NXmalloc (void** data, int rank, 
+				   const int dimensions[], int datatype)
+  {
+	  int status;
+	  int64_t* dims64 = dupDimsArray((int *)dimensions, rank);
+	  status = NXmalloc64(data, rank, dims64, datatype);
+	  free(dims64);
+	  return status;
+  }
+
+  NXstatus  NXmalloc64 (void** data, int rank, 
+				   const int64_t dimensions[], int datatype)
+  {
+    int i;
+    size_t size = 1;
+    *data = NULL;
+    for(i=0; i<rank; i++)
+	{
+        size *= (size_t)dimensions[i];
+	}
+    if ((datatype == NX_CHAR) || (datatype == NX_INT8) 
+	    || (datatype == NX_UINT8)) {
+        /* allow for terminating \0 */
+      size += 2;
+      }
+      else if ((datatype == NX_INT16) || (datatype == NX_UINT16)) {
+      size *= 2;
+      }    
+      else if ((datatype == NX_INT32) || (datatype == NX_UINT32) 
+	       || (datatype == NX_FLOAT32)) {
+        size *= 4;
+      }    
+      else if ((datatype == NX_INT64) || (datatype == NX_UINT64)){
+        size *= 8;
+      }    
+      else if (datatype == NX_FLOAT64) {
+        size *= 8;
+      }
+      else {
+        NXReportError(
+			"ERROR: NXmalloc - unknown data type in array");
+        return NX_ERROR;
+    }
+    *data = (void*)malloc(size);
+     memset(*data,0,size);
+    return NX_OK;
+  }
+    
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXfree (void** data)
+  {
+    if (data == NULL) {
+       NXReportError( "ERROR: passing NULL to NXfree");
+       return NX_ERROR;
+    }
+    if (*data == NULL) {
+       NXReportError("ERROR: passing already freed pointer to NXfree");
+       return NX_ERROR;
+    }
+    free(*data);
+    *data = NULL;
+    return NX_OK;
+  }
+
+  /* --------------------------------------------------------------------- */
+           
+ 
+  NXstatus  NXgetnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetnextentry(pFunc->pNexusData, name, nxclass, datatype));  
+  }
+/*----------------------------------------------------------------------*/
+/*
+**  TRIM.C - Remove leading, trailing, & excess embedded spaces
+**
+**  public domain by Bob Stout
+*/
+#define NUL '\0'
+
+char *nxitrim(char *str)
+{
+      char *ibuf = str;
+      int i = 0;
+
+      /*
+      **  Trap NULL
+      */
+
+      if (str)
+      {
+            /*
+            **  Remove leading spaces (from RMLEAD.C)
+            */
+
+            for (ibuf = str; *ibuf && isspace(*ibuf); ++ibuf)
+                  ;
+	    str = ibuf;
+
+            /*
+            **  Remove trailing spaces (from RMTRAIL.C)
+            */
+	    i = (int)strlen(str);
+            while (--i >= 0)
+            {
+                  if (!isspace(str[i]))
+                        break;
+            }
+            str[++i] = NUL;
+      }
+      return str;
+}
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetdata (NXhandle fid, void *data)
+  {
+    int status, type, rank;
+	int64_t iDim[NX_MAXRANK];
+    char *pPtr, *pPtr2;
+
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    status = LOCKED_CALL(pFunc->nxgetinfo64(pFunc->pNexusData, &rank, iDim, &type)); /* unstripped size if string */
+    /* only strip one dimensional strings */
+    if ( (type == NX_CHAR) && (pFunc->stripFlag == 1) && (rank == 1) )
+    {
+		pPtr = (char*)malloc((size_t)iDim[0]+5);
+        memset(pPtr, 0, (size_t)iDim[0]+5);
+        status = LOCKED_CALL(pFunc->nxgetdata(pFunc->pNexusData, pPtr)); 
+		pPtr2 = nxitrim(pPtr);
+		strncpy((char*)data, pPtr2, strlen(pPtr2)); /* not NULL terminated by default */
+		free(pPtr);
+    }
+    else
+    {
+        status = LOCKED_CALL(pFunc->nxgetdata(pFunc->pNexusData, data)); 
+    }
+    return status;
+  }
+/*---------------------------------------------------------------------------*/
+  NXstatus  NXgetrawinfo64 (NXhandle fid, int *rank, 
+				    int64_t dimension[], int *iType)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetinfo64(pFunc->pNexusData, rank, dimension, iType));
+  }
+
+  NXstatus  NXgetrawinfo (NXhandle fid, int *rank, 
+				    int dimension[], int *iType)
+  {
+    int i, status;
+	int64_t dims64[NX_MAXRANK];
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    status = LOCKED_CALL(pFunc->nxgetinfo64(pFunc->pNexusData, rank, dims64, iType));
+	for(i=0; i < *rank; ++i)
+	{
+		dimension[i] = (int)dims64[i];
+	}
+    return status;
+  }
+  /*-------------------------------------------------------------------------*/
+ 
+  NXstatus  NXgetinfo (NXhandle fid, int *rank, 
+				    int dimension[], int *iType)
+  {
+	  int i, status;
+	  int64_t dims64[NX_MAXRANK];
+	  status = NXgetinfo64(fid, rank, dims64, iType);
+	  for(i=0; i < *rank; ++i)
+	  {
+		  dimension[i] = (int)dims64[i];
+	  }
+	  return status;
+  }
+
+  NXstatus  NXgetinfo64 (NXhandle fid, int *rank, 
+				    int64_t dimension[], int *iType)
+  {
+    int status;
+    char *pPtr = NULL;
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+	*rank = 0;
+    status = LOCKED_CALL(pFunc->nxgetinfo64(pFunc->pNexusData, rank, dimension, iType));
+    /*
+      the length of a string may be trimmed....
+    */
+    /* only strip one dimensional strings */
+    if((*iType == NX_CHAR) && (pFunc->stripFlag == 1) && (*rank == 1)){
+      pPtr = (char *)malloc((size_t)(dimension[0]+1)*sizeof(char));
+      if(pPtr != NULL){
+	memset(pPtr,0,(size_t)(dimension[0]+1)*sizeof(char));
+	LOCKED_CALL(pFunc->nxgetdata(pFunc->pNexusData, pPtr));
+	dimension[0] = strlen(nxitrim(pPtr));
+	free(pPtr);
+      }
+    } 
+    return status;
+  }
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetslab (NXhandle fid, void *data, 
+				    const int iStart[], const int iSize[])
+  {
+	  int i, iType, rank;
+	  int64_t iStart64[NX_MAXRANK], iSize64[NX_MAXRANK];
+	  if (NXgetinfo64(fid, &rank, iStart64, &iType) != NX_OK)
+	  {
+		  return NX_ERROR;
+	  }
+	  for(i=0; i < rank; ++i)
+	  {
+		  iStart64[i] = iStart[i];
+		  iSize64[i] = iSize[i];
+	  }
+	  return NXgetslab64(fid, data, iStart64, iSize64);
+  }
+  
+  NXstatus  NXgetslab64 (NXhandle fid, void *data, 
+				    const int64_t iStart[], const int64_t iSize[])
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetslab64(pFunc->pNexusData, data, iStart, iSize));
+  }
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetnextattr (NXhandle fileid, NXname pName,
+                                     int *iLength, int *iType)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fileid);
+    return LOCKED_CALL(pFunc->nxgetnextattr(pFunc->pNexusData, pName, iLength, iType));  
+  }
+ 
+
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetattr(pFunc->pNexusData, name, data, datalen, iType));  
+  }
+
+
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetattrinfo (NXhandle fid, int *iN)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetattrinfo(pFunc->pNexusData, iN));  
+  }
+
+
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetgroupID (NXhandle fileid, NXlink* sRes)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fileid);
+    return LOCKED_CALL(pFunc->nxgetgroupID(pFunc->pNexusData, sRes));  
+  }
+
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXgetgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxgetgroupinfo(pFunc->pNexusData, iN, pName, pClass));  
+  }
+
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NXsameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fileid);
+    return LOCKED_CALL(pFunc->nxsameID(pFunc->pNexusData, pFirstID, pSecondID));  
+  }
+
+  /*-------------------------------------------------------------------------*/
+  
+  NXstatus  NXinitattrdir (NXhandle fid)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxinitattrdir(pFunc->pNexusData));
+  }
+  /*-------------------------------------------------------------------------*/
+  
+  NXstatus  NXsetnumberformat (NXhandle fid, 
+					    int type, char *format)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    if(pFunc->nxsetnumberformat != NULL)
+    {
+      return LOCKED_CALL(pFunc->nxsetnumberformat(pFunc->pNexusData,type,format));
+    }
+    else
+    {
+      /*
+	silently ignore this. Most NeXus file formats do not require
+        this
+      */
+      return NX_OK;
+    }
+  }
+  
+  
+  /*-------------------------------------------------------------------------*/
+ 
+  NXstatus  NXinitgroupdir (NXhandle fid)
+  {
+    pNexusFunction pFunc = handleToNexusFunc(fid);
+    return LOCKED_CALL(pFunc->nxinitgroupdir(pFunc->pNexusData));
+  }
+/*----------------------------------------------------------------------*/
+ NXstatus  NXinquirefile(NXhandle handle, char *filename, 
+				int filenameBufferLength){
+  pFileStack fileStack;
+  char *pPtr = NULL;
+  int length, status;
+
+  pNexusFunction pFunc = handleToNexusFunc(handle);
+   if (pFunc->nxnativeinquirefile != NULL) {
+
+  	status = LOCKED_CALL(pFunc->nxnativeinquirefile(pFunc->pNexusData, filename, filenameBufferLength));
+	if (status < 0) {
+		return NX_ERROR;
+	} else {
+		return NX_OK;
+	}
+
+   }
+
+  fileStack = (pFileStack)handle;
+  pPtr = peekFilenameOnStack(fileStack);
+  if(pPtr != NULL){
+    length = (int)strlen(pPtr);
+    if(length > filenameBufferLength){
+      length = filenameBufferLength -1;
+    }
+    memset(filename,0,filenameBufferLength);
+    memcpy(filename,pPtr, length);
+    return NX_OK;
+  } else {
+    return NX_ERROR;
+  }
+}
+/*------------------------------------------------------------------------*/
+NXstatus  NXisexternalgroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, 
+			    char *url, int urlLen){
+  int status, attStatus, length = 1023, type = NX_CHAR;
+  char nxurl[1024];
+
+  pNexusFunction pFunc = handleToNexusFunc(fid);
+
+   if (pFunc->nxnativeisexternallink != NULL) {
+  	status = LOCKED_CALL(pFunc->nxnativeisexternallink(pFunc->pNexusData, name, url, urlLen));
+	if (status == NX_OK) {
+		return NX_OK;
+	}
+	// need to continue, could still be old style link
+   }
+
+  status = LOCKED_CALL(pFunc->nxopengroup(pFunc->pNexusData, name, nxclass));
+  if(status != NX_OK){
+    return status;
+  }
+  NXMDisableErrorReporting();
+  attStatus = NXgetattr(fid,"napimount",nxurl,&length, &type);
+  NXMEnableErrorReporting();
+  LOCKED_CALL(pFunc->nxclosegroup(pFunc->pNexusData));
+  if(attStatus == NX_OK){
+    length = (int)strlen(nxurl);
+    if(length >= urlLen){
+      length = urlLen - 1;
+    }
+    memset(url,0,urlLen);
+    memcpy(url,nxurl,length);
+    return attStatus;
+  } else {
+    return NX_ERROR;
+  }
+}
+/*------------------------------------------------------------------------*/
+NXstatus  NXisexternaldataset(NXhandle fid, CONSTCHAR *name,
+			    char *url, int urlLen){
+  int status, attStatus, length = 1023, type = NX_CHAR;
+  char nxurl[1024];
+
+  pNexusFunction pFunc = handleToNexusFunc(fid);
+
+   if (pFunc->nxnativeisexternallink != NULL) {
+  	status = LOCKED_CALL(pFunc->nxnativeisexternallink(pFunc->pNexusData, name, url, urlLen));
+	if (status == NX_OK) {
+		return NX_OK;
+	}
+	// need to continue, could still be old style link
+   }
+
+  status = LOCKED_CALL(pFunc->nxopendata(pFunc->pNexusData, name));
+  if(status != NX_OK){
+    return status;
+  }
+  NXMDisableErrorReporting();
+  attStatus = NXgetattr(fid,"napimount",nxurl,&length, &type);
+  NXMEnableErrorReporting();
+  LOCKED_CALL(pFunc->nxclosedata(pFunc->pNexusData));
+  if(attStatus == NX_OK){
+    length = (int)strlen(nxurl);
+    if(length >= urlLen){
+      length = urlLen - 1;
+    }
+    memset(url,0,urlLen);
+    memcpy(url,nxurl,length);
+    return attStatus;
+  } else {
+    return NX_ERROR;
+  }
+}
+/*------------------------------------------------------------------------*/
+NXstatus  NXlinkexternal(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, CONSTCHAR *url) {
+  int status, type = NX_CHAR, length=1024, urllen;
+  char nxurl[1024], exfile[512], expath[512];
+  pNexusFunction pFunc = handleToNexusFunc(fid);
+
+  // in HDF5 we support external linking natively
+  if (pFunc->nxnativeexternallink != NULL) {
+        urllen = (int)strlen(url);
+        memset(nxurl, 0, length);
+        if(urllen >= length){
+          urllen = length - 1;
+        }
+        memcpy(nxurl, url, urllen);
+        status = analyzeNapimount(nxurl,exfile,511,expath,511);
+        if(status != NX_OK){
+           return status;
+        }
+	status = LOCKED_CALL(pFunc->nxnativeexternallink(pFunc->pNexusData, name, exfile, expath));
+        if(status != NX_OK){
+           return status;
+        }
+        return NX_OK;
+  }
+
+  NXMDisableErrorReporting();
+  LOCKED_CALL(pFunc->nxmakegroup(pFunc->pNexusData,name,nxclass));
+  NXMEnableErrorReporting();
+
+  status = LOCKED_CALL(pFunc->nxopengroup(pFunc->pNexusData,name,nxclass));
+  if(status != NX_OK){
+    return status;
+  }
+  length = (int)strlen(url);
+  status = NXputattr(fid, "napimount",url,length, type);
+  if(status != NX_OK){
+    return status;
+  }
+  LOCKED_CALL(pFunc->nxclosegroup(pFunc->pNexusData));
+  return NX_OK;
+}
+/*------------------------------------------------------------------------*/
+NXstatus  NXlinkexternaldataset(NXhandle fid, CONSTCHAR *name, 
+			 CONSTCHAR *url){
+  int status, type = NX_CHAR, length=1024, urllen;
+  char nxurl[1024], exfile[512], expath[512];
+  pNexusFunction pFunc = handleToNexusFunc(fid);
+  int rank = 1;
+  int64_t dims[1] = {1};
+  
+  //TODO cut and paste
+
+  // in HDF5 we support external linking natively
+  if (pFunc->nxnativeexternallink != NULL) {
+        urllen = (int)strlen(url);
+        memset(nxurl, 0, length);
+        if(urllen > length){
+          urllen = length - 1;
+        }
+        memcpy(nxurl, url, urllen);
+        status = analyzeNapimount(nxurl,exfile,511,expath,511);
+        if(status != NX_OK){
+           return status;
+        }
+	status = LOCKED_CALL(pFunc->nxnativeexternallink(pFunc->pNexusData, name, exfile, expath));
+        if(status != NX_OK){
+           return status;
+        }
+        return NX_OK;
+  }
+
+
+  status = LOCKED_CALL(pFunc->nxmakedata64(pFunc->pNexusData, name, NX_CHAR, rank, dims));
+  if(status != NX_OK){
+    return status;
+  }
+  status = LOCKED_CALL(pFunc->nxopendata(pFunc->pNexusData, name));
+  if(status != NX_OK){
+    return status;
+  }
+  length = (int)strlen(url);
+  status = NXputattr(fid, "napimount",url,length, type);
+  if(status != NX_OK){
+    return status;
+  }
+  LOCKED_CALL(pFunc->nxclosedata(pFunc->pNexusData));
+  return NX_OK;
+}
+/*------------------------------------------------------------------------
+  Implementation of NXopenpath 
+  --------------------------------------------------------------------------*/
+static int isDataSetOpen(NXhandle hfil)
+{
+  NXlink id;
+  
+  /*
+    This uses the (sensible) feauture that NXgetdataID returns NX_ERROR
+    when no dataset is open
+  */
+  if(NXgetdataID(hfil,&id) == NX_ERROR)
+  {
+    return 0;
+  }
+  else 
+  {
+    return 1;
+  }
+}
+/*----------------------------------------------------------------------*/
+static int isRoot(NXhandle hfil)
+{
+  NXlink id;
+  
+  /*
+    This uses the feauture that NXgetgroupID returns NX_ERROR
+    when we are at root level
+  */
+  if(NXgetgroupID(hfil,&id) == NX_ERROR)
+  {
+    return 1;
+  }
+  else 
+  {
+    return 0;
+  }
+}
+/*--------------------------------------------------------------------
+  copies the next path element into element.
+  returns a pointer into path beyond the extracted path
+  ---------------------------------------------------------------------*/
+static char *extractNextPath(char *path, NXname element)
+{
+  char *pPtr, *pStart;
+  int length;
+
+  pPtr = path;
+  /*
+    skip over leading /
+  */
+  if(*pPtr == '/')
+  {
+    pPtr++;
+  }
+  pStart = pPtr;
+  
+  /*
+    find next /
+  */
+  pPtr = strchr(pStart,'/');
+  if(pPtr == NULL)
+  {
+    /*
+      this is the last path element
+    */
+    strcpy(element,pStart);
+    return NULL;
+  } else {
+    length = (int)(pPtr - pStart);
+    strncpy(element,pStart,length);
+    element[length] = '\0';
+  }
+  return pPtr + 1;
+}
+/*-------------------------------------------------------------------*/
+static NXstatus gotoRoot(NXhandle hfil)
+{
+    int status;
+
+    if(isDataSetOpen(hfil))
+    {
+      status = NXclosedata(hfil);
+      if(status == NX_ERROR)
+      {
+	return status;
+      }
+    }
+    while(!isRoot(hfil))
+    {
+      status = NXclosegroup(hfil);
+      if(status == NX_ERROR)
+      {
+	return status;
+      }
+    }
+    return NX_OK;
+}
+/*--------------------------------------------------------------------*/
+static int isRelative(char *path)
+{
+  if(path[0] == '.' && path[1] == '.')
+    return 1;
+  else
+    return 0;
+}
+/*------------------------------------------------------------------*/
+static NXstatus moveOneDown(NXhandle hfil)
+{
+  if(isDataSetOpen(hfil))
+  {
+    return NXclosedata(hfil);
+  } 
+  else
+  {
+    return NXclosegroup(hfil);
+  }
+}
+/*-------------------------------------------------------------------
+  returns a pointer to the remaining path string to move up
+  --------------------------------------------------------------------*/
+static char *moveDown(NXhandle hfil, char *path, int *code)
+{
+  int status;
+  char *pPtr;
+
+  *code = NX_OK;
+
+  if(path[0] == '/')
+  {
+    *code = gotoRoot(hfil);
+    return path;
+  } 
+  else 
+  {
+    pPtr = path;
+    while(isRelative(pPtr))
+    {
+      status = moveOneDown(hfil);
+      if(status == NX_ERROR)
+      {
+	*code = status;
+	return pPtr;
+      }
+      pPtr += 3;
+    }
+    return pPtr;
+  }
+} 
+/*--------------------------------------------------------------------*/
+static NXstatus stepOneUp(NXhandle hfil, char *name)
+{
+  int datatype;
+  NXname name2, xclass;
+  char pBueffel[256];  
+
+  /*
+    catch the case when we are there: i.e. no further stepping
+    necessary. This can happen with paths like ../
+  */
+  if (strlen(name) < 1) {
+      return NX_OK;
+  }
+  
+  NXinitgroupdir(hfil);
+
+  while(NXgetnextentry(hfil, name2, xclass, &datatype) != NX_EOD)
+  {
+    if(strcmp(name2,name) == 0)
+    {
+      if(strcmp(xclass,"SDS") == 0)
+      {
+	return NXopendata(hfil,name);
+      } else {
+	return NXopengroup(hfil,name,xclass);
+      }
+    }
+  }
+  snprintf(pBueffel,255,"ERROR: NXopenpath cannot step into %s",name);
+  NXReportError( pBueffel);
+  return NX_ERROR;              
+}
+/*--------------------------------------------------------------------*/
+static NXstatus stepOneGroupUp(NXhandle hfil, char *name)
+{
+  int datatype;
+  NXname name2, xclass;
+  char pBueffel[256];  
+
+  /*
+    catch the case when we are there: i.e. no further stepping
+    necessary. This can happen with paths like ../
+  */
+  if(strlen(name) < 1)
+  {
+      return NX_OK;
+  }
+  
+  NXinitgroupdir(hfil);
+  while(NXgetnextentry(hfil,name2,xclass,&datatype) != NX_EOD)
+  {
+    
+    if(strcmp(name2,name) == 0)
+    {
+      if(strcmp(xclass,"SDS") == 0) {
+	return NX_EOD;
+      } 
+      else
+      {
+	return NXopengroup(hfil,name,xclass);
+      }
+    }
+  }
+  snprintf(pBueffel,255,"ERROR: NXopenpath cannot step into %s",name);
+  NXReportError( pBueffel);
+  return NX_ERROR;              
+}
+/*---------------------------------------------------------------------*/
+NXstatus  NXopenpath(NXhandle hfil, CONSTCHAR *path)
+{
+  int status, run = 1;
+  NXname pathElement;
+  char *pPtr;
+
+  if(hfil == NULL || path == NULL)
+  {
+    NXReportError(
+     "ERROR: NXopendata needs both a file handle and a path string");
+    return NX_ERROR;
+  }
+
+  pPtr = moveDown(hfil,(char *)path,&status);
+  if(status != NX_OK)
+  {
+    NXReportError( 
+		    "ERROR: NXopendata failed to move down in hierarchy");
+    return status;
+  }
+
+  while(run == 1)
+  {
+    pPtr = extractNextPath(pPtr, pathElement);
+    status = stepOneUp(hfil,pathElement);
+    if(status != NX_OK)
+    {
+      return status;
+    }
+    if(pPtr == NULL)
+    {
+      run = 0;
+    }
+  }
+  return NX_OK;
+}
+/*---------------------------------------------------------------------*/
+NXstatus  NXopengrouppath(NXhandle hfil, CONSTCHAR *path)
+{
+  int status, run = 1;
+  NXname pathElement;
+  char *pPtr;
+
+  if(hfil == NULL || path == NULL)
+  {
+    NXReportError(
+     "ERROR: NXopendata needs both a file handle and a path string");
+    return NX_ERROR;
+  }
+
+  pPtr = moveDown(hfil,(char *)path,&status);
+  if(status != NX_OK)
+  {
+    NXReportError( 
+		    "ERROR: NXopendata failed to move down in hierarchy");
+    return status;
+  }
+
+  while(run == 1)
+  {
+    pPtr = extractNextPath(pPtr, pathElement);
+    status = stepOneGroupUp(hfil,pathElement);
+    if(status == NX_ERROR)
+    {
+      return status;
+    }
+    if(pPtr == NULL || status == NX_EOD)
+    {
+      run = 0;
+    }
+  }
+  return NX_OK;
+}
+/*---------------------------------------------------------------------*/
+NXstatus NXIprintlink(NXhandle fid, NXlink* link)
+{
+     pNexusFunction pFunc = handleToNexusFunc(fid);
+     return LOCKED_CALL(pFunc->nxprintlink(pFunc->pNexusData, link));   
+}
+/*----------------------------------------------------------------------*/
+NXstatus NXgetpath(NXhandle fid, char *path, int pathlen){
+  int status;
+  pFileStack fileStack = NULL;
+
+  fileStack = (pFileStack)fid;
+  status = buildPath(fileStack,path,pathlen);
+  if(status != 1){
+    return NX_ERROR;
+  } 
+  return NX_OK;
+}
+
+/*--------------------------------------------------------------------
+  format NeXus time. Code needed in every NeXus file driver
+  ---------------------------------------------------------------------*/
+char *NXIformatNeXusTime(){
+    time_t timer;
+    char* time_buffer = NULL;
+    struct tm *time_info;
+    const char* time_format;
+    long gmt_offset;
+#ifdef USE_FTIME
+    struct timeb timeb_struct;
+#endif 
+
+    time_buffer = (char *)malloc(64*sizeof(char));
+    if(!time_buffer){
+      NXReportError("Failed to allocate buffer for time data");
+      return NULL;
+    }
+
+#ifdef NEED_TZSET
+    tzset();
+#endif 
+    time(&timer);
+#ifdef USE_FTIME
+    ftime(&timeb_struct);
+    gmt_offset = -timeb_struct.timezone * 60;
+    if (timeb_struct.dstflag != 0)
+    {
+        gmt_offset += 3600;
+    }
+#else
+    time_info = gmtime(&timer);
+    if (time_info != NULL)
+    {
+        gmt_offset = (long)difftime(timer, mktime(time_info));
+    }
+    else
+    {
+        NXReportError( 
+        "Your gmtime() function does not work ... timezone information will be incorrect\n");
+        gmt_offset = 0;
+    }
+#endif 
+    time_info = localtime(&timer);
+    if (time_info != NULL)
+    {
+        if (gmt_offset < 0)
+        {
+            time_format = "%04d-%02d-%02dT%02d:%02d:%02d-%02d:%02d";
+        }
+        else
+        {
+            time_format = "%04d-%02d-%02dT%02d:%02d:%02d+%02d:%02d";
+        }
+        sprintf(time_buffer, time_format,
+            1900 + time_info->tm_year,
+            1 + time_info->tm_mon,
+            time_info->tm_mday,
+            time_info->tm_hour,
+            time_info->tm_min,
+            time_info->tm_sec,
+            abs(gmt_offset / 3600),
+            abs((gmt_offset % 3600) / 60)
+        );
+    }
+    else
+    {
+        strcpy(time_buffer, "1970-01-01T00:00:00+00:00");
+    }
+    return time_buffer;
+}
+/*----------------------------------------------------------------------
+                 F77 - API - Support - Routines
+  ----------------------------------------------------------------------*/
+  /*
+   * We store the whole of the NeXus file in the array - that way
+   * we can just pass the array name to C as it will be a valid
+   * NXhandle. We could store the NXhandle value in the FORTRAN array
+   * instead, but that would mean writing far more wrappers
+   */
+  NXstatus  NXfopen(char * filename, NXaccess* am, 
+                                 NXhandle pHandle)
+  {
+	NXstatus ret;
+ 	NXhandle fileid = NULL;
+	ret = NXopen(filename, *am, &fileid);
+	if (ret == NX_OK)
+	{
+	  memcpy(pHandle, fileid, getFileStackSize());
+	}
+	else
+	{
+	  memset(pHandle, 0, getFileStackSize());
+	}
+	if (fileid != NULL)
+	{
+	    free(fileid);
+	}
+	return ret;
+  }
+/* 
+ * The pHandle from FORTRAN is a pointer to a static FORTRAN
+ * array holding the NexusFunction structure. We need to malloc()
+ * a temporary copy as NXclose will try to free() this
+ */
+  NXstatus  NXfclose (NXhandle pHandle)
+  {
+    NXhandle h;
+    NXstatus ret;
+    h = (NXhandle)malloc(getFileStackSize());
+    memcpy(h, pHandle, getFileStackSize());
+    ret = NXclose(&h);		/* does free(h) */
+    memset(pHandle, 0, getFileStackSize());
+    return ret;
+  }
+  
+/*---------------------------------------------------------------------*/  
+  NXstatus  NXfflush(NXhandle pHandle)
+  {
+    NXhandle h;
+    NXstatus ret;
+    h = (NXhandle)malloc(getFileStackSize());
+    memcpy(h, pHandle, getFileStackSize());
+    ret = NXflush(&h);		/* modifies and reallocates h */
+    memcpy(pHandle, h, getFileStackSize());
+    return ret;
+  }
+/*----------------------------------------------------------------------*/
+  NXstatus  NXfmakedata(NXhandle fid, char *name, int *pDatatype,
+		int *pRank, int dimensions[])
+  {
+    NXstatus ret;
+    static char buffer[256];
+    int i, *reversed_dimensions;
+    reversed_dimensions = (int*)malloc(*pRank * sizeof(int));
+    if (reversed_dimensions == NULL)
+    {
+        sprintf (buffer, 
+        "ERROR: Cannot allocate space for array rank of %d in NXfmakedata", 
+                *pRank);
+        NXReportError( buffer);
+	return NX_ERROR;
+    }
+/*
+ * Reverse dimensions array as FORTRAN is column major, C row major
+ */
+    for(i=0; i < *pRank; i++)
+    {
+	reversed_dimensions[i] = dimensions[*pRank - i - 1];
+    }
+    ret = NXmakedata(fid, name, *pDatatype, *pRank, reversed_dimensions);
+    free(reversed_dimensions);
+    return ret;
+  }
+
+/*-----------------------------------------------------------------------*/
+  NXstatus  NXfcompmakedata(NXhandle fid, char *name, 
+                int *pDatatype,
+		int *pRank, int dimensions[],
+                int *compression_type, int chunk[])
+  {
+    NXstatus ret;
+    static char buffer[256];
+    int i, *reversed_dimensions, *reversed_chunk;
+    reversed_dimensions = (int*)malloc(*pRank * sizeof(int));
+    reversed_chunk = (int*)malloc(*pRank * sizeof(int));
+    if (reversed_dimensions == NULL || reversed_chunk == NULL)
+    {
+        sprintf (buffer, 
+      "ERROR: Cannot allocate space for array rank of %d in NXfcompmakedata", 
+         *pRank);
+        NXReportError( buffer);
+	return NX_ERROR;
+    }
+/*
+ * Reverse dimensions array as FORTRAN is column major, C row major
+ */
+    for(i=0; i < *pRank; i++)
+    {
+	reversed_dimensions[i] = dimensions[*pRank - i - 1];
+	reversed_chunk[i] = chunk[*pRank - i - 1];
+    }
+    ret = NXcompmakedata(fid, name, *pDatatype, *pRank, 
+        reversed_dimensions,*compression_type, reversed_chunk);
+    free(reversed_dimensions);
+    free(reversed_chunk);
+    return ret;
+  }
+/*-----------------------------------------------------------------------*/
+  NXstatus  NXfcompress(NXhandle fid, int *compr_type)
+  { 
+      return NXcompress(fid,*compr_type);
+  }
+/*-----------------------------------------------------------------------*/
+  NXstatus  NXfputattr(NXhandle fid, const char *name, const void *data, 
+                                   int *pDatalen, int *pIType)
+  {
+    return NXputattr(fid, name, data, *pDatalen, *pIType);
+  }
+
+
+  /*
+   * implement snprintf when it is not available 
+   */
+  int nxisnprintf(char* buffer, int len, const char* format, ... )
+  {
+	  int ret;
+	  va_list valist;
+	  va_start(valist,format);
+	  ret = vsprintf(buffer, format, valist);
+	  va_end(valist);
+	  return ret;
+  }
+
+/*--------------------------------------------------------------------------*/
+NXstatus NXfgetpath(NXhandle fid, char *path, int *pathlen)
+{
+  return NXgetpath(fid,path,*pathlen);
+}
+
+const char* NXgetversion()
+{
+    return NEXUS_VERSION ;
+}
+
diff --git a/src/napi4.c b/src/napi4.c
new file mode 100644
index 0000000..99e4fff
--- /dev/null
+++ b/src/napi4.c
@@ -0,0 +1,1983 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  Application Program Interface (HDF4) Routines
+  
+  Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+             
+  For further information, see <http://www.nexusformat.org>
+  
+  $Id$
+
+----------------------------------------------------------------------------*/
+
+#ifdef HDF4 
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+
+#include "napi.h"
+#include "napi4.h"
+
+extern	void *NXpData;
+
+  typedef struct __NexusFile {
+    struct iStack {
+      int32 *iRefDir;
+      int32 *iTagDir;
+      int32 iVref;
+      int32 __iStack_pad;               
+      int iNDir;
+      int iCurDir;
+    } iStack[NXMAXSTACK];
+    struct iStack iAtt;
+    int32 iVID;
+    int32 iSID;
+    int32 iCurrentVG;
+    int32 iCurrentSDS;
+    int iNXID;
+    int iStackPtr;
+    char iAccess[2];
+  } NexusFile, *pNexusFile;
+   /*-------------------------------------------------------------------*/
+
+  static pNexusFile NXIassert(NXhandle fid)
+  {
+    pNexusFile pRes;
+  
+    assert(fid != NULL);
+    pRes = (pNexusFile)fid;
+    assert(pRes->iNXID == NXSIGNATURE);
+    return pRes;
+  }
+  /*----------------------------------------------------------------------*/
+static int findNapiClass(pNexusFile pFile, int groupRef, NXname nxclass)
+{
+  NXname classText, linkClass;
+  int32 tags[2], attID, linkID, groupID;
+
+  groupID = Vattach(pFile->iVID,groupRef,"r");
+  Vgetclass(groupID, classText);
+  if(strcmp(classText,"NAPIlink") != 0)
+  {
+    /* normal group */
+    strcpy(nxclass,classText);
+    Vdetach(groupID);
+    return groupRef;
+  }
+  else 
+  {
+    /* code for linked renamed groups */
+    attID = Vfindattr(groupID,"NAPIlink");
+    if(attID >= 0)
+    {
+      Vgetattr(groupID,attID, tags);
+      linkID = Vattach(pFile->iVID,tags[1],"r");
+      Vgetclass(linkID, linkClass);
+      Vdetach(groupID);
+      Vdetach(linkID);
+      strcpy(nxclass,linkClass);
+      return tags[1];
+    } 
+    else
+    {
+      /* this allows for finding the NAPIlink group in NXmakenamedlink */
+      strcpy(nxclass,classText);
+      Vdetach(groupID);
+      return groupRef;
+    }
+  } 
+}
+  /* --------------------------------------------------------------------- */
+
+  static int32 NXIFindVgroup (pNexusFile pFile, CONSTCHAR *name, CONSTCHAR *nxclass)
+  {
+    int32 iNew, iRef, iTag;
+    int iN, i;
+    int32 *pArray = NULL;
+    NXname pText;
+  
+    assert (pFile != NULL);
+  
+    if (pFile->iCurrentVG == 0) { /* root level */
+      /* get the number and ID's of all lone Vgroups in the file */
+      iN = Vlone (pFile->iVID, NULL, 0);
+      if(iN == 0) {
+         return NX_EOD;
+      }
+      pArray = (int32 *) malloc (iN * sizeof (int32));
+      if (!pArray) {
+        NXReportError( "ERROR: out of memory in NXIFindVgroup");
+        return NX_EOD;
+      }
+      Vlone (pFile->iVID, pArray, iN);
+  
+      /* loop and check */
+      for (i = 0; i < iN; i++) {
+        iNew = Vattach (pFile->iVID, pArray[i], "r");
+        Vgetname (iNew, pText);
+        Vdetach(iNew);
+        if (strcmp (pText, name) == 0) {
+          pArray[i] = findNapiClass(pFile,pArray[i],pText);
+          if (strcmp (pText, nxclass) == 0) {
+            /* found ! */
+            iNew = pArray[i];
+            free (pArray);
+            return iNew;
+          }
+        }
+      }
+      /* nothing found */
+      free (pArray);
+      return NX_EOD;
+    } else {                      /* case in Vgroup */
+      iN = Vntagrefs (pFile->iCurrentVG);
+      for (i = 0; i < iN; i++) {
+        Vgettagref (pFile->iCurrentVG, i, &iTag, &iRef);
+        if (iTag == DFTAG_VG) {
+          iNew = Vattach (pFile->iVID, iRef, "r");
+          Vgetname (iNew, pText);
+          Vdetach(iNew);
+          if (strcmp (pText, name) == 0) {
+	    iRef = findNapiClass(pFile,iRef, pText);
+            if (strcmp (pText, nxclass) == 0) {
+              return iRef;
+            }
+          }
+        }
+      }                           /* end for */
+    }                             /* end else */
+    /* not found */
+    return NX_EOD;
+  }
+  
+  /*----------------------------------------------------------------------*/  
+
+  static int32 NXIFindSDS (NXhandle fid, CONSTCHAR *name)
+  {
+    pNexusFile self;
+    int32 iNew, iRet, iTag, iRef;
+    int32 i, iN, iA, iD1, iD2;
+    NXname pNam;
+    int32 iDim[H4_MAX_VAR_DIMS];
+  
+    self = NXIassert (fid);
+  
+    /* root level search */
+    if (self->iCurrentVG == 0) {
+      i = SDfileinfo (self->iSID, &iN, &iA);
+      if (i < 0) {
+        NXReportError( "ERROR: failure to read file information");
+        return NX_EOD;
+      }
+      for (i = 0; i < iN; i++) {
+        iNew = SDselect (self->iSID, i);
+        SDgetinfo (iNew, pNam, &iA, iDim, &iD1, &iD2);
+        if (strcmp (pNam, name) == 0) {
+          iRet = SDidtoref (iNew);
+          SDendaccess (iNew);
+          return iRet;
+        } else {
+          SDendaccess (iNew);
+        }
+      }
+      /* not found */
+      return NX_EOD;
+    }
+    /* end root level */
+    else {                        /* search in a Vgroup */
+      iN = Vntagrefs (self->iCurrentVG);
+      for (i = 0; i < iN; i++) {
+        Vgettagref (self->iCurrentVG, i, &iTag, &iRef);
+        /* we are now writing using DFTAG_NDG, but need others for backward compatability */
+        if ((iTag == DFTAG_SDG) || (iTag == DFTAG_NDG) || (iTag == DFTAG_SDS)) {
+          iNew = SDreftoindex (self->iSID, iRef);
+          iNew = SDselect (self->iSID, iNew);
+          SDgetinfo (iNew, pNam, &iA, iDim, &iD1, &iD2);
+          if (strcmp (pNam, name) == 0) {
+            SDendaccess (iNew);
+            return iRef;
+          }
+          SDendaccess (iNew);
+        }
+      }                           /* end for */
+    }                             /* end Vgroup */
+    /* we get here, only if nothing found */
+    return NX_EOD;
+  }
+  
+  /*----------------------------------------------------------------------*/
+
+  static int NXIInitDir (pNexusFile self)
+  {
+    int i;
+    int32 iTag, iRef;
+    int iStackPtr;
+  
+  /* 
+   * Note: the +1 to various malloc() operations is to avoid a
+   *  malloc(0), which is an error on some operating systems 
+   */
+    iStackPtr = self->iStackPtr;
+    if (self->iCurrentVG == 0 &&
+        self->iStack[iStackPtr].iRefDir == NULL) {        /* root level */
+      /* get the number and ID's of all lone Vgroups in the file */
+      self->iStack[iStackPtr].iNDir = Vlone (self->iVID, NULL, 0);
+      self->iStack[iStackPtr].iRefDir = 
+          (int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
+      if (!self->iStack[iStackPtr].iRefDir) {
+        NXReportError( "ERROR: out of memory in NXIInitDir");
+        return NX_EOD;
+      }
+      Vlone (self->iVID,
+             self->iStack[self->iStackPtr].iRefDir,
+             self->iStack[self->iStackPtr].iNDir);
+    } else {
+      /* Vgroup level */
+      self->iStack[iStackPtr].iNDir = Vntagrefs (self->iCurrentVG);
+      self->iStack[iStackPtr].iRefDir =
+        (int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
+      self->iStack[iStackPtr].iTagDir =
+        (int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
+      if ((!self->iStack[iStackPtr].iRefDir) ||
+          (!self->iStack[iStackPtr].iTagDir)) {
+        NXReportError( "ERROR: out of memory in NXIInitDir");
+        return NX_EOD;
+      }
+      for (i = 0; i < self->iStack[self->iStackPtr].iNDir; i++) {
+        Vgettagref (self->iCurrentVG, i, &iTag, &iRef);
+        self->iStack[iStackPtr].iRefDir[i] = iRef;
+        self->iStack[iStackPtr].iTagDir[i] = iTag;
+      }
+    }
+    self->iStack[iStackPtr].iCurDir = 0;
+    return 1;
+  }
+
+  /*----------------------------------------------------------------------*/
+    
+  static void NXIKillDir (pNexusFile self)
+  {
+    if (self->iStack[self->iStackPtr].iRefDir) {
+      free (self->iStack[self->iStackPtr].iRefDir);
+      self->iStack[self->iStackPtr].iRefDir = NULL;
+    }
+    if (self->iStack[self->iStackPtr].iTagDir) {
+      free (self->iStack[self->iStackPtr].iTagDir);
+      self->iStack[self->iStackPtr].iTagDir = NULL;
+    }
+    self->iStack[self->iStackPtr].iCurDir = 0;
+    self->iStack[self->iStackPtr].iNDir = 0;
+  }
+
+ 
+  /*-------------------------------------------------------------------------*/
+
+  static int NXIInitAttDir (pNexusFile pFile)
+  {
+    int iRet;
+    int32 iData, iAtt, iRank, iType;
+    int32 iDim[H4_MAX_VAR_DIMS];
+    NXname pNam;
+  
+    pFile->iAtt.iCurDir = 0;
+    if (pFile->iCurrentSDS != 0) {        /* SDS level */
+      iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
+                        &iAtt);
+    } else {
+      if(pFile->iCurrentVG == 0){
+	/* global level */
+	iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
+      } else {
+	/* group attribute */
+	iRet = Vnattrs(pFile->iCurrentVG);
+	iAtt = iRet;
+      }
+    }
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF cannot read attribute numbers");
+      pFile->iAtt.iNDir = 0;
+      return NX_ERROR;
+    }
+    pFile->iAtt.iNDir = iAtt;
+    return NX_OK;
+  }
+
+  /* --------------------------------------------------------------------- */
+
+  static void NXIKillAttDir (pNexusFile self)
+  {
+    if (self->iAtt.iRefDir) {
+      free (self->iAtt.iRefDir);
+      self->iAtt.iRefDir = NULL;
+    }
+    if (self->iAtt.iTagDir) {
+      free (self->iAtt.iTagDir);
+      self->iAtt.iTagDir = NULL;
+    }
+    self->iAtt.iCurDir = 0;
+    self->iAtt.iNDir = 0;
+  }
+/*------------------------------------------------------------------*/
+  static void NXIbuildPath(pNexusFile pFile, char *buffer, int bufLen)
+  {
+    int i;
+    int32 groupID, iA, iD1, iD2, iDim[H4_MAX_VAR_DIMS];
+    NXname pText;
+
+    buffer[0] = '\0';
+    for(i = 1; i <= pFile->iStackPtr; i++){
+      strncat(buffer,"/",bufLen-strlen(buffer));
+      groupID = Vattach(pFile->iVID,pFile->iStack[i].iVref, "r");
+      if (groupID != -1)
+      {
+          if (Vgetname(groupID, pText) != -1) {
+              strncat(buffer,pText,bufLen-strlen(buffer));
+          } else {
+              NXReportError( "ERROR: NXIbuildPath cannot get vgroup name");
+          }
+          Vdetach(groupID);
+      }
+      else
+      {
+          NXReportError( "ERROR: NXIbuildPath cannot attach to vgroup");
+      }
+    }
+    if(pFile->iCurrentSDS != 0){
+      if (SDgetinfo(pFile->iCurrentSDS,pText,&iA,iDim,&iD1,&iD2) != -1) {
+          strncat(buffer,"/",bufLen-strlen(buffer));
+          strncat(buffer,pText,bufLen-strlen(buffer));
+      }
+      else
+      {
+          NXReportError( "ERROR: NXIbuildPath cannot read SDS");
+      }
+    }
+  } 
+  /* ---------------------------------------------------------------------- 
+  
+                          Definition of NeXus API
+
+   ---------------------------------------------------------------------*/
+
+
+   NXstatus  NX4open(CONSTCHAR *filename, NXaccess am, 
+				  NXhandle* pHandle)
+  {
+    pNexusFile pNew = NULL;
+    char pBuffer[512];
+    char *time_puffer = NULL;
+    char HDF_VERSION[64];
+    uint32 lmajor, lminor, lrelease;
+    int32 am1=0;
+  
+    *pHandle = NULL;
+
+    /* mask off any options for now */
+    am = (NXaccess)(am & NXACCMASK_REMOVEFLAGS);
+    /* map Nexus NXaccess types to HDF4 types */
+    if (am == NXACC_CREATE) {
+      am1 = DFACC_CREATE;
+    } else if (am == NXACC_CREATE4) {
+      am1 = DFACC_CREATE;
+    } else if (am == NXACC_READ) { 
+      am1 = DFACC_READ;
+    } else if (am == NXACC_RDWR) {
+      am1 = DFACC_RDWR;
+    }   
+    /* get memory */
+    pNew = (pNexusFile) malloc (sizeof (NexusFile));
+    if (!pNew) {
+      NXReportError( "ERROR: no memory to create File datastructure");
+      return NX_ERROR;
+    }
+    memset (pNew, 0, sizeof (NexusFile));
+
+#if WRITE_OLD_IDENT     /* not used at moment */
+/*
+ * write something that can be used by OLE
+ */
+    
+    if (am == NXACC_CREATE || am == NXACC_CREATE4) {
+      if ( (file_id = Hopen(filename, am1, 0)) == -1 ) {
+        sprintf (pBuffer, "ERROR: cannot open file_a: %s", filename);
+        NXReportError( pBuffer);
+        free (pNew);
+        return NX_ERROR;
+      }
+      an_id = ANstart(file_id);
+      ann_id = ANcreatef(an_id, AN_FILE_LABEL); /* AN_FILE_DESC */
+      ANwriteann(ann_id, "NeXus", 5);
+      ANendaccess(ann_id);
+      ANend(an_id);
+      if (Hclose(file_id) == -1) {
+        sprintf (pBuffer, "ERROR: cannot close file: %s", filename);
+        NXReportError( pBuffer);
+        free (pNew);
+        return NX_ERROR;
+      }
+      am = NXACC_RDWR;
+    }
+#endif /* WRITE_OLD_IDENT */
+
+    /* start SDS interface */
+    pNew->iSID = SDstart (filename, am1);
+    if (pNew->iSID <= 0) {
+      sprintf (pBuffer, "ERROR: cannot open file_b: %s", filename);
+      NXReportError( pBuffer);
+      free (pNew);
+      return NX_ERROR;
+    }
+/*
+ * need to create global attributes         file_name file_time NeXus_version 
+ * at some point for new files
+ */
+    if (am != NXACC_READ) {
+      if (SDsetattr(pNew->iSID, "NeXus_version", DFNT_CHAR8, strlen(NEXUS_VERSION), NEXUS_VERSION) < 0) {
+          NXReportError( "ERROR: HDF failed to store NeXus_version attribute ");
+          return NX_ERROR;
+      }
+      Hgetlibversion(&lmajor, &lminor, &lrelease, HDF_VERSION); 
+      if (SDsetattr(pNew->iSID, "HDF_version", DFNT_CHAR8, strlen(HDF_VERSION), HDF_VERSION) < 0) {
+          NXReportError( "ERROR: HDF failed to store HDF_version attribute ");
+          return NX_ERROR;
+      }
+    }
+
+    time_puffer = NXIformatNeXusTime();
+    if (am == NXACC_CREATE || am == NXACC_CREATE4) {
+      if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, strlen(filename), (char*)filename) < 0) {
+        NXReportError( "ERROR: HDF failed to store file_name attribute ");
+        return NX_ERROR;
+      }
+      if(time_puffer != NULL){
+	if (SDsetattr(pNew->iSID, "file_time", DFNT_CHAR8, 
+		      strlen(time_puffer), time_puffer) < 0) {
+	  NXReportError( 
+			  "ERROR: HDF failed to store file_time attribute ");
+	  free(time_puffer);
+	  return NX_ERROR;
+	}
+      }
+    }
+    if (time_puffer != NULL) {
+	free(time_puffer);
+    }
+
+    /* 
+     * Otherwise we try to create the file two times which makes HDF
+     * Throw up on us.
+     */
+    if (am == NXACC_CREATE || am == NXACC_CREATE4) {
+      am = NXACC_RDWR;
+      am1 = DFACC_RDWR;
+    }
+
+    /* Set Vgroup access mode */
+    if (am == NXACC_READ) {
+      strcpy(pNew->iAccess,"r");
+    } else {
+      strcpy(pNew->iAccess,"w");
+    }
+  
+    /* start Vgroup API */
+    
+    pNew->iVID = Hopen(filename, am1, 100);
+    if (pNew->iVID <= 0) {
+      sprintf (pBuffer, "ERROR: cannot open file_c: %s", filename);
+      NXReportError( pBuffer);
+      free (pNew);
+      return NX_ERROR;
+    }
+    Vstart (pNew->iVID);
+    pNew->iNXID = NXSIGNATURE;
+    pNew->iStack[0].iVref = 0;    /* root! */
+  
+    *pHandle = (NXhandle)pNew;
+    return NX_OK;
+  }
+
+/*-----------------------------------------------------------------------*/
+ 
+  NXstatus  NX4close (NXhandle* fid)
+  {
+    pNexusFile pFile = NULL;
+    int iRet;
+  
+    pFile = NXIassert(*fid);
+    iRet = 0;
+    /* close links into vGroups or SDS */
+    if (pFile->iCurrentVG != 0) {
+      Vdetach (pFile->iCurrentVG);
+    }
+    if (pFile->iCurrentSDS != 0) {
+      iRet = SDendaccess (pFile->iCurrentSDS);
+    }
+    if (iRet < 0) {
+      NXReportError( "ERROR: ending access to SDS");
+    }
+    /* close the SDS and Vgroup API's */
+    Vend (pFile->iVID);
+    iRet = SDend (pFile->iSID);
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF cannot close SDS interface");
+    }
+    iRet = Hclose (pFile->iVID);
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF cannot close HDF file");
+    }
+    /* release memory */
+    NXIKillDir (pFile);
+    free (pFile);
+    *fid = NULL;
+    return NX_OK;
+  } 
+
+
+/*-----------------------------------------------------------------------*/   
+
+  
+  NXstatus  NX4makegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
+  {
+    pNexusFile pFile;
+    int32 iNew, iRet;
+    char pBuffer[256];
+  
+    pFile = NXIassert (fid);
+    /* 
+     * Make sure that a group with the same name and nxclass does not
+     * already exist.
+     */
+    if ((iRet = NXIFindVgroup (pFile, (char*)name, nxclass)) >= 0) {
+      sprintf (pBuffer, "ERROR: Vgroup %s, class %s already exists", 
+                        name, nxclass);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+  
+    /* create and configure the group */
+    iNew = Vattach (pFile->iVID, -1, "w");
+    if (iNew < 0) {
+      NXReportError( "ERROR: HDF could not create Vgroup");
+      return NX_ERROR;
+    }
+    Vsetname (iNew, name);
+    Vsetclass (iNew, nxclass);
+  
+    /* Insert it into the hierarchy, when appropriate */
+    iRet = 0;     
+    if (pFile->iCurrentVG != 0) {
+      iRet = Vinsert (pFile->iCurrentVG, iNew);
+    }
+    Vdetach (iNew);
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF failed to insert Vgroup");
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }
+
+
+  /*------------------------------------------------------------------------*/
+  NXstatus  NX4opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
+  {
+    pNexusFile pFile;
+    int32 iRef;
+    char pBuffer[256];
+  
+    pFile = NXIassert (fid);
+  
+    iRef = NXIFindVgroup (pFile, (char*)name, nxclass);
+    if (iRef < 0) {
+      sprintf (pBuffer, "ERROR: Vgroup \"%s\", class \"%s\" NOT found", name, nxclass);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+    /* are we at root level ? */
+    if (pFile->iCurrentVG == 0) {
+      pFile->iCurrentVG = Vattach (pFile->iVID, iRef,pFile->iAccess);
+      pFile->iStackPtr++;
+      pFile->iStack[pFile->iStackPtr].iVref = iRef;
+    } else {
+      Vdetach (pFile->iCurrentVG);
+      pFile->iStackPtr++;
+      pFile->iStack[pFile->iStackPtr].iVref = iRef;
+      pFile->iCurrentVG = Vattach (pFile->iVID,
+                                   pFile->iStack[pFile->iStackPtr].iVref,
+                                   pFile->iAccess);
+    }
+    NXIKillDir (pFile);
+    return NX_OK;
+  }
+  /* ------------------------------------------------------------------- */
+
+  
+   NXstatus  NX4closegroup (NXhandle fid)
+  {
+    pNexusFile pFile;
+  
+    pFile = NXIassert (fid);
+  
+    /* first catch the trivial case: we are at root and cannot get 
+       deeper into a negative directory hierarchy (anti-directory)
+     */
+    if (pFile->iCurrentVG == 0) {
+      NXIKillDir (pFile);
+      return NX_OK;
+    } else {                      /* Sighhh. Some work to do */
+      /* close the current VG and decrement stack */
+      Vdetach (pFile->iCurrentVG);
+      NXIKillDir (pFile);
+      pFile->iStackPtr--;
+      if (pFile->iStackPtr <= 0) {        /* we hit root */
+        pFile->iStackPtr = 0;
+        pFile->iCurrentVG = 0;
+      } else {
+        /* attach to the lower Vgroup */
+        pFile->iCurrentVG = Vattach (pFile->iVID,
+                                     pFile->iStack[pFile->iStackPtr].iVref,
+                                     pFile->iAccess);
+      }
+    }
+    return NX_OK;
+  }
+  
+  
+  /* --------------------------------------------------------------------- */
+  
+  NXstatus  NX4makedata64 (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
+              int64_t dimensions[])
+  {
+    pNexusFile pFile;
+    int32 iNew;
+    char pBuffer[256];
+    int i, iRet, type;
+    int32 myDim[H4_MAX_VAR_DIMS];  
+
+    pFile = NXIassert (fid);
+      
+    if (dimensions[0] == NX_UNLIMITED)
+      {
+        dimensions[0] = SD_UNLIMITED;
+      }
+     
+    if ((iNew = NXIFindSDS (fid, name))>=0) {
+      sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+  
+    if (datatype == NX_CHAR)
+    {
+        type=DFNT_CHAR8;
+    }
+    else if (datatype == NX_INT8)
+    {
+        type=DFNT_INT8;
+    }
+    else if (datatype == NX_UINT8)
+    {
+        type=DFNT_UINT8;
+    }
+    else if (datatype == NX_INT16)
+    {
+        type=DFNT_INT16;
+    }
+    else if (datatype == NX_UINT16)
+    {
+        type=DFNT_UINT16;
+    }
+    else if (datatype == NX_INT32)
+    {
+        type=DFNT_INT32;
+    }
+    else if (datatype == NX_UINT32)
+    {
+        type=DFNT_UINT32;
+    }
+    else if (datatype == NX_FLOAT32)
+    {
+        type=DFNT_FLOAT32;
+    }
+    else if (datatype == NX_FLOAT64)
+    {
+        type=DFNT_FLOAT64;
+    }
+    else
+    {
+      NXReportError( "ERROR: invalid type in NX4makedata");
+      return NX_ERROR;
+    }
+      
+    if (rank <= 0) {
+      sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
+               name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+
+    /*
+      Check dimensions for consistency. The first dimension may be 0
+      thus denoting an unlimited dimension.
+    */
+    for (i = 1; i < rank; i++) {
+      if (dimensions[i] <= 0) {
+        sprintf (pBuffer,
+                 "ERROR: invalid dimension %d, value %lld given for SDS %s",
+                 i, (long long)dimensions[i], name);
+        NXReportError( pBuffer);
+        return NX_ERROR;
+      }
+    }
+
+    /* cast the dimensions array properly for non 32-bit ints */
+    for(i = 0; i < rank; i++)
+    {
+      myDim[i] = (int32)dimensions[i];
+    }
+
+
+    /* behave nicely, if there is still an SDS open */
+    if (pFile->iCurrentSDS != 0) {
+      SDendaccess (pFile->iCurrentSDS);
+      pFile->iCurrentSDS = 0;
+    }
+  
+    /* Do not allow creation of SDS's at the root level */
+    if (pFile->iCurrentVG == 0) {
+      sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted");
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+          
+    /* dataset creation */
+    iNew = SDcreate (pFile->iSID, (char*)name, (int32)type, 
+                     (int32)rank, myDim);
+    if (iNew < 0) {
+      sprintf (pBuffer, "ERROR: cannot create SDS %s, check arguments",
+               name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+    /* link into Vgroup, if in one */
+    if (pFile->iCurrentVG != 0) {
+      iRet = Vaddtagref (pFile->iCurrentVG, DFTAG_NDG, SDidtoref (iNew));
+    }
+    iRet = SDendaccess (iNew);
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF cannot end access to SDS");
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }
+  
+  
+ /* --------------------------------------------------------------------- */
+  
+   
+  NXstatus  NX4compmakedata64 (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
+              int64_t dimensions[],int compress_type, int64_t chunk_size[])
+  {
+    pNexusFile pFile;
+    int32 iNew, iRet, type;
+    char pBuffer[256];
+    int i, compress_level;
+    int32 myDim[H4_MAX_VAR_DIMS];  
+    comp_info compstruct;
+
+    pFile = NXIassert (fid);
+      
+    if (dimensions[0] == NX_UNLIMITED)
+      {
+        dimensions[0] = SD_UNLIMITED;
+      }
+     
+    if ((iNew = NXIFindSDS (fid, name))>=0) {
+      sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+  
+    if (datatype == NX_CHAR)
+    {
+        type=DFNT_CHAR8;
+    }
+    else if (datatype == NX_INT8)
+    {
+        type=DFNT_INT8;
+    }
+    else if (datatype == NX_UINT8)
+    {
+        type=DFNT_UINT8;
+    }
+    else if (datatype == NX_INT16)
+    {
+        type=DFNT_INT16;
+    }
+    else if (datatype == NX_UINT16)
+    {
+        type=DFNT_UINT16;
+    }
+    else if (datatype == NX_INT32)
+    {
+        type=DFNT_INT32;
+    }
+    else if (datatype == NX_UINT32)
+    {
+        type=DFNT_UINT32;
+    }
+    else if (datatype == NX_FLOAT32)
+    {
+        type=DFNT_FLOAT32;
+    }
+    else if (datatype == NX_FLOAT64)
+    {
+        type=DFNT_FLOAT64;
+    }
+    else
+    {
+      NXReportError( "ERROR: invalid datatype in NX4compmakedata");
+      return NX_ERROR;
+    }
+      
+    if (rank <= 0) {
+      sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
+               name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+
+    /*
+      Check dimensions for consistency. The first dimension may be 0
+      thus denoting an unlimited dimension.
+    */
+    for (i = 1; i < rank; i++) {
+      if (dimensions[i] <= 0) {
+        sprintf (pBuffer,
+                 "ERROR: invalid dimension %d, value %lld given for SDS %s",
+                 i, (long long)dimensions[i], name);
+        NXReportError( pBuffer);
+        return NX_ERROR;
+      }
+    }
+
+    /* cast the dimensions array properly for non 32-bit ints */
+    for(i = 0; i < rank; i++)
+    {
+      myDim[i] = (int32)dimensions[i];
+    }
+
+
+    /* behave nicely, if there is still an SDS open */
+    if (pFile->iCurrentSDS != 0) {
+      SDendaccess (pFile->iCurrentSDS);
+      pFile->iCurrentSDS = 0;
+    }
+  
+    /* Do not allow creation of SDS's at the root level */
+    if (pFile->iCurrentVG == 0) {
+      sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted");
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+          
+    /* dataset creation */
+    iNew = SDcreate (pFile->iSID, (char*)name, (int32)type, 
+                     (int32)rank, myDim);
+    if (iNew < 0) {
+      sprintf (pBuffer, "ERROR: cannot create SDS %s, check arguments",
+               name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+     
+    /* compress SD data set */
+    compress_level = 6;
+    if( (compress_type / 100) == NX_COMP_LZW )
+    {
+	compress_level = compress_type % 100;
+	compress_type = NX_COMP_LZW;
+    }
+
+    if(compress_type == NX_COMP_LZW)
+    {
+      compstruct.deflate.level = compress_level; 
+      iRet = SDsetcompress(iNew, COMP_CODE_DEFLATE, &compstruct);
+      if (iRet < 0) 
+      {
+        NXReportError( "Deflate-Compression failure!");
+        return NX_ERROR;
+      } 
+    }
+    else if (compress_type == NX_COMP_RLE)
+    {
+      iRet = SDsetcompress(iNew, COMP_CODE_RLE, &compstruct);
+      if (iRet < 0) 
+        {
+          NXReportError( "RLE-Compression failure!");
+          return NX_ERROR;
+        }   
+    }
+    else if (compress_type == NX_COMP_HUF)
+    {
+      compstruct.skphuff.skp_size = DFKNTsize(type); 
+      iRet = SDsetcompress(iNew, COMP_CODE_SKPHUFF, &compstruct);
+      if (iRet < 0) 
+        {
+          NXReportError( "HUF-Compression failure!");
+          return NX_ERROR;
+        }  
+    }
+    else if (compress_type == NX_COMP_NONE)
+    {
+      /*      */
+    }
+    else 
+    {
+      NXReportError( "Unknown compression method!");
+      return NX_ERROR; 
+    }
+    /* link into Vgroup, if in one */
+    if (pFile->iCurrentVG != 0) {
+      iRet = Vaddtagref (pFile->iCurrentVG, DFTAG_NDG, SDidtoref (iNew));
+    }
+    iRet = SDendaccess (iNew);
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF cannot end access to SDS");
+      return NX_ERROR;
+    }
+    
+    return NX_OK;
+  }
+ 
+  /* --------------------------------------------------------------------- */
+
+   
+  NXstatus  NX4compress (NXhandle fid, int compress_type)
+  {
+    pNexusFile pFile;
+    int32 iRank, iAtt, iType, iRet;
+    int32 iSize[H4_MAX_VAR_DIMS];
+    comp_coder_t compress_typei = COMP_CODE_NONE;
+    NXname pBuffer;
+    char pError[512];
+    comp_info compstruct;  
+    int compress_level = 6;
+   
+    pFile = NXIassert (fid);
+  
+    /* check if there is an SDS open */
+    if (pFile->iCurrentSDS == 0) {
+      NXReportError( "ERROR: no SDS open");
+      return NX_ERROR;
+    }
+    
+    if (compress_type == NX_COMP_NONE) 
+      {
+        compress_typei = COMP_CODE_NONE;
+      }
+      else if (compress_type == NX_COMP_LZW) 
+      {
+        compress_typei = COMP_CODE_DEFLATE;
+      }
+      else if ( (compress_type / 100) == NX_COMP_LZW )
+      {
+        compress_typei = COMP_CODE_DEFLATE;
+        compress_level = compress_type % 100;
+	compress_type = NX_COMP_LZW;
+      }
+      else if (compress_type == NX_COMP_RLE)
+      {
+        compress_typei = COMP_CODE_RLE;
+      }
+      else if  
+      (compress_type == NX_COMP_HUF)
+      {
+        compress_typei = COMP_CODE_SKPHUFF;
+      }
+    
+    /* first read dimension information */
+    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
+
+    /* 
+       according to compression type initialize compression
+       information 
+    */
+    if(compress_type == NX_COMP_LZW)
+    {
+         compstruct.deflate.level = compress_level;
+    }
+    else if(compress_type == NX_COMP_HUF)
+    {
+        compstruct.skphuff.skp_size = DFKNTsize(iType);
+    }
+
+    iRet = SDsetcompress(pFile->iCurrentSDS, compress_typei, &compstruct);
+    if (iRet < 0) {
+      sprintf (pError, "ERROR: failure to compress data to %s", pBuffer);
+      NXReportError( pError);
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }  
+
+  /* --------------------------------------------------------------------- */
+  
+ 
+  NXstatus  NX4opendata (NXhandle fid, CONSTCHAR *name)
+  {
+    pNexusFile pFile;
+    int32 iNew, attID, tags[2];
+    char pBuffer[256];
+    int iRet;
+  
+    pFile = NXIassert (fid);
+  
+    /* First find the reference number of the SDS */
+    iNew = NXIFindSDS (fid, name);
+    if (iNew < 0) {
+      sprintf (pBuffer, "ERROR: SDS \"%s\" not found at this level", name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+    /* Be nice: properly close the old open SDS silently if there is
+     * still an SDS open.
+     */
+    if (pFile->iCurrentSDS) {
+      iRet = SDendaccess (pFile->iCurrentSDS);
+      if (iRet < 0) {
+        NXReportError( "ERROR: HDF cannot end access to SDS");
+      }
+    }
+    /* clear pending attribute directories first */
+    NXIKillAttDir (pFile);
+
+    /* open the SDS, thereby watching for linked SDS under a different name */
+    iNew = SDreftoindex (pFile->iSID, iNew);
+    pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
+    attID = SDfindattr(pFile->iCurrentSDS,"NAPIlink");
+    if(attID >= 0)
+    {
+      SDreadattr(pFile->iCurrentSDS,attID, tags);
+      SDendaccess(pFile->iCurrentSDS);
+      iNew = SDreftoindex (pFile->iSID, tags[1]);
+      pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
+    }
+
+    if (pFile->iCurrentSDS < 0) {
+      NXReportError( "ERROR: HDF error opening SDS");
+      pFile->iCurrentSDS = 0;
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }
+    
+  /* ----------------------------------------------------------------- */
+    
+  
+  NXstatus  NX4closedata (NXhandle fid)
+  {
+    pNexusFile pFile;
+    int iRet;
+  
+    pFile = NXIassert (fid);
+  
+    if (pFile->iCurrentSDS != 0) {
+      iRet = SDendaccess (pFile->iCurrentSDS);
+      pFile->iCurrentSDS = 0;
+      if (iRet < 0) {
+        NXReportError( "ERROR: HDF cannot end access to SDS");
+        return NX_ERROR;
+      }
+    } else {
+      NXReportError( "ERROR: no SDS open --> nothing to do");
+      return NX_ERROR;
+    }
+    NXIKillAttDir (pFile);                /* for attribute data */
+    return NX_OK;
+  }
+   
+  
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX4putdata (NXhandle fid, const void *data)
+  {
+    pNexusFile pFile;
+    int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS], iStride[H4_MAX_VAR_DIMS];
+    NXname pBuffer;
+    int32 iRank, iAtt, iType, iRet, i;
+    char pError[512];
+      
+    pFile = NXIassert (fid);
+  
+    /* check if there is an SDS open */
+    if (pFile->iCurrentSDS == 0) {
+      NXReportError( "ERROR: no SDS open");
+      return NX_ERROR;
+    }
+    /* first read dimension information */
+    memset (iStart, 0, H4_MAX_VAR_DIMS * sizeof (int32));
+    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
+  
+    /* initialise stride to 1 */
+    for (i = 0; i < iRank; i++) {
+      iStride[i] = 1;
+    }
+  
+    /* actually write */
+    iRet = SDwritedata (pFile->iCurrentSDS, iStart, iStride, iSize, (void*)data);
+    if (iRet < 0) {
+      /* HEprint(stdout,0); */
+      sprintf (pError, "ERROR: failure to write data to %s", pBuffer);
+      NXReportError( pError);
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }
+    
+  /* ------------------------------------------------------------------- */
+
+  NXstatus
+   NX4putattr (NXhandle fid, CONSTCHAR *name, const void *data, int datalen, int iType)
+  {
+    pNexusFile pFile;
+    int iRet, type;
+  
+    pFile = NXIassert (fid);
+    if (iType == NX_CHAR)
+    {
+        type=DFNT_CHAR8;
+    }
+    else if (iType == NX_INT8)
+    {
+        type=DFNT_INT8;
+    }
+    else if (iType == NX_UINT8)
+    {
+        type=DFNT_UINT8;
+    }
+    else if (iType == NX_INT16)
+    {
+        type=DFNT_INT16;
+    }
+    else if (iType == NX_UINT16)
+    {
+        type=DFNT_UINT16;
+    }
+    else if (iType == NX_INT32)
+    {
+        type=DFNT_INT32;
+    }
+    else if (iType == NX_UINT32)
+    {
+        type=DFNT_UINT32;
+    }
+    else if (iType == NX_FLOAT32)
+    {
+        type=DFNT_FLOAT32;
+    }
+    else if (iType == NX_FLOAT64)
+    {
+        type=DFNT_FLOAT64;
+    }
+    else
+    {
+      NXReportError( "ERROR: Invalid data type for HDF attribute");
+      return NX_ERROR;
+    }
+    if (pFile->iCurrentSDS != 0) {
+      /* SDS attribute */
+      iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)type,
+                        (int32)datalen, data);
+    } else {
+      if(pFile->iCurrentVG == 0){
+	/* global attribute */
+	iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type,
+			  (int32)datalen, data);
+      } else {
+	/* group attribute */
+	iRet = Vsetattr(pFile->iCurrentVG, (char *)name, (int32) type,
+			(int32)datalen,data);
+      }
+    }
+    iType = type;
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF failed to store attribute ");
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }
+ 
+   /* ------------------------------------------------------------------- */
+
+   
+  NXstatus  NX4putslab64 (NXhandle fid, const void *data, const int64_t iStart[], const int64_t iSize[])
+  {
+    pNexusFile pFile;
+    int iRet;
+    int32 iStride[H4_MAX_VAR_DIMS];
+    int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS];
+    int32 i, iRank, iType, iAtt;
+    NXname pBuffer;  
+  
+  
+    pFile = NXIassert (fid);
+  
+    /* check if there is an SDS open */
+    if (pFile->iCurrentSDS == 0) {
+      NXReportError( "ERROR: no SDS open");
+      return NX_ERROR;
+    }
+    /* initialise stride to 1 */
+    for (i = 0; i < H4_MAX_VAR_DIMS; i++) {
+      iStride[i] = 1;
+    }
+
+         SDgetinfo (pFile->iCurrentSDS, pBuffer, 
+            &iRank, myStart, &iType, &iAtt);
+         for(i = 0; i < iRank; i++)
+         {
+           myStart[i] = (int32)iStart[i];
+           mySize[i]  = (int32)iSize[i];
+         }
+         /* finally write */
+         iRet = SDwritedata (pFile->iCurrentSDS, myStart, 
+                        iStride, mySize, (void*)data);
+
+
+    /* deal with HDF errors */
+    if (iRet < 0) {
+      NXReportError( "ERROR: writing slab failed");
+      return NX_ERROR;
+    }
+    return NX_OK;
+  }
+
+  
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX4getdataID (NXhandle fid, NXlink* sRes)
+  {
+    pNexusFile pFile;
+    int datalen, type = NX_CHAR;
+
+    pFile = NXIassert (fid);
+  
+    if (pFile->iCurrentSDS == 0) {
+      sRes->iTag = NX_ERROR;
+      return NX_ERROR;
+    } else {
+      sRes->iTag = DFTAG_NDG;
+      sRes->iRef = SDidtoref (pFile->iCurrentSDS);
+      NXMDisableErrorReporting();
+      datalen = 1024;
+      memset(&sRes->targetPath,0,1024);
+      if(NX4getattr(fid,"target",&sRes->targetPath,&datalen,&type) != NX_OK)
+      {
+	NXIbuildPath(pFile,sRes->targetPath,1024);
+      }
+      NXMEnableErrorReporting();
+      return NX_OK;
+    }
+    sRes->iTag = NX_ERROR;
+    return NX_ERROR;                  /* not reached */
+  }
+
+
+  /* ------------------------------------------------------------------- */
+
+  
+  NXstatus  NX4makelink (NXhandle fid, NXlink* sLink)
+  {
+    pNexusFile pFile;
+    int32 dataID, type = DFNT_CHAR8, length;
+    char name[] = "target";
+  
+    pFile = NXIassert (fid);
+  
+    if (pFile->iCurrentVG == 0) { /* root level, can not link here */
+      return NX_ERROR;
+    }
+    Vaddtagref(pFile->iCurrentVG, sLink->iTag, sLink->iRef);
+    length = strlen(sLink->targetPath);
+    if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
+       sLink->iTag == DFTAG_SDS)
+    {
+      dataID = SDreftoindex(pFile->iSID,sLink->iRef);
+      dataID = SDselect(pFile->iSID,dataID);
+      SDsetattr(dataID,name,type,length,sLink->targetPath);
+      SDendaccess(dataID);
+    }
+    else 
+    {
+      dataID = Vattach(pFile->iVID,sLink->iRef,"w");
+      Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
+      Vdetach(dataID);
+    }
+    return NX_OK;
+  }
+  /* ------------------------------------------------------------------- */
+
+  
+  NXstatus  NX4makenamedlink (NXhandle fid, CONSTCHAR* newname, NXlink* sLink)
+  {
+    pNexusFile pFile;
+    int32 dataID, type = DFNT_CHAR8, length, dataType = NX_CHAR, 
+      rank = 1, attType = NX_INT32;
+    int64_t iDim[1];
+    char name[] = "target";
+    int tags[2];  
+
+    pFile = NXIassert (fid);
+  
+    if (pFile->iCurrentVG == 0) { /* root level, can not link here */
+      return NX_ERROR;
+    }
+
+    tags[0] = sLink->iTag;
+    tags[1] = sLink->iRef;
+
+    length = strlen(sLink->targetPath); 
+    if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
+       sLink->iTag == DFTAG_SDS)
+    {
+      iDim[0] = 1;
+      NX4makedata64(fid,newname, dataType,rank,iDim);
+      NX4opendata(fid,newname);
+      NX4putattr(fid,"NAPIlink",tags, 2, attType);
+      NX4closedata(fid); 
+      dataID = SDreftoindex(pFile->iSID,sLink->iRef);
+      dataID = SDselect(pFile->iSID,dataID);
+      SDsetattr(dataID,name,type,length,sLink->targetPath);
+      SDendaccess(dataID);
+    } else {
+      NX4makegroup(fid,newname,"NAPIlink");
+      NX4opengroup(fid,newname,"NAPIlink");
+      NX4putattr(fid,"NAPIlink",tags, 2, attType);
+      NX4closegroup(fid);
+      dataID = Vattach(pFile->iVID,sLink->iRef,"w");
+      Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
+      Vdetach(dataID);
+    }
+    return NX_OK;
+  }
+
+  /*----------------------------------------------------------------------*/
+  
+  NXstatus  NX4printlink (NXhandle fid, NXlink* sLink)
+  {
+     NXIassert (fid);
+     printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n", sLink->iTag, sLink->iRef, sLink->targetPath);
+    return NX_OK;
+  }
+  
+  /*----------------------------------------------------------------------*/
+
+  NXstatus  NX4flush(NXhandle *pHandle)
+  {
+    char *pFileName, *pCopy = NULL;
+    int access, dummy, iRet, i, iStack;
+    pNexusFile pFile = NULL;
+    NXaccess ac;
+    int *iRefs = NULL;
+
+    pFile = NXIassert(*pHandle);
+    
+    /*
+      The HDF4-API does not support a flush. We help ourselves with
+      inquiring the name and access type of the file, closing it and
+      opening it again. This is also the reason why this needs a pointer
+      to the handle structure as the handle changes. The other thing we
+      do is to store the refs of all open vGroups in a temporary array
+      in order to recover the position in the vGroup hierarchy before the
+      flush.
+    */
+    iRet = Hfidinquire(pFile->iVID,&pFileName,&access,&dummy);
+    if (iRet < 0) {
+      NXReportError( 
+        "ERROR: Failed to inquire file name for HDF file");
+      return NX_ERROR;
+    }
+    if(pFile->iAccess[0] == 'r') {
+      ac = NXACC_READ;
+    }else if(pFile->iAccess[0] == 'w') {
+      ac = NXACC_RDWR;
+    } else {
+      NXReportError( 
+        "ERROR: NX4flush failed to determine file access mode");
+      return NX_ERROR;
+    }
+    pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char));
+    if(!pCopy) {
+      NXReportError( 
+        "ERROR: Failed to allocate data for filename copy");
+      return NX_ERROR;
+    }
+    memset(pCopy,0,strlen(pFileName)+10);
+    strcpy(pCopy,pFileName);      
+    
+    /* get refs for recovering vGroup position */
+    iStack = 0;
+    if(pFile->iStackPtr > 0) {
+      iStack = pFile->iStackPtr + 1;
+      iRefs = (int *)malloc(iStack*sizeof(int));
+      if(!iRefs){
+        NXReportError( 
+        "ERROR: Failed to allocate data for hierarchy copy");
+        return NX_ERROR;
+      }
+      for(i = 0; i < iStack; i++){
+         iRefs[i] = pFile->iStack[i].iVref;
+      }
+    }
+
+    iRet = NX4close(pHandle);
+    if(iRet != NX_OK) {
+      return iRet;
+    }
+
+    iRet = NX4open(pCopy, ac, pHandle);
+    free(pCopy);
+   
+    /* return to position in vGroup hierarchy */
+    pFile = NXIassert(*pHandle);
+    if(iStack > 0){
+      pFile->iStackPtr = iStack - 1;
+      for(i = 0; i < iStack; i++){
+        pFile->iStack[i].iVref = iRefs[i];
+      }
+      free(iRefs);
+      pFile->iCurrentVG = Vattach(pFile->iVID,
+                                  pFile->iStack[pFile->iStackPtr].iVref,
+                                  pFile->iAccess);
+    }
+    
+    return iRet;
+  }  
+
+  /*-------------------------------------------------------------------------*/
+  
+
+  NXstatus  NX4getnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype)
+  {
+    pNexusFile pFile;
+    int iRet, iStackPtr, iCurDir;
+    int32 iTemp, iD1, iD2, iA;
+    int32 iDim[H4_MAX_VAR_DIMS];
+  
+    pFile = NXIassert (fid);
+  
+    iStackPtr = pFile->iStackPtr;
+    iCurDir   = pFile->iStack[pFile->iStackPtr].iCurDir;
+  
+    /* first case to check for: no directory entry */
+    if (pFile->iStack[pFile->iStackPtr].iRefDir == NULL) {
+      iRet = NXIInitDir (pFile);
+      if (iRet < 0) {
+        NXReportError(
+                        "ERROR: no memory to store directory info");
+        return NX_EOD;
+      }
+    }
+
+    /* Next case: end of directory */
+    if (iCurDir >= pFile->iStack[pFile->iStackPtr].iNDir) {
+      NXIKillDir (pFile);
+      return NX_EOD;
+    }
+
+    /* Next case: we have data! supply it and increment counter */
+    if (pFile->iCurrentVG == 0) { /* root level */
+      iTemp = Vattach (pFile->iVID,
+                       pFile->iStack[iStackPtr].iRefDir[iCurDir], "r");
+      if (iTemp < 0) {
+        NXReportError( "ERROR: HDF cannot attach to Vgroup");
+        return NX_ERROR;
+      }
+      Vgetname (iTemp, name);
+      Vdetach (iTemp);
+      findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
+      *datatype = DFTAG_VG;
+      pFile->iStack[pFile->iStackPtr].iCurDir++;
+      return NX_OK;
+    } else {                      /* in Vgroup */
+      if (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_VG) {/* Vgroup */
+        iTemp = Vattach (pFile->iVID,
+                         pFile->iStack[iStackPtr].iRefDir[iCurDir], "r");
+        if (iTemp < 0) {
+          NXReportError( "ERROR: HDF cannot attach to Vgroup");
+          return NX_ERROR;
+        }
+        Vgetname (iTemp, name);
+        Vdetach(iTemp);
+	findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
+        *datatype = DFTAG_VG;
+        pFile->iStack[pFile->iStackPtr].iCurDir++;
+        Vdetach (iTemp);
+        return NX_OK;
+        /* we are now writing using DFTAG_NDG, but need others for backward compatability */
+      } else if ((pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDG) ||
+                 (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_NDG) ||
+                 (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDS)) {
+        iTemp = SDreftoindex (pFile->iSID,
+                              pFile->iStack[iStackPtr].iRefDir[iCurDir]);
+        iTemp = SDselect (pFile->iSID, iTemp);
+        SDgetinfo (iTemp, name, &iA, iDim, &iD1, &iD2);
+        strcpy (nxclass, "SDS");
+        *datatype = iD1;
+        SDendaccess (iTemp);
+        pFile->iStack[pFile->iStackPtr].iCurDir++;
+        return NX_OK;
+      } else {                    /* unidentified */
+        strcpy (name, "UNKNOWN");
+        strcpy (nxclass, "UNKNOWN");
+        *datatype = pFile->iStack[iStackPtr].iTagDir[iCurDir];
+        pFile->iStack[pFile->iStackPtr].iCurDir++;
+        return NX_OK;
+      }
+    }
+    return NX_ERROR;              /* not reached */
+  }
+
+
+  /*-------------------------------------------------------------------------*/
+
+   
+  NXstatus  NX4getdata (NXhandle fid, void *data)
+  {
+    pNexusFile pFile;
+    int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS];
+    NXname pBuffer;
+    int32 iRank, iAtt, iType;
+  
+    pFile = NXIassert (fid);
+  
+    /* check if there is an SDS open */
+    if (pFile->iCurrentSDS == 0) {
+      NXReportError( "ERROR: no SDS open");
+      return NX_ERROR;
+    }
+    /* first read dimension information */
+    memset (iStart, 0, H4_MAX_VAR_DIMS * sizeof (int32));
+    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
+    /* actually read */
+    SDreaddata (pFile->iCurrentSDS, iStart, NULL, iSize, data);
+    return NX_OK;
+  } 
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus
+   NX4getinfo64 (NXhandle fid, int *rank, int64_t dimension[], 
+			    int *iType)
+  {
+    pNexusFile pFile;
+    NXname pBuffer;
+    int32 iAtt, myDim[H4_MAX_VAR_DIMS], i, iRank, mType;
+  
+    pFile = NXIassert (fid);
+  
+    /* check if there is an SDS open */
+    if (pFile->iCurrentSDS == 0) {
+      NXReportError( "ERROR: no SDS open");
+      return NX_ERROR;
+    }
+    /* read information */
+    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, myDim, 
+               &mType, &iAtt);
+
+    /* conversion to proper ints for the platform */ 
+    *iType = (int)mType;
+    *rank = (int)iRank;
+    for(i = 0; i < iRank; i++)
+    {
+       dimension[i] = (int)myDim[i];
+    }
+    return NX_OK;
+  }
+  
+   
+  /*-------------------------------------------------------------------------*/
+
+  
+  NXstatus  NX4getslab64 (NXhandle fid, void *data, const int64_t iStart[], const int64_t iSize[])
+  {
+    pNexusFile pFile;
+    int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS];
+    int32 i, iRank, iType, iAtt;
+    NXname pBuffer;  
+
+    pFile = NXIassert (fid);
+  
+    /* check if there is an SDS open */
+    if (pFile->iCurrentSDS == 0) {
+      NXReportError( "ERROR: no SDS open");
+      return NX_ERROR;
+    }
+
+         SDgetinfo (pFile->iCurrentSDS, pBuffer, 
+            &iRank, myStart, &iType, &iAtt);
+         for(i = 0; i < iRank; i++)
+         {
+           myStart[i] = (int32)iStart[i];
+           mySize[i]  = (int32)iSize[i];
+         }
+        /* finally read  */
+        SDreaddata (pFile->iCurrentSDS, myStart, NULL, 
+                   mySize, data);
+        return NX_OK;
+  }
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NX4getnextattr (NXhandle fileid, NXname pName,
+           int *iLength, int *iType)
+  {
+    pNexusFile pFile;
+    int iRet;
+    int32 iPType, iCount, count;
+  
+    pFile = NXIassert (fileid);
+  
+    /* first check if we have to start a new attribute search */
+    if (pFile->iAtt.iNDir == 0) {
+      iRet = NXIInitAttDir (pFile);
+      if (iRet == NX_ERROR) {
+        return NX_ERROR;
+      }
+    }
+    /* are we done ? */
+    if (pFile->iAtt.iCurDir >= pFile->iAtt.iNDir) {
+      NXIKillAttDir (pFile);
+      return NX_EOD;
+    }
+    /* well, there must be data to copy */
+    if (pFile->iCurrentSDS == 0) {        
+      if(pFile->iCurrentVG == 0) {
+	/* global attribute */
+	iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir,
+			   pName, &iPType, &iCount);
+      }else {
+	/* group attribute */
+	iRet = Vattrinfo(pFile->iCurrentVG, pFile->iAtt.iCurDir,
+			 pName, &iPType, &iCount, &count);
+      }
+    } else {
+      iRet = SDattrinfo (pFile->iCurrentSDS, pFile->iAtt.iCurDir,
+                         pName, &iPType, &iCount);
+    }
+    if (iRet < 0) {
+      NXReportError( "ERROR: HDF cannot read attribute info");
+      return NX_ERROR;
+    }
+    *iLength = iCount;
+    *iType = iPType;
+    pFile->iAtt.iCurDir++;
+    return NX_OK;
+  }
+   
+  
+  /*-------------------------------------------------------------------------*/
+
+
+  NXstatus  NX4getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
+  {
+    pNexusFile pFile;
+    int32 iNew, iType32, count;
+    void *pData = NULL;
+    int32 iLen, iRet;
+    int type;
+    char pBuffer[256];
+    NXname pNam;
+  
+    type = *iType;
+    if (type == NX_CHAR)
+    {
+        type=DFNT_CHAR8;
+    }
+    else if (type == NX_INT8)
+    {
+        type=DFNT_INT8;
+    }
+    else if (type == NX_UINT8)
+    {
+        type=DFNT_UINT8;
+    }
+    else if (type == NX_INT16)
+    {
+        type=DFNT_INT16;
+    }
+    else if (type == NX_UINT16)
+    {
+        type=DFNT_UINT16;
+    }
+    else if (type == NX_INT32)
+    {
+        type=DFNT_INT32;
+    }
+    else if (type == NX_UINT32)
+    {
+        type=DFNT_UINT32;
+    }
+    else if (type == NX_FLOAT32)
+    {
+        type=DFNT_FLOAT32;
+    }
+    else if (type == NX_FLOAT64)
+    {
+        type=DFNT_FLOAT64;
+    }
+    *datalen = (*datalen) * DFKNTsize(type);
+    pFile = NXIassert (fid);
+  
+    /* find attribute */
+    if (pFile->iCurrentSDS != 0) {
+      /* SDS attribute */
+      iNew = SDfindattr (pFile->iCurrentSDS, name);
+    } else {
+      if(pFile->iCurrentVG == 0){
+       /* global attribute */
+       iNew = SDfindattr (pFile->iSID, name);
+      } else {
+        /* group attribute */
+	iNew = Vfindattr(pFile->iCurrentVG, name); 
+      }
+    }
+    if (iNew < 0) {
+      sprintf (pBuffer, "ERROR: attribute \"%s\" not found", name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+    /* get more info, allocate temporary data space */
+    iType32 = (int32)type;
+    if (pFile->iCurrentSDS != 0) {
+      iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen);
+    } else {
+      if(pFile->iCurrentVG == 0){
+	iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen);
+      } else {
+	iRet = Vattrinfo(pFile->iCurrentVG,iNew,pNam,&iType32,&count,
+			 &iLen);
+      }
+    }
+    if (iRet < 0) {
+      sprintf (pBuffer, "ERROR: HDF could not read attribute info");
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+    *iType = (int)iType32;
+    iLen = iLen * DFKNTsize (*iType);
+    if(*iType == NX_CHAR){
+      iLen += 1;
+    }
+    pData = (void *) malloc (iLen);
+    if (!pData) {
+      NXReportError( "ERROR: allocating memory in NXgetattr");
+      return NX_ERROR;
+    }
+    memset (pData, 0, iLen);
+  
+    /* finally read the data */
+    if (pFile->iCurrentSDS != 0) {
+      iRet = SDreadattr (pFile->iCurrentSDS, iNew, pData);
+    } else {
+      if(pFile->iCurrentVG == 0){
+	iRet = SDreadattr (pFile->iSID, iNew, pData);
+      } else {
+	iRet = Vgetattr(pFile->iCurrentVG, iNew, pData);
+      }
+    }
+    if (iRet < 0) {
+      sprintf (pBuffer, "ERROR: HDF could not read attribute data");
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+    /* copy data to caller */
+    memset (data, 0, *datalen);
+    if ((*datalen <= iLen) && 
+     (*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) {
+      iLen = *datalen - 1; /* this enforces NULL termination regardless of size of datalen */
+    }
+    memcpy (data, pData, iLen);
+    *datalen = iLen / DFKNTsize(*iType);
+    free (pData);
+    return NX_OK;
+  }
+ 
+  /*-------------------------------------------------------------------------*/
+
+    
+  NXstatus  NX4getattrinfo (NXhandle fid, int *iN)
+  {
+    pNexusFile pFile;
+    int iRet;
+    int32 iData, iAtt, iRank, iType;
+    int32 iDim[H4_MAX_VAR_DIMS];
+    NXname pNam;
+  
+    pFile = NXIassert (fid);
+    if (pFile->iCurrentSDS != 0) {        /* SDS level */
+      iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
+                        &iAtt);
+    } else {
+      if(pFile->iCurrentVG == 0){  
+	/* global level */
+	iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
+      } else {
+	iRet = Vnattrs(pFile->iCurrentVG);
+        iAtt = iRet;
+      }
+    }
+    if (iRet < 0) {
+      NXReportError( "NX_ERROR: HDF cannot read attribute numbers");
+      *iN = 0;
+      return NX_ERROR;
+    }
+    *iN = iAtt;
+    return NX_OK;
+  }
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NX4getgroupID (NXhandle fileid, NXlink* sRes)
+  {
+    pNexusFile pFile;
+  
+    pFile = NXIassert (fileid);
+  
+    if (pFile->iCurrentVG == 0) {
+      sRes->iTag = NX_ERROR;
+      return NX_ERROR;
+    } else {
+      sRes->iTag = DFTAG_VG;
+      sRes->iRef = VQueryref(pFile->iCurrentVG);
+      NXIbuildPath(pFile,sRes->targetPath,1024);
+      return NX_OK;
+    }
+    /* not reached */
+    sRes->iTag = NX_ERROR;
+    return NX_ERROR;
+  }
+
+ /*-------------------------------------------------------------------------*/
+
+  NXstatus
+   NX4getgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
+  {
+    pNexusFile pFile;
+  
+    pFile = NXIassert (fid);
+    /* check if there is a group open */
+    if (pFile->iCurrentVG == 0) {
+      *iN = Vlone (pFile->iVID, NULL, 0);
+      strcpy (pName, "root");
+      strcpy (pClass, "NXroot");
+    }
+    else {
+      *iN = Vntagrefs (pFile->iCurrentVG);
+      Vgetname (pFile->iCurrentVG, pName);
+      Vgetclass (pFile->iCurrentVG, pClass);
+    }
+    return NX_OK;
+  }
+  
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX4sameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID)
+  {
+    NXIassert (fileid);
+    if ((pFirstID->iTag == pSecondID->iTag) & (pFirstID->iRef == pSecondID->iRef)) {
+       return NX_OK;
+    } else {
+       return NX_ERROR;
+    }
+  }
+
+  /*-------------------------------------------------------------------------*/
+
+  
+  NXstatus  NX4initattrdir (NXhandle fid)
+  {
+    pNexusFile pFile;
+    int iRet;
+    
+    pFile = NXIassert (fid);
+    NXIKillAttDir (pFile);
+    iRet = NXIInitAttDir (pFile);
+    if (iRet == NX_ERROR)
+      return NX_ERROR;
+    return NX_OK;
+  }
+  
+ 
+  /*-------------------------------------------------------------------------*/
+ 
+  
+  NXstatus  NX4initgroupdir (NXhandle fid)
+  {
+    pNexusFile pFile;
+    int iRet;
+    
+    pFile = NXIassert (fid);
+    NXIKillDir (pFile);
+    iRet = NXIInitDir (pFile);
+    if (iRet < 0) {
+      NXReportError("NX_ERROR: no memory to store directory info");
+      return NX_EOD;
+    }
+    return NX_OK;
+  }
+ 
+/*--------------------------------------------------------------------*/
+void NX4assignFunctions(pNexusFunction fHandle)
+{
+      fHandle->nxclose=NX4close;
+	  fHandle->nxreopen=NULL;
+      fHandle->nxflush=NX4flush;
+      fHandle->nxmakegroup=NX4makegroup;
+      fHandle->nxopengroup=NX4opengroup;
+      fHandle->nxclosegroup=NX4closegroup;
+      fHandle->nxmakedata64=NX4makedata64;
+      fHandle->nxcompmakedata64=NX4compmakedata64;
+      fHandle->nxcompress=NX4compress;
+      fHandle->nxopendata=NX4opendata;
+      fHandle->nxclosedata=NX4closedata;
+      fHandle->nxputdata=NX4putdata;
+      fHandle->nxputattr=NX4putattr;
+      fHandle->nxputslab64=NX4putslab64;    
+      fHandle->nxgetdataID=NX4getdataID;
+      fHandle->nxmakelink=NX4makelink;
+      fHandle->nxmakenamedlink=NX4makenamedlink;
+      fHandle->nxgetdata=NX4getdata;
+      fHandle->nxgetinfo64=NX4getinfo64;
+      fHandle->nxgetnextentry=NX4getnextentry;
+      fHandle->nxgetslab64=NX4getslab64;
+      fHandle->nxgetnextattr=NX4getnextattr;
+      fHandle->nxgetattr=NX4getattr;
+      fHandle->nxgetattrinfo=NX4getattrinfo;
+      fHandle->nxgetgroupID=NX4getgroupID;
+      fHandle->nxgetgroupinfo=NX4getgroupinfo;
+      fHandle->nxsameID=NX4sameID;
+      fHandle->nxinitgroupdir=NX4initgroupdir;
+      fHandle->nxinitattrdir=NX4initattrdir;
+      fHandle->nxprintlink=NX4printlink;
+      fHandle->nxnativeexternallink=NULL;
+}
+
+#endif /*HDF4*/
diff --git a/src/napi5.c b/src/napi5.c
new file mode 100644
index 0000000..d58ab9f
--- /dev/null
+++ b/src/napi5.c
@@ -0,0 +1,2383 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  Application Program Interface (HDF5) Routines
+  
+  Copyright (C) 1997-2011 Mark Koennecke, Przemek Klosowski
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+             
+  For further information, see <http://www.nexusformat.org>
+
+----------------------------------------------------------------------------*/
+
+#ifdef HDF5 
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+
+#include "napi.h"
+#include "napi5.h"
+
+#ifdef H5_VERSION_GE
+#if !H5_VERSION_GE(1,8,0)
+#error HDF5 Version must be 1.8.0 or higher
+#endif
+#endif
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif /* _MSC_VER */
+
+#define NX_UNKNOWN_GROUP "" /* for when no NX_class attr */
+
+extern  void *NXpData;
+
+  typedef struct __NexusFile5 {
+        struct iStack5 {
+          char irefn[1024];
+          int iVref;
+          hsize_t iCurrentIDX;
+        } iStack5[NXMAXSTACK];
+        struct iStack5 iAtt5;
+        int iFID;
+        int iCurrentG;
+        int iCurrentD;
+        int iCurrentS;
+        int iCurrentT;
+        int iCurrentA;
+        int iNX;
+        int iNXID;
+        int iStackPtr;
+        char *iCurrentLGG;
+        char *iCurrentLD;
+        char name_ref[1024];
+        char name_tmp[1024];
+        char iAccess[2];
+  } NexusFile5, *pNexusFile5;
+
+/* 
+   forward declaration of NX5closegroup in order to get rid of a nasty
+   warning
+*/
+NXstatus  NX5closegroup (NXhandle fid);
+/*-------------------------------------------------------------------*/
+
+  static pNexusFile5 NXI5assert(NXhandle fid)
+  {
+    pNexusFile5 pRes;
+  
+    assert(fid != NULL);
+    pRes = (pNexusFile5)fid;
+    assert(pRes->iNXID == NX5SIGNATURE);
+    return pRes;
+  }
+  
+  /*--------------------------------------------------------------------*/
+
+   static void NXI5KillDir (pNexusFile5 self)
+  {
+    self->iStack5[self->iStackPtr].iCurrentIDX = 0;
+  }
+
+static herr_t readStringAttribute(hid_t attr, char** data)
+{
+     size_t iSize;
+     herr_t iRet;
+     hid_t atype = -1, btype = -1;
+
+	atype = H5Aget_type(attr);
+	*data = NULL;
+	if ( H5Tis_variable_str(atype) )
+	{
+	    btype = H5Tget_native_type(atype, H5T_DIR_ASCEND); 
+	    iRet = H5Aread(attr, btype, data);
+	    H5Tclose(btype);
+	}
+	else
+	{
+	    iSize = H5Tget_size(atype);
+	    *data = malloc(iSize+1);
+	    iRet = H5Aread(attr, atype, *data);
+	    (*data)[iSize] = '\0';
+	}
+	H5Tclose(atype);
+    return iRet;
+}
+  
+static herr_t readStringAttributeN(hid_t attr, char* data, int maxlen)
+{
+    herr_t iRet;
+    char* vdat = NULL;
+    iRet = readStringAttribute(attr, &vdat);
+    if (iRet >= 0)
+    {
+        strncpy(data, vdat, maxlen);
+        free(vdat);
+    }
+    data[maxlen-1] = '\0';
+    return iRet;
+}
+  /*--------------------------------------------------------------------*/
+
+  static void NXI5KillAttDir (pNexusFile5 self)
+  {
+    self->iAtt5.iCurrentIDX = 0;
+  }
+/*---------------------------------------------------------------------*/
+static void buildCurrentPath(pNexusFile5 self, char *pathBuffer, 
+			     int pathBufferLen){
+
+  memset(pathBuffer,0,pathBufferLen);
+  if(self->iCurrentG != 0) {
+    strcpy(pathBuffer,"/");
+    if((int)strlen(self->name_ref) + 1 < pathBufferLen){
+      strcat(pathBuffer, self->name_ref);
+    }
+  }
+  if(self->iCurrentD != 0){
+    strcat(pathBuffer,"/");
+    if((int)strlen(self->iCurrentLD) + (int)strlen(pathBuffer) < pathBufferLen){
+      strcat(pathBuffer,self->iCurrentLD);
+    }
+  }
+}
+  /* ---------------------------------------------------------------------- 
+  
+                          Definition of NeXus API
+
+   ---------------------------------------------------------------------*/
+
+  NXstatus  NX5reopen(NXhandle pOrigHandle, NXhandle* pNewHandle)  
+{
+        pNexusFile5 pNew = NULL, pOrig = NULL;
+    *pNewHandle = NULL;
+       pOrig = (pNexusFile5)pOrigHandle;
+    pNew = (pNexusFile5) malloc (sizeof (NexusFile5));
+    if (!pNew) {
+      NXReportError ("ERROR: no memory to create File datastructure");
+      return NX_ERROR;
+    }
+    memset (pNew, 0, sizeof (NexusFile5));
+    pNew->iFID = H5Freopen (pOrig->iFID);
+    if (pNew->iFID <= 0) {
+        NXReportError ("cannot clone file");
+		free (pNew);
+      return NX_ERROR;
+       }
+       strcpy(pNew->iAccess, pOrig->iAccess);
+    pNew->iNXID = NX5SIGNATURE;
+    pNew->iStack5[0].iVref = 0;    /* root! */
+    *pNewHandle = (NXhandle)pNew;
+    return NX_OK;
+}
+
+NXstatus  NX5open(CONSTCHAR *filename, NXaccess am, 
+				 NXhandle* pHandle)
+  {
+  hid_t attr1,aid1, aid2, iVID;
+  pNexusFile5 pNew = NULL;
+  char pBuffer[512];
+  char *time_buffer = NULL;
+  char version_nr[10];
+  unsigned int vers_major, vers_minor, vers_release, am1 ;
+  hid_t fapl = -1;     
+  int mdc_nelmts;
+  size_t rdcc_nelmts;
+  size_t rdcc_nbytes;
+  double rdcc_w0;
+  unsigned hdf5_majnum, hdf5_minnum, hdf5_relnum;
+
+  *pHandle = NULL;
+
+  if (H5get_libversion(&hdf5_majnum, &hdf5_minnum, &hdf5_relnum) < 0)
+  {
+      NXReportError("ERROR: cannot determine HDF5 library version");
+      return NX_ERROR;
+  }
+  if (hdf5_majnum == 1 && hdf5_minnum < 8)
+  {
+      NXReportError("ERROR: HDF5 library 1.8.0 or higher required");
+      return NX_ERROR;
+  }
+
+  /* mask of any options for now */
+  am = (NXaccess)(am & NXACCMASK_REMOVEFLAGS);
+
+  /* turn off the automatic HDF error handling */  
+      H5Eset_auto(H5E_DEFAULT, NULL, NULL);  
+#ifdef USE_FTIME
+    struct timeb timeb_struct;
+#endif 
+
+
+    pNew = (pNexusFile5) malloc (sizeof (NexusFile5));
+    if (!pNew) {
+      NXReportError("ERROR: not enough memory to create file structure");
+      return NX_ERROR;
+    }
+    memset (pNew, 0, sizeof (NexusFile5));
+
+
+    /* start HDF5 interface */
+    if (am == NXACC_CREATE5) {  
+       fapl = H5Pcreate(H5P_FILE_ACCESS);
+       H5Pget_cache(fapl,&mdc_nelmts,&rdcc_nelmts,&rdcc_nbytes,&rdcc_w0);
+       rdcc_nbytes=(size_t)nx_cacheSize;
+       H5Pset_cache(fapl,mdc_nelmts,rdcc_nelmts,rdcc_nbytes,rdcc_w0);
+       H5Pset_fclose_degree(fapl,H5F_CLOSE_STRONG);
+       am1 = H5F_ACC_TRUNC;
+       pNew->iFID = H5Fcreate (filename, am1, H5P_DEFAULT, fapl);
+    } else {
+       if (am == NXACC_READ) {
+          am1 = H5F_ACC_RDONLY;
+        } else {
+          am1 = H5F_ACC_RDWR;
+        }    
+        fapl = H5Pcreate(H5P_FILE_ACCESS);
+	H5Pset_fclose_degree(fapl,H5F_CLOSE_STRONG);
+        pNew->iFID = H5Fopen (filename, am1, fapl);
+    }  
+    if(fapl != -1) {
+      H5Pclose(fapl);
+    }
+    if (pNew->iFID <= 0) {
+      sprintf (pBuffer, "ERROR: cannot open file: %s", filename);
+      NXReportError( pBuffer);
+      free (pNew);
+      return NX_ERROR;
+    }
+
+/*
+ * need to create global attributes         file_name file_time NeXus_version 
+ * at some point for new files
+ */
+    if (am1 != H5F_ACC_RDONLY) 
+    {
+        iVID = H5Gopen(pNew->iFID,"/", H5P_DEFAULT);
+        aid2 = H5Screate(H5S_SCALAR);
+        aid1 = H5Tcopy(H5T_C_S1);
+        H5Tset_size(aid1, strlen(NEXUS_VERSION));
+        if (am1 == H5F_ACC_RDWR)
+        {
+        H5Adelete(iVID, "NeXus_version"); 
+        }
+        attr1= H5Acreate(iVID, "NeXus_version", aid1, aid2, H5P_DEFAULT, H5P_DEFAULT);
+        if (attr1<0)
+        {
+          NXReportError( 
+                         "ERROR: failed to store NeXus_version attribute ");
+          return NX_ERROR;
+        } 
+        if (H5Awrite(attr1, aid1,NEXUS_VERSION)<0)
+        {
+          NXReportError( 
+                         "ERROR: failed to store NeXus_version attribute ");
+          return NX_ERROR;
+        }
+       /* Close attribute dataspace  */
+       H5Tclose(aid1);
+       H5Sclose(aid2); 
+       /* Close attribute */
+       H5Aclose(attr1); 
+       H5Gclose(iVID); 
+    }
+    if (am1 == H5F_ACC_TRUNC) 
+    {
+        iVID = H5Gopen(pNew->iFID,"/", H5P_DEFAULT);
+        aid2 = H5Screate(H5S_SCALAR);
+        aid1 = H5Tcopy(H5T_C_S1);
+        H5Tset_size(aid1, strlen(filename));
+        attr1= H5Acreate(iVID, "file_name", aid1, aid2, H5P_DEFAULT, H5P_DEFAULT);
+        if (attr1 < 0)
+        {
+          NXReportError( 
+			  "ERROR: failed to store file_name attribute ");
+          return NX_ERROR;
+        }
+        if (H5Awrite(attr1, aid1, (char*)filename) < 0)
+        {
+          NXReportError( 
+			  "ERROR: failed to store file_name attribute ");
+          return NX_ERROR;
+        }
+	H5Tclose(aid1);
+	H5Sclose(aid2); 
+        H5Aclose(attr1);
+	/*  ------- library version ------*/
+        H5get_libversion(&vers_major, &vers_minor, &vers_release);
+        sprintf (version_nr, "%d.%d.%d", vers_major,vers_minor,vers_release);
+        aid2=H5Screate(H5S_SCALAR);
+        aid1 = H5Tcopy(H5T_C_S1);
+        H5Tset_size(aid1, strlen(version_nr));
+        attr1= H5Acreate(iVID, "HDF5_Version", aid1, aid2, H5P_DEFAULT, H5P_DEFAULT);
+        if (attr1 < 0)
+        {
+          NXReportError( 
+			  "ERROR: failed to store file_name attribute ");
+          return NX_ERROR;
+        }
+        if (H5Awrite(attr1, aid1, (char*)version_nr) < 0)
+        {
+          NXReportError( 
+			  "ERROR: failed to store file_name attribute ");
+          return NX_ERROR;
+        }
+	H5Tclose(aid1);
+	H5Sclose(aid2); 
+        H5Aclose(attr1);
+	/*----------- file time */
+	time_buffer = NXIformatNeXusTime();
+	if(time_buffer != NULL){
+	  aid2=H5Screate(H5S_SCALAR);
+	  aid1 = H5Tcopy(H5T_C_S1);
+	  H5Tset_size(aid1, strlen(time_buffer));
+	  attr1=H5Acreate(iVID, "file_time", aid1, aid2, H5P_DEFAULT, H5P_DEFAULT);
+	  if (attr1 < 0)
+	  {
+	      NXReportError( 
+			  "ERROR: failed to store file_time attribute ");
+	      free(time_buffer);
+	      return NX_ERROR;
+	  }
+	  if (H5Awrite(attr1, aid1, time_buffer) < 0)
+	  {
+	      NXReportError( 
+			  "ERROR: failed to store file_time attribute ");
+	      free(time_buffer);
+	      return NX_ERROR;
+	  }
+	  /* Close attribute dataspace */
+	  H5Tclose(aid1);
+	  H5Sclose(aid2); 
+	  /* Close attribute */
+	  H5Aclose(attr1); 
+	  free(time_buffer);
+	}
+	H5Gclose(iVID); 
+    }
+    /* Set HDFgroup access mode */
+    if (am1 == H5F_ACC_RDONLY) {
+      strcpy(pNew->iAccess,"r");
+    } else {
+      strcpy(pNew->iAccess,"w");
+    }
+    pNew->iNXID = NX5SIGNATURE;
+    pNew->iStack5[0].iVref = 0;    /* root! */
+    *pHandle = (NXhandle)pNew;
+     return NX_OK;
+  }
+ 
+  /* ------------------------------------------------------------------------- */
+
+  NXstatus  NX5close (NXhandle* fid)
+  {
+    pNexusFile5 pFile = NULL;
+    herr_t iRet;
+ 
+    pFile=NXI5assert(*fid);
+
+    iRet=0;
+    /*
+    printf("HDF5 object count before close: %d\n",
+	   H5Fget_obj_count(pFile->iFID,H5F_OBJ_ALL));
+    */
+    iRet = H5Fclose(pFile->iFID);
+
+    /* 
+      leave this here: it helps in debugging leakage problems   
+    printf("HDF5 object count after close: %d\n",
+	   H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_ALL));
+    printf("HDF5 dataset count after close: %d\n",
+	   H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_DATASET));
+    printf("HDF5 group count after close: %d\n",
+	   H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_GROUP));
+    printf("HDF5 datatype count after close: %d\n",
+	   H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_DATATYPE));
+    printf("HDF5 attribute count after close: %d\n",
+	   H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_ATTR));
+    */
+
+    if (iRet < 0) {
+      NXReportError( "ERROR: cannot close HDF file");
+    }
+    /* release memory */
+    NXI5KillDir (pFile);
+    if(pFile->iCurrentLGG != NULL){
+      free(pFile->iCurrentLGG);
+    }
+    if(pFile->iCurrentLD != NULL){
+      free(pFile->iCurrentLD);
+    }
+    free (pFile);
+    *fid = NULL;
+    H5garbage_collect();
+    return NX_OK;
+  }
+
+ /*-----------------------------------------------------------------------*/   
+
+  NXstatus  NX5makegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
+  {
+    pNexusFile5 pFile;
+    herr_t iRet;
+    hid_t iVID;
+    hid_t attr1,aid1, aid2;
+    char pBuffer[1024] = "";
+    
+    pFile = NXI5assert (fid);
+    /* create and configure the group */
+    if (pFile->iCurrentG==0) {
+       snprintf(pBuffer,1023,"/%s",name);
+    } else {
+       snprintf(pBuffer,1023,"/%s/%s",pFile->name_ref,name);
+    }   
+    iRet = H5Gcreate(pFile->iFID,(const char*)pBuffer, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+    if (iRet < 0) {
+      NXReportError( "ERROR: could not create Group");
+      return NX_ERROR;
+    }
+    iVID = iRet;
+    aid2 = H5Screate(H5S_SCALAR);
+    aid1 = H5Tcopy(H5T_C_S1);
+    H5Tset_size(aid1, strlen(nxclass));
+    attr1= H5Acreate(iVID, "NX_class", aid1, aid2, H5P_DEFAULT, H5P_DEFAULT);
+    if (attr1 < 0) {
+       NXReportError( "ERROR: failed to store class name");
+       return NX_ERROR;
+    }
+    if (H5Awrite(attr1, aid1, (char*)nxclass) < 0) {
+      NXReportError( "ERROR: failed to store class name");
+      return NX_ERROR;
+    }
+    /* close group */
+    iRet=H5Sclose(aid2);
+    iRet=H5Tclose(aid1);
+    iRet=H5Aclose(attr1);
+    iRet=H5Gclose(iVID);
+    return NX_OK;
+  }
+  
+  /*------------------------------------------------------------------------*/
+
+  herr_t attr_check (hid_t loc_id, const char *member_name, const H5A_info_t *unused, void *opdata)
+  {
+    char attr_name[8+1];   /* need to leave space for \0 as well */
+    
+    strcpy(attr_name,"NX_class");
+    return strstr(member_name, attr_name) ? 1 : 0;
+  }
+  /*------------------------------------------------------------------------*/
+  NXstatus  NX5opengroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
+  {
+
+    pNexusFile5 pFile;
+    hid_t attr1, atype;
+    herr_t iRet;
+    char pBuffer[1024];
+    char data[128];
+          
+    pFile = NXI5assert (fid);
+    if (pFile->iCurrentG == 0) {
+      strcpy(pBuffer,name);
+    } else {
+       sprintf(pBuffer,"%s/%s",pFile->name_tmp,name);
+    }
+    iRet = H5Gopen(pFile->iFID, (const char *)pBuffer, H5P_DEFAULT);
+    if (iRet < 0) {
+      sprintf (pBuffer, "ERROR: group %s does not exist", pFile->name_tmp);
+      NXReportError( pBuffer);
+      return NX_ERROR;  
+    }
+    pFile->iCurrentG = iRet;
+    strcpy(pFile->name_tmp,pBuffer);
+    strcpy(pFile->name_ref,pBuffer);
+
+    if ((nxclass != NULL) && (strcmp(nxclass, NX_UNKNOWN_GROUP) != 0)) {
+        /* check group attribute */
+        iRet=H5Aiterate(pFile->iCurrentG,H5_INDEX_CRT_ORDER,H5_ITER_INC,0,attr_check,NULL);
+        if (iRet < 0) {
+          NXReportError( "ERROR: iterating through attribute list");
+          return NX_ERROR;  
+        } else if (iRet == 1) {
+         /* group attribute was found */
+        } else {
+         /* no group attribute available */
+         NXReportError( "ERROR: no group attribute available");
+         return NX_ERROR;
+        }
+        /* check contents of group attribute */
+        attr1 = H5Aopen_by_name(pFile->iCurrentG, ".", "NX_class", H5P_DEFAULT, H5P_DEFAULT);
+        if (attr1 < 0) {
+              NXReportError( "ERROR: opening NX_class group attribute");
+              return NX_ERROR; 
+        }
+        atype=H5Tcopy(H5T_C_S1);
+        H5Tset_size(atype,sizeof(data));  
+	iRet = readStringAttributeN(attr1, data, sizeof(data));
+        //iRet = H5Aread(attr1, atype, data);
+        if (strcmp(data, nxclass) == 0) {
+              /* test OK */
+        } else {
+              snprintf(pBuffer, sizeof(pBuffer), "ERROR: group class is not identical: \"%s\" != \"%s\"", data, nxclass);
+              NXReportError(pBuffer);
+              iRet = H5Tclose(atype);
+              iRet = H5Aclose(attr1); 
+              return NX_ERROR; 
+        }          
+        iRet = H5Tclose(atype);
+        iRet = H5Aclose(attr1); 
+    }
+
+    /* maintain stack */
+    pFile->iStackPtr++;
+    pFile->iStack5[pFile->iStackPtr].iVref=pFile->iCurrentG;
+    strcpy(pFile->iStack5[pFile->iStackPtr].irefn,name);
+    pFile->iAtt5.iCurrentIDX=0;
+    pFile->iCurrentD = 0;
+    if(pFile->iCurrentLGG != NULL){
+      free(pFile->iCurrentLGG);
+    }
+    pFile->iCurrentLGG = strdup(name);
+    NXI5KillDir (pFile);
+    return NX_OK;
+  }
+
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX5closegroup (NXhandle fid)
+  {
+    pNexusFile5 pFile;
+    int i,ii;
+    char *uname = NULL;
+    char *u1name = NULL;
+    
+    pFile = NXI5assert (fid);
+    /* first catch the trivial case: we are at root and cannot get 
+       deeper into a negative directory hierarchy (anti-directory)
+     */
+    if (pFile->iCurrentG == 0) {
+      NXI5KillDir (pFile);
+      return NX_OK;
+    } else {                      
+      /* close the current group and decrement name_ref */
+      H5Gclose (pFile->iCurrentG);
+      i = 0;
+      i = (int)strlen(pFile->iStack5[pFile->iStackPtr].irefn);
+      ii = (int)strlen(pFile->name_ref);
+      if (pFile->iStackPtr>1) {
+         ii=ii-i-1;
+      } else {
+          ii=ii-i;
+      }       
+      if (ii>0) {
+        uname = strdup(pFile->name_ref);  
+        u1name = (char*) malloc((ii+1)*sizeof(char));
+        memset(u1name,0,ii);
+        for (i=0; i<ii; i++) {
+           *(u1name + i) = *(uname + i);
+        }
+        *(u1name + i) = '\0';
+        /*
+        strncpy(u1name, uname, ii);
+        */
+        strcpy(pFile->name_ref,u1name);
+        strcpy(pFile->name_tmp,u1name);
+        free(uname);
+        free(u1name);
+      } else {
+        strcpy(pFile->name_ref,"");
+        strcpy(pFile->name_tmp,"");
+      }
+      NXI5KillDir (pFile);
+      pFile->iStackPtr--;
+      if (pFile->iStackPtr>0) {
+         pFile->iCurrentG=pFile->iStack5[pFile->iStackPtr].iVref;
+      } else {
+         pFile->iCurrentG=0;
+      }
+    }
+    return NX_OK;
+  }
+/*-----------------------------------------------------------------------*/
+static hid_t nxToHDF5Type(int datatype)
+{
+  hid_t type;
+    if (datatype == NX_CHAR) {
+        type=H5T_C_S1;
+    } else if (datatype == NX_INT8) {
+        type=H5T_NATIVE_CHAR;
+    } else if (datatype == NX_UINT8) {
+        type=H5T_NATIVE_UCHAR;
+    } else if (datatype == NX_INT16) {
+        type=H5T_NATIVE_SHORT;
+    } else if (datatype == NX_UINT16) {
+        type=H5T_NATIVE_USHORT;
+    } else if (datatype == NX_INT32) {
+        type=H5T_NATIVE_INT;
+    } else if (datatype == NX_UINT32) {
+        type=H5T_NATIVE_UINT;
+    } else if (datatype == NX_INT64) {
+	type = H5T_NATIVE_INT64;
+    } else if (datatype == NX_UINT64) {
+	type = H5T_NATIVE_UINT64;
+    } else if (datatype == NX_FLOAT32) {
+        type=H5T_NATIVE_FLOAT;
+    } else if (datatype == NX_FLOAT64) {
+        type=H5T_NATIVE_DOUBLE;
+    } else {
+      NXReportError( "ERROR: nxToHDF5Type: unknown type");
+      type = -1;
+    }
+    return type;
+}
+  
+ /* --------------------------------------------------------------------- */
+
+  NXstatus  NX5compmakedata64 (NXhandle fid, CONSTCHAR *name, 
+					  int datatype, 
+					  int rank, int64_t dimensions[],
+					  int compress_type, int64_t chunk_size[])
+  {
+      hid_t datatype1, dataspace, iNew;
+      herr_t iRet;
+      hid_t type, cparms = -1;
+      pNexusFile5 pFile;
+      char pBuffer[256];
+      int i;
+      size_t byte_zahl = 0;
+      hsize_t chunkdims[H5S_MAX_RANK];
+      hsize_t mydim[H5S_MAX_RANK], mydim1[H5S_MAX_RANK];  
+      hsize_t size[H5S_MAX_RANK];
+      hsize_t maxdims[H5S_MAX_RANK];
+      int compress_level;
+      int unlimiteddim = 0;
+
+      pFile = NXI5assert (fid);
+      if (pFile->iCurrentG <= 0) {
+          sprintf(pBuffer, "ERROR: no group open for makedata on %s", name);
+          NXReportError( pBuffer);
+          return NX_ERROR;
+      }
+
+      if (rank <= 0) {
+          sprintf (pBuffer, "ERROR: invalid rank specified %s", name);
+          NXReportError( pBuffer);
+          return NX_ERROR;
+      }
+
+      type = nxToHDF5Type(datatype);
+
+      /*
+      Check dimensions for consistency. Dimension may be -1
+      thus denoting an unlimited dimension.
+      */
+      for (i = 0; i < rank; i++)
+      {
+          chunkdims[i] = chunk_size[i];
+          mydim[i] = dimensions[i];
+          maxdims[i] = dimensions[i];
+          size[i] = dimensions[i];
+          if (dimensions[i] <= 0) 
+          {
+		mydim[i] = 1;
+		maxdims[i] = H5S_UNLIMITED;
+                size[i] = 1;
+		unlimiteddim = 1;
+          } else {
+                mydim[i] = dimensions[i];
+                maxdims[i] = dimensions[i];
+                size[i] = dimensions[i];
+          }
+      }
+
+      if (datatype == NX_CHAR)
+      {
+          /* 
+          *  This assumes string lenght is in the last dimensions and
+          *  the logic must be the same as used in NX5getslab and NX5getinfo
+          *
+          *  search for tests on H5T_STRING
+          */
+          byte_zahl=(size_t)mydim[rank-1]; 
+          for(i = 0; i < rank; i++)
+          {
+              mydim1[i] = mydim[i];
+		if (dimensions[i] <= 0) 
+		  {
+	              mydim1[0] = 1;
+       		       maxdims[0] = H5S_UNLIMITED;
+		 }
+
+          }
+          mydim1[rank-1] = 1;
+          if (mydim[rank-1] > 1)
+          {
+              mydim[rank-1] = maxdims[rank-1] = size[rank-1] = 1;
+          }
+          if (chunkdims[rank-1] > 1) 
+          { 
+              chunkdims[rank-1] = 1; 
+          }
+          dataspace=H5Screate_simple(rank,mydim1,maxdims);
+      } 
+      else 
+      {
+	  if (unlimiteddim)
+	  {
+              dataspace=H5Screate_simple(rank, mydim, maxdims);
+          } 
+          else 
+          {
+              /* dataset creation */
+              dataspace=H5Screate_simple(rank, mydim, NULL);  
+          }
+      }  
+      datatype1=H5Tcopy(type);
+      if (datatype == NX_CHAR)
+      {
+          H5Tset_size(datatype1, byte_zahl);
+          /*       H5Tset_strpad(H5T_STR_SPACEPAD); */
+      }
+      compress_level = 6;
+      if ( (compress_type / 100) ==  NX_COMP_LZW )
+      {
+          compress_level = compress_type % 100;
+          compress_type = NX_COMP_LZW;
+      }
+      if(compress_type == NX_COMP_LZW)
+      {
+          cparms = H5Pcreate(H5P_DATASET_CREATE);
+          iNew = H5Pset_chunk(cparms,rank,chunkdims);
+          if (iNew < 0) 
+          {
+              NXReportError( "ERROR: size of chunks could not be set");
+              return NX_ERROR;
+          }
+          H5Pset_deflate(cparms,compress_level); 
+          iRet = H5Dcreate(pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT);   
+      } 
+      else if (compress_type == NX_COMP_NONE) 
+      {
+          if (unlimiteddim)
+          {
+              cparms = H5Pcreate(H5P_DATASET_CREATE);
+              iNew = H5Pset_chunk(cparms,rank,chunkdims);
+              if (iNew < 0) 
+              {
+                  NXReportError( "ERROR: size of chunks could not be set");
+                  return NX_ERROR;
+              }
+              iRet = H5Dcreate(pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT);   
+          } 
+          else 
+          {
+              iRet = H5Dcreate(pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+          }               
+      } 
+      else if (compress_type == NX_CHUNK) 
+      {
+          cparms = H5Pcreate(H5P_DATASET_CREATE);
+          iNew = H5Pset_chunk(cparms,rank,chunkdims);
+          if (iNew < 0) 
+          {
+              NXReportError("ERROR: size of chunks could not be set");
+              return NX_ERROR;
+          }
+          iRet = H5Dcreate(pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT);
+
+      } 
+      else 
+      {
+          NXReportError( 
+              "HDF5 doesn't support selected compression method! Dataset was saved without compression");
+          iRet = H5Dcreate (pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 
+      }
+      if (iRet < 0) 
+      {
+          NXReportError( "ERROR: creating chunked dataset failed");
+          return NX_ERROR;
+      } 
+      else 
+      {
+          pFile->iCurrentD = iRet;
+      }
+      if (unlimiteddim)
+      {      
+          iNew = H5Dset_extent  (pFile->iCurrentD, size);
+          if (iNew < 0) 
+          {
+              sprintf (pBuffer, "ERROR: cannot create dataset %s",
+                  name);
+              NXReportError( pBuffer);
+              return NX_ERROR;
+          }
+      }
+      if (cparms != -1)
+      {
+          iRet = H5Pclose(cparms);
+      }
+      iRet = H5Sclose(dataspace);
+      iRet = H5Tclose(datatype1);
+      iRet = H5Dclose(pFile->iCurrentD);
+      pFile->iCurrentD = 0;
+      if (iRet < 0)
+      {
+          NXReportError( "ERROR: HDF cannot close dataset");
+          return NX_ERROR;
+      }
+      return NX_OK;
+  }
+
+
+  /* --------------------------------------------------------------------- */
+
+  NXstatus  NX5makedata64 (NXhandle fid, CONSTCHAR *name, int datatype, 
+                                  int rank, int64_t dimensions[])
+  {
+  int64_t chunk_size[H5S_MAX_RANK];
+  int i;
+   
+  NXI5assert(fid);
+    
+  memset(chunk_size,0,H5S_MAX_RANK*sizeof(int64_t));
+  memcpy(chunk_size,dimensions,rank*sizeof(int64_t));
+  for(i = 0; i< rank; i++) {
+  if (dimensions[i] == NX_UNLIMITED || dimensions[i] <= 0){
+         chunk_size[i]= 1;
+  }    
+  }
+  return NX5compmakedata64 (fid, name, datatype, rank, dimensions, NX_COMP_NONE, chunk_size);
+  }
+
+  
+  /* --------------------------------------------------------------------- */
+
+  NXstatus  NX5compress (NXhandle fid, int compress_type)
+  {
+    printf(" NXcompress ERROR: NeXus API  based  on  HDF5  doesn't support\n");
+    printf("                   NXcompress  function!  Using  HDF5 library,\n");
+    printf("                   the NXcompmakedata function can be applied\n"); 
+    printf("                   for compression of data!\n");
+    return NX_ERROR;
+  }  
+
+  /* --------------------------------------------------------------------- */
+
+  NXstatus  NX5opendata (NXhandle fid, CONSTCHAR *name)
+  {
+    pNexusFile5 pFile;
+    char pBuffer[256];
+      
+    pFile = NXI5assert (fid);
+    /* clear pending attribute directories first */
+    NXI5KillAttDir (pFile);
+
+
+    /* find the ID number and open the dataset */
+    pFile->iCurrentD = H5Dopen(pFile->iCurrentG, name, H5P_DEFAULT);
+    if (pFile->iCurrentD < 0) {
+      sprintf (pBuffer, "ERROR: dataset \"%s\" not found at this level", name);
+      NXReportError( pBuffer);
+      return NX_ERROR;
+    }
+     /* find the ID number of datatype */
+    pFile->iCurrentT = H5Dget_type(pFile->iCurrentD);
+    if (pFile->iCurrentT < 0) {
+      NXReportError( "ERROR: error opening dataset");
+      pFile->iCurrentT=0;
+      return NX_ERROR;
+    }
+    /* find the ID number of dataspace */
+    pFile->iCurrentS = H5Dget_space(pFile->iCurrentD);
+    if (pFile->iCurrentS < 0) {
+      NXReportError( "ERROR:HDF error opening dataset");
+      pFile->iCurrentS=0;
+      return NX_ERROR;
+    }
+    if(pFile->iCurrentLD != NULL){
+      free(pFile->iCurrentLD);
+    }
+    pFile->iCurrentLD = strdup(name); 
+    return NX_OK;
+  }
+  
+  /* ----------------------------------------------------------------- */
+
+  NXstatus  NX5closedata (NXhandle fid)
+  {
+    pNexusFile5 pFile;
+    herr_t iRet;
+  
+    pFile = NXI5assert (fid);
+    iRet = H5Sclose(pFile->iCurrentS);
+    iRet = H5Tclose(pFile->iCurrentT);
+    iRet = H5Dclose(pFile->iCurrentD);
+    if (iRet < 0) {
+        NXReportError( "ERROR: cannot end access to dataset");
+        return NX_ERROR;
+     }
+    pFile->iCurrentD=0;
+    return NX_OK;
+  }
+  
+  /* ------------------------------------------------------------------- */
+  
+
+
+  NXstatus  NX5putdata (NXhandle fid, const void *data)
+  {
+    pNexusFile5 pFile;
+    herr_t iRet;
+    int64_t myStart[H5S_MAX_RANK];
+    int64_t mySize[H5S_MAX_RANK];
+    hsize_t thedims[H5S_MAX_RANK],maxdims[H5S_MAX_RANK];
+    int i, rank, unlimiteddim = 0;
+    
+    char pError[512] = "";
+      
+    pFile = NXI5assert (fid);
+    rank = H5Sget_simple_extent_ndims(pFile->iCurrentS);    
+    if (rank < 0)
+    {
+        NXReportError("ERROR: Cannot determine dataset rank");
+	return NX_ERROR;
+    }
+    iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, thedims, maxdims);
+    if (iRet < 0)
+    {
+        NXReportError("ERROR: Cannot determine dataset dimensions");
+	return NX_ERROR;
+    }
+    for(i=0; i<rank; ++i)
+    {
+	myStart[i] = 0;
+	mySize[i] = thedims[i];
+	if (maxdims[i] == H5S_UNLIMITED)
+	{
+	    unlimiteddim = 1;
+	    myStart[i] = thedims[i] + 1;
+	    mySize[i] = 1;
+	}
+    }
+    /* If we are using putdata on an unlimied dimesnion dataset, assume we want to append one single new slab */
+    if ( unlimiteddim )
+    {
+	return NX5putslab64(fid, data, myStart, mySize);
+    }
+    else
+    {
+        iRet = H5Dwrite (pFile->iCurrentD, pFile->iCurrentT, H5S_ALL, H5S_ALL, 
+                     H5P_DEFAULT, data);
+        if (iRet < 0) {
+          snprintf (pError,sizeof(pError)-1, "ERROR: failure to write data");
+          NXReportError( pError);
+          return NX_ERROR;
+        }
+    }
+    return NX_OK;
+  }
+/*------------------------------------------------------------------*/
+static int getAttVID(pNexusFile5 pFile){
+  int vid;
+     if(pFile->iCurrentG == 0 && pFile->iCurrentD == 0){
+       /* global attribute */
+       vid = H5Gopen(pFile->iFID,"/", H5P_DEFAULT);
+     } else if(pFile->iCurrentD != 0) {
+       /* dataset attribute */
+       vid = pFile->iCurrentD;
+     } else {
+       /* group attribute */;
+       vid = pFile->iCurrentG;
+     }
+     return vid;
+}
+/*---------------------------------------------------------------*/
+static void killAttVID(pNexusFile5 pFile, int vid){
+  if(pFile->iCurrentG == 0 && pFile->iCurrentD == 0){
+    H5Gclose(vid);
+  }
+}
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX5putattr (NXhandle fid, CONSTCHAR *name, const void *data, 
+
+			int datalen, int iType)
+  {
+    pNexusFile5 pFile;
+    hid_t  attr1, aid1, aid2;
+    hid_t type;
+    herr_t iRet;
+    int vid;  
+
+    pFile = NXI5assert (fid);
+
+    type = nxToHDF5Type(iType);
+   
+    /* determine vid */
+    vid = getAttVID(pFile);
+    aid2=H5Screate(H5S_SCALAR);
+    aid1=H5Tcopy(type);
+    if (iType == NX_CHAR){
+      H5Tset_size(aid1,datalen); 
+    }         
+    iRet = H5Aopen_by_name(vid, ".", name, H5P_DEFAULT, H5P_DEFAULT);
+    if (iRet>0) {
+      H5Aclose(iRet);
+      iRet=H5Adelete(vid,name);
+      if (iRet<0) {
+	NXReportError( "ERROR: old attribute cannot be removed! ");
+	killAttVID(pFile,vid);
+	return NX_ERROR;
+      }
+    }    
+    attr1 = H5Acreate(vid, name, aid1, aid2, H5P_DEFAULT, H5P_DEFAULT);
+    if (attr1 < 0) {
+      NXReportError( "ERROR: attribute cannot created! ");
+      killAttVID(pFile,vid);
+      return NX_ERROR;
+    }   
+    if (H5Awrite(attr1,aid1,data) < 0) {
+      NXReportError( "ERROR: failed to store attribute ");
+      killAttVID(pFile,vid);
+      return NX_ERROR;
+    }
+    /* Close attribute dataspace */
+    iRet=H5Tclose(aid1);
+    iRet=H5Sclose(aid2); 
+    /* Close attribute  */
+    iRet=H5Aclose(attr1); 
+    killAttVID(pFile,vid);
+    return NX_OK;
+  }
+  
+  /* ------------------------------------------------------------------- */
+ 
+  NXstatus  NX5putslab64 (NXhandle fid, const void *data, const int64_t iStart[], const int64_t iSize[])
+  {
+    pNexusFile5 pFile;
+    int iRet, rank, i;
+    hsize_t myStart[H5S_MAX_RANK];
+    hsize_t mySize[H5S_MAX_RANK];
+    hsize_t size[H5S_MAX_RANK],thedims[H5S_MAX_RANK],maxdims[H5S_MAX_RANK];
+    hid_t   filespace,dataspace; 
+    int unlimiteddim = 0;
+  
+    pFile = NXI5assert (fid);
+     /* check if there is an Dataset open */
+    if (pFile->iCurrentD == 0) {
+      NXReportError( "ERROR: no dataset open");
+      return NX_ERROR;
+    }
+    rank = H5Sget_simple_extent_ndims(pFile->iCurrentS);    
+    if (rank < 0) {
+      NXReportError( "ERROR: cannot get rank");
+      return NX_ERROR;
+    }
+    iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, thedims, maxdims);
+    if (iRet < 0) {
+      NXReportError( "ERROR: cannot get dimensions");
+      return NX_ERROR;
+    }
+
+    for(i = 0; i < rank; i++)
+    {
+       myStart[i] = iStart[i];
+       mySize[i]  = iSize[i];
+       size[i]    =  iStart[i] + iSize[i];
+       if (maxdims[i] == H5S_UNLIMITED) {
+	unlimiteddim = 1;
+       }
+    }
+    if (H5Tget_class(pFile->iCurrentT) == H5T_STRING)
+    {
+        mySize[rank - 1] = 1;
+        myStart[rank - 1] = 0;
+        size[rank - 1] = 1;
+    }
+    dataspace = H5Screate_simple(rank, mySize, NULL);
+    if (unlimiteddim)
+    {
+       for(i = 0; i < rank; i++)
+       {
+	if (size[i] < thedims[i]) {
+		size[i] = thedims[i];
+	}
+       } 
+       iRet = H5Dset_extent(pFile->iCurrentD, size);
+       if (iRet < 0) 
+       {
+           NXReportError( "ERROR: extend slab failed");
+           return NX_ERROR;
+       }
+
+       filespace = H5Dget_space(pFile->iCurrentD);
+       
+       /* define slab */
+       iRet = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, myStart,
+                               NULL, mySize, NULL);
+       /* deal with HDF errors */
+       if (iRet < 0) 
+       {
+       NXReportError( "ERROR: selecting slab failed");
+       return NX_ERROR;
+       }
+       /* write slab */ 
+       iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, 
+                    filespace, H5P_DEFAULT, data);
+       if (iRet < 0)
+       {
+           NXReportError( "ERROR: writing slab failed");
+       }
+       /* update with new size */
+       iRet = H5Sclose(pFile->iCurrentS);             
+       pFile->iCurrentS = filespace;
+   } else {
+       /* define slab */
+       iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart,
+                               NULL, mySize, NULL);
+       /* deal with HDF errors */
+       if (iRet < 0) 
+       {
+       NXReportError( "ERROR: selecting slab failed");
+       return NX_ERROR;
+       }
+       /* write slab */ 
+       iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, 
+                    pFile->iCurrentS, H5P_DEFAULT, data);
+       if (iRet < 0)
+       {
+           NXReportError( "ERROR: writing slab failed");
+       }
+   }
+   /* deal with HDF errors */
+   iRet = H5Sclose(dataspace);
+   if (iRet < 0) 
+   {
+      NXReportError( "ERROR: closing slab failed");
+      return NX_ERROR;
+   }
+    return NX_OK;
+  }
+ 
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX5getdataID (NXhandle fid, NXlink* sRes)
+  {
+    pNexusFile5 pFile;
+    int datalen, type = NX_CHAR;
+  
+    pFile = NXI5assert (fid);
+
+    /*
+      we cannot return ID's when no datset is open
+    */
+    if(pFile->iCurrentD <= 0){
+      return NX_ERROR;
+    }
+
+    /*
+      this means: if the item is already linked: use the target attribute else, 
+      the path to the current node
+    */
+    NXMDisableErrorReporting();
+    datalen = 1024;
+    memset(&sRes->targetPath,0,datalen*sizeof(char));
+    if(NX5getattr(fid,"target",&sRes->targetPath,&datalen,&type) != NX_OK)
+    {
+      buildCurrentPath(pFile, sRes->targetPath, 1024);
+    }
+    NXMEnableErrorReporting();
+    sRes->linkType = 1;
+    return NX_OK;
+  }
+
+ /* ------------------------------------------------------------------- */
+ 
+  NXstatus  NX5printlink (NXhandle fid, NXlink* sLink)
+  {
+    NXI5assert(fid);
+    printf("HDF5 link: targetPath = \"%s\", linkType = \"%d\"\n", sLink->targetPath, sLink->linkType);
+    return NX_OK;
+  }
+/*--------------------------------------------------------------------*/
+static NXstatus NX5settargetattribute(pNexusFile5 pFile, NXlink *sLink)
+{
+  hid_t  dataID, aid2, aid1, attID;
+  herr_t status;
+  char name[] = "target";
+
+    /*
+      set the target attribute
+    */
+    if(sLink->linkType > 0)
+    {
+      dataID = H5Dopen(pFile->iFID,sLink->targetPath, H5P_DEFAULT);
+    } else {
+      dataID = H5Gopen(pFile->iFID,sLink->targetPath, H5P_DEFAULT);
+    }
+    if(dataID < 0)
+    {
+      NXReportError("Internal error, path to link does not exist");
+      return NX_ERROR;
+    }
+    status = H5Aopen_by_name(dataID,".", name, H5P_DEFAULT, H5P_DEFAULT);
+    if(status > 0)
+    {
+      H5Aclose(status);
+      status = H5Adelete(dataID,name);
+      if(status < 0)
+      {
+	return NX_OK;
+      }
+    }
+    aid2 = H5Screate(H5S_SCALAR);
+    aid1 = H5Tcopy(H5T_C_S1);
+    H5Tset_size(aid1,strlen(sLink->targetPath));
+    attID = H5Acreate(dataID,name,aid1,aid2,H5P_DEFAULT, H5P_DEFAULT);
+    if(attID < 0)
+    {
+	return NX_OK;
+    }
+    status = H5Awrite(attID,aid1,sLink->targetPath);
+    H5Tclose(aid1);
+    H5Sclose(aid2); 
+    H5Aclose(attID); 
+    if(sLink->linkType > 0){
+      H5Dclose(dataID);
+    } else {
+      H5Gclose(dataID);
+    }
+    return NX_OK;
+}
+/*---------------------------------------------------------------------*/
+NXstatus NX5makenamedlink(NXhandle fid, CONSTCHAR *name, NXlink *sLink)
+{
+    pNexusFile5 pFile;
+    char        linkTarget[1024];
+
+    pFile = NXI5assert (fid);
+    if (pFile->iCurrentG == 0) { /* root level, can not link here */
+      return NX_ERROR;
+    }
+    
+    /*
+      build pathname to link from our current group and the name 
+      of the thing to link
+    */
+    if(strlen(pFile->name_ref) + strlen(name) + 2 < 1024)
+    {
+      strcpy(linkTarget,"/");
+      strcat(linkTarget,pFile->name_ref);
+      strcat(linkTarget,"/");
+      strcat(linkTarget,name);
+    }
+    else 
+    {
+      NXReportError("ERROR: path string to long");
+      return NX_ERROR;
+    } 
+
+    //targetid = H5Oopen(pFile->iFID, sLink->targetPath, H5P_DEFAULT);
+    H5Lcreate_hard(pFile->iFID, sLink->targetPath, H5L_SAME_LOC, linkTarget, H5P_DEFAULT, H5P_DEFAULT);
+    //H5Oclose(targetid);
+
+    return NX5settargetattribute(pFile,sLink);
+}
+ /* ------------------------------------------------------------------- */
+  
+  NXstatus  NX5makelink (NXhandle fid, NXlink* sLink)
+  {
+    pNexusFile5 pFile;
+    char        linkTarget[1024];
+    char        *itemName = NULL;
+
+    pFile = NXI5assert (fid);
+    if (pFile->iCurrentG == 0) { /* root level, can not link here */
+      return NX_ERROR;
+    }
+    
+    /*
+      locate name of the element to link 
+    */
+    itemName = strrchr(sLink->targetPath,'/');
+    if(itemName == NULL){
+      NXReportError("ERROR: bad link structure");
+      return NX_ERROR;
+    }
+    itemName++;
+
+    /*
+      build pathname to link from our current group and the name 
+      of the thing to link
+    */
+    if(strlen(pFile->name_ref) + strlen(itemName) + 2 < 1024)
+    {
+      strcpy(linkTarget,"/");
+      strcat(linkTarget,pFile->name_ref);
+      strcat(linkTarget,"/");
+      strcat(linkTarget,itemName);
+    }
+    else 
+    {
+      NXReportError("ERROR: path string to long");
+      return NX_ERROR;
+    } 
+
+    //targetid = H5Oopen(pFile->iFID, sLink->targetPath, H5P_DEFAULT);
+    H5Lcreate_hard(pFile->iFID, sLink->targetPath, H5L_SAME_LOC, linkTarget, H5P_DEFAULT, H5P_DEFAULT);
+    //H5Oclose(targetid);
+
+    return NX5settargetattribute(pFile,sLink);
+   }
+ 
+  /*----------------------------------------------------------------------*/
+
+  NXstatus  NX5flush(NXhandle *pHandle)
+  {
+    pNexusFile5 pFile = NULL;
+    herr_t      iRet;
+   
+    pFile = NXI5assert (*pHandle);    
+    if (pFile->iCurrentD != 0)
+    {    
+    iRet=H5Fflush(pFile->iCurrentD,H5F_SCOPE_LOCAL);
+    }
+    else if (pFile->iCurrentG != 0)
+    {    
+    iRet=H5Fflush(pFile->iCurrentG,H5F_SCOPE_LOCAL);
+    }
+    else
+    { 
+    iRet=H5Fflush(pFile->iFID,H5F_SCOPE_LOCAL);
+    }
+    if (iRet < 0){
+      NXReportError( "ERROR: The object cannot be flushed");
+      return NX_ERROR; 
+    }
+    return NX_OK;
+  }   
+  
+  /*-------------------------------------------------------------------------*/
+  
+  /* Operator function. */
+           
+  herr_t nxgroup_info(hid_t loc_id, const char *name, const H5L_info_t *statbuf, void *op_data)
+  {
+    pinfo self = (pinfo) op_data;
+    H5O_info_t object_info;
+    H5Oget_info_by_name(loc_id, name, &object_info, H5P_DEFAULT);
+    switch ((object_info).type) {
+      case H5O_TYPE_GROUP: 
+         self->iname = strdup(name);
+         self->type = H5O_TYPE_GROUP;
+         break;
+      case H5O_TYPE_DATASET: 
+         self->iname = strdup(name);
+         self->type = H5O_TYPE_DATASET;
+         break;
+      default:
+         // TODO defaults to group. not what we would want?
+         self->type=0;
+         break;     
+    }
+    return 1; 
+  }
+  /* --------------------------------------------------------------------- */
+
+  /* Operator function. */
+
+  herr_t group_info1(hid_t loc_id, const char *name, const H5L_info_t *statbuf, void *opdata)
+  {
+    int iNX = *((int*)opdata);
+    H5O_info_t object_info;
+    H5Oget_info_by_name(loc_id, name, &object_info, H5P_DEFAULT);
+    switch ((object_info).type) {
+      case H5O_TYPE_GROUP: 
+        iNX++;
+        *((int*)opdata)=iNX;
+        break;
+      case H5O_TYPE_DATASET:
+        iNX++;
+        *((int*)opdata)=iNX;
+        break;
+      default:
+	break;
+    }
+    return 0; 
+  }
+  
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NX5getgroupinfo_recurse(NXhandle fid, int *iN, NXname pName, NXname pClass)
+  {
+    pNexusFile5 pFile;
+    hid_t       atype, attr_id, grp;
+    char        data[64];
+        
+    pFile = NXI5assert (fid);
+    /* check if there is a group open */
+    if (pFile->iCurrentG == 0) {
+       strcpy (pName, "root");
+       strcpy (pClass, "NXroot");
+       pFile->iNX=0;
+       grp = H5Gopen(pFile->iFID,"/",H5P_DEFAULT);
+       H5Literate(grp, H5_INDEX_NAME, H5_ITER_INC, 0, group_info1, &pFile->iNX);
+       H5Gclose(grp);
+       *iN=pFile->iNX;
+    }
+    else {
+      strcpy (pName,pFile->name_ref);
+      attr_id = H5Aopen_by_name(pFile->iCurrentG,".", "NX_class", H5P_DEFAULT, H5P_DEFAULT);
+      if (attr_id<0) {
+         strcpy(pClass, NX_UNKNOWN_GROUP);
+      } else {
+        atype=H5Tcopy(H5T_C_S1);
+        H5Tset_size(atype,sizeof(data));  
+	readStringAttributeN(attr_id, data, sizeof(data));
+        //H5Aread(attr_id, atype, data);
+        strcpy(pClass,data);
+        pFile->iNX=0;
+        grp = H5Gopen(pFile->iFID,pFile->name_ref,H5P_DEFAULT);
+        H5Literate(grp, H5_INDEX_NAME, H5_ITER_INC, 0, group_info1, &pFile->iNX);
+        H5Gclose(grp);
+        *iN=pFile->iNX;
+        H5Aclose(attr_id);
+      }
+    }
+    return NX_OK;
+  }
+/*---------------------------------------------------------------------------*/
+static int countObjectsInGroup(hid_t loc_id)
+{
+  int count = 0;
+  H5G_info_t numobj;
+  
+  herr_t status;
+
+  status = H5Gget_info(loc_id, &numobj);
+  if(status < 0) {
+    NXReportError("Internal error, failed to retrive no of objects");
+    return 0;
+  }
+
+  count = (int)numobj.nlinks;
+  return count;
+}
+/*----------------------------------------------------------------------------*/
+  NXstatus  NX5getgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
+  {
+    pNexusFile5 pFile;
+    hid_t atype, attr_id, gid;
+    char data[64];
+
+    pFile = NXI5assert (fid);
+    /* check if there is a group open */
+    if (pFile->iCurrentG == 0) {
+       strcpy (pName, "root");
+       strcpy (pClass, "NXroot");
+       gid = H5Gopen(pFile->iFID,"/", H5P_DEFAULT);
+       *iN = countObjectsInGroup(gid);
+       H5Gclose(gid);
+    }
+    else {
+      strcpy (pName,pFile->name_ref);
+      attr_id = H5Aopen_by_name(pFile->iCurrentG,".", "NX_class", H5P_DEFAULT, H5P_DEFAULT);
+      if (attr_id<0) {
+         strcpy(pClass, NX_UNKNOWN_GROUP);
+      } else {
+        atype=H5Tcopy(H5T_C_S1);
+        H5Tset_size(atype,sizeof(data));  
+	readStringAttributeN(attr_id, data, sizeof(data));
+        //H5Aread(attr_id, atype, data);
+        strcpy(pClass,data);
+        H5Aclose(attr_id);
+      }
+      pFile->iNX=0;
+      *iN = countObjectsInGroup(pFile->iCurrentG);
+    }
+    return NX_OK;
+  }
+
+
+/*-------------------------------------------------------------------------
+ * Function: hdf5ToNXType
+ *
+ * Purpose:	Convert a HDF5 class to a NeXus type;  it handles the following HDF5 classes
+ *  H5T_STRING
+ *  H5T_INTEGER
+ *  H5T_FLOAT
+ *
+ * Return: the NeXus type
+ *
+ *-------------------------------------------------------------------------
+ */
+  static int hdf5ToNXType(H5T_class_t tclass, hid_t atype)
+  {
+      int        iPtype = -1;
+      size_t     size;
+      H5T_sign_t sign;
+
+      if (tclass==H5T_STRING)
+      {
+          iPtype=NX_CHAR;
+      }
+      else if (tclass==H5T_INTEGER)
+      {
+          size=H5Tget_size(atype);
+          sign=H5Tget_sign(atype);
+          if (size==1)
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  iPtype=NX_INT8;
+              } else {
+                  iPtype=NX_UINT8;
+              }
+          } 
+          else if (size==2) 
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  iPtype=NX_INT16;
+              } else {
+                  iPtype=NX_UINT16;
+              }
+          }
+          else if (size==4) 
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  iPtype=NX_INT32;
+              } else {
+                  iPtype=NX_UINT32;
+              }
+          } 
+          else if(size == 8)
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  iPtype=NX_INT64;
+              } else {
+                  iPtype=NX_UINT64;
+              }
+          }
+      } 
+      else if (tclass==H5T_FLOAT)     
+      {
+          size=H5Tget_size(atype);
+          if (size==4)
+          {
+              iPtype=NX_FLOAT32;
+          } 
+          else if (size==8) 
+          {
+              iPtype=NX_FLOAT64;
+          }
+      }
+      if (iPtype == -1)
+      {
+          NXReportError( "ERROR: hdf5ToNXtype: invalid type");
+      }
+
+      return iPtype;
+  }
+/*--------------------------------------------------------------------------*/
+  static hid_t h5MemType(hid_t atype)
+  {
+      hid_t       memtype_id = -1;
+      size_t      size;
+      H5T_sign_t  sign;
+      H5T_class_t tclass;
+
+      tclass = H5Tget_class(atype);
+
+      if (tclass==H5T_INTEGER)
+      {
+          size=H5Tget_size(atype);
+          sign=H5Tget_sign(atype);
+          if (size==1)
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  memtype_id = H5T_NATIVE_INT8;
+              } else {
+                  memtype_id = H5T_NATIVE_UINT8;
+              }
+          } 
+          else if (size==2) 
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  memtype_id = H5T_NATIVE_INT16;
+              } else {
+                  memtype_id = H5T_NATIVE_UINT16; 
+              }
+          }
+          else if (size==4) 
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  memtype_id = H5T_NATIVE_INT32;
+              } else {
+                  memtype_id = H5T_NATIVE_UINT32; 
+              }
+          }
+          else if (size==8) 
+          {
+              if (sign==H5T_SGN_2)
+              {
+                  memtype_id = H5T_NATIVE_INT64;
+              } else {
+                  memtype_id = H5T_NATIVE_UINT64;
+              }
+          }
+      } else if (tclass==H5T_FLOAT)     
+      {
+          size=H5Tget_size(atype);
+          if (size==4)
+          {
+              memtype_id = H5T_NATIVE_FLOAT; 
+          } else if (size==8) {
+              memtype_id = H5T_NATIVE_DOUBLE;
+          }
+      }           
+      if (memtype_id == -1)
+      {
+          NXReportError( "ERROR: h5MemType: invalid type");
+      }
+      return memtype_id;
+  }
+  /*-------------------------------------------------------------------------*/
+
+  NXstatus  NX5getnextentry(NXhandle fid, NXname name, NXname nxclass, int *datatype)
+  {
+    pNexusFile5 pFile;
+    hid_t       grp, attr1,type,atype;
+    herr_t      iRet;
+    int         iPtype, i;
+    hsize_t     idx;
+    H5T_class_t tclass;
+    char        data[128];
+    char        ph_name[1024];
+    info_type   op_data;
+    herr_t      iRet_iNX=-1;
+    char        pBuffer[256];
+     
+    pFile = NXI5assert (fid);
+    op_data.iname = NULL;
+
+    /*
+      iterate to next entry in group list
+    */
+    idx=pFile->iStack5[pFile->iStackPtr].iCurrentIDX;
+    if (strlen(pFile->name_ref) == 0) {
+       /* root group */
+       strcpy(pFile->name_ref,"/");
+    }  
+    grp = H5Gopen(pFile->iFID, pFile->name_ref, H5P_DEFAULT);
+    // index can be wrong here
+    iRet=H5Literate(grp, H5_INDEX_NAME, H5_ITER_INC, &idx, nxgroup_info, &op_data);
+    H5Gclose(grp);
+    strcpy(nxclass, NX_UNKNOWN_GROUP);
+   
+    /*
+      figure out the number of items in the current group. We need this in order to
+      find out if we are at the end of the search. 
+    */
+    if (pFile->iCurrentG == 0) {
+	// if pFile->iCurrentG == 0 would not pFile->name_ref be "/" already, so we could skip that if statement ?
+       pFile->iNX=0;
+       grp = H5Gopen(pFile->iFID, "/", H5P_DEFAULT);
+       iRet_iNX=H5Literate(grp, H5_INDEX_NAME, H5_ITER_INC, 0, group_info1, &pFile->iNX);
+       H5Gclose(grp);
+    } else {
+      pFile->iNX=0;
+      grp = H5Gopen(pFile->iFID, pFile->name_ref, H5P_DEFAULT);
+	// index can be wrong here
+      iRet_iNX=H5Literate(grp, H5_INDEX_NAME, H5_ITER_INC, 0, group_info1, &pFile->iNX);
+      H5Gclose(grp);
+    }
+    if (idx == pFile->iNX) {
+	// why 2?
+       iRet_iNX = 2;   
+    } 
+         
+    if (iRet > 0)
+      {
+        pFile->iStack5[pFile->iStackPtr].iCurrentIDX++;
+        if (op_data.iname != NULL) {
+	  strcpy(name,op_data.iname);
+           free(op_data.iname);
+        } else {
+	  pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0;   
+	  return NX_EOD;
+	}	  
+        if (op_data.type == H5O_TYPE_GROUP) {
+	  /*
+	    open group and find class name attribute 
+	  */
+           strcpy(ph_name,"");
+           for(i = 1; i < (pFile->iStackPtr + 1); i++)
+           {
+              strcat(ph_name,pFile->iStack5[i].irefn);
+              strcat(ph_name,"/");
+           }
+           strcat(ph_name,name);
+           grp = H5Gopen(pFile->iFID,ph_name, H5P_DEFAULT);
+           if (grp < 0) {
+              sprintf(pBuffer, "ERROR: group %s does not exist", ph_name);
+              NXReportError(pBuffer);
+              return NX_ERROR;  
+           }
+           attr1 = H5Aopen_by_name(grp,".",  "NX_class", H5P_DEFAULT, H5P_DEFAULT);
+           if (attr1 < 0) {
+	      strcpy(nxclass, NX_UNKNOWN_GROUP);
+           } else {
+               type=H5T_C_S1;
+               atype=H5Tcopy(type);
+               H5Tset_size(atype,sizeof(data));  
+	       iRet = readStringAttributeN(attr1, data, sizeof(data));
+               //iRet = H5Aread(attr1, atype, data);
+               strcpy(nxclass,data);
+               H5Tclose(atype);
+	       H5Aclose(attr1);
+           }
+           H5Gclose(grp);
+        } else if (op_data.type==H5O_TYPE_DATASET) {
+	  /*
+	    open dataset and find type
+	  */
+           grp=H5Dopen(pFile->iCurrentG,name, H5P_DEFAULT);
+           type=H5Dget_type(grp);
+           atype=H5Tcopy(type);
+           tclass = H5Tget_class(atype);
+           iPtype = hdf5ToNXType(tclass, atype);
+           *datatype=iPtype;
+           strcpy(nxclass, "SDS");
+           H5Tclose(atype);
+	    H5Tclose(type);
+	    H5Dclose(grp);
+	 }
+	  return NX_OK;
+       } else { 
+	 /*
+	   we are at the end of the search: clear the data structure and reset 
+	   iCurrentIDX to 0
+	 */
+	  if (iRet_iNX == 2) {
+	    if (op_data.iname != NULL) {
+	       free(op_data.iname);
+	    }
+	    pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0;   
+	    return NX_EOD;
+	 } 
+	 if (op_data.iname != NULL) {
+	    free(op_data.iname);
+	 } 
+	 NXReportError("ERROR: iterating through group not successful");
+	 return NX_ERROR;              
+       }
+   }
+
+   /*-------------------------------------------------------------------------*/
+
+   NXstatus  NX5getdata (NXhandle fid, void *data)
+   {
+     pNexusFile5 pFile;
+     int i, iStart[H5S_MAX_RANK], status;
+     hid_t memtype_id; 
+     H5T_class_t tclass;
+     hsize_t ndims,dims[H5S_MAX_RANK];
+     size_t len;    
+     char** vstrdata = NULL;
+
+     pFile = NXI5assert (fid);
+     /* check if there is an Dataset open */
+     if (pFile->iCurrentD == 0) 
+     {
+	NXReportError( "ERROR: no dataset open");
+	return NX_ERROR;
+     }
+     ndims = H5Sget_simple_extent_dims(pFile->iCurrentS, dims, NULL); 
+     if (ndims <= 0)
+     {
+	NXReportError( "ERROR: unable to read dims");
+	return NX_ERROR;
+     }
+     memset (iStart, 0, H5S_MAX_RANK * sizeof(int));
+     /* map datatypes of other plateforms */
+     tclass = H5Tget_class(pFile->iCurrentT);
+     if ( H5Tis_variable_str(pFile->iCurrentT) )
+     {
+        vstrdata = (char **) malloc ((size_t)dims[0] * sizeof (char *));
+	memtype_id = H5Tcopy(H5T_C_S1);
+	H5Tset_size(memtype_id, H5T_VARIABLE);
+        status = H5Dread (pFile->iCurrentD, memtype_id, 
+		       H5S_ALL, H5S_ALL,H5P_DEFAULT, vstrdata);
+        ((char*)data)[0] = '\0';
+        if (status >= 0)
+	{
+	    for(i=0; i<dims[0]; ++i)
+	    {
+	        if (vstrdata[i] != NULL)
+	 	{
+		    strcat((char*)data, vstrdata[i]);
+		}
+	    }
+	}
+        H5Dvlen_reclaim(memtype_id, pFile->iCurrentS, H5P_DEFAULT, vstrdata);
+	free(vstrdata);
+        H5Tclose(memtype_id);
+     }
+     else if (tclass==H5T_STRING)
+     {
+        status = H5Dread (pFile->iCurrentD, pFile->iCurrentT, 
+		       H5S_ALL, H5S_ALL,H5P_DEFAULT, data);
+     }
+     else 
+     {
+       memtype_id = h5MemType(pFile->iCurrentT);
+       status = H5Dread (pFile->iCurrentD, memtype_id, 
+		       H5S_ALL, H5S_ALL,H5P_DEFAULT, data);
+     }
+     if(status < 0)
+     {
+	NXReportError( "ERROR: failed to transfer dataset");
+	return NX_ERROR;
+
+     }
+     return NX_OK;
+   }
+
+   /*-------------------------------------------------------------------------*/
+
+   NXstatus  NX5getinfo64 (NXhandle fid, int *rank, int64_t dimension[], int *iType)
+   {
+     pNexusFile5 pFile;
+     int i, iRank, mType;
+     hsize_t myDim[H5S_MAX_RANK], vlen_bytes = 0, total_dims_size = 1; 
+     H5T_class_t tclass;
+
+     pFile = NXI5assert (fid);
+     /* check if there is an Dataset open */
+     if (pFile->iCurrentD == 0) {
+       NXReportError( "ERROR: no dataset open");
+       return NX_ERROR;
+     }
+
+     /* read information */
+     tclass = H5Tget_class(pFile->iCurrentT);
+     mType = hdf5ToNXType(tclass,pFile->iCurrentT);
+     iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS);
+     H5Sget_simple_extent_dims(pFile->iCurrentS, myDim, NULL);   
+     for(i=0; i<iRank; ++i)
+     {
+	total_dims_size *= myDim[i];
+     }
+     /* conversion to proper ints for the platform */ 
+     *iType = (int)mType;
+     if (tclass==H5T_STRING && myDim[iRank-1] == 1) {
+	if ( H5Tis_variable_str(pFile->iCurrentT) )
+	{
+	    /* this would not work for ragged arrays */
+	    H5Dvlen_get_buf_size(pFile->iCurrentD, pFile->iCurrentT, pFile->iCurrentS, &vlen_bytes);
+	    myDim[iRank-1] = vlen_bytes / total_dims_size;
+	}
+	else
+	{
+            myDim[iRank-1] = H5Tget_size(pFile->iCurrentT);
+	}
+     } 
+     *rank = (int)iRank;
+     for (i = 0; i < iRank; i++)
+     {
+	  dimension[i] = (int64_t)myDim[i];
+     }
+     return NX_OK;
+   }
+
+   /*-------------------------------------------------------------------------*/
+
+   NXstatus  NX5getslab64 (NXhandle fid, void *data, const int64_t iStart[], const int64_t iSize[])
+   {
+     pNexusFile5 pFile;
+     hsize_t myStart[H5S_MAX_RANK];
+     hsize_t mySize[H5S_MAX_RANK];
+     hsize_t mStart[H5S_MAX_RANK];
+     hid_t   memspace, iRet;
+     H5T_class_t tclass;
+     hid_t   memtype_id;
+     char *tmp_data = NULL;
+     char *data1;
+     int i, iRank, mtype = 0;
+     size_t dims;
+
+     pFile = NXI5assert (fid);
+     /* check if there is an Dataset open */
+     if (pFile->iCurrentD == 0) 
+       {
+	 NXReportError( "ERROR: no dataset open");
+	 return NX_ERROR;
+       }
+     iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); 
+     for (i = 0; i < iRank; i++)
+	{
+	  myStart[i] = (hssize_t)iStart[i];
+	  mySize[i]  = (hsize_t)iSize[i];
+	  mStart[i] = (hsize_t)0;
+	}
+      tclass = H5Tget_class(pFile->iCurrentT);
+      if (tclass == H5T_STRING) {
+/* 
+ * FAA 24/1/2007: I don't think this will work for multidimensional
+ * string arrays. 
+ * MK 23/7/2007: You are right Freddie. 
+*/
+	 mtype = NX_CHAR;
+	 if (mySize[0] == 1) {
+	     mySize[0]  = H5Tget_size(pFile->iCurrentT);
+	 }    
+	 tmp_data = (char*) malloc((size_t)mySize[0]);
+	 memset(tmp_data,0,sizeof(mySize[0]));
+	 iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, mStart,
+				NULL, mySize, NULL);
+      } else {
+	 iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart,
+				NULL, mySize, NULL);
+      }
+      /* define slab */
+      /* deal with HDF errors */
+      if (iRet < 0) 
+	{
+	  NXReportError( "ERROR: selecting slab failed");
+	  return NX_ERROR;
+	}
+
+      memspace=H5Screate_simple(iRank, mySize, NULL);
+      iRet = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, mStart,
+				NULL, mySize, NULL);
+      if (iRet < 0) 
+	{
+	  NXReportError( "ERROR: selecting memspace failed");
+	  return NX_ERROR;
+	}
+       /* map datatypes of other plateforms */
+       if (tclass == H5T_STRING)
+       {
+         memtype_id = pFile->iCurrentT;
+       }
+       else 
+       {
+	 memtype_id = h5MemType(pFile->iCurrentT);
+       }
+
+      /* read slab */ 
+      if (mtype == NX_CHAR) {
+	 iRet = H5Dread(pFile->iCurrentD, memtype_id, H5S_ALL, 
+		     H5S_ALL, H5P_DEFAULT,tmp_data);
+	  data1 = tmp_data + myStart[0];
+	  strncpy((char*)data,data1,(size_t)iSize[0]);
+	  free(tmp_data);           
+      } else {    
+	 iRet = H5Dread(pFile->iCurrentD, memtype_id, memspace, 
+		     pFile->iCurrentS, H5P_DEFAULT,data);
+      }    
+      /* cleanup */
+      H5Sclose(memspace);
+
+      if (iRet < 0) 
+
+	{
+	  NXReportError( "ERROR: reading slab failed");
+	  return NX_ERROR;
+	}
+      return NX_OK;
+   }
+
+   /*-------------------------------------------------------------------------*/
+
+   /* Operator function. */
+
+   herr_t attr_info(hid_t loc_id, const char *name, const H5A_info_t *unused, void *opdata)
+   {
+     *((char**)opdata)=strdup(name);
+     return 1;
+   }
+
+   NXstatus  NX5getnextattr (NXhandle fileid, NXname pName, int *iLength, int *iType)
+   {
+     pNexusFile5 pFile;
+     hid_t attr_id;
+     hid_t atype, aspace;
+     herr_t iRet;
+     int iPType,rank;
+     char *iname = NULL, *vlen_str = NULL; 
+     hsize_t idx, intern_idx=-1;
+     int vid;
+     H5O_info_t oinfo;
+
+     pFile = NXI5assert (fileid);
+
+     vid = getAttVID(pFile);
+
+     pName[0] = '\0';
+     idx=pFile->iAtt5.iCurrentIDX;
+     iRet=0;
+ 
+     H5Oget_info(vid, &oinfo);
+     intern_idx=oinfo.num_attrs;
+     if(intern_idx == idx) {
+       killAttVID(pFile,vid);
+       return NX_EOD;
+     }
+
+     if (intern_idx > idx) {
+       iRet=H5Aiterate(vid,H5_INDEX_CRT_ORDER,H5_ITER_INC,&idx,attr_info,&iname);
+     } else {
+       iRet=0;
+     } 
+     intern_idx=-1;
+     if (iRet < 0) {
+	   NXReportError( "ERROR: iterating through attribute list");
+	   killAttVID(pFile,vid);
+	   return NX_ERROR;  
+     } 
+     pFile->iAtt5.iCurrentIDX++;
+     if (iname != NULL) {
+       if(strcmp(iname, "NX_class") == 0 && pFile->iCurrentG != 0 && pFile->iCurrentD == 0) {
+	 /*
+	   skip NXclass attribute which is internal 
+	 */
+	 killAttVID(pFile, vid);
+	 return NX5getnextattr(fileid, pName, iLength, iType);
+       }
+       strcpy(pName, iname);
+       free(iname);
+       iname = NULL;
+     } else {
+       strcpy(pName,"What is this?");
+     }
+     pFile->iCurrentA = H5Aopen_by_name(vid, ".", pName, H5P_DEFAULT, H5P_DEFAULT);
+     atype  = H5Aget_type(pFile->iCurrentA);
+     aspace = H5Aget_space(pFile->iCurrentA);
+     rank = H5Sget_simple_extent_ndims(aspace);
+     attr_id = H5Tget_class(atype);
+     if (attr_id==H5T_STRING) {
+       iPType=NX_CHAR;
+       readStringAttribute(pFile->iCurrentA, &vlen_str);
+       rank = (int)strlen(vlen_str);
+       free(vlen_str);
+     }
+     if (rank == 0) {
+       rank++;
+     }  
+     iPType = hdf5ToNXType(attr_id,atype);
+     *iType=iPType;
+     *iLength=rank;
+     H5Tclose(atype);
+     H5Sclose(aspace);
+     H5Aclose(pFile->iCurrentA);
+  
+     H5Oget_info(vid, &oinfo);
+     intern_idx=oinfo.num_attrs;
+
+     killAttVID(pFile,vid);
+     return NX_OK;
+   }
+ /*-------------------------------------------------------------------------*/
+
+   NXstatus  NX5getattr (NXhandle fid, char *name, 
+			 void *data, int* datalen, int* iType)
+   {
+     pNexusFile5 pFile;
+     int iNew, vid;
+     herr_t iRet;
+     hid_t type, atype = -1;
+     char pBuffer[256];
+
+     pFile = NXI5assert (fid);
+
+     type = nxToHDF5Type(*iType);
+
+     vid = getAttVID(pFile);
+     iNew = H5Aopen_by_name(vid, ".", name, H5P_DEFAULT, H5P_DEFAULT);
+     if (iNew < 0) {
+       sprintf (pBuffer, "ERROR: attribute \"%s\" not found", name);
+       killAttVID(pFile,vid);
+       NXReportError( pBuffer);
+       return NX_ERROR;
+     }
+     pFile->iCurrentA = iNew;
+     /* finally read the data */
+     if (type==H5T_C_S1)
+     {
+	atype = H5Aget_type(pFile->iCurrentA);
+	iRet = readStringAttributeN(pFile->iCurrentA, data, *datalen);
+	*datalen = (int)strlen((char*)data);
+     } else {
+       iRet = H5Aread(pFile->iCurrentA, type, data);
+       *datalen=1;
+     }
+
+     if (iRet < 0) {
+       sprintf (pBuffer, "ERROR: could not read attribute data for \"%s\"", name);
+       NXReportError( pBuffer);
+       killAttVID(pFile,vid);
+       return NX_ERROR;
+     }
+
+     H5Aclose(pFile->iCurrentA);
+
+     killAttVID(pFile,vid);
+     if (type==H5T_C_S1)
+     {
+       H5Tclose(atype);
+     }
+     return NX_OK;
+   }  
+
+   /*-------------------------------------------------------------------------*/
+
+   NXstatus  NX5getattrinfo (NXhandle fid, int *iN)
+   {
+     pNexusFile5 pFile;
+     hid_t idx;
+     int vid;
+     H5O_info_t oinfo;
+    
+     pFile = NXI5assert (fid);
+     idx=0;
+     *iN = idx;
+
+     vid = getAttVID(pFile);
+
+     H5Oget_info(vid, &oinfo);
+     idx=(hid_t)oinfo.num_attrs;
+     if (idx > 0) {
+       if(pFile->iCurrentG > 0 && pFile->iCurrentD == 0){
+	 *iN = idx -1; 
+       } else {
+	 *iN = idx;
+       }
+     } else {
+       *iN = 0;   
+     }
+     killAttVID(pFile,vid);
+     return NX_OK;
+   }
+
+
+   /*-------------------------------------------------------------------------*/
+   NXstatus  NX5getgroupID (NXhandle fileid, NXlink* sRes)
+  {
+    pNexusFile5 pFile;
+    int datalen, type = NX_CHAR;
+  
+    pFile = NXI5assert (fileid);
+    if (pFile->iCurrentG == 0) {
+      return NX_ERROR;
+    } 
+    else {
+      /*
+	this means: if the item is already linked: use the target attribute, else 
+	the path to the current node
+      */
+      NXMDisableErrorReporting();
+      datalen = 1024;
+      memset(sRes->targetPath,0,datalen*sizeof(char));
+      if(NX5getattr(fileid,"target",sRes->targetPath,&datalen,&type) != NX_OK){
+	buildCurrentPath(pFile,sRes->targetPath,1024);
+      }
+      NXMEnableErrorReporting();
+      sRes->linkType = 0;
+      return NX_OK;
+    }
+    /* not reached */
+    return NX_ERROR;
+  }  
+ 
+  /* ------------------------------------------------------------------- */
+
+   NXstatus  NX5nativeexternallink(NXhandle fileid, const char* name, const char* externalfile, const char* remotetarget)
+  {
+     herr_t iRet;
+     pNexusFile5 pFile;
+     hid_t openwhere;
+
+     pFile = NXI5assert(fileid);
+
+      if (pFile->iCurrentG <= 0) {
+          openwhere = pFile->iFID;
+      } else {
+          openwhere = pFile->iCurrentG;
+      }
+
+     iRet = H5Lcreate_external(externalfile, remotetarget, openwhere, name, H5P_DEFAULT, H5P_DEFAULT);
+     if (iRet < 0) {
+       NXReportError("ERROR: making external link failed");
+       return NX_ERROR;
+     }
+     return NX_OK;
+  }
+  /* ------------------------------------------------------------------- */
+
+   NXstatus  NX5nativeinquirefile(NXhandle fileid, char* externalfile, const int filenamelen)
+  {
+     pNexusFile5 pFile;
+     ssize_t name_size;
+     hid_t openthing;
+
+     pFile = NXI5assert(fileid);
+      if (pFile->iCurrentD > 0) {
+          openthing = pFile->iCurrentD;
+      } else if (pFile->iCurrentG > 0) {
+          openthing = pFile->iCurrentG;
+      } else {
+          openthing = pFile->iFID;
+      }
+
+     name_size = H5Fget_name(openthing, externalfile, filenamelen);
+
+     // Check for failure again
+     if( name_size < 0 ) {
+         NXReportError("ERROR: retrieving file name");
+         return NX_ERROR;
+     }
+     return NX_OK;
+  }
+  /* ------------------------------------------------------------------- */
+
+   NXstatus  NX5nativeisexternallink(NXhandle fileid, const char* name, char* url, const int urllen)
+  {
+     pNexusFile5 pFile;
+     herr_t ret;
+     H5L_info_t link_buff;
+     char linkval_buff[1024];
+     const char *filepath = NULL, *objpath = NULL;
+     size_t val_size;
+     hid_t openthing;
+
+     pFile = NXI5assert(fileid);
+     memset(url, 0, urllen);
+
+     if (pFile->iCurrentG > 0) {
+         openthing = pFile->iCurrentG;
+     } else {
+         openthing = pFile->iFID;
+     }
+
+     ret = H5Lget_info(openthing, name, &link_buff, H5P_DEFAULT);
+     if (ret < 0 || link_buff.type != H5L_TYPE_EXTERNAL) {
+       return NX_ERROR;
+     }
+
+     val_size = link_buff.u.val_size;
+     if (val_size > sizeof(linkval_buff)) {
+       NXReportError("ERROR: linkval_buff too small");
+       return NX_ERROR;
+     }
+
+     ret = H5Lget_val(openthing, name, linkval_buff, val_size, H5P_DEFAULT);
+     if (ret < 0) {
+       NXReportError("ERROR: H5Lget_val failed");
+       return NX_ERROR;
+     }
+
+     ret = H5Lunpack_elink_val(linkval_buff, val_size, NULL, &filepath, &objpath);
+     if (ret < 0) {
+       NXReportError("ERROR: H5Lunpack_elink_val failed");
+       return NX_ERROR;
+     }
+
+    snprintf(url, urllen-1, "nxfile://%s#%s", filepath, objpath);
+    return NX_OK;
+     
+  }
+  /* ------------------------------------------------------------------- */
+
+  NXstatus  NX5sameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID)
+  {
+    NXI5assert(fileid);
+    if ((strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0)){
+       return NX_OK;
+    } else {
+       return NX_ERROR;
+    }
+  }
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+  NXstatus  NX5initattrdir (NXhandle fid)
+  {
+    pNexusFile5 pFile;
+        
+    pFile = NXI5assert (fid);
+    NXI5KillAttDir (pFile);
+    return NX_OK;
+  }
+
+  /*-------------------------------------------------------------------------*/
+ 
+  NXstatus  NX5initgroupdir (NXhandle fid)
+  {
+    pNexusFile5 pFile;
+        
+    pFile = NXI5assert (fid);
+    NXI5KillDir (pFile);
+    return NX_OK;
+  }
+/*------------------------------------------------------------------------*/
+void NX5assignFunctions(pNexusFunction fHandle)
+{
+		
+      fHandle->nxclose=NX5close;
+      fHandle->nxreopen=NX5reopen;
+      fHandle->nxflush=NX5flush;
+      fHandle->nxmakegroup=NX5makegroup;
+      fHandle->nxopengroup=NX5opengroup;
+      fHandle->nxclosegroup=NX5closegroup;
+      fHandle->nxmakedata64=NX5makedata64;
+      fHandle->nxcompmakedata64=NX5compmakedata64;
+      fHandle->nxcompress=NX5compress;
+      fHandle->nxopendata=NX5opendata;
+      fHandle->nxclosedata=NX5closedata;
+      fHandle->nxputdata=NX5putdata;
+      fHandle->nxputattr=NX5putattr;
+      fHandle->nxputslab64=NX5putslab64;    
+      fHandle->nxgetdataID=NX5getdataID;
+      fHandle->nxmakelink=NX5makelink;
+      fHandle->nxmakenamedlink=NX5makenamedlink;
+      fHandle->nxgetdata=NX5getdata;
+      fHandle->nxgetinfo64=NX5getinfo64;
+      fHandle->nxgetnextentry=NX5getnextentry;
+      fHandle->nxgetslab64=NX5getslab64;
+      fHandle->nxgetnextattr=NX5getnextattr;
+      fHandle->nxgetattr=NX5getattr;
+      fHandle->nxgetattrinfo=NX5getattrinfo;
+      fHandle->nxgetgroupID=NX5getgroupID;
+      fHandle->nxgetgroupinfo=NX5getgroupinfo;
+      fHandle->nxsameID=NX5sameID;
+      fHandle->nxinitgroupdir=NX5initgroupdir;
+      fHandle->nxinitattrdir=NX5initattrdir;
+      fHandle->nxprintlink=NX5printlink;
+      fHandle->nxnativeexternallink=NX5nativeexternallink;
+      fHandle->nxnativeinquirefile=NX5nativeinquirefile;
+      fHandle->nxnativeisexternallink=NX5nativeisexternallink;
+}
+
+#endif /* HDF5 */
diff --git a/src/napi_exports.c b/src/napi_exports.c
new file mode 100644
index 0000000..c4dcaed
--- /dev/null
+++ b/src/napi_exports.c
@@ -0,0 +1,19 @@
+/*
+ * $Id$
+ *
+ *  __stdcall uppercase aliases for Windows
+ */
+
+#include "napi.h"
+
+#define CALL_MODE	__stdcall
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "napi_exports.h"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/src/napi_exports.h b/src/napi_exports.h
new file mode 100644
index 0000000..a8df8c2
--- /dev/null
+++ b/src/napi_exports.h
@@ -0,0 +1,263 @@
+/*
+ * code for napi_exports.c
+ */
+
+NXstatus CALL_MODE NXISETCACHE(long newVal)
+{
+    return NXsetcache(newVal);
+}
+
+/*
+void CALL_MODE NXNXNXREPORTERROR(void *pData, char *string)
+{
+    NXNXNXReportError(pData, string);
+}
+*/
+     
+NXstatus CALL_MODE NXIOPEN(CONSTCHAR *filename, NXaccess am, NXhandle *gHandle)
+{
+    return NXopen(filename, am, gHandle);
+}
+
+NXstatus CALL_MODE NXICLOSE(NXhandle *fid)
+{
+    return NXclose(fid);
+}
+
+NXstatus CALL_MODE NXIFLUSH(NXhandle* pHandle)
+{
+    return NXflush(pHandle);
+}
+
+NXstatus CALL_MODE NXIMAKEGROUP(NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass)
+{
+    return NXmakegroup(handle, name, NXclass);
+}
+
+NXstatus CALL_MODE NXIOPENGROUP(NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass)
+{
+    return NXopengroup(handle, name, NXclass);
+}
+
+NXstatus CALL_MODE NXIOPENPATH(NXhandle handle, CONSTCHAR *path)
+{
+    return NXopenpath(handle, path);
+}
+
+NXstatus CALL_MODE NXIOPENGROUPPATH (NXhandle handle, CONSTCHAR *path)
+{
+    return NXopengrouppath(handle, path);
+}
+
+NXstatus CALL_MODE NXICLOSEGROUP(NXhandle handle)
+{
+    return NXclosegroup(handle);
+}
+  
+NXstatus CALL_MODE NXIMAKEDATA (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[])
+{
+    return NXmakedata (handle, label, datatype, rank, dim);
+}
+
+NXstatus CALL_MODE NXICOMPMAKEDATA (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[], int comp_typ, int bufsize[])
+{
+    return NXcompmakedata (handle, label, datatype, rank, dim, comp_typ, bufsize);
+}
+
+NXstatus CALL_MODE NXICOMPRESS (NXhandle handle, int compr_type)
+{
+    return NXcompress (handle, compr_type);
+}
+
+NXstatus CALL_MODE NXIOPENDATA (NXhandle handle, CONSTCHAR* label)
+{
+    return NXopendata (handle, label);
+}
+
+NXstatus CALL_MODE NXICLOSEDATA(NXhandle handle)
+{
+    return NXclosedata(handle);
+}
+
+NXstatus CALL_MODE NXIPUTDATA(NXhandle handle, void* data)
+{
+    return NXputdata(handle, data);
+}
+
+NXstatus CALL_MODE NXIPUTATTR(NXhandle handle, CONSTCHAR* name, void* data, int iDataLen, int iType)
+{
+    return NXputattr(handle, name, data, iDataLen, iType);
+}
+
+NXstatus CALL_MODE NXIPUTSLAB(NXhandle handle, void* data, int start[], int size[])
+{
+    return NXputslab(handle, data, start, size);
+}
+
+NXstatus CALL_MODE NXIGETDATAID(NXhandle handle, NXlink* pLink)
+{
+    return NXgetdataID(handle, pLink);
+}
+
+NXstatus CALL_MODE NXIMAKELINK(NXhandle handle, NXlink* pLink)
+{
+    return NXmakelink(handle, pLink);
+}
+
+NXstatus CALL_MODE NXIOPENSOURCEGROUP(NXhandle handle)
+{
+    return NXopensourcegroup(handle);
+}
+
+NXstatus CALL_MODE NXIGETDATA(NXhandle handle, void* data)
+{
+    return NXgetdata(handle, data);
+}
+
+NXstatus CALL_MODE NXIGETINFO(NXhandle handle, int* rank, int dimension[], int* datatype)
+{
+    return NXgetinfo(handle, rank, dimension, datatype);
+}
+
+NXstatus CALL_MODE NXIGETNEXTENTRY(NXhandle handle, NXname name, NXname nxclass, int* datatype)
+{
+    return NXgetnextentry(handle, name, nxclass, datatype);
+}
+
+NXstatus CALL_MODE NXIGETSLAB(NXhandle handle, void* data, int start[], int size[])
+{
+    return NXgetslab(handle, data, start, size);
+}
+
+NXstatus CALL_MODE NXIGETNEXTATTR(NXhandle handle, NXname pName, int *iLength, int *iType)
+{
+    return NXgetnextattr(handle, pName, iLength, iType);
+}
+
+NXstatus CALL_MODE NXIGETATTR(NXhandle handle, char* name, void* data, int* iDataLen, int* iType)
+{
+    return NXgetattr(handle, name, data, iDataLen, iType);
+}
+
+NXstatus CALL_MODE NXIGETATTRINFO(NXhandle handle, int* no_items)
+{
+    return NXgetattrinfo(handle, no_items);
+}
+
+NXstatus CALL_MODE NXIGETGROUPID(NXhandle handle, NXlink* pLink)
+{
+    return NXgetgroupID(handle, pLink);
+}
+
+NXstatus CALL_MODE NXIGETGROUPINFO(NXhandle handle, int* no_items, NXname name, NXname nxclass)
+{
+    return NXgetgroupinfo(handle, no_items, name, nxclass);
+}
+
+NXstatus CALL_MODE NXISAMEID(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID)
+{
+    return NXsameID(handle, pFirstID, pSecondID);
+}
+
+NXstatus CALL_MODE NXIINITGROUPDIR(NXhandle handle)
+{
+    return  NXinitgroupdir(handle);
+}
+NXstatus CALL_MODE NXIINITATTRDIR(NXhandle handle)
+{
+    return  NXinitattrdir(handle);
+}
+NXstatus CALL_MODE NXISETNUMBERFORMAT(NXhandle handle, int type, char *format)
+{
+    return  NXsetnumberformat(handle,type, format);
+}
+
+NXstatus CALL_MODE NXIMALLOC(void** data, int rank, int dimensions[], int datatype)
+{
+    return NXmalloc(data, rank, dimensions, datatype);
+}
+
+NXstatus CALL_MODE NXIFREE(void** data)
+{
+    return NXfree(data);
+}
+
+#if 0
+/*-----------------------------------------------------------------------
+    NAPI internals 
+------------------------------------------------------------------------*/
+extern  void  NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text));
+extern void (*NXIReportError)(void *pData,char *text);
+extern void *NXpData;
+extern char *NXIformatNeXusTime();
+#endif
+
+/* FORTRAN internals */
+
+NXstatus CALL_MODE NXIFOPEN(char * filename, NXaccess* am, 
+					NexusFunction* pHandle)
+{
+    return NXfopen(filename, am, pHandle);
+}
+
+NXstatus CALL_MODE NXIFCLOSE (NexusFunction* pHandle)
+{
+  return  NXfclose (pHandle);
+}
+
+NXstatus CALL_MODE NXIFPUTATTR(NXhandle fid, char *name, void *data, 
+                                   int *pDatalen, int *pIType)
+{
+  return  NXfputattr(fid, name, data, pDatalen, pIType);
+}
+
+NXstatus CALL_MODE NXIFCOMPRESS(NXhandle fid, int *compr_type)
+{
+  return  NXfcompress(fid, compr_type);
+}
+
+NXstatus CALL_MODE NXIFCOMPMAKEDATA(NXhandle fid, char *name, 
+                int *pDatatype,
+		int *pRank, int dimensions[],
+                int *compression_type, int chunk[])
+{
+  return  NXfcompmakedata(fid, name, pDatatype, pRank, dimensions,
+                compression_type, chunk);
+}
+
+NXstatus CALL_MODE NXIFMAKEDATA(NXhandle fid, char *name, int *pDatatype,
+		int *pRank, int dimensions[])
+{
+  return  NXfmakedata(fid, name, pDatatype, pRank, dimensions);
+}
+
+NXstatus CALL_MODE NXIFFLUSH(NexusFunction* pHandle)
+{
+  return NXfflush(pHandle);
+}
+
+NXstatus CALL_MODE NXIINQUIREFILE(NXhandle handle, char *filename, int filenameBufferLength)
+{
+    return NXinquirefile(handle, filename, filenameBufferLength);
+}
+
+NXstatus CALL_MODE NXIISEXTERNALGROUP(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, char *url, int urlLen)
+{
+    return NXisexternalgroup(fid, name, nxclass, url, urlLen);
+}
+
+NXstatus CALL_MODE NXILINKEXTERNAL(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, CONSTCHAR *url)
+{
+    return NXlinkexternal(fid, name, nxclass, url);
+}
+
+NXstatus CALL_MODE NXIMAKENAMEDLINK(NXhandle fid, CONSTCHAR *newname, NXlink* pLink)
+{
+    return NXmakenamedlink(fid, newname, pLink);
+}
+
+NXstatus CALL_MODE NXIGETRAWINFO(NXhandle handle, int* rank, int dimension[], int* datatype)
+{
+    return NXgetrawinfo(handle, rank, dimension, datatype);
+}
+
diff --git a/src/napi_exports2.c b/src/napi_exports2.c
new file mode 100644
index 0000000..bbeb220
--- /dev/null
+++ b/src/napi_exports2.c
@@ -0,0 +1,20 @@
+/*
+ * $Id$
+ *
+ *  __cdecl uppercase aliases for Windows
+ */
+
+#include "napi.h"
+
+#define CALL_MODE	__cdecl
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "napi_exports.h"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
diff --git a/src/napiu.c b/src/napiu.c
new file mode 100644
index 0000000..5189d76
--- /dev/null
+++ b/src/napiu.c
@@ -0,0 +1,159 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  NeXus Utility (NXU) Application Program Interface Header File
+  
+  Copyright (C) 2005 Freddie Akeroyd
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexus.anl.gov/>
+  
+  $Id$
+
+ ----------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include "napiu.h"
+
+#define DO_GLOBAL(__name) \
+	if (__name != NULL) \
+	{ \
+		if (NXputattr(file_id, #__name, (char*)__name, (int)strlen(__name), NX_CHAR) != NX_OK) \
+		{ \
+			return NX_ERROR; \
+		} \
+	}
+
+ NXstatus  NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* telephone_number, const char* fax_number, const char* email)
+ {
+	DO_GLOBAL(user);
+	DO_GLOBAL(affiliation);
+	DO_GLOBAL(address);
+	DO_GLOBAL(telephone_number);
+	DO_GLOBAL(fax_number);
+	DO_GLOBAL(email);
+	return NX_OK;
+ }
+
+ /* NXUwritegroup creates and leaves open a group */
+ NXstatus  NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class)
+ {
+	   int status;
+	   status = NXmakegroup(file_id, group_name, group_class);
+	   if (status == NX_OK)
+	   {
+		   status = NXopengroup(file_id, group_name, group_class);
+	   }
+	 return status;
+ }
+
+ NXstatus  NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[])
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[])
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units)
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units)
+ {
+	 return NX_OK;
+ }
+
+static int NXcompress_type = 0;
+static int NXcompress_size = 0;
+
+ /* NXUsetcompress sets the default compression type and minimum size */
+ NXstatus  NXUsetcompress(NXhandle file_id, int comp_type, int comp_size)
+ {
+	 int status;
+     if (comp_type == NX_COMP_LZW || comp_type == NX_COMP_HUF || 
+          comp_type == NX_COMP_RLE || comp_type == NX_COMP_NONE)
+	 {
+         NXcompress_type = comp_type;
+         if (comp_size != 0)
+		 {
+			 NXcompress_size = comp_size;
+		 }
+         status = NX_OK;
+	 }
+	 else
+	 {
+		 NXReportError( "Invalid compression option");
+         status = NX_ERROR;
+	 }
+	 return status;
+ }
+
+	/* !NXUfindgroup finds if a NeXus group of the specified name exists */
+ NXstatus  NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class)
+ {
+	int status, n;
+	NXname vname, vclass;
+      status = NXgetgroupinfo(file_id, &n, vname, vclass);
+      if (status != NX_OK)
+	  {
+		  return status;
+	  }
+	 return NX_OK;
+ }
+
+ NXstatus  NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index)
+ {
+	 return NX_OK;
+ }
+
+/* NXUfinddata finds if a NeXus data item is in the current group */
+ NXstatus  NXUfinddata(NXhandle file_id, const char* data_name)
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUfindattr(NXhandle file_id, const char* attr_name)
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[])
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[])
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class)
+ {
+	 return NX_OK;
+ }
+
+ NXstatus  NXUresumelink(NXhandle file_id, NXlink group_id)
+ {
+	 return NX_OK;
+ }
+
diff --git a/src/nexus_symbols.txt b/src/nexus_symbols.txt
new file mode 100644
index 0000000..898307f
--- /dev/null
+++ b/src/nexus_symbols.txt
@@ -0,0 +1,83 @@
+nxiclose_
+nxiclosedata_
+nxiclosegroup_
+nxicompmakedata_
+nxicompmakedata64_
+nxicompress_
+nxifclose_
+nxifcompmakedata_
+nxifcompress_
+nxifflush_
+nxiflush_
+nxifmakedata_
+nxifopen_
+nxifputattr_
+nxifree_
+nxifgetpath_
+nxigetattr_
+nxigetattrinfo_
+nxigetdata_
+nxigetdataid_
+nxigetgroupid_
+nxigetgroupinfo_
+nxigetinfo_
+nxigetinfo64_
+nxigetnextattr_
+nxigetnextentry_
+nxigetslab_
+nxigetslab64_
+nxiinitattrdir_
+nxiinitgroupdir_
+nximakedata_
+nximakedata64_
+nximakegroup_
+nximakelink_
+nximalloc_
+nximalloc64_
+nxiopen_
+nxiopendata_
+nxiopengroup_
+nxiopengrouppath_
+nxiopenpath_
+nxigetpath_
+nxiopensourcegroup_
+nxiputattr_
+nxiputdata_
+nxiputslab_
+nxiputslab64_
+nxisameid_
+nxisetcache_
+nxisetnumberformat_
+nxilinkexternal_
+nxiinquirefile_
+nxiisexternalgroup_
+nxiisexternaldataset_
+NXMSetError
+NXMSetTError
+NXReportError
+NXIReportError
+NXIprintlink
+nxiinquirefile_
+nxilinkexternal_
+nxilinkexternaldataset_
+nxiisexternalgroup_
+NXMGetError
+NXMDisableErrorReporting
+NXMEnableErrorReporting
+nximakenamedlink_
+createNXDataset
+createTextNXDataset
+dropNXDataset
+getNXDatasetByteLength
+getNXDatasetDim
+getNXDatasetLength
+getNXDatasetRank
+getNXDatasetText
+getNXDatasetType
+getNXDatasetValue
+getNXDatasetValueAt
+putNXDatasetValue
+putNXDatasetValueAt
+nxigetrawinfo_
+nxigetrawinfo64_
+nxireopen_
diff --git a/src/nexus_symbols_win.txt b/src/nexus_symbols_win.txt
new file mode 100755
index 0000000..d6682f0
--- /dev/null
+++ b/src/nexus_symbols_win.txt
@@ -0,0 +1,44 @@
+NXICLOSE at 4
+NXICLOSEDATA at 4
+NXICLOSEGROUP at 4
+NXICOMPMAKEDATA at 28
+NXICOMPRESS at 8
+NXIFCLOSE at 4
+NXIFCOMPMAKEDATA at 28
+NXIFCOMPRESS at 8
+NXIFFLUSH at 4
+NXIFLUSH at 4
+NXIFMAKEDATA at 20
+NXIFOPEN at 12
+NXIFPUTATTR at 20
+NXIFREE at 4
+NXIGETATTR at 20
+NXIGETATTRINFO at 8
+NXIGETDATA at 8
+NXIGETDATAID at 8
+NXIGETGROUPID at 8
+NXIGETGROUPINFO at 16
+NXIGETINFO at 16
+NXIGETNEXTATTR at 16
+NXIGETNEXTENTRY at 16
+NXIGETRAWINFO at 16
+NXIGETSLAB at 16
+NXIINITATTRDIR at 4
+NXIINITGROUPDIR at 4
+NXIMAKEDATA at 20
+NXIMAKEGROUP at 12
+NXIMAKELINK at 8
+NXIMALLOC at 16
+NXIOPEN at 12
+NXIOPENDATA at 8
+NXIOPENGROUP at 12
+NXIOPENGROUPPATH at 8
+NXIOPENPATH at 8
+NXIOPENSOURCEGROUP at 4
+NXIPUTATTR at 20
+NXIPUTDATA at 8
+NXIPUTSLAB at 16
+NXISAMEID at 12
+NXISETCACHE at 4
+NXISETNUMBERFORMAT at 12
+NXIMAKENAMEDLINK at 12
diff --git a/src/nx_stptok.h b/src/nx_stptok.h
new file mode 100644
index 0000000..2f75e1e
--- /dev/null
+++ b/src/nx_stptok.h
@@ -0,0 +1,6 @@
+#ifndef NX_STPTOK
+#define NX_STPTOK
+
+extern char *stptok(const char *s, char *tok, size_t toklen, char *brk);
+
+#endif /* NX_STPTOK */
diff --git a/src/nxdataset.c b/src/nxdataset.c
new file mode 100644
index 0000000..2ad0a8f
--- /dev/null
+++ b/src/nxdataset.c
@@ -0,0 +1,313 @@
+/*
+  This is a module which implements the notion of a dataset. Its is
+  designed for the use with scripting languages.
+  
+  copyright: GPL
+
+  Mark Koennecke, October 2002
+*/
+#include <stdlib.h>
+#include <string.h>
+#include "nxdataset.h"
+
+/*-----------------------------------------------------------------------*/
+static int getTypeSize(int typecode){
+  switch(typecode){
+  case NX_FLOAT32:
+  case NX_INT32:
+  case NX_UINT32:
+    return 4;
+    break;
+  case NX_FLOAT64:
+  case NX_INT64:
+  case NX_UINT64:
+    return 8;
+    break;
+  case NX_INT16:
+  case NX_UINT16:
+    return 2;
+    break;
+  default:
+    return 1;
+    break;
+  }
+}
+/*-----------------------------------------------------------------------*/
+pNXDS createNXDataset(int rank, int typecode, int64_t dim[]){
+  pNXDS pNew = NULL;
+  int64_t length;
+  int i;
+
+  pNew = (pNXDS)malloc(sizeof(NXDS));
+  if(pNew == NULL){
+    return NULL;
+  }
+
+  pNew->dim = (int64_t *)malloc(rank*sizeof(int64_t));
+  for(i = 0, length = 1; i < rank; i++){
+    length *= dim[i];
+  }
+  /* add +1 in case of string NULL termination */
+  pNew->u.ptr = malloc((size_t)length*getTypeSize(typecode)+1);
+
+  if(pNew->dim == NULL || pNew->u.ptr == NULL){
+    free(pNew);
+    return NULL;
+  }
+  pNew->rank = rank;
+  pNew->type = typecode;
+  pNew->format = NULL;
+  for(i = 0; i < rank; i++){
+    pNew->dim[i] = dim[i];
+  }
+  pNew->magic = MAGIC;
+  /* add +1 in case of string NULL termination  - see above */
+  memset(pNew->u.ptr,0,(size_t)length*getTypeSize(typecode)+1);
+  return pNew;
+}
+/*---------------------------------------------------------------------*/
+pNXDS createTextNXDataset(char *name){
+  pNXDS pNew = NULL;
+
+  pNew = (pNXDS)malloc(sizeof(NXDS));
+  if(pNew == NULL){
+    return NULL;
+  }
+  pNew->dim = (int64_t *)malloc(sizeof(int64_t));
+  pNew->u.cPtr = strdup(name);
+  if(pNew->dim == NULL || pNew->u.ptr == NULL){
+    free(pNew);
+    return NULL;
+  }
+  pNew->rank = 1;
+  pNew->type = NX_CHAR;
+  pNew->magic = MAGIC;
+  pNew->dim[0] = strlen(name);
+  return pNew;
+}
+/*-----------------------------------------------------------------------*/
+void  dropNXDataset(pNXDS dataset){
+  if(dataset == NULL){
+    return;
+  }
+  if(dataset->magic != MAGIC){
+    return;
+  }
+  if(dataset->dim != NULL){
+    free(dataset->dim);
+  }
+  if(dataset->u.ptr != NULL){
+    free(dataset->u.ptr);
+  }
+  if(dataset->format != NULL){
+    free(dataset->format);
+  }
+  free(dataset);
+}
+/*-----------------------------------------------------------------------*/
+int   getNXDatasetRank(pNXDS dataset){
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+  return dataset->rank;
+}
+/*-----------------------------------------------------------------------*/
+int   getNXDatasetDim(pNXDS dataset, int which){
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+  if(which < 0 || which >= dataset->rank){
+    return 0;
+  }
+  return (int)dataset->dim[which];
+}
+/*------------------------------------------------------------------------*/
+int   getNXDatasetType(pNXDS dataset){
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+  return dataset->type;
+}
+/*--------------------------------------------------------------------*/
+int getNXDatasetLength(pNXDS dataset){
+  int length, i;
+
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+  length = (int)dataset->dim[0];
+  for(i = 1; i < dataset->rank; i++){
+    length *= (int)dataset->dim[i];
+  }
+  return length;
+}
+/*---------------------------------------------------------------------*/
+int getNXDatasetByteLength(pNXDS dataset){
+  return getNXDatasetLength(dataset)*getTypeSize(dataset->type);
+}
+/*----------------------------------------------------------------------
+  This calculates an arbitray address in C storage order
+  -----------------------------------------------------------------------*/
+static int64_t calculateAddress(pNXDS dataset, int64_t pos[]){
+  int64_t result, mult;
+  int i, j;
+
+  result = pos[dataset->rank - 1];
+  for(i = 0; i < dataset->rank -1; i++){
+    mult = 1;
+    for(j = dataset->rank -1; j > i; j--){
+      mult *= dataset->dim[j];
+    }
+    if(pos[i] < dataset->dim[i] && pos[i] > 0){
+      result += mult*pos[i];
+    }
+  }
+  return result;
+}
+/*-----------------------------------------------------------------------*/
+double getNXDatasetValue(pNXDS dataset, int64_t pos[]){
+  int64_t address;
+ 
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+
+  address = calculateAddress(dataset,pos);
+  return getNXDatasetValueAt(dataset, address);
+}
+/*----------------------------------------------------------------------*/
+double getNXDatasetValueAt(pNXDS dataset, int64_t address){
+  double value;
+
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+
+  switch(dataset->type){
+  case NX_FLOAT64:
+    value = dataset->u.dPtr[address];
+    break;
+  case NX_FLOAT32:
+    value = (double)dataset->u.fPtr[address];
+    break;
+  case NX_INT32:
+  case NX_UINT32:
+    value = (double)dataset->u.iPtr[address];
+    break;
+  case NX_INT64:
+  case NX_UINT64:
+    value = (double)dataset->u.lPtr[address];
+    break;
+  case NX_INT16:
+  case NX_UINT16:
+    value = (double)dataset->u.sPtr[address];
+    break;
+  default:
+    value = (double)dataset->u.cPtr[address];
+    break;
+  }
+  return value;
+}
+/*-----------------------------------------------------------------------*/
+char  *getNXDatasetText(pNXDS dataset){
+  char *resultBuffer = NULL;
+  int status = 1;
+
+  if(dataset == NULL){
+    return strdup("NULL");
+  }
+  if(dataset->magic != MAGIC){
+    return strdup("NULL");
+  }
+  if(dataset->rank > 1){
+    status = 0;
+  } 
+  if(dataset->type == NX_FLOAT32 ||
+     dataset->type == NX_FLOAT64 ||
+     dataset->type == NX_INT32 ||
+     dataset->type == NX_UINT32 ||
+     dataset->type == NX_INT64 ||
+     dataset->type == NX_UINT64 ||
+     dataset->type == NX_INT16 ||
+     dataset->type == NX_UINT16 ) {
+    status = 0;
+  }
+
+  if(status == 0){
+    return strdup("NO type problem");
+  }else{
+    resultBuffer = (char *)malloc(((size_t)dataset->dim[0]+10)*sizeof(char));
+    if(resultBuffer == NULL){
+      return strdup("NO Memory");
+    }
+    memset(resultBuffer,0,((size_t)dataset->dim[0]+10)*sizeof(char));
+    strncpy(resultBuffer,dataset->u.cPtr,(size_t)dataset->dim[0]);
+  }
+  return resultBuffer;
+}
+/*----------------------------------------------------------------------*/
+int   putNXDatasetValue(pNXDS dataset, int64_t pos[], double value){
+  int64_t address;
+
+  if(dataset == NULL){
+    return 0;
+  }
+  if(dataset->magic != MAGIC){
+    return 0;
+  }
+
+  address = calculateAddress(dataset,pos);
+  return putNXDatasetValueAt(dataset,address,value);
+}
+  /*---------------------------------------------------------------------*/
+int putNXDatasetValueAt(pNXDS dataset, int64_t address, double value){
+  /*
+    this code is dangerous, it casts without checking the data range.
+    This may cause trouble in some cases
+  */
+  switch(dataset->type){
+  case NX_FLOAT64:
+    dataset->u.dPtr[address] = value;
+    break;
+  case NX_FLOAT32:
+    dataset->u.fPtr[address] = (float)value;
+    break;
+  case NX_INT32:
+  case NX_UINT32:
+    dataset->u.iPtr[address] = (int)value;
+    break;
+  case NX_INT64:
+  case NX_UINT64:
+    dataset->u.lPtr[address] = (int64_t)value;
+    break;
+  case NX_INT16:
+  case NX_UINT16:
+    dataset->u.sPtr[address] = (short int)value;
+    break;
+  default:
+    dataset->u.cPtr[address] = (char)value;
+    break;
+  }
+  return 1;
+}
+
+
+
diff --git a/src/nxdataset.h b/src/nxdataset.h
new file mode 100644
index 0000000..b7a3509
--- /dev/null
+++ b/src/nxdataset.h
@@ -0,0 +1,74 @@
+/*
+  This is a module which implements the notion of a dataset. Its is
+  designed for the use with scripting languages.
+  
+  copyright: GPL
+
+  Mark Koennecke, October 2002
+*/
+#ifndef NXDATASET
+#define NXDATASET
+
+
+#define MAGIC 7776622 
+
+#include "napiconfig.h"
+
+typedef struct {
+                   int magic;
+                   int rank;
+                   int type;
+                   int64_t *dim;
+                   char *format;
+                   union {
+		     void *ptr;
+		     float *fPtr;
+		     double *dPtr;
+		     int    *iPtr;
+		     short int   *sPtr;
+		     char   *cPtr;
+                     int64_t *lPtr;
+		   } u;
+}*pNXDS, NXDS;
+
+/*
+  include NeXus type codes if not already defined
+*/
+#ifndef NX_FLOAT32
+
+#define NX_FLOAT32   5
+#define NX_FLOAT64   6
+#define NX_INT8     20  
+#define NX_UINT8    21
+#define NX_INT16    22  
+#define NX_UINT16   23
+#define NX_INT32    24
+#define NX_UINT32   25
+#define NX_INT64    26
+#define NX_UINT64   27
+#define NX_CHAR      4
+
+#define NX_MAXRANK 32
+
+#endif
+
+
+pNXDS createNXDataset(int rank, int typecode, int64_t dim[]);
+pNXDS createTextNXDataset(char *name);
+
+void  dropNXDataset(pNXDS dataset);
+
+int   getNXDatasetRank(pNXDS dataset);
+int   getNXDatasetDim(pNXDS dataset, int which);
+int   getNXDatasetType(pNXDS dataset);
+int   getNXDatasetLength(pNXDS dataset);
+int   getNXDatasetByteLength(pNXDS dataset);
+
+double getNXDatasetValue(pNXDS dataset, int64_t pos[]);
+double getNXDatasetValueAt(pNXDS dataset, int64_t address);
+char  *getNXDatasetText(pNXDS dataset);
+
+int   putNXDatasetValue(pNXDS dataset, int64_t pos[], double value);
+int   putNXDatasetValueAt(pNXDS dataset, int64_t address, double value);
+
+#endif
diff --git a/src/nxdict/Makefile.nxdict b/src/nxdict/Makefile.nxdict
new file mode 100644
index 0000000..d156afe
--- /dev/null
+++ b/src/nxdict/Makefile.nxdict
@@ -0,0 +1,21 @@
+#--------------------------------------------------------------------------
+# Makefile for the test program for NXDICT
+# copyleft: Mark Koennecke, August 1997
+#------------------------------------------------------------------------ 
+
+OBJ= nxdict.o dict.o stringdict.o lld.o dynstring.o
+
+
+CFLAGS= -I../../include -I/afs/psi.ch/project/sinq/tru64/include -I. -g -c
+LFLAG=  -L../ -L/afs/psi.ch/project/sinq/tru64/lib \
+       -lhdf5  -lmfhdf -ldf -ljpeg -lz -lm -lc
+.c.o:
+	cc $(CFLAGS) $*.c
+
+
+dict: $(OBJ) 
+	cc -g -non_shared -o dict $(OBJ) ../napi.o ../napi4.o ../napi5.o $(LFLAG)
+
+clean:
+	rm *.o
+	rm dict
diff --git a/src/nxdict/README.nxdict b/src/nxdict/README.nxdict
new file mode 100644
index 0000000..e4a80e2
--- /dev/null
+++ b/src/nxdict/README.nxdict
@@ -0,0 +1,37 @@
+
+     High,
+
+     these are the files for the nxdict-API. You need:
+     - nxdict.*     : nuweb sources, .c and .h files for the API itself.
+     - stringdict.* : a list based string dictionary used for implementing
+                      nxdict.
+     - dymstring.*  : a dynamically resizing string
+     - lld.*        : a PD linked list package from somebody else. All
+                      credits to A. Reitsma, Delft.
+     - dict.c       : a test/ example program.
+     - test.dict    : a test dictionary.
+     - nxdictus.tex : API user documentation, derived from nxdict.tex,
+                      which is the full doc including implementation
+                      details.
+     - Makefile.nxdict : a DigitalUnix Makefile for nxdict.
+
+     Of course you need the napi-files.
+
+     At the time of writing (October,3, 1997) a tiny change in napi.c is
+     necessary to make this work:
+
+     line 82 of napi.c:
+       remove the keyword static from the definitons of NXpData and
+       NXIReportError. This is necessary as NXDICT uses the same error
+       reporting mechanism as the napi itself.
+
+     Consider this early beta. It works for me, though.
+
+     I somebody cares to debug my code or improve on my english, 
+     please edit nxdict.w. 
+
+				Mark Koennecke
+
+				Mark.Koennecke at psi.ch
+ 
+      
\ No newline at end of file
diff --git a/src/nxdict/defines.h b/src/nxdict/defines.h
new file mode 100644
index 0000000..f486e1e
--- /dev/null
+++ b/src/nxdict/defines.h
@@ -0,0 +1,18 @@
+/*  ======================================================================
+    DEFINES.h       Standard definitions etc.
+                    For simplification or for debugging substitution.
+
+                    v1.02  94-08-11  Stripped version.
+
+ _____              This version is Public Domain.
+ /_|__|             A.Reitsma, Delft, Nederland.
+/  | \  --------------------------------------------------------------- */
+
+#include <stdlib.h>         /* for malloc() prototype */
+#include <string.h>         /* for memcpy() prototype */
+
+#define MALLOC(size,type)   (type *) malloc( (size) * sizeof( type ))
+#define FREE(mem)           free( mem )
+#define CALLOC(size,type)   (type *) calloc( (size), sizeof( type))
+
+/*  === DEFINES.h end ================================================= */
diff --git a/src/nxdict/dict.c b/src/nxdict/dict.c
new file mode 100644
index 0000000..c3c63e8
--- /dev/null
+++ b/src/nxdict/dict.c
@@ -0,0 +1,81 @@
+
+/*--------------------------------------------------------------------------
+                               D I C T 
+
+ This file exercises some of the NXDICT functionality for test purposes.
+ It can also serve as an example for the usage of the API.
+
+ Mark Koennecke, August 1997
+  
+ Upgraded to support file idetification and text replacement
+
+ Mark Koennecke, April 1998
+----------------------------------------------------------------------------*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <mfhdf.h>
+#include "dynstring.h"
+#include "napi.h"
+#include "nxdict.h"
+
+   int main(int argc, char *argv[])
+   {
+      NXdict pDict = NULL;
+      NXhandle hfil;
+      void *pData = NULL;
+      float fTina[3] = { 0.123, 0.234, 0.456};
+      float fTest[3], fDelta;
+      float fTust[20*20];
+      char pBuffer[256];
+      int i;
+
+      /* test nxdict */
+      NXDinitfromfile("test.dict",&pDict);
+      NXopen("test.hdf",NXACC_CREATE,&hfil);
+      NXDadd(pDict,"Gundula",
+            "/entry1,NXentry/SphereOmeter,NXinstrument/SDS");
+      NXDupdate(pDict,"Bea","/entry1,NXentry/SDS");
+      NXDget(pDict,"Bea",pBuffer,131);
+      printf("Bea = %s\n",pBuffer);
+      NXDget(pDict,"Linda",pBuffer,254);
+      NXDopendef(hfil,pDict,pBuffer);
+      NXDputalias(hfil,pDict,"Tina",fTina);
+      NXDputalias(hfil,pDict,"Gina",fTina);
+      NXDgetalias(hfil,pDict,"Tina",fTest);
+      NXDgetalias(hfil,pDict,"Gina",fTest);
+      NXDputalias(hfil,pDict,"Linda",fTust);
+      NXDaliaslink(hfil,pDict,"Eva","Linda");
+      NXDclose(pDict,"close.dict");
+      NXclose(&hfil);
+      printf("NXDICT seemed to have worked \n");
+
+      /* test Utility functions */
+      printf(" Proceeding to test of utility functions \n");
+      NXopen("test2.hdf",NXACC_CREATE,&hfil);
+      NXUwriteglobals(hfil,
+                      "test2.hdf",
+                      "Willibald Wuergehals",
+                      "Rue des Martyrs, 26505 Timbuktu, Legoland ",
+                      "+41-56-3102512",
+                      "Nobody at nowhere.edu",
+                      " 755-898767",
+                      "Dingsbums");
+      NXUentergroup(hfil, "TestGroup", "NXtest");
+      NXclosegroup(hfil);
+      NXUentergroup(hfil, "TestGroup", "NXtest");
+
+      i = 120;
+      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
+      NXclosedata(hfil);
+      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
+
+      NXUallocSDS(hfil,&pData);
+      NXUfreeSDS(&pData);
+      NXclose(&hfil);
+      printf("All tests seem to have worked OK,  %s %s\n",
+             "but the test is pathetic\n", 
+             "Do not rely, in any circumstances, on this test alone");
+
+ 
+   }
diff --git a/src/nxdict/dynstring.c b/src/nxdict/dynstring.c
new file mode 100644
index 0000000..aa20e57
--- /dev/null
+++ b/src/nxdict/dynstring.c
@@ -0,0 +1,247 @@
+/*-------------------------------------------------------------------------
+                            D Y N S T R I N G
+                            
+  Implementation file for a dynamic string object.
+  Usage and copyright: see dynstring.h
+  
+  Mark Koennecke, March 1998
+-----------------------------------------------------------------------------*/
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include "dynstring.h"
+
+#define DYNMAGIC 27031998 
+
+/*--------------------------------------------------------------------------*/
+  typedef struct __DynString {
+                               int iMAGIC;                            
+                               char *pBuffer;
+                               int iTextLen;
+                               int iBufferSize;
+                               int iResize;
+                              } DynString;
+/*--------------------------------------------------------------------------*/
+ pDynString CreateDynString(int iInitial, int iResize)
+ {
+   pDynString pNew = NULL;
+   
+   if(iInitial <= 0)
+           iInitial = 512;
+   if(iResize <= 0)
+           iResize = 512;
+           
+   /* new memory */
+   pNew = (pDynString)malloc(sizeof(DynString));
+   if(!pNew)
+   {
+     return NULL;
+   }      
+   memset(pNew,0,sizeof(DynString));
+   pNew->pBuffer = (char *)malloc(iInitial*sizeof(char));
+   if(!pNew->pBuffer)
+   {
+     free(pNew);
+     return NULL;
+   }          
+   memset(pNew->pBuffer,0,iInitial*sizeof(char));
+   
+   /* initialise the rest */
+   pNew->iMAGIC = DYNMAGIC;
+   pNew->iBufferSize = iInitial;
+   pNew->iResize =   iResize;
+   pNew->iTextLen = 0;
+   
+   return pNew;
+ }         
+/*--------------------------------------------------------------------------*/
+ static int Resize(pDynString self, int iRequested)
+ {
+     char *pNewBuffer;
+     int iNewSize;
+     
+     if(iRequested < self->iBufferSize)
+     {
+       return 1;
+     } 
+     
+     /* get new data space */
+     iNewSize = iRequested + self->iResize;
+     pNewBuffer = (char *)malloc(iNewSize *sizeof(char));
+     if(!pNewBuffer)
+     {
+       return 0;
+     }
+     memset(pNewBuffer,0,iNewSize);
+     
+     /* copy data */
+     memcpy(pNewBuffer,self->pBuffer,self->iTextLen);
+     
+     /* swap things around */
+     if(self->pBuffer)
+     {
+        free(self->pBuffer);
+     }
+     self->pBuffer = pNewBuffer;
+     self->iBufferSize = iNewSize;
+     return 1;
+ }  
+/*--------------------------------------------------------------------------*/
+ void DeleteDynString(pDynString self)
+ {
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+    
+    if(self->pBuffer)
+        free(self->pBuffer);
+        
+    free(self);    
+ }  
+/*-------------------------------------------------------------------------*/
+ int DynStringCopy(pDynString self, char *pText)
+ {
+    int iRequested, iRet;
+
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+    
+    iRequested = strlen(pText);
+    if(iRequested >= self->iBufferSize) 
+    {
+       iRet = Resize(self,iRequested);
+       if(!iRet)
+       {
+         return 0;
+       }
+    }
+    else /* safety: remove rubbish */
+    {
+       memset(self->pBuffer,0,self->iBufferSize*sizeof(char));
+    }
+    strcpy(self->pBuffer,pText);
+    self->iTextLen = iRequested;
+    return 1;
+ }           
+/*--------------------------------------------------------------------------*/
+ int DynStringConcat(pDynString self, char *pText)
+ {
+    int iRequested, iRet;
+
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+    
+    iRequested = strlen(pText) + self->iTextLen;
+    if(iRequested >= self->iBufferSize) 
+    {
+       iRet = Resize(self,iRequested);
+       if(!iRet)
+       {
+         return 0;
+       }
+    }
+
+    strcat(self->pBuffer,pText);
+    self->iTextLen = iRequested;
+    return 1;
+ }      
+/*--------------------------------------------------------------------------*/
+ int DynStringConcatChar(pDynString self, char c)
+ {
+    int iRequested, iRet;
+
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+    
+    iRequested = self->iTextLen + 1;
+    if(iRequested >= self->iBufferSize) 
+    {
+       iRet = Resize(self,iRequested);
+       if(!iRet)
+       {
+         return 0;
+       }
+    }
+
+    self->pBuffer[self->iTextLen] = c;
+    self->iTextLen++;
+    return 1;
+ }      
+/*---------------------------------------------------------------------------*/
+ int DynStringInsert(pDynString self, char *pText, int iPos)
+ {
+    int iRequested, iRet, iPush, iRest;
+    char *pPtr;
+
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+    
+    /* provide space */
+    iPush = strlen(pText);
+    iRequested = self->iTextLen + iPush;
+    if(iRequested >= self->iBufferSize) 
+    {
+       iRet = Resize(self,iRequested);
+       if(!iRet)
+       {
+         return 0;
+       }
+    }
+    
+    /* we need a temporary buffer to hold the backend of the string */
+    iRest = self->iTextLen - iPos;
+    pPtr = (char *)malloc((iRest+10)*sizeof(char));
+    if(!pPtr)
+    {
+      return 0;
+    }
+    memset(pPtr,0,(iRest+10)*sizeof(char));
+    strcpy(pPtr,&self->pBuffer[iPos]);
+    
+    /* OK build the result string */
+    memset(&self->pBuffer[iPos],0,iRest*sizeof(char));
+    strcat(self->pBuffer,pText);
+    strcat(self->pBuffer,pPtr);
+    free(pPtr);
+    self->iTextLen = iRequested;
+    return 1;
+ }    
+/*--------------------------------------------------------------------------*/
+ int DynStringReplace(pDynString self, char *pText, int iPos)
+ {
+    int iRequested, iRet;
+
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+    
+    iRequested = strlen(pText) + iPos;
+    if(iRequested >= self->iBufferSize) 
+    {
+       iRet = Resize(self,iRequested);
+       if(!iRet)
+       {
+         return 0;
+       }
+    }
+
+    memcpy(&self->pBuffer[iPos],pText,strlen(pText)*sizeof(char));
+    self->iTextLen = strlen(self->pBuffer);
+    return 1;
+ }
+/*---------------------------------------------------------------------------*/
+ char *GetCharArray(pDynString self)
+ {
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+
+    return self->pBuffer;     
+ } 
+/*---------------------------------------------------------------------------*/
+ int GetDynStringLength(pDynString self)
+ {
+    assert(self);
+    assert(self->iMAGIC == DYNMAGIC);
+
+    return self->iTextLen;     
+ } 
+ 
\ No newline at end of file
diff --git a/src/nxdict/dynstring.h b/src/nxdict/dynstring.h
new file mode 100644
index 0000000..8f1e429
--- /dev/null
+++ b/src/nxdict/dynstring.h
@@ -0,0 +1,89 @@
+/*---------------------------------------------------------------------------
+                           D Y N S T R I N G
+                           
+    A dynamic String Implementation. You can append and insert into this
+    string at will. It automatically takes care of allocating more
+    memory when needed.
+
+    COPYRIGHT:
+              CopyLeft, 1998, Mark Koennecke
+              There are two things you MAY NOT DO with this code:
+              - Sue me or my employer because it does not work.
+              - Use it in a critical environment, i.e health, 
+                radioactive device control, military control
+                systems and the like. 
+              You may do everything else with this code. It has been
+              written with swiss taxpayers money. 
+          
+    NOTE:
+         All functions return 1 or a pointer on success,
+         0, or NULL on failure           
+    
+    Mark Koennecke, March 1998 
+----------------------------------------------------------------------------*/
+#ifndef DYNAMICSTRING
+#define DYNAMICSTRING
+       typedef struct __DynString *pDynString;
+       
+/*----------------------- live and death ----------------------------------*/
+   pDynString CreateDynString(int iInitialLength, int iResizeLength);
+   /*
+     Create a new DynString Object. Its initial length will be iInitialLength.
+     It will be resized in iResizeLength steps. This allows for efficient
+     storage management. It woul be seriously inefficient to allocate
+     per added character.
+   */  
+     
+   void       DeleteDynString(pDynString self);
+/*----------------------- interface to it --------------------------------- */          
+
+   int DynStringCopy(pDynString self, char *pText);
+   
+   /* 
+    Copies the text in Text into the DynString starting at 0 and over
+    writing anything there beforehand.
+   */
+   
+   int DynStringConcat(pDynString self, char *pText);
+   /*
+     Concatenates the string in DynString with the one supplied
+     in string.
+   */
+
+   int DynStringConcatChar(pDynString self, char c);
+   /*
+     adds one character at the end of the string
+   */  
+   
+   int DynStringInsert(pDynString self, char *pText, int iPos);
+   
+   /*
+     inserts the text in pText at Position iPos in the DynString.
+     Everything behind iPos will be pushed outwards in order to create
+     space for pText.
+   */
+
+   int DynStringReplace(pDynString self, char *pText, int iPos);
+   
+   /*
+     Starting at iPos, replace everything after it with ptext. In
+     contrats to insert this won't push data backwards.
+   */
+   
+   char *GetCharArray(pDynString self);
+   
+   /* 
+     retrieves a pointer to the character array keeping the current 
+     text. NEVER, ever free this pointer, otherwise you are rewarded
+     with a core dump. The pointer belongs to DynString and will be
+     deleted when deleting the DynString.
+   */
+   
+   int GetDynStringLength(pDynString self);
+   
+   /*
+     returns the current length of the dynamic string.
+   */  
+          
+#endif    
+                       
\ No newline at end of file
diff --git a/src/nxdict/lld.c b/src/nxdict/lld.c
new file mode 100644
index 0000000..b028bcd
--- /dev/null
+++ b/src/nxdict/lld.c
@@ -0,0 +1,685 @@
+/* =======================================================================
+    LLD.c           Generic Doubly Linked Lists for fixed size data.
+                    Each List has its own specific data size.
+                    This version uses dummy head and dummy tail nodes.
+                    Which prevents special handling for the first and last
+                    nodes.
+
+                    v1.00  94-08-21
+
+                    Compile with NDEBUG not defined for debugging version.
+                    Compile with NDEBUG defined for production version.
+
+                    The node pointers are restricted to valid values.
+                    They point only in empty lists to invalid data.
+
+                    Possible future enhancements:
+                    - List(s) of free nodes for fast node memory alloc.
+                    - FindFirst() & FindNext().
+                    - Data access via first and/or last node pointers.
+                      (duplicate the functions and change .current to
+                      .first or .last)
+                    - Node deletion via first and/or last node pointers.
+                      (as for access functions, then simplify ...)
+
+ _____              This version is Public Domain.
+ /_|__|             A.Reitsma, Delft, The Netherlands.
+/  | \  --------------------------------------------------------------- */
+
+#include <stdarg.h>         /* variable arg handling */
+#include <assert.h>         /* debugging */
+#include "defines.h"        /* debugging incl MALLOC (re-) definition   */
+#include "lld.h"            /* also includes portable.h if necessary    */
+
+#define NO_PROBLEMS LIST_NO_PROBLEMS /* local redefinition */
+
+struct Node
+{
+    struct Node * next;
+    struct Node * prev;
+    int data;               /* also place-holder for larger items.      */
+};                          /* actual nodes have various sizes,         */
+                            /* but a fixed size within a list.          */
+struct ListHead
+{
+    struct Node * current;  /* points to the actual current node        */
+    struct Node * first;    /* always points to dummy head node         */
+    struct Node * last;     /* always points to dummy tail node         */
+    int itemsize ;          /* zero value: used as 'list not used' flag */
+};
+
+#define ERR_MEMORY          -1
+
+#define NODE_MALLOC(list)   (struct Node *) \
+                            MALLOC( ListControl[ list ].itemsize \
+                                    + 2 * sizeof( struct Node * )\
+                                    + sizeof(int), char )
+
+#define NODE_FREE(node)     FREE(node)
+
+/* ---- Local data ---------------------------------------------------- */
+
+static struct ListHead * ListControl = NULL;
+static unsigned int ListCount = 0;
+
+/* ---- LL system mangement ------------------------------------------- */
+
+static int ListInit( int List, int ItemSize )
+{
+    struct Node * Tmp ;
+
+    if( 0 != ItemSize )
+    {
+        /* create dummy head node
+        */
+        Tmp = NODE_MALLOC( List );
+        if( NULL == Tmp )
+        {
+            return ERR_MEMORY ;
+        }
+        Tmp->prev = NULL ;     /* NULL identifies it as dummy head node */
+        Tmp->data = 0xA709 ;   /* dummy value */
+        ListControl[ List ].first = Tmp ;
+
+        /* create dummy tail node
+        */
+        Tmp = NODE_MALLOC( List );
+        if( NULL == Tmp )
+        {
+            NODE_FREE( Tmp );          /* no need to cause memory leaks */
+            ListControl[ List ].first = NULL ; /* or other errors       */
+            return ERR_MEMORY ;        /* even if we're in trouble ...  */
+        }
+        Tmp->next = NULL ;     /* NULL identifies it as dummy tail node */
+        Tmp->data = 0xA725 ;   /* dummy value */
+        Tmp->prev = ListControl[ List ].first ;
+
+        ListControl[ List ].current     =
+        ListControl[ List ].last        =
+        ListControl[ List ].first->next = Tmp ;
+    }
+    else
+    {
+        ListControl[ List ].current =
+        ListControl[ List ].first   =
+        ListControl[ List ].last    = NULL ;
+    }
+
+    ListControl[ List ].itemsize = ItemSize ; /* zero: list not used    */
+    return NO_PROBLEMS ;
+}
+
+int LLDsystemInit( int ListCountInit )
+{
+    assert( (unsigned) ( ListCountInit -1 ) <= 20 -1 );
+                 /* negative is logic error (cast => neg. is large int) */
+                 /* higher than 20 is ridiculous for an initial setup   */
+                 /* zero is useless                                     */
+
+    if( NULL != ListControl )
+    {
+        return NO_PROBLEMS ; /* LL system already initialized */
+    }
+
+    ListControl = MALLOC( ListCountInit, struct ListHead );
+    if( NULL == ListControl )
+    {
+        return ERR_MEMORY ;
+    }
+    /* MK */
+    memset(ListControl,0,ListCountInit*sizeof(struct ListHead));
+
+    for( ListCount = 0 ; ListCount < (unsigned)ListCountInit ; ListCount++ )
+        ListInit( ListCount, 0 ); /* just mark it as usable ... */
+
+    /* ListCount is now ListCountInit */
+    assert( ListCount == (unsigned)ListCountInit );
+
+    return NO_PROBLEMS;
+}
+
+int LLDsystemClose(void)
+{
+  if(ListControl)
+  {
+    free(ListControl);
+  }
+  ListControl = NULL;
+  return 1;
+}
+int LLDcreate( int ItemSize )
+{
+    int List ;
+
+    assert( (unsigned) ( ItemSize -1 ) < 1024 -1 ) ;
+                             /* limit to 1kB. A size of 0 is ridiculous */
+
+    /* trigger automatic system initialisation if neccesary
+    */
+    if( NULL == ListControl  &&  0 != LLDsystemInit( 1 ))
+    {
+        return ERR_MEMORY ;
+    }
+
+    /* Look for empty slot
+    */
+    for( List = 0; List < (int)ListCount; List++ )
+    {
+        if( 0 == ListControl[ List ].itemsize )
+            break;
+    }
+
+    /*  What if NO EMPTY slot ???
+    */
+    if( List == (int)ListCount )
+    {
+        struct ListHead * tmp ;         /* ListControl expansion needed */
+
+        tmp = MALLOC( ListCount + 1, struct ListHead );
+        if( NULL == tmp )
+        {
+            return ERR_MEMORY ;
+        }
+        /* MK */
+        memset(tmp,0,(ListCount+1)*sizeof(struct ListHead));
+        
+        memcpy( tmp, ListControl, ListCount * sizeof( struct ListHead ));
+        /* MK */
+        free(ListControl);
+        ListControl = tmp ;
+        ListCount++ ;
+    }
+
+    /* create dummy head node and set up ListControl for the list.
+    */
+    if( ERR_MEMORY == ListInit( List, ItemSize ))
+    {
+        return ERR_MEMORY ;
+    }
+
+    return List ;
+}
+
+void LLDdelete( int List )
+{
+    struct Node * Tmp ;
+    struct Node * Old ;
+
+    assert( (unsigned) List < ListCount );
+
+    Tmp = ListControl[ List ].first ; /* dummies are also deleted !!!   */
+    while( NULL != Tmp )              /* still assuming last node has   */
+    {                                 /* a NULL next pointer ...        */
+        Old = Tmp ;
+        Tmp = Old->next;
+        NODE_FREE( Old ); /* data already presumed to be deleted */
+    }
+
+    ListInit( List, 0 ); /* 0: mark list as not used. */
+
+    return ;
+}
+
+/* ---- LL system maintenance ----------------------------------------- */
+
+int LLDcheck( int List )
+{
+    if( NULL == ListControl )
+    {
+        return LIST_SYSTEM_NULL ;
+    }
+
+    if( (unsigned) List >= ListCount )
+    {
+        return LIST_INV_NUMBER ;
+    }
+
+    if( 0 == ListControl[ List ].itemsize )
+    {
+        return LIST_NOT_CREATED ;
+    }
+
+    if( NULL == ListControl[ List ].first
+        || NULL == ListControl[ List ].first->next    /* missing tail ? */
+        || NULL != ListControl[ List ].first->prev )
+    {
+        return LIST_ERR_HEAD ;
+    }
+
+    /* Validate current pointer
+    */
+    if( NULL == ListControl[ List ].current )
+    {
+        return LIST_CORRUPT7 ;    /* shouldn't be NULL with a good head */
+    }
+
+    if( NULL != ListControl[ List ].first->next->next ) /* empty list ? */
+    {                                                   /* not empty.   */
+        struct Node * tmp = ListControl[ List ].first ;
+
+        if( NULL == ListControl[ List ].current->next )
+        {
+            return LIST_CORRUPT6 ; /* a NULL next pointer is only valid */
+        }                          /* for an empty list.                */
+
+        /* look for .current in list,
+           checking the .prev links along the way
+        */
+        do
+        {
+            tmp = tmp->next ;
+
+            if( NULL == tmp || NULL == tmp->prev
+                || tmp != tmp->prev->next )
+            {
+                return LIST_CORRUPT5 ;  /* current not found in list */
+            }                           /* or link to/from next node */
+                                        /* invalid                   */
+        }while( tmp != ListControl[ List ].current );
+
+        /* Found .current in list. Also without link errors.
+           Now look for valid last node pointer in the list,
+           checking the .prev links along the way
+           Note that .current itself is never supposed to be equal
+           to .last (which points to the dummy tail) !
+        */
+        if( NULL == ListControl[ List ].last )
+        {
+            return LIST_ERR_LAST ;
+        }
+
+        do
+        {
+            tmp = tmp->next ;
+            if( NULL == tmp || NULL == tmp->prev
+                || tmp != tmp->prev->next )
+            {
+                return LIST_CORRUPT4 ;  /* last not found in list    */
+            }                           /* or link to/from prev node */
+                                        /* invalid                   */
+        }while( tmp != ListControl[ List ].last );
+
+        /* Found .last in list but is it really a valid last pointer?
+           Note: tmp == .last
+        */
+        if( NULL != tmp->next )
+        {
+            return LIST_CORRUPT3 ;
+        }
+
+        return NO_PROBLEMS ;
+    }
+
+    /* .first->next->next == NULL  =>  list is empty
+    */
+    if( ListControl[ List ].current != ListControl[ List ].first->next )
+    {
+        return LIST_CORRUPT2 ;
+    }
+
+    if( ListControl[ List ].last != ListControl[ List ].first->next
+        || ListControl[ List ].last
+                             != ListControl[ List ].current->prev->next )
+    {
+        return LIST_CORRUPT1 ;
+    }
+
+    return LIST_EMPTY ;
+}
+
+/* ---- node management ----------------------------------------------- */
+
+int LLDnodeInsert( int List, ... )      /* insert _BEFORE_ current node */
+{
+    va_list DataPtr ;
+    int Retval ;
+
+    /* set DataPtr to the address of "..."
+       then action, cleanup and return.
+    */
+    va_start( DataPtr, List );
+
+    Retval = LLDnodeInsertFrom( List, (void *)va_arg(DataPtr,void *) );
+
+    va_end( DataPtr );
+    return Retval ;
+}
+
+int LLDnodeAdd( int List, ... )          /* insert _AFTER_ current node */
+{
+    va_list DataPtr ;
+    int Retval ;
+
+    /* set DataPtr to the address of "..."
+       then action, cleanup and return.
+    */
+    va_start( DataPtr, List );
+
+    Retval = LLDnodeAddFrom( List, (void *)va_arg(DataPtr,void *) );
+
+    va_end( DataPtr );
+    return Retval ;
+}
+
+int LLDnodePrepend( int List, ... )             /* insert as first node */
+{
+    va_list DataPtr ;
+    int Retval ;
+
+    /* set DataPtr to the address of "..."
+       then action, cleanup and return.
+    */
+    va_start( DataPtr, List );
+
+    Retval = LLDnodePrependFrom( List, (void *)va_arg(DataPtr,void *) );
+
+    va_end( DataPtr );
+    return Retval ;
+}
+
+int LLDnodeAppend( int List, ... )               /* insert as last node */
+{
+    va_list DataPtr ;
+    int Retval ;
+
+    /* set DataPtr to the address of "..."
+       then action, cleanup and return.
+    */
+    va_start( DataPtr, List );
+
+    Retval = LLDnodeAppendFrom( List, (void *)va_arg(DataPtr,void *) );
+
+    va_end( DataPtr );
+    return Retval ;
+}
+
+int LLDnodeInsertFrom( int List, void * Source )
+{                                       /* insert _BEFORE_ current node */
+    struct Node * New ;
+
+    assert( (unsigned) List < ListCount );
+
+    /* create new node if possible
+    */
+    New = NODE_MALLOC( List );
+    if( NULL == New )
+    {
+        return ERR_MEMORY ;
+    }
+
+    /* fill node with data, link to next and previous nodes
+       and adjust current node pointer
+    */
+    memcpy( & New->data, Source, ListControl[ List ].itemsize );
+    New->next = ListControl[ List ].current;
+    New->prev = ListControl[ List ].current->prev;
+
+    ListControl[ List ].current->prev = New ;
+    New->prev->next = New ;
+
+    ListControl[ List ].current = New ;
+
+    return NO_PROBLEMS;
+}
+
+int LLDnodeAddFrom( int List, void * Source )
+{                                        /* insert _AFTER_ current node */
+    struct Node * New ;
+
+    assert( (unsigned) List < ListCount );
+
+    /* create new node if possible
+    */
+    New = NODE_MALLOC( List );
+    if( NULL == New )
+    {
+        return ERR_MEMORY ;
+    }
+
+    /* fill node with data and link to next and previous nodes
+       with special handling when the current node pointer points
+       to the dummy tail node: i.e it is an empty list.
+       (the same case in a non-empty list is made not to occur.)
+    */
+    memcpy( & New->data, Source, ListControl[ List ].itemsize );
+
+    if( NULL != ListControl[ List ].current->next )
+        ListControl[ List ].current = ListControl[ List ].current->next ;
+
+    New->next = ListControl[ List ].current;
+    New->prev = ListControl[ List ].current->prev;
+
+    ListControl[ List ].current->prev = New ;
+    New->prev->next = New ;
+
+    ListControl[ List ].current = New ;
+
+    return NO_PROBLEMS;
+}
+
+int LLDnodePrependFrom( int List, void * Source )
+{                                               /* insert as first node */
+    struct Node * New ;
+
+    assert( (unsigned) List < ListCount );
+
+    /* create new node if possible
+    */
+    New = NODE_MALLOC( List );
+    if( NULL == New )
+    {
+        return ERR_MEMORY ;
+    }
+
+    /* fill node with data and link to dummy head and actual first nodes
+    */
+    memcpy( & New->data, Source, ListControl[ List ].itemsize );
+    New->prev = ListControl[ List ].first;     /* == .first->next->prev */
+    New->next = ListControl[ List ].first->next;
+
+    ListControl[ List ].first->next = New;
+    New->next->prev = New ;
+
+    /* Prevent .current from pointing at the dummy tail
+       (New is the only normal node...)
+    */
+    if( NULL == ListControl[ List ].current->next )
+        ListControl[ List ].current = New;
+
+    return NO_PROBLEMS;
+}
+
+int LLDnodeAppendFrom( int List, void * Source )
+{                                                /* insert as last node */
+    struct Node * New ;
+
+    assert( (unsigned) List < ListCount );
+
+    /* create new node if possible
+    */
+    New = NODE_MALLOC( List );
+    if( NULL == New )
+    {
+        return ERR_MEMORY ;
+    }
+
+    /* fill node with data and link to dummy tail and actual last nodes
+    */
+    memcpy( & New->data, Source, ListControl[ List ].itemsize );
+    New->next = ListControl[ List ].last ;      /* == .last->prev->next */
+    New->prev = ListControl[ List ].last->prev;
+
+    ListControl[ List ].last->prev = New ;
+    New->prev->next = New ;
+
+    /* Prevent .current from pointing at the dummy tail
+       (New is the only normal node...)
+    */
+    if( NULL == ListControl[ List ].current->next )
+        ListControl[ List ].current = New;
+
+    return NO_PROBLEMS;
+}
+
+void LLDnodeDelete( int List )
+{
+    struct Node * Old = ListControl[ List ].current ;
+
+    assert( (unsigned) List < ListCount );
+
+    if( NULL == ListControl[ List ].current->next )
+    {
+        return ;  /* don't delete dummy tail node (list is empty) */
+    }
+
+    /* adjust links
+    */
+    Old->prev->next = Old->next ;
+    Old->next->prev = Old->prev ;
+
+    /* adjust current node pointer
+       prevent it from pointing to the dummy tail node
+    */
+    if( NULL != Old->next->next )
+        ListControl[ List ].current = Old->next ;
+    else
+        ListControl[ List ].current = Old->prev ;
+
+    NODE_FREE( Old );
+
+    return ;
+}
+
+int LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr )
+{                        /* FindFirst/FindNext format may be needed ... */
+    int RetVal ;
+
+    assert( (unsigned) List < ListCount );
+
+    if( NULL == ListControl[ List ].first->next->next ) /* empty list ? */
+    {
+        return 2; /* a compare usually returns just -1, 0 or 1 !!! */
+    }
+
+    /* note: current->next will never be NULL in a non-empty list */
+
+    if( NULL == Compare ) /* default to memcmp with .itemsize */
+    {
+        while( 0 != (RetVal = memcmp( DataPtr,
+                                      & ListControl[ List ].current->data,
+                                      ListControl[ List ].itemsize ))
+               && NULL != ListControl[ List ].current->next->next )
+        {
+            ListControl[ List ].current=ListControl[ List ].current->next;
+        }
+        return RetVal ;
+    }
+    else
+    {
+        while( 0 != (RetVal = (*Compare)( DataPtr,
+                                   & ListControl[ List ].current->data ))
+               && NULL != ListControl[ List ].current->next->next )
+        {
+            ListControl[ List ].current=ListControl[ List ].current->next;
+        }
+        return RetVal ;
+    }
+}
+
+/* ---- current node pointer management ------------------------------- */
+
+int  LLDnodePtr2First( int List )
+{
+    assert( (unsigned) List < ListCount );
+
+    ListControl[ List ].current = ListControl[ List ].first->next ;
+
+    return NULL != ListControl[ List ].first->next->next ;
+}
+
+int  LLDnodePtr2Last( int List )
+{
+    assert( (unsigned) List < ListCount );
+
+    ListControl[ List ].current = ListControl[ List ].last->prev ;
+
+    return NULL != ListControl[ List ].last->prev->prev ;
+}
+
+int  LLDnodePtr2Next( int List )
+{
+    assert( (unsigned) List < ListCount );
+
+    if( NULL == ListControl[ List ].current->next       /* empty list ? */
+        || NULL == ListControl[ List ].current->next->next ) /* at end ?*/
+    {
+        return 0 ;             /* do not allow the current node pointer */
+    }                          /* to point at the dummy tail node ...   */
+
+    ListControl[ List ].current = ListControl[ List ].current->next ;
+    return 1 ;
+}
+
+int  LLDnodePtr2Prev( int List )
+{
+    assert( (unsigned) List < ListCount );
+
+    if( NULL == ListControl[ List ].current->prev       /* empty list ? */
+        || NULL == ListControl[ List ].current->prev->prev ) /* begin ? */
+    {
+        return 0 ;             /* do not allow the current node pointer */
+    }                          /* to point at the dummy head node ...   */
+
+    ListControl[ List ].current = ListControl[ List ].current->prev ;
+    return 1 ;
+}
+
+/* ---- stored data management ---------------------------------------- */
+
+int LLDnodeInt( int List )
+{
+    return ListControl[ List ].current->data;
+}
+
+long LLDnodeLong( int List )
+{
+    return *((long *) &ListControl[ List ].current->data );
+}
+
+void * LLDnodePtr( int List )
+{
+    return *((void **) &ListControl[ List ].current->data );
+}
+
+void FAR * LLDnodeFptr( int List )
+{
+    return *((void FAR **) &ListControl[ List ].current->data );
+}
+
+int LLDnodeDataTo( int List, void * Destination )
+{
+    if( NULL != Destination )
+    {
+        memcpy( Destination,
+                & ListControl[ List ].current->data,
+                ListControl[ List ].itemsize );
+    }
+
+    return ListControl[ List ].itemsize ;       /* size needed for blob */
+}
+
+/* added: Mark Koennecke, 7.4.1997 */
+int LLDnodeDataFrom( int List, void *source )
+{
+    if( NULL != source )
+    {
+        memcpy(
+                & ListControl[ List ].current->data,
+                source,
+                ListControl[ List ].itemsize );
+    }
+
+    return ListControl[ List ].itemsize ;       /* size needed for blob */
+}
+
+/* ==== LLD.c  end ==================================================== */
diff --git a/src/nxdict/lld.h b/src/nxdict/lld.h
new file mode 100644
index 0000000..1bfffd4
--- /dev/null
+++ b/src/nxdict/lld.h
@@ -0,0 +1,137 @@
+/* =======================================================================
+    LLD.h           Generic Doubly Linked List for fixed size data-items.
+
+                    v1.00  94-08-21
+
+ _____              This version is Public Domain.
+ /_|__|             A.Reitsma, Delft, The Netherlands.
+/  | \  --------------------------------------------------------------- */
+
+#include "defines.h"
+
+#ifndef FAR
+#define FAR
+#endif
+
+#ifndef LL__ERR_H
+#define LL__ERR_H       /* same values used in LLS ...                  */
+
+enum ListErrors         /* return values for LLDcheck()                 */
+{                       /* The highest value is returned                */
+
+    LIST_NO_PROBLEMS,   /* All is OK (multiple use)                     */
+    LIST_EMPTY,         /* No data available                            */
+    LIST_ERRORS,        /* Dummy to separate warnings from              */
+                        /* ---- REAL errors --------------------------- */
+    LIST_CORRUPT1,      /* invalid last node pointer: != first->next    */
+                        /*      (empty list) or link error              */
+    LIST_CORRUPT2,      /* invalid current node pointer: != first->next */
+                        /*      (empty list)                            */
+    LIST_CORRUPT3,      /* invalid last node pointer: Not really last.  */
+    LIST_CORRUPT4,      /* invalid last node pointer: Not in list,      */
+                        /*      or link error after current node        */
+    LIST_ERR_LAST,      /* invalid last node pointer: NULL              */
+    LIST_CORRUPT5,      /* invalid current node pointer: Not in list,   */
+                        /*      or link error before current node       */
+    LIST_CORRUPT6,      /* invalid current->next node pointer: NULL     */
+                        /*      although the list is not empty          */
+    LIST_CORRUPT7,      /* NULL current node pointer                    */
+    LIST_ERR_HEAD,      /* NULL first node pointer                      */
+                        /*      or error in head node                   */
+    LIST_NOT_CREATED,   /* List deleted or not created                  */
+    LIST_INV_NUMBER,    /* List number out of range                     */
+    LIST_SYSTEM_NULL    /* List system not intialized                   */
+};
+
+typedef int (*CompFunPtr)( const void *, const void * );
+                                             /* simplifies declarations */
+#endif
+#ifndef LLD_H
+#define LLD_H
+
+/* ---- LL system management and maintenance -------------------------- */
+int  LLDsystemInit( int ListCount );
+               /* returns -1 on failure. It is not required to call it. */
+               /* A second call does nothing: ListCount is ignored.     */
+
+int  LLDcreate( int ItemSize );
+                        /* returns list number to use or -1 on failure. */
+                        /* MUST be called before using a list.          */
+                        /* Calls LLsystemInit if necessary.             */
+
+void LLDdelete( int List ); /* delete entire list, data is NOT free()'d */
+
+int  LLDcheck( int List ); /* returns enum ListErrors value             */
+                           /* its primary purpose is debugging.         */
+
+int LLDsystemClose(void);
+         /* MK mainly frees memory for the ListControlBlocks */
+/* ---- Node management --------------------------------------------------
+   Functions changing current node pointer to the new node.
+   Each created list has its own -- fixed -- datasize. See LLcreate().
+   An ellipsis "..." indicates the data to insert.
+*/
+int  LLDnodeInsert( int List, ... );      /* insert BEFORE current node */
+int  LLDnodeAdd( int List, ... );         /* insert AFTER current node  */
+         /* a return value of -1 indicates a memory allocation problem. */
+
+/* Functions NOT changing the current node pointer.
+   Especially intended for implementation of Queue's and Stacks.
+*/
+int  LLDnodePrepend( int List, ... );           /* insert as first node */
+int  LLDnodeAppend( int List, ... );            /* insert as last node  */
+         /* a return value of -1 indicates a memory allocation problem. */
+
+/* The following four functions are essentially the same as the preceeding
+   four. The data is however not passed by value but by reference.
+*/
+int  LLDnodeInsertFrom( int List, void * Source );
+int  LLDnodeAddFrom( int List, void * Source );
+int  LLDnodePrependFrom( int List, void * Source );
+int  LLDnodeAppendFrom( int List, void * Source );
+
+void LLDnodeDelete( int List );                  /* remove current node */
+        /* current node ptr moved to next node. UNLESS the deleted node */
+        /* was the last node: then current ptr moved to previous node   */
+
+int  LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr );
+        /* Find *DataPtr in the List using the *Compare function.       */
+        /* Returns the return value of *Compare. 0 == equal == found.   */
+        /* non-zero == not found. Current node is set to found node.    */
+        /* Returns 2 for an empty list.                                 */
+        /* First checked node is current node.                          */
+        /* A NULL Compare-function defaults to the use of memcmp() with */
+        /* the list's itemsize as third (size) parameter.               */
+        /* simple implementation. FindFirst and FindNext may be needed. */
+
+/* ---- current node pointer management ----------------------------------
+   These functions change the current node pointer and return 1 when there
+   was a change. A return of 0 indicates trying to move past the begin or
+   the end of the list, or an empty list. The return value is intended for
+   iteration purposes. I.e. stopping a scan through a list.
+*/
+int  LLDnodePtr2First( int List );
+int  LLDnodePtr2Last( int List );
+int  LLDnodePtr2Next( int List );
+int  LLDnodePtr2Prev( int List );
+
+/* ---- stored data management -------------------------------------------
+   return typed data:
+*/
+int  LLDnodeInt( int List );
+long LLDnodeLong( int List );
+void * LLDnodePtr( int List );
+void FAR * LLDnodeFptr( int List );
+
+/* 'return' typeless data. The return value is the size of the data.
+   The data is transferred to Destination.
+   If 'Destination' is NULL, the only action is returning the size.
+*/
+int LLDnodeDataTo( int List, void * Destination );
+
+/*
+  replaces typeless data with source 
+*/
+int LLDnodeDataFrom(int List, void *source);
+#endif
+/* ==== LLD.h  end ==================================================== */
diff --git a/src/nxdict/nxdict.c b/src/nxdict/nxdict.c
new file mode 100644
index 0000000..7453988
--- /dev/null
+++ b/src/nxdict/nxdict.c
@@ -0,0 +1,2014 @@
+
+
+
+
+/*---------------------------------------------------------------------------
+                 Nexus Dictionary API implementation file.
+
+  For documentation see the nxdict.tex file which comes with this 
+  distribution.
+
+  copyleft: Mark Koennecke
+            Labor fuer Neutronenstreuung
+            Paul Scherrer Institut
+            CH-5232 Villigen-PSI
+            Switzerland
+            Mark.Koennecke at psi.ch
+
+  No warranties of any kind, whether explicit or implied, taken.
+  Distributed under the GNU copyleft license as documented elsewhere.
+
+  August, 1997
+
+  Version: 1.0
+
+  Version 1.1
+
+  Updated to use the combined HDF4 HDF5 API. New keyword -chunk which
+  defines the chunk buffer size for a SDS.
+
+  Mark Koennecke, August 2001
+
+-----------------------------------------------------------------------------*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include "lld.h"
+#include "napi.h"
+#include "stringdict.h"
+#include "dynstring.h"
+#include "nxdict.h"
+/*------------------ The magic number used for pointer checking */
+#define NXDMAGIC 260558
+/*--------------------------------------------------------------------------
+      Things defined in napi.c for error reporting 
+---------------------------------------------------------------------------*/
+       extern void *NXpData;
+       extern void (*NXIReportError)(void *pData, char *pBuffer);  
+/*--------------------------------------------------------------------------*/
+/* #define DEFDEBUG 1 */
+/* define DEFDEBUG when you wish to print your definition strings before
+   action. This can help a lot to resolve mysteries when working with
+   dictionaries.
+*/
+/*-------------------------------------------------------------------------*/
+
+
+    typedef struct __NXdict
+                           {
+                               int iID;
+                               pStringDict pDictionary;
+                           } sNXdict;
+/*------------------ verbosity level -------------------------------------*/
+   static int iVerbosity = 0 ;
+
+
+/*-------------------------------------------------------------------------*/
+  static char *NXDIReadFile(FILE *fd)
+  {
+     char *pNew = NULL;
+     long lLength = 0;
+ 
+     assert(fd); 
+
+     /* determine length of file */
+     fseek(fd,0L,SEEK_END);
+     lLength = ftell(fd);
+     if(lLength <= 0)
+     {
+        return NULL;
+     }
+     fseek(fd,0L,SEEK_SET);
+
+     /* allocate buffer */
+     lLength += 3;
+     pNew = (char *)malloc(lLength*sizeof(char));
+     if(!pNew)
+     {
+       return NULL;
+     }
+     memset(pNew,0,lLength); /* this ensures a 0 at the end */
+
+     /* read file */
+     fread(pNew,sizeof(char),lLength-3,fd);
+     
+     /* check for existence of the NXDICT string in the file */
+     if(strncmp(pNew,"##NXDICT-1.0",12) != 0 )
+     {
+        NXIReportError(NXpData,"ERROR: This is NO NXdict file");
+        free(pNew);
+        return NULL;
+     }
+     return pNew;
+  }
+/*--------------------------------------------------------------------------*/
+
+
+#define FWORD 1
+#define FHASH 2
+#define FEOL  3
+#define FEOB  4
+#define FEQUAL 5
+#define FSLASH 6
+
+   static char *NXDIfNextToken(char *pPtr, char *pToken, int *iToken)
+   {
+       pToken[0] = '\0';
+       /* skip whitespace */
+       while( (*pPtr == ' ') || (*pPtr == '\t') )
+       {
+         pPtr++;
+       } 
+
+       /* check for special characters */
+       if(*pPtr == '#')
+       {
+         *iToken = FHASH;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '\n')
+       {
+         *iToken = FEOL;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '\0')
+       {
+         *iToken = FEOB;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '=')
+       {
+         *iToken = FEQUAL;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '\\')
+       {
+         *iToken = FSLASH;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else 
+       {
+         *iToken = FWORD;
+         /* copy word to pToken */
+         while( (*pPtr != ' ') && (*pPtr != '\t') && 
+                (*pPtr != '\n') && (*pPtr != '\0') && (*pPtr != '=') )
+         {
+           *pToken = *pPtr;
+           pPtr++;
+           pToken++;
+         } 
+         *pToken = '\0';
+         return pPtr;
+       }
+      /* not reached */
+      return pPtr;
+   }
+    
+
+
+/*------------------------------------------------------------------------*/
+
+
+#define AMODE 0
+#define DMODE 1
+
+  static void  NXDIParse(char *pBuffer, pStringDict pDict)
+  {
+     char *pPtr;
+     int iToken;
+     int iMode;
+     char pAlias[132];
+     char pDefinition[1024]; /* this is > 10 lines of definition */
+     char pWord[132];
+
+     assert(pBuffer);
+     assert(pDict);
+
+     iMode = AMODE;
+     pPtr = pBuffer;
+     iToken = -1;
+     pDefinition[0] = '\0';
+     pAlias[0] = '\0';
+     pWord[0] = '\0';
+
+     while(iToken != FEOB)
+     {
+         pPtr = NXDIfNextToken(pPtr,pWord,&iToken);
+         switch(iToken)
+         {
+           case FHASH:
+           case FSLASH: /* skip over \n to next non blank */
+                       while(*pPtr != '\n')
+                       {
+                          pPtr++;
+                          /* check for end of file */
+                          if(*pPtr == '\0')
+                          {
+                            return;
+                          }
+                       }
+                       pPtr++;
+                       break;
+           case FEQUAL: /* do a mode change */
+                       iMode = DMODE;
+                       pDefinition[0] = '\0';
+                       break;
+
+           case FWORD:
+                       if(iMode == AMODE)
+                       {
+                         strcpy(pAlias,pWord);
+                       }  
+                       else
+                       {
+                         strcat(pDefinition,pWord);
+                         strcat(pDefinition," ");
+                       }
+                       break;
+           case FEOL:
+                       if(iMode == DMODE)
+                       {
+                          /* enter in dictionary */
+                          StringDictAddPair(pDict,pAlias,pDefinition);
+                          iMode = AMODE;
+                          pAlias[0] = '\0';
+                       }
+                       break;
+           case FEOB:
+                       if(iMode == AMODE) 
+                       {
+                         /* empty line or a problem */
+                       }          
+                       else
+                       {
+                          /* enter in dictionary */
+                          StringDictAddPair(pDict,pAlias,pDefinition);
+                          iMode = AMODE;
+                          pAlias[0] = '\0';
+                       }
+                       return;
+           default:
+                   assert(0); /* unrecognized token is a programming
+                                 error
+                              */
+                   break;
+         }
+     }
+  }
+
+
+/*--------------------------------------------------------------------------*/
+  NXstatus NXDinitfromfile(char *filename, NXdict *pData)
+  {
+     NXdict pNew = NULL;
+     FILE *fd = NULL;
+     char *pBuffer = NULL;
+     char pError[512];
+
+
+
+     /* allocate a new NXdict structure */
+     if(iVerbosity == NXalot)
+     {
+         NXIReportError(NXpData, "Allocating new NXdict structure ");
+     }
+     pNew = (NXdict)malloc(sizeof(sNXdict));
+     if(!pNew)
+     {
+         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");
+         return NX_ERROR;
+     }
+     
+     /* initialise it */
+     pNew->iID = NXDMAGIC;
+     pNew->pDictionary = CreateStringDict();
+     if(!pNew->pDictionary)
+     {
+         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");
+         free(pNew);
+         return NX_ERROR;
+     }
+
+
+
+     /* is there a file name argument */
+     if(filename == NULL)
+     {
+        if(iVerbosity == NXalot)
+        {
+           NXIReportError(NXpData, "NXDinitfrom file finished without data");
+        }
+        *pData = pNew;
+        return NX_OK;
+     }
+
+
+      fd = fopen(filename,"rb");
+      if(!fd)
+      {
+         sprintf(pError,"ERROR: file %s NOT found ",filename);
+         NXIReportError(NXpData, pError);
+         NXIReportError(NXpData, "NXDinitfrom file finished without data");
+         *pData = pNew;
+         return NX_ERROR;
+      }
+
+
+       /* read the file contents */
+       if(iVerbosity == NXalot)
+       {
+          NXIReportError(NXpData, "NXDinitfrom: reading file");
+       }
+       pBuffer = NXDIReadFile(fd);
+       fclose(fd); /* we are done with it then */
+       if(!pBuffer)
+       {
+         sprintf(pError,"ERROR: reading file %s or no memory",filename);
+         NXIReportError(NXpData, pError);
+         NXIReportError(NXpData, "NXDinitfrom file finished without data");
+         *pData = pNew;
+         return NX_ERROR;
+       }
+
+       /* parse it */
+       if(iVerbosity == NXalot)
+       {
+          NXIReportError(NXpData, "NXDinitfrom: parsing dictionary definitions");
+       }
+       NXDIParse(pBuffer, pNew->pDictionary);
+
+
+       if(iVerbosity == NXalot)
+       {
+          NXIReportError(NXpData, "NXDinitfrom: performed successfully");
+       }
+       free(pBuffer);
+       *pData = pNew;
+       return NX_OK;
+  }   
+/*--------------------------------------------------------------------------*/
+
+   NXdict NXDIAssert(NXdict handle)
+   {
+      NXdict self = NULL;
+      assert(handle);
+      self = (NXdict)handle;
+      assert(self->iID == NXDMAGIC);
+      return self;
+   }
+
+
+/*-------------------------------------------------------------------------*/
+
+   NXstatus NXDclose(NXdict handle, char *filename)
+   {
+      NXdict self;
+      const char *pKey = NULL;
+      char pValue[1024];
+      FILE *fd = NULL;
+
+      self = NXDIAssert(handle);
+
+      if(filename) /* we must write a file */
+      {
+        if(iVerbosity == NXalot)
+        {
+           sprintf(pValue,"Writing file %s",filename);
+           NXIReportError(NXpData, pValue);
+        }
+        fd = fopen(filename,"w");
+        if(!fd)
+        {
+           sprintf(pValue,"ERROR: opening file %s for write",filename);
+           NXIReportError(NXpData, pValue);
+           return NX_ERROR;
+        }   
+        
+        /* write our magic recognition header */
+        fprintf(fd,"##NXDICT-1.0\n");
+
+        /* write all our keys */
+        pKey = StringDictGetNext(self->pDictionary, pValue,1023);
+        while(pKey != NULL)
+        {
+          fprintf(fd,"%s = %s\n",pKey,pValue);
+          pKey = StringDictGetNext(self->pDictionary,pValue,1023);
+        }
+        fclose(fd);
+        if(iVerbosity == NXalot)
+        {
+           sprintf(pValue,"File %s written",filename);
+           NXIReportError(NXpData, pValue);
+        }
+      }
+
+      /* now we send the cleaners in */
+      DeleteStringDict(self->pDictionary);
+      free(self);
+      return NX_OK;
+   }
+
+/*------------------------------------------------------------------------*/
+
+   NXstatus NXDadd(NXdict handle, char *alias, char *pDef)
+   {
+     NXdict self;
+     int iRet;
+
+     self = NXDIAssert(handle);
+     iRet = StringDictAddPair(self->pDictionary,alias,pDef);
+     if(!iRet)
+     {
+       return NX_ERROR;
+     }
+     return NX_OK;
+   }
+/*---------------------------------------------------------------------------*/
+   NXstatus NXDget(NXdict handle, char *pKey, char *pBuffer, int iBufLen)
+   {
+     NXdict self;
+     int iRet;
+
+     self = NXDIAssert(handle);
+     iRet = StringDictGet(self->pDictionary,pKey,pBuffer,iBufLen);
+     if(!iRet)
+     {
+       return NX_ERROR;
+     }
+#ifdef DEFDEBUG
+     printf("Resolved: %s to %s\n",pKey,pBuffer);
+#endif
+     return NX_OK;
+   }
+/*-------------------------------------------------------------------------*/
+   NXstatus NXDupdate(NXdict handle, char *pKey, char *pNewVal)
+   {
+     NXdict self;
+     int iRet;
+
+     self = NXDIAssert(handle);
+     iRet = StringDictUpdate(self->pDictionary,pKey,pNewVal);
+     if(!iRet)
+     {
+       return NX_ERROR;
+     }
+     return NX_OK;
+   }
+/*-----------------------------------------------------------------------*/
+#define NORMAL 1
+#define ALIAS  2
+   pDynString NXDItextreplace(NXdict handle, char *pDefString)
+   {
+     NXdict self;
+     int iRet, iPos, i;
+     pDynString pReplaced = NULL;
+     char pBueffel[1024];
+     char pBuffer2[1024];
+     char *pPtr;
+     int iState;
+
+     self = NXDIAssert(handle);
+     
+     /* create a dynamic string */
+     pReplaced = CreateDynString(strlen(pDefString),512);
+     if(!pReplaced)
+     {
+       NXIReportError(NXpData,"ERROR: out of memory in NXDtextreplace");
+       return NULL;
+     }
+
+     /* the loop */
+     iState = NORMAL;
+     for(i = 0, pPtr = pDefString; i < strlen(pDefString); i++,pPtr++)
+     {
+        if(iState == NORMAL)
+        {
+           if(*pPtr == '$')
+           {
+             iState = ALIAS;
+             memset(pBueffel,0,1024);
+             iPos = 0;
+           }
+           else
+           {
+               DynStringConcatChar(pReplaced,*pPtr);
+           }
+        }
+        else if(iState == ALIAS)
+        {
+           switch(*pPtr)
+           {
+             case '(': /* ignore */
+                       break;
+             case ')': 
+                       /* do the replacement */
+                       memset(pBuffer2,0,1023);
+                       iRet = NXDget(handle, pBueffel,pBuffer2,1023);
+                       if(iRet != NX_OK)
+                       {
+                         DeleteDynString(pReplaced);
+                         return NULL;
+                       }
+                       DynStringConcat(pReplaced,pBuffer2);
+                       iState = NORMAL;
+                       break;
+             default:
+                       pBueffel[iPos] = *pPtr;
+                       iPos++;
+                       if(iPos >= 1024)
+                       {
+                          NXIReportError(NXpData,
+                                     "ERROR: buffer overrun in NXDItextreplace");
+                          DeleteDynString(pReplaced);
+                          return NULL;
+                       }
+                       break;
+           }
+        }
+     }
+#ifdef DEFDEBUG
+    printf("Replacement result: %s\n",GetCharArray(pReplaced));
+#endif
+     return pReplaced;
+   }
+/*------------------------------------------------------------------------*/
+   NXstatus NXDdefget(NXdict handle, char *pKey, char *pBuffer, int iBufLen)
+   {
+     int status;
+     pDynString pRep = NULL;
+
+     status = NXDget(handle,pKey,pBuffer,iBufLen);
+     if(status != NX_OK)
+     {
+       return status;
+     }
+     
+     pRep = NXDItextreplace(handle,pBuffer);
+     if(pRep)
+     {
+       strncpy(pBuffer,GetCharArray(pRep),iBufLen);
+       status = NX_OK;
+       DeleteDynString(pRep);
+     } 
+     else 
+     {
+       status = NX_ERROR;
+     }
+     return status;
+   }
+/*--------------------------------------------------------------------------*/
+   NXstatus NXDtextreplace(NXdict handle, char *pDefString, 
+                           char *pBuffer, int iBufLen)
+   {
+     pDynString pResult = NULL;
+     char *pPtr = NULL;
+
+     pResult = NXDItextreplace(handle,pDefString);
+     if(!pResult)
+     {
+         return NX_ERROR;
+     }
+
+     /* copy results home */
+     pPtr = GetCharArray(pResult);
+     strncpy(pBuffer,pPtr,iBufLen);   
+     DeleteDynString(pResult);
+     return NX_OK;
+   }
+
+/*------------------- The Defintion String Parser -----------------------*/
+/*------- Data structures */
+  typedef struct {
+                  char *pText;
+                  int iCode;
+                 }  TokDat;
+
+#define TERMSDS 100
+#define TERMVG  200
+#define TERMLINK 300
+
+   typedef struct {
+                    char *pPtr;
+                    char pToken[256];
+                    int iToken;
+                    int iDepth;
+                    int iMayCreate;
+                    int iTerminal;
+                  } ParDat;
+
+   static void DummyError(void *pData, char *pError)
+   {
+     return;
+   }
+  typedef struct {
+                   char name[256];
+                   char value[256];
+                  }AttItem;
+
+/*---------------- Token name defines ---------------------------*/
+#define DSLASH 0
+#define DKOMMA 1
+#define DSDS   2
+#define DLINK  3
+#define DGROUP 4
+#define DRANK  5
+#define DDIM   6
+#define DTYPE  7
+#define DWORD  9
+#define DOPEN  10
+#define DCLOSE 11
+#define DATTR  12
+#define DEND   13
+#define DLZW   14
+#define DHUF   15
+#define DRLE   16
+#define CHUNK  17
+
+/*----------------- Keywords ----------------------------------------*/
+
+  static TokDat TokenList[12] = { 
+                                {"SDS",DSDS},
+                                {"NXLINK",DLINK},
+                                {"NXVGROUP",DGROUP},
+                                {"-dim",DDIM},
+                                {"-type",DTYPE},
+                                {"-rank",DRANK},
+                                {"-attr",DATTR},
+                                {"-chunk",CHUNK},
+                                {"-LZW",DLZW},
+                                {"-HUF",DHUF},
+                                {"-RLE",DRLE},
+                                {NULL,0} };
+
+/*-----------------------------------------------------------------------*/
+   static void NXDIDefToken(ParDat *sStat)
+   {
+       int i;
+       
+
+       sStat->pToken[0] = '\0';
+
+       /* skip whitespace */
+       while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') )
+       {
+         sStat->pPtr++;
+       } 
+
+       /* check for special characters */
+       if(*(sStat->pPtr) == '/')
+       {
+         sStat->iToken = DSLASH;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == ',')
+       {
+         sStat->iToken = DKOMMA;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '\0')
+       {
+         sStat->iToken = DEND;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '{')
+       {
+         sStat->iToken = DOPEN;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '}')
+       {
+         sStat->iToken = DCLOSE;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else 
+       {
+         sStat->iToken = DWORD;
+         /* copy word to pToken */
+         i = 0;
+         while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') && 
+                (*(sStat->pPtr) != '/') && (*(sStat->pPtr) != '\0') &&
+                (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') )
+         {
+           sStat->pToken[i] = *(sStat->pPtr);
+           sStat->pPtr++;
+           i++;
+         } 
+         sStat->pToken[i] = '\0';
+
+         /*--------- try to find word in Tokenlist */
+         for(i = 0; i < 11; i++)
+         {
+           if(strcmp(sStat->pToken,TokenList[i].pText) == 0)
+           {
+             sStat->iToken = TokenList[i].iCode;
+             break;
+           }
+         }
+         return;
+       }
+      /* not reached */
+      return;
+   }
+/*-----------------------------------------------------------------------*/
+   static void NXDIAttValue(ParDat *sStat)
+   {
+       int i;
+       
+
+       sStat->pToken[0] = '\0';
+
+       /* skip whitespace */
+       while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') )
+       {
+         sStat->pPtr++;
+       } 
+
+       if(*(sStat->pPtr) == ',')
+       {
+         sStat->iToken = DKOMMA;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '\0')
+       {
+         sStat->iToken = DEND;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '{')
+       {
+         sStat->iToken = DOPEN;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '}')
+       {
+         sStat->iToken = DCLOSE;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else 
+       {
+         sStat->iToken = DWORD;
+         /* copy word to pToken */
+         i = 0;
+         while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') && 
+                 (*(sStat->pPtr) != '\0') &&
+                (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') )
+         {
+           sStat->pToken[i] = *(sStat->pPtr);
+           sStat->pPtr++;
+           i++;
+         } 
+         sStat->pToken[i] = '\0';
+         return;
+       }
+      /* not reached */
+      return;
+   }
+
+
+/*------------------------------------------------------------------------*/
+
+   int NXDIParsePath(NXhandle hfil, ParDat *pParse)
+   {
+       int iRet, iToken;
+       void (*ErrFunc)(void *pData, char *pErr); 
+       char pName[132], pClass[132];
+       char pError[256];
+
+       /* get the name */
+       NXDIDefToken(pParse); /* next token */
+       if( (pParse->iToken == DSDS) || (pParse->iToken == DGROUP)
+           || (pParse->iToken == DLINK) )
+       {
+         /* put back & OK */
+         pParse->pPtr -= strlen(pParse->pToken);
+         return NX_OK;
+       }
+       if(pParse->iToken != DWORD)
+       {
+          sprintf(pError,"ERROR: parse error at %s, expected vGroup name",
+                  pParse->pToken);
+          NXIReportError(NXpData, pError);
+          return NX_ERROR;
+       }       
+       strcpy(pName,pParse->pToken);
+     
+       /* now we expect a komma */
+       NXDIDefToken(pParse); /* next token */
+       if(pParse->iToken != DKOMMA)
+       {
+          sprintf(pError,"ERROR: parse error at %s, expected komma",
+                  pParse->pToken);
+          NXIReportError(NXpData, pError);
+          return NX_ERROR;
+       }       
+
+       /* next must be the class */
+       NXDIDefToken(pParse); /* next token */
+       if(pParse->iToken != DWORD)
+       {
+          sprintf(pError,"ERROR: parse error at %s, expected vGroup class",
+                  pParse->pToken);
+          NXIReportError(NXpData, pError);
+          return NX_ERROR;
+       }       
+       strcpy(pClass,pParse->pToken);
+
+       /* done reading, ACTION, first install dummy error handler */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening vGroup */
+       iRet = NXopengroup(hfil, pName, pClass);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         pParse->iDepth++;
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it, if we may */
+          if(pParse->iMayCreate)
+          {
+            iRet = NXmakegroup(hfil,pName,pClass);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXopengroup(hfil,pName,pClass);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            pParse->iDepth++;
+            return NX_OK; 
+          }
+          else
+          {
+             /* this is an error */
+             sprintf(pError,"ERROR: vGroup %s, %s NOT found",pName, pClass);
+             NXIReportError(NXpData,pError);
+             return NX_ERROR;
+          }
+       }
+       /* not reached */
+       return NX_ERROR;
+   }
+
+/*------------------------------------------------------------------------*/
+
+   static int NXDIParseAttr(ParDat *pParse, int iList)
+   {
+     char pError[256];
+     int iRet;
+     AttItem sAtt;
+
+     /* a { is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DOPEN)
+     {
+        sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+
+     /* a word is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DWORD)
+     {
+        sprintf(pError,"ERROR: expected attribute name, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+     strcpy(sAtt.name,pParse->pToken);
+
+     /* a , is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DKOMMA)
+     {
+        sprintf(pError,"ERROR: expected , , got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+
+     /* a word is expected */
+     NXDIAttValue(pParse);
+     if(pParse->iToken != DWORD)
+     {
+        sprintf(pError,"ERROR: expected attribute value, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+     strcpy(sAtt.value,pParse->pToken);
+
+     /* a } is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DCLOSE)
+     {
+        sprintf(pError,"ERROR: expected }, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+
+     /* enter into list */
+     LLDnodeAppendFrom(iList,&sAtt);
+     return NX_OK;
+   }
+
+/*------------------------------------------------------------------------*/
+   static int NXDIParseDim(ParDat *pParse, int *iDim)
+   {
+       char pError[256];
+       int iRet, i;
+
+        /* initialise dimensions to 0 */
+        for(i = 0; i < NX_MAXRANK; i++)
+        {
+          iDim[i] = 0;
+        }
+
+        NXDIDefToken(pParse);
+        if(pParse->iToken != DOPEN)
+        {
+          sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);
+          NXIReportError(NXpData,pError);
+          return NX_ERROR;
+        }
+
+        i = 0;      
+        while(pParse->iToken != DCLOSE)
+        {
+           /* get a number */
+           NXDIDefToken(pParse);
+           if(pParse->iToken != DWORD)
+           {
+              sprintf(pError,"ERROR: expected number, got %s",pParse->pToken);
+              NXIReportError(NXpData,pError);
+              return NX_ERROR;
+           }
+           iDim[i] = atoi(pParse->pToken);
+           i++;
+           /* next must be close of komma */
+           NXDIDefToken(pParse);
+           if( (pParse->iToken != DKOMMA) && (pParse->iToken != DCLOSE) )
+           {
+              sprintf(pError,"ERROR: expected , or }, got %s",pParse->pToken);
+              NXIReportError(NXpData,pError);
+              return NX_ERROR;
+           }
+           if(pParse->iToken == DCLOSE)
+           {
+              break;
+           }
+        }
+        return NX_OK;
+   }
+/*------------------------------------------------------------------------*/
+   static TokDat tDatType[] = {
+                      {"DFNT_FLOAT32",NX_FLOAT32},   
+                      {"DFNT_FLOAT64",NX_FLOAT64},    
+                      {"DFNT_INT8",NX_INT8},  
+                      {"DFNT_UINT8",NX_UINT8},
+                      {"DFNT_INT16",NX_INT16},      
+                      {"DFNT_UINT16",NX_UINT16},
+                      {"DFNT_INT32",NX_INT32},
+                      {"DFNT_UINT32",NX_UINT32},
+                      {"DFNT_CHAR",NX_CHAR},
+                      {"NX_FLOAT32",NX_FLOAT32},   
+                      {"NX_FLOAT64",NX_FLOAT64},    
+                      {"NX_INT8",NX_INT8},  
+                      {"NX_UINT8",NX_UINT8},
+                      {"NX_INT16",NX_INT16},      
+                      {"NX_UINT16",NX_UINT16},
+                      {"NX_INT32",NX_INT32},
+                      {"NX_UINT32",NX_UINT32},
+                      {"NX_CHAR",NX_CHAR},
+                      {NULL,-122} };
+
+
+
+   static int NXDIParseType(ParDat *pParse, int *iType)
+   {
+      char pError[256];
+      int i = 0;
+
+      NXDIDefToken(pParse);
+      if(pParse->iToken != DWORD)
+      { 
+        sprintf(pError,"ERROR: expected data type, got %s", pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+      }
+       
+      /* try to interpret data type */
+      while(tDatType[i].iCode > 0) {
+        if(strcmp(tDatType[i].pText,pParse->pToken) == 0)
+        {
+           *iType = tDatType[i].iCode;
+            return NX_OK;
+        }
+        i++;
+      }
+      /* if we are here, the data type has not been recognized. Reason for
+         some boring error reporting code
+      */
+      sprintf(pError,"ERROR: %s not recognized as valid data type",
+                      pParse->pToken);
+      NXIReportError(NXpData,pError);
+      return NX_ERROR;      
+   }
+
+/*-------------------------------------------------------------------------*/
+   static int NXDIParseSDS(NXhandle hfil, ParDat *pParse)
+   {
+      int iType = NX_FLOAT32;
+      int iRank = 1;
+      int iCompress = NX_COMP_NONE;
+      int iDim[NX_MAXRANK], iChunk[NX_MAXRANK];
+      int iList, iChunkDefined = 0 ;
+      int iRet, iStat, i;
+      char pError[256];
+      char pName[NX_MAXNAMELEN];
+      void (*ErrFunc)(void *pData, char *pErr);
+      AttItem sAtt; 
+
+
+       iDim[0] = 1;
+       /* first find the name */
+       NXDIDefToken(pParse);
+       if(pParse->iToken != DWORD)
+       {
+          sprintf(pError,"ERROR: parsing, expected name, got %s",
+                  pParse->pToken);
+          NXIReportError(NXpData,pError);
+          return NX_ERROR;
+       }
+        strcpy(pName,pParse->pToken);
+
+       /* create the attribute list */
+       iList = LLDcreate(sizeof(AttItem));
+       if(iList < 0)
+       {
+          NXIReportError(NXpData, "ERROR: cannot create list in NXDIParseSDS");
+          return NX_ERROR;
+       }
+
+       NXDIDefToken(pParse);
+       while(pParse->iToken != DEND)
+       {
+          switch(pParse->iToken)
+          {
+            case DRANK: /* rank */
+                       NXDIDefToken(pParse); /* advance */
+                       if(pParse->iToken != DWORD)
+                       {
+                         sprintf(pError,
+                         "ERROR: expected int, got %s", pParse->pToken);
+                          NXIReportError(NXpData,pError);
+                          LLDdelete(iList);
+                          return NX_ERROR; 
+                       }
+                       iRank = atoi(pParse->pToken);
+                       break;
+            case CHUNK: /* chunk size for compression  */
+                     iRet = NXDIParseDim(pParse, iChunk);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     iChunkDefined = 1;
+                     break;
+            case DDIM:
+                     iRet = NXDIParseDim(pParse, iDim);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     break;
+            case DTYPE:
+                     iRet = NXDIParseType(pParse, &iType);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     break;
+            case DATTR:
+                     iRet = NXDIParseAttr(pParse, iList);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     break;
+	    case DLZW:
+                     iCompress = NX_COMP_LZW;
+                     break;
+	    case DRLE:
+                     iCompress = NX_COMP_RLE;
+                     break;
+	    case DHUF:
+                     iCompress = NX_COMP_HUF;
+                     break;
+            case DEND:
+                     break;
+            default:
+                     sprintf(pError,"ERROR: cannot identify token %s",
+                                     pParse->pToken);
+                     NXIReportError(NXpData, pError);
+                     LLDdelete(iList);
+                     return NX_ERROR;
+                    
+          }
+          NXDIDefToken(pParse);
+       }
+
+       /* whew! got all information for doing the SDS 
+          However, if the chunk sizes for compression have not 
+          been set, default them to the dimensions of the data set
+       */
+       if(iChunkDefined == 0)
+       {
+	 for(i = 0; i < iRank; i++)
+	 {
+	   iChunk[i] = iDim[i];
+         }
+       }
+       
+       /* first install dummy error handler, try open it, then
+          deinstall again and create if allowed 
+       */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening SDS */
+       iRet = NXopendata(hfil, pName);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         LLDdelete(iList);
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it, if we may */
+          if(pParse->iMayCreate)
+          {
+            iRet = NXcompmakedata(hfil,pName,iType, iRank,iDim,
+                                  iCompress,iChunk);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 LLDdelete(iList);
+                 return iRet;
+            }
+            iRet = NXopendata(hfil,pName);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 LLDdelete(iList);
+                 return iRet;
+            }
+
+            /* put attributes in */
+            iRet = LLDnodePtr2First(iList);
+            while(iRet != 0)
+            {
+              LLDnodeDataTo(iList,&sAtt);
+              iStat = NXputattr(hfil,sAtt.name,
+                                sAtt.value,strlen(sAtt.value),NX_CHAR);
+              if(iStat != NX_OK)
+              {
+                 /* NeXus already complained bitterly */
+                 LLDdelete(iList);
+                 return iStat;
+              }
+              iRet = LLDnodePtr2Next(iList);
+            }
+            LLDdelete(iList);
+            return NX_OK; 
+          }
+          else
+          {
+             /* this is an error */
+             sprintf(pError,"ERROR: SDS %s NOT found",pName);
+             NXIReportError(NXpData,pError);
+             LLDdelete(iList);
+             return NX_ERROR;
+          }
+       }
+       return NX_OK;
+   }
+/*------------------------------------------------------------------------*/
+   static int NXDIParseLink(NXhandle hfil, NXdict pDict,ParDat *pParse)
+   {
+     char pError[256];
+     int i, iRet;
+
+     /* need one word of alias */ 
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DCLOSE)
+     {
+        sprintf(pError,"ERROR: expected alias , got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+    
+     /* move back in hierarchy */
+     for(i = 0; i < pParse->iDepth; i++)
+     {
+       iRet = NXclosegroup(hfil);
+       if(iRet == NX_ERROR)
+       {
+         return NX_ERROR;
+       }
+     }
+     
+     /* open the link instead */ 
+     return NXDopenalias(hfil, pDict, pParse->pToken);
+
+   }
+/*------------------------------------------------------------------------*/
+    int NXDIDefParse(NXhandle hFil, NXdict pDict, ParDat *pParse)
+    {
+       int iRet;
+       char pError[256];
+ 
+       pParse->iToken = -1;
+       while(pParse->iToken != DEND)
+       {
+         NXDIDefToken(pParse); /* next token */
+         switch(pParse->iToken)
+         {
+            case DEND:
+                      break;
+            case DSLASH:
+                      iRet = NXDIParsePath(hFil, pParse);
+                      if(iRet == NX_ERROR)
+                      {
+                         return NX_ERROR;
+                      }
+                      break;
+            case DSDS:
+                      iRet = NXDIParseSDS(hFil, pParse);
+                      if(iRet == NX_ERROR)
+                      {
+                         return NX_ERROR;
+                      }
+                      pParse->iTerminal = TERMSDS;
+                      break;
+            case DLINK:
+                      iRet = NXDIParseLink(hFil,pDict, pParse);                      
+                      if(iRet == NX_ERROR)
+                      {
+                         return NX_ERROR;
+                      }
+                      pParse->iTerminal = TERMLINK;
+                      break;
+            case DGROUP:
+                      pParse->iTerminal = TERMVG;
+                      return NX_OK;
+            default:
+                     sprintf(pError,
+            "ERROR: Definition String parse error: %s not permitted here",
+             pParse->pToken);
+                     NXIReportError(NXpData,pError);
+                     return NX_ERROR;
+                     break;
+         }
+       }
+       return NX_OK;
+    }
+/*----------------------------------------------------------------------*/
+  NXstatus NXDIUnwind(NXhandle hFil, int iDepth)
+  {
+     int i, iRet;
+      
+     for(i = 0; i < iDepth; i++)
+     {
+        iRet = NXclosegroup(hFil);
+        if(iRet != NX_OK)
+        {
+          return NX_ERROR;
+        }
+     }
+     return NX_OK;
+  }
+/*-------------------- The Data Transfer Functions ----------------------*/
+   NXstatus NXDopendef(NXhandle hfil, NXdict dict, char *pDef)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 1;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+     iRet = NXDIDefParse(hfil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+         iRet = NXDIUnwind(hfil,pParse.iDepth);
+         return NX_ERROR;
+     }
+
+     
+     /* try rewinding the hierarchy */
+     if(pParse.iTerminal == TERMSDS)
+     {
+         iStat = NXDIUnwind(hfil,pParse.iDepth);
+         if(iStat != NX_OK)
+         {
+            return NX_ERROR;
+         }
+     }
+     /* do not rewind on links */
+     return iRet;
+   }
+/*------------------------------------------------------------------------*/
+   NXstatus NXDopenalias(NXhandle hfil, NXdict dict, char *pAlias)
+   {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[2048];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,2047);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+     
+     /* do the text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+         return NX_ERROR;
+     }
+
+     /* call NXDopendef */
+     iRet = NXDopendef(hfil,dict,GetCharArray(pReplaced));
+     DeleteDynString(pReplaced);
+     return iRet;
+   }
+/*------------------------------------------------------------------------*/
+   NXstatus NXDputdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 1;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+#ifdef DEFDEBUG
+     printf("Putting: %s\n",pDef);
+#endif
+     iRet = NXDIDefParse(hFil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+          NXDIUnwind(hFil,pParse.iDepth);
+          return NX_ERROR;
+     }
+
+     
+     /* only SDS can be written */
+     if(pParse.iTerminal != TERMSDS)
+     {
+        NXIReportError(NXpData,
+                     "ERROR: can only write to an SDS!");
+        iStat = NX_ERROR;
+     } 
+     else 
+     {
+       /* the SDS should be open by now, write it */
+       iStat = NXputdata(hFil, pData);
+       iRet = NXclosedata(hFil);
+     }   
+
+
+     /* rewind the hierarchy */
+     iRet = NXDIUnwind(hFil,pParse.iDepth);
+     if(iRet != NX_OK)
+     {
+       return NX_ERROR;
+     }
+     return iStat;
+   }
+/*------------------------------------------------------------------------*/
+  NXstatus NXDputalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)
+  {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[2048];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,2047);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+     
+     /* do text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+       return NX_ERROR;
+     }
+
+     /* call NXDputdef */
+     iRet = NXDputdef(hFil,dict,GetCharArray(pReplaced),pData);
+     DeleteDynString(pReplaced);
+     return iRet;
+  }
+/*------------------------------------------------------------------------*/
+   NXstatus NXDgetdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 0;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+#ifdef DEFDEBUG
+     printf("Getting: %s\n",pDef);
+#endif
+     iRet = NXDIDefParse(hFil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParse.iDepth);
+          return NX_ERROR;
+     }
+
+
+     /* only SDS can be written */
+     if(pParse.iTerminal != TERMSDS)
+     {
+        NXIReportError(NXpData,
+                     "ERROR: can only write to an SDS!");
+        iStat = NX_ERROR;
+     } 
+     else 
+     {
+       /* the SDS should be open by now, read it */
+       iStat = NXgetdata(hFil, pData);
+       iRet = NXclosedata(hFil);
+     }   
+
+
+     /* rewind the hierarchy */
+     iRet = NXDIUnwind(hFil,pParse.iDepth);
+     if(iRet != NX_OK)
+     {
+        return NX_ERROR;
+     }
+     return iStat;
+   }
+
+/*------------------------------------------------------------------------*/
+  NXstatus NXDgetalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)
+  {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[2048];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,2047);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+ 
+     /* do text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+       return NX_ERROR;
+     }
+     
+     /* call NXDgetdef */
+     iRet = NXDgetdef(hFil,dict,GetCharArray(pReplaced),pData);
+     DeleteDynString(pReplaced);
+     return iRet;
+  }
+/*------------------------------------------------------------------------*/
+
+   NXstatus NXDinfodef(NXhandle hFil, NXdict dict, char *pDef, int *rank,
+   			int dimension[], int *iType)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 0;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+#ifdef DEFDEBUG
+     printf("Getting: %s\n",pDef);
+#endif
+     iRet = NXDIDefParse(hFil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParse.iDepth);
+          return NX_ERROR;
+     }
+
+
+     /* only SDS can be written */
+     if(pParse.iTerminal != TERMSDS)
+     {
+        NXIReportError(NXpData,
+                     "ERROR: can only write to an SDS!");
+        iStat = NX_ERROR;
+     } 
+     else 
+     {
+       /* the SDS should be open by now, read it */
+       iStat = NXgetinfo(hFil, rank,dimension, iType);
+       iRet = NXclosedata(hFil);
+     }   
+
+
+     /* rewind the hierarchy */
+     iRet = NXDIUnwind(hFil,pParse.iDepth);
+     if(iRet != NX_OK)
+     {
+        return NX_ERROR;
+     }
+     return iStat;
+   }
+
+/*------------------------------------------------------------------------*/
+
+  NXstatus NXDinfoalias(NXhandle hFil, NXdict dict, char *pAlias, int *rank,
+   			int dimension[], int *iType)
+  {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[2048];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,2047);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+ 
+     /* do text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+       return NX_ERROR;
+     }
+     
+     /* call NXDgetdef */
+     iRet = NXDinfodef(hFil,dict,GetCharArray(pReplaced),rank,dimension,iType);
+     DeleteDynString(pReplaced);
+     return iRet;
+  }
+
+/*------------------------------------------------------------------------*/
+  NXstatus NXDdeflink(NXhandle hFil, NXdict dict, 
+                      char *pTarget, char *pVictim)
+  {
+     NXdict pDict;
+     ParDat pParseT, pParseV;
+     int iRet, i, iStat;
+     NXlink sLink;
+
+     pDict = NXDIAssert(dict);
+
+
+#ifdef DEFDEBUG
+     printf("Linking: %s\n",pVictim);
+     printf("To: %s\n", pTarget);
+#endif
+     
+
+     /* parse Victim  */
+     pParseV.iMayCreate = 0;
+     pParseV.pPtr = pVictim;
+     pParseV.iDepth = 0;
+     iRet = NXDIDefParse(hFil,pDict,&pParseV);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParseV.iDepth);
+          return NX_ERROR;
+     }
+     /* get link data */
+     if(pParseV.iTerminal == TERMSDS)
+     {
+       NXgetdataID(hFil,&sLink);
+       iRet =  NXclosedata(hFil);
+       if(iRet != NX_OK)
+       {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParseV.iDepth);
+          return NX_ERROR;
+       }
+     }
+     else if(pParseV.iTerminal == TERMVG)
+     {
+       NXgetgroupID(hFil,&sLink);
+     }
+     else
+     {
+        assert(0); /* serious programming error */
+     }
+     /* Unwind */
+     iRet = NXDIUnwind(hFil,pParseV.iDepth);
+     if(iRet != NX_OK)
+     {
+       return NX_ERROR;
+     }
+
+     /* parse Target */
+     pParseT.iMayCreate = 1;
+     pParseT.pPtr = pTarget;
+     pParseT.iDepth = 0;
+     iRet = NXDIDefParse(hFil,pDict,&pParseT);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParseT.iDepth);
+          return NX_ERROR;
+     }
+     /* check it being a vGroup! */
+     if(pParseT.iTerminal != TERMVG)
+     {
+       NXIReportError(NXpData,"ERROR: can link only into a vGroup");
+       NXDIUnwind(hFil,pParseT.iDepth);
+       return NX_ERROR;
+     }
+    
+     /* link, finally */
+     iRet = NXmakelink(hFil,&sLink);
+     /* Unwind anyway */
+     iStat = NXDIUnwind(hFil,pParseT.iDepth);
+     if(iStat != NX_OK)
+     {
+       return NX_ERROR;
+     }
+     return iStat;
+  }
+/*--------------------------------------------------------------------------*/
+  NXstatus NXDaliaslink(NXhandle hFil, NXdict dict, 
+                      char *pTarget, char *pVictim)
+  {
+    char pTargetDef[2048], pVictimDef[2048];
+    int iRet;
+    NXdict pDict;
+    pDynString pRep1 = NULL, pRep2 = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Target Definition String  */
+     iRet = NXDget(pDict,pTarget,pTargetDef,2047);
+     if(iRet != NX_OK)
+     {
+        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);
+        NXIReportError(NXpData,pTargetDef);
+        return NX_ERROR;
+     }       
+
+     /* get Victim definition string */
+     iRet = NXDget(pDict,pVictim,pVictimDef,2047);
+     if(iRet != NX_OK)
+     {
+        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);
+        NXIReportError(NXpData,pTargetDef);
+        return NX_ERROR;
+     }
+
+     /* do replacements */
+     pRep1 = NXDItextreplace(dict,pTargetDef);
+     pRep2 = NXDItextreplace(dict,pVictimDef);
+     if( (!pRep1) || (!pRep2) )
+     {
+        if(pRep1)
+           DeleteDynString(pRep1);
+        if(pRep2)
+           DeleteDynString(pRep2);
+        return NX_ERROR;
+     }
+
+     /* call NXdeflin */
+     iRet = NXDdeflink(hFil,pDict,GetCharArray(pRep1),GetCharArray(pRep2));
+     DeleteDynString(pRep1);
+     DeleteDynString(pRep2);
+     return iRet;
+  }
+/*-------------------------------------------------------------------------*/
+  static void SNXFormatTime(char *pBuffer, int iBufLen)
+  {
+     time_t iDate;
+     struct tm *psTime;
+
+     /* make time string */
+     iDate = time(NULL);
+     psTime = localtime(&iDate);
+     memset(pBuffer,0,iBufLen);         
+     strftime(pBuffer,iBufLen,"%Y-%m-%d %H:%M:%S",psTime);
+  }  
+/*--------------------------------------------------------------------------*/
+   NXstatus NXUwriteglobals(NXhandle pFile, 
+                            char *filename,
+                            char *owner,
+                            char *adress,
+                            char *phone,
+                            char *email,
+                            char *fax,
+                            char *instrument)
+   {
+     char pBueffel[512];
+     int iStat;
+     
+     /* store global attributes, now done by NXopen
+     iStat = NXputattr(pFile,"file_name",filename, 
+                       strlen(filename)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+       return NX_ERROR;
+     }
+     */
+     
+     /* write creation time, now done by NXopen
+     SNXFormatTime(pBueffel,512);
+     iStat = NXputattr(pFile,"file_time",pBueffel,
+                       strlen(pBueffel)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+       return NX_ERROR;
+     }
+     */
+
+     /* instrument name */
+     iStat = NXputattr(pFile,"instrument",instrument,
+                       strlen(instrument)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+
+     /* owner */
+     iStat = NXputattr(pFile,"owner",owner,
+                       strlen(owner)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+
+     /* Adress */
+     iStat = NXputattr(pFile,"owner_adress",adress,
+                       strlen(adress)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+        return iStat;
+     }
+
+     /* phone */
+     iStat = NXputattr(pFile,"owner_telephone_number",phone,
+                       strlen(phone)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+        return iStat;
+     }
+
+     /* fax */
+     iStat = NXputattr(pFile,"owner_fax_number",fax,
+                       strlen(fax)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+
+     /* email */
+     iStat = NXputattr(pFile,"owner_email",email,
+                       strlen(email)+1,NX_CHAR);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+     return NX_OK;
+   }
+/*-----------------------------------------------------------------------*/
+   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class)
+   {
+       void (*ErrFunc)(void *pData, char *pErr); 
+       int iRet;
+
+       /* ACTION, first install dummy error handler */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening vGroup */
+       iRet = NXopengroup(hFil, name, class);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it */
+            iRet = NXmakegroup(hFil,name,class);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXopengroup(hFil,name,class);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+       }
+       return NX_OK;
+   }
+/*-----------------------------------------------------------------------*/
+   NXstatus NXUenterdata(NXhandle hFil, char *label, int datatype,
+                         int rank, int dim[], char *pUnits)
+   {
+       void (*ErrFunc)(void *pData, char *pErr); 
+       int iRet;
+
+       /* ACTION, first install dummy error handler */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening SDS */
+       iRet = NXopendata(hFil, label);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it */
+            iRet = NXmakedata(hFil,label, datatype, rank,dim);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXopendata(hFil,label);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXputattr(hFil, "Units",pUnits,
+                             strlen(pUnits) + 1,NX_INT8);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+       }
+       return NX_OK;
+   }
+/*-----------------------------------------------------------------------*/
+   NXstatus NXUallocSDS(NXhandle hFil, void **pData)
+   {
+      int iDIM[NX_MAXRANK];
+      int iRank,iType;
+      int iRet, i;
+      long lLength;
+
+      /* get info */
+      iRet = NXgetinfo(hFil,&iRank, iDIM, &iType);
+      if(iRet != NX_OK)
+      {
+        return iRet;
+      }      
+
+      /* calculate Size */
+      lLength = iDIM[0];
+      for(i = 1; i < iRank; i++)
+      {
+        lLength *= iDIM[i];
+      }
+      switch(iType)
+      {
+        case NX_FLOAT32:
+             lLength *= sizeof(float);
+             break;
+        case NX_FLOAT64:
+             lLength *= sizeof(double);
+             break;
+        case NX_INT8:
+        case NX_CHAR:
+             lLength *= sizeof(char);
+             break;
+        case NX_UINT8:
+             lLength *= sizeof(unsigned char);
+             break;
+        case NX_INT16:
+             lLength *= sizeof(short);
+             break;
+        case NX_UINT16:
+             lLength *= sizeof(unsigned short);
+             break;
+        case NX_INT32:
+             lLength *= sizeof(int);
+             break;
+        case NX_UINT32:
+             lLength *= sizeof(int);
+             break;
+        default:
+             NXIReportError(NXpData,"ERROR: Internal: number type not recoginized");
+             return NX_ERROR;
+      }
+
+      /* time to malloc */
+      *pData = NULL;
+      *pData = malloc(lLength);
+      if(*pData == NULL)
+      {
+        NXIReportError(NXpData,"ERROR: memory exhausted in NXUallocSDS");
+        return NX_ERROR;
+      }
+      memset(*pData,0,lLength);
+      return NX_OK;
+   }
+/*----------------------------------------------------------------------*/
+   NXstatus NXUfreeSDS(void **pData)
+   {
+      free(*pData);
+      *pData = NULL;
+      return NX_OK;
+   }
+
diff --git a/src/nxdict/nxdict.h b/src/nxdict/nxdict.h
new file mode 100644
index 0000000..606f7fb
--- /dev/null
+++ b/src/nxdict/nxdict.h
@@ -0,0 +1,94 @@
+
+#line 2239 "nxdict.w"
+
+/*---------------------------------------------------------------------------
+                            NXDICT API header file
+
+   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland
+
+   No warranties of any kind taken.
+----------------------------------------------------------------------------*/
+#ifndef NXDICTAPI
+#define NXDICTAPI
+#include "napi.h" /* make sure, napi is included */
+
+/*-------------------- NXDict data types & defines ----------------------*/
+
+#line 195 "nxdict.w"
+
+   typedef struct __NXdict *NXdict;
+
+#line 2252 "nxdict.w"
+
+#define NXquiet 0
+#define NXalot  1
+/*-------------------- Dictionary Maintainance ----------------------------*/
+
+#line 201 "nxdict.w"
+
+   NXstatus NXDinitfromfile(char *filename, NXdict *pDict);
+   NXstatus NXDclose(NXdict handle, char *filename);
+
+   NXstatus NXDadd(NXdict handle, char *alias, char *DefString);
+   NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int iBufLen);
+   NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal);
+   NXstatus NXDtextreplace(NXdict handle, char *pDefString, char *pBuffer,
+                           int iBuflen);
+
+#line 2256 "nxdict.w"
+
+/*----------------- Dictionary added data transfer -----------------------*/ 
+
+#line 240 "nxdict.w"
+
+   NXstatus NXDputalias(NXhandle file, NXdict dict, 
+                        char *alias, void *pData);
+   NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, void *pData);
+
+   NXstatus NXDgetalias(NXhandle file, NXdict dict, 
+                        char *alias, void *pData);
+   NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData);
+   
+   NXstatus NXDinfoalias(NXhandle hFil, NXdict dict, char *pAlias, int *rank,
+                          int dimension[], int *iType);
+
+   NXstatus NXDinfodef(NXhandle hFil, NXdict dict, char *pDef, int *rank,
+                           int dimension[], int *iType);
+                           
+   NXstatus NXDaliaslink(NXhandle file, NXdict dict, 
+                         char *pAlias1, char *pAlias2);
+   NXstatus NXDdeflink(NXhandle file, NXdict dict, 
+                         char *pDef1, char *pDef2);
+
+   NXstatus NXDopenalias(NXhandle file, NXdict dict, 
+                        char *alias);
+   NXstatus NXDopendef(NXhandle file, NXdict dict, char *pDefString);
+
+
+#line 2258 "nxdict.w"
+
+/*-------------------- Utility Functions --------------------------------*/
+
+#line 310 "nxdict.w"
+
+        NXstatus NXUwriteglobals(NXhandle file, 
+                            char *filename,
+                            char *owner,
+                            char *adress,
+                            char *phone,
+                            char *email,
+                            char *fax,
+                            char *thing);
+
+
+   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class);
+   NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, 
+                          int rank, int dim[], char *pUnits);
+   
+   NXstatus NXUallocSDS(NXhandle hFil, void **pData);
+   NXstatus NXUfreeSDS(void **pData);
+
+
+#line 2260 "nxdict.w"
+
+#endif
diff --git a/src/nxdict/nxdict.tex b/src/nxdict/nxdict.tex
new file mode 100644
index 0000000..f416a41
--- /dev/null
+++ b/src/nxdict/nxdict.tex
@@ -0,0 +1,3053 @@
+%
+%
+%  This software is distributed in the hope that it will be useful,
+%  but WITHOUT ANY WARRANTY; without even the implied warranty of
+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%  GNU General Public License for more details.
+%
+%  You may already have a copy of the GNU General Public License; if
+%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+%  Cambridge, MA 02139, USA.
+%
+
+\documentclass[12pt]{article}
+
+\setlength{\oddsidemargin}{-.1in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.2in}
+\setlength{\marginparwidth}{0.5in}
+
+\begin{document}
+\title{The NEXUS Dictionary API}
+
+\author{Mark K\"onnecke\\
+  Labor f\"ur Neutronenstreuung\\
+  Paul Scherrer Institut\\
+  CH-5232 Villigen PSI\\
+  Switzerland\\       
+  Mark.Koennecke at psi.ch \\
+}
+
+
+
+\maketitle
+
+\vskip.3in
+\centerline{\large\bf Abstract}
+\vskip.2in
+\begin{center}
+\parbox{.8\textwidth}{
+  There is a proposed portable data exchange format for neutron and
+  X-ray scattering communities, NEXUS (described in a separate
+  publication).   Another document describes an application programmers
+ interface to NEXUS. This is a base level API which hides many of the
+ hideous details of the HDF interface from the NeXus programmer. The
+ present document   introduces a higher level application programmers
+ interface sitting on top of the NeXus API. This API (the NEXDICT-API),
+ reads all file structure data  from a dictionary data file and creates
+ the structure automatically from that information. The NEXDICT user only
+ needs to specify the data to write or read.
+}
+\end{center}
+
+\clearpage
+
+\section{Introduction}
+ There exists a proposal for a portable data exchange format for neutron and
+ X--ray scattering communities, NeXus. NeXus is fully described
+ elsewhere$^{1}$. NeXus sits on top of the hierarchical data format (HDF) as
+ defined and specified by the National Center for Supercomputer Applications, 
+ NCSA, USA. HDF comes with a library of access functions. On top of the
+ HDF-library an application programmers interface (API) for NeXus was
+ defined which hides many of the low level details and ideosyncracies of
+ the HDF interface form the NeXus programmer. However, writing NeXus files stays
+ hideous even with this interface due to the amount of repetitive code
+ required to  implement the NeXus structure. Now, repetitive tasks is one
+ area a computer is good at. So, why not have the computer take care of all
+ the structure associated with the NeXus format? Such an approach has the 
+additional benefit that changes in the file structure just require to edit
+the dictionary data file with no changes to the source code writing or
+reading the data. In order to do all this two
+ components are needed:
+\begin{itemize}
+\item A language which describes the NeXus file structure to the computer.
+  This language will be called the NeXus Data Definition Language (NXDDL).
+  NXDLL might also be used as a tool for discussing and defining NeXus
+  data structures.
+\item A application programmers interface which works with the NeXus Data 
+ Definition Language.
+\end{itemize}
+Both of the above will be detailed in this document.
+
+\section{The NeXus Data Definition Language}
+The NeXus Data Definition Language's(NXDDL) purpose is to define the structure
+and data items in a NeXus file in a form which can be understood by a human
+programmer and which can be parsed by the computer in order to create the 
+structure. 
+For this a dictionary based approach will be used. This dictionary
+will contain pairs of short aliases for data items and definition strings 
+which hold the structure information. This dictionary will
+be initialized from a data file, the NXDDL-file. Such a dictionary can be
+used in the following way: Given an appropriate API function, a NXDICT
+programmer  needs to specify only the alias and the data to write and 
+everything else is taken care of by the API: vGroup creation, opening,
+SDS definition etc. Another use may involve the creation of definition
+strings
+completely or partly at run time which can then be used by an API function
+in order to create the structures defined by the definition string. The same
+holds for writing as well.
+
+
+A NXDDL dictionary is preferably initialized from a file.
+Such a NXDDL file has to follow these general structure guidelines:
+\begin{itemize}
+\item All input is in US--ASCII.
+\item The first line must read: ##NXDICT-1.0. This is in order to
+automatically identify the file.
+\item A \verb+#+ in the first column denotes a comment and will be ignored.
+\item A \verb+\+ at the end of the line means that the current text will be 
+ continued with the next non-blank character for the next line.
+\item All other entries follow the form: alias = definition string.
+ This defines \verb+alias+ as a short form for the definition string  after the
+ equality sign.
+\item There is a text replacement facility similar to shell variables under
+Unix: The sequence $(alias) anywhere in a definition string will be replaced
+ by the value of the alias specified between the braces. This scheme allows
+to cater for multiple entries in a file or changing data descriptions as a
+function of instrument modes.
+\end{itemize}         
+It might be considered to add a special global vGroup of class NXdict to the
+NexUs API which holds the dictionary information within a NeXus file.
+
+ The next thing to define is the content of the definition string. A
+ definition string will have the general form: \\
+\centerline{\bf PATH/TerminalSymbol}
+ This means a definition string will consist of a path specifier which
+ describes the position of a data item in the vGroup hierarchy and a
+ terminal symbol which describes the nature of the data item. 
+
+ The path through the vGroup hierarchy to a data item will be described in a
+ manner analog to a Unix directory hierarchy. However, NeXus requires two
+ pieces of data in order to fully qualify a vGroup. This is it's name and
+ class. Consequently, both name and classname will be given for each vGroup,
+ separated by a komma. A valid path string then looks like: \\
+\begin{verbatim} 
+     /scan1,NXentry/DMC,NXinstrument/big_detector,NXdetector/TerminalSymbol
+\end{verbatim}
+ This translates into: TerminalSymbol in vGroup big\_detector, class
+ NXdetector, which resides in vGroup DMC of class NXinstrument, which in
+ turn is situated in the vGroup scan1 of class NXentry.
+
+ The terminal symbol in a definition string is used to define the data item
+ at the end of the definition. NeXus currently supports only three types of
+ data items at the end of the chain: these are scientific data sets (SDS),
+ vGroups and links to other data items or vGroups. The terminal symbol for a link
+ is specified by the keyword \verb+NXLINK+  
+ followed
+ by a valid alias of another data item or vGroup. For example the terminal 
+ symbol: \\
+ \centerline{\bf SDS counts}
+ would define a SDS with name counts.
+
+ A vGroup would be denoted by the keyword VGROUP. By then, the vGroup has
+ already been defined by the path string. This form of alias is only useful
+ for the definition of links to vGroups.
+
+ A SDS is more involved. The definition of an SDS starts with the keyword
+ \verb+SDS+. This keyword must then be followed by the name of the SDS.
+ Following the name there are option value pairs which define the 
+  details of the SDS. The following option exist:
+ \begin{itemize}
+  \item {\bf -rank} defines the rank of the SDS.
+  \item {\bf -dim \{dim0,dim1,dim2,...., dimn\} } defines the dimensions of the
+       SDS. Exactly the number of rank numbers defining the dimensions
+ length is required inside the curly braces. 
+  \item {\bf -type} defines the data type of the SDS as a string corresponding
+  to the HDF data types.
+  \item {\bf -attr \{name,value\} } defines an attribute. In the curly braces
+   there must be the name and value of the attribute separated by a comma.
+  \end{itemize}
+  If no options are given a default is used. This will be a single floating
+  point number, as this is the most frequently written data item. As an 
+  example see the definition of a 3d array of 32 bit integers:
+  \begin{verbatim}
+   PATHSTRING/SDS counts -rank 3 -dim {64,64,712} -type DFNT_INT32 \
+                  -attr {Units,Counts}      
+
+  \end{verbatim}
+
+  \section{The NXDICT--API}
+  In order to interface with the NeXus dictionary API a set of
+  API--functions is needed. All functions and data types belonging to
+  this API start with the letters: NXD. The functions belonging to this API
+  fall into three groups:
+  \begin{itemize}
+   \item Dictionary maintainance functions.
+   \item Data writing and reading functions.
+   \item Utility functions.
+  \end{itemize}
+  
+  One additional data type is needed for this API:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap1}
+$\langle$tata {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   typedef struct __NXdict *NXdict;@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXdict will be used as a handle for the dictionary currently in use.
+
+\subsubsection{Dictionary Maintainance Function}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap2}
+$\langle$dicman {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDinitfromfile(char *filename, NXdict *pDict);@\\
+\mbox{}\verb@   NXstatus NXDclose(NXdict handle, char *filename);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDadd(NXdict handle, char *alias, char *DefString);@\\
+\mbox{}\verb@   NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int iBufLen);@\\
+\mbox{}\verb@   NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal);@\\
+\mbox{}\verb@   NXstatus NXDtextreplace(NXdict handle, char *pDefString, char *pBuffer,@\\
+\mbox{}\verb@                           int iBuflen);@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+{\bf NXDinitfromfile} creates a new NeXus dictionary. If filename is NULL, this
+  is all that happens. If filename is not NULL, it will be opened and the
+  dictionary will be initialized from the file specified.  The return value
+  is either 0 for failure or non zero for success. 
+
+  {\bf NXDclose} deletes and writes a NeXus dictionary. If filename is not NULL,
+  the dictionary specified by handle is written to the file specified by
+  filename. In any case the dictionary specified by handle will be deleted.
+
+  {\bf NXDadd} adds a new alias -- Definition String pair to the dictionary
+  specified by handle.
+
+  {\bf NXDget} retrieves the definition string for the alias specified as
+  the second parameter from the dictionary handle. The definition string
+  is copied to pBuffer. Maximum iBufLen characters will be copied.
+
+  {\bf NXDupdate} replaces the definition for the alias specified as second
+ parameter with the new value supplied as last parameter.
+  
+  If a special dictionary vGroup as extension to NeXus would be accepted,
+  two more functions need to be defined which read and write the dictionary 
+  from the NeXus file.
+
+ {\bf NXDtextreplace} resolves any text replacements in the definition
+ string pDefString. Maximum iBuflen characters of replacement results will
+ be copied into the buffer variable. 
+
+\subsubsection{Data Handling functions}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap3}
+$\langle$dicdata {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDputalias(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, void *pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDgetalias(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDaliaslink(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                         char *pAlias1, char *pAlias2);@\\
+\mbox{}\verb@   NXstatus NXDdeflink(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                         char *pDef1, char *pDef2);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDopenalias(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                        char *alias);@\\
+\mbox{}\verb@   NXstatus NXDopendef(NXhandle file, NXdict dict, char *pDefString);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The NXDICT data handling functions go in pairs. The version ending in
+ alias expects an NXdict and an alias as input. These routines work
+ out the pass from that. These routines also resolve all text replacement 
+ operations automatically. The other version ending on def acts upon 
+ a definition string specified as second parameter. Using this scheme
+ both full dictionary operation is possible, as well as operation with
+ program generated definition strings. All routines return the
+ usual NeXus status returns. All these routines start at the current vGroup
+ level and return back to it.  
+
+ NXDputalias, NXDputdef write the data element specified by the alias or
+ the definition string to the NeXus file specified as first parameter. 
+ pData is a pointer to the data to be written. These routines will check for
+ the existence of all vGroups required in the path part of the definition
+ string. If a vGroup  is missing it will be created. These routines step
+ back to the same vGroup level from which they were called.
+
+ NXDgetalias, NXDgetdef read a data item from file. pData MUST point to a
+ data area large enough to hold the data read. If a vGroup is missing in
+ the path for one of these routines an error is generated because it is 
+ assumed that the data is present if a program wants to read it. These 
+ routines step
+ back to the same vGroup level from which they were called.
+ 
+ NXDaliaslink, NXDdeflink links the alias or definition given as fourth
+ parameter to the vGroup specified by the  third parameter. pAlias1 or
+ pDef1 MUST refer to a vGroup (we cannot link to a SDS, can't we?). The
+ item being linked against MUST exist, otherwise the software will complain.
+ The vGroup into which the link is installed will be created on the fly,
+ if not present.
+ Please note, that bot aliases or definition strings specified need to
+ start from the same vGroup position.  These routines step
+ back to the same vGroup level from which they were called. 
+
+ NXDopenalias, NXDopendef open the specified data items specified by the
+ alias or the definition string. Then the usual NeXus functions can be 
+ used to interact with the data. These routines use the same scheme for
+ creating vGroups on the fly as the put routines above. The status in the
+ vGroup hierarchy after this call is dependent on the nature of the terminal
+ symbol. If it is a SDS, the vGroup hierarchy will be stepped back to the
+ level from which the call occurred. The SDS will be left open. If the
+ terminal symbol is a vGroup, then the this vGroup will be made the current
+ vGroup. No back stepping occurs. 
+
+
+  
+  \subsection{NeXus Utility Functions}
+  This section list a couple of functions which either perform common 
+   tasks on NeXus files or relate
+  to aspects of error handling and debugging.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap4}
+$\langle$dicutil {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@        NXstatus NXUwriteglobals(NXhandle file, @\\
+\mbox{}\verb@                            char *filename,@\\
+\mbox{}\verb@                            char *owner,@\\
+\mbox{}\verb@                            char *adress,@\\
+\mbox{}\verb@                            char *phone,@\\
+\mbox{}\verb@                            char *email,@\\
+\mbox{}\verb@                            char *fax,@\\
+\mbox{}\verb@                            char *thing);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class);@\\
+\mbox{}\verb@   NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, @\\
+\mbox{}\verb@                          int rank, int dim[], char *pUnits);@\\
+\mbox{}\verb@   @\\
+\mbox{}\verb@   NXstatus NXUallocSDS(NXhandle hFil, void **pData);@\\
+\mbox{}\verb@   NXstatus NXUfreeSDS(void **pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+{\bf NXUwriteglobals} writes the global attributes to a newly opened 
+ NeXus file. The parameters should be self explaining. In addition 
+ the file creation date is automatically written.
+
+
+ {\bf NXUentergroup} tries to open the group specified by name and class.
+ If it not present, it will be created and opened.
+
+ {\bf NXUenterdata} tries to open the SDS specified by label.
+ If it not present, it will be created and opened.
+
+  {\bf NXUallocSDS} allocates enough space for the currently open SDS. The
+  pointer created is returned in pData. 
+
+  {\bf NXUfreeSDS} returns memory allocated by NXUallocSDS to the system.
+
+
+\section{Implementation}
+\subsection{The NXDICT Data Structure}
+The NXDICT--API is based on a dictionary which maps an alias to a definition
+string in NXDDL. Clearly, the first thing needed is a dictionary which maps
+key string to value strings. It was chosen to use an existing string
+dictionary (developed for SICS) as the dictionary for the NXDICT--API. This
+is realised and documented in files stringdict.*. This string dictionary is
+based on a linked list implementation available in the public domain (Files
+lld.*). This is not the most efficient approach as any search requires
+searching at maximum the whole linked list via strcmp. More efficient
+dictionaries would use hash tables or binary trees. However, implementation
+of a more efficient dictionary will be    delayed until it is proven that
+the current approach poses a serious performance problem.  
+
+Thus, the NXdict data structure looks like this:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap5}
+$\langle$dicdat {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@    typedef struct __NXdict@\\
+\mbox{}\verb@                           {@\\
+\mbox{}\verb@                               int iID;@\\
+\mbox{}\verb@                               pStringDict pDictionary;@\\
+\mbox{}\verb@                           } sNXdict;@\\
+\mbox{}\verb@/*------------------ verbosity level -------------------------------------*/@\\
+\mbox{}\verb@   static int iVerbosity = 0 ;@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The first data member is a magic ID number which will be used for testing
+pointers passed in as NXdict pointers. C permits any pointer to be passed
+here. But only those with the correct magic number will be accepted. The
+next data member is a pointer to the string dictionary used for implementing
+the dictionary.
+
+Another feature is the verbosity level. This one is declared as a file
+static in order to be available generally.
+
+\subsection{The Dictionary Maintainance Functions}
+\subsubsection{NXDinitfromfile}
+This routine starts off by creating and initializing a new NXdict structure:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap6}
+$\langle$iniini {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* allocate a new NXdict structure */@\\
+\mbox{}\verb@     if(iVerbosity == NXalot)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         NXIReportError(NXpData, "Allocating new NXdict structure ");@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     pNew = (NXdict)malloc(sizeof(sNXdict));@\\
+\mbox{}\verb@     if(!pNew)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* initialise it */@\\
+\mbox{}\verb@     pNew->iID = NXDMAGIC;@\\
+\mbox{}\verb@     pNew->pDictionary = CreateStringDict();@\\
+\mbox{}\verb@     if(!pNew->pDictionary)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");@\\
+\mbox{}\verb@         free(pNew);@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The next step is to check for the existence of a filename. If filename is
+NULL we are done:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap7}
+$\langle$inicheck {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* is there a file name argument */@\\
+\mbox{}\verb@     if(filename == NULL)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        if(iVerbosity == NXalot)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           NXIReportError(NXpData, "NXDinitfrom file finished without data");@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        *pData = pNew;@\\
+\mbox{}\verb@        return NX_OK;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The next step is to open the file:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap8}
+$\langle$inifil {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@      fd = fopen(filename,"rb");@\\
+\mbox{}\verb@      if(!fd)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@         sprintf(pError,"ERROR: file %s NOT found ",filename);@\\
+\mbox{}\verb@         NXIReportError(NXpData, pError);@\\
+\mbox{}\verb@         NXIReportError(NXpData, "NXDinitfrom file finished without data");@\\
+\mbox{}\verb@         *pData = pNew;@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Now this file needs to be parsed and the alias -- definition string pairs to
+be extracted. This is done in two steps: First the file contents is copied
+in a buffer. Then this buffer is parsed. This aproach has the advantage that
+the parsing code can be reused if another source for the dictionary
+definition shows up. For instance if it is decided to include it with the
+NeXus file in a special vGroup. 
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap9}
+$\langle$iniparse {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* read the file contents */@\\
+\mbox{}\verb@       if(iVerbosity == NXalot)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          NXIReportError(NXpData, "NXDinitfrom: reading file");@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       pBuffer = NXDIReadFile(fd);@\\
+\mbox{}\verb@       fclose(fd); /* we are done with it then */@\\
+\mbox{}\verb@       if(!pBuffer)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sprintf(pError,"ERROR: reading file %s or no memory",filename);@\\
+\mbox{}\verb@         NXIReportError(NXpData, pError);@\\
+\mbox{}\verb@         NXIReportError(NXpData, "NXDinitfrom file finished without data");@\\
+\mbox{}\verb@         *pData = pNew;@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* parse it */@\\
+\mbox{}\verb@       if(iVerbosity == NXalot)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          NXIReportError(NXpData, "NXDinitfrom: parsing dictionary definitions");@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       NXDIParse(pBuffer, pNew->pDictionary);@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Once this has been done, the task left is to clean up and exit.  
+
+\paragraph{NXDIReadFile}
+This is an internal function which determines the length of the file,
+allocates a suitable buffer for it and then reads the file in the buffer.
+Please note, that the code for determining the length of the file works
+nicely on a Unix or DOS. On a VMS however, there might be a few rubbish
+characters at the end of the buffer. This is due to the record structure of
+files under VMS. 
+
+\paragraph{NXDIParse}
+NXDIParse is an internal function which parses a buffer into aliases and
+values. It is one of two parsers in the nxdict system. Later on there will
+be a definition string parser.  This file reading parser uses a 
+Tokenizer.
+
+The Tokenizer does not need to recognize a lot of
+tokens, so it is rather simple. NXDIfNextToken returns a pointer pointing to
+the character after the last token read. pPtr is the current position in
+the buffer. The value of the last token read will be returned in the buffer
+pToken. iToken will be set to the type of token recognized.
+  
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap10}
+$\langle$ftoken {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@#define FWORD 1@\\
+\mbox{}\verb@#define FHASH 2@\\
+\mbox{}\verb@#define FEOL  3@\\
+\mbox{}\verb@#define FEOB  4@\\
+\mbox{}\verb@#define FEQUAL 5@\\
+\mbox{}\verb@#define FSLASH 6@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   static char *NXDIfNextToken(char *pPtr, char *pToken, int *iToken)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       pToken[0] = '\0';@\\
+\mbox{}\verb@       /* skip whitespace */@\\
+\mbox{}\verb@       while( (*pPtr == ' ') || (*pPtr == '\t') )@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         pPtr++;@\\
+\mbox{}\verb@       } @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* check for special characters */@\\
+\mbox{}\verb@       if(*pPtr == '#')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         *iToken = FHASH;@\\
+\mbox{}\verb@         pToken[0] = *pPtr;@\\
+\mbox{}\verb@         pPtr++;@\\
+\mbox{}\verb@         return pPtr;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*pPtr == '\n')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         *iToken = FEOL;@\\
+\mbox{}\verb@         pToken[0] = *pPtr;@\\
+\mbox{}\verb@         pPtr++;@\\
+\mbox{}\verb@         return pPtr;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*pPtr == '\0')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         *iToken = FEOB;@\\
+\mbox{}\verb@         pToken[0] = *pPtr;@\\
+\mbox{}\verb@         pPtr++;@\\
+\mbox{}\verb@         return pPtr;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*pPtr == '=')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         *iToken = FEQUAL;@\\
+\mbox{}\verb@         pToken[0] = *pPtr;@\\
+\mbox{}\verb@         pPtr++;@\\
+\mbox{}\verb@         return pPtr;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*pPtr == '\\')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         *iToken = FSLASH;@\\
+\mbox{}\verb@         pToken[0] = *pPtr;@\\
+\mbox{}\verb@         pPtr++;@\\
+\mbox{}\verb@         return pPtr;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else @\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         *iToken = FWORD;@\\
+\mbox{}\verb@         /* copy word to pToken */@\\
+\mbox{}\verb@         while( (*pPtr != ' ') && (*pPtr != '\t') && @\\
+\mbox{}\verb@                (*pPtr != '\n') && (*pPtr != '\0') && (*pPtr != '=') )@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@           *pToken = *pPtr;@\\
+\mbox{}\verb@           pPtr++;@\\
+\mbox{}\verb@           pToken++;@\\
+\mbox{}\verb@         } @\\
+\mbox{}\verb@         *pToken = '\0';@\\
+\mbox{}\verb@         return pPtr;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@      /* not reached */@\\
+\mbox{}\verb@      return pPtr;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@    @\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXDIParse has two modes: parsing an alias  or parsing a definition string.
+ 
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap11}
+$\langle$fparse {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@#define AMODE 0@\\
+\mbox{}\verb@#define DMODE 1@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  static void  NXDIParse(char *pBuffer, pStringDict pDict)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     char *pPtr;@\\
+\mbox{}\verb@     int iToken;@\\
+\mbox{}\verb@     int iMode;@\\
+\mbox{}\verb@     char pAlias[132];@\\
+\mbox{}\verb@     char pDefinition[1024]; /* this is > 10 lines of definition */@\\
+\mbox{}\verb@     char pWord[132];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     assert(pBuffer);@\\
+\mbox{}\verb@     assert(pDict);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     iMode = AMODE;@\\
+\mbox{}\verb@     pPtr = pBuffer;@\\
+\mbox{}\verb@     iToken = -1;@\\
+\mbox{}\verb@     pDefinition[0] = '\0';@\\
+\mbox{}\verb@     pAlias[0] = '\0';@\\
+\mbox{}\verb@     pWord[0] = '\0';@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     while(iToken != FEOB)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         pPtr = NXDIfNextToken(pPtr,pWord,&iToken);@\\
+\mbox{}\verb@         switch(iToken)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@           case FHASH:@\\
+\mbox{}\verb@           case FSLASH: /* skip over \n to next non blank */@\\
+\mbox{}\verb@                       while(*pPtr != '\n')@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                          pPtr++;@\\
+\mbox{}\verb@                          /* check for end of file */@\\
+\mbox{}\verb@                          if(*pPtr == '\0')@\\
+\mbox{}\verb@                          {@\\
+\mbox{}\verb@                            return;@\\
+\mbox{}\verb@                          }@\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       pPtr++;@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@           case FEQUAL: /* do a mode change */@\\
+\mbox{}\verb@                       iMode = DMODE;@\\
+\mbox{}\verb@                       pDefinition[0] = '\0';@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@           case FWORD:@\\
+\mbox{}\verb@                       if(iMode == AMODE)@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                         strcpy(pAlias,pWord);@\\
+\mbox{}\verb@                       }  @\\
+\mbox{}\verb@                       else@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                         strcat(pDefinition,pWord);@\\
+\mbox{}\verb@                         strcat(pDefinition," ");@\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@           case FEOL:@\\
+\mbox{}\verb@                       if(iMode == DMODE)@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                          /* enter in dictionary */@\\
+\mbox{}\verb@                          StringDictAddPair(pDict,pAlias,pDefinition);@\\
+\mbox{}\verb@                          iMode = AMODE;@\\
+\mbox{}\verb@                          pAlias[0] = '\0';@\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@           case FEOB:@\\
+\mbox{}\verb@                       if(iMode == AMODE) @\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                         /* empty line or a problem */@\\
+\mbox{}\verb@                       }          @\\
+\mbox{}\verb@                       else@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                          /* enter in dictionary */@\\
+\mbox{}\verb@                          StringDictAddPair(pDict,pAlias,pDefinition);@\\
+\mbox{}\verb@                          iMode = AMODE;@\\
+\mbox{}\verb@                          pAlias[0] = '\0';@\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       return;@\\
+\mbox{}\verb@           default:@\\
+\mbox{}\verb@                   assert(0); /* unrecognized token is a programming@\\
+\mbox{}\verb@                                 error@\\
+\mbox{}\verb@                              */@\\
+\mbox{}\verb@                   break;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDClose}
+This routine will just write the dictionary to file if requested and clean
+up afterwards. Prior to defining NXDClose anohter internal function is
+needed which checks the validity of the handle passed into the routine.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap12}
+$\langle$dassert {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXdict NXDIAssert(NXdict handle)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      NXdict self = NULL;@\\
+\mbox{}\verb@      assert(handle);@\\
+\mbox{}\verb@      self = (NXdict)handle;@\\
+\mbox{}\verb@      assert(self->iID == NXDMAGIC);@\\
+\mbox{}\verb@      return self;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap13}
+$\langle$dclose {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDclose(NXdict handle, char *filename)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      NXdict self;@\\
+\mbox{}\verb@      const char *pKey = NULL;@\\
+\mbox{}\verb@      char pValue[1024];@\\
+\mbox{}\verb@      FILE *fd = NULL;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      self = NXDIAssert(handle);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      if(filename) /* we must write a file */@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        if(iVerbosity == NXalot)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           sprintf(pValue,"Writing file %s",filename);@\\
+\mbox{}\verb@           NXIReportError(NXpData, pValue);@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        fd = fopen(filename,"w");@\\
+\mbox{}\verb@        if(!fd)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           sprintf(pValue,"ERROR: opening file %s for write",filename);@\\
+\mbox{}\verb@           NXIReportError(NXpData, pValue);@\\
+\mbox{}\verb@           return NX_ERROR;@\\
+\mbox{}\verb@        }   @\\
+\mbox{}\verb@        @\\
+\mbox{}\verb@        /* write our magic recognition header */@\\
+\mbox{}\verb@        fprintf(fd,"##NXDICT-1.0\n");@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        /* write all our keys */@\\
+\mbox{}\verb@        pKey = StringDictGetNext(self->pDictionary, pValue,1023);@\\
+\mbox{}\verb@        while(pKey != NULL)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@          fprintf(fd,"%s = %s\n",pKey,pValue);@\\
+\mbox{}\verb@          pKey = StringDictGetNext(self->pDictionary,pValue,1023);@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        fclose(fd);@\\
+\mbox{}\verb@        if(iVerbosity == NXalot)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           sprintf(pValue,"File %s written",filename);@\\
+\mbox{}\verb@           NXIReportError(NXpData, pValue);@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* now we send the cleaners in */@\\
+\mbox{}\verb@      DeleteStringDict(self->pDictionary);@\\
+\mbox{}\verb@      free(self);@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDadd, NXDget, NXDupdate}
+These are very much only wrapper function around the corresponding functions
+for maintaining StringDicts. Accordingly, they are fairly simple.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap14}
+$\langle$dmaintain {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDadd(NXdict handle, char *alias, char *pDef)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict self;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     self = NXDIAssert(handle);@\\
+\mbox{}\verb@     iRet = StringDictAddPair(self->pDictionary,alias,pDef);@\\
+\mbox{}\verb@     if(!iRet)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@/*---------------------------------------------------------------------------*/@\\
+\mbox{}\verb@   NXstatus NXDget(NXdict handle, char *pKey, char *pBuffer, int iBufLen)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict self;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     self = NXDIAssert(handle);@\\
+\mbox{}\verb@     iRet = StringDictGet(self->pDictionary,pKey,pBuffer,iBufLen);@\\
+\mbox{}\verb@     if(!iRet)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@#ifdef DEFDEBUG@\\
+\mbox{}\verb@     printf("Resolved: %s to %s\n",pKey,pBuffer);@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@   NXstatus NXDupdate(NXdict handle, char *pKey, char *pNewVal)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict self;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     self = NXDIAssert(handle);@\\
+\mbox{}\verb@     iRet = StringDictUpdate(self->pDictionary,pKey,pNewVal);@\\
+\mbox{}\verb@     if(!iRet)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Text replacement}
+A definition string as retrieved from the string dictionary may still
+contain text replacement items. The next function, NXDtextreplace resolves
+these text replacements.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap15}
+$\langle$textrep {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@#define NORMAL 1@\\
+\mbox{}\verb@#define ALIAS  2@\\
+\mbox{}\verb@   pDynString NXDItextreplace(NXdict handle, char *pDefString)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict self;@\\
+\mbox{}\verb@     int iRet, iPos, i;@\\
+\mbox{}\verb@     pDynString pReplaced = NULL;@\\
+\mbox{}\verb@     char pBueffel[1024];@\\
+\mbox{}\verb@     char pBuffer2[1024];@\\
+\mbox{}\verb@     char *pPtr;@\\
+\mbox{}\verb@     int iState;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     self = NXDIAssert(handle);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* create a dynamic string */@\\
+\mbox{}\verb@     pReplaced = CreateDynString(strlen(pDefString),512);@\\
+\mbox{}\verb@     if(!pReplaced)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       NXIReportError(NXpData,"ERROR: out of memory in NXDtextreplace");@\\
+\mbox{}\verb@       return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* the loop */@\\
+\mbox{}\verb@     iState = NORMAL;@\\
+\mbox{}\verb@     for(i = 0, pPtr = pDefString; i < strlen(pDefString); i++,pPtr++)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        if(iState == NORMAL)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           if(*pPtr == '$')@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@             iState = ALIAS;@\\
+\mbox{}\verb@             memset(pBueffel,0,1024);@\\
+\mbox{}\verb@             iPos = 0;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@           else@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@               DynStringConcatChar(pReplaced,*pPtr);@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        else if(iState == ALIAS)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           switch(*pPtr)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@             case '(': /* ignore */@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@             case ')': @\\
+\mbox{}\verb@                       /* do the replacement */@\\
+\mbox{}\verb@                       memset(pBuffer2,0,1023);@\\
+\mbox{}\verb@                       iRet = NXDget(handle, pBueffel,pBuffer2,1023);@\\
+\mbox{}\verb@                       if(iRet != NX_OK)@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                         DeleteDynString(pReplaced);@\\
+\mbox{}\verb@                         return NULL;@\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       DynStringConcat(pReplaced,pBuffer2);@\\
+\mbox{}\verb@                       iState = NORMAL;@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@             default:@\\
+\mbox{}\verb@                       pBueffel[iPos] = *pPtr;@\\
+\mbox{}\verb@                       iPos++;@\\
+\mbox{}\verb@                       if(iPos >= 1024)@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                          NXIReportError(NXpData,@\\
+\mbox{}\verb@                                     "ERROR: buffer overrun in NXDItextreplace");@\\
+\mbox{}\verb@                          DeleteDynString(pReplaced);@\\
+\mbox{}\verb@                          return NULL;@\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@#ifdef DEFDEBUG@\\
+\mbox{}\verb@    printf("Replacement result: %s\n",GetCharArray(pReplaced));@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@     return pReplaced;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@   NXstatus NXDtextreplace(NXdict handle, char *pDefString, @\\
+\mbox{}\verb@                           char *pBuffer, int iBufLen)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     pDynString pResult = NULL;@\\
+\mbox{}\verb@     char *pPtr = NULL;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pResult = NXDItextreplace(handle,pDefString);@\\
+\mbox{}\verb@     if(!pResult)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* copy results home */@\\
+\mbox{}\verb@     pPtr = GetCharArray(pResult);@\\
+\mbox{}\verb@     strncpy(pBuffer,pPtr,iBufLen);   @\\
+\mbox{}\verb@     DeleteDynString(pResult);@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Dictionary Added Data Transfer}
+The heart of these routines is the NXDopendef function which opens the data
+item specified. Most of the other routines can be defined as wrappers to
+this one. That is why it is discussed as the first function. Again a parser
+is needed for parsing and interpreting the definition string. 
+
+\subsubsection{The Definition String Parser}
+The definition string  parser is implemented as a classic recursive descent 
+parser. And once
+more again a Tokenizer is needed. The Tokenizer has an own datastructure for
+holding token information in a static array:
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap16}
+$\langle$tokdat {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  typedef struct {@\\
+\mbox{}\verb@                  char pText[20];@\\
+\mbox{}\verb@                  int iCode;@\\
+\mbox{}\verb@                 }  TokDat;@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+In order to do the parsing a data structure for holding parsing information
+is necessary:
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap17}
+$\langle$padef {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@#define TERMSDS 100@\\
+\mbox{}\verb@#define TERMVG  200@\\
+\mbox{}\verb@#define TERMLINK 300@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   typedef struct {@\\
+\mbox{}\verb@                    char *pPtr;@\\
+\mbox{}\verb@                    char pToken[256];@\\
+\mbox{}\verb@                    int iToken;@\\
+\mbox{}\verb@                    int iDepth;@\\
+\mbox{}\verb@                    int iMayCreate;@\\
+\mbox{}\verb@                    int iTerminal;@\\
+\mbox{}\verb@                  } ParDat;@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+In this structure pPtr is the current position in the buffer, iToken the ID
+of the current token, pToken the text of the current token, iDepth gets
+incremented whenever a vGroup is opened. This is needed in order to roll the
+vGroups back in the hierarchy after finishing operations. iMayCreate will be
+set if the path parsing function may create new vGroups if the one requested
+can not be found.
+
+This is the tokenizer:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap18}
+$\langle$deftok {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------- Token name defines ---------------------------*/@\\
+\mbox{}\verb@#define DSLASH 0@\\
+\mbox{}\verb@#define DKOMMA 1@\\
+\mbox{}\verb@#define DSDS   2@\\
+\mbox{}\verb@#define DLINK  3@\\
+\mbox{}\verb@#define DGROUP 4@\\
+\mbox{}\verb@#define DRANK  5@\\
+\mbox{}\verb@#define DDIM   6@\\
+\mbox{}\verb@#define DTYPE  7@\\
+\mbox{}\verb@#define DWORD  9@\\
+\mbox{}\verb@#define DOPEN  10@\\
+\mbox{}\verb@#define DCLOSE 11@\\
+\mbox{}\verb@#define DATTR  12@\\
+\mbox{}\verb@#define DEND   13@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@/*----------------- Keywords ----------------------------------------*/@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  static TokDat TokenList[8] = { @\\
+\mbox{}\verb@                                {"SDS",DSDS},@\\
+\mbox{}\verb@                                {"NXLINK",DLINK},@\\
+\mbox{}\verb@                                {"NXVGROUP",DGROUP},@\\
+\mbox{}\verb@                                {"-dim",DDIM},@\\
+\mbox{}\verb@                                {"-type",DTYPE},@\\
+\mbox{}\verb@                                {"-rank",DRANK},@\\
+\mbox{}\verb@                                {"-attr",DATTR},@\\
+\mbox{}\verb@                                {NULL,0} };@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
+\mbox{}\verb@   static void NXDIDefToken(ParDat *sStat)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       int i;@\\
+\mbox{}\verb@       @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       sStat->pToken[0] = '\0';@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* skip whitespace */@\\
+\mbox{}\verb@       while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') )@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->pPtr++;@\\
+\mbox{}\verb@       } @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* check for special characters */@\\
+\mbox{}\verb@       if(*(sStat->pPtr) == '/')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->iToken = DSLASH;@\\
+\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
+\mbox{}\verb@         sStat->pPtr++;@\\
+\mbox{}\verb@         return;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*(sStat->pPtr) == ',')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->iToken = DKOMMA;@\\
+\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
+\mbox{}\verb@         sStat->pPtr++;@\\
+\mbox{}\verb@         return;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*(sStat->pPtr) == '\0')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->iToken = DEND;@\\
+\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
+\mbox{}\verb@         sStat->pPtr++;@\\
+\mbox{}\verb@         return;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*(sStat->pPtr) == '{')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->iToken = DOPEN;@\\
+\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
+\mbox{}\verb@         sStat->pPtr++;@\\
+\mbox{}\verb@         return;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else if(*(sStat->pPtr) == '}')@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->iToken = DCLOSE;@\\
+\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
+\mbox{}\verb@         sStat->pPtr++;@\\
+\mbox{}\verb@         return;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       else @\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         sStat->iToken = DWORD;@\\
+\mbox{}\verb@         /* copy word to pToken */@\\
+\mbox{}\verb@         i = 0;@\\
+\mbox{}\verb@         while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') && @\\
+\mbox{}\verb@                (*(sStat->pPtr) != '/') && (*(sStat->pPtr) != '\0') &&@\\
+\mbox{}\verb@                (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') )@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@           sStat->pToken[i] = *(sStat->pPtr);@\\
+\mbox{}\verb@           sStat->pPtr++;@\\
+\mbox{}\verb@           i++;@\\
+\mbox{}\verb@         } @\\
+\mbox{}\verb@         sStat->pToken[i] = '\0';@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@         /*--------- try to find word in Tokenlist */@\\
+\mbox{}\verb@         for(i = 0; i < 7; i++)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@           if(strcmp(sStat->pToken,TokenList[i].pText) == 0)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@             sStat->iToken = TokenList[i].iCode;@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@         return;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@      /* not reached */@\\
+\mbox{}\verb@      return;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Now, finally we can define the parser! This parser is universally used by
+all the data transfer functions.  Input is the file handle of the NeXus file
+and a pointer to an initialised ParDat structure. It is expected, that the
+pPtr field points to the start of the definition string, that iMayCreate is
+properly defined and that iDepth is 0. 
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap19}
+$\langle$defpar {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@    static int NXDIDefParse(NXhandle hFil, NXdict pDict, ParDat *pParse)@\\
+\mbox{}\verb@    {@\\
+\mbox{}\verb@       int iRet;@\\
+\mbox{}\verb@       char pError[256];@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@       pParse->iToken = -1;@\\
+\mbox{}\verb@       while(pParse->iToken != DEND)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         NXDIDefToken(pParse); /* next token */@\\
+\mbox{}\verb@         switch(pParse->iToken)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            case DEND:@\\
+\mbox{}\verb@                      break;@\\
+\mbox{}\verb@            case DSLASH:@\\
+\mbox{}\verb@                      iRet = NXDIParsePath(hFil, pParse);@\\
+\mbox{}\verb@                      if(iRet == NX_ERROR)@\\
+\mbox{}\verb@                      {@\\
+\mbox{}\verb@                         return NX_ERROR;@\\
+\mbox{}\verb@                      }@\\
+\mbox{}\verb@                      break;@\\
+\mbox{}\verb@            case DSDS:@\\
+\mbox{}\verb@                      iRet = NXDIParseSDS(hFil, pParse);@\\
+\mbox{}\verb@                      if(iRet == NX_ERROR)@\\
+\mbox{}\verb@                      {@\\
+\mbox{}\verb@                         return NX_ERROR;@\\
+\mbox{}\verb@                      }@\\
+\mbox{}\verb@                      pParse->iTerminal = TERMSDS;@\\
+\mbox{}\verb@                      break;@\\
+\mbox{}\verb@            case DLINK:@\\
+\mbox{}\verb@                      iRet = NXDIParseLink(hFil,pDict, pParse);                      @\\
+\mbox{}\verb@                      if(iRet == NX_ERROR)@\\
+\mbox{}\verb@                      {@\\
+\mbox{}\verb@                         return NX_ERROR;@\\
+\mbox{}\verb@                      }@\\
+\mbox{}\verb@                      pParse->iTerminal = TERMLINK;@\\
+\mbox{}\verb@                      break;@\\
+\mbox{}\verb@            case DGROUP:@\\
+\mbox{}\verb@                      pParse->iTerminal = TERMVG;@\\
+\mbox{}\verb@                      return NX_OK;@\\
+\mbox{}\verb@            default:@\\
+\mbox{}\verb@                     sprintf(pError,@\\
+\mbox{}\verb@            "ERROR: Definition String parse error: %s not permitted here",@\\
+\mbox{}\verb@             pParse->pToken);@\\
+\mbox{}\verb@                     NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@                     return NX_ERROR;@\\
+\mbox{}\verb@                     break;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@    }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The next thing to do is to implement ParsePath. This will try to interpret a
+path string and initiate the apropriate actions, i.e. opening vGroups or
+creating them. However, there is a small problem here. The code needs to
+know if the vGroup exists. This can be checked by trying to open the group
+with NXopengroup. This will return an error if this group does not exist.
+NXopengroup will also print an error message saying so. This is not what is
+wanted here, as we might choose to create the missing group silently.
+ In order to suppress
+that one, it is needed to replace the current error handler by a dummy which
+just prints nothing anywhere and to step back to the original handler once
+we are done. The other option would be to use internals of the NeXus API
+implementation. However, the aim is to keep the original NeXus API and this
+as independent as possible.  Consequently, here is the definition of the
+dummy error handler:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap20}
+$\langle$dummyerr {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static void DummyError(void *pData, char *pError)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     return;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+When NXDIParsePath has been called the / has already been read.
+NXDIParsePath has to read the name and class of the vGroup separated by a
+komma. Then it has either to open the vGroup, and if this fails create it if
+the create flag in pParse is set.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap21}
+$\langle$defpath {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   int NXDIParsePath(NXhandle hfil, ParDat *pParse)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       int iRet, iToken;@\\
+\mbox{}\verb@       void (*ErrFunc)(void *pData, char *pErr); @\\
+\mbox{}\verb@       char pName[132], pClass[132];@\\
+\mbox{}\verb@       char pError[256];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* get the name */@\\
+\mbox{}\verb@       NXDIDefToken(pParse); /* next token */@\\
+\mbox{}\verb@       if( (pParse->iToken == DSDS) || (pParse->iToken == DGROUP)@\\
+\mbox{}\verb@           || (pParse->iToken == DLINK) )@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         /* put back & OK */@\\
+\mbox{}\verb@         pParse->pPtr -= strlen(pParse->pToken);@\\
+\mbox{}\verb@         return NX_OK;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          sprintf(pError,"ERROR: parse error at %s, expected vGroup name",@\\
+\mbox{}\verb@                  pParse->pToken);@\\
+\mbox{}\verb@          NXIReportError(NXpData, pError);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@       }       @\\
+\mbox{}\verb@       strcpy(pName,pParse->pToken);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@       /* now we expect a komma */@\\
+\mbox{}\verb@       NXDIDefToken(pParse); /* next token */@\\
+\mbox{}\verb@       if(pParse->iToken != DKOMMA)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          sprintf(pError,"ERROR: parse error at %s, expected komma",@\\
+\mbox{}\verb@                  pParse->pToken);@\\
+\mbox{}\verb@          NXIReportError(NXpData, pError);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@       }       @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* next must be the class */@\\
+\mbox{}\verb@       NXDIDefToken(pParse); /* next token */@\\
+\mbox{}\verb@       if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          sprintf(pError,"ERROR: parse error at %s, expected vGroup class",@\\
+\mbox{}\verb@                  pParse->pToken);@\\
+\mbox{}\verb@          NXIReportError(NXpData, pError);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@       }       @\\
+\mbox{}\verb@       strcpy(pClass,pParse->pToken);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* done reading, ACTION, first install dummy error handler */@\\
+\mbox{}\verb@       ErrFunc = NXIReportError;@\\
+\mbox{}\verb@       NXMSetError(NXpData, DummyError);@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@       /* try opening vGroup */@\\
+\mbox{}\verb@       iRet = NXopengroup(hfil, pName, pClass);@\\
+\mbox{}\verb@       NXMSetError(NXpData,ErrFunc);@\\
+\mbox{}\verb@       if(iRet == NX_OK)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         pParse->iDepth++;@\\
+\mbox{}\verb@         return NX_OK;@\\
+\mbox{}\verb@       } @\\
+\mbox{}\verb@       else@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          /* we need to create it, if we may */@\\
+\mbox{}\verb@          if(pParse->iMayCreate)@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@            iRet = NXmakegroup(hfil,pName,pClass);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            iRet = NXopengroup(hfil,pName,pClass);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            pParse->iDepth++;@\\
+\mbox{}\verb@            return NX_OK; @\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@          else@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@             /* this is an error */@\\
+\mbox{}\verb@             sprintf(pError,"ERROR: vGroup %s, %s NOT found",pName, pClass);@\\
+\mbox{}\verb@             NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@             return NX_ERROR;@\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       /* not reached */@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXDIParseSDS is more involved, as we have to deal with all the extras an SDS
+can have: dimensions, types etc. Each of these options can be present or
+not, and these options can go in any order. Particularly troublesome are
+attributes which can only be written after opening or creating an SDS. this
+implies that attributes have to be stored in a list during parsing in order
+to have them available after creation or opening of the SDS. This requires
+another private data structure for holding attribute information during
+parsing:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap22}
+$\langle$attitem {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  typedef struct {@\\
+\mbox{}\verb@                   char name[256];@\\
+\mbox{}\verb@                   char value[256];@\\
+\mbox{}\verb@                  }AttItem;@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap23}
+$\langle$nxpasds {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int NXDIParseSDS(NXhandle hfil, ParDat *pParse)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      int iType = DFNT_FLOAT32;@\\
+\mbox{}\verb@      int iRank = 1;@\\
+\mbox{}\verb@      int32 iDim[MAX_VAR_DIMS];@\\
+\mbox{}\verb@      int iList;@\\
+\mbox{}\verb@      int iRet, iStat;@\\
+\mbox{}\verb@      char pError[256];@\\
+\mbox{}\verb@      char pName[MAX_NC_NAME];@\\
+\mbox{}\verb@      void (*ErrFunc)(void *pData, char *pErr);@\\
+\mbox{}\verb@      AttItem sAtt; @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       iDim[0] = 1;@\\
+\mbox{}\verb@       /* first find the name */@\\
+\mbox{}\verb@       NXDIDefToken(pParse);@\\
+\mbox{}\verb@       if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          sprintf(pError,"ERROR: parsing, expected name, got %s",@\\
+\mbox{}\verb@                  pParse->pToken);@\\
+\mbox{}\verb@          NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@        strcpy(pName,pParse->pToken);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* create the attribute list */@\\
+\mbox{}\verb@       iList = LLDcreate(sizeof(AttItem));@\\
+\mbox{}\verb@       if(iList < 0)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          NXIReportError(NXpData, "ERROR: cannot create list in NXDIParseSDS");@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       NXDIDefToken(pParse);@\\
+\mbox{}\verb@       while(pParse->iToken != DEND)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          switch(pParse->iToken)@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@            case DRANK: /* rank */@\\
+\mbox{}\verb@                       NXDIDefToken(pParse); /* advance */@\\
+\mbox{}\verb@                       if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@                       {@\\
+\mbox{}\verb@                         sprintf(pError,@\\
+\mbox{}\verb@                         "ERROR: expected int, got %s", pParse->pToken);@\\
+\mbox{}\verb@                          NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@                          LLDdelete(iList);@\\
+\mbox{}\verb@                          return NX_ERROR; @\\
+\mbox{}\verb@                       }@\\
+\mbox{}\verb@                       iRank = atoi(pParse->pToken);@\\
+\mbox{}\verb@                       break;@\\
+\mbox{}\verb@            case DDIM:@\\
+\mbox{}\verb@                     iRet = NXDIParseDim(pParse, iDim);@\\
+\mbox{}\verb@                     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@                     {@\\
+\mbox{}\verb@                        LLDdelete(iList);@\\
+\mbox{}\verb@                        return iRet;@\\
+\mbox{}\verb@                     } @\\
+\mbox{}\verb@                     break;@\\
+\mbox{}\verb@            case DTYPE:@\\
+\mbox{}\verb@                     iRet = NXDIParseType(pParse, &iType);@\\
+\mbox{}\verb@                     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@                     {@\\
+\mbox{}\verb@                        LLDdelete(iList);@\\
+\mbox{}\verb@                        return iRet;@\\
+\mbox{}\verb@                     } @\\
+\mbox{}\verb@                     break;@\\
+\mbox{}\verb@            case DATTR:@\\
+\mbox{}\verb@                     iRet = NXDIParseAttr(pParse, iList);@\\
+\mbox{}\verb@                     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@                     {@\\
+\mbox{}\verb@                        LLDdelete(iList);@\\
+\mbox{}\verb@                        return iRet;@\\
+\mbox{}\verb@                     } @\\
+\mbox{}\verb@                     break;@\\
+\mbox{}\verb@            case DEND:@\\
+\mbox{}\verb@                     break;@\\
+\mbox{}\verb@            default:@\\
+\mbox{}\verb@                     sprintf(pError,"ERROR: cannot identify token %s",@\\
+\mbox{}\verb@                                     pParse->pToken);@\\
+\mbox{}\verb@                     NXIReportError(NXpData, pError);@\\
+\mbox{}\verb@                     LLDdelete(iList);@\\
+\mbox{}\verb@                     return NX_ERROR;@\\
+\mbox{}\verb@                    @\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@          NXDIDefToken(pParse);@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       @\\
+\mbox{}\verb@       /* whew! got all information for doing the SDS */@\\
+\mbox{}\verb@       /* first install dummy error handler, try open it, then@\\
+\mbox{}\verb@          deinstall again and create if allowed @\\
+\mbox{}\verb@       */@\\
+\mbox{}\verb@       ErrFunc = NXIReportError;@\\
+\mbox{}\verb@       NXMSetError(NXpData, DummyError);@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@       /* try opening SDS */@\\
+\mbox{}\verb@       iRet = NXopendata(hfil, pName);@\\
+\mbox{}\verb@       NXMSetError(NXpData,ErrFunc);@\\
+\mbox{}\verb@       if(iRet == NX_OK)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         LLDdelete(iList);@\\
+\mbox{}\verb@         return NX_OK;@\\
+\mbox{}\verb@       } @\\
+\mbox{}\verb@       else@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          /* we need to create it, if we may */@\\
+\mbox{}\verb@          if(pParse->iMayCreate)@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@            iRet = NXmakedata(hfil,pName,iType, iRank,iDim);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 LLDdelete(iList);@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            iRet = NXopendata(hfil,pName);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 LLDdelete(iList);@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            /* put attributes in */@\\
+\mbox{}\verb@            iRet = LLDnodePtr2First(iList);@\\
+\mbox{}\verb@            while(iRet != 0)@\\
+\mbox{}\verb@            {@\\
+\mbox{}\verb@              LLDnodeDataTo(iList,&sAtt);@\\
+\mbox{}\verb@              iStat = NXputattr(hfil,sAtt.name,@\\
+\mbox{}\verb@                                sAtt.value,strlen(sAtt.value),NX_CHAR);@\\
+\mbox{}\verb@              if(iStat != NX_OK)@\\
+\mbox{}\verb@              {@\\
+\mbox{}\verb@                 /* NeXus already complained bitterly */@\\
+\mbox{}\verb@                 LLDdelete(iList);@\\
+\mbox{}\verb@                 return iStat;@\\
+\mbox{}\verb@              }@\\
+\mbox{}\verb@              iRet = LLDnodePtr2Next(iList);@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            LLDdelete(iList);@\\
+\mbox{}\verb@            return NX_OK; @\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@          else@\\
+\mbox{}\verb@          {@\\
+\mbox{}\verb@             /* this is an error */@\\
+\mbox{}\verb@             sprintf(pError,"ERROR: SDS %s NOT found",pName);@\\
+\mbox{}\verb@             NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@             LLDdelete(iList);@\\
+\mbox{}\verb@             return NX_ERROR;@\\
+\mbox{}\verb@          }@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXDIParseType is fairly straightforward: read a word and try to interpret it 
+as one of the standard NeXus data types.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap24}
+$\langle$parsetype {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static TokDat tDatType[] = {@\\
+\mbox{}\verb@                      {"DFNT_FLOAT32",DFNT_FLOAT32},   @\\
+\mbox{}\verb@                      {"DFNT_FLOAT64",DFNT_FLOAT64},    @\\
+\mbox{}\verb@                      {"DFNT_INT8",DFNT_INT8},  @\\
+\mbox{}\verb@                      {"DFNT_UINT8",DFNT_UINT8},@\\
+\mbox{}\verb@                      {"DFNT_INT16",DFNT_INT16},      @\\
+\mbox{}\verb@                      {"DFNT_UINT16",DFNT_UINT16},@\\
+\mbox{}\verb@                      {"DFNT_INT32",DFNT_INT32},@\\
+\mbox{}\verb@                      {"DFNT_UINT32",DFNT_UINT32},@\\
+\mbox{}\verb@                      {NULL,-122} };@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int NXDIParseType(ParDat *pParse, int *iType)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      char pError[256];@\\
+\mbox{}\verb@      int i = 0;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      NXDIDefToken(pParse);@\\
+\mbox{}\verb@      if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@      { @\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected data type, got %s", pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@       @\\
+\mbox{}\verb@      /* try to interpret data type */@\\
+\mbox{}\verb@      while(tDatType[i].iCode > 0) {@\\
+\mbox{}\verb@        if(strcmp(tDatType[i].pText,pParse->pToken) == 0)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           *iType = tDatType[i].iCode;@\\
+\mbox{}\verb@            return NX_OK;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        i++;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      /* if we are here, the data type has not been recognized. Reason for@\\
+\mbox{}\verb@         some boring error reporting code@\\
+\mbox{}\verb@      */@\\
+\mbox{}\verb@      sprintf(pError,"ERROR: %s not recognized as valid data type",@\\
+\mbox{}\verb@                      pParse->pToken);@\\
+\mbox{}\verb@      NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@      return NX_ERROR;      @\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXDIParseDim tries to read dimension information. This starts with a {
+followed by numbers and kommas until there is a closing curly brace.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap25}
+$\langle$parsedim {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int NXDIParseDim(ParDat *pParse, int *iDim)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       char pError[256];@\\
+\mbox{}\verb@       int iRet, i;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        /* initialise dimensions to 0 */@\\
+\mbox{}\verb@        for(i = 0; i < MAX_VAR_DIMS; i++)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@          iDim[i] = 0;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        NXDIDefToken(pParse);@\\
+\mbox{}\verb@        if(pParse->iToken != DOPEN)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@          sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);@\\
+\mbox{}\verb@          NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@        i = 0;      @\\
+\mbox{}\verb@        while(pParse->iToken != DCLOSE)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@           /* get a number */@\\
+\mbox{}\verb@           NXDIDefToken(pParse);@\\
+\mbox{}\verb@           if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@              sprintf(pError,"ERROR: expected number, got %s",pParse->pToken);@\\
+\mbox{}\verb@              NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@              return NX_ERROR;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@           iDim[i] = atoi(pParse->pToken);@\\
+\mbox{}\verb@           i++;@\\
+\mbox{}\verb@           /* next must be close of komma */@\\
+\mbox{}\verb@           NXDIDefToken(pParse);@\\
+\mbox{}\verb@           if( (pParse->iToken != DKOMMA) && (pParse->iToken != DCLOSE) )@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@              sprintf(pError,"ERROR: expected , or }, got %s",pParse->pToken);@\\
+\mbox{}\verb@              NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@              return NX_ERROR;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@           if(pParse->iToken == DCLOSE)@\\
+\mbox{}\verb@           {@\\
+\mbox{}\verb@              break;@\\
+\mbox{}\verb@           }@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@        return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXDIParseAttr tries to parse an attribute and enters it into the attribute
+list.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap26}
+$\langle$parseatt {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int NXDIParseAttr(ParDat *pParse, int iList)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     char pError[256];@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@     AttItem sAtt;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* a { is expected */@\\
+\mbox{}\verb@     NXDIDefToken(pParse);@\\
+\mbox{}\verb@     if(pParse->iToken != DOPEN)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* a word is expected */@\\
+\mbox{}\verb@     NXDIDefToken(pParse);@\\
+\mbox{}\verb@     if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected attribute name, got %s",pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     strcpy(sAtt.name,pParse->pToken);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* a , is expected */@\\
+\mbox{}\verb@     NXDIDefToken(pParse);@\\
+\mbox{}\verb@     if(pParse->iToken != DKOMMA)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected , , got %s",pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* a word is expected */@\\
+\mbox{}\verb@     NXDIDefToken(pParse);@\\
+\mbox{}\verb@     if(pParse->iToken != DWORD)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected attribute value, got %s",pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     strcpy(sAtt.value,pParse->pToken);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* a } is expected */@\\
+\mbox{}\verb@     NXDIDefToken(pParse);@\\
+\mbox{}\verb@     if(pParse->iToken != DCLOSE)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected }, got %s",pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* enter into list */@\\
+\mbox{}\verb@     LLDnodeAppendFrom(iList,&sAtt);@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The last part of the definition string parser is NXDIParseLink. This
+function parses and handles a link to another data item in the file.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap27}
+$\langle$parselink {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   static int NXDIParseLink(NXhandle hfil, NXdict pDict,ParDat *pParse)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     char pError[256];@\\
+\mbox{}\verb@     int i, iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* need one word of alias */ @\\
+\mbox{}\verb@     NXDIDefToken(pParse);@\\
+\mbox{}\verb@     if(pParse->iToken != DCLOSE)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pError,"ERROR: expected alias , got %s",pParse->pToken);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@    @\\
+\mbox{}\verb@     /* move back in hierarchy */@\\
+\mbox{}\verb@     for(i = 0; i < pParse->iDepth; i++)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       iRet = NXclosegroup(hfil);@\\
+\mbox{}\verb@       if(iRet == NX_ERROR)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* open the link instead */ @\\
+\mbox{}\verb@     return NXDopenalias(hfil, pDict, pParse->pToken);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Another helper function unwinds the vGroup hierarchy.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap28}
+$\langle$unwind {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  static NXstatus NXDIUnwind(NXhandle hFil, int iDepth)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     int i, iRet;@\\
+\mbox{}\verb@      @\\
+\mbox{}\verb@     for(i = 0; i < iDepth; i++)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        iRet = NXclosegroup(hFil);@\\
+\mbox{}\verb@        if(iRet != NX_OK)@\\
+\mbox{}\verb@        {@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@        }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDopendef}
+NXDopendef calls the definiton string parser and then just steps back in the
+vGroup hierarchy and stays there.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap29}
+$\langle$nxddefopen {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDopendef(NXhandle hfil, NXdict dict, char *pDef)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     ParDat pParse;@\\
+\mbox{}\verb@     int iRet, i, iStat;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* parse and act on definition string */@\\
+\mbox{}\verb@     pParse.iMayCreate = 1;@\\
+\mbox{}\verb@     pParse.pPtr = pDef;@\\
+\mbox{}\verb@     pParse.iDepth = 0;@\\
+\mbox{}\verb@     iRet = NXDIDefParse(hfil,pDict,&pParse);@\\
+\mbox{}\verb@     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         /* unwind and throw up */@\\
+\mbox{}\verb@         iRet = NXDIUnwind(hfil,pParse.iDepth);@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* try rewinding the hierarchy */@\\
+\mbox{}\verb@     if(pParse.iTerminal == TERMSDS)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         iStat = NXDIUnwind(hfil,pParse.iDepth);@\\
+\mbox{}\verb@         if(iStat != NX_OK)@\\
+\mbox{}\verb@         {@\\
+\mbox{}\verb@            return NX_ERROR;@\\
+\mbox{}\verb@         }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     /* do not rewind on links */@\\
+\mbox{}\verb@     return iRet;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDopenalias}
+NXDOpenalias is just a wrapper around  NXDopendef which retrieves a
+definition string from the directory first.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap30}
+$\langle$nxdaliasopen {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDopenalias(NXhandle hfil, NXdict dict, char *pAlias)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@     char pDefinition[1024];@\\
+\mbox{}\verb@     pDynString pReplaced = NULL;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* get Definition String  */@\\
+\mbox{}\verb@     iRet = NXDget(pDict,pAlias,pDefinition,1023);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pDefinition);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* do the text replacement */@\\
+\mbox{}\verb@     pReplaced = NXDItextreplace(dict,pDefinition);@\\
+\mbox{}\verb@     if(!pReplaced)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* call NXDopendef */@\\
+\mbox{}\verb@     iRet = NXDopendef(hfil,dict,GetCharArray(pReplaced));@\\
+\mbox{}\verb@     DeleteDynString(pReplaced);@\\
+\mbox{}\verb@     return iRet;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDputdef}
+This routine puts a data item into a NeXus file using a definition string.
+This naturally can work only, if there is an SDS at the end.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap31}
+$\langle$nxput {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDputdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     ParDat pParse;@\\
+\mbox{}\verb@     int iRet, i, iStat;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* parse and act on definition string */@\\
+\mbox{}\verb@     pParse.iMayCreate = 1;@\\
+\mbox{}\verb@     pParse.pPtr = pDef;@\\
+\mbox{}\verb@     pParse.iDepth = 0;@\\
+\mbox{}\verb@#ifdef DEFDEBUG@\\
+\mbox{}\verb@     printf("Putting: %s\n",pDef);@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@     iRet = NXDIDefParse(hFil,pDict,&pParse);@\\
+\mbox{}\verb@     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@          NXDIUnwind(hFil,pParse.iDepth);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* only SDS can be written */@\\
+\mbox{}\verb@     if(pParse.iTerminal != TERMSDS)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,@\\
+\mbox{}\verb@                     "ERROR: can only write to an SDS!");@\\
+\mbox{}\verb@        iStat = NX_ERROR;@\\
+\mbox{}\verb@     } @\\
+\mbox{}\verb@     else @\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       /* the SDS should be open by now, write it */@\\
+\mbox{}\verb@       iStat = NXputdata(hFil, pData);@\\
+\mbox{}\verb@       iRet = NXclosedata(hFil);@\\
+\mbox{}\verb@     }   @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* rewind the hierarchy */@\\
+\mbox{}\verb@     iRet = NXDIUnwind(hFil,pParse.iDepth);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return iStat;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDputalias}
+Just finds the definition string and calls NXputdef then.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap32}
+$\langle$nxdputalias {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  NXstatus NXDputalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@     char pDefinition[1024];@\\
+\mbox{}\verb@     pDynString pReplaced = NULL;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* get Definition String  */@\\
+\mbox{}\verb@     iRet = NXDget(pDict,pAlias,pDefinition,1023);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pDefinition);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* do text replacement */@\\
+\mbox{}\verb@     pReplaced = NXDItextreplace(dict,pDefinition);@\\
+\mbox{}\verb@     if(!pReplaced)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* call NXDputdef */@\\
+\mbox{}\verb@     iRet = NXDputdef(hFil,dict,GetCharArray(pReplaced),pData);@\\
+\mbox{}\verb@     DeleteDynString(pReplaced);@\\
+\mbox{}\verb@     return iRet;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDgetdef}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap33}
+$\langle$nxget {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDgetdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     ParDat pParse;@\\
+\mbox{}\verb@     int iRet, i, iStat;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* parse and act on definition string */@\\
+\mbox{}\verb@     pParse.iMayCreate = 0;@\\
+\mbox{}\verb@     pParse.pPtr = pDef;@\\
+\mbox{}\verb@     pParse.iDepth = 0;@\\
+\mbox{}\verb@#ifdef DEFDEBUG@\\
+\mbox{}\verb@     printf("Getting: %s\n",pDef);@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@     iRet = NXDIDefParse(hFil,pDict,&pParse);@\\
+\mbox{}\verb@     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         /* unwind and throw up */@\\
+\mbox{}\verb@          NXDIUnwind(hFil,pParse.iDepth);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* only SDS can be written */@\\
+\mbox{}\verb@     if(pParse.iTerminal != TERMSDS)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,@\\
+\mbox{}\verb@                     "ERROR: can only write to an SDS!");@\\
+\mbox{}\verb@        iStat = NX_ERROR;@\\
+\mbox{}\verb@     } @\\
+\mbox{}\verb@     else @\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       /* the SDS should be open by now, read it */@\\
+\mbox{}\verb@       iStat = NXgetdata(hFil, pData);@\\
+\mbox{}\verb@       iRet = NXclosedata(hFil);@\\
+\mbox{}\verb@     }   @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* rewind the hierarchy */@\\
+\mbox{}\verb@     iRet = NXDIUnwind(hFil,pParse.iDepth);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return iStat;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXgetalias}
+Just finds the definition string and calls NXgetdef then.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap34}
+$\langle$nxdgetalias {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  NXstatus NXDgetalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     int iRet;@\\
+\mbox{}\verb@     char pDefinition[1024];@\\
+\mbox{}\verb@     pDynString pReplaced = NULL;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* get Definition String  */@\\
+\mbox{}\verb@     iRet = NXDget(pDict,pAlias,pDefinition,1023);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pDefinition);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@     /* do text replacement */@\\
+\mbox{}\verb@     pReplaced = NXDItextreplace(dict,pDefinition);@\\
+\mbox{}\verb@     if(!pReplaced)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* call NXDgetdef */@\\
+\mbox{}\verb@     iRet = NXDgetdef(hFil,dict,GetCharArray(pReplaced),pData);@\\
+\mbox{}\verb@     DeleteDynString(pReplaced);@\\
+\mbox{}\verb@     return iRet;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXDdeflink, NXDaliaslink}
+The first alias/definition string must be a vGroup, the other can be a
+vGroup or a SDS.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap35}
+$\langle$nxlink {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@  NXstatus NXDdeflink(NXhandle hFil, NXdict dict, @\\
+\mbox{}\verb@                      char *pTarget, char *pVictim)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     NXdict pDict;@\\
+\mbox{}\verb@     ParDat pParseT, pParseV;@\\
+\mbox{}\verb@     int iRet, i, iStat;@\\
+\mbox{}\verb@     NXlink sLink;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#ifdef DEFDEBUG@\\
+\mbox{}\verb@     printf("Linking: %s\n",pVictim);@\\
+\mbox{}\verb@     printf("To: %s\n", pTarget);@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* parse Victim  */@\\
+\mbox{}\verb@     pParseV.iMayCreate = 0;@\\
+\mbox{}\verb@     pParseV.pPtr = pVictim;@\\
+\mbox{}\verb@     pParseV.iDepth = 0;@\\
+\mbox{}\verb@     iRet = NXDIDefParse(hFil,pDict,&pParseV);@\\
+\mbox{}\verb@     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         /* unwind and throw up */@\\
+\mbox{}\verb@          NXDIUnwind(hFil,pParseV.iDepth);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     /* get link data */@\\
+\mbox{}\verb@     if(pParseV.iTerminal == TERMSDS)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       NXgetdataID(hFil,&sLink);@\\
+\mbox{}\verb@       iRet =  NXclosedata(hFil);@\\
+\mbox{}\verb@       if(iRet != NX_OK)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         /* unwind and throw up */@\\
+\mbox{}\verb@          NXDIUnwind(hFil,pParseV.iDepth);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     else if(pParseV.iTerminal == TERMVG)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       NXgetgroupID(hFil,&sLink);@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     else@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        assert(0); /* serious programming error */@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     /* Unwind */@\\
+\mbox{}\verb@     iRet = NXDIUnwind(hFil,pParseV.iDepth);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* parse Target */@\\
+\mbox{}\verb@     pParseT.iMayCreate = 1;@\\
+\mbox{}\verb@     pParseT.pPtr = pTarget;@\\
+\mbox{}\verb@     pParseT.iDepth = 0;@\\
+\mbox{}\verb@     iRet = NXDIDefParse(hFil,pDict,&pParseT);@\\
+\mbox{}\verb@     if(iRet == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@         /* unwind and throw up */@\\
+\mbox{}\verb@          NXDIUnwind(hFil,pParseT.iDepth);@\\
+\mbox{}\verb@          return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     /* check it being a vGroup! */@\\
+\mbox{}\verb@     if(pParseT.iTerminal != TERMVG)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       NXIReportError(NXpData,"ERROR: can link only into a vGroup");@\\
+\mbox{}\verb@       NXDIUnwind(hFil,pParseT.iDepth);@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@    @\\
+\mbox{}\verb@     /* link, finally */@\\
+\mbox{}\verb@     iRet = NXmakelink(hFil,&sLink);@\\
+\mbox{}\verb@     /* Unwind anyway */@\\
+\mbox{}\verb@     iStat = NXDIUnwind(hFil,pParseT.iDepth);@\\
+\mbox{}\verb@     if(iStat != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return iStat;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@  NXstatus NXDaliaslink(NXhandle hFil, NXdict dict, @\\
+\mbox{}\verb@                      char *pTarget, char *pVictim)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@    char pTargetDef[1024], pVictimDef[1024];@\\
+\mbox{}\verb@    int iRet;@\\
+\mbox{}\verb@    NXdict pDict;@\\
+\mbox{}\verb@    pDynString pRep1 = NULL, pRep2 = NULL;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     pDict = NXDIAssert(dict);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* get Target Definition String  */@\\
+\mbox{}\verb@     iRet = NXDget(pDict,pTarget,pTargetDef,1023);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pTargetDef);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }       @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* get Victim definition string */@\\
+\mbox{}\verb@     iRet = NXDget(pDict,pVictim,pVictimDef,1023);@\\
+\mbox{}\verb@     if(iRet != NX_OK)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);@\\
+\mbox{}\verb@        NXIReportError(NXpData,pTargetDef);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* do replacements */@\\
+\mbox{}\verb@     pRep1 = NXDItextreplace(dict,pTargetDef);@\\
+\mbox{}\verb@     pRep2 = NXDItextreplace(dict,pVictimDef);@\\
+\mbox{}\verb@     if( (!pRep1) || (!pRep2) )@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        if(pRep1)@\\
+\mbox{}\verb@           DeleteDynString(pRep1);@\\
+\mbox{}\verb@        if(pRep2)@\\
+\mbox{}\verb@           DeleteDynString(pRep2);@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* call NXdeflin */@\\
+\mbox{}\verb@     iRet = NXDdeflink(hFil,pDict,GetCharArray(pRep1),GetCharArray(pRep2));@\\
+\mbox{}\verb@     DeleteDynString(pRep1);@\\
+\mbox{}\verb@     DeleteDynString(pRep2);@\\
+\mbox{}\verb@     return iRet;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Utility functions}
+\subsubsection{NXUwriteglobals}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap36}
+$\langle$global {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@  static void SNXFormatTime(char *pBuffer, int iBufLen)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     time_t iDate;@\\
+\mbox{}\verb@     struct tm *psTime;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* make time string */@\\
+\mbox{}\verb@     iDate = time(NULL);@\\
+\mbox{}\verb@     psTime = localtime(&iDate);@\\
+\mbox{}\verb@     memset(pBuffer,0,iBufLen);         @\\
+\mbox{}\verb@     strftime(pBuffer,iBufLen,"%Y-%d-%m %H:%M:%S",psTime);@\\
+\mbox{}\verb@  }  @\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@   NXstatus NXUwriteglobals(NXhandle pFile, @\\
+\mbox{}\verb@                            char *filename,@\\
+\mbox{}\verb@                            char *owner,@\\
+\mbox{}\verb@                            char *adress,@\\
+\mbox{}\verb@                            char *phone,@\\
+\mbox{}\verb@                            char *email,@\\
+\mbox{}\verb@                            char *fax,@\\
+\mbox{}\verb@                            char *instrument)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@     char pBueffel[512];@\\
+\mbox{}\verb@     int iStat;@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* store global attributes */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"file_name",filename, @\\
+\mbox{}\verb@                       strlen(filename)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* write creation time */@\\
+\mbox{}\verb@     SNXFormatTime(pBueffel,512);@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"file_time",pBueffel,@\\
+\mbox{}\verb@                       strlen(pBueffel)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NX_ERROR;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* instrument name */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"instrument",instrument,@\\
+\mbox{}\verb@                       strlen(instrument)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return iStat;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* owner */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"owner",owner,@\\
+\mbox{}\verb@                       strlen(owner)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return iStat;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* Adress */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"owner_adress",adress,@\\
+\mbox{}\verb@                       strlen(adress)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        return iStat;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* phone */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"owner_telephone_number",phone,@\\
+\mbox{}\verb@                       strlen(phone)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        return iStat;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* fax */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"owner_fax_number",fax,@\\
+\mbox{}\verb@                       strlen(fax)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return iStat;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* email */@\\
+\mbox{}\verb@     iStat = NXputattr(pFile,"owner_email",email,@\\
+\mbox{}\verb@                       strlen(email)+1,DFNT_INT8);@\\
+\mbox{}\verb@     if(iStat == NX_ERROR)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return iStat;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXUentergroup}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap37}
+$\langle$enterg {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       void (*ErrFunc)(void *pData, char *pErr); @\\
+\mbox{}\verb@       int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* ACTION, first install dummy error handler */@\\
+\mbox{}\verb@       ErrFunc = NXIReportError;@\\
+\mbox{}\verb@       NXMSetError(NXpData, DummyError);@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@       /* try opening vGroup */@\\
+\mbox{}\verb@       iRet = NXopengroup(hFil, name, class);@\\
+\mbox{}\verb@       NXMSetError(NXpData,ErrFunc);@\\
+\mbox{}\verb@       if(iRet == NX_OK)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         return NX_OK;@\\
+\mbox{}\verb@       } @\\
+\mbox{}\verb@       else@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          /* we need to create it */@\\
+\mbox{}\verb@            iRet = NXmakegroup(hFil,name,class);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            iRet = NXopengroup(hFil,name,class);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXUenterdata}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap38}
+$\langle$enterd {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUenterdata(NXhandle hFil, char *label, int datatype,@\\
+\mbox{}\verb@                         int rank, int dim[], char *pUnits)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@       void (*ErrFunc)(void *pData, char *pErr); @\\
+\mbox{}\verb@       int iRet;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       /* ACTION, first install dummy error handler */@\\
+\mbox{}\verb@       ErrFunc = NXIReportError;@\\
+\mbox{}\verb@       NXMSetError(NXpData, DummyError);@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@       /* try opening SDS */@\\
+\mbox{}\verb@       iRet = NXopendata(hFil, label);@\\
+\mbox{}\verb@       NXMSetError(NXpData,ErrFunc);@\\
+\mbox{}\verb@       if(iRet == NX_OK)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@         return NX_OK;@\\
+\mbox{}\verb@       } @\\
+\mbox{}\verb@       else@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          /* we need to create it */@\\
+\mbox{}\verb@            iRet = NXmakedata(hFil,label, datatype, rank,dim);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            iRet = NXopendata(hFil,label);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@            iRet = NXputattr(hFil, "Units",pUnits,@\\
+\mbox{}\verb@                             strlen(pUnits) + 1,DFNT_INT8);@\\
+\mbox{}\verb@            if(iRet != NX_OK)@\\
+\mbox{}\verb@            { @\\
+\mbox{}\verb@                 /* a comment on this one has already been written! */@\\
+\mbox{}\verb@                 return iRet;@\\
+\mbox{}\verb@            }@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{NXUallocSDS}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap39}
+$\langle$allocs {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUallocSDS(NXhandle hFil, void **pData)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      int iDIM[MAX_VAR_DIMS];@\\
+\mbox{}\verb@      int iRank,iType;@\\
+\mbox{}\verb@      int iRet, i;@\\
+\mbox{}\verb@      long lLength;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* get info */@\\
+\mbox{}\verb@      iRet = NXgetinfo(hFil,&iRank, iDIM, &iType);@\\
+\mbox{}\verb@      if(iRet != NX_OK)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        return iRet;@\\
+\mbox{}\verb@      }      @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* calculate Size */@\\
+\mbox{}\verb@      lLength = iDIM[0];@\\
+\mbox{}\verb@      for(i = 1; i < iRank; i++)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        lLength *= iDIM[i];@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      switch(iType)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        case DFNT_FLOAT32:@\\
+\mbox{}\verb@             lLength *= sizeof(float32);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_FLOAT64:@\\
+\mbox{}\verb@             lLength *= sizeof(float64);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_INT8:@\\
+\mbox{}\verb@             lLength *= sizeof(int8);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_UINT8:@\\
+\mbox{}\verb@             lLength *= sizeof(uint8);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_INT16:@\\
+\mbox{}\verb@             lLength *= sizeof(int16);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_UINT16:@\\
+\mbox{}\verb@             lLength *= sizeof(uint16);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_INT32:@\\
+\mbox{}\verb@             lLength *= sizeof(int32);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        case DFNT_UINT32:@\\
+\mbox{}\verb@             lLength *= sizeof(uint32);@\\
+\mbox{}\verb@             break;@\\
+\mbox{}\verb@        default:@\\
+\mbox{}\verb@             NXIReportError(NXpData,"ERROR: Internal: number type not recoginized");@\\
+\mbox{}\verb@             return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* time to malloc */@\\
+\mbox{}\verb@      *pData = NULL;@\\
+\mbox{}\verb@      *pData = malloc(lLength);@\\
+\mbox{}\verb@      if(*pData == NULL)@\\
+\mbox{}\verb@      {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: memory exhausted in NXUallocSDS");@\\
+\mbox{}\verb@        return NX_ERROR;@\\
+\mbox{}\verb@      }@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap40}
+$\langle$free {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUfreeSDS(void **pData)@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      free(*pData);@\\
+\mbox{}\verb@      *pData = NULL;@\\
+\mbox{}\verb@      return NX_OK;@\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Files}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap41}
+\verb@"nxdict.h"@ {\footnotesize ? }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------------------------------------------------------------------@\\
+\mbox{}\verb@                            NXDICT API header file@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   No warranties of any kind taken.@\\
+\mbox{}\verb at ----------------------------------------------------------------------------*/@\\
+\mbox{}\verb@#ifndef NXDICTAPI@\\
+\mbox{}\verb@#define NXDICTAPI@\\
+\mbox{}\verb@#include "napi.h" /* make sure, napi is included */@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@/*-------------------- NXDict data types & defines ----------------------*/@\\
+\mbox{}\verb@@$\langle$tata {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@#define NXquiet 0@\\
+\mbox{}\verb@#define NXalot  1@\\
+\mbox{}\verb@/*-------------------- Dictionary Maintainance ----------------------------*/@\\
+\mbox{}\verb@@$\langle$dicman {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*----------------- Dictionary added data transfer -----------------------*/ @\\
+\mbox{}\verb@@$\langle$dicdata {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-------------------- Utility Functions --------------------------------*/@\\
+\mbox{}\verb@@$\langle$dicutil {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap42}
+\verb@"nxdict.c"@ {\footnotesize ? }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*---------------------------------------------------------------------------@\\
+\mbox{}\verb@                 Nexus Dictionary API implementation file.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  For documentation see the nxdict.tex file which comes with this @\\
+\mbox{}\verb@  distribution.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  copyleft: Mark Koennecke@\\
+\mbox{}\verb@            Labor fuer Neutronenstreuung@\\
+\mbox{}\verb@            Paul Scherrer Institut@\\
+\mbox{}\verb@            CH-5232 Villigen-PSI@\\
+\mbox{}\verb@            Switzerland@\\
+\mbox{}\verb@            Mark.Koennecke@{\tt @}\verb at psi.ch@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  No warranties of any kind, whether explicit or implied, taken.@\\
+\mbox{}\verb@  Distributed under the GNU copyleft license as documented elsewhere.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  August, 1997@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@  Version: 1.0@\\
+\mbox{}\verb at -----------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#include <stdlib.h>@\\
+\mbox{}\verb@#include <stdio.h>@\\
+\mbox{}\verb@#include <assert.h>@\\
+\mbox{}\verb@#include <string.h>@\\
+\mbox{}\verb@#include <time.h>@\\
+\mbox{}\verb@#include <mfhdf.h>@\\
+\mbox{}\verb@#include "lld.h"@\\
+\mbox{}\verb@#include "napi.h"@\\
+\mbox{}\verb@#include "stringdict.h"@\\
+\mbox{}\verb@#include "dynstring.h"@\\
+\mbox{}\verb@#include "nxdict.h"@\\
+\mbox{}\verb@/*------------------ The magic number used for pointer checking */@\\
+\mbox{}\verb@#define NXDMAGIC 260558@\\
+\mbox{}\verb@/*--------------------------------------------------------------------------@\\
+\mbox{}\verb@      Things defined in napi.c for error reporting @\\
+\mbox{}\verb at ---------------------------------------------------------------------------*/@\\
+\mbox{}\verb@       extern void *NXpData;@\\
+\mbox{}\verb@       extern void (*NXIReportError)(void *pData, char *pBuffer);  @\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@#define DEFDEBUG 1@\\
+\mbox{}\verb@/* define DEFDEBUG when you wish to print your definition strings before@\\
+\mbox{}\verb@   action. This can help a lot to resolve mysteries when working with@\\
+\mbox{}\verb@   dictionaries.@\\
+\mbox{}\verb@*/@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$dicdat {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@  static char *NXDIReadFile(FILE *fd)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     char *pNew = NULL;@\\
+\mbox{}\verb@     long lLength = 0;@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@     assert(fd); @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* determine length of file */@\\
+\mbox{}\verb@     fseek(fd,0L,SEEK_END);@\\
+\mbox{}\verb@     lLength = ftell(fd);@\\
+\mbox{}\verb@     if(lLength <= 0)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     fseek(fd,0L,SEEK_SET);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* allocate buffer */@\\
+\mbox{}\verb@     lLength += 3;@\\
+\mbox{}\verb@     pNew = (char *)malloc(lLength*sizeof(char));@\\
+\mbox{}\verb@     if(!pNew)@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@       return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     memset(pNew,0,lLength); /* this ensures a 0 at the end */@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@     /* read file */@\\
+\mbox{}\verb@     fread(pNew,sizeof(char),lLength-3,fd);@\\
+\mbox{}\verb@     @\\
+\mbox{}\verb@     /* check for existence of the NXDICT string in the file */@\\
+\mbox{}\verb@     if(strncmp(pNew,"##NXDICT-1.0",12) != 0 )@\\
+\mbox{}\verb@     {@\\
+\mbox{}\verb@        NXIReportError(NXpData,"ERROR: This is NO NXdict file");@\\
+\mbox{}\verb@        free(pNew);@\\
+\mbox{}\verb@        return NULL;@\\
+\mbox{}\verb@     }@\\
+\mbox{}\verb@     return pNew;@\\
+\mbox{}\verb@  }@\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$ftoken {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$fparse {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@  NXstatus NXDinitfromfile(char *filename, NXdict *pData)@\\
+\mbox{}\verb@  {@\\
+\mbox{}\verb@     NXdict pNew = NULL;@\\
+\mbox{}\verb@     FILE *fd = NULL;@\\
+\mbox{}\verb@     char *pBuffer = NULL;@\\
+\mbox{}\verb@     char pError[512];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\langle$iniini {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$inicheck {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$inifil {\footnotesize ?}$\rangle$\verb@ @\\
+\mbox{}\verb@@$\langle$iniparse {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@       if(iVerbosity == NXalot)@\\
+\mbox{}\verb@       {@\\
+\mbox{}\verb@          NXIReportError(NXpData, "NXDinitfrom: performed successfully");@\\
+\mbox{}\verb@       }@\\
+\mbox{}\verb@       free(pBuffer);@\\
+\mbox{}\verb@       *pData = pNew;@\\
+\mbox{}\verb@       return NX_OK;@\\
+\mbox{}\verb@  }   @\\
+\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$dassert {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$dclose {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$dmaintain {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$textrep {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------- The Defintion String Parser -----------------------*/@\\
+\mbox{}\verb@/*------- Data structures */@\\
+\mbox{}\verb@@$\langle$tokdat {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$padef {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$dummyerr {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$attitem {\footnotesize ?}$\rangle$\verb@ @\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$deftok {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$defpath {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$parseatt {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$parsedim {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$parsetype {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxpasds {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$parselink {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$defpar {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$unwind {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-------------------- The Data Transfer Functions ----------------------*/@\\
+\mbox{}\verb@@$\langle$nxddefopen {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxdaliasopen {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxput {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxdputalias {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxget {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxdgetalias {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$nxlink {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$global {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$enterg {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$enterd {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$allocs {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
+\mbox{}\verb@@$\langle$free {\footnotesize ?}$\rangle$\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap43}
+\verb@"dict.c"@ {\footnotesize ? }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@/*--------------------------------------------------------------------------@\\
+\mbox{}\verb@                               D I C T @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@ This file exercises some of the NXDICT functionality for test purposes.@\\
+\mbox{}\verb@ It can also serve as an example for the usage of the API.@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@ Mark Koennecke, August 1997@\\
+\mbox{}\verb@  @\\
+\mbox{}\verb@ Upgraded to support file idetification and text replacement@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@ Mark Koennecke, April 1998@\\
+\mbox{}\verb at ----------------------------------------------------------------------------*/@\\
+\mbox{}\verb@#include <stdlib.h>@\\
+\mbox{}\verb@#include <stdio.h>@\\
+\mbox{}\verb@#include <assert.h>@\\
+\mbox{}\verb@#include <mfhdf.h>@\\
+\mbox{}\verb@#include "dynstring.h"@\\
+\mbox{}\verb@#include "napi.h"@\\
+\mbox{}\verb@#include "nxdict.h"@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   int main(int argc, char *argv[])@\\
+\mbox{}\verb@   {@\\
+\mbox{}\verb@      NXdict pDict = NULL;@\\
+\mbox{}\verb@      NXhandle hfil;@\\
+\mbox{}\verb@      void *pData = NULL;@\\
+\mbox{}\verb@      float fTina[3] = { 0.123, 0.234, 0.456};@\\
+\mbox{}\verb@      float fTest[3], fDelta;@\\
+\mbox{}\verb@      float fTust[20*20];@\\
+\mbox{}\verb@      char pBuffer[132];@\\
+\mbox{}\verb@      int i;@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* test nxdict */@\\
+\mbox{}\verb@      NXDinitfromfile("test.dict",&pDict);@\\
+\mbox{}\verb@      NXopen("test.hdf",NXACC_CREATE,&hfil);@\\
+\mbox{}\verb@      NXDadd(pDict,"Gundula",@\\
+\mbox{}\verb@            "/entry1,NXentry/SphereOmeter,NXinstrument/SDS");@\\
+\mbox{}\verb@      NXDupdate(pDict,"Bea","/entry1,NXentry/SDS");@\\
+\mbox{}\verb@      NXDget(pDict,"Bea",pBuffer,131);@\\
+\mbox{}\verb@      printf("Bea = %s\n",pBuffer);@\\
+\mbox{}\verb@      NXDget(pDict,"Linda",pBuffer,131);@\\
+\mbox{}\verb@      NXDopendef(hfil,pDict,pBuffer);@\\
+\mbox{}\verb@      NXDputalias(hfil,pDict,"Tina",fTina);@\\
+\mbox{}\verb@      NXDputalias(hfil,pDict,"Gina",fTina);@\\
+\mbox{}\verb@      NXDgetalias(hfil,pDict,"Tina",fTest);@\\
+\mbox{}\verb@      NXDgetalias(hfil,pDict,"Gina",fTest);@\\
+\mbox{}\verb@      NXDputalias(hfil,pDict,"Linda",fTust);@\\
+\mbox{}\verb@      NXDaliaslink(hfil,pDict,"Eva","Linda");@\\
+\mbox{}\verb@      NXDclose(pDict,"close.dict");@\\
+\mbox{}\verb@      NXclose(&hfil);@\\
+\mbox{}\verb@      printf("NXDICT seemed to have worked \n");@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      /* test Utility functions */@\\
+\mbox{}\verb@      printf(" Proceeding to test of utility functions \n");@\\
+\mbox{}\verb@      NXopen("test2.hdf",NXACC_CREATE,&hfil);@\\
+\mbox{}\verb@      NXUwriteglobals(hfil,@\\
+\mbox{}\verb@                      "test2.hdf",@\\
+\mbox{}\verb@                      "Willibald Wuergehals",@\\
+\mbox{}\verb@                      "Rue des Martyrs, 26505 Timbuktu, Legoland ",@\\
+\mbox{}\verb@                      "+41-56-3102512",@\\
+\mbox{}\verb@                      "Nobody@{\tt @}\verb at nowhere.edu",@\\
+\mbox{}\verb@                      " 755-898767",@\\
+\mbox{}\verb@                      "Dingsbums");@\\
+\mbox{}\verb@      NXUentergroup(hfil, "TestGroup", "NXtest");@\\
+\mbox{}\verb@      NXclosegroup(hfil);@\\
+\mbox{}\verb@      NXUentergroup(hfil, "TestGroup", "NXtest");@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      i = 120;@\\
+\mbox{}\verb@      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");@\\
+\mbox{}\verb@      NXclosedata(hfil);@\\
+\mbox{}\verb@      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@      NXUallocSDS(hfil,&pData);@\\
+\mbox{}\verb@      NXUfreeSDS(&pData);@\\
+\mbox{}\verb@      NXclose(&hfil);@\\
+\mbox{}\verb@      printf("All tests seem to have worked OK,  %s %s\n",@\\
+\mbox{}\verb@             "but the test is pathetic\n", @\\
+\mbox{}\verb@             "Do not rely, in any circumstances, on this test alone");@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@ @\\
+\mbox{}\verb@   }@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap44}
+\verb@"test.dict"@ {\footnotesize ? }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@##NXDICT-1.0@\\
+\mbox{}\verb@#----------------------------------------------------------------------------@\\
+\mbox{}\verb@# A dictionary file for test purposes@\\
+\mbox{}\verb@# Mark Koennecke, August 1997@\\
+\mbox{}\verb@#----------------------------------------------------------------------------@\\
+\mbox{}\verb@@\\
+\mbox{}\verb at Linda = /entry1,NXentry/Wuerfelometer,NXinstrument/SDS Counts \@\\
+\mbox{}\verb@ -type DFNT_INT32 -rank 2 -dim {20,20} -attr {Units,Wuerfel} \@\\
+\mbox{}\verb@ -attr {axis,1}@\\
+\mbox{}\verb at Eva   = \@\\
+\mbox{}\verb@ /entry1,NXentry/NXVGROUP@\\
+\mbox{}\verb at Chloe = /entry1,NXentry/NXLINK Linda@\\
+\mbox{}\verb at Bea =@\\
+\mbox{}\verb at Tina = /entry1,NXentry/InvertedTOPSI,NXinstrument/SDS Tina \@\\
+\mbox{}\verb@       -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit}   @\\
+\mbox{}\verb at Reptil = Alligator,NXanimal/@\\
+\mbox{}\verb at Gina = /entry1,NXentry/$(Reptil)SDS Tina \@\\
+\mbox{}\verb@       -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit}   @\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{document}
diff --git a/src/nxdict/nxdict.w b/src/nxdict/nxdict.w
new file mode 100644
index 0000000..10c5708
--- /dev/null
+++ b/src/nxdict/nxdict.w
@@ -0,0 +1,2537 @@
+%
+%
+%  This software is distributed in the hope that it will be useful,
+%  but WITHOUT ANY WARRANTY; without even the implied warranty of
+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%  GNU General Public License for more details.
+%
+%  You may already have a copy of the GNU General Public License; if
+%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+%  Cambridge, MA 02139, USA.
+%
+
+\documentclass[12pt]{article}
+
+\setlength{\oddsidemargin}{-.1in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.2in}
+\setlength{\marginparwidth}{0.5in}
+
+\begin{document}
+\title{The NEXUS Dictionary API}
+
+\author{Mark K\"onnecke\\
+  Labor f\"ur Neutronenstreuung\\
+  Paul Scherrer Institut\\
+  CH-5232 Villigen PSI\\
+  Switzerland\\       
+  Mark.Koennecke@@psi.ch \\
+}
+
+
+
+\maketitle
+
+\vskip.3in
+\centerline{\large\bf Abstract}
+\vskip.2in
+\begin{center}
+\parbox{.8\textwidth}{
+  There is a proposed portable data exchange format for neutron and
+  X-ray scattering communities, NEXUS (described in a separate
+  publication).   Another document describes an application programmers
+ interface to NEXUS. This is a base level API which hides many of the
+ hideous details of the HDF interface from the NeXus programmer. The
+ present document   introduces a higher level application programmers
+ interface sitting on top of the NeXus API. This API (the NEXDICT-API),
+ reads all file structure data  from a dictionary data file and creates
+ the structure automatically from that information. The NEXDICT user only
+ needs to specify the data to write or read.
+}
+\end{center}
+
+\clearpage
+
+\section{Introduction}
+ There exists a proposal for a portable data exchange format for neutron and
+ X--ray scattering communities, NeXus. NeXus is fully described
+ elsewhere$^{1}$. NeXus sits on top of the hierarchical data format (HDF) as
+ defined and specified by the National Center for Supercomputer Applications, 
+ NCSA, USA. HDF comes with a library of access functions. On top of the
+ HDF-library an application programmers interface (API) for NeXus was
+ defined which hides many of the low level details and ideosyncracies of
+ the HDF interface form the NeXus programmer. However, writing NeXus files stays
+ hideous even with this interface due to the amount of repetitive code
+ required to  implement the NeXus structure. Now, repetitive tasks is one
+ area a computer is good at. So, why not have the computer take care of all
+ the structure associated with the NeXus format? Such an approach has the 
+additional benefit that changes in the file structure just require to edit
+the dictionary data file with no changes to the source code writing or
+reading the data. In order to do all this two
+ components are needed:
+\begin{itemize}
+\item A language which describes the NeXus file structure to the computer.
+  This language will be called the NeXus Data Definition Language (NXDDL).
+  NXDLL might also be used as a tool for discussing and defining NeXus
+  data structures.
+\item A application programmers interface which works with the NeXus Data 
+ Definition Language.
+\end{itemize}
+Both of the above will be detailed in this document.
+
+\section{The NeXus Data Definition Language}
+The NeXus Data Definition Language's(NXDDL) purpose is to define the structure
+and data items in a NeXus file in a form which can be understood by a human
+programmer and which can be parsed by the computer in order to create the 
+structure. 
+For this a dictionary based approach will be used. This dictionary
+will contain pairs of short aliases for data items and definition strings 
+which hold the structure information. This dictionary will
+be initialized from a data file, the NXDDL-file. Such a dictionary can be
+used in the following way: Given an appropriate API function, a NXDICT
+programmer  needs to specify only the alias and the data to write and 
+everything else is taken care of by the API: vGroup creation, opening,
+SDS definition etc. Another use may involve the creation of definition
+strings
+completely or partly at run time which can then be used by an API function
+in order to create the structures defined by the definition string. The same
+holds for writing as well.
+
+
+A NXDDL dictionary is preferably initialized from a file.
+Such a NXDDL file has to follow these general structure guidelines:
+\begin{itemize}
+\item All input is in US--ASCII.
+\item The first line must read: ##NXDICT-1.0. This is in order to
+automatically identify the file.
+\item A \verb+#+ in the first column denotes a comment and will be ignored.
+\item A \verb+\+ at the end of the line means that the current text will be 
+ continued with the next non-blank character for the next line.
+\item All other entries follow the form: alias = definition string.
+ This defines \verb+alias+ as a short form for the definition string  after the
+ equality sign.
+\item There is a text replacement facility similar to shell variables under
+Unix: The sequence $(alias) anywhere in a definition string will be replaced
+ by the value of the alias specified between the braces. This scheme allows
+to cater for multiple entries in a file or changing data descriptions as a
+function of instrument modes.
+\end{itemize}         
+It might be considered to add a special global vGroup of class NXdict to the
+NexUs API which holds the dictionary information within a NeXus file.
+
+ The next thing to define is the content of the definition string. A
+ definition string will have the general form: \\
+\centerline{\bf PATH/TerminalSymbol}
+ This means a definition string will consist of a path specifier which
+ describes the position of a data item in the vGroup hierarchy and a
+ terminal symbol which describes the nature of the data item. 
+
+ The path through the vGroup hierarchy to a data item will be described in a
+ manner analog to a Unix directory hierarchy. However, NeXus requires two
+ pieces of data in order to fully qualify a vGroup. This is it's name and
+ class. Consequently, both name and classname will be given for each vGroup,
+ separated by a komma. A valid path string then looks like: \\
+\begin{verbatim} 
+     /scan1,NXentry/DMC,NXinstrument/big_detector,NXdetector/TerminalSymbol
+\end{verbatim}
+ This translates into: TerminalSymbol in vGroup big\_detector, class
+ NXdetector, which resides in vGroup DMC of class NXinstrument, which in
+ turn is situated in the vGroup scan1 of class NXentry.
+
+ The terminal symbol in a definition string is used to define the data item
+ at the end of the definition. NeXus currently supports only three types of
+ data items at the end of the chain: these are scientific data sets (SDS),
+ vGroups and links to other data items or vGroups. The terminal symbol for a link
+ is specified by the keyword \verb+NXLINK+  
+ followed
+ by a valid alias of another data item or vGroup. For example the terminal 
+ symbol: \\
+ \centerline{\bf SDS counts}
+ would define a SDS with name counts.
+
+ A vGroup would be denoted by the keyword VGROUP. By then, the vGroup has
+ already been defined by the path string. This form of alias is only useful
+ for the definition of links to vGroups.
+
+ A SDS is more involved. The definition of an SDS starts with the keyword
+ \verb+SDS+. This keyword must then be followed by the name of the SDS.
+ Following the name there are option value pairs which define the 
+  details of the SDS. The following option exist:
+ \begin{itemize}
+  \item {\bf -rank} defines the rank of the SDS.
+  \item {\bf -dim \{dim0,dim1,dim2,...., dimn\} } defines the dimensions of the
+       SDS. Exactly the number of rank numbers defining the dimensions
+ length is required inside the curly braces. 
+  \item {\bf -type} defines the data type of the SDS as a string corresponding
+  to the HDF data types.
+  \item {\bf -attr \{name,value\} } defines an attribute. In the curly braces
+   there must be the name and value of the attribute separated by a comma.
+  \end{itemize}
+  If no options are given a default is used. This will be a single floating
+  point number, as this is the most frequently written data item. As an 
+  example see the definition of a 3d array of 32 bit integers:
+  \begin{verbatim}
+   PATHSTRING/SDS counts -rank 3 -dim {64,64,712} -type DFNT_INT32 \
+                  -attr {Units,Counts}      
+
+  \end{verbatim}
+
+  \section{The NXDICT--API}
+  In order to interface with the NeXus dictionary API a set of
+  API--functions is needed. All functions and data types belonging to
+  this API start with the letters: NXD. The functions belonging to this API
+  fall into three groups:
+  \begin{itemize}
+   \item Dictionary maintainance functions.
+   \item Data writing and reading functions.
+   \item Utility functions.
+  \end{itemize}
+  
+  One additional data type is needed for this API:
+ at d tata @{
+   typedef struct __NXdict *NXdict;
+@}
+ NXdict will be used as a handle for the dictionary currently in use.
+
+\subsubsection{Dictionary Maintainance Function}
+ at d dicman @{
+   NXstatus NXDinitfromfile(char *filename, NXdict *pDict);
+   NXstatus NXDclose(NXdict handle, char *filename);
+
+   NXstatus NXDadd(NXdict handle, char *alias, char *DefString);
+   NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int iBufLen);
+   NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal);
+   NXstatus NXDtextreplace(NXdict handle, char *pDefString, char *pBuffer,
+                           int iBuflen);
+@}
+  
+  {\bf NXDinitfromfile} creates a new NeXus dictionary. If filename is NULL, this
+  is all that happens. If filename is not NULL, it will be opened and the
+  dictionary will be initialized from the file specified.  The return value
+  is either 0 for failure or non zero for success. 
+
+  {\bf NXDclose} deletes and writes a NeXus dictionary. If filename is not NULL,
+  the dictionary specified by handle is written to the file specified by
+  filename. In any case the dictionary specified by handle will be deleted.
+
+  {\bf NXDadd} adds a new alias -- Definition String pair to the dictionary
+  specified by handle.
+
+  {\bf NXDget} retrieves the definition string for the alias specified as
+  the second parameter from the dictionary handle. The definition string
+  is copied to pBuffer. Maximum iBufLen characters will be copied.
+
+  {\bf NXDupdate} replaces the definition for the alias specified as second
+ parameter with the new value supplied as last parameter.
+  
+  If a special dictionary vGroup as extension to NeXus would be accepted,
+  two more functions need to be defined which read and write the dictionary 
+  from the NeXus file.
+
+ {\bf NXDtextreplace} resolves any text replacements in the definition
+ string pDefString. Maximum iBuflen characters of replacement results will
+ be copied into the buffer variable. 
+
+\subsubsection{Data Handling functions}
+ at d dicdata @{
+   NXstatus NXDputalias(NXhandle file, NXdict dict, 
+                        char *alias, void *pData);
+   NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, void *pData);
+
+   NXstatus NXDgetalias(NXhandle file, NXdict dict, 
+                        char *alias, void *pData);
+   NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData);
+
+   NXstatus NXDaliaslink(NXhandle file, NXdict dict, 
+                         char *pAlias1, char *pAlias2);
+   NXstatus NXDdeflink(NXhandle file, NXdict dict, 
+                         char *pDef1, char *pDef2);
+
+   NXstatus NXDopenalias(NXhandle file, NXdict dict, 
+                        char *alias);
+   NXstatus NXDopendef(NXhandle file, NXdict dict, char *pDefString);
+
+@}
+ The NXDICT data handling functions go in pairs. The version ending in
+ alias expects an NXdict and an alias as input. These routines work
+ out the pass from that. These routines also resolve all text replacement 
+ operations automatically. The other version ending on def acts upon 
+ a definition string specified as second parameter. Using this scheme
+ both full dictionary operation is possible, as well as operation with
+ program generated definition strings. All routines return the
+ usual NeXus status returns. All these routines start at the current vGroup
+ level and return back to it.  
+
+ NXDputalias, NXDputdef write the data element specified by the alias or
+ the definition string to the NeXus file specified as first parameter. 
+ pData is a pointer to the data to be written. These routines will check for
+ the existence of all vGroups required in the path part of the definition
+ string. If a vGroup  is missing it will be created. These routines step
+ back to the same vGroup level from which they were called.
+
+ NXDgetalias, NXDgetdef read a data item from file. pData MUST point to a
+ data area large enough to hold the data read. If a vGroup is missing in
+ the path for one of these routines an error is generated because it is 
+ assumed that the data is present if a program wants to read it. These 
+ routines step
+ back to the same vGroup level from which they were called.
+ 
+ NXDaliaslink, NXDdeflink links the alias or definition given as fourth
+ parameter to the vGroup specified by the  third parameter. pAlias1 or
+ pDef1 MUST refer to a vGroup (we cannot link to a SDS, can't we?). The
+ item being linked against MUST exist, otherwise the software will complain.
+ The vGroup into which the link is installed will be created on the fly,
+ if not present.
+ Please note, that bot aliases or definition strings specified need to
+ start from the same vGroup position.  These routines step
+ back to the same vGroup level from which they were called. 
+
+ NXDopenalias, NXDopendef open the specified data items specified by the
+ alias or the definition string. Then the usual NeXus functions can be 
+ used to interact with the data. These routines use the same scheme for
+ creating vGroups on the fly as the put routines above. The status in the
+ vGroup hierarchy after this call is dependent on the nature of the terminal
+ symbol. If it is a SDS, the vGroup hierarchy will be stepped back to the
+ level from which the call occurred. The SDS will be left open. If the
+ terminal symbol is a vGroup, then the this vGroup will be made the current
+ vGroup. No back stepping occurs. 
+
+
+  
+  \subsection{NeXus Utility Functions}
+  This section list a couple of functions which either perform common 
+   tasks on NeXus files or relate
+  to aspects of error handling and debugging.
+
+ at d dicutil @{
+        NXstatus NXUwriteglobals(NXhandle file, 
+                            char *filename,
+                            char *owner,
+                            char *adress,
+                            char *phone,
+                            char *email,
+                            char *fax,
+                            char *thing);
+
+
+   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class);
+   NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, 
+                          int rank, int dim[], char *pUnits);
+   
+   NXstatus NXUallocSDS(NXhandle hFil, void **pData);
+   NXstatus NXUfreeSDS(void **pData);
+
+@}
+
+ {\bf NXUwriteglobals} writes the global attributes to a newly opened 
+ NeXus file. The parameters should be self explaining. In addition 
+ the file creation date is automatically written.
+
+
+ {\bf NXUentergroup} tries to open the group specified by name and class.
+ If it not present, it will be created and opened.
+
+ {\bf NXUenterdata} tries to open the SDS specified by label.
+ If it not present, it will be created and opened.
+
+  {\bf NXUallocSDS} allocates enough space for the currently open SDS. The
+  pointer created is returned in pData. 
+
+  {\bf NXUfreeSDS} returns memory allocated by NXUallocSDS to the system.
+
+
+\section{Implementation}
+\subsection{The NXDICT Data Structure}
+The NXDICT--API is based on a dictionary which maps an alias to a definition
+string in NXDDL. Clearly, the first thing needed is a dictionary which maps
+key string to value strings. It was chosen to use an existing string
+dictionary (developed for SICS) as the dictionary for the NXDICT--API. This
+is realised and documented in files stringdict.*. This string dictionary is
+based on a linked list implementation available in the public domain (Files
+lld.*). This is not the most efficient approach as any search requires
+searching at maximum the whole linked list via strcmp. More efficient
+dictionaries would use hash tables or binary trees. However, implementation
+of a more efficient dictionary will be    delayed until it is proven that
+the current approach poses a serious performance problem.  
+
+Thus, the NXdict data structure looks like this:
+ at d dicdat @{
+    typedef struct __NXdict
+                           {
+                               int iID;
+                               pStringDict pDictionary;
+                           } sNXdict;
+/*------------------ verbosity level -------------------------------------*/
+   static int iVerbosity = 0 ;
+@}
+The first data member is a magic ID number which will be used for testing
+pointers passed in as NXdict pointers. C permits any pointer to be passed
+here. But only those with the correct magic number will be accepted. The
+next data member is a pointer to the string dictionary used for implementing
+the dictionary.
+
+Another feature is the verbosity level. This one is declared as a file
+static in order to be available generally.
+
+\subsection{The Dictionary Maintainance Functions}
+\subsubsection{NXDinitfromfile}
+This routine starts off by creating and initializing a new NXdict structure:
+ at d iniini @{
+     /* allocate a new NXdict structure */
+     if(iVerbosity == NXalot)
+     {
+         NXIReportError(NXpData, "Allocating new NXdict structure ");
+     }
+     pNew = (NXdict)malloc(sizeof(sNXdict));
+     if(!pNew)
+     {
+         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");
+         return NX_ERROR;
+     }
+     
+     /* initialise it */
+     pNew->iID = NXDMAGIC;
+     pNew->pDictionary = CreateStringDict();
+     if(!pNew->pDictionary)
+     {
+         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");
+         free(pNew);
+         return NX_ERROR;
+     }
+
+@} 
+
+The next step is to check for the existence of a filename. If filename is
+NULL we are done:
+ at d inicheck @{
+     /* is there a file name argument */
+     if(filename == NULL)
+     {
+        if(iVerbosity == NXalot)
+        {
+           NXIReportError(NXpData, "NXDinitfrom file finished without data");
+        }
+        *pData = pNew;
+        return NX_OK;
+     }
+@}
+
+The next step is to open the file:
+ at d inifil @{
+      fd = fopen(filename,"rb");
+      if(!fd)
+      {
+         sprintf(pError,"ERROR: file %s NOT found ",filename);
+         NXIReportError(NXpData, pError);
+         NXIReportError(NXpData, "NXDinitfrom file finished without data");
+         *pData = pNew;
+         return NX_ERROR;
+      }
+
+
+@}
+
+Now this file needs to be parsed and the alias -- definition string pairs to
+be extracted. This is done in two steps: First the file contents is copied
+in a buffer. Then this buffer is parsed. This aproach has the advantage that
+the parsing code can be reused if another source for the dictionary
+definition shows up. For instance if it is decided to include it with the
+NeXus file in a special vGroup. 
+ at d iniparse @{
+       /* read the file contents */
+       if(iVerbosity == NXalot)
+       {
+          NXIReportError(NXpData, "NXDinitfrom: reading file");
+       }
+       pBuffer = NXDIReadFile(fd);
+       fclose(fd); /* we are done with it then */
+       if(!pBuffer)
+       {
+         sprintf(pError,"ERROR: reading file %s or no memory",filename);
+         NXIReportError(NXpData, pError);
+         NXIReportError(NXpData, "NXDinitfrom file finished without data");
+         *pData = pNew;
+         return NX_ERROR;
+       }
+
+       /* parse it */
+       if(iVerbosity == NXalot)
+       {
+          NXIReportError(NXpData, "NXDinitfrom: parsing dictionary definitions");
+       }
+       NXDIParse(pBuffer, pNew->pDictionary);
+@}
+Once this has been done, the task left is to clean up and exit.  
+
+\paragraph{NXDIReadFile}
+This is an internal function which determines the length of the file,
+allocates a suitable buffer for it and then reads the file in the buffer.
+Please note, that the code for determining the length of the file works
+nicely on a Unix or DOS. On a VMS however, there might be a few rubbish
+characters at the end of the buffer. This is due to the record structure of
+files under VMS. 
+
+\paragraph{NXDIParse}
+NXDIParse is an internal function which parses a buffer into aliases and
+values. It is one of two parsers in the nxdict system. Later on there will
+be a definition string parser.  This file reading parser uses a 
+Tokenizer.
+
+The Tokenizer does not need to recognize a lot of
+tokens, so it is rather simple. NXDIfNextToken returns a pointer pointing to
+the character after the last token read. pPtr is the current position in
+the buffer. The value of the last token read will be returned in the buffer
+pToken. iToken will be set to the type of token recognized.
+  
+ at d ftoken @{
+#define FWORD 1
+#define FHASH 2
+#define FEOL  3
+#define FEOB  4
+#define FEQUAL 5
+#define FSLASH 6
+
+   static char *NXDIfNextToken(char *pPtr, char *pToken, int *iToken)
+   {
+       pToken[0] = '\0';
+       /* skip whitespace */
+       while( (*pPtr == ' ') || (*pPtr == '\t') )
+       {
+         pPtr++;
+       } 
+
+       /* check for special characters */
+       if(*pPtr == '#')
+       {
+         *iToken = FHASH;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '\n')
+       {
+         *iToken = FEOL;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '\0')
+       {
+         *iToken = FEOB;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '=')
+       {
+         *iToken = FEQUAL;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else if(*pPtr == '\\')
+       {
+         *iToken = FSLASH;
+         pToken[0] = *pPtr;
+         pPtr++;
+         return pPtr;
+       }
+       else 
+       {
+         *iToken = FWORD;
+         /* copy word to pToken */
+         while( (*pPtr != ' ') && (*pPtr != '\t') && 
+                (*pPtr != '\n') && (*pPtr != '\0') && (*pPtr != '=') )
+         {
+           *pToken = *pPtr;
+           pPtr++;
+           pToken++;
+         } 
+         *pToken = '\0';
+         return pPtr;
+       }
+      /* not reached */
+      return pPtr;
+   }
+    
+@}
+
+
+NXDIParse has two modes: parsing an alias  or parsing a definition string.
+ 
+ at d fparse @{
+#define AMODE 0
+#define DMODE 1
+
+  static void  NXDIParse(char *pBuffer, pStringDict pDict)
+  {
+     char *pPtr;
+     int iToken;
+     int iMode;
+     char pAlias[132];
+     char pDefinition[1024]; /* this is > 10 lines of definition */
+     char pWord[132];
+
+     assert(pBuffer);
+     assert(pDict);
+
+     iMode = AMODE;
+     pPtr = pBuffer;
+     iToken = -1;
+     pDefinition[0] = '\0';
+     pAlias[0] = '\0';
+     pWord[0] = '\0';
+
+     while(iToken != FEOB)
+     {
+         pPtr = NXDIfNextToken(pPtr,pWord,&iToken);
+         switch(iToken)
+         {
+           case FHASH:
+           case FSLASH: /* skip over \n to next non blank */
+                       while(*pPtr != '\n')
+                       {
+                          pPtr++;
+                          /* check for end of file */
+                          if(*pPtr == '\0')
+                          {
+                            return;
+                          }
+                       }
+                       pPtr++;
+                       break;
+           case FEQUAL: /* do a mode change */
+                       iMode = DMODE;
+                       pDefinition[0] = '\0';
+                       break;
+
+           case FWORD:
+                       if(iMode == AMODE)
+                       {
+                         strcpy(pAlias,pWord);
+                       }  
+                       else
+                       {
+                         strcat(pDefinition,pWord);
+                         strcat(pDefinition," ");
+                       }
+                       break;
+           case FEOL:
+                       if(iMode == DMODE)
+                       {
+                          /* enter in dictionary */
+                          StringDictAddPair(pDict,pAlias,pDefinition);
+                          iMode = AMODE;
+                          pAlias[0] = '\0';
+                       }
+                       break;
+           case FEOB:
+                       if(iMode == AMODE) 
+                       {
+                         /* empty line or a problem */
+                       }          
+                       else
+                       {
+                          /* enter in dictionary */
+                          StringDictAddPair(pDict,pAlias,pDefinition);
+                          iMode = AMODE;
+                          pAlias[0] = '\0';
+                       }
+                       return;
+           default:
+                   assert(0); /* unrecognized token is a programming
+                                 error
+                              */
+                   break;
+         }
+     }
+  }
+@}   
+
+\subsubsection{NXDClose}
+This routine will just write the dictionary to file if requested and clean
+up afterwards. Prior to defining NXDClose anohter internal function is
+needed which checks the validity of the handle passed into the routine.
+
+ at d dassert @{
+   NXdict NXDIAssert(NXdict handle)
+   {
+      NXdict self = NULL;
+      assert(handle);
+      self = (NXdict)handle;
+      assert(self->iID == NXDMAGIC);
+      return self;
+   }
+@}
+
+ at d dclose @{
+   NXstatus NXDclose(NXdict handle, char *filename)
+   {
+      NXdict self;
+      const char *pKey = NULL;
+      char pValue[1024];
+      FILE *fd = NULL;
+
+      self = NXDIAssert(handle);
+
+      if(filename) /* we must write a file */
+      {
+        if(iVerbosity == NXalot)
+        {
+           sprintf(pValue,"Writing file %s",filename);
+           NXIReportError(NXpData, pValue);
+        }
+        fd = fopen(filename,"w");
+        if(!fd)
+        {
+           sprintf(pValue,"ERROR: opening file %s for write",filename);
+           NXIReportError(NXpData, pValue);
+           return NX_ERROR;
+        }   
+        
+        /* write our magic recognition header */
+        fprintf(fd,"##NXDICT-1.0\n");
+
+        /* write all our keys */
+        pKey = StringDictGetNext(self->pDictionary, pValue,1023);
+        while(pKey != NULL)
+        {
+          fprintf(fd,"%s = %s\n",pKey,pValue);
+          pKey = StringDictGetNext(self->pDictionary,pValue,1023);
+        }
+        fclose(fd);
+        if(iVerbosity == NXalot)
+        {
+           sprintf(pValue,"File %s written",filename);
+           NXIReportError(NXpData, pValue);
+        }
+      }
+
+      /* now we send the cleaners in */
+      DeleteStringDict(self->pDictionary);
+      free(self);
+      return NX_OK;
+   }
+@}
+
+\subsubsection{NXDadd, NXDget, NXDupdate}
+These are very much only wrapper function around the corresponding functions
+for maintaining StringDicts. Accordingly, they are fairly simple.
+ at d dmaintain @{
+   NXstatus NXDadd(NXdict handle, char *alias, char *pDef)
+   {
+     NXdict self;
+     int iRet;
+
+     self = NXDIAssert(handle);
+     iRet = StringDictAddPair(self->pDictionary,alias,pDef);
+     if(!iRet)
+     {
+       return NX_ERROR;
+     }
+     return NX_OK;
+   }
+/*---------------------------------------------------------------------------*/
+   NXstatus NXDget(NXdict handle, char *pKey, char *pBuffer, int iBufLen)
+   {
+     NXdict self;
+     int iRet;
+
+     self = NXDIAssert(handle);
+     iRet = StringDictGet(self->pDictionary,pKey,pBuffer,iBufLen);
+     if(!iRet)
+     {
+       return NX_ERROR;
+     }
+#ifdef DEFDEBUG
+     printf("Resolved: %s to %s\n",pKey,pBuffer);
+#endif
+     return NX_OK;
+   }
+/*-------------------------------------------------------------------------*/
+   NXstatus NXDupdate(NXdict handle, char *pKey, char *pNewVal)
+   {
+     NXdict self;
+     int iRet;
+
+     self = NXDIAssert(handle);
+     iRet = StringDictUpdate(self->pDictionary,pKey,pNewVal);
+     if(!iRet)
+     {
+       return NX_ERROR;
+     }
+     return NX_OK;
+   }
+
+@}
+\subsubsection{Text replacement}
+A definition string as retrieved from the string dictionary may still
+contain text replacement items. The next function, NXDtextreplace resolves
+these text replacements.
+
+ at d textrep @{
+#define NORMAL 1
+#define ALIAS  2
+   pDynString NXDItextreplace(NXdict handle, char *pDefString)
+   {
+     NXdict self;
+     int iRet, iPos, i;
+     pDynString pReplaced = NULL;
+     char pBueffel[1024];
+     char pBuffer2[1024];
+     char *pPtr;
+     int iState;
+
+     self = NXDIAssert(handle);
+     
+     /* create a dynamic string */
+     pReplaced = CreateDynString(strlen(pDefString),512);
+     if(!pReplaced)
+     {
+       NXIReportError(NXpData,"ERROR: out of memory in NXDtextreplace");
+       return NULL;
+     }
+
+     /* the loop */
+     iState = NORMAL;
+     for(i = 0, pPtr = pDefString; i < strlen(pDefString); i++,pPtr++)
+     {
+        if(iState == NORMAL)
+        {
+           if(*pPtr == '$')
+           {
+             iState = ALIAS;
+             memset(pBueffel,0,1024);
+             iPos = 0;
+           }
+           else
+           {
+               DynStringConcatChar(pReplaced,*pPtr);
+           }
+        }
+        else if(iState == ALIAS)
+        {
+           switch(*pPtr)
+           {
+             case '(': /* ignore */
+                       break;
+             case ')': 
+                       /* do the replacement */
+                       memset(pBuffer2,0,1023);
+                       iRet = NXDget(handle, pBueffel,pBuffer2,1023);
+                       if(iRet != NX_OK)
+                       {
+                         DeleteDynString(pReplaced);
+                         return NULL;
+                       }
+                       DynStringConcat(pReplaced,pBuffer2);
+                       iState = NORMAL;
+                       break;
+             default:
+                       pBueffel[iPos] = *pPtr;
+                       iPos++;
+                       if(iPos >= 1024)
+                       {
+                          NXIReportError(NXpData,
+                                     "ERROR: buffer overrun in NXDItextreplace");
+                          DeleteDynString(pReplaced);
+                          return NULL;
+                       }
+                       break;
+           }
+        }
+     }
+#ifdef DEFDEBUG
+    printf("Replacement result: %s\n",GetCharArray(pReplaced));
+#endif
+     return pReplaced;
+   }
+/*--------------------------------------------------------------------------*/
+   NXstatus NXDtextreplace(NXdict handle, char *pDefString, 
+                           char *pBuffer, int iBufLen)
+   {
+     pDynString pResult = NULL;
+     char *pPtr = NULL;
+
+     pResult = NXDItextreplace(handle,pDefString);
+     if(!pResult)
+     {
+         return NX_ERROR;
+     }
+
+     /* copy results home */
+     pPtr = GetCharArray(pResult);
+     strncpy(pBuffer,pPtr,iBufLen);   
+     DeleteDynString(pResult);
+     return NX_OK;
+   }
+@}
+
+\subsection{Dictionary Added Data Transfer}
+The heart of these routines is the NXDopendef function which opens the data
+item specified. Most of the other routines can be defined as wrappers to
+this one. That is why it is discussed as the first function. Again a parser
+is needed for parsing and interpreting the definition string. 
+
+\subsubsection{The Definition String Parser}
+The definition string  parser is implemented as a classic recursive descent 
+parser. And once
+more again a Tokenizer is needed. The Tokenizer has an own datastructure for
+holding token information in a static array:
+
+ at d tokdat @{
+  typedef struct {
+                  char pText[20];
+                  int iCode;
+                 }  TokDat;
+@}
+
+In order to do the parsing a data structure for holding parsing information
+is necessary:
+
+ at d padef @{
+#define TERMSDS 100
+#define TERMVG  200
+#define TERMLINK 300
+
+   typedef struct {
+                    char *pPtr;
+                    char pToken[256];
+                    int iToken;
+                    int iDepth;
+                    int iMayCreate;
+                    int iTerminal;
+                  } ParDat;
+@}
+In this structure pPtr is the current position in the buffer, iToken the ID
+of the current token, pToken the text of the current token, iDepth gets
+incremented whenever a vGroup is opened. This is needed in order to roll the
+vGroups back in the hierarchy after finishing operations. iMayCreate will be
+set if the path parsing function may create new vGroups if the one requested
+can not be found.
+
+This is the tokenizer:
+ at d deftok @{
+/*---------------- Token name defines ---------------------------*/
+#define DSLASH 0
+#define DKOMMA 1
+#define DSDS   2
+#define DLINK  3
+#define DGROUP 4
+#define DRANK  5
+#define DDIM   6
+#define DTYPE  7
+#define DWORD  9
+#define DOPEN  10
+#define DCLOSE 11
+#define DATTR  12
+#define DEND   13
+
+/*----------------- Keywords ----------------------------------------*/
+
+  static TokDat TokenList[9] = { 
+                                {"SDS",DSDS},
+                                {"NXLINK",DLINK},
+                                {"NXVGROUP",DGROUP},
+                                {"-dim",DDIM},
+                                {"-type",DTYPE},
+                                {"-rank",DRANK},
+                                {"-attr",DATTR},
+                                {NULL,0} };
+
+/*-----------------------------------------------------------------------*/
+   static void NXDIDefToken(ParDat *sStat)
+   {
+       int i;
+       
+
+       sStat->pToken[0] = '\0';
+
+       /* skip whitespace */
+       while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') )
+       {
+         sStat->pPtr++;
+       } 
+
+       /* check for special characters */
+       if(*(sStat->pPtr) == '/')
+       {
+         sStat->iToken = DSLASH;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == ',')
+       {
+         sStat->iToken = DKOMMA;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '\0')
+       {
+         sStat->iToken = DEND;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '{')
+       {
+         sStat->iToken = DOPEN;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else if(*(sStat->pPtr) == '}')
+       {
+         sStat->iToken = DCLOSE;
+         sStat->pToken[0] = *(sStat->pPtr);
+         sStat->pPtr++;
+         return;
+       }
+       else 
+       {
+         sStat->iToken = DWORD;
+         /* copy word to pToken */
+         i = 0;
+         while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') && 
+                (*(sStat->pPtr) != '/') && (*(sStat->pPtr) != '\0') &&
+                (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') )
+         {
+           sStat->pToken[i] = *(sStat->pPtr);
+           sStat->pPtr++;
+           i++;
+         } 
+         sStat->pToken[i] = '\0';
+
+         /*--------- try to find word in Tokenlist */
+         for(i = 0; i < 7; i++)
+         {
+           if(strcmp(sStat->pToken,TokenList[i].pText) == 0)
+           {
+             sStat->iToken = TokenList[i].iCode;
+             break;
+           }
+         }
+         return;
+       }
+      /* not reached */
+      return;
+   }
+
+@}
+
+Now, finally we can define the parser! This parser is universally used by
+all the data transfer functions.  Input is the file handle of the NeXus file
+and a pointer to an initialised ParDat structure. It is expected, that the
+pPtr field points to the start of the definition string, that iMayCreate is
+properly defined and that iDepth is 0. 
+
+ at d defpar @{
+    static int NXDIDefParse(NXhandle hFil, NXdict pDict, ParDat *pParse)
+    {
+       int iRet;
+       char pError[256];
+ 
+       pParse->iToken = -1;
+       while(pParse->iToken != DEND)
+       {
+         NXDIDefToken(pParse); /* next token */
+         switch(pParse->iToken)
+         {
+            case DEND:
+                      break;
+            case DSLASH:
+                      iRet = NXDIParsePath(hFil, pParse);
+                      if(iRet == NX_ERROR)
+                      {
+                         return NX_ERROR;
+                      }
+                      break;
+            case DSDS:
+                      iRet = NXDIParseSDS(hFil, pParse);
+                      if(iRet == NX_ERROR)
+                      {
+                         return NX_ERROR;
+                      }
+                      pParse->iTerminal = TERMSDS;
+                      break;
+            case DLINK:
+                      iRet = NXDIParseLink(hFil,pDict, pParse);                      
+                      if(iRet == NX_ERROR)
+                      {
+                         return NX_ERROR;
+                      }
+                      pParse->iTerminal = TERMLINK;
+                      break;
+            case DGROUP:
+                      pParse->iTerminal = TERMVG;
+                      return NX_OK;
+            default:
+                     sprintf(pError,
+            "ERROR: Definition String parse error: %s not permitted here",
+             pParse->pToken);
+                     NXIReportError(NXpData,pError);
+                     return NX_ERROR;
+                     break;
+         }
+       }
+       return NX_OK;
+    }
+@}
+
+The next thing to do is to implement ParsePath. This will try to interpret a
+path string and initiate the apropriate actions, i.e. opening vGroups or
+creating them. However, there is a small problem here. The code needs to
+know if the vGroup exists. This can be checked by trying to open the group
+with NXopengroup. This will return an error if this group does not exist.
+NXopengroup will also print an error message saying so. This is not what is
+wanted here, as we might choose to create the missing group silently.
+ In order to suppress
+that one, it is needed to replace the current error handler by a dummy which
+just prints nothing anywhere and to step back to the original handler once
+we are done. The other option would be to use internals of the NeXus API
+implementation. However, the aim is to keep the original NeXus API and this
+as independent as possible.  Consequently, here is the definition of the
+dummy error handler:
+ at d dummyerr @{
+   static void DummyError(void *pData, char *pError)
+   {
+     return;
+   }
+@}
+
+
+When NXDIParsePath has been called the / has already been read.
+NXDIParsePath has to read the name and class of the vGroup separated by a
+komma. Then it has either to open the vGroup, and if this fails create it if
+the create flag in pParse is set.
+
+ at d defpath @{
+   int NXDIParsePath(NXhandle hfil, ParDat *pParse)
+   {
+       int iRet, iToken;
+       void (*ErrFunc)(void *pData, char *pErr); 
+       char pName[132], pClass[132];
+       char pError[256];
+
+       /* get the name */
+       NXDIDefToken(pParse); /* next token */
+       if( (pParse->iToken == DSDS) || (pParse->iToken == DGROUP)
+           || (pParse->iToken == DLINK) )
+       {
+         /* put back & OK */
+         pParse->pPtr -= strlen(pParse->pToken);
+         return NX_OK;
+       }
+       if(pParse->iToken != DWORD)
+       {
+          sprintf(pError,"ERROR: parse error at %s, expected vGroup name",
+                  pParse->pToken);
+          NXIReportError(NXpData, pError);
+          return NX_ERROR;
+       }       
+       strcpy(pName,pParse->pToken);
+     
+       /* now we expect a komma */
+       NXDIDefToken(pParse); /* next token */
+       if(pParse->iToken != DKOMMA)
+       {
+          sprintf(pError,"ERROR: parse error at %s, expected komma",
+                  pParse->pToken);
+          NXIReportError(NXpData, pError);
+          return NX_ERROR;
+       }       
+
+       /* next must be the class */
+       NXDIDefToken(pParse); /* next token */
+       if(pParse->iToken != DWORD)
+       {
+          sprintf(pError,"ERROR: parse error at %s, expected vGroup class",
+                  pParse->pToken);
+          NXIReportError(NXpData, pError);
+          return NX_ERROR;
+       }       
+       strcpy(pClass,pParse->pToken);
+
+       /* done reading, ACTION, first install dummy error handler */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening vGroup */
+       iRet = NXopengroup(hfil, pName, pClass);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         pParse->iDepth++;
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it, if we may */
+          if(pParse->iMayCreate)
+          {
+            iRet = NXmakegroup(hfil,pName,pClass);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXopengroup(hfil,pName,pClass);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            pParse->iDepth++;
+            return NX_OK; 
+          }
+          else
+          {
+             /* this is an error */
+             sprintf(pError,"ERROR: vGroup %s, %s NOT found",pName, pClass);
+             NXIReportError(NXpData,pError);
+             return NX_ERROR;
+          }
+       }
+       /* not reached */
+       return NX_ERROR;
+   }
+@} 
+
+
+NXDIParseSDS is more involved, as we have to deal with all the extras an SDS
+can have: dimensions, types etc. Each of these options can be present or
+not, and these options can go in any order. Particularly troublesome are
+attributes which can only be written after opening or creating an SDS. this
+implies that attributes have to be stored in a list during parsing in order
+to have them available after creation or opening of the SDS. This requires
+another private data structure for holding attribute information during
+parsing:
+ at d attitem @{
+  typedef struct {
+                   char name[256];
+                   char value[256];
+                  }AttItem;
+@}
+
+
+ at d nxpasds @{
+   static int NXDIParseSDS(NXhandle hfil, ParDat *pParse)
+   {
+      int iType = DFNT_FLOAT32;
+      int iRank = 1;
+      int32 iDim[MAX_VAR_DIMS];
+      int iList;
+      int iRet, iStat, i;
+      char pError[256];
+      char pName[MAX_NC_NAME];
+      void (*ErrFunc)(void *pData, char *pErr);
+      AttItem sAtt; 
+
+
+       iDim[0] = 1;
+       /* first find the name */
+       NXDIDefToken(pParse);
+       if(pParse->iToken != DWORD)
+       {
+          sprintf(pError,"ERROR: parsing, expected name, got %s",
+                  pParse->pToken);
+          NXIReportError(NXpData,pError);
+          return NX_ERROR;
+       }
+        strcpy(pName,pParse->pToken);
+
+       /* create the attribute list */
+       iList = LLDcreate(sizeof(AttItem));
+       if(iList < 0)
+       {
+          NXIReportError(NXpData, "ERROR: cannot create list in NXDIParseSDS");
+          return NX_ERROR;
+       }
+
+       NXDIDefToken(pParse);
+       while(pParse->iToken != DEND)
+       {
+          switch(pParse->iToken)
+          {
+            case DRANK: /* rank */
+                       NXDIDefToken(pParse); /* advance */
+                       if(pParse->iToken != DWORD)
+                       {
+                         sprintf(pError,
+                         "ERROR: expected int, got %s", pParse->pToken);
+                          NXIReportError(NXpData,pError);
+                          LLDdelete(iList);
+                          return NX_ERROR; 
+                       }
+                       iRank = atoi(pParse->pToken);
+                       break;
+            case DDIM:
+                     iRet = NXDIParseDim(pParse, iDim);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     break;
+            case DTYPE:
+                     iRet = NXDIParseType(pParse, &iType);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     break;
+            case DATTR:
+                     iRet = NXDIParseAttr(pParse, iList);
+                     if(iRet == NX_ERROR)
+                     {
+                        LLDdelete(iList);
+                        return iRet;
+                     } 
+                     break;
+            case DEND:
+                     break;
+            default:
+                     sprintf(pError,"ERROR: cannot identify token %s",
+                                     pParse->pToken);
+                     NXIReportError(NXpData, pError);
+                     LLDdelete(iList);
+                     return NX_ERROR;
+                    
+          }
+          NXDIDefToken(pParse);
+       }
+       
+       /* whew! got all information for doing the SDS */
+       /* first install dummy error handler, try open it, then
+          deinstall again and create if allowed 
+       */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening SDS */
+       iRet = NXopendata(hfil, pName);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         LLDdelete(iList);
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it, if we may */
+          if(pParse->iMayCreate)
+          {
+            iRet = NXmakedata(hfil,pName,iType, iRank,iDim);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 LLDdelete(iList);
+                 return iRet;
+            }
+            iRet = NXopendata(hfil,pName);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 LLDdelete(iList);
+                 return iRet;
+            }
+            /* put attributes in */
+            iRet = LLDnodePtr2First(iList);
+            while(iRet != 0)
+            {
+              LLDnodeDataTo(iList,&sAtt);
+              iStat = NXputattr(hfil,sAtt.name,
+                                sAtt.value,strlen(sAtt.value),NX_CHAR);
+              if(iStat != NX_OK)
+              {
+                 /* NeXus already complained bitterly */
+                 LLDdelete(iList);
+                 return iStat;
+              }
+              iRet = LLDnodePtr2Next(iList);
+            }
+            LLDdelete(iList);
+            return NX_OK; 
+          }
+          else
+          {
+             /* this is an error */
+             sprintf(pError,"ERROR: SDS %s NOT found",pName);
+             NXIReportError(NXpData,pError);
+             LLDdelete(iList);
+             return NX_ERROR;
+          }
+       }
+       return NX_OK;
+   }
+@}
+
+NXDIParseType is fairly straightforward: read a word and try to interpret it 
+as one of the standard NeXus data types.
+
+ at d parsetype @{
+   static TokDat tDatType[] = {
+                      {"DFNT_FLOAT32",DFNT_FLOAT32},   
+                      {"DFNT_FLOAT64",DFNT_FLOAT64},    
+                      {"DFNT_INT8",DFNT_INT8},  
+                      {"DFNT_UINT8",DFNT_UINT8},
+                      {"DFNT_INT16",DFNT_INT16},      
+                      {"DFNT_UINT16",DFNT_UINT16},
+                      {"DFNT_INT32",DFNT_INT32},
+                      {"DFNT_UINT32",DFNT_UINT32},
+                      {NULL,-122} };
+
+
+
+   static int NXDIParseType(ParDat *pParse, int *iType)
+   {
+      char pError[256];
+      int i = 0;
+
+      NXDIDefToken(pParse);
+      if(pParse->iToken != DWORD)
+      { 
+        sprintf(pError,"ERROR: expected data type, got %s", pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+      }
+       
+      /* try to interpret data type */
+      while(tDatType[i].iCode > 0) {
+        if(strcmp(tDatType[i].pText,pParse->pToken) == 0)
+        {
+           *iType = tDatType[i].iCode;
+            return NX_OK;
+        }
+        i++;
+      }
+      /* if we are here, the data type has not been recognized. Reason for
+         some boring error reporting code
+      */
+      sprintf(pError,"ERROR: %s not recognized as valid data type",
+                      pParse->pToken);
+      NXIReportError(NXpData,pError);
+      return NX_ERROR;      
+   }
+@}
+
+NXDIParseDim tries to read dimension information. This starts with a {
+followed by numbers and kommas until there is a closing curly brace.
+
+ at d parsedim @{
+   static int NXDIParseDim(ParDat *pParse, int *iDim)
+   {
+       char pError[256];
+       int iRet, i;
+
+        /* initialise dimensions to 0 */
+        for(i = 0; i < MAX_VAR_DIMS; i++)
+        {
+          iDim[i] = 0;
+        }
+
+        NXDIDefToken(pParse);
+        if(pParse->iToken != DOPEN)
+        {
+          sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);
+          NXIReportError(NXpData,pError);
+          return NX_ERROR;
+        }
+
+        i = 0;      
+        while(pParse->iToken != DCLOSE)
+        {
+           /* get a number */
+           NXDIDefToken(pParse);
+           if(pParse->iToken != DWORD)
+           {
+              sprintf(pError,"ERROR: expected number, got %s",pParse->pToken);
+              NXIReportError(NXpData,pError);
+              return NX_ERROR;
+           }
+           iDim[i] = atoi(pParse->pToken);
+           i++;
+           /* next must be close of komma */
+           NXDIDefToken(pParse);
+           if( (pParse->iToken != DKOMMA) && (pParse->iToken != DCLOSE) )
+           {
+              sprintf(pError,"ERROR: expected , or }, got %s",pParse->pToken);
+              NXIReportError(NXpData,pError);
+              return NX_ERROR;
+           }
+           if(pParse->iToken == DCLOSE)
+           {
+              break;
+           }
+        }
+        return NX_OK;
+   }
+@}
+
+NXDIParseAttr tries to parse an attribute and enters it into the attribute
+list.
+
+ at d parseatt @{
+   static int NXDIParseAttr(ParDat *pParse, int iList)
+   {
+     char pError[256];
+     int iRet;
+     AttItem sAtt;
+
+     /* a { is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DOPEN)
+     {
+        sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+
+     /* a word is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DWORD)
+     {
+        sprintf(pError,"ERROR: expected attribute name, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+     strcpy(sAtt.name,pParse->pToken);
+
+     /* a , is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DKOMMA)
+     {
+        sprintf(pError,"ERROR: expected , , got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+
+     /* a word is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DWORD)
+     {
+        sprintf(pError,"ERROR: expected attribute value, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+     strcpy(sAtt.value,pParse->pToken);
+
+     /* a } is expected */
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DCLOSE)
+     {
+        sprintf(pError,"ERROR: expected }, got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+
+     /* enter into list */
+     LLDnodeAppendFrom(iList,&sAtt);
+     return NX_OK;
+   }
+@} 
+
+The last part of the definition string parser is NXDIParseLink. This
+function parses and handles a link to another data item in the file.
+
+ at d parselink @{
+   static int NXDIParseLink(NXhandle hfil, NXdict pDict,ParDat *pParse)
+   {
+     char pError[256];
+     int i, iRet;
+
+     /* need one word of alias */ 
+     NXDIDefToken(pParse);
+     if(pParse->iToken != DCLOSE)
+     {
+        sprintf(pError,"ERROR: expected alias , got %s",pParse->pToken);
+        NXIReportError(NXpData,pError);
+        return NX_ERROR;
+     }
+    
+     /* move back in hierarchy */
+     for(i = 0; i < pParse->iDepth; i++)
+     {
+       iRet = NXclosegroup(hfil);
+       if(iRet == NX_ERROR)
+       {
+         return NX_ERROR;
+       }
+     }
+     
+     /* open the link instead */ 
+     return NXDopenalias(hfil, pDict, pParse->pToken);
+
+   }
+@}
+
+Another helper function unwinds the vGroup hierarchy.
+ at d unwind @{
+  static NXstatus NXDIUnwind(NXhandle hFil, int iDepth)
+  {
+     int i, iRet;
+      
+     for(i = 0; i < iDepth; i++)
+     {
+        iRet = NXclosegroup(hFil);
+        if(iRet != NX_OK)
+        {
+          return NX_ERROR;
+        }
+     }
+     return NX_OK;
+  }
+@}
+
+\subsubsection{NXDopendef}
+NXDopendef calls the definiton string parser and then just steps back in the
+vGroup hierarchy and stays there.
+
+ at d nxddefopen @{
+   NXstatus NXDopendef(NXhandle hfil, NXdict dict, char *pDef)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 1;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+     iRet = NXDIDefParse(hfil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+         iRet = NXDIUnwind(hfil,pParse.iDepth);
+         return NX_ERROR;
+     }
+
+     
+     /* try rewinding the hierarchy */
+     if(pParse.iTerminal == TERMSDS)
+     {
+         iStat = NXDIUnwind(hfil,pParse.iDepth);
+         if(iStat != NX_OK)
+         {
+            return NX_ERROR;
+         }
+     }
+     /* do not rewind on links */
+     return iRet;
+   }
+@}  
+
+\subsubsection{NXDopenalias}
+NXDOpenalias is just a wrapper around  NXDopendef which retrieves a
+definition string from the directory first.
+
+ at d nxdaliasopen @{
+   NXstatus NXDopenalias(NXhandle hfil, NXdict dict, char *pAlias)
+   {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[1024];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,1023);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+     
+     /* do the text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+         return NX_ERROR;
+     }
+
+     /* call NXDopendef */
+     iRet = NXDopendef(hfil,dict,GetCharArray(pReplaced));
+     DeleteDynString(pReplaced);
+     return iRet;
+   }
+@}  
+
+\subsubsection{NXDputdef}
+This routine puts a data item into a NeXus file using a definition string.
+This naturally can work only, if there is an SDS at the end.
+
+ at d nxput @{
+   NXstatus NXDputdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 1;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+#ifdef DEFDEBUG
+     printf("Putting: %s\n",pDef);
+#endif
+     iRet = NXDIDefParse(hFil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+          NXDIUnwind(hFil,pParse.iDepth);
+          return NX_ERROR;
+     }
+
+     
+     /* only SDS can be written */
+     if(pParse.iTerminal != TERMSDS)
+     {
+        NXIReportError(NXpData,
+                     "ERROR: can only write to an SDS!");
+        iStat = NX_ERROR;
+     } 
+     else 
+     {
+       /* the SDS should be open by now, write it */
+       iStat = NXputdata(hFil, pData);
+       iRet = NXclosedata(hFil);
+     }   
+
+
+     /* rewind the hierarchy */
+     iRet = NXDIUnwind(hFil,pParse.iDepth);
+     if(iRet != NX_OK)
+     {
+       return NX_ERROR;
+     }
+     return iStat;
+   }
+@}
+
+\subsubsection{NXDputalias}
+Just finds the definition string and calls NXputdef then.
+ at d nxdputalias @{
+  NXstatus NXDputalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)
+  {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[1024];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,1023);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+     
+     /* do text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+       return NX_ERROR;
+     }
+
+     /* call NXDputdef */
+     iRet = NXDputdef(hFil,dict,GetCharArray(pReplaced),pData);
+     DeleteDynString(pReplaced);
+     return iRet;
+  }
+@}
+
+\subsubsection{NXDgetdef}
+
+ at d nxget @{
+   NXstatus NXDgetdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)
+   {
+     NXdict pDict;
+     ParDat pParse;
+     int iRet, i, iStat;
+
+     pDict = NXDIAssert(dict);
+     
+     /* parse and act on definition string */
+     pParse.iMayCreate = 0;
+     pParse.pPtr = pDef;
+     pParse.iDepth = 0;
+#ifdef DEFDEBUG
+     printf("Getting: %s\n",pDef);
+#endif
+     iRet = NXDIDefParse(hFil,pDict,&pParse);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParse.iDepth);
+          return NX_ERROR;
+     }
+
+
+     /* only SDS can be written */
+     if(pParse.iTerminal != TERMSDS)
+     {
+        NXIReportError(NXpData,
+                     "ERROR: can only write to an SDS!");
+        iStat = NX_ERROR;
+     } 
+     else 
+     {
+       /* the SDS should be open by now, read it */
+       iStat = NXgetdata(hFil, pData);
+       iRet = NXclosedata(hFil);
+     }   
+
+
+     /* rewind the hierarchy */
+     iRet = NXDIUnwind(hFil,pParse.iDepth);
+     if(iRet != NX_OK)
+     {
+        return NX_ERROR;
+     }
+     return iStat;
+   }
+@}
+
+\subsubsection{NXgetalias}
+Just finds the definition string and calls NXgetdef then.
+ at d nxdgetalias @{
+  NXstatus NXDgetalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)
+  {
+     NXdict pDict;
+     int iRet;
+     char pDefinition[1024];
+     pDynString pReplaced = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Definition String  */
+     iRet = NXDget(pDict,pAlias,pDefinition,1023);
+     if(iRet != NX_OK)
+     {
+        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
+        NXIReportError(NXpData,pDefinition);
+        return NX_ERROR;
+     }
+ 
+     /* do text replacement */
+     pReplaced = NXDItextreplace(dict,pDefinition);
+     if(!pReplaced)
+     {
+       return NX_ERROR;
+     }
+     
+     /* call NXDgetdef */
+     iRet = NXDgetdef(hFil,dict,GetCharArray(pReplaced),pData);
+     DeleteDynString(pReplaced);
+     return iRet;
+  }
+@}
+
+\subsubsection{NXDdeflink, NXDaliaslink}
+The first alias/definition string must be a vGroup, the other can be a
+vGroup or a SDS.
+
+ at d nxlink @{
+  NXstatus NXDdeflink(NXhandle hFil, NXdict dict, 
+                      char *pTarget, char *pVictim)
+  {
+     NXdict pDict;
+     ParDat pParseT, pParseV;
+     int iRet, i, iStat;
+     NXlink sLink;
+
+     pDict = NXDIAssert(dict);
+
+
+#ifdef DEFDEBUG
+     printf("Linking: %s\n",pVictim);
+     printf("To: %s\n", pTarget);
+#endif
+     
+
+     /* parse Victim  */
+     pParseV.iMayCreate = 0;
+     pParseV.pPtr = pVictim;
+     pParseV.iDepth = 0;
+     iRet = NXDIDefParse(hFil,pDict,&pParseV);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParseV.iDepth);
+          return NX_ERROR;
+     }
+     /* get link data */
+     if(pParseV.iTerminal == TERMSDS)
+     {
+       NXgetdataID(hFil,&sLink);
+       iRet =  NXclosedata(hFil);
+       if(iRet != NX_OK)
+       {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParseV.iDepth);
+          return NX_ERROR;
+       }
+     }
+     else if(pParseV.iTerminal == TERMVG)
+     {
+       NXgetgroupID(hFil,&sLink);
+     }
+     else
+     {
+        assert(0); /* serious programming error */
+     }
+     /* Unwind */
+     iRet = NXDIUnwind(hFil,pParseV.iDepth);
+     if(iRet != NX_OK)
+     {
+       return NX_ERROR;
+     }
+
+     /* parse Target */
+     pParseT.iMayCreate = 1;
+     pParseT.pPtr = pTarget;
+     pParseT.iDepth = 0;
+     iRet = NXDIDefParse(hFil,pDict,&pParseT);
+     if(iRet == NX_ERROR)
+     {
+         /* unwind and throw up */
+          NXDIUnwind(hFil,pParseT.iDepth);
+          return NX_ERROR;
+     }
+     /* check it being a vGroup! */
+     if(pParseT.iTerminal != TERMVG)
+     {
+       NXIReportError(NXpData,"ERROR: can link only into a vGroup");
+       NXDIUnwind(hFil,pParseT.iDepth);
+       return NX_ERROR;
+     }
+    
+     /* link, finally */
+     iRet = NXmakelink(hFil,&sLink);
+     /* Unwind anyway */
+     iStat = NXDIUnwind(hFil,pParseT.iDepth);
+     if(iStat != NX_OK)
+     {
+       return NX_ERROR;
+     }
+     return iStat;
+  }
+/*--------------------------------------------------------------------------*/
+  NXstatus NXDaliaslink(NXhandle hFil, NXdict dict, 
+                      char *pTarget, char *pVictim)
+  {
+    char pTargetDef[1024], pVictimDef[1024];
+    int iRet;
+    NXdict pDict;
+    pDynString pRep1 = NULL, pRep2 = NULL;
+
+     pDict = NXDIAssert(dict);
+     
+     /* get Target Definition String  */
+     iRet = NXDget(pDict,pTarget,pTargetDef,1023);
+     if(iRet != NX_OK)
+     {
+        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);
+        NXIReportError(NXpData,pTargetDef);
+        return NX_ERROR;
+     }       
+
+     /* get Victim definition string */
+     iRet = NXDget(pDict,pVictim,pVictimDef,1023);
+     if(iRet != NX_OK)
+     {
+        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);
+        NXIReportError(NXpData,pTargetDef);
+        return NX_ERROR;
+     }
+
+     /* do replacements */
+     pRep1 = NXDItextreplace(dict,pTargetDef);
+     pRep2 = NXDItextreplace(dict,pVictimDef);
+     if( (!pRep1) || (!pRep2) )
+     {
+        if(pRep1)
+           DeleteDynString(pRep1);
+        if(pRep2)
+           DeleteDynString(pRep2);
+        return NX_ERROR;
+     }
+
+     /* call NXdeflin */
+     iRet = NXDdeflink(hFil,pDict,GetCharArray(pRep1),GetCharArray(pRep2));
+     DeleteDynString(pRep1);
+     DeleteDynString(pRep2);
+     return iRet;
+  }
+
+@}
+
+\subsection{Utility functions}
+\subsubsection{NXUwriteglobals}
+ at d global @{
+/*-------------------------------------------------------------------------*/
+  static void SNXFormatTime(char *pBuffer, int iBufLen)
+  {
+     time_t iDate;
+     struct tm *psTime;
+
+     /* make time string */
+     iDate = time(NULL);
+     psTime = localtime(&iDate);
+     memset(pBuffer,0,iBufLen);         
+     strftime(pBuffer,iBufLen,"%Y-%d-%m %H:%M:%S",psTime);
+  }  
+/*--------------------------------------------------------------------------*/
+   NXstatus NXUwriteglobals(NXhandle pFile, 
+                            char *filename,
+                            char *owner,
+                            char *adress,
+                            char *phone,
+                            char *email,
+                            char *fax,
+                            char *instrument)
+   {
+     char pBueffel[512];
+     int iStat;
+     
+     /* store global attributes */
+     iStat = NXputattr(pFile,"file_name",filename, 
+                       strlen(filename)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+       return NX_ERROR;
+     }
+     
+     /* write creation time */
+     SNXFormatTime(pBueffel,512);
+     iStat = NXputattr(pFile,"file_time",pBueffel,
+                       strlen(pBueffel)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+       return NX_ERROR;
+     }
+
+     /* instrument name */
+     iStat = NXputattr(pFile,"instrument",instrument,
+                       strlen(instrument)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+
+     /* owner */
+     iStat = NXputattr(pFile,"owner",owner,
+                       strlen(owner)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+
+     /* Adress */
+     iStat = NXputattr(pFile,"owner_adress",adress,
+                       strlen(adress)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+        return iStat;
+     }
+
+     /* phone */
+     iStat = NXputattr(pFile,"owner_telephone_number",phone,
+                       strlen(phone)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+        return iStat;
+     }
+
+     /* fax */
+     iStat = NXputattr(pFile,"owner_fax_number",fax,
+                       strlen(fax)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+
+     /* email */
+     iStat = NXputattr(pFile,"owner_email",email,
+                       strlen(email)+1,DFNT_INT8);
+     if(iStat == NX_ERROR)
+     {
+       return iStat;
+     }
+     return NX_OK;
+   }
+@}
+
+\subsubsection{NXUentergroup}
+
+ at d enterg @{
+   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class)
+   {
+       void (*ErrFunc)(void *pData, char *pErr); 
+       int iRet;
+
+       /* ACTION, first install dummy error handler */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening vGroup */
+       iRet = NXopengroup(hFil, name, class);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it */
+            iRet = NXmakegroup(hFil,name,class);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXopengroup(hFil,name,class);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+       }
+       return NX_OK;
+   }
+@} 
+\subsubsection{NXUenterdata}
+ at d enterd @{
+   NXstatus NXUenterdata(NXhandle hFil, char *label, int datatype,
+                         int rank, int dim[], char *pUnits)
+   {
+       void (*ErrFunc)(void *pData, char *pErr); 
+       int iRet;
+
+       /* ACTION, first install dummy error handler */
+       ErrFunc = NXIReportError;
+       NXMSetError(NXpData, DummyError);
+ 
+       /* try opening SDS */
+       iRet = NXopendata(hFil, label);
+       NXMSetError(NXpData,ErrFunc);
+       if(iRet == NX_OK)
+       {
+         return NX_OK;
+       } 
+       else
+       {
+          /* we need to create it */
+            iRet = NXmakedata(hFil,label, datatype, rank,dim);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXopendata(hFil,label);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+            iRet = NXputattr(hFil, "Units",pUnits,
+                             strlen(pUnits) + 1,DFNT_INT8);
+            if(iRet != NX_OK)
+            { 
+                 /* a comment on this one has already been written! */
+                 return iRet;
+            }
+       }
+       return NX_OK;
+   }
+@}
+
+\subsubsection{NXUallocSDS}
+ at d allocs @{
+   NXstatus NXUallocSDS(NXhandle hFil, void **pData)
+   {
+      int iDIM[MAX_VAR_DIMS];
+      int iRank,iType;
+      int iRet, i;
+      long lLength;
+
+      /* get info */
+      iRet = NXgetinfo(hFil,&iRank, iDIM, &iType);
+      if(iRet != NX_OK)
+      {
+        return iRet;
+      }      
+
+      /* calculate Size */
+      lLength = iDIM[0];
+      for(i = 1; i < iRank; i++)
+      {
+        lLength *= iDIM[i];
+      }
+      switch(iType)
+      {
+        case DFNT_FLOAT32:
+             lLength *= sizeof(float32);
+             break;
+        case DFNT_FLOAT64:
+             lLength *= sizeof(float64);
+             break;
+        case DFNT_INT8:
+             lLength *= sizeof(int8);
+             break;
+        case DFNT_UINT8:
+             lLength *= sizeof(uint8);
+             break;
+        case DFNT_INT16:
+             lLength *= sizeof(int16);
+             break;
+        case DFNT_UINT16:
+             lLength *= sizeof(uint16);
+             break;
+        case DFNT_INT32:
+             lLength *= sizeof(int32);
+             break;
+        case DFNT_UINT32:
+             lLength *= sizeof(uint32);
+             break;
+        default:
+             NXIReportError(NXpData,"ERROR: Internal: number type not recoginized");
+             return NX_ERROR;
+      }
+
+      /* time to malloc */
+      *pData = NULL;
+      *pData = malloc(lLength);
+      if(*pData == NULL)
+      {
+        NXIReportError(NXpData,"ERROR: memory exhausted in NXUallocSDS");
+        return NX_ERROR;
+      }
+      return NX_OK;
+   }
+@}
+
+ at d free @{
+   NXstatus NXUfreeSDS(void **pData)
+   {
+      free(*pData);
+      *pData = NULL;
+      return NX_OK;
+   }
+@}
+
+\section{Files}
+ at o nxdict.h -d @{
+/*---------------------------------------------------------------------------
+                            NXDICT API header file
+
+   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland
+
+   No warranties of any kind taken.
+----------------------------------------------------------------------------*/
+#ifndef NXDICTAPI
+#define NXDICTAPI
+#include "napi.h" /* make sure, napi is included */
+
+/*-------------------- NXDict data types & defines ----------------------*/
+@<tata@>
+#define NXquiet 0
+#define NXalot  1
+/*-------------------- Dictionary Maintainance ----------------------------*/
+@<dicman@>
+/*----------------- Dictionary added data transfer -----------------------*/ 
+@<dicdata@>
+/*-------------------- Utility Functions --------------------------------*/
+@<dicutil@>
+#endif
+@} 
+
+ at o nxdict.c -d @{
+/*---------------------------------------------------------------------------
+                 Nexus Dictionary API implementation file.
+
+  For documentation see the nxdict.tex file which comes with this 
+  distribution.
+
+  copyleft: Mark Koennecke
+            Labor fuer Neutronenstreuung
+            Paul Scherrer Institut
+            CH-5232 Villigen-PSI
+            Switzerland
+            Mark.Koennecke@@psi.ch
+
+  No warranties of any kind, whether explicit or implied, taken.
+  Distributed under the GNU copyleft license as documented elsewhere.
+
+  August, 1997
+
+  Version: 1.0
+-----------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <mfhdf.h>
+#include "lld.h"
+#include "napi.h"
+#include "stringdict.h"
+#include "dynstring.h"
+#include "nxdict.h"
+/*------------------ The magic number used for pointer checking */
+#define NXDMAGIC 260558
+/*--------------------------------------------------------------------------
+      Things defined in napi.c for error reporting 
+---------------------------------------------------------------------------*/
+       extern void *NXpData;
+       extern void (*NXIReportError)(void *pData, char *pBuffer);  
+/*--------------------------------------------------------------------------*/
+#define DEFDEBUG 1
+/* define DEFDEBUG when you wish to print your definition strings before
+   action. This can help a lot to resolve mysteries when working with
+   dictionaries.
+*/
+/*-------------------------------------------------------------------------*/
+@<dicdat@>
+/*-------------------------------------------------------------------------*/
+  static char *NXDIReadFile(FILE *fd)
+  {
+     char *pNew = NULL;
+     long lLength = 0;
+ 
+     assert(fd); 
+
+     /* determine length of file */
+     fseek(fd,0L,SEEK_END);
+     lLength = ftell(fd);
+     if(lLength <= 0)
+     {
+        return NULL;
+     }
+     fseek(fd,0L,SEEK_SET);
+
+     /* allocate buffer */
+     lLength += 3;
+     pNew = (char *)malloc(lLength*sizeof(char));
+     if(!pNew)
+     {
+       return NULL;
+     }
+     memset(pNew,0,lLength); /* this ensures a 0 at the end */
+
+     /* read file */
+     fread(pNew,sizeof(char),lLength-3,fd);
+     
+     /* check for existence of the NXDICT string in the file */
+     if(strncmp(pNew,"##NXDICT-1.0",12) != 0 )
+     {
+        NXIReportError(NXpData,"ERROR: This is NO NXdict file");
+        free(pNew);
+        return NULL;
+     }
+     return pNew;
+  }
+/*--------------------------------------------------------------------------*/
+@<ftoken@>
+/*------------------------------------------------------------------------*/
+@<fparse@>
+/*--------------------------------------------------------------------------*/
+  NXstatus NXDinitfromfile(char *filename, NXdict *pData)
+  {
+     NXdict pNew = NULL;
+     FILE *fd = NULL;
+     char *pBuffer = NULL;
+     char pError[512];
+
+@<iniini@>
+@<inicheck@>
+@<inifil@> 
+@<iniparse@>
+
+       if(iVerbosity == NXalot)
+       {
+          NXIReportError(NXpData, "NXDinitfrom: performed successfully");
+       }
+       free(pBuffer);
+       *pData = pNew;
+       return NX_OK;
+  }   
+/*--------------------------------------------------------------------------*/
+@<dassert@>
+/*-------------------------------------------------------------------------*/
+@<dclose@>
+/*------------------------------------------------------------------------*/
+@<dmaintain@>
+/*-----------------------------------------------------------------------*/
+@<textrep@>
+/*------------------- The Defintion String Parser -----------------------*/
+/*------- Data structures */
+@<tokdat@>
+@<padef@>
+@<dummyerr@>
+@<attitem@> 
+/*------------------------------------------------------------------------*/
+@<deftok@>
+/*------------------------------------------------------------------------*/
+@<defpath@>
+/*------------------------------------------------------------------------*/
+@<parseatt@>
+/*------------------------------------------------------------------------*/
+@<parsedim@>
+/*------------------------------------------------------------------------*/
+@<parsetype@>
+/*-------------------------------------------------------------------------*/
+@<nxpasds@>
+/*------------------------------------------------------------------------*/
+@<parselink@>
+/*------------------------------------------------------------------------*/
+@<defpar@>
+/*----------------------------------------------------------------------*/
+@<unwind@>
+/*-------------------- The Data Transfer Functions ----------------------*/
+@<nxddefopen@>
+/*------------------------------------------------------------------------*/
+@<nxdaliasopen@>
+/*------------------------------------------------------------------------*/
+@<nxput@>
+/*------------------------------------------------------------------------*/
+@<nxdputalias@>
+/*------------------------------------------------------------------------*/
+@<nxget@>
+/*------------------------------------------------------------------------*/
+@<nxdgetalias@>
+/*------------------------------------------------------------------------*/
+@<nxlink@>
+/*-----------------------------------------------------------------------*/
+@<global@>
+/*-----------------------------------------------------------------------*/
+@<enterg@>
+/*-----------------------------------------------------------------------*/
+@<enterd@>
+/*-----------------------------------------------------------------------*/
+@<allocs@>
+/*----------------------------------------------------------------------*/
+@<free@>
+@}
+
+ at o dict.c @{
+/*--------------------------------------------------------------------------
+                               D I C T 
+
+ This file exercises some of the NXDICT functionality for test purposes.
+ It can also serve as an example for the usage of the API.
+
+ Mark Koennecke, August 1997
+  
+ Upgraded to support file idetification and text replacement
+
+ Mark Koennecke, April 1998
+----------------------------------------------------------------------------*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <mfhdf.h>
+#include "dynstring.h"
+#include "napi.h"
+#include "nxdict.h"
+
+   int main(int argc, char *argv[])
+   {
+      NXdict pDict = NULL;
+      NXhandle hfil;
+      void *pData = NULL;
+      float fTina[3] = { 0.123, 0.234, 0.456};
+      float fTest[3], fDelta;
+      float fTust[20*20];
+      char pBuffer[132];
+      int i;
+
+      /* test nxdict */
+      NXDinitfromfile("test.dict",&pDict);
+      NXopen("test.hdf",NXACC_CREATE,&hfil);
+      NXDadd(pDict,"Gundula",
+            "/entry1,NXentry/SphereOmeter,NXinstrument/SDS");
+      NXDupdate(pDict,"Bea","/entry1,NXentry/SDS");
+      NXDget(pDict,"Bea",pBuffer,131);
+      printf("Bea = %s\n",pBuffer);
+      NXDget(pDict,"Linda",pBuffer,131);
+      NXDopendef(hfil,pDict,pBuffer);
+      NXDputalias(hfil,pDict,"Tina",fTina);
+      NXDputalias(hfil,pDict,"Gina",fTina);
+      NXDgetalias(hfil,pDict,"Tina",fTest);
+      NXDgetalias(hfil,pDict,"Gina",fTest);
+      NXDputalias(hfil,pDict,"Linda",fTust);
+      NXDaliaslink(hfil,pDict,"Eva","Linda");
+      NXDclose(pDict,"close.dict");
+      NXclose(&hfil);
+      printf("NXDICT seemed to have worked \n");
+
+      /* test Utility functions */
+      printf(" Proceeding to test of utility functions \n");
+      NXopen("test2.hdf",NXACC_CREATE,&hfil);
+      NXUwriteglobals(hfil,
+                      "test2.hdf",
+                      "Willibald Wuergehals",
+                      "Rue des Martyrs, 26505 Timbuktu, Legoland ",
+                      "+41-56-3102512",
+                      "Nobody@@nowhere.edu",
+                      " 755-898767",
+                      "Dingsbums");
+      NXUentergroup(hfil, "TestGroup", "NXtest");
+      NXclosegroup(hfil);
+      NXUentergroup(hfil, "TestGroup", "NXtest");
+
+      i = 120;
+      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
+      NXclosedata(hfil);
+      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
+
+      NXUallocSDS(hfil,&pData);
+      NXUfreeSDS(&pData);
+      NXclose(&hfil);
+      printf("All tests seem to have worked OK,  %s %s\n",
+             "but the test is pathetic\n", 
+             "Do not rely, in any circumstances, on this test alone");
+
+ 
+   }
+@}
+ at o test.dict @{
+##NXDICT-1.0
+#----------------------------------------------------------------------------
+# A dictionary file for test purposes
+# Mark Koennecke, August 1997
+#----------------------------------------------------------------------------
+
+Linda = /entry1,NXentry/Wuerfelometer,NXinstrument/SDS Counts \
+ -type DFNT_INT32 -rank 2 -dim {20,20} -attr {Units,Wuerfel} \
+ -attr {axis,1}
+Eva   = \
+ /entry1,NXentry/NXVGROUP
+Chloe = /entry1,NXentry/NXLINK Linda
+Bea =
+Tina = /entry1,NXentry/InvertedTOPSI,NXinstrument/SDS Tina \
+       -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit}   
+Reptil = Alligator,NXanimal/
+Gina = /entry1,NXentry/$(Reptil)SDS Tina \
+       -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit}   
+
+@}
+
+\end{document}
diff --git a/src/nxdict/nxdictus.tex b/src/nxdict/nxdictus.tex
new file mode 100644
index 0000000..158e43b
--- /dev/null
+++ b/src/nxdict/nxdictus.tex
@@ -0,0 +1,378 @@
+%
+%
+%  This software is distributed in the hope that it will be useful,
+%  but WITHOUT ANY WARRANTY; without even the implied warranty of
+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%  GNU General Public License for more details.
+%
+%  You may already have a copy of the GNU General Public License; if
+%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+%  Cambridge, MA 02139, USA.
+%
+
+\documentclass[12pt]{article}
+
+\setlength{\oddsidemargin}{-.1in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.2in}
+\setlength{\marginparwidth}{0.5in}
+
+\begin{document}
+\title{The NEXUS Dictionary API}
+
+\author{Mark K\"onnecke\\
+  Labor f\"ur Neutronenstreuung\\
+  Paul Scherrer Institut\\
+  CH-5232 Villigen PSI\\
+  Switzerland\\       
+  Mark.Koennecke at psi.ch \\
+}
+
+
+
+\maketitle
+
+\vskip.3in
+\centerline{\large\bf Abstract}
+\vskip.2in
+\begin{center}
+\parbox{.8\textwidth}{
+  There is a proposed portable data exchange format for neutron and
+  X-ray scattering communities, NEXUS (described in a separate
+  publication).   Another document describes an application programmers
+ interface to NEXUS. This is a base level API which hides many of the
+ hideous details of the HDF interface from the NeXus programmer. The
+ present document   introduces a higher level application programmers
+ interface sitting on top of the NeXus API. This API (the NEXDICT-API),
+ reads all file structure interface from a dictionary data file and creates
+ the structure automatically from that information. The NEXDICT user only
+ needs to specify the data to write.
+}
+\end{center}
+
+\clearpage
+
+\section{Introduction}
+ There exists a prosal for a portable data exchange format for neutron and
+ X--ray scattering communities, NeXus. NeXus is fully described
+ elsewhere$^{1}$. NeXus sits on top of the hierachical data format (HDF) as
+ defined and specified by the National Center for Supercompter Applications, 
+ NCSA, USA. HDF comes with a library of access functions. On top of the
+ HDF-library an application programmers interface (API) for NeXus was
+ defined which hides many of the low level details and ideosyncracies of
+ the HDF interface form the NeXus programmer. However, writing NeXus files stays
+ hideous even with this interface due to the amount of repetetive code
+ required to  implement the NeXus structure. Now, repetetive tasks is one
+ area a computer is good at. So, why not have the computer take care of all
+ the structure associated with the NeXus format? In order to do this two
+ components are needed:
+\begin{itemize}
+\item A language which describes the NeXus file structure to the computer.
+  This language will be called the NeXus Data Definition Language (NXDDL).
+  NXDLL might also be used as a tool for discussing and defining NeXus
+  datastructures.
+\item A application programmers interface which works with the NeXus Data 
+ Definition Language.
+\end{itemize}
+Both of the above will be detailed in this document.
+
+\section{The NeXus Data Definition Language}
+The NeXus Data Definition Language(NXDDL) has the purpose to define the structure
+and data items in a NeXus file in a form which can be understood by a human
+programmer and which can be parsed by the computer in order to create the 
+structure. 
+For this a dictionary based aproach will be used. This dictionary
+will contain pairs of short aliases for data items and definition strings 
+which hold the structure information. This dictionary will
+be initialised from a data file, the NXDDL-file. Such a dictionary can be
+used in the following way: Given an apropriate API function, a NXDICT
+programmer  needs to specify only the alias and the data to write and 
+everything else is taken care of by the API: vGroup creation, opening,
+SDS definition etc. Another use may involve the creation of definition string
+completely or partly at run time which can then be used by an API function
+in order to create the structures defined by the definition string. The same
+holds for writing as well.
+
+
+A NXDDL dictionary is preferably initialised from a file.
+Such a NXDDL file has to follow these general structure guidelines:
+\begin{itemize}
+\item All input is in US--ASCII.
+\item A \verb+#+ in the first column denotes a comment and will be ignored.
+\item A \verb+\+ at the end of the line means that the current text will be 
+ continued with the next non-blanck character for the next line.
+\item All other entries follow the form: alias = definition string.
+ This defines \verb+alias+ as a short form for the definition string  after the
+ equality sign.
+\end{itemize}         
+It might be considered to add a special global vGroup of class NXdict to the
+NexUs API which holds the dictionary information within a NeXus file.
+
+ The next thing to define is the content of the definition string. A
+ definition string will have the general form: \\
+\centerline{\bf PATH/TerminalSymbol}
+ This means a definition string will consist of a path specifier which
+ describes the position of a data item in the vGroup hierarchy and a
+ terminal symbol which describes the nature of the data item. 
+
+ The path through the vGroup hierarchy to a data item will be described in a
+ manner analog to a Unix directory hierarchy. However, NeXus requires two
+ pieces of data in order to fully qualify a vGroup. This is it's name and
+ class. Consequently, both name and classname will be given for each vGroup,
+ separated by a komma. A valid path string then looks like: \\
+\begin{verbatim} 
+     /scan1,NXentry/DMC,NXinstrument/big_detector,NXdetector/TerminalSymbol
+\end{verbatim}
+ This translates into: TerminalSymbol in vGroup big\_detector, class
+ NXdetector, which resides in vGroup DMC of class NXinstrument, which in
+ turn is situated in the vGroup scan1 of class NXentry.
+
+ The terminal symbol in a definition string is used to define the data item
+ at the end of the definition. NeXus currently supports only three types of
+ data items at the end of the chain: these are scientific data sets (SDS),
+ vGroups and links to other data items or vGroups. The terminal symbol for a link
+ is specified by the keyword \verb+NXLINK+  
+ followed
+ by a valid alias of another data item or vGroup. For example the terminal 
+ symbol: \\
+ \centerline{\bf SDS counts}
+ would define a SDS with name counts.
+
+ A vGroup would be denoted by the keyword VGROUP. By then, the vGroup has
+ already been defined by the path string. This form of alias is only useful
+ for the definition of links to vGroups.
+
+ A SDS is more involved. The definition of an SDS starts with the keyword
+ \verb+SDS+. This keyword must then be followed by the name of the SDS.
+ Following the name there are option value pairs which define the 
+  details of the SDS. The following option exist:
+ \begin{itemize}
+  \item {\bf -rank} defines the rank of the SDS.
+  \item {\bf -dim \{dim0,dim1,dim2,...., dimn\} } defines the dimensions of the
+       SDS. Exactly the number of rank numbers defining the dimensions
+ length is required inside the curly braces. 
+  \item {\bf -type} defines the datatype of the SDS as a string corresponding
+  to the HDF data types.
+  \item {\bf -attr \{name,value\} } defines an attribute. In the curly braces
+   there must be the name and value of the attribute separated by a komma.
+  \end{itemize}
+  If no options are given a default is used. This will be a single floating
+  point number, as this is the most frequently written data item. As an 
+  example see the definition of a 3d array of 32 bit integers:
+  \begin{verbatim}
+   PATHSTRING/SDS counts -rank 3 -dim {64,64,712} -type DFNT_INT32 \
+                  -attr {Units,Counts}      
+
+  \end{verbatim}
+
+  \section{The NXDICT--API}
+  In order to interface with the NeXus dictionary API a set of
+  API--functions is needed. All functions and data types belonging to
+  this API start with the letters: NXD. The functions belonging to this API
+  fall into three groups:
+  \begin{itemize}
+   \item Dictionary maintainance functions.
+   \item Data writing and reading functions.
+   \item Utility functions.
+  \end{itemize}
+  
+  One additional data type is needed for this API:
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap1}
+$\langle$tata {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   typedef struct __NXdict *NXdict;@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+NXdict will be used as a handle for the dictionary currently in use.
+
+\subsubsection{Dictionary Maintainance Function}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap2}
+$\langle$dicman {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDinitfromfile(char *filename, NXdict *pDict);@\\
+\mbox{}\verb@   NXstatus NXDclose(NXdict handle, char *filename);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDadd(NXdict handle, char *alias, char *DefString);@\\
+\mbox{}\verb@   NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int iBufLen);@\\
+\mbox{}\verb@   NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal);@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+{\bf NXDinitfromfile} creates a new NeXus dictionary. If filename is NULL, this
+  is all that happens. If filename is not NULL, it will be opened and the
+  dictionary will be initialised from the file specified.  The return value
+  is either 0 for failure or non zero for success. 
+
+  {\bf NXDclose} deletes and writes a NeXus dictionary. If filename is not NULL,
+  the dictionary specified by handle is written to the file specified by
+  filename. In any case the dictionary specified by handle will be deleted.
+
+  {\bf NXDadd} adds a new alias -- Definition String pair to the dictionary
+  specified by handle.
+
+  {\bf NXDget} retrieves the definition string for the alias specified as
+  the second parameter from the dictionary handle. The definition string
+  is copied to pBuffer. Maximum iBufLen characters will be copied.
+
+  {\bf NXDupdate} replaces the definition for the alias specified as second
+ parameter with the new value supplied as last parameter.
+  
+  If a special dictionary vGroup as extemsion to NeXus would be accepted,
+  two more functions need to be defined which read and write the dictionary 
+  from the NeXus file.
+
+\subsubsection{Data Handling functions}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap3}
+$\langle$dicdata {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDputalias(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, void *pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDgetalias(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                        char *alias, void *pData);@\\
+\mbox{}\verb@   NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDaliaslink(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                         char *pAlias1, char *pAlias2);@\\
+\mbox{}\verb@   NXstatus NXDdeflink(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                         char *pDef1, char *pDef2);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXDopenalias(NXhandle file, NXdict dict, @\\
+\mbox{}\verb@                        char *alias);@\\
+\mbox{}\verb@   NXstatus NXDopendef(NXhandle file, NXdict dict, char *pDefString);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The NXDICT data handling functions go in pairs. The version ending in
+ alias expects an NXdict and an alias as input. These routines work
+ out the pass from that. The other version ending on def acts upon 
+ a definition string specified as second parameter. Using this scheme
+ both full dictionary operation is possible, as well as operation with
+ program generated definition strings. All routines return the
+ usual NeXus status returns. All these routines start at the current vGroup
+ level and return back to it.  
+
+ NXDputalias, NXDputdef write the data element specified by the alias or
+ the definition string to the NeXus file specified as first parameter. 
+ pData is a pointer to the data to be written. These routines will check for
+ the existence of all vGroups required in the path part of the definition
+ string. If a vGroup  is missing it will be created. These routines step
+ back to the same vGroup level from which they were called.
+
+ NXDgetalias, NXDgetdef read a data item from file. pData MUST point to a
+ data area large enough to hold the data read. If a vGroup is missing in
+ the path for one of these routines an error is generated because it is 
+ assumed that the data is present if a program wants to read it. These 
+ routines step
+ back to the same vGroup level from which they were called.
+ 
+ NXDaliaslink, NXDdeflink links the alias or definition given as fourth
+ parameter to the vGroup specified by the  third parameter. pAlias1 or
+ pDef1 MUST refer to a vGroup (we cannot link to a SDS, can't we?). The
+ item being linked against MUST exist, otherwise the software will complain.
+ The vGroup into which the link is installed will be created on the fly,
+ if not present.
+ Please note, that bot aliases or definition strings specified need to
+ start from the same vGroup position.  These routines step
+ back to the same vGroup level from which they were called. 
+
+ NXDopenalias, NXDopendef open the specified data items specified by the
+ alias or the definition string. Then the usual NeXus functions can be 
+ used to interact with the data. These routines use the same scheme for
+ creating vGroups on the fly as the put routines above. The status in the
+ vGroup hierarchy after this call is dependent on the nature of the terminal
+ symbol. If it is a SDS, the vGroup hierarchy will be stepped back to the
+ level from which the call ocurred. The SDS will be left open. If the
+ terminal symbol is a vGroup, then the this vGroup will be made the current
+ vGroup. No back stepping occurs. 
+
+
+  
+  \subsection{NeXus Utility Functions}
+  This section list a couple of functions which either perform common 
+   tasks on NeXus files or relate
+  to aspects of error handling and debugging.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap4}
+$\langle$dicutil {\footnotesize ?}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUwriteglobals(NXhandle file, @\\
+\mbox{}\verb@                            char *filename,@\\
+\mbox{}\verb@                            char *owner,@\\
+\mbox{}\verb@                            char *adress,@\\
+\mbox{}\verb@                            char *phone,@\\
+\mbox{}\verb@                            char *email,@\\
+\mbox{}\verb@                            char *thing);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class);@\\
+\mbox{}\verb@   NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, @\\
+\mbox{}\verb@                          int rank, int dim[], char *pUnits);@\\
+\mbox{}\verb@   @\\
+\mbox{}\verb@   NXstatus NXUallocSDS(NXhandle hFil, void **pData);@\\
+\mbox{}\verb@   NXstatus NXUfreeSDS(void **pData);@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@@$\diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap ?.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+{\bf NXUwriteglobals} writes the global attributes to a newly opened 
+ NeXus file. The parameters should be self explaining. In addition 
+ the file creation date is automatically written.
+
+
+ {\bf NXUentergroup} tries to open the group specified by name and class.
+ If it not present, it will be created and opened.
+
+ {\bf NXUenterdata} tries to open the SDS specified by label.
+ If it not present, it will be created and opened.
+
+  {\bf NXUallocSDS} allocates enough space for the currently open SDS. The
+  pointer created is returned in pData. 
+
+  {\bf NXUfreeSDS} returns memory allocated by NXUallocSDS to the system.
+
+
+\end{document}
diff --git a/src/nxdict/stringdict.c b/src/nxdict/stringdict.c
new file mode 100644
index 0000000..bc85fe5
--- /dev/null
+++ b/src/nxdict/stringdict.c
@@ -0,0 +1,272 @@
+/*-------------------------------------------------------------------------
+
+			S T R I N G D I C T
+			
+	Implementation file for a simple list based string dictionary
+	of name value pairs.
+
+       Mark Koennecke, April 1997
+	
+       Copyright:
+
+       Labor fuer Neutronenstreuung
+       Paul Scherrer Institut
+       CH-5423 Villigen-PSI
+
+
+      The authors hereby grant permission to use, copy, modify, distribute,
+      and license this software and its documentation for any purpose, provided
+      that existing copyright notices are retained in all copies and that this
+      notice is included verbatim in any distributions. No written agreement,
+      license, or royalty fee is required for any of the authorized uses.
+      Modifications to this software may be copyrighted by their authors
+      and need not follow the licensing terms described here, provided that
+      the new terms are clearly indicated on the first page of each file where
+      they apply.
+
+      IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+      FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+      ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+      DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+      POSSIBILITY OF SUCH DAMAGE.
+
+      THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+      INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+      FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+      IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+      NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+      MODIFICATIONS.
+----------------------------------------------------------------------------*/
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+/* #include "fortify.h" */
+#include "lld.h"
+#include "stringdict.h"
+
+/*-------------------------------------------------------------------------*/
+  typedef struct __StringDict {
+                                 int iList;
+                                 int iTraverse;
+                              } StringDict;
+
+  typedef struct {
+                   char *name;
+                   char *value;
+                  } SDE, *pSDE;
+/*-------------------------------------------------------------------------*/                  
+  pStringDict CreateStringDict(void)
+  {
+     pStringDict pNew = NULL;
+     
+     pNew = (pStringDict)malloc(sizeof(StringDict));
+     if(!pNew)
+     {
+       return NULL;
+     }
+     pNew->iList = LLDcreate(sizeof(SDE));
+     if(pNew->iList < 0)
+     {
+       free(pNew);
+       return NULL;
+     }
+     pNew->iTraverse = 0;
+     return pNew;
+  }
+/*------------------------------------------------------------------------*/  
+  void        DeleteStringDict(pStringDict self)
+  {
+     int iRet;
+     SDE sVal;
+     
+     assert(self);
+     iRet = LLDnodePtr2First(self->iList);
+     while(iRet != 0)
+     {
+        LLDnodeDataTo(self->iList,&sVal);
+        if(sVal.name)
+        {
+          free(sVal.name);
+        }
+        if(sVal.value)
+        {
+          free(sVal.value);
+        }
+        iRet = LLDnodePtr2Next(self->iList);
+     }
+     LLDdelete(self->iList);
+     free(self);
+  }
+/*-------------------------------------------------------------------------*/
+  int StringDictAddPair(pStringDict self, char *name, char *value)
+  {
+     SDE sVal;
+     
+     assert(self);
+     sVal.name = NULL;
+     sVal.value = NULL;
+     
+     sVal.name = strdup(name);
+     sVal.value = strdup(value);
+     
+     LLDnodeAppendFrom(self->iList,&sVal);
+     return 1;
+  }
+/*---------------------------------------------------------------------------*/  
+  int StringDictExists(pStringDict self, char *name)
+  {
+     SDE sVal;
+     int iRet;
+     
+     iRet = LLDnodePtr2First(self->iList);
+     while(iRet != 0)
+     {
+        LLDnodeDataTo(self->iList,&sVal);
+        if(strcmp(sVal.name,name) == 0)
+        {
+          return 1;
+        }
+        iRet = LLDnodePtr2Next(self->iList);
+     }
+     return 0;
+  }  
+/*--------------------------------------------------------------------------*/  
+  int StringDictUpdate(pStringDict self, char *name, char *value)
+  {
+     SDE sVal;
+     int iRet;
+     
+     iRet = LLDnodePtr2First(self->iList);
+     while(iRet != 0)
+     {
+        LLDnodeDataTo(self->iList,&sVal);
+        if(strcmp(sVal.name,name) == 0)
+        {
+          if(sVal.value)
+          {
+            free(sVal.value);
+          }
+          sVal.value = strdup(value);
+          LLDnodeDataFrom(self->iList,&sVal);
+          return 1;
+        }
+        iRet = LLDnodePtr2Next(self->iList);
+     }
+     return 0;
+  }  
+/*--------------------------------------------------------------------------*/  
+  int StringDictGet(pStringDict self, char *name, char *pResult, int iLen)
+  {
+     SDE sVal;
+     int iRet;
+     
+     iRet = LLDnodePtr2First(self->iList);
+     while(iRet != 0)
+     {
+        LLDnodeDataTo(self->iList,&sVal);
+        if(strcmp(sVal.name,name) == 0)
+        {
+          if(pResult == NULL)
+          {
+            return strlen(sVal.value);
+          }
+          else
+          {
+             strncpy(pResult,sVal.value,iLen);
+             return 1;
+          }   
+        }
+        iRet = LLDnodePtr2Next(self->iList);
+     }
+     return 0;
+  }  
+/*------------------------------------------------------------------------*/  
+  int StringDictDelete(pStringDict self, char *name)
+  {
+     SDE sVal;
+     int iRet;
+     
+     iRet = LLDnodePtr2First(self->iList);
+     while(iRet != 0)
+     {
+        LLDnodeDataTo(self->iList,&sVal);
+        if(strcmp(sVal.name,name) == 0)
+        {
+          if(sVal.name)
+          {
+            free(sVal.name);
+          }
+          if(sVal.value)
+          {
+            free(sVal.value);
+          }
+          LLDnodeDelete(self->iList);
+          return 1;
+        }
+        iRet = LLDnodePtr2Next(self->iList);
+     }
+     return 0;
+  }  
+/*------------------------------------------------------------------------*/
+ int StringDictGetAsNumber(pStringDict self, char *name, float *fVal)
+ {
+   char pBueffel[80];
+   int iRet;
+   SDE sVal;
+   
+   assert(self);
+   
+   iRet = StringDictGet(self,name,pBueffel,79);
+   if(!iRet)
+   {
+     return iRet;
+   }
+   
+   iRet = sscanf(pBueffel,"%f",fVal);
+   if(iRet != 1)
+   {
+     return 0;
+   }
+   return 1;
+ }
+/*-------------------------------------------------------------------------*/
+  const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
+  {
+     int iRet;
+     SDE sVal;
+     
+     assert(self);
+     
+     if(self->iTraverse)
+     {
+       iRet = LLDnodePtr2Next(self->iList);
+       if(iRet == 0) /* exhausted */
+       {
+         self->iTraverse = 0;
+         return NULL;
+       }
+       else
+       {
+        LLDnodeDataTo(self->iList,&sVal);
+        strncpy(pValue,sVal.value,iValLen);
+        return sVal.name;          
+       }
+     }
+     else /* start a new one */
+     {
+       iRet = LLDnodePtr2First(self->iList);
+       if(iRet == 0)
+       {
+         return NULL;
+       }
+       else
+       {
+         self->iTraverse = 1;
+         LLDnodeDataTo(self->iList,&sVal);
+         strncpy(pValue,sVal.value,iValLen);
+         return sVal.name;          
+       }
+     }
+     return NULL;
+  }
diff --git a/src/nxdict/stringdict.h b/src/nxdict/stringdict.h
new file mode 100644
index 0000000..cac8f41
--- /dev/null
+++ b/src/nxdict/stringdict.h
@@ -0,0 +1,38 @@
+
+#line 49 "stringdict.w"
+
+/*--------------------------------------------------------------------------
+                        S T R I N G D I C T
+
+ A module which implements a general purpose string dictionary.
+
+ copyright: see implementation file
+
+ Mark Koennecke, April 1997
+---------------------------------------------------------------------------*/
+#ifndef SICSSTRINGDICT
+#define SICSSTRINGDICT
+
+  typedef struct __StringDict *pStringDict;
+
+
+#line 6 "stringdict.w"
+
+  pStringDict CreateStringDict(void);
+  void        DeleteStringDict(pStringDict self);
+
+  int StringDictAddPair(pStringDict self, char *name, char *value);
+  int StringDictExists(pStringDict self, char *name);
+  int StringDictUpdate(pStringDict self, char *name, char *value);
+  int StringDictGet(pStringDict self, char *name, char *pResult, int iLen);
+  int StringDictGetAsNumber(pStringDict self, char *name, float *fVal);
+  int StringDictDelete(pStringDict self, char *name);
+
+  const char *StringDictGetNext(pStringDict self, 
+                                char *pValue, int iValLen);
+
+#line 64 "stringdict.w"
+
+
+#endif
+
diff --git a/src/nxdict/stringdict.w b/src/nxdict/stringdict.w
new file mode 100644
index 0000000..786fade
--- /dev/null
+++ b/src/nxdict/stringdict.w
@@ -0,0 +1,70 @@
+\subsubsection{Dictionary}
+This is just a simple implementation of an dictionary of name value strings
+on top of the LLD linked list package. It is needed in the histogram memory
+module. This module provides the following functions:
+
+ at d Protos @{
+  pStringDict CreateStringDict(void);
+  void        DeleteStringDict(pStringDict self);
+
+  int StringDictAddPair(pStringDict self, char *name, char *value);
+  int StringDictExists(pStringDict self, char *name);
+  int StringDictUpdate(pStringDict self, char *name, char *value);
+  int StringDictGet(pStringDict self, char *name, char *pResult, int iLen);
+  int StringDictGetAsNumber(pStringDict self, char *name, float *fVal);
+  int StringDictDelete(pStringDict self, char *name);
+
+  const char *StringDictGetNext(pStringDict self, 
+                                char *pValue, int iValLen);
+@}
+
+
+
+As usual, all function return 1 on success, 0 if there is a problem.
+
+CreateStringDict creates and initialises a new string dictionanry.
+
+DeleteStringDict deletes the whole dictionary and all ist values from
+memory. self will point to rubbish afterwards.
+
+StringDictAddPair adds a new name value pair to the dictionary.
+
+StringDictExists test for the existence of name in the Dictionary.
+
+StringDictUpdate replaces the value for name with the new one specified.
+
+StringDictGet copies the value for name into the string pResult, but maximum
+iLen characters. If pResult is NULL, this function returns the length of the
+value string.
+
+StringDictDelete deletes the entry for name from the dictionary.
+
+StringDictGetNext implements a scan through the whole dictionary. It returns
+a pointer to the current key or NULL if the dictionary is exhausted. 
+Maximum iValLen characters of value information will be copied into pValue.
+NEVER, ever delete the pointer passed from StringDictGetNext. A core dump
+will be your reward. Please note, that each call to the usual search
+functions will mess up a dictionary traversal. 
+
+
+
+ at o stringdict.h -d @{
+/*--------------------------------------------------------------------------
+			S T R I N G D I C T
+
+ A module which implements a general purpose string dictionary.
+
+ copyright: see implementation file
+
+ Mark Koennecke, April 1997
+---------------------------------------------------------------------------*/
+#ifndef SICSSTRINGDICT
+#define SICSSTRINGDICT
+
+  typedef struct __StringDict *pStringDict;
+
+@<Protos@>
+
+#endif
+
+@}
diff --git a/src/nxdict/test.dict b/src/nxdict/test.dict
new file mode 100644
index 0000000..d2330de
--- /dev/null
+++ b/src/nxdict/test.dict
@@ -0,0 +1,19 @@
+##NXDICT-1.0
+#----------------------------------------------------------------------------
+# A dictionary file for test purposes
+# Mark Koennecke, August 1997
+#----------------------------------------------------------------------------
+
+Linda = /entry1,NXentry/Wuerfelometer,NXinstrument/SDS Counts \
+ -type DFNT_INT32 -rank 2 -dim {20,20} -attr {Units,Wuerfel} \
+ -LZW -chunk {20,20} -attr {axis,1}
+Eva   = \
+ /entry1,NXentry/NXVGROUP
+Chloe = /entry1,NXentry/NXLINK Linda
+Bea =
+Tina = /entry1,NXentry/InvertedTOPSI,NXinstrument/SDS Tina \
+       -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit}   
+Reptil = Alligator,NXanimal/
+Gina = /entry1,NXentry/$(Reptil)SDS Tina \
+       -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit}   
+
diff --git a/src/nxio.c b/src/nxio.c
new file mode 100644
index 0000000..3e77ea9
--- /dev/null
+++ b/src/nxio.c
@@ -0,0 +1,749 @@
+/**
+ * This file contains functions necessary to perform XML-I/O for
+ * NeXus with the mxml-library.
+ * 
+ * Most notably it contains the callback function for reading and
+ * writing  data
+ *
+ *   Copyright (C) 2004 Mark Koennecke
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  For further information, see <http://www.nexusformat.org>
+ */
+
+#ifdef NXXML 
+
+#include <mxml.h> 
+#include <assert.h>
+#include "napi.h"
+#include "nxio.h"
+#include "nxdataset.h"
+#include "napiconfig.h"
+
+/* fix for mxml-2.3 */
+#ifndef MXML_WRAP
+#define MXML_WRAP 79
+#endif
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif /* _MSC_VER */
+
+/* #define TESTMAIN 1 */
+/*=================== type code handling ================================= */
+typedef struct {
+  char name[30];
+  char format[30];
+  int  nx_type;
+}type_code;
+
+#define NTYPECODE 11
+static type_code typecode[NTYPECODE];
+/*-----------------------------------------------------------------------*/
+void initializeNumberFormats(){
+  type_code myCode;
+
+  strcpy(myCode.name,"NX_FLOAT32");
+  strcpy(myCode.format,"%12.4f");
+  myCode.nx_type = NX_FLOAT32;
+  typecode[0] = myCode;
+
+  strcpy(myCode.name,"NX_FLOAT64");
+  strcpy(myCode.format,"%16.5f");
+  myCode.nx_type = NX_FLOAT64;
+  typecode[1] = myCode;
+
+  strcpy(myCode.name,"NX_INT8");
+  strcpy(myCode.format,"%5d");
+  myCode.nx_type = NX_INT8;
+  typecode[2] = myCode;
+
+  strcpy(myCode.name,"NX_UINT8");
+  strcpy(myCode.format,"%5d");
+  myCode.nx_type = NX_UINT8;
+  typecode[3] = myCode;
+
+  strcpy(myCode.name,"NX_INT16");
+  strcpy(myCode.format,"%8d");
+  myCode.nx_type = NX_INT16;
+  typecode[4] = myCode;
+
+  strcpy(myCode.name,"NX_UINT16");
+  strcpy(myCode.format,"%8d");
+  myCode.nx_type = NX_UINT16;
+  typecode[5] = myCode;
+
+  strcpy(myCode.name,"NX_INT32");
+  strcpy(myCode.format,"%12d");
+  myCode.nx_type = NX_INT32;
+  typecode[6] = myCode;
+
+  strcpy(myCode.name,"NX_UINT32");
+  strcpy(myCode.format,"%12d");
+  myCode.nx_type = NX_UINT32;
+  typecode[7] = myCode;
+
+  strcpy(myCode.name,"NX_INT64");
+  strcpy(myCode.format,"%24lld");
+  myCode.nx_type = NX_INT64;
+  typecode[8] = myCode;
+
+  strcpy(myCode.name,"NX_UINT64");
+  strcpy(myCode.format,"%24llu");
+  myCode.nx_type = NX_UINT64;
+  typecode[9] = myCode;
+
+  strcpy(myCode.name,"NX_CHAR");
+  strcpy(myCode.format,"%c");
+  myCode.nx_type = NX_CHAR;
+  typecode[10] = myCode;
+}
+/*----------------------------------------------------------------------*/
+void setNumberFormat(int nx_type, char *format){
+  int i;
+
+  for(i = 0; i < NTYPECODE; i++){
+    if(typecode[i].nx_type == nx_type){
+      strncpy(typecode[i].format,format,29);
+    }
+  }
+}
+/*------------------------------------------------------------------*/
+static void getNumberFormat(int nx_type, char format[30]){
+  int i;
+
+  for(i = 0; i < NTYPECODE; i++){
+    if(typecode[i].nx_type == nx_type){
+      strncpy(format,typecode[i].format,29);
+    }
+  }
+}
+/*----------------------------------------------------------------*/
+void getNumberText(int nx_type, char *typestring, int typeLen){
+  int i;
+
+  for(i = 0; i < NTYPECODE; i++){
+    if(typecode[i].nx_type == nx_type){
+      strncpy(typestring,typecode[i].name,typeLen);
+    }
+  }
+}
+/*
+ * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
+ * copied here from mxml-file.c to achieve compatibility with mxml-2.1
+ * standard
+ */
+
+static int				/* O  - 0 on success, -1 on error */
+myxml_add_char(int  ch,			/* I  - Character to add */
+              char **bufptr,		/* IO - Current position in buffer */
+	      char **buffer,		/* IO - Current buffer */
+	      size_t  *bufsize)		/* IO - Current buffer size */
+{
+  char	*newbuffer;			/* New buffer value */
+
+
+  if (*bufptr >= (*buffer + *bufsize - 4))
+  {
+   /*
+    * Increase the size of the buffer...
+    */
+
+    if (*bufsize < 1024)
+    {
+      (*bufsize) *= 2;
+    }
+    else
+    {
+      (*bufsize) *= 3;
+      (*bufsize) /= 2;
+    }
+
+    newbuffer = (char *)malloc(*bufsize*sizeof(char));
+    if(!newbuffer){
+      free(*buffer);
+
+      mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
+
+      return (-1);
+    }
+    memset(newbuffer,0,*bufsize*sizeof(char));
+    memcpy(newbuffer,*buffer,*bufptr - *buffer);
+    free(*buffer);
+
+    *bufptr = newbuffer + (*bufptr - *buffer);
+    *buffer = newbuffer;
+  }
+
+  if (ch < 128)
+  {
+   /*
+    * Single byte ASCII...
+    */
+
+    *(*bufptr)++ = ch;
+  }
+  else if (ch < 2048)
+  {
+   /*
+    * Two-byte UTF-8...
+    */
+
+    *(*bufptr)++ = 0xc0 | (ch >> 6);
+    *(*bufptr)++ = 0x80 | (ch & 0x3f);
+  }
+  else if (ch < 65536)
+  {
+   /*
+    * Three-byte UTF-8...
+    */
+
+    *(*bufptr)++ = 0xe0 | (ch >> 12);
+    *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
+    *(*bufptr)++ = 0x80 | (ch & 0x3f);
+  }
+  else
+  {
+   /*
+    * Four-byte UTF-8...
+    */
+
+    *(*bufptr)++ = 0xf0 | (ch >> 18);
+    *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
+    *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
+    *(*bufptr)++ = 0x80 | (ch & 0x3f);
+  }
+
+  return (0);
+}
+/*------------------------------------------------------------------*/
+extern char *stptok(char *s, char *tok, size_t toklen, char *brk);
+/*=====================================================================
+ actual stuff for implementing the callback functions
+ =====================================================================*/
+
+/*
+ * if passed NX_CHAR, then returns dimension of -1 and the caller
+ * needs to do a strlen() or equivalent 
+ */
+void analyzeDim(const char *typeString, int *rank, 
+			    int64_t *iDim, int *type){
+  char dimString[132];
+  char dim[20];
+  const char *dimStart, *dimEnd;
+  char* dimTemp;
+  int myRank;
+
+  if(strchr(typeString,(int)'[') == NULL){
+    *rank = 1;
+    switch(*type){
+    case NX_INT8:
+    case NX_UINT8:
+    case NX_INT16:
+    case NX_UINT16:
+    case NX_INT32:
+    case NX_UINT32:
+    case NX_INT64:
+    case NX_UINT64:
+    case NX_FLOAT32:
+    case NX_FLOAT64:
+      iDim[0] = 1;
+      break;
+    case NX_CHAR:
+      iDim[0] = -1;	/* length unknown, caller needs to determine later */
+      break;
+    default:
+      mxml_error("ERROR: (analyzeDim) unknown type code %d for typeString %s", *type, typeString);
+      break;
+    }
+  } else {
+    /*
+      we have to determine rank and the dims.
+      Start by extracting the dimension string.
+    */
+    dimStart = strchr(typeString,(int)'[') + 1;
+    dimEnd =  strchr(typeString,(int)']');
+    if(!dimStart || !dimEnd) {
+      mxml_error("ERROR: malformed dimension string in %s",typeString);
+      return;
+    }
+    if((dimEnd - dimStart) > 131){
+      mxml_error("ERROR: run away dimension definition in %s",typeString);
+      return;
+    }
+    memset(dimString,0,132);
+    memcpy(dimString,dimStart,(dimEnd-dimStart)*sizeof(char));
+    dimTemp = stptok(dimString,dim,19,",");
+    myRank = 0;
+    while(dimTemp != NULL){
+      iDim[myRank] = atoi(dim);
+      dimTemp = stptok(dimTemp,dim,19,",");
+      myRank++;
+    }
+    *rank = myRank;
+  }
+}
+/*--------------------------------------------------------------------*/
+int translateTypeCode(const char *code, const char* term){
+  int i, result = -1;
+  char test_str[80];
+  
+  for(i = 0; i < NTYPECODE; i++){
+    snprintf(test_str, sizeof(test_str)-1, "%s%s", typecode[i].name, term);
+    if(strncmp(code, test_str, strlen(test_str)) == 0){
+      result = typecode[i].nx_type;
+      break;
+    }
+  }
+  return result;
+}
+
+/* 
+ * This is used to locate an Idims node from the new style table data layout
+ */
+static mxml_node_t* findDimsNode(mxml_node_t *node)
+{
+    mxml_node_t *tnode = NULL;
+    const char* name = node->value.element.name;
+    if ( (node->parent != NULL) && !strcmp(node->parent->value.element.name, DATA_NODE_NAME) )
+    {
+	tnode = mxmlFindElement(node->parent->parent, node->parent->parent, DIMS_NODE_NAME, NULL, NULL, MXML_DESCEND_FIRST);
+	if (tnode != NULL)
+	{
+	    tnode = mxmlFindElement(tnode,tnode,name,NULL,NULL,MXML_DESCEND_FIRST);
+	}
+    }
+    return tnode;
+}
+
+/*---------------------------------------------------------------------*/
+/*return 1 if in table mode , 0 if not */
+static void analyzeDataType(mxml_node_t *parent, int *rank, int *type,
+			    int64_t *iDim){
+  const char *typeString;
+  mxml_node_t* tnode;
+  int nx_type = -1;
+  int table_mode = 0;
+
+  *rank = 1;
+  *type = NX_CHAR;
+  iDim[0] = -1;
+
+  /*
+    get the type attribute. No attribute means: plain text
+  */ 
+  tnode = findDimsNode(parent);
+  if (tnode != NULL)
+  {
+	table_mode = 1;
+	parent = tnode;
+  }
+  typeString = mxmlElementGetAttr(parent,TYPENAME);
+  if(typeString == NULL){
+    return;
+  }
+
+  nx_type = translateTypeCode((char *)typeString, "");
+
+  /*
+    assign type
+  */
+  if(nx_type == -1){
+    mxml_error(
+     "ERROR: %s is an invalid NeXus type, I try to continue but may fail",
+     typeString);
+    *type =NX_CHAR;
+    return;
+  }
+
+  *type = nx_type;
+  
+  analyzeDim(typeString, rank, iDim, type);
+  if (table_mode)
+  {
+	*rank = 1;
+	iDim[0] = 1;
+  }
+  return;
+}
+/*-------------------------------------------------------------------*/
+void destroyDataset(void *data){
+  if(data != NULL){
+    dropNXDataset((pNXDS)data);
+  }
+}
+/*-------------------------------------------------------------------*/
+static char *getNextNumber(char *pStart, char pNumber[80]){
+  int charCount = 0;
+  pNumber[0] = '\0';
+
+  /* advance to first digit */
+  while(isspace(*pStart) && *pStart != '\0'){
+    pStart++;
+  }
+  if(*pStart == '\0'){
+    return NULL;
+  }
+
+  /* copy */
+  while(!isspace(*pStart) && *pStart != '\0' && charCount < 78){
+    pNumber[charCount] = *pStart;
+    pStart++;
+    charCount++;
+  }
+  pNumber[charCount] = '\0';
+  return pStart;
+}
+/*--------------------------------------------------------------------*/
+mxml_type_t nexusTypeCallback(mxml_node_t *parent){
+  const char *typeString;
+
+  if(strstr(parent->value.element.name,"?xml") != NULL ||
+     !strncmp(parent->value.element.name,"NX",2) ||
+     !strcmp(parent->value.element.name,DATA_NODE_NAME) ||
+     !strcmp(parent->value.element.name,DIMS_NODE_NAME)){
+    return MXML_ELEMENT;
+  } else {
+    /* data nodes do not habe TYPENAME in table style but are always CUSTOM */
+    if (parent->parent != NULL && !strcmp(parent->parent->value.element.name, DATA_NODE_NAME))
+    {
+	return MXML_CUSTOM;
+    }
+    if (parent->parent != NULL && !strcmp(parent->parent->value.element.name, DIMS_NODE_NAME))
+    {
+	return MXML_OPAQUE;
+    }
+    typeString = mxmlElementGetAttr(parent,TYPENAME);
+    if(typeString == NULL){
+      /*
+	MXML_TEXT seems more appropriate here. But mxml hacks text into
+	single words which is not what NeXus wants.
+      */
+      return MXML_OPAQUE;
+    } else{
+      if(strstr(typeString,"NX_CHAR") != NULL){
+	return MXML_OPAQUE;
+      } else {
+	return MXML_CUSTOM;
+      }
+    }
+  }
+}
+/*----------------------------------------------------------------------*/
+int nexusLoadCallback(mxml_node_t *node, const char *buffer){
+  mxml_node_t *parent = NULL;
+  int rank, type; 
+  int64_t iDim[NX_MAXRANK];
+  char pNumber[80], *pStart;
+  long address, maxAddress;
+  pNXDS dataset = NULL;
+
+  parent = node->parent;
+  analyzeDataType(parent,&rank,&type,iDim);
+  if(iDim[0] == -1 || !strcmp(parent->parent->value.element.name, DIMS_NODE_NAME)){
+    iDim[0] = strlen(buffer);
+    node->value.custom.data = strdup(buffer);
+    node->value.custom.destroy = free;
+    return 0;
+  } else {
+    node->value.custom.data = createNXDataset(rank,type,iDim);
+    dataset = (pNXDS)node->value.custom.data;
+    if(dataset == NULL){
+      mxml_error("Failed to allocate custom dataset");
+      return 1;
+    }
+    node->value.custom.destroy = destroyDataset; 
+  }
+
+  /*
+    load data
+  */
+  pStart = (char *)buffer;
+  maxAddress = getNXDatasetLength(dataset);
+  address = 0;
+  while( (pStart = getNextNumber(pStart,pNumber)) != NULL && 
+	 address < maxAddress){
+    putNXDatasetValueAt(dataset,address,atof(pNumber));
+    address++;
+  }
+
+  return 0;
+}
+/*---------------------------------------------------------------------*/
+static void stringIntoBuffer(char **buffer, char **bufPtr, size_t *bufSize, 
+		      char *string){
+  size_t i;
+
+  for(i = 0; i < strlen(string); i++){
+    myxml_add_char(string[i],bufPtr,buffer,bufSize);
+  }
+}
+/*--------------------------------------------------------------------*/
+static void formatNumber(double value, char *txt, int txtLen,
+			 char *format, int type){
+  switch(type){
+  case NX_INT8:
+  case NX_UINT8:
+  case NX_INT16:
+  case NX_UINT16:
+  case NX_INT32:
+  case NX_UINT32:
+    snprintf(txt,txtLen,format,(int)value);
+    break;
+  case NX_INT64:
+    snprintf(txt,txtLen,format,(int64_t)value);
+    break;
+  case NX_UINT64:
+    snprintf(txt,txtLen,format,(uint64_t)value);
+    break;
+  case NX_FLOAT32:
+  case NX_FLOAT64:
+    snprintf(txt,txtLen,format,value);
+    break;
+  default:
+    /*assert(0);  something is very wrong here */
+    printf("Problem\n");
+    break;
+  }
+}
+/*--------------------------------------------------------------------*/
+static int countDepth(mxml_node_t *node){
+  int count = 0;
+  mxml_node_t *cur;
+
+  cur = node;
+  while(cur != NULL){
+    count++;
+    cur = cur->parent;
+  }
+  count--;
+  return count;
+}
+/*---------------------------------------------------------------------*/
+char *nexusWriteCallback(mxml_node_t *node){
+  int type, col;
+  char pNumber[80], indent[80], format[30];
+  char *buffer, *bufPtr;
+  pNXDS dataset;
+  int currentLen, table_style = 0; 
+  size_t i, bufsize, length;
+  int is_definition = 0;
+  /* this is set by nxconvert when making a definiton */
+  is_definition = (getenv("NX_IS_DEFINITION") != NULL);
+
+  if (!strcmp(node->parent->parent->value.element.name, DATA_NODE_NAME))
+  {
+	table_style = 1;
+  }
+  /*
+    allocate output buffer
+  */
+  buffer = (char *)malloc(1024*sizeof(char));
+  if(buffer == NULL){
+    mxml_error("Unable to allocate buffer");
+    return NULL;
+  }
+  memset(buffer,0,1024);
+  bufPtr = buffer;
+  bufsize = 1024;
+
+  dataset = (pNXDS)node->value.custom.data;
+
+  /*
+    prepare indentation level
+  */
+  col = countDepth(node)*2;
+  memset(indent,0,80);
+  for(i = 0; i < col; i++){
+    indent[i] = ' ';
+  }
+
+  /*
+    get dataset info
+  */
+  type = getNXDatasetType(dataset);
+  if (is_definition) {
+    length = 1;
+  } else {
+    length = getNXDatasetLength(dataset);
+  }
+  if(dataset->format != NULL){
+    strcpy(format,dataset->format);
+  } else {
+    getNumberFormat(type,format);
+  }
+
+  /*
+    actually get the data out
+  */
+  if (table_style)
+  {
+      for(i = 0; i < length; i++){
+        formatNumber(getNXDatasetValueAt(dataset,i),pNumber,79,format,type);
+        stringIntoBuffer(&buffer,&bufPtr,&bufsize,pNumber);
+      }
+  }
+  else
+  {
+      currentLen = col;
+      myxml_add_char('\n',&bufPtr,&buffer,&bufsize);
+      stringIntoBuffer(&buffer,&bufPtr,&bufsize,indent);
+      for(i = 0; i < length; i++){
+        formatNumber(getNXDatasetValueAt(dataset,i),pNumber,79,format,type);
+        if(currentLen + strlen(pNumber) > MXML_WRAP){
+          /*
+	    wrap line
+          */
+          myxml_add_char('\n',&bufPtr,&buffer,&bufsize);
+          stringIntoBuffer(&buffer,&bufPtr,&bufsize,indent);
+          currentLen = col;
+        }
+        stringIntoBuffer(&buffer,&bufPtr,&bufsize,pNumber);
+        myxml_add_char(' ',&bufPtr,&buffer,&bufsize);
+        currentLen += strlen(pNumber) + 1;
+      }
+  }
+  myxml_add_char('\0',&bufPtr,&buffer,&bufsize);
+  return (char *)buffer;
+}
+/*------------------------------------------------------------------*/
+int isDataNode(mxml_node_t *node){
+  if(mxmlElementGetAttr(node,"name") != NULL){
+    return 0;
+  }
+  if(strcmp(node->value.element.name,"NXroot") == 0){
+    return 0;
+  }
+  if(strcmp(node->value.element.name,DIMS_NODE_NAME) == 0){
+    return 0;
+  }
+  if(strcmp(node->value.element.name,DATA_NODE_NAME) == 0){
+    return 0;
+  }
+  if(strcmp(node->value.element.name,"NAPIlink") == 0){
+    return 0;
+  }
+  return 1;
+}
+/*--------------------------------------------------------------------*/
+static int isTextData(mxml_node_t *node){
+  const char *attr = NULL;
+
+  if(!isDataNode(node)){
+    return 0;
+  }
+  /*
+    test datasets
+  */
+  attr = mxmlElementGetAttr(node,TYPENAME);
+  if(attr == NULL){
+    return 1;
+  }
+  if(strstr(attr,"NX_CHAR") != NULL){
+    return 1;
+  } else {
+    return 0;
+  }
+}
+/*---------------------------------------------------------------------*/
+
+/*
+ * note: not reentrant or thead safe; returns pointer to static storage
+ */
+const char *NXwhitespaceCallback(mxml_node_t *node, int where){
+  static char *indent = NULL;
+  int len;  
+
+  if(strstr(node->value.element.name,"?xml") != NULL){
+    return NULL;
+  }
+  if (node->parent != NULL && !strcmp(node->parent->value.element.name, DATA_NODE_NAME))
+  {
+    return NULL;
+  }
+  if (where == MXML_WS_BEFORE_CLOSE && !strcmp(node->value.element.name, DATA_NODE_NAME))
+  {
+    return NULL;
+  }
+
+  if(isTextData(node)){
+    if(where == MXML_WS_BEFORE_OPEN){
+      len = countDepth(node)*2 + 2;
+      if (indent != NULL)
+      {
+	free(indent);
+	indent = NULL;
+      }
+      indent = (char *)malloc(len*sizeof(char));
+      if(indent != NULL){
+	memset(indent,' ',len);
+	indent[0]= '\n';
+	indent[len-1] = '\0';
+	return  (const char*)indent;
+      }
+    }
+    return NULL;
+  }
+
+  if(where == MXML_WS_BEFORE_OPEN || where == MXML_WS_BEFORE_CLOSE){
+    len = countDepth(node)*2 + 2;
+    if (indent != NULL)
+    {
+	free(indent);
+	indent = NULL;
+    }
+    indent = (char *)malloc(len*sizeof(char));
+    if(indent != NULL){
+      memset(indent,' ',len);
+      indent[0]= '\n';
+      indent[len-1] = '\0';
+      return  (const char*)indent;
+    }
+  }
+  return NULL;
+}
+/*-----------------------------------------------------------------------*/
+#ifdef TESTMAIN
+#include <stdio.h>
+
+int main(int argc, char *argv[]){
+   mxml_node_t *root = NULL;
+   FILE *f;
+
+   mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback);
+   initializeNumberFormats();
+
+   /*
+     read test
+   */
+   f = fopen("dmc.xml","r");
+   root = mxmlLoadFile(NULL,f,nexusTypeCallback);
+   fclose(f);
+
+   /*
+     write test
+   */
+   setNumberFormat(NX_INT32,"%8d");
+   setNumberFormat(NX_FLOAT32,"%8.2f");
+   f = fopen("dmc2.xml","w");
+   mxmlSaveFile(root,f,NXwhitespaceCallback);
+   fclose(f);
+
+}
+#endif
+
+
+#endif /*NXXML*/ 
diff --git a/src/nxio.h b/src/nxio.h
new file mode 100644
index 0000000..0d51ddd
--- /dev/null
+++ b/src/nxio.h
@@ -0,0 +1,50 @@
+/**
+ * This file contains functions necessary to perform XML-I/O for
+ * NeXus with the mxml-library.
+ * 
+ * Most notably it contains the callback function for reading data
+ *
+ *   Copyright (C) 2004 Mark Koennecke
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  For further information, see <http://www.nexusformat.org>
+ */
+
+#ifndef __NXIO
+#define __NXIO
+#include <mxml.h>
+
+#define TYPENAME "NAPItype"
+
+#define DIMS_NODE_NAME "columns"
+#define DATA_NODE_NAME "row"
+
+mxml_type_t nexusTypeCallback(mxml_node_t *parent);
+const char *NXwhitespaceCallback(mxml_node_t *node, int where);
+int nexusLoadCallback(mxml_node_t *node, const char *buffer);
+char *nexusWriteCallback(mxml_node_t *node);
+
+void setNumberFormat(int dataType, char *formatString);
+void initializeNumberFormats();
+void getNumberText(int nx_type, char *typestring, int typeLen);
+void destroyDataset(void *data);
+int translateTypeCode(const char *code, const char* term);
+int isDataNode(mxml_node_t *node);
+void analyzeDim(const char *typeString, int *rank, 
+		int64_t *iDim, int *type);
+
+
+#endif
diff --git a/src/nxstack.c b/src/nxstack.c
new file mode 100644
index 0000000..a5ba2bd
--- /dev/null
+++ b/src/nxstack.c
@@ -0,0 +1,145 @@
+/*
+  This is some code to handle a stack of NeXus files. This is used to implement 
+  external linking within the NeXus-API
+
+  Copyright (C) 1997-2006 Mark Koennecke
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+
+  Added code to support the path stack for NXgetpath, 
+        Mark Koennecke, October 2009
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <napi.h>
+#include "nxstack.h"
+
+/*-----------------------------------------------------------------------
+ Data definitions
+---------------------------------------------------------------------*/
+
+typedef struct {
+  pNexusFunction pDriver;
+  NXlink closeID;
+  char filename[1024];
+}fileStackEntry;
+
+
+typedef struct __fileStack {
+  int fileStackPointer;
+  fileStackEntry fileStack[MAXEXTERNALDEPTH];
+  int pathPointer;
+  char pathStack[NXMAXSTACK][NX_MAXNAMELEN];
+}fileStack;
+/*---------------------------------------------------------------------*/
+pFileStack makeFileStack(){
+  pFileStack pNew = NULL;
+  
+  pNew = (pFileStack)malloc(sizeof(fileStack));
+  if(pNew == NULL){
+    return NULL;
+  }
+  memset(pNew,0,sizeof(fileStack));
+  pNew->fileStackPointer = -1;
+  pNew->pathPointer = -1;
+  return pNew;
+}
+/*---------------------------------------------------------------------*/
+void killFileStack(pFileStack self){
+  if(self != NULL){
+    free(self);
+  }
+}
+/*---------------------------------------------------------------------*/
+int getFileStackSize(){
+  return sizeof(fileStack);
+}
+/*----------------------------------------------------------------------*/
+void pushFileStack(pFileStack self, pNexusFunction pDriv, char *file){
+  size_t length;
+
+  self->fileStackPointer++;
+  self->fileStack[self->fileStackPointer].pDriver = pDriv;
+  memset(&self->fileStack[self->fileStackPointer].closeID,0,sizeof(NXlink));
+  length = strlen(file);
+  if(length >= 1024){
+    length = 1023;
+  }
+  memcpy(&self->fileStack[self->fileStackPointer].filename,file,length);
+}
+/*----------------------------------------------------------------------*/
+void popFileStack(pFileStack self){
+  self->fileStackPointer--;
+  if(self->fileStackPointer < -1){
+    self->fileStackPointer = -1;
+  }
+}
+/*----------------------------------------------------------------------*/
+pNexusFunction peekFileOnStack(pFileStack self){
+  return self->fileStack[self->fileStackPointer].pDriver;
+}
+/*---------------------------------------------------------------------*/
+char *peekFilenameOnStack(pFileStack self){
+  return self->fileStack[self->fileStackPointer].filename;
+}
+/*----------------------------------------------------------------------*/
+void peekIDOnStack(pFileStack self, NXlink *id){
+  memcpy(id, &self->fileStack[self->fileStackPointer].closeID, sizeof(NXlink));
+}
+/*---------------------------------------------------------------------*/
+void setCloseID(pFileStack self, NXlink id){
+  memcpy(&self->fileStack[self->fileStackPointer].closeID, &id, sizeof(NXlink));
+}
+/*----------------------------------------------------------------------*/
+int fileStackDepth(pFileStack self){
+  return self->fileStackPointer;
+}
+/*----------------------------------------------------------------------*/
+void pushPath(pFileStack self, const char *name){
+  self->pathPointer++;
+  strncpy(self->pathStack[self->pathPointer],name,NX_MAXNAMELEN-1);
+}
+/*-----------------------------------------------------------------------*/
+void popPath(pFileStack self){
+  self->pathPointer--;
+  if(self->pathPointer < -1){
+    self->pathPointer = -1;
+  }
+}
+/*-----------------------------------------------------------------------*/
+int buildPath(pFileStack self, char *path, int pathlen){
+  int i;
+  size_t totalPathLength;
+  char *totalPath;
+
+  for(i = 0, totalPathLength = 5; i <= self->pathPointer; i++){
+    totalPathLength += strlen(self->pathStack[i]) + 1;
+  }
+  totalPath = (char*)malloc(totalPathLength*sizeof(char));
+  if(totalPath == NULL){
+    return 0;
+  }
+  memset(totalPath,0,totalPathLength*sizeof(char));
+  for(i = 0; i <= self->pathPointer; i++){
+    strcat(totalPath,"/");
+    strcat(totalPath,self->pathStack[i]);
+  }
+  
+  strncpy(path,totalPath,pathlen-1);
+  free(totalPath);
+  return 1;
+}
diff --git a/src/nxstack.h b/src/nxstack.h
new file mode 100644
index 0000000..2faaf04
--- /dev/null
+++ b/src/nxstack.h
@@ -0,0 +1,52 @@
+/*
+  This is some code to handle a stack of NeXus files. This is used to implement 
+  external linking within the NeXus-API
+
+  Copyright (C) 1997-2006 Mark Koennecke
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 
+  For further information, see <http://www.nexusformat.org>
+
+  Added functions to deal with the path stack for NXgetpath
+  Mark Koennecke, October 2009
+
+*/
+#ifndef NEXUSFILESTACK
+#define NEXUSFILESTACK
+
+typedef struct __fileStack *pFileStack;
+#define MAXEXTERNALDEPTH 16
+
+pFileStack makeFileStack();
+void killFileStack(pFileStack self);
+int getFileStackSize();
+
+void pushFileStack(pFileStack self, pNexusFunction pDriv, char *filename);
+void popFileStack(pFileStack self);
+
+pNexusFunction peekFileOnStack(pFileStack self);
+char *peekFilenameOnStack(pFileStack self);
+void peekIDOnStack(pFileStack self, NXlink *id);
+void setCloseID(pFileStack self, NXlink id);
+ 
+int fileStackDepth(pFileStack self);
+
+void pushPath(pFileStack self, const char *name);
+void popPath(pFileStack self);
+int buildPath(pFileStack self, char *path, int pathlen);
+
+#endif
+
diff --git a/src/nxxml.c b/src/nxxml.c
new file mode 100644
index 0000000..e0fc934
--- /dev/null
+++ b/src/nxxml.c
@@ -0,0 +1,2001 @@
+/*
+ * This is the implementation file for the XML file driver
+ * for NeXus
+ *
+ *   Copyright (C) 2006 Mark Koennecke
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  For further information, see <http://www.nexusformat.org>
+ */
+
+
+#ifdef NXXML 
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdint.h>
+#include <mxml.h>
+#include <napi.h>
+#include <nxxml.h>
+#include "nxio.h"
+#include "nxdataset.h"
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif /* _MSC_VER */
+
+extern  void *NXpData;
+extern int validNXName(const char* name, int allow_colon); /* from napi.c */
+char *nxitrim(char *str); /* from napi.c */
+
+/*----------------------- our data structures --------------------------
+  One might wonder why a node stack is still needed even if this API
+  operates on top of a tree API. The reason for this are the links.
+  Following a link on any NXopenpath, data means a jump through the
+  whole tree. In order to correctly return from such adventures,
+  a stack is needed. Moreover we need it in order to keep track of the
+  state of search operations.
+
+  The true NXroot node is always at stack[0]. The root in the data
+  structure is the ?xml element. The latter one is needed to store
+  the tree.
+-----------------------------------------------------------------------*/
+typedef struct {
+    mxml_node_t *current;
+    mxml_node_t *currentChild;
+    int currentAttribute;
+    int options; /**< additional information about the node */
+}xmlStack;
+
+/*
+ * Freddie Akeroyd, 19/03/2008
+ *
+ * Add in support for table style data writing - this is 
+ * indicated internally via the XMLSTACK_OPTION_TABLE flag
+ * and separates the dimensions and data into separate nodes contained
+ * in DIMS_NODE_NAME and DATA_NODE_NAME. This is a first commit and 
+ * involves some code duplication that will need to be cleaned up later.
+ * Also writing in table style is only enabled for 1D arrays as
+ * I haven't done slab writing yet which the nexus test program uses
+ * for writing 2D arrays. 
+ *
+ * Table output is enabled by opening a file with (NXACC_CREATEXML | NXACC_TABLE)
+ *
+ * See http://trac.nexusformat.org/code/ticket/111 for further details
+ */
+#define XMLSTACK_OPTION_TABLE 		0x1 /**< indicates table option in xmlStack */
+
+
+/*---------------------------------------------------------------------*/
+typedef struct {
+  mxml_node_t *root;           /* root node */
+  int readOnly;                /* read only flag */
+  int tableStyle;              /**< whether to output data in XML table style */
+  int stackPointer;            /* stack pointer */
+  char filename[1024];         /* file name, for NXflush, NXclose */
+  xmlStack stack[NXMAXSTACK];  /* stack */
+}XMLNexus, *pXMLNexus;
+/*===================== support functions ===============================*/
+extern char *stptok(char *s, char *tok, size_t toklen, char *brk);
+/*----------------------------------------------------------------------*/
+static mxml_node_t *getLinkTarget(pXMLNexus xmlHandle, const char *target){
+  mxml_node_t *node = NULL;
+  mxml_node_t *testNode = NULL;
+  char path[132], *pPtr;
+
+  pPtr = (char *)target + 1;
+  node = xmlHandle->stack[0].current;
+  while((pPtr = stptok(pPtr,path,131,"/")) != NULL){
+    /*
+      search for group node
+    */
+    testNode = mxmlFindElement(node,node,NULL,"name",path,MXML_DESCEND_FIRST);
+    if(testNode == NULL){
+      /*
+	it can still be a data node
+      */
+      testNode = mxmlFindElement(node,node,path,NULL,NULL,MXML_DESCEND_FIRST);
+    }
+    if(testNode == NULL){
+      NXReportError("Cannot follow broken link");
+      return NULL;
+    } else {
+      node = testNode;
+    }
+  }
+  return node;
+}
+/*==================== file functions ===================================*/
+static void errorCallbackForMxml(const char *txt){
+  NXReportError((char *)txt);
+}
+/*-----------------------------------------------------------------------*/
+NXstatus  NXXopen(CONSTCHAR *filename, NXaccess am, 
+			       NXhandle* pHandle) {
+  pXMLNexus xmlHandle = NULL;
+  FILE *fp = NULL;
+  char *time_buffer = NULL;
+  mxml_node_t *current;
+
+  /*
+    allocate data
+  */
+  xmlHandle = (pXMLNexus)malloc(sizeof(XMLNexus));
+  if(!xmlHandle){
+    NXReportError( "Out of memory allocating XML file handle");
+    return NX_ERROR;
+  }
+  memset(xmlHandle,0,sizeof(XMLNexus));
+
+  /*
+    initialize mxml XML parser
+  */
+  mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback);
+  initializeNumberFormats();
+  mxmlSetErrorCallback(errorCallbackForMxml);
+
+  xmlHandle->tableStyle = ((am & NXACC_TABLE) ? 1 : 0);
+  /*
+    open file
+  */
+  strncpy(xmlHandle->filename,filename,1023);
+  switch(am & NXACCMASK_REMOVEFLAGS){
+  case NXACC_READ:
+    xmlHandle->readOnly = 1;
+  case NXACC_RDWR:
+    fp = fopen(filename,"r");
+    if(fp == NULL){
+      NXReportError("Failed to open file:");
+      NXReportError((char *)filename);
+      free(xmlHandle);
+      return NX_ERROR;
+    }
+    xmlHandle->root = mxmlLoadFile(NULL,fp,nexusTypeCallback);
+    xmlHandle->stack[0].current = mxmlFindElement(xmlHandle->root,
+						  xmlHandle->root,
+						  "NXroot",
+						  NULL,NULL,
+						  MXML_DESCEND);
+    xmlHandle->stack[0].currentChild = NULL;
+    xmlHandle->stack[0].currentAttribute = 0;
+    xmlHandle->stack[0].options = 0;
+    fclose(fp);
+    break;
+  case NXACC_CREATEXML:
+    xmlHandle->root = mxmlNewElement(NULL,
+		   "?xml version=\"1.0\" encoding=\"UTF-8\"?");
+    current = mxmlNewElement(xmlHandle->root,"NXroot");
+    mxmlElementSetAttr(current,"NeXus_version",NEXUS_VERSION);
+    mxmlElementSetAttr(current,"XML_version","mxml");
+    mxmlElementSetAttr(current,"file_name",filename);
+    mxmlElementSetAttr(current,"xmlns", NEXUS_SCHEMA_NAMESPACE);
+    mxmlElementSetAttr(current,"xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
+    mxmlElementSetAttr(current,"xsi:schemaLocation",
+	NEXUS_SCHEMA_NAMESPACE " " NEXUS_SCHEMA_URL);
+    time_buffer = NXIformatNeXusTime();
+    if(time_buffer != NULL){
+      mxmlElementSetAttr(current,"file_time",time_buffer);
+      free(time_buffer);
+    } 
+    xmlHandle->stack[0].current = current;
+    xmlHandle->stack[0].currentChild = NULL;
+    xmlHandle->stack[0].currentAttribute = 0;
+    xmlHandle->stack[0].options = 0;
+    break;
+  default:
+    NXReportError("Bad access parameter specified in NXXopen");
+    return NX_ERROR;
+  }
+  if(xmlHandle->stack[0].current == NULL){
+      NXReportError(
+		     "No NXroot element in XML-file, no NeXus-XML file");
+      return NX_ERROR;
+  }
+
+  *pHandle = xmlHandle;
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXclose (NXhandle* fid){
+  pXMLNexus xmlHandle = NULL;
+  FILE *fp = NULL;
+
+  xmlHandle = (pXMLNexus)*fid;
+  assert(xmlHandle);
+  
+  if(xmlHandle->readOnly == 0) {
+    fp = fopen(xmlHandle->filename,"w");
+    if(fp == NULL){
+      NXReportError("Failed to open NeXus XML file for writing");
+      return NX_ERROR;
+    }
+    mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
+    fclose(fp);
+  }
+  mxmlDelete(xmlHandle->root);
+  free(xmlHandle);
+  *fid = NULL;
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXflush(NXhandle *fid){
+  pXMLNexus xmlHandle = NULL;
+  FILE *fp = NULL;
+
+  xmlHandle = (pXMLNexus)*fid;
+  assert(xmlHandle);
+  
+  if(xmlHandle->readOnly == 0) {
+    fp = fopen(xmlHandle->filename,"w");
+    if(fp == NULL){
+      NXReportError("Failed to open NeXus XML file for writing");
+      return NX_ERROR;
+    }
+    mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
+    fclose(fp);
+  }
+  return NX_OK;
+}
+/*=======================================================================
+                   Group functions
+=========================================================================*/
+NXstatus  NXXmakegroup (NXhandle fid, CONSTCHAR *name, 
+				     CONSTCHAR *nxclass){
+  char buffer[256];
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *newGroup = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if (!validNXName(name, 0))
+  {
+    sprintf(buffer, "ERROR: invalid characters in group name \"%s\"", name);
+    NXReportError(buffer);
+    return NX_ERROR;
+  }
+  if ( strlen(nxclass) == 0 ) /* xml node must have a name */
+  {
+      nxclass = "NXcollection";
+  }
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("Close dataset before trying to create a group");
+    return NX_ERROR;
+  }
+
+  newGroup = mxmlNewElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+			    nxclass);
+  if(!newGroup){
+    NXReportError("failed to allocate new group");
+    return NX_ERROR;
+  }
+  mxmlElementSetAttr(newGroup,"name",name);
+  return NX_OK;
+} 
+/*----------------------------------------------------------------------*/
+static mxml_node_t *searchGroupLinks(pXMLNexus xmlHandle, CONSTCHAR *name, 
+				CONSTCHAR *nxclass){
+  mxml_node_t *linkNode = NULL;
+  mxml_node_t *current;
+  mxml_node_t *test = NULL;
+  const char *linkTarget;
+  const char *linkName = NULL;
+
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  linkNode = current;
+  while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
+				    MXML_DESCEND_FIRST)) != NULL){
+    linkTarget = mxmlElementGetAttr(linkNode,"target");
+    test = getLinkTarget(xmlHandle,linkTarget);
+    if(test != NULL){
+      if(strcmp(test->value.element.name,nxclass) == 0){
+	if(strcmp(mxmlElementGetAttr(test,"name"),name) == 0){
+	  return test;
+	}
+      }
+    }
+    /*
+      test for named links
+    */
+    linkName = mxmlElementGetAttr(linkNode,"name");
+    if(test != NULL && linkName != NULL){
+      if(strcmp(test->value.element.name,nxclass) == 0){
+	if(strcmp(linkName, name) == 0){
+	  return test;
+	}
+      }
+    }
+  }
+  return NULL;
+}
+/*------------------------------------------------------------------------*/
+NXstatus  NXXopengroup (NXhandle fid, CONSTCHAR *name, 
+				     CONSTCHAR *nxclass){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *newGroup = NULL;
+  char error[1024];
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("Close dataset before trying to open a group");
+    return NX_ERROR;
+  }
+  if ( strlen(nxclass) == 0 ) /* xml node must have a name */
+  {
+      nxclass = "NXcollection";
+  }
+  newGroup = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+			     xmlHandle->stack[xmlHandle->stackPointer].current,
+			     nxclass,
+			     "name",
+			     name,
+			     MXML_DESCEND_FIRST);
+  if(newGroup == NULL){
+    newGroup = searchGroupLinks(xmlHandle,name,nxclass);
+  }
+  if(!newGroup){
+    snprintf(error,1023,"Failed to open %s, %s",name,nxclass);
+    NXReportError(error);
+    return NX_ERROR;
+  }
+  xmlHandle->stackPointer++;
+  xmlHandle->stack[xmlHandle->stackPointer].current = newGroup;
+  xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
+  xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
+  xmlHandle->stack[xmlHandle->stackPointer].options = 0;
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXclosegroup (NXhandle fid){
+  pXMLNexus xmlHandle = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    /*
+      silently fix this
+    */
+    NXXclosedata(fid);
+  }
+  if(xmlHandle->stackPointer > 0){
+    xmlHandle->stackPointer--;
+  }
+  return NX_OK;
+}
+/*=========================================================================
+         dataset functions
+=========================================================================*/
+NXstatus  NXXcompmakedata64 (NXhandle fid, CONSTCHAR *name, 
+					int datatype, 
+					int rank, 
+					int64_t dimensions[],
+					int compress_type, int64_t chunk_size[]){
+  /*
+    compression does not relly make sense with XML
+  */
+  return NXXmakedata64(fid,name,datatype,rank,dimensions);
+}
+/*-----------------------------------------------------------------------*/
+static char *buildTypeString(int datatype, int rank, int64_t dimensions[]){
+  char *typestring = NULL;
+  char pNumber[20];
+  int i;
+
+  /*
+    allocate data
+  */
+  typestring = (char *)malloc(132*sizeof(char));
+  if(!typestring){
+    NXReportError("Failed to allocate typestring");
+    return NULL;
+  }
+  memset(typestring,0,132*sizeof(char));
+
+  getNumberText(datatype,typestring,130);
+  if(rank > 1 || datatype == NX_CHAR || dimensions[0] > 1) {
+    strcat(typestring,"[");
+    snprintf(pNumber,19,"%lld", (long long)dimensions[0]);
+    strncat(typestring,pNumber,130-strlen(typestring));
+    for(i = 1; i < rank; i++){
+      snprintf(pNumber,19,",%lld", (long long)dimensions[i]);
+      strncat(typestring,pNumber,130-strlen(typestring));
+    }
+    strcat(typestring,"]");
+  }
+  return typestring;
+}
+
+/*------------------------------------------------------------------------*/
+NXstatus  NXXmakedatatable64 (NXhandle fid, 
+				    CONSTCHAR *name, int datatype, 
+				    int rank, int64_t dimensions[]){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *dataNode = NULL, *dataNodeRoot = NULL, *dimsNode = NULL, *dimsNodeRoot = NULL;
+  mxml_node_t *newData = NULL;
+  mxml_node_t *current;
+  char *typestring;
+  int i, ndata; 
+  char buffer[256];
+  static int64_t one = 1;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+  if (!validNXName(name, 0))
+  {
+    sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
+    NXReportError(buffer);
+    return NX_ERROR;
+  }
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("Close dataset before trying to create a dataset");
+    return NX_ERROR;
+  }
+  if(dimensions[0] < 0){
+    dimensions[0] = 1;
+  }
+
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+  dimsNodeRoot = mxmlFindElement(current, current, DIMS_NODE_NAME, NULL, NULL, MXML_DESCEND_FIRST);
+  if (dimsNodeRoot == NULL)
+  {
+      dimsNodeRoot = mxmlNewElement(current, DIMS_NODE_NAME);
+  }
+  dimsNode = mxmlNewElement(dimsNodeRoot, name);
+  mxmlNewOpaque(dimsNode, "");
+  typestring = buildTypeString(datatype,rank,dimensions);
+  if(typestring != NULL){
+    mxmlElementSetAttr(dimsNode,TYPENAME,typestring);
+    free(typestring);
+  } else {
+    NXReportError("Failed to allocate typestring");
+    return NX_ERROR;
+  }
+  ndata = 1;
+  for(i=0; i<rank; i++)
+  {
+     ndata *= dimensions[i];
+  }
+  dataNodeRoot = current;
+  for(i=0; i<ndata; i++)
+  {
+      dataNodeRoot = mxmlFindElement(dataNodeRoot, current, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
+      if (dataNodeRoot == NULL)
+      {
+          dataNodeRoot = mxmlNewElement(current, DATA_NODE_NAME);
+      }
+      dataNode = mxmlNewElement(dataNodeRoot,name);
+      newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
+      if(!newData){
+        NXReportError("Failed to allocate space for dataset");
+        return NX_ERROR;
+      }
+      memset(newData,0,sizeof(mxml_node_t));
+      mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
+      newData->type = MXML_CUSTOM;
+/*        newData->value.custom.data = createNXDataset(rank,datatype,dimensions); */
+      newData->value.custom.data = createNXDataset(1,datatype,&one);
+      if(!newData->value.custom.data){
+        NXReportError("Failed to allocate space for dataset");
+        return NX_ERROR;
+      }
+      newData->value.custom.destroy = destroyDataset;
+  }
+  return NX_OK;
+}
+
+NXstatus  NXXmakedata64 (NXhandle fid, 
+				    CONSTCHAR *name, int datatype, 
+				    int rank, int64_t dimensions[]){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *dataNode = NULL;
+  mxml_node_t *newData = NULL;
+  mxml_node_t *current;
+  char *typestring;
+  char buffer[256];
+
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+  if (!validNXName(name, 0))
+  {
+    sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
+    NXReportError(buffer);
+    return NX_ERROR;
+  }
+
+  if (xmlHandle->tableStyle && datatype != NX_CHAR && dimensions[0] != NX_UNLIMITED && rank == 1)
+  {
+      return NXXmakedatatable64(fid,name,datatype,rank,dimensions);
+  }
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("Close dataset before trying to create a dataset");
+    return NX_ERROR;
+  }
+  if(dimensions[0] < 0){
+    dimensions[0] = 1;
+  }
+
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  dataNode = mxmlNewElement(current,name);
+  typestring = buildTypeString(datatype,rank,dimensions);
+  if(typestring != NULL){
+    mxmlElementSetAttr(dataNode,TYPENAME,typestring);
+    free(typestring);
+  } else {
+    NXReportError("Failed to allocate typestring");
+    return NX_ERROR;
+  }
+  /*
+    NX_CHAR maps to MXML_OPAQUE datasets
+  */
+  if(datatype == NX_CHAR){
+    newData = mxmlNewOpaque(dataNode,"");
+    return NX_OK;
+  } else {
+    newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
+    if(!newData){
+      NXReportError("Failed to allocate space for dataset");
+      return NX_ERROR;
+    }
+    memset(newData,0,sizeof(mxml_node_t));
+    mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
+    newData->type = MXML_CUSTOM;
+    newData->value.custom.data = createNXDataset(rank,datatype,dimensions);
+    if(!newData->value.custom.data){
+      NXReportError("Failed to allocate space for dataset");
+      return NX_ERROR;
+    }
+    newData->value.custom.destroy = destroyDataset;
+  }
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static mxml_node_t *searchSDSLinks(pXMLNexus xmlHandle, CONSTCHAR *name){
+  mxml_node_t *linkNode = NULL;
+  mxml_node_t *current;
+  mxml_node_t *test = NULL;
+  const char *linkTarget;
+  const char *linkName = NULL;
+
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  linkNode = current;
+  while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
+				    MXML_DESCEND_FIRST)) != NULL){
+    linkTarget = mxmlElementGetAttr(linkNode,"target");
+    test = getLinkTarget(xmlHandle,linkTarget);
+    if(test != NULL){
+      if(strcmp(test->value.element.name,name) == 0){
+	return test;
+      }
+    }
+    /*
+      test for named links
+    */
+    linkName = mxmlElementGetAttr(linkNode,"name");
+    if(test != NULL && linkName != NULL){
+      if(strcmp(linkName,name) == 0){
+	return test;
+      }
+    }
+  }
+  return NULL;
+}
+/*-----------------------------------------------------------------------*/
+NXstatus  NXXopendatatable (NXhandle fid, CONSTCHAR *name){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *dataNode = NULL, *dimsNode = NULL;
+  char error[1024];
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    /*
+      silently fix this
+    */
+    xmlHandle->stackPointer--;
+    if(xmlHandle->stackPointer < 0){
+      xmlHandle->stackPointer = 0;
+    }
+  }
+  
+  dimsNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+			     xmlHandle->stack[xmlHandle->stackPointer].current,
+			     DIMS_NODE_NAME,
+			     NULL,
+			     NULL,
+			     MXML_DESCEND_FIRST);
+
+  if(!dimsNode){
+    snprintf(error,1023,"Failed to open dataset %s",name);
+    NXReportError(error);
+    return NX_ERROR;
+  }
+
+  dataNode = mxmlFindElement(dimsNode,
+			     dimsNode,
+			     name,
+			     NULL,
+			     NULL,
+			     MXML_DESCEND_FIRST);
+  if(dataNode == NULL){
+    dataNode = searchSDSLinks(xmlHandle,name);
+  }
+  if(!dataNode){
+    snprintf(error,1023,"Failed to open dataset %s",name);
+    NXReportError(error);
+    return NX_ERROR;
+  }
+  xmlHandle->stackPointer++;
+  xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
+  xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
+  xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
+  xmlHandle->stack[xmlHandle->stackPointer].options = XMLSTACK_OPTION_TABLE;
+  return NX_OK;
+}
+
+
+NXstatus  NXXopendata (NXhandle fid, CONSTCHAR *name){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *dataNode = NULL, *current = NULL;
+  char error[1024];
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  /* is this a table style node ? */
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  dataNode = mxmlFindElement(current,
+			     current,
+			     DATA_NODE_NAME,
+			     NULL,
+			     NULL,
+			     MXML_DESCEND_FIRST);
+  if (dataNode != NULL)
+  {
+      dataNode = mxmlFindElement(dataNode,
+			     dataNode,
+			     name,
+			     NULL,
+			     NULL,
+			     MXML_DESCEND_FIRST);
+  }
+  if (dataNode != NULL)
+  {
+	return NXXopendatatable(fid, name);
+  }
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    /*
+      silently fix this
+    */
+    xmlHandle->stackPointer--;
+    if(xmlHandle->stackPointer < 0){
+      xmlHandle->stackPointer = 0;
+    }
+  }
+  
+  dataNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+			     xmlHandle->stack[xmlHandle->stackPointer].current,
+			     name,
+			     NULL,
+			     NULL,
+			     MXML_DESCEND_FIRST);
+  if(dataNode == NULL){
+    dataNode = searchSDSLinks(xmlHandle,name);
+  }
+  if(!dataNode){
+    snprintf(error,1023,"Failed to open dataset %s",name);
+    NXReportError(error);
+    return NX_ERROR;
+  }
+  xmlHandle->stackPointer++;
+  xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
+  xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
+  xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
+  xmlHandle->stack[xmlHandle->stackPointer].options = 0;
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+
+NXstatus  NXXclosedata (NXhandle fid){
+  pXMLNexus xmlHandle = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    if(xmlHandle->stackPointer > 0){
+      xmlHandle->stackPointer--;
+    }
+    return NX_OK;
+  }
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static mxml_node_t *findData(mxml_node_t *node){
+  mxml_node_t *baby = node;
+  
+  while( (baby = mxmlWalkNext(baby,node,MXML_DESCEND_FIRST)) != NULL){
+    if(baby->type == MXML_OPAQUE || baby->type == MXML_CUSTOM){
+      return baby;
+    }
+  }
+  return NULL;
+}
+
+/* we only havv to deal with non-character data here */
+NXstatus  NXXputdatatable (NXhandle fid, const void *data){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  mxml_node_t *nodeRoot = NULL;
+  mxml_node_t *dataNodeRoot = NULL;
+  mxml_node_t *dataNode = NULL;
+  const char* name;
+  pNXDS dataset;
+  int i, offset, length;
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+  /* current points at the Idims node as done in NXXopendatatable */
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  name = current->value.element.name;
+  /* we want to walk all Idata nodes and set name */
+  nodeRoot =  current->parent->parent;
+  dataNodeRoot = nodeRoot;
+  offset = 0;
+  for(i=0; dataNodeRoot != NULL; i++)
+  {
+      dataNodeRoot = mxmlFindElement(dataNodeRoot, nodeRoot, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
+      if (dataNodeRoot != NULL)
+      {
+	dataNode = mxmlFindElement(dataNodeRoot,dataNodeRoot,name,NULL,NULL,MXML_DESCEND_FIRST);
+	if (dataNode != NULL)
+	{
+	    userData = findData(dataNode);
+  	    assert(userData != NULL);
+            dataset = (pNXDS)userData->value.custom.data;
+            assert(dataset);
+            length = getNXDatasetByteLength(dataset);
+            memcpy(dataset->u.ptr,(char*)data + offset,length);
+	    offset += length;
+	}
+      }
+    } 
+    return NX_OK;
+}
+
+/*------------------------------------------------------------------------*/
+NXstatus  NXXputdata (NXhandle fid, const void *data){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  pNXDS dataset;
+  int i, length, type, rank; 
+  int64_t dim[NX_MAXRANK];
+  char *pPtr = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
+  {
+      return NXXputdatatable(fid,data);
+  }
+
+  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No dataset open");
+    return NX_ERROR;
+  }
+  
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  userData = findData(current);
+  assert(userData != NULL);
+  if(userData->type == MXML_OPAQUE){
+    /*
+      Text data. We have to make sure that the text is \0 terminated. 
+      Some language bindings do not ensure that this is the case.
+    */
+    if(NXXgetinfo64(fid,&rank, dim, &type) == NX_OK){
+      length = 1;
+      for(i=0; i<rank; i++)
+      {
+	length *= dim[i];
+      }
+      /* we seem to have trouble reading an empty node back (no userData), so make sure we have at least a single space present even for empty strings */
+      if (length == 0)
+      {
+	mxmlSetOpaque(userData," ");
+      }
+      else
+      {
+        pPtr = (char *)malloc((length+1)*sizeof(char));
+        if(pPtr != NULL){
+          memcpy(pPtr,data,length);
+          pPtr[length] = '\0';
+	  mxmlSetOpaque(userData,(const char *)pPtr);
+          free(pPtr);
+        }
+      }
+    }
+    else
+    {
+        NXReportError("Unable to determine size of character dataset");
+        return NX_ERROR;
+    }
+  } else {
+    dataset = (pNXDS)userData->value.custom.data;
+    assert(dataset);
+    length = getNXDatasetByteLength(dataset);
+    memcpy(dataset->u.ptr,data,length);
+  }
+  return NX_OK;
+}
+
+NXstatus  NXXgetdatatable (NXhandle fid, void *data){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  mxml_node_t *nodeRoot = NULL;
+  mxml_node_t *dataNodeRoot = NULL;
+  mxml_node_t *dataNode = NULL;
+  const char* name;
+  pNXDS dataset;
+  int i, offset, length;
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  /* current points at the Idims node as done in NXXopendatatable */
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  name = current->value.element.name;
+  /* we want to walk all Idata nodes and set name */
+  nodeRoot =  current->parent->parent;
+  dataNodeRoot = nodeRoot;
+  offset = 0;
+  for(i=0; dataNodeRoot != NULL; i++)
+  {
+      dataNodeRoot = mxmlFindElement(dataNodeRoot, nodeRoot, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
+      if (dataNodeRoot != NULL)
+      {
+	dataNode = mxmlFindElement(dataNodeRoot,dataNodeRoot,name,NULL,NULL,MXML_DESCEND_FIRST);
+	if (dataNode != NULL)
+	{
+	    userData = findData(dataNode);
+  	    assert(userData != NULL);
+            dataset = (pNXDS)userData->value.custom.data;
+            assert(dataset);
+            length = getNXDatasetByteLength(dataset);
+            memcpy((char*)data + offset, dataset->u.ptr, length);
+	    offset += length;
+	}
+      }
+    } 
+    return NX_OK;
+}
+
+
+/*------------------------------------------------------------------------*/
+NXstatus  NXXgetdata (NXhandle fid, void *data){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  pNXDS dataset;
+  int i, length, type, rank; 
+  int64_t dim[NX_MAXRANK];
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
+  {
+      return NXXgetdatatable(fid,data);
+  }
+
+  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No dataset open");
+    return NX_ERROR;
+  }
+  
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  userData = findData(current);
+  assert(userData != NULL);
+  if(userData->type == MXML_OPAQUE){
+    /*
+      text data
+    */
+    if(NXXgetinfo64(fid,&rank, dim, &type) == NX_OK){
+      length = 1;
+      for(i=0; i<rank; i++)
+      {
+          length *= dim[i];
+      }
+      strncpy((char *)data,userData->value.opaque,length);
+    } else {
+      strcpy((char *)data,nxitrim(userData->value.opaque));
+    }
+
+  } else {
+    dataset = (pNXDS)userData->value.custom.data;
+    assert(dataset);
+    length = getNXDatasetByteLength(dataset);
+    memcpy(data,dataset->u.ptr,length);
+  }
+  return NX_OK;
+}
+/*------------------------------------------------------------------------*/
+NXstatus  NXXgetinfo64 (NXhandle fid, int *rank, 
+				   int64_t dimension[], int *iType){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  pNXDS dataset;
+  int myRank, i;
+  const char *attr = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No dataset open");
+    return NX_ERROR;
+  }
+  
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  userData = findData(current);
+  assert(userData != NULL);
+  if(userData->type == MXML_OPAQUE){
+    /*
+      text data
+    */
+    attr = mxmlElementGetAttr(current, TYPENAME);
+    if(attr == NULL){
+      *rank = 1;
+      *iType = NX_CHAR;
+      dimension[0]= strlen(userData->value.opaque);
+    } else {
+      *iType = translateTypeCode(attr, "");
+      analyzeDim(attr,rank,dimension,iType);
+      if (dimension[0] == -1) /* 1D strings are NX_CHAR not NX_CHAR[] so length will not be correct */
+      {
+        dimension[0] = strlen(userData->value.opaque);
+      }
+      
+    }
+  } else { 
+    dataset = (pNXDS)userData->value.custom.data;
+    assert(dataset);
+    myRank = getNXDatasetRank(dataset);
+    *rank = myRank;
+    *iType = getNXDatasetType(dataset);
+    for(i = 0; i < myRank; i++){
+      dimension[i] = getNXDatasetDim(dataset,i);
+    }
+  }
+  return NX_OK;
+}
+/*---------------------------------------------------------------------
+  clone the dataset and set the data pointer. This in order to use
+  the addressing and type conversion implemented in nxdataset
+---------------------------------------------------------------------*/ 
+static pNXDS makeSlabData(pNXDS dataset, const void *data, const int64_t size[]){
+  pNXDS slabData = NULL;
+  int rank, i;
+  
+  slabData = (pNXDS)malloc(sizeof(NXDS));
+  if(slabData == NULL){
+    return NULL;
+  }
+
+  rank = getNXDatasetRank(dataset);
+  slabData->rank = rank;
+  slabData->dim = (int64_t *)malloc(rank*sizeof(int64_t));
+  for(i = 0; i < rank; i++){
+    slabData->dim[i] = size[i];
+  }
+  slabData->type = getNXDatasetType(dataset);
+  slabData->u.ptr = (void*)data;
+  slabData->magic = dataset->magic;
+  return slabData;
+} 
+/*--------------------------------------------------------------------
+  This goes by recursion
+----------------------------------------------------------------------*/
+static void putSlabData(pNXDS dataset, pNXDS slabData, int dim,
+			const int64_t start[], 
+			int64_t sourcePos[], int64_t targetPos[]){
+  int64_t i, rank, length;
+
+  rank = getNXDatasetRank(slabData);
+  length = getNXDatasetDim(slabData,dim);
+  if(dim != rank-1){
+    for(i = 0; i < length; i++){
+      targetPos[dim] = start[dim] +i;
+      sourcePos[dim] = i;
+      putSlabData(dataset,slabData, dim+1,start,
+		  sourcePos,targetPos);
+    }
+  } else {
+    for(i = 0; i < length; i++){
+      targetPos[dim] = start[dim] +i;
+      sourcePos[dim] = i;
+      putNXDatasetValue(dataset,targetPos,
+			getNXDatasetValue(slabData,sourcePos));
+    }
+  }
+}
+/*----------------------------------------------------------------------
+ This is in order to support unlimited dimensions along the first axis
+ -----------------------------------------------------------------------*/
+static int checkAndExtendDataset(mxml_node_t *node, pNXDS dataset, 
+				 const int64_t start[], const int64_t size[]){
+  int64_t dim0, byteLength;
+  void *oldData = NULL;
+  char *typestring = NULL;
+
+  dim0 = start[0] + size[0];
+  if(dim0 > dataset->dim[0]){
+    byteLength = getNXDatasetByteLength(dataset);
+    oldData = dataset->u.ptr;
+    dataset->dim[0] = dim0;
+    dataset->u.ptr = malloc(getNXDatasetByteLength(dataset));
+    if(dataset->u.ptr == NULL){
+      return 0;
+    }
+    memset(dataset->u.ptr,0,getNXDatasetByteLength(dataset));
+    memcpy(dataset->u.ptr,oldData,byteLength);
+    free(oldData);
+    typestring = buildTypeString(dataset->type,dataset->rank,dataset->dim);
+    if(typestring != NULL){
+      mxmlElementSetAttr(node,TYPENAME,typestring);
+      free(typestring);
+    } else {
+      NXReportError("Failed to allocate typestring");
+      return 0;
+    }
+  }
+  return 1;
+}
+
+NXstatus  NXXputslabtable (NXhandle fid, const void *data, 
+				   const int64_t iStart[], const int64_t iSize[]){
+    return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXputslab64 (NXhandle fid, const void *data, 
+				   const int64_t iStart[], const int64_t iSize[]){
+  
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  pNXDS dataset, slabData;
+  int64_t sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
+  int status;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
+  {
+      return NXXputslabtable(fid,data,iStart,iSize);
+  }
+
+  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No dataset open");
+    return NX_ERROR;
+  }
+  
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  userData = findData(current);
+  assert(userData != NULL);
+  if(userData->type == MXML_OPAQUE){
+    NXReportError("This API does not support slabs on text data");
+    return NX_ERROR;
+  }
+  dataset = (pNXDS)userData->value.custom.data;
+  assert(dataset);
+
+  status = checkAndExtendDataset(current,dataset,iStart,iSize);
+  if(status == 0){
+    NXReportError("Out of memory extending dataset");
+    return NX_ERROR;
+  }
+
+  slabData = makeSlabData(dataset, data, iSize);
+  if(slabData == NULL){
+    NXReportError("Failed to allocate slab data");
+    return NX_ERROR;
+  }
+  
+
+  putSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
+  free(slabData->dim);
+  free(slabData);
+  
+  return NX_OK;
+}
+/*--------------------------------------------------------------------
+  This goes by recursion
+----------------------------------------------------------------------*/
+static void getSlabData(pNXDS dataset, pNXDS slabData, int dim,
+			const int64_t start[], 
+			int64_t sourcePos[],int64_t targetPos[]){
+  int64_t i, rank, length;
+
+  rank = getNXDatasetRank(slabData);
+  length = getNXDatasetDim(slabData,dim);
+  if(dim != rank-1){
+    for(i = 0; i < length; i++){
+      sourcePos[dim] = start[dim] +i;
+      targetPos[dim] = i;
+      getSlabData(dataset,slabData, dim+1,start,
+		  sourcePos,targetPos);
+    }
+  } else {
+    for(i = 0; i < length; i++){
+      sourcePos[dim] = start[dim] +i;
+      targetPos[dim] = i;
+      putNXDatasetValue(slabData,targetPos,
+			getNXDatasetValue(dataset,sourcePos));
+    }
+  }
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXgetslab64 (NXhandle fid, void *data, 
+				   const int64_t iStart[], const int64_t iSize[]){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *userData = NULL;
+  mxml_node_t *current = NULL;
+  pNXDS dataset, slabData;
+  int64_t sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No dataset open");
+    return NX_ERROR;
+  }
+  
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  userData = findData(current);
+  assert(userData != NULL);
+  if(userData->type == MXML_OPAQUE){
+    NXReportError("This API does not support slabs on text data");
+    return NX_ERROR;
+  }
+  dataset = (pNXDS)userData->value.custom.data;
+  assert(dataset);
+  slabData = makeSlabData(dataset, data, iSize);
+  if(slabData == NULL){
+    NXReportError("Failed to allocate slab data");
+    return NX_ERROR;
+  }
+  getSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
+  free(slabData->dim);
+  free(slabData);
+  
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static NXstatus  NXXsetnumberformat(NXhandle fid,
+						 int type, char *format){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  mxml_node_t *userData = NULL;
+  pNXDS dataset;
+  
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    current = xmlHandle->stack[xmlHandle->stackPointer].current;
+    userData = findData(current);
+    assert(userData != NULL);
+    if(userData->type == MXML_OPAQUE){
+      return NX_OK;
+    }
+    dataset = (pNXDS)userData->value.custom.data;
+    assert(dataset);
+    if(dataset->format != NULL){
+      free(dataset->format);
+    }
+    dataset->format = strdup(format);
+  } else {
+    setNumberFormat(type, format);
+  }
+  return NX_OK;
+}
+/*============================ Attributes ============================*/
+static char *formatAttributeData(const void *data, int datalen, int iType){
+  int intData = 0;
+  long iValue = -99999;
+  double dValue = -1e38;
+  char type[20];
+  char *number;
+
+
+  if(iType == NX_CHAR){
+/* data may not be NULL terminated */
+    number = (char*)malloc((datalen+1) * sizeof(char));
+    memcpy(number, data, datalen * sizeof(char));
+    number[datalen] = '\0';
+    return number;
+  }
+
+  number = (char *)malloc(132*sizeof(char));
+  if(!number){
+    NXReportError("Failed to allocate attribute number buffer");
+    return NULL;
+  }
+  
+  if(datalen > 1){
+    return NULL;
+  }
+  type[0] = '\0';
+  switch(iType){
+  case NX_INT32:
+    iValue = ((int *)data)[0];
+    intData = 1;
+    strcpy(type,"NX_INT32:");
+    break;
+  case NX_UINT32:
+    iValue = ((unsigned int *)data)[0];
+    intData = 1;
+    strcpy(type,"NX_UINT32:");
+    break;
+  case NX_INT16:
+    iValue = ((short *)data)[0];
+    intData = 1;
+    strcpy(type,"NX_INT16:");
+    break;
+  case NX_UINT16:
+    iValue = ((unsigned short *)data)[0];
+    intData = 1;
+    strcpy(type,"NX_UINT16:");
+    break;
+  case NX_INT8:
+    iValue = (int)((char *)data)[0];
+    intData = 1;
+    strcpy(type,"NX_INT8:");
+    break;
+  case NX_UINT8:
+    intData = 1;
+    iValue = (int)((unsigned char *)data)[0];
+    strcpy(type,"NX_UINT8:");
+    break;
+  case NX_FLOAT32:
+    dValue = ((float *)data)[0];
+    strcpy(type,"NX_FLOAT32:");
+    intData = 0;
+    break;
+  case NX_FLOAT64:
+    dValue = ((double *)data)[0];
+    strcpy(type,"NX_FLOAT64:");
+    intData = 0;
+    break;
+  }
+  if(intData){
+    snprintf(number,79,"%s%ld",type,iValue);
+  } else {
+    snprintf(number,79,"%s%f",type,dValue);
+  }
+  return number;
+}
+/*---------------------------------------------------------------------*/
+NXstatus  NXXputattr (NXhandle fid, CONSTCHAR *name, const void *data, 
+				   int datalen, int iType){
+  char buffer[256];
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  char *numberData = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+  if (!validNXName(name, 1))
+  {
+    sprintf(buffer, "ERROR: invalid characters in attribute name \"%s\"", name);
+    NXReportError(buffer);
+    return NX_ERROR;
+  }
+
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    if(strcmp(name,TYPENAME) == 0){
+      NXReportError("type is a reserved attribute name, rejected");
+      return  NX_ERROR;
+    }
+  }
+
+  numberData = formatAttributeData(data,datalen,iType);
+  if(numberData == NULL){
+    NXReportError("This API does not support non number arrays");
+    return NX_ERROR;
+  } else {
+    mxmlElementSetAttr(current,name,numberData);
+    free(numberData);
+  }
+  return NX_OK;
+}
+/*--------------------------------------------------------------------------*/
+NXstatus  NXXgetattr (NXhandle fid, char *name, 
+				   void *data, int* datalen, int* iType){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  const char *attribute = NULL;
+  char error[1024];
+  const char *attData = NULL;
+  int nx_type;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+  attribute = mxmlElementGetAttr(current,name);
+  if(!attribute){
+    snprintf(error,1023,"Attribute %s not found", name);
+    NXReportError(error);
+    return NX_ERROR;
+  }
+  nx_type = translateTypeCode((char *)attribute, ":");
+  if(nx_type < 0) {
+    /*
+      no type code == text attribute
+    */
+    nx_type = NX_CHAR;
+  } else {
+    /*
+      We need to find the number after the type code. However, there is
+      the complication of the datatype type attribute ...
+    */
+    if(strcmp(name,TYPENAME) == 0){
+      nx_type = NX_CHAR;
+    } else {
+      attData = strchr(attribute,(int)':');
+      if(attData == NULL){
+        snprintf(error,1023,"ERROR: bad attribute string, : missing for attribute \"%s\"", name);
+	NXReportError(error);
+	return NX_ERROR;
+      }
+      attData++;
+    }
+  }
+  *iType = nx_type;
+  switch(nx_type){
+  case NX_CHAR:
+    /* enforce NULL termination regardless of length of datalen */
+    strncpy((char *)data, attribute, *datalen-1);
+    ((char*)data)[*datalen-1] = '\0';
+    /* *datalen = strlen(attribute); */
+    *datalen = strlen((char*)data);
+    *iType = NX_CHAR;
+    break;
+  case NX_INT32:
+    ((int *)data)[0] = atoi(attData);
+    *datalen = 1;
+    break;
+  case NX_UINT32:
+    ((unsigned int *)data)[0] = atoi(attData);
+    *datalen = 1;
+    break;
+  case NX_INT16:
+    ((short *)data)[0] = atoi(attData);
+    *datalen = 1;
+    break;
+  case NX_UINT16:
+    ((unsigned short *)data)[0] = atoi(attData);
+    *datalen = 1;
+    break;
+  case NX_INT8:
+    ((char *)data)[0] = atoi(attData);
+    *datalen = 1;
+    break;
+  case NX_UINT8:
+    ((unsigned char *)data)[0] = atoi(attData);
+    *datalen = 1;
+    break;
+  case NX_FLOAT32:
+    ((float *)data)[0] = atof(attData);
+    *datalen = 1;
+    break;
+  case NX_FLOAT64:
+    ((double *)data)[0] = atof(attData);
+    *datalen = 1;
+    break;
+  }
+
+  return NX_OK;
+}
+
+/* find the next node, ignoring Idata */
+static mxml_node_t* find_node(mxml_node_t* node, int next)
+{
+  int done = 0;
+  mxml_node_t* parent_next = NULL; /* parent to use if we are in an Idims  search */
+   if (node == NULL)
+   {
+	return NULL;
+   }
+   if ( (node->parent != NULL)  && !strcmp(node->parent->value.element.name, DIMS_NODE_NAME) )
+   {
+	parent_next = node->parent->next;
+   }
+   else
+   {
+	parent_next = NULL;
+   }
+   if (next)
+   {
+       if (node->next != NULL)
+       {
+	    node = node->next;
+       }
+       else
+       {
+	    node = parent_next;
+       }
+   }
+   while(node != NULL && !done)
+   {
+     if ( (node->parent != NULL)  && !strcmp(node->parent->value.element.name, DIMS_NODE_NAME) )
+     {
+	parent_next = node->parent->next;
+     }
+     else
+     {
+        parent_next = NULL;
+     }
+     if ( (node->type != MXML_ELEMENT) || !strcmp(node->value.element.name, DATA_NODE_NAME) )
+     {
+	if (node->next != NULL)
+	{
+	    node = node->next;
+	}
+	else
+	{
+	    node = parent_next;
+	}
+	continue;
+     }
+     if (!strcmp(node->value.element.name, DIMS_NODE_NAME))
+     {
+	node = node->child;
+	continue;
+     }
+     done = 1;
+  }
+  return node;
+}
+
+/*====================== search functions =================================*/
+NXstatus  NXXgetnextentry (NXhandle fid,NXname name, 
+					NXname nxclass, int *datatype){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *next = NULL, *userData, *node = NULL;
+  int stackPtr;
+  const char *target = NULL, *attname = NULL;
+  pNXDS dataset;
+  char pBueffel[256];
+  const char *linkName = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    /*
+      be nice to user: silently fix this problem
+    */
+    NXXclosedata(fid);
+  }
+
+  stackPtr = xmlHandle->stackPointer;
+  if(xmlHandle->stack[stackPtr].currentChild == NULL){
+    /*
+      initialization of search
+    */
+      node = find_node(xmlHandle->stack[stackPtr].current->child, 0);
+  } else {
+    /*
+      proceed
+    */
+    node = find_node(xmlHandle->stack[stackPtr].currentChild, 1);
+  }
+  xmlHandle->stack[stackPtr].currentChild = node;
+  next = node;
+  if(next == NULL){
+    return NX_EOD;
+  }
+  if(strcmp(next->value.element.name,"NAPIlink") == 0){
+    target = mxmlElementGetAttr(next,"target");
+    linkName = mxmlElementGetAttr(next,"name");
+    if(target == NULL){
+      NXReportError("Corrupted file, NAPIlink without target");
+      return NX_ERROR;
+    }
+    next = getLinkTarget(xmlHandle,target);
+    if(next == NULL){
+      NXReportError("Corrupted file, broken link");
+      return NX_ERROR;
+    }
+  }
+
+  if(isDataNode(next)){
+    strcpy(name,next->value.element.name);
+    strcpy(nxclass,"SDS");
+    userData = findData(next);
+    if(userData == NULL){
+	snprintf(pBueffel,255,"Corrupted file, userData for %s not found",
+		 name);
+      NXReportError(pBueffel);
+      return NX_ERROR;
+    }
+    if(userData->type == MXML_OPAQUE){
+      *datatype = NX_CHAR;
+    } else {
+      dataset = (pNXDS)userData->value.custom.data;
+      assert(dataset);
+      *datatype = getNXDatasetType(dataset);
+    }
+  } else {
+    strcpy(nxclass,next->value.element.name);
+    attname = mxmlElementGetAttr(next,"name");
+    strcpy(name,attname);
+  }
+  /*
+    this is for named links
+  */
+  if(linkName != NULL){
+    strcpy(name,linkName);
+  }
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+extern  NXstatus NXXinitgroupdir(NXhandle fid){
+  pXMLNexus xmlHandle = NULL;
+  int stackPtr;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("Cannot search datasets");
+    return NX_ERROR;
+  }
+
+  stackPtr = xmlHandle->stackPointer;
+  xmlHandle->stack[stackPtr].currentChild = NULL;
+  return NX_OK;
+}
+/*-------------------------------------------------------------------------*/
+NXstatus  NXXgetnextattr (NXhandle fid, NXname pName,
+					  int *iLength, int *iType){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  int stackPtr, currentAtt, nx_type;
+  char *attVal; 
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  stackPtr = xmlHandle->stackPointer;
+
+  current = xmlHandle->stack[stackPtr].current;
+  currentAtt = xmlHandle->stack[stackPtr].currentAttribute;
+  if(currentAtt >= 
+     current->value.element.num_attrs ){
+    xmlHandle->stack[stackPtr].currentAttribute = 0;
+    return NX_EOD;
+  }
+
+  /*
+    hide group name attribute
+  */
+  if(strcmp(current->value.element.attrs[currentAtt].name,"name") == 0
+     && !isDataNode(current) ){
+    xmlHandle->stack[stackPtr].currentAttribute++;
+    return NXXgetnextattr(fid,pName,iLength,iType);
+  }
+
+  /*
+    hide type attribute
+  */
+  if(strcmp(current->value.element.attrs[currentAtt].name,TYPENAME) == 0
+     && isDataNode(current)){
+    xmlHandle->stack[stackPtr].currentAttribute++;
+    return NXXgetnextattr(fid,pName,iLength,iType);
+  }
+
+  strcpy(pName,current->value.element.attrs[currentAtt].name);
+  attVal = current->value.element.attrs[currentAtt].value;
+  nx_type = translateTypeCode((char *)attVal, ":");
+  if(nx_type < 0 || strcmp(pName,TYPENAME) == 0){
+    /*
+      no type == NX_CHAR
+    */
+    *iLength = strlen(attVal);
+    *iType = NX_CHAR;
+  } else {
+    *iLength = 1;
+    *iType = nx_type;
+  }
+
+  xmlHandle->stack[stackPtr].currentAttribute++;
+  return NX_OK;
+}
+/*-------------------------------------------------------------------------*/
+extern  NXstatus  NXXinitattrdir(NXhandle fid){
+  pXMLNexus xmlHandle = NULL;
+  int stackPtr;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  stackPtr = xmlHandle->stackPointer;
+  xmlHandle->stack[stackPtr].currentAttribute = 0;
+  return NX_OK;
+}
+/*-------------------------------------------------------------------------*/
+NXstatus  NXXgetgroupinfo (NXhandle fid, int *iN, 
+					NXname pName, NXname pClass){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *node = NULL, *child = NULL;
+  mxml_node_t *current = NULL;
+  const char *nameAtt = NULL;
+  int childCount;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No group open");
+    return NX_ERROR;
+  } 
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+  nameAtt = mxmlElementGetAttr(current,"name");
+  if(nameAtt !=  NULL){
+    strcpy(pName,nameAtt);
+  }
+  strcpy(pClass,current->value.element.name);
+
+/* count all child nodes, but need to ignore DATA_NODE_NAME and
+ * descend into DIMS_NODE_NAME 
+ */
+  childCount = 0;
+  node = current->child;
+  while(node != NULL)
+  {
+	if (!strcmp(node->value.element.name, DATA_NODE_NAME))
+	{
+	    ;	/* names also exist in DIMS_NODE_NAME so do nothing here */
+	}
+	else if (!strcmp(node->value.element.name, DIMS_NODE_NAME))
+	{
+	    child = node->child;
+	    while(child != NULL)
+	    {
+		/* not sure why this check is needed, but you double count otherwise */
+		if (child->type == MXML_ELEMENT) 
+		{
+		    childCount++;
+		}
+		child = child->next;
+	    }
+	}
+	else
+	{
+    	    childCount++;
+	}
+	node = node->next;
+  }
+  *iN = childCount;
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXgetattrinfo (NXhandle fid, int *iN){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  int stackPtr, skip;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  stackPtr = xmlHandle->stackPointer;
+
+  current = xmlHandle->stack[stackPtr].current;
+
+  /*
+    hide type and group name attributes
+  */
+  skip=0;
+  if(isDataNode(current)) {
+    /* data nodes may have type */
+    if(mxmlElementGetAttr(current,TYPENAME) != NULL) skip=1;
+  } else {
+    /* group nodes (except root) have name */
+    if(mxmlElementGetAttr(current,"name") != NULL) skip=1;
+  }
+  *iN = current->value.element.num_attrs - skip;
+  return NX_OK;
+}
+/*================= Linking functions =================================*/
+static int countPathChars(mxml_node_t *path[], int stackPtr){
+  int count = 1;
+  const char *name = NULL;
+
+  while(stackPtr >= 0) {
+    if(isDataNode(path[stackPtr])){
+      count += strlen(path[stackPtr]->value.element.name);
+    } else {
+      name = mxmlElementGetAttr(path[stackPtr],"name");
+      if(name != NULL){
+	count += strlen(name);
+      }
+    }
+    stackPtr--;
+    count += 1;
+  }
+  return count;
+}
+/*-------------------------------------------------------------------*/
+static char *buildPathString(mxml_node_t *path[], int stackPtr){
+  int count = 0;
+  const char *name = NULL;
+  char *pathString = NULL;
+
+  count = countPathChars(path,stackPtr);
+  pathString = (char *)malloc((count+10)*sizeof(char));
+  if(pathString == NULL){
+    return NULL;
+  }
+  memset(pathString,0,(count+10)*sizeof(char));
+
+  while(stackPtr >= 0) {
+    if(isDataNode(path[stackPtr])){
+      strcat(pathString,"/");
+      strcat(pathString,path[stackPtr]->value.element.name);
+    } else {
+      name = mxmlElementGetAttr(path[stackPtr],"name");
+      if(name != NULL){
+	strcat(pathString,"/");
+	strcat(pathString,name);
+      }
+    }
+    stackPtr--;
+  }
+  return pathString;
+}
+/*--------------------------------------------------------------------*/
+static char *findLinkPath(mxml_node_t *node){
+  mxml_node_t **path = NULL;
+  int stackPtr;
+  mxml_node_t *current = NULL;
+  char *result = NULL;
+
+  path = (mxml_node_t **)malloc(NXMAXSTACK*sizeof(mxml_node_t *));
+  if(path == NULL){
+    NXReportError("ERROR: out of memory following link path");
+    return NULL;
+  }
+  memset(path,0,NXMAXSTACK*sizeof(mxml_node_t *));
+
+  /*
+    first path:  walk up the tree untill NXroot is found
+  */
+  current = node;
+  stackPtr = 0;
+  while(current != NULL && 
+	strcmp(current->value.element.name,"NXroot") != 0){
+    path[stackPtr] = current;
+    stackPtr++;
+    current = current->parent;
+  }
+  stackPtr--;
+
+  /*
+    path now contains the nodes to the root node in reverse order.
+    From this build the path string
+  */
+  result = buildPathString(path,stackPtr);
+  free(path);
+  return result;
+}
+/*--------------------------------------------------------------------*/
+NXstatus  NXXgetdataID (NXhandle fid, NXlink* sRes){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  char *linkPath = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    return NX_ERROR;
+  } 
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  
+  linkPath = findLinkPath(current);
+  if(!linkPath){
+    NXReportError("Failed to allocate link path string");
+    return NX_ERROR;
+  }
+  strncpy(sRes->targetPath,linkPath,1023);
+  free(linkPath);
+  return NX_OK;
+}
+/*--------------------------------------------------------------------*/
+NXstatus  NXXgetgroupID (NXhandle fid, NXlink* sRes){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL;
+  char *linkPath = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No group open");
+    return NX_ERROR;
+  } 
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+  if(xmlHandle->stackPointer == 0){
+    return NX_ERROR;
+  }
+
+  linkPath = findLinkPath(current);
+  if(!linkPath){
+    NXReportError("Failed to allocate link path string");
+    return NX_ERROR;
+  }
+  strncpy(sRes->targetPath,linkPath,1023);
+  free(linkPath);
+  return NX_OK;
+}
+
+/*-----------------------------------------------------------------------*/
+  NXstatus  NXXprintlink (NXhandle fid, NXlink* sLink)
+  {
+    pXMLNexus xmlHandle = NULL;
+    xmlHandle = (pXMLNexus)fid;
+    assert(xmlHandle);
+
+    printf("XML link: target=\"%s\"\n", sLink->targetPath);
+    return NX_OK;
+  }
+  
+/*-----------------------------------------------------------------------*/
+NXstatus  NXXmakelink (NXhandle fid, NXlink* sLink){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL, *linkNode = NULL;
+  mxml_node_t *linkedNode = NULL;
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No group to link to open");
+    return NX_ERROR;
+  } 
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  linkNode = mxmlNewElement(current,"NAPIlink");
+  if(!linkNode){
+    NXReportError("Failed to allocate new link element");
+    return NX_ERROR;
+  }
+  mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
+  linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
+  if(linkedNode != NULL){
+    mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
+  }
+  return NX_OK;
+}
+  
+/*-----------------------------------------------------------------------*/
+NXstatus  NXXmakenamedlink (NXhandle fid, CONSTCHAR *name, NXlink* sLink){
+  pXMLNexus xmlHandle = NULL;
+  mxml_node_t *current = NULL, *linkNode = NULL;
+  mxml_node_t *linkedNode = NULL;
+  char buffer[256];
+
+  xmlHandle = (pXMLNexus)fid;
+  assert(xmlHandle);
+  if (!validNXName(name, 0))
+  {
+    sprintf(buffer, "ERROR: invalid characters in link name \"%s\"", name);
+    NXReportError(buffer);
+    return NX_ERROR;
+  }
+
+  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+    NXReportError("No group to link to open");
+    return NX_ERROR;
+  } 
+  current = xmlHandle->stack[xmlHandle->stackPointer].current;
+  linkNode = mxmlNewElement(current,"NAPIlink");
+  if(!linkNode){
+    NXReportError("Failed to allocate new link element");
+    return NX_ERROR;
+  }
+  mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
+  mxmlElementSetAttr(linkNode,"name",name);
+  linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
+  if(linkedNode != NULL){
+    mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
+  }
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus  NXXsameID (NXhandle fileid, NXlink* pFirstID, 
+				  NXlink* pSecondID){
+  if(strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0) {
+    return NX_OK;
+  } else {
+    return NX_ERROR;
+  }
+}
+/*--------------------------------------------------------------------*/
+int  NXXcompress(NXhandle fid, int comp){
+  /* that will throw an exception in the Java API, errors have to be fatal */
+  /* NXReportError("NXcompress is deprecated, IGNORED"); */
+  return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+void NXXassignFunctions(pNexusFunction fHandle){
+      fHandle->nxclose=NXXclose;
+	  fHandle->nxreopen=NULL;
+      fHandle->nxflush=NXXflush;
+      fHandle->nxmakegroup=NXXmakegroup;
+      fHandle->nxopengroup=NXXopengroup;
+      fHandle->nxclosegroup=NXXclosegroup;
+      fHandle->nxmakedata64=NXXmakedata64;
+      fHandle->nxcompmakedata64=NXXcompmakedata64;
+      fHandle->nxcompress=NXXcompress;
+      fHandle->nxopendata=NXXopendata;
+      fHandle->nxclosedata=NXXclosedata;
+      fHandle->nxputdata=NXXputdata;
+      fHandle->nxputattr=NXXputattr;
+      fHandle->nxputslab64=NXXputslab64;    
+      fHandle->nxgetdataID=NXXgetdataID;
+      fHandle->nxmakelink=NXXmakelink;
+      fHandle->nxmakenamedlink=NXXmakenamedlink;
+      fHandle->nxgetdata=NXXgetdata;
+      fHandle->nxgetinfo64=NXXgetinfo64;
+      fHandle->nxgetnextentry=NXXgetnextentry;
+      fHandle->nxgetslab64=NXXgetslab64;
+      fHandle->nxgetnextattr=NXXgetnextattr;
+      fHandle->nxgetattr=NXXgetattr;
+      fHandle->nxgetattrinfo=NXXgetattrinfo;
+      fHandle->nxgetgroupID=NXXgetgroupID;
+      fHandle->nxgetgroupinfo=NXXgetgroupinfo;
+      fHandle->nxsameID=NXXsameID;
+      fHandle->nxinitgroupdir=NXXinitgroupdir;
+      fHandle->nxinitattrdir=NXXinitattrdir;
+      fHandle->nxsetnumberformat=NXXsetnumberformat;
+      fHandle->nxprintlink=NXXprintlink;
+      fHandle->nxnativeexternallink=NULL;
+}
+
+
+
+#endif /*NXXML*/
diff --git a/src/stptok.c b/src/stptok.c
new file mode 100755
index 0000000..6074089
--- /dev/null
+++ b/src/stptok.c
@@ -0,0 +1,66 @@
+/*
+**  stptok() -- public domain by Ray Gardner, modified by Bob Stout
+**
+**   You pass this function a string to parse, a buffer to receive the
+**   "token" that gets scanned, the length of the buffer, and a string of
+**   "break" characters that stop the scan.  It will copy the string into
+**   the buffer up to any of the break characters, or until the buffer is
+**   full, and will always leave the buffer null-terminated.  It will
+**   return a pointer to the first non-breaking character after the one
+**   that stopped the scan.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include "nx_stptok.h"
+
+char *stptok(const char *s, char *tok, size_t toklen, char *brk)
+{
+      char *lim, *b;
+
+      if (!*s)
+            return NULL;
+
+      lim = tok + toklen - 1;
+      while ( *s && tok < lim )
+      {
+            for ( b = brk; *b; b++ )
+            {
+                  if ( *s == *b )
+                  {
+                        *tok = 0;
+                        return (char *)(s+1);
+                  }
+            }
+            *tok++ = *s++;
+      }
+      *tok = 0;
+      return (char *)s;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ static char *SkipSpace(char *pText)
+ {
+   char *pRes;
+   
+   pRes = pText;
+   while(*pRes)
+   {
+     if( (*pRes != ' ') && (*pRes != '\t') && (*pRes != '\r') )
+     {
+       return pRes;
+     }
+     pRes++;
+   }
+   return NULL;
+ }
+*/ 
+
+
+
+
+
+
+
+
+
diff --git a/svn2cl_nexus_authors.xml b/svn2cl_nexus_authors.xml
new file mode 100644
index 0000000..a878d8f
--- /dev/null
+++ b/svn2cl_nexus_authors.xml
@@ -0,0 +1,69 @@
+<?xml version = "1.0" encoding="utf-8"?>
+<authors>
+  <author uid="faa59">
+    Freddie Akeroyd <freddie.akeroyd at stfc.ac.uk>
+  </author>
+  <author uid="faa">
+    Freddie Akeroyd <freddie.akeroyd at stfc.ac.uk>
+  </author>
+  <author uid="Freddie Akeroyd">
+    Freddie Akeroyd <freddie.akeroyd at stfc.ac.uk>
+  </author>
+  <author uid="pfp">
+    Peter Peterson <petersonpf at ornl.gov>
+  </author>
+  <author uid="Peter Peterson">
+    Peter Peterson <petersonpf at ornl.gov>
+  </author>
+  <author uid="mk">
+    Mark Koennecke <Mark.Koennecke at psi.ch>
+  </author>
+  <author uid="Mark Koennecke">
+    Mark Koennecke <Mark.Koennecke at psi.ch>
+  </author>
+  <author uid="rio">
+    Ray Osborn <ROsborn at anl.gov>
+  </author>
+  <author uid="Ray Osborn">
+    Ray Osborn <ROsborn at anl.gov>
+  </author>
+  <author uid="jk">
+    Jens Krueger <jens.krueger at frm2.tum.de>
+  </author>
+  <author uid="Jens Krueger">
+    Jens Krueger <jens.krueger at frm2.tum.de>
+  </author>
+  <author uid="ncm">
+    Nick Maliszewskyj <nickm at nist.gov>
+  </author>
+  <author uid="Nick Maliszewskyj">
+    Nick Maliszewskyj <nickm at nist.gov>
+  </author>
+  <author uid="hg">
+    Hartmut Gilde <Hartmut.Gilde at frm2.tum.de>
+  </author>
+  <author uid="Hartmut Gilde">
+    Hartmut Gilde <Hartmut.Gilde at frm2.tum.de>
+  </author>
+  <author uid="uf">
+    Uwe Filges <Uwe.Filges at psi.ch>
+  </author>
+  <author uid="jcb">
+    Jean-Christophe Bilheux <bilheuxjm at ornl.gov>
+  </author>
+  <author uid="ag">
+    Andy Gotz <Andy.Gotz at esrf.fr>
+  </author>
+  <author uid="jph">
+    John Hammonds <jphammonds at anl.gov>
+  </author>
+  <author uid="nexus">
+    NeXus Developers <nexus-developers at nexusformat.org>
+  </author>
+  <author uid="Tobias Richter">
+    Tobias Richter <tobias.richter at diamond.ac.uk>
+  </author>
+  <author uid="Stuart Campbell">
+    Stuart Campbell <campbellsi at ornl.gov>
+  </author>
+</authors>
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..dab74c2
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,37 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+SET (NXEXAMPLE_FILES napif4_test.f  napif5_test.f  napif_test.f  napi_test.c  napi_test_cpp.cxx  NXtest.f90)
+
+INSTALL (FILES ${NXEXAMPLE_FILES} DESTINATION ${NXEXAMPLEDIR} COMPONENT Examples)
+
+add_executable(napi_test_hdf5 napi_test.c)
+target_link_libraries(napi_test_hdf5 NeXus_Shared_Library)
+
+add_test(napi_test_hdf5 ${EXECUTABLE_OUTPUT_PATH}/napi_test_hdf5)
+#set_property(TEST napi_test_hdf5 PROPERTY PASS_REGULAR_EXPRESSION kkk)
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..9e866e5
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,262 @@
+## Process this file with automake to produce Makefile.in
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id$
+#  
+#  Makefile for generating test programs
+#
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#====================================================================
+
+# so   "make test"   is the same as   "make check"
+test: check
+
+LIBNEXUS=$(top_builddir)/src/libNeXus.la
+LIBNEXUS77=$(top_builddir)/bindings/f77/libNeXus77.la
+LIBNEXUS90=$(top_builddir)/bindings/f90/libNeXus90.la
+LIBNEXUSCPP=$(top_builddir)/bindings/cpp/libNeXusCPP.la
+
+AM_CPPFLAGS=-I. -I$(top_srcdir)/include -I$(top_srcdir)/bindings/cpp
+AM_FFLAGS=-I$(top_srcdir)/bindings/f77
+AM_FCFLAGS=-I$(top_builddir)/bindings/f90
+CLEANFILES=NXtest.nx4 NXtest.nx5 NXtest.nxs NXtest.xml NXtest-table.xml \
+	leak_test.nxs leak_test1.nxs leak_test2_*.nxs \
+	nxtranslate nxsummary nxconvert nxvalidate nxdir nxbrowse \
+	NXtest.h4 NXtest.h5 test_unlimited.*
+
+
+## testdir=$(prefix)/nexus/test
+
+HDF4_TARGETS = napi_test-hdf4 napi_test-hdf4-static napi_test_cpp-hdf4
+
+HDF5_TARGETS = napi_test-hdf5 napi_test-hdf5-static napi_test_cpp-hdf5
+
+XML_TARGETS = napi_test-xml napi_test-xml-static \
+		napi_test-xml-table-static \
+		napi_test_cpp-xml napi_test_cpp-xml-table
+
+F77_TARGETS = napif_test-hdf4 napif_test-hdf5
+
+F90_TARGETS = NXtest
+
+if HAVE_CPP
+CPP_TARGETS = leak_test2 leak_test3
+endif
+
+EXTRA_DIST	= testsuite.at $(TESTSUITE_AT) testsuite package.m4 \
+			NXtest.f90 napif_test.f README.tests \
+			napi_test.c napif4_test.f napif5_test.f \
+			setup_test $(srcdir)/data/dmc* \
+			nxbrowse.txt napi_test_cpp.cxx
+
+TESTSUITE	= $(srcdir)/testsuite
+
+TESTSUITE_AT	= ## dbase.at devices.at starter.at
+
+AUTOTEST	= $(AUTOM4TE) --language=autotest
+
+check_PROGRAMS = run_test skip_test $(HDF4_TARGETS) $(HDF5_TARGETS) $(F77_TARGETS) $(F90_TARGETS) $(XML_TARGETS) $(CPP_TARGETS) leak_test1 test_nxunlimited
+
+#nxtestdir=$(NXTESTDIR)
+#nxtest_PROGRAMS = $(HDF4_TARGETS) $(HDF5_TARGETS) $(F77_TARGETS) $(F90_TARGETS) $(XML_TARGETS) leak_test1 leak_test2 leak_test3
+#nxtest_DATA = README.tests
+
+nxexampledir=$(NXEXAMPLEDIR)
+nxexample_DATA = napi_test.c napif4_test.f napif5_test.f napif_test.f \
+	NXtest.f90 napi_test_cpp.cxx
+
+nxsummary:
+	rm -f $@
+	if test -r ../applications/NXsummary/$@$(EXEEXT); then \
+	    ln -s ../applications/NXsummary/$@$(EXEEXT) $@; \
+	fi
+
+nxconvert:
+	rm -f $@
+	ln -s ../applications/NXconvert/$@$(EXEEXT) $@
+
+nxvalidate:
+	rm -f $@
+	ln -s ../applications/NXvalidate/$@ $@
+
+nxbrowse:
+	rm -f $@
+	ln -s ../applications/NXbrowse/$@$(EXEEXT) $@
+
+nxdir:
+	rm -f $@
+	ln -s ../applications/NXdir/$@$(EXEEXT) $@
+
+nxtranslate:
+	rm -f $@
+	if test -r ../applications/NXtranslate/$@$(EXEEXT); then \
+	    ln -s ../applications/NXtranslate/$@$(EXEEXT) $@; \
+	fi
+
+# for running tests via   "make check"
+## check_PROGRAMS = $(test_PROGRAMS)	# what to build
+## TESTS = $(test_PROGRAMS)		# what to run
+
+# this sets the test running environment - in case we
+# have got built with shared HDF libraries we need to set LD_LIBRARY_PATH
+TESTS_ENVIRONMENT=env PYTHON=$(PYTHON) IDL_PATH="@abs_top_srcdir@/bindings/idl:<IDL_DEFAULT>" IDL_DLM_PATH="@abs_top_builddir@/bindings/idl:<IDL_DEFAULT>" LD_LIBRARY_PATH=@abs_top_builddir@/src/.libs:@abs_top_builddir@/bindings/cpp/.libs:@abs_top_builddir@/bindings/idl:$${LD_LIBRARY_PATH}:@EXTRA_LD_LIBRARY_PATH@:/usr/local/lib DYLD_LIBRARY_PATH=@abs_top_builddir@/src/.libs:@abs_top_builddir@/bindings/cpp/.libs:@abs_top_builddir@/bindings/idl:$${DYLD_LIBRARY_PATH}:@EXTRA_LD_LIBRARY_PATH@: [...]
+
+run_test_SOURCES=run_test.c
+run_test_LDFLAGS=-static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+skip_test_SOURCES=skip_test.c
+skip_test_LDFLAGS=-static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+leak_test1_SOURCES=leak_test1.c
+leak_test1_LDADD=$(LIBNEXUS)
+leak_test1_LDFLAGS=-static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+leak_test2_SOURCES=leak_test2.cxx
+leak_test2_LDADD=$(LIBNEXUS)
+leak_test2_LDFLAGS=-static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+leak_test3_SOURCES=leak_test3.cxx
+leak_test3_LDADD=$(LIBNEXUS)
+leak_test3_LDFLAGS=-static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+test_nxunlimited_SOURCES=test_nxunlimited.c
+test_nxunlimited_LDADD=$(LIBNEXUS)
+test_nxunlimited_LDFLAGS=-static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+
+if HAVE_XML
+napi_test_xml_SOURCES = napi_test.c
+napi_test_xml_CPPFLAGS = -I$(top_srcdir)/include @XML_CPPFLAGS@
+napi_test_xml_LDADD = $(LIBNEXUS) @XML_LDFLAGS@
+napi_test_xml_static_SOURCES = napi_test.c
+napi_test_xml_static_CPPFLAGS = -I$(top_srcdir)/include @XML_CPPFLAGS@
+napi_test_xml_static_LDADD = $(LIBNEXUS) @XML_LDFLAGS@
+napi_test_xml_static_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+napi_test_xml_table_static_SOURCES = napi_test.c
+napi_test_xml_table_static_CPPFLAGS = -I$(top_srcdir)/include @XML_CPPFLAGS@
+napi_test_xml_table_static_LDADD = $(LIBNEXUS) @XML_LDFLAGS@
+napi_test_xml_table_static_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+napi_test_cpp_xml_SOURCES = napi_test_cpp.cxx
+napi_test_cpp_xml_LDADD = $(LIBNEXUSCPP)
+napi_test_cpp_xml_table_SOURCES = napi_test_cpp.cxx
+napi_test_cpp_xml_table_LDADD = $(LIBNEXUSCPP)
+else
+napi_test_xml_SOURCES = dummy.c
+napi_test_xml_static_SOURCES = dummy.c
+napi_test_xml_table_static_SOURCES = dummy.c
+napi_test_xml_static_LDFLAGS = $(LDFLAGS)
+napi_test_cpp_xml_SOURCES = dummy.c
+napi_test_cpp_xml_table_SOURCES = dummy.c
+endif
+
+if HAVE_HDF4
+napi_test_hdf4_SOURCES = napi_test.c
+napi_test_hdf4_CPPFLAGS = -I$(top_srcdir)/include @HDF4_CPPFLAGS@
+napi_test_hdf4_LDADD = $(LIBNEXUS) @HDF4_LDFLAGS@
+napi_test_hdf4_static_SOURCES = napi_test.c
+napi_test_hdf4_static_CPPFLAGS = -I$(top_srcdir)/include @HDF4_CPPFLAGS@
+napi_test_hdf4_static_LDADD = $(LIBNEXUS) @HDF4_LDFLAGS@
+napi_test_hdf4_static_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+napi_test_cpp_hdf4_SOURCES = napi_test_cpp.cxx
+napi_test_cpp_hdf4_LDADD = $(LIBNEXUSCPP)
+if HAVE_F77
+napif_test_hdf4_SOURCES = napif4_test.f
+napif_test_hdf4_LDADD = $(LIBNEXUS77) # $(FLIBS)
+napif_test_hdf4_LINK = $(F77LINK)
+napif_test_hdf4_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+else
+napif_test_hdf4_SOURCES = dummy.c
+napif_test_hdf4_LINK = $(LINK)
+endif
+else
+napi_test_hdf4_SOURCES = dummy.c
+napi_test_hdf4_static_SOURCES = dummy.c
+napi_test_hdf4_static_LDFLAGS = $(LDFLAGS)
+napif_test_hdf4_SOURCES = dummy.c
+napif_test_hdf4_LINK = $(LINK)
+napi_test_cpp_hdf4_SOURCES = dummy.c
+endif
+
+if HAVE_HDF5
+napi_test_hdf5_SOURCES = napi_test.c
+napi_test_hdf5_CPPFLAGS = -I$(top_srcdir)/include @HDF5_CPPFLAGS@
+napi_test_hdf5_LDADD = $(LIBNEXUS) @HDF5_LDFLAGS@
+napi_test_hdf5_static_SOURCES = napi_test.c
+napi_test_hdf5_static_CPPFLAGS = -I$(top_srcdir)/include @HDF5_CPPFLAGS@
+napi_test_hdf5_static_LDADD = $(LIBNEXUS) @HDF5_LDFLAGS@
+napi_test_hdf5_static_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+napi_test_cpp_hdf5_SOURCES = napi_test_cpp.cxx
+napi_test_cpp_hdf5_LDADD=$(LIBNEXUSCPP)
+if HAVE_F77
+napif_test_hdf5_SOURCES = napif5_test.f
+napif_test_hdf5_LDADD = $(LIBNEXUS77) # $(FLIBS)
+napif_test_hdf5_LINK = $(F77LINK)
+napif_test_hdf5_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+else
+napif_test_hdf5_SOURCES = dummy.c
+napif_test_hdf5_LINK = $(LINK)
+endif
+else
+napi_test_hdf5_SOURCES = dummy.c
+napi_test_hdf5_static_SOURCES = dummy.c
+napi_test_hdf5_static_LDFLAGS = $(LDFLAGS)
+napif_test_hdf5_SOURCES = dummy.c
+napif_test_hdf5_LINK = $(LINK)
+napi_test_cpp_hdf5_SOURCES = dummy.c
+endif
+
+if HAVE_F90
+NXtest_SOURCES = NXtest.f90
+NXtest_LDADD = $(LIBNEXUS90)
+NXtest_LINK = $(FCLINK)
+NXtest_LDFLAGS = -static $(HDF4_LDFLAGS) $(HDF5_LDFLAGS) $(XML_LDFLAGS) $(LDFLAGS)
+else
+NXtest_SOURCES = dummy.c
+NXtest_LINK = $(LINK)
+endif
+
+include $(top_srcdir)/build_rules.am
+
+$(srcdir)/package.m4:	$(top_srcdir)/configure.ac
+	{\
+		echo '# Signature of the current package.'; \
+		echo 'm4_define([AT_PACKAGE_NAME],      [@PACKAGE_NAME@])'; \
+		echo 'm4_define([AT_PACKAGE_TARNAME],   [@PACKAGE_TARNAME@])'; \
+		echo 'm4_define([AT_PACKAGE_VERSION],   [@PACKAGE_VERSION@])'; \
+		echo 'm4_define([AT_PACKAGE_STRING],    [@PACKAGE_STRING@])'; \
+		echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
+	} > $(srcdir)/package.m4
+
+check-local: atconfig atlocal nxconvert nxvalidate nxsummary nxdir nxbrowse nxtranslate $(TESTSUITE) 
+	$(TESTS_ENVIRONMENT) $(SHELL) $(TESTSUITE)
+
+$(TESTSUITE):	$(srcdir)/testsuite.at $(TESTSUITE_AT) $(srcdir)/package.m4
+	$(AUTOTEST) -I $(srcdir) $@.at -o $@.tmp
+	mv $@.tmp $@
+
+atconfig:	$(top_builddir)/config.status
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+clean-local:
+	-$(SHELL) $(TESTSUITE) --clean
+
+
+DISTCLEANFILES = atconfig
diff --git a/test/NXtest.f90 b/test/NXtest.f90
new file mode 100644
index 0000000..d392b93
--- /dev/null
+++ b/test/NXtest.f90
@@ -0,0 +1,209 @@
+!------------------------------------------------------------------------------
+! NeXus - Neutron & X-ray Common Data Format
+!  
+! Test program for the Fortran 90 API
+!
+! Copyright (C) 1999-2002, Ray Osborn
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Lesser General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+! Lesser General Public License for more details.
+!
+! You should have received a copy of the GNU Lesser General Public
+! License along with this library; if not, write to the Free Software
+! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+!
+!  For further information, see <http://www.nexusformat.org>
+!
+! $Id$
+!------------------------------------------------------------------------------
+
+program NXtest
+
+   use NXmodule
+
+   integer :: NXrank, NXdims(NX_maxrank), NXtype, NXlen, entry_status, attr_status
+   integer(kind=NXi1), dimension(4) :: i1_array = (/1, 2, 3, 4/)
+   integer(kind=NXi2), dimension(4) :: i2_array = (/1000, 2000, 3000, 4000/)
+   integer(kind=NXi4), dimension(4) :: i4_array = (/1000000, 2000000, 3000000, 4000000/)
+   real(kind=NXr4), dimension(4,5) :: r4_array
+   real(kind=NXr8), dimension(4,5) :: r8_array
+   integer(kind=NXi4), dimension(4) :: i4_buffer
+   real(kind=NXr4), dimension(4) :: r4_buffer
+   real(kind=NXr8), dimension(16) :: r8_buffer
+   integer(kind=NXi4), dimension(2000) :: comp_array
+   integer(kind=NXi4) :: i, j
+   real(kind=NXr4) :: r
+   character(len=20) :: char_buffer
+   character(len=NX_maxnamelen) :: name, class
+   type(NXhandle) :: fileid
+   type(NXlink) :: glink, dlink, blink
+
+   r4_array = reshape ((/(i*1.0_NXr4,i=1,20)/),(/4,5/))
+   r8_array = reshape ((/(i*1.0_NXr8,i=1,20)/),(/4,5/))
+! *** create file
+   if (NXopen("NXtest.nxs", NXACC_CREATE5, fileid) /= NX_OK) stop
+   if (NXmakegroup(fileid, "entry", "NXentry") /= NX_OK) stop
+   if (NXopengroup(fileid, "entry", "NXentry") /= NX_OK) stop
+      if (NXmakedata(fileid, "ch_data", NX_CHAR, 1, (/10/)) /= NX_OK) stop
+      if (NXopendata(fileid, "ch_data") /= NX_OK) stop
+         if (NXputdata(fileid, "NeXus data") /= NX_OK) stop
+      if (NXclosedata(fileid) /= NX_OK) stop
+      if (NXmakedata(fileid, "i1_data", NX_INT8, 1, (/4/)) /= NX_OK) stop
+      if (NXopendata(fileid, "i1_data") /= NX_OK) stop
+         if (NXputdata(fileid, i1_array) /= NX_OK) stop
+      if (NXclosedata(fileid) /= NX_OK) stop
+      if (NXmakedata(fileid, "i2_data", NX_INT16, 1, (/4/)) /= NX_OK) stop
+      if (NXopendata(fileid, "i2_data") /= NX_OK) stop
+         if (NXputdata(fileid, i2_array) /= NX_OK) stop
+      if (NXclosedata(fileid) /= NX_OK) stop
+      if (NXmakedata(fileid, "i4_data", NX_INT32, 1, (/4/)) /= NX_OK) stop
+      if (NXopendata(fileid, "i4_data") /= NX_OK) stop
+         if (NXputdata(fileid, i4_array) /= NX_OK) stop
+      if (NXclosedata(fileid) /= NX_OK) stop
+      if (NXmakedata(fileid, "r4_data", NX_FLOAT32, 2, (/4,5/), NX_COMP_LZW, (/4,5/)) /= NX_OK) stop
+      if (NXopendata(fileid, "r4_data") /= NX_OK) stop
+         if (NXputdata(fileid, reshape(r4_array,(/size(r4_array)/))) /= NX_OK) stop
+      if (NXclosedata(fileid) /= NX_OK) stop
+      if (NXmakedata(fileid, "r8_data", NX_FLOAT64, 2, (/4,5/)) /= NX_OK) stop
+      if (NXopendata(fileid, "r8_data") /= NX_OK) stop
+         r8_buffer(1:4) = reshape(r8_array(1:4,5:5),(/4/))
+         if (NXputslab(fileid, r8_buffer, (/1,5/), (/4,1/)) /= NX_OK) stop
+         r8_buffer = reshape(r8_array(1:4,1:4),(/16/))
+         if (NXputslab(fileid, r8_buffer, (/1,1/), (/4,4/)) /= NX_OK) stop
+         if (NXputattr(fileid, "ch_attribute", "NeXus") /= NX_OK) stop
+         if (NXputattr(fileid, "i4_attribute", 42) /= NX_OK) stop
+         if (NXputattr(fileid, "r4_attribute", 3.141593_NXr4) /= NX_OK) stop
+         if (NXgetdataID(fileid, dlink) /= NX_OK) stop
+      if (NXclosedata(fileid) /= NX_OK) stop
+      if (NXmakegroup(fileid, "data", "NXdata") /= NX_OK) stop
+      if (NXopengroup(fileid, "data", "NXdata") /= NX_OK) stop
+         if (NXmakelink(fileid, dlink) /= NX_OK) stop
+         if (NXmakedata(fileid, "comp_data", NX_INT32, 2, (/20,100/)) /= NX_OK) stop
+         if (NXopendata(fileid, "comp_data") /= NX_OK) stop
+            comp_array = (/((j-1,i=1,20),j=1,100)/)
+            if (NXputdata(fileid, comp_array) /= NX_OK) stop
+         if (NXclosedata(fileid) /= NX_OK) stop
+         if (NXflush(fileid) /= NX_OK) stop
+         if (NXmakedata(fileid, "flush_data", NX_INT32, 1, (/NX_UNLIMITED/)) /= NX_OK) stop
+            do i = 1,7
+               if (NXopendata(fileid, "flush_data") /= NX_OK) stop
+                  if (NXputslab(fileid, (/i/), (/i/), (/1/)) /= NX_OK) stop
+                  if (NXflush(fileid) /= NX_OK) stop
+            end do
+      if (NXclosegroup(fileid) /= NX_OK) stop
+      if (NXmakegroup(fileid, "sample", "NXsample") /= NX_OK) stop
+      if (NXopengroup(fileid, "sample", "NXsample") /= NX_OK) stop
+         print 300, "Writing character data"
+         if (NXmakedata(fileid, "ch_data", NX_CHAR, 1, (/12/)) /= NX_OK) stop
+         if (NXopendata(fileid, "ch_data") /= NX_OK) stop
+            if (NXputdata(fileid, "NeXus sample") /= NX_OK) stop
+         if (NXclosedata(fileid) /= NX_OK) stop
+         if (NXgetgroupID(fileid, glink) /= NX_OK) stop
+      if (NXclosegroup(fileid) /= NX_OK) stop
+   if (NXclosegroup(fileid) /= NX_OK) stop
+   if (NXmakegroup(fileid, "link", "NXentry") /= NX_OK) stop
+   if (NXopengroup(fileid, "link", "NXentry") /= NX_OK) stop
+      if (NXmakelink(fileid, glink) /= NX_OK) stop
+   if (NXclosegroup(fileid) /= NX_OK) stop
+   if (NXclose(fileid) /= NX_OK) stop
+! *** read data
+   if (NXopen("NXtest.nxs", NXACC_READ, fileid) /= NX_OK) stop
+   if (NXgetattrinfo(fileid, i) /= NX_OK) stop
+   if (i > 0) print 200, "Number of global attributes: ", i
+   attr_status = NX_OK
+   do while (attr_status == NX_OK)
+      attr_status = NXgetnextattr(fileid, name, NXlen, NXtype)
+      if (attr_status == NX_ERROR) stop
+      if (attr_status == NX_OK) then
+	     if ((name /= "HDF_version") .and. (name /= "HDF5_Version") .and. &
+	         (name /= "file_time")) then
+            select case (NXtype)
+               case (NX_CHAR)
+                  NXlen = len(char_buffer)
+                  if (NXgetattr(fileid, name, char_buffer, NXlen, NXtype) /= NX_OK) stop
+                     print 300, "   "//trim(name)//" = "//trim(char_buffer)
+            end select
+         end if
+      end if
+   end do
+   if (NXopengroup(fileid, "entry", "NXentry") /= NX_OK) stop
+   if (NXgetgroupinfo(fileid, i, name, class) /= NX_OK) stop
+      print '(A,i8,A)', "Group: "//trim(name)//"("//trim(class)//") contains ", i, " items"
+   do
+      entry_status = NXgetnextentry(fileid, name, class, NXtype)
+      if (entry_status == NX_ERROR) then
+         stop
+      else if (entry_status == NX_EOD) then
+         exit
+      else if (trim(class) /= "SDS") then
+         print 300, "   Subgroup: "//trim(name)//"("//trim(class)//")"
+      else if (entry_status == NX_OK) then
+         if (NXopendata(fileid, name) /= NX_OK) stop
+            if (NXgetinfo(fileid, NXrank, NXdims, NXtype) /= NX_OK) stop
+            print 300, "   "//trim(name)//" : ", trim(NXdatatype(NXtype))
+            if (NXtype == NX_CHAR) then
+               if (NXgetdata(fileid, char_buffer) /= NX_OK) stop
+               print 300, "   Values : ", trim(char_buffer)
+            else if (NXtype == NX_INT8 .or. NXtype == NX_INT16 .or. NXtype == NX_INT32) then
+               if (NXgetdata(fileid, i4_buffer) /= NX_OK) stop
+               print 200, "   Values : ", i4_buffer
+            else if (NXtype == NX_FLOAT32 .or. NXtype == NX_FLOAT64) then
+               if (NXgetslab(fileid, r4_buffer, (/1,1/), (/4,1/)) /= NX_OK) stop
+               print 100, "   Values : ", r4_buffer
+               if (NXgetslab(fileid, r4_buffer, (/1,2/), (/4,1/)) /= NX_OK) stop
+               print 100, "          : ", r4_buffer
+               if (NXgetslab(fileid, r4_buffer, (/1,3/), (/4,1/)) /= NX_OK) stop
+               print 100, "          : ", r4_buffer
+               if (NXgetslab(fileid, r4_buffer, (/1,4/), (/4,1/)) /= NX_OK) stop
+               print 100, "          : ", r4_buffer
+               if (NXgetslab(fileid, r4_buffer, (/1,5/), (/4,1/)) /= NX_OK) stop
+               print 100, "          : ", r4_buffer
+            end if
+            do
+               attr_status = NXgetnextattr(fileid, name, NXdims(1), NXtype) 
+               if (attr_status == NX_ERROR) then
+                  stop
+               else if (attr_status == NX_EOD) then
+                  exit
+               else if (attr_status == NX_OK) then
+                  if (NXtype == NX_CHAR) then
+                     if (NXgetattr(fileid, name, char_buffer) /= NX_OK) stop
+                     print 300, "   "//trim(name)//" : ", trim(char_buffer)
+                  else if (NXtype == NX_INT32) then
+                     if (NXgetattr(fileid, name, i) /= NX_OK) stop
+                     print 200, "   "//trim(name)//" : ", i
+                  else if (NXtype == NX_FLOAT32) then
+                     if (NXgetattr(fileid, name, r) /= NX_OK) stop
+                     print 100, "   "//trim(name)//" : ", r
+                  end if
+               end if
+            end do
+         if (NXclosedata(fileid) /= NX_OK) stop
+      end if
+   end do
+   if (NXclosegroup(fileid) /= NX_OK) stop
+   if (NXopengroup(fileid, "link", "NXentry") /= NX_OK) stop
+      if (NXgetgroupID(fileid, glink) /= NX_OK) stop
+   if (NXclosegroup(fileid) /= NX_OK) stop
+   if (NXopengroup(fileid, "link", "NXentry") /= NX_OK) stop
+      if (NXgetgroupID(fileid, blink) /= NX_OK) stop
+      if (NXsameID(fileid, glink, blink)) then
+         print 300, "Link Check OK"
+      else
+         print 300, "Link Check Failed"
+      end if
+   if (NXclosegroup(fileid) /= NX_OK) stop
+   if (NXclose(fileid) /= NX_OK) stop
+
+ 100 format(A,4f12.7)
+ 200 format(A,4i8)
+ 300 format(4A)
+
+end program NXtest
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..40c94d0
--- /dev/null
+++ b/test/README
@@ -0,0 +1,38 @@
+*
+* This file is CVS only - README.tests is installed in /usr/local/nexus/tests
+*
+Both dynamic library versions (e.g. napi_test-hdf4) and 
+static library versions (e.g. napi_test-hdf4-static) of the test
+programs are now build. 
+
+Static Library Version
+----------------------
+
+The static version "napi_test-hdf4-static" is a real self contained
+executable and you can run it either directly or in a debugger with simply
+
+    gdb napi_test-hdf4-static
+
+Dynamic Library Version
+-----------------------
+
+"napi_test-hdf4" is not a real executable, but a shell script that
+invokes the real dynamic executable ".libs/napi_test-hdf4". Though
+you can run ".libs/napi_test-hdf4" directly you should be aware that
+it will then pick up whatever NeXus library is either currently in your 
+LD_* environment variable paths or installed in a system shared library 
+area (such as /usr/local/lib)
+
+To test the NeXus shared library you have just built you must use 
+the shell script "napi_test-hdf4" which will set
+the correct environment before running ".libs/napi_test-hdf4"
+
+If you wish to run the program in a debugger you must use
+
+    libtool --mode=execute gdb napi_test-hdf4
+
+To check what shared libraries the program will load run
+
+    libtool --mode=execute ldd napi_test-hdf4
+
+$Id$
diff --git a/test/README.tests b/test/README.tests
new file mode 100644
index 0000000..0379182
--- /dev/null
+++ b/test/README.tests
@@ -0,0 +1,8 @@
+NeXus test programs and files
+--------------------------------
+
+Test executables are installed to /usr/local/nexus/tests and
+program source code to /usr/local/nexus/examples
+
+--
+$Id$
diff --git a/test/SConscript b/test/SConscript
new file mode 100644
index 0000000..7200b33
--- /dev/null
+++ b/test/SConscript
@@ -0,0 +1,68 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 961 2007-09-04 12:31:49Z Freddie Akeroyd $
+#
+#  Top level scons file for coordinating NeXus build
+#  
+#  Copyright (C) 2008 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org/>
+#
+#====================================================================
+
+import os
+import platform
+import sys
+import re
+import shutil
+from socket import gethostname
+
+import nexus_scons_utils
+
+Import('env')
+myenv = env.Clone()
+myenv.Append(CPPPATH=['#/include','#bindings/cpp'])
+shared_list = env['SHARED_LIST']
+static_list = env['STATIC_LIST']
+libList = env['MYLIBLIST']
+libDirList = env['MYLIBDIRLIST']
+shlibList = env['MYSHLIBLIST']
+shlibDirList = env['MYSHLIBDIRLIST']
+
+myenv_dynamic = myenv.Clone()
+myenv_dynamic.Append(LIBS=shlibList)
+myenv_dynamic.Append(LIBPATH=shlibDirList)
+myenv_dynamic.Append(LIBPATH='#Bin/Shared')
+shared = myenv_dynamic.Program('napi_test_hdf4',['napi_test.c'],PDB='napi_test_hdf4.pdb')
+shared = myenv_dynamic.Program('napi_test_xml5',['napi_test.c'],PDB='napi_test_hdf5.pdb')
+shared = myenv_dynamic.Program('napi_test_xml',['napi_test.c'],PDB='napi_test_xml.pdb')
+shared = myenv_dynamic.Program('napi_test_cpp_xml',['napi_test_cpp.cxx'],PDB='napi_test_cpp_xml.pdb')
+
+myenv_static = myenv.Clone()
+myenv_static.Append(LIBS=libList)
+myenv_static.Append(LIBPATH=libDirList)
+myenv_static.Append(LIBPATH='#Bin/Static')
+#myenv_static.Append(LINKFLAGS=['-static'])
+static = myenv_static.Program('napi_test_hdf4_static',['napi_test.c'],PDB='napi_test_hdf4_static.pdb')
+static = myenv_static.Program('napi_test_xml5_static',['napi_test.c'],PDB='napi_test_hdf5_static.pdb')
+static = myenv_static.Program('napi_test_xml_static',['napi_test.c'],PDB='napi_test_xml_static.pdb')
+static = myenv_static.Program('napi_test_cpp_xml_static',['napi_test_cpp.cxx'],PDB='napi_test_cpp_xml_static.pdb')
+
+retval = { 'shared': shared, 'static' : static }
+Return('retval')
diff --git a/test/atlocal.in b/test/atlocal.in
new file mode 100644
index 0000000..f8ba1d3
--- /dev/null
+++ b/test/atlocal.in
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# $Id$
+#
+# @configure_input@
+#
+SETUP_TEST="sh $abs_srcdir/setup_test $abs_srcdir"
+export SETUP_TEST
+#
+if test ! -z "@H4ROOT@"; then
+    HAVE_HDF4="napi_test-hdf4-static -q"
+else
+    HAVE_HDF4=skip_test
+fi
+export HAVE_HDF4
+#
+if test ! -z "@H5ROOT@"; then
+    HAVE_HDF5="napi_test-hdf5-static -q"
+else
+    HAVE_HDF5=skip_test
+fi
+export HAVE_HDF5
+#
+if test ! -z "@MXMLROOT@"; then
+    HAVE_XML="napi_test-xml-static -q"
+else
+    HAVE_XML=skip_test
+fi
+export HAVE_XML
+#
+if test "@WITH_F77@" = "yes"; then
+    HAVE_F77=run_test
+else
+    HAVE_F77=skip_test
+fi
+export HAVE_F77
+#
+if test "@WITH_F90@" = "yes"; then
+    HAVE_F90=run_test
+else
+    HAVE_F90=skip_test
+fi
+export HAVE_F90
+#
+if test -f nxsummary; then
+    HAVE_NXSUMMARY=run_test
+else
+    HAVE_NXSUMMARY=skip_test
+fi
+export HAVE_NXSUMMARY
+#
+if test -f nxtranslate; then
+    HAVE_NXTRANSLATE=run_test
+else
+    HAVE_NXTRANSLATE=skip_test
+fi
+export HAVE_NXTRANSLATE
+#
+if test ! -z "@WGET@"; then
+    HAVE_WGET=run_test
+else
+    HAVE_WGET=skip_test
+fi
+export HAVE_WGET
+#
+if test ! -z "@XMLLINT@"; then
+    HAVE_XMLLINT=run_test
+else
+    HAVE_XMLLINT=skip_test
+fi
+export HAVE_XMLLINT
+#
+if test ! -z "@PYTHONROOT@"; then
+    HAVE_PYTHON=run_test
+else
+    HAVE_PYTHON=skip_test
+fi
+export HAVE_PYTHON
+#
+if test ! -z "@IDLROOT@"; then
+    HAVE_IDL=run_test
+else
+    HAVE_IDL=skip_test
+fi
+export HAVE_IDL
+#
diff --git a/test/data/dmc01.h5 b/test/data/dmc01.h5
new file mode 100644
index 0000000..f0649bd
Binary files /dev/null and b/test/data/dmc01.h5 differ
diff --git a/test/data/dmc01.hdf b/test/data/dmc01.hdf
new file mode 100644
index 0000000..64247e4
Binary files /dev/null and b/test/data/dmc01.hdf differ
diff --git a/test/data/dmc01.xml b/test/data/dmc01.xml
new file mode 100644
index 0000000..601b128
--- /dev/null
+++ b/test/data/dmc01.xml
@@ -0,0 +1,437 @@
+<?xml version="1.0"?>
+  <NXroot NeXus_version="3.0.0"
+HDF_version="NCSA HDF Version 4.2 Release 0, December 2, 2003"
+file_name="/home/dmc/data/2005/003/dmc2005n003077.hdf"
+file_time="2005-05-27 05:44:13" instrument="DMC" owner="keller"
+owner_telephone_number="UNKNOWN" owner_fax_number="UNKNOWN"
+owner_email="UNKNOWN" owner_address="UNKNOWN">
+    <NXentry name="entry1">
+      <title>Ga0.94Mn0.04Sb_8mm 2.567A T=4</title>
+      <start_time>2005-05-27 05:44:13</start_time>
+      <NXinstrument name="DMC">
+        <name>DMC at SINQ</name>
+        <NXsource name="SINQ">
+          <name>SINQ</name>
+          <type>Continuous flux spallation source</type>
+        </NXsource>
+        <NXcrystal name="Monochromator">
+          <type>Pyrolithic Graphite 002</type>
+          <theta NAPItype="NX_FLOAT32">
+                 22.4300 
+          </theta>
+          <two_theta NAPItype="NX_FLOAT32">
+                 44.8700 
+          </two_theta>
+          <lambda NAPItype="NX_FLOAT32" units="Angstroem">
+                  2.5666 
+          </lambda>
+          <curvature NAPItype="NX_FLOAT32">
+                 14.0000 
+          </curvature>
+          <x_translation NAPItype="NX_FLOAT32">
+                  0.9400 
+          </x_translation>
+          <y_translation NAPItype="NX_FLOAT32">
+                  0.2100 
+          </y_translation>
+          <chi NAPItype="NX_FLOAT32">
+                  0.3560 
+          </chi>
+          <phi NAPItype="NX_FLOAT32">
+                 -0.0020 
+          </phi>
+          <d_spacing NAPItype="NX_FLOAT32" units="Angstroem">
+                  3.3537 
+          </d_spacing>
+        </NXcrystal>
+        <NXpsd name="DMC-BF3-Detector">
+          <Preset NAPItype="NX_INT32">
+              1094713344 
+          </Preset>
+          <CounterMode>monitor</CounterMode>
+          <time NAPItype="NX_FLOAT32">
+                284.5530 
+          </time>
+          <beam_monitor NAPItype="NX_INT32" units="counts">
+                 2368697 
+          </beam_monitor>
+          <Monitor NAPItype="NX_INT32" units="counts">
+                   12000 
+          </Monitor>
+          <proton_monitor NAPItype="NX_INT32" units="counts">
+                33077902 
+          </proton_monitor>
+          <two_theta_start NAPItype="NX_FLOAT32" units="degree">
+                 18.3000 
+          </two_theta_start>
+          <Step NAPItype="NX_FLOAT32" units="degree">
+                  0.2000 
+          </Step>
+          <no_of_steps NAPItype="NX_INT32">
+                     400 
+          </no_of_steps>
+          <two_theta NAPItype="NX_FLOAT32[400]" axis="1" units="degree">
+                 18.3000      18.5000      18.7000      18.9000      19.1000 
+                 19.3000      19.5000      19.7000      19.9000      20.1000 
+                 20.3000      20.5000      20.7000      20.9000      21.1000 
+                 21.3000      21.5000      21.7000      21.9000      22.1000 
+                 22.3000      22.5000      22.7000      22.9000      23.1000 
+                 23.3000      23.5000      23.7000      23.9000      24.1000 
+                 24.3000      24.5000      24.7000      24.9000      25.1000 
+                 25.3000      25.5000      25.7000      25.9000      26.1000 
+                 26.3000      26.5000      26.7000      26.9000      27.1000 
+                 27.3000      27.5000      27.7000      27.9000      28.1000 
+                 28.3000      28.5000      28.7000      28.9000      29.1000 
+                 29.3000      29.5000      29.7000      29.9000      30.1000 
+                 30.3000      30.5000      30.7000      30.9000      31.1000 
+                 31.3000      31.5000      31.7000      31.9000      32.1000 
+                 32.3000      32.5000      32.7000      32.9000      33.1000 
+                 33.3000      33.5000      33.7000      33.9000      34.1000 
+                 34.3000      34.5000      34.7000      34.9000      35.1000 
+                 35.3000      35.5000      35.7000      35.9000      36.1000 
+                 36.3000      36.5000      36.7000      36.9000      37.1000 
+                 37.3000      37.5000      37.7000      37.9000      38.1000 
+                 38.3000      38.5000      38.7000      38.9000      39.1000 
+                 39.3000      39.5000      39.7000      39.9000      40.1000 
+                 40.3000      40.5000      40.7000      40.9000      41.1000 
+                 41.3000      41.5000      41.7000      41.9000      42.1000 
+                 42.3000      42.5000      42.7000      42.9000      43.1000 
+                 43.3000      43.5000      43.7000      43.9000      44.1000 
+                 44.3000      44.5000      44.7000      44.9000      45.1000 
+                 45.3000      45.5000      45.7000      45.9000      46.1000 
+                 46.3000      46.5000      46.7000      46.9000      47.1000 
+                 47.3000      47.5000      47.7000      47.9000      48.1000 
+                 48.3000      48.5000      48.7000      48.9000      49.1000 
+                 49.3000      49.5000      49.7000      49.9000      50.1000 
+                 50.3000      50.5000      50.7000      50.9000      51.1000 
+                 51.3000      51.5000      51.7000      51.9000      52.1000 
+                 52.3000      52.5000      52.7000      52.9000      53.1000 
+                 53.3000      53.5000      53.7000      53.9000      54.1000 
+                 54.3000      54.5000      54.7000      54.9000      55.1000 
+                 55.3000      55.5000      55.7000      55.9000      56.1000 
+                 56.3000      56.5000      56.7000      56.9000      57.1000 
+                 57.3000      57.5000      57.7000      57.9000      58.1000 
+                 58.3000      58.5000      58.7000      58.9000      59.1000 
+                 59.3000      59.5000      59.7000      59.9000      60.1000 
+                 60.3000      60.5000      60.7000      60.9000      61.1000 
+                 61.3000      61.5000      61.7000      61.9000      62.1000 
+                 62.3000      62.5000      62.7000      62.9000      63.1000 
+                 63.3000      63.5000      63.7000      63.9000      64.1000 
+                 64.3000      64.5000      64.7000      64.9000      65.1000 
+                 65.3000      65.5000      65.7000      65.9000      66.1000 
+                 66.3000      66.5000      66.7000      66.9000      67.1000 
+                 67.3000      67.5000      67.7000      67.9000      68.1000 
+                 68.3000      68.5000      68.7000      68.9000      69.1000 
+                 69.3000      69.5000      69.7000      69.9000      70.1000 
+                 70.3000      70.5000      70.7000      70.9000      71.1000 
+                 71.3000      71.5000      71.7000      71.9000      72.1000 
+                 72.3000      72.5000      72.7000      72.9000      73.1000 
+                 73.3000      73.5000      73.7000      73.9000      74.1000 
+                 74.3000      74.5000      74.7000      74.9000      75.1000 
+                 75.3000      75.5000      75.7000      75.9000      76.1000 
+                 76.3000      76.5000      76.7000      76.9000      77.1000 
+                 77.3000      77.5000      77.7000      77.9000      78.1000 
+                 78.3000      78.5000      78.7000      78.9000      79.1000 
+                 79.3000      79.5000      79.7000      79.9000      80.1000 
+                 80.3000      80.5000      80.7000      80.9000      81.1000 
+                 81.3000      81.5000      81.7000      81.9000      82.1000 
+                 82.3000      82.5000      82.7000      82.9000      83.1000 
+                 83.3000      83.5000      83.7000      83.9000      84.1000 
+                 84.3000      84.5000      84.7000      84.9000      85.1000 
+                 85.3000      85.5000      85.7000      85.9000      86.1000 
+                 86.3000      86.5000      86.7000      86.9000      87.1000 
+                 87.3000      87.5000      87.7000      87.9000      88.1000 
+                 88.3000      88.5000      88.7000      88.9000      89.1000 
+                 89.3000      89.5000      89.7000      89.9000      90.1000 
+                 90.3000      90.5000      90.7000      90.9000      91.1000 
+                 91.3000      91.5000      91.7000      91.9000      92.1000 
+                 92.3000      92.5000      92.7000      92.9000      93.1000 
+                 93.3000      93.5000      93.7000      93.9000      94.1000 
+                 94.3000      94.5000      94.7000      94.9000      95.1000 
+                 95.3000      95.5000      95.7000      95.9000      96.1000 
+                 96.3000      96.5000      96.7000      96.9000      97.1000 
+                 97.3000      97.5000      97.7000      97.9000      98.1000 
+          </two_theta>
+          <counts NAPItype="NX_INT32[400]" signal="1">
+                      94          103           86           84           88 
+                     106           92           87           95          104 
+                      96          114           99           89          102 
+                      89          120           93          101           97 
+                      94           84          102          116           98 
+                      92           77           90          111           89 
+                      90          125           86           90           97 
+                     111           85           81          108           96 
+                     101           95           95          119           91 
+                     103           95           97           75          105 
+                      68           95          101          102          107 
+                     102          105           96          116          107 
+                      98          115          113           90           92 
+                      78           70           89          107          106 
+                      84          100          107          102          112 
+                     104          107           98          102          105 
+                     102           94          107           94           91 
+                      99          101           94          119          108 
+                     110          105          107          106           93 
+                     102          109          104          102          109 
+                     102           94           91           88           94 
+                      99          116          101          110          104 
+                      98          110          108           99           99 
+                     108          135          146          251          315 
+                     484         2049         3541         2935          901 
+                     178          134          110          137          132 
+                     120           89          121          107           92 
+                     104          115          111          114           89 
+                      91          113          120          100           93 
+                     110           92          104          115          127 
+                     117          108           94          109          118 
+                     101          152          198          199          188 
+                     135          117          109          102          112 
+                     102          113          104           93           96 
+                     100          119          135          124          121 
+                      96           93          108          100           97 
+                     105           88           92          101          114 
+                     101          118          104           73           98 
+                      76          104           85           93           86 
+                      90           98           88           96          111 
+                      81           94           86           97           86 
+                      96          102          116           99          112 
+                     114          105           89           99          106 
+                     115           90           83          103           87 
+                     113           78           89           82           94 
+                      92          106           97           85          117 
+                      92           96          106           90           92 
+                     101           73           76          102           98 
+                     111          104          109           84          108 
+                      99          105           99           93           88 
+                      85           88           92          105          100 
+                     109          115          136          130          114 
+                     113          116          102          108           99 
+                     111          107          106           97          144 
+                     249          827         1588         2159         2201 
+                    2225         1557          606          269          152 
+                     156          126           97          100          112 
+                     100          132          122           85          108 
+                      96          130          115          110           93 
+                      92           96           76          100           93 
+                      94          104           80           86           96 
+                      69          107           91           84          106 
+                     105           99           91          106           93 
+                     102           82          103           87           95 
+                     106           92           93          106           96 
+                     101          112          103          134          103 
+                      93          103           96          129          100 
+                      86          100           95           96           98 
+                     128          105          109          138          126 
+                     146          191          450          807         1423 
+                    1648         1986         1839         1614         1162 
+                     634          296          190          139          122 
+                     125          130          104          109           98 
+                     121          142          128          105          138 
+                     119           92          104           98          147 
+                     132          116          112          124          112 
+                     104          113          107          100           87 
+                     105           86          117           92          110 
+                      86           98           82          107          105 
+                     119          105          107          101          105 
+          </counts>
+        </NXpsd>
+      </NXinstrument>
+      <NXsample name="sample">
+        <sample_name>Ga0.94Mn0.04Sb_8mm</sample_name>
+        <sample_table_rotation NAPItype="NX_FLOAT32" units="degree">
+              297.2100 
+        </sample_table_rotation>
+        <sample_temperature NAPItype="NX_FLOAT32" units="K">
+                4.0017 
+        </sample_temperature>
+        <device_name>ccr4k</device_name>
+        <temperature_mean NAPItype="NX_FLOAT32" units="K">
+                4.0000 
+        </temperature_mean>
+        <temperature_stddev NAPItype="NX_FLOAT32" units="K">
+                0.0000 
+        </temperature_stddev>
+        <sample_mur NAPItype="NX_FLOAT32" units="degree">
+                0.0000 
+        </sample_mur>
+      </NXsample>
+      <NXdata name="data1">
+        <counts NAPItype="NX_INT32[400]" signal="1">
+                    94          103           86           84           88 
+                   106           92           87           95          104 
+                    96          114           99           89          102 
+                    89          120           93          101           97 
+                    94           84          102          116           98 
+                    92           77           90          111           89 
+                    90          125           86           90           97 
+                   111           85           81          108           96 
+                   101           95           95          119           91 
+                   103           95           97           75          105 
+                    68           95          101          102          107 
+                   102          105           96          116          107 
+                    98          115          113           90           92 
+                    78           70           89          107          106 
+                    84          100          107          102          112 
+                   104          107           98          102          105 
+                   102           94          107           94           91 
+                    99          101           94          119          108 
+                   110          105          107          106           93 
+                   102          109          104          102          109 
+                   102           94           91           88           94 
+                    99          116          101          110          104 
+                    98          110          108           99           99 
+                   108          135          146          251          315 
+                   484         2049         3541         2935          901 
+                   178          134          110          137          132 
+                   120           89          121          107           92 
+                   104          115          111          114           89 
+                    91          113          120          100           93 
+                   110           92          104          115          127 
+                   117          108           94          109          118 
+                   101          152          198          199          188 
+                   135          117          109          102          112 
+                   102          113          104           93           96 
+                   100          119          135          124          121 
+                    96           93          108          100           97 
+                   105           88           92          101          114 
+                   101          118          104           73           98 
+                    76          104           85           93           86 
+                    90           98           88           96          111 
+                    81           94           86           97           86 
+                    96          102          116           99          112 
+                   114          105           89           99          106 
+                   115           90           83          103           87 
+                   113           78           89           82           94 
+                    92          106           97           85          117 
+                    92           96          106           90           92 
+                   101           73           76          102           98 
+                   111          104          109           84          108 
+                    99          105           99           93           88 
+                    85           88           92          105          100 
+                   109          115          136          130          114 
+                   113          116          102          108           99 
+                   111          107          106           97          144 
+                   249          827         1588         2159         2201 
+                  2225         1557          606          269          152 
+                   156          126           97          100          112 
+                   100          132          122           85          108 
+                    96          130          115          110           93 
+                    92           96           76          100           93 
+                    94          104           80           86           96 
+                    69          107           91           84          106 
+                   105           99           91          106           93 
+                   102           82          103           87           95 
+                   106           92           93          106           96 
+                   101          112          103          134          103 
+                    93          103           96          129          100 
+                    86          100           95           96           98 
+                   128          105          109          138          126 
+                   146          191          450          807         1423 
+                  1648         1986         1839         1614         1162 
+                   634          296          190          139          122 
+                   125          130          104          109           98 
+                   121          142          128          105          138 
+                   119           92          104           98          147 
+                   132          116          112          124          112 
+                   104          113          107          100           87 
+                   105           86          117           92          110 
+                    86           98           82          107          105 
+                   119          105          107          101          105 
+        </counts>
+        <two_theta NAPItype="NX_FLOAT32[400]" axis="1" units="degree">
+               18.3000      18.5000      18.7000      18.9000      19.1000 
+               19.3000      19.5000      19.7000      19.9000      20.1000 
+               20.3000      20.5000      20.7000      20.9000      21.1000 
+               21.3000      21.5000      21.7000      21.9000      22.1000 
+               22.3000      22.5000      22.7000      22.9000      23.1000 
+               23.3000      23.5000      23.7000      23.9000      24.1000 
+               24.3000      24.5000      24.7000      24.9000      25.1000 
+               25.3000      25.5000      25.7000      25.9000      26.1000 
+               26.3000      26.5000      26.7000      26.9000      27.1000 
+               27.3000      27.5000      27.7000      27.9000      28.1000 
+               28.3000      28.5000      28.7000      28.9000      29.1000 
+               29.3000      29.5000      29.7000      29.9000      30.1000 
+               30.3000      30.5000      30.7000      30.9000      31.1000 
+               31.3000      31.5000      31.7000      31.9000      32.1000 
+               32.3000      32.5000      32.7000      32.9000      33.1000 
+               33.3000      33.5000      33.7000      33.9000      34.1000 
+               34.3000      34.5000      34.7000      34.9000      35.1000 
+               35.3000      35.5000      35.7000      35.9000      36.1000 
+               36.3000      36.5000      36.7000      36.9000      37.1000 
+               37.3000      37.5000      37.7000      37.9000      38.1000 
+               38.3000      38.5000      38.7000      38.9000      39.1000 
+               39.3000      39.5000      39.7000      39.9000      40.1000 
+               40.3000      40.5000      40.7000      40.9000      41.1000 
+               41.3000      41.5000      41.7000      41.9000      42.1000 
+               42.3000      42.5000      42.7000      42.9000      43.1000 
+               43.3000      43.5000      43.7000      43.9000      44.1000 
+               44.3000      44.5000      44.7000      44.9000      45.1000 
+               45.3000      45.5000      45.7000      45.9000      46.1000 
+               46.3000      46.5000      46.7000      46.9000      47.1000 
+               47.3000      47.5000      47.7000      47.9000      48.1000 
+               48.3000      48.5000      48.7000      48.9000      49.1000 
+               49.3000      49.5000      49.7000      49.9000      50.1000 
+               50.3000      50.5000      50.7000      50.9000      51.1000 
+               51.3000      51.5000      51.7000      51.9000      52.1000 
+               52.3000      52.5000      52.7000      52.9000      53.1000 
+               53.3000      53.5000      53.7000      53.9000      54.1000 
+               54.3000      54.5000      54.7000      54.9000      55.1000 
+               55.3000      55.5000      55.7000      55.9000      56.1000 
+               56.3000      56.5000      56.7000      56.9000      57.1000 
+               57.3000      57.5000      57.7000      57.9000      58.1000 
+               58.3000      58.5000      58.7000      58.9000      59.1000 
+               59.3000      59.5000      59.7000      59.9000      60.1000 
+               60.3000      60.5000      60.7000      60.9000      61.1000 
+               61.3000      61.5000      61.7000      61.9000      62.1000 
+               62.3000      62.5000      62.7000      62.9000      63.1000 
+               63.3000      63.5000      63.7000      63.9000      64.1000 
+               64.3000      64.5000      64.7000      64.9000      65.1000 
+               65.3000      65.5000      65.7000      65.9000      66.1000 
+               66.3000      66.5000      66.7000      66.9000      67.1000 
+               67.3000      67.5000      67.7000      67.9000      68.1000 
+               68.3000      68.5000      68.7000      68.9000      69.1000 
+               69.3000      69.5000      69.7000      69.9000      70.1000 
+               70.3000      70.5000      70.7000      70.9000      71.1000 
+               71.3000      71.5000      71.7000      71.9000      72.1000 
+               72.3000      72.5000      72.7000      72.9000      73.1000 
+               73.3000      73.5000      73.7000      73.9000      74.1000 
+               74.3000      74.5000      74.7000      74.9000      75.1000 
+               75.3000      75.5000      75.7000      75.9000      76.1000 
+               76.3000      76.5000      76.7000      76.9000      77.1000 
+               77.3000      77.5000      77.7000      77.9000      78.1000 
+               78.3000      78.5000      78.7000      78.9000      79.1000 
+               79.3000      79.5000      79.7000      79.9000      80.1000 
+               80.3000      80.5000      80.7000      80.9000      81.1000 
+               81.3000      81.5000      81.7000      81.9000      82.1000 
+               82.3000      82.5000      82.7000      82.9000      83.1000 
+               83.3000      83.5000      83.7000      83.9000      84.1000 
+               84.3000      84.5000      84.7000      84.9000      85.1000 
+               85.3000      85.5000      85.7000      85.9000      86.1000 
+               86.3000      86.5000      86.7000      86.9000      87.1000 
+               87.3000      87.5000      87.7000      87.9000      88.1000 
+               88.3000      88.5000      88.7000      88.9000      89.1000 
+               89.3000      89.5000      89.7000      89.9000      90.1000 
+               90.3000      90.5000      90.7000      90.9000      91.1000 
+               91.3000      91.5000      91.7000      91.9000      92.1000 
+               92.3000      92.5000      92.7000      92.9000      93.1000 
+               93.3000      93.5000      93.7000      93.9000      94.1000 
+               94.3000      94.5000      94.7000      94.9000      95.1000 
+               95.3000      95.5000      95.7000      95.9000      96.1000 
+               96.3000      96.5000      96.7000      96.9000      97.1000 
+               97.3000      97.5000      97.7000      97.9000      98.1000 
+        </two_theta>
+        <two_theta_start NAPItype="NX_FLOAT32" units="degree">
+               18.3000 
+        </two_theta_start>
+        <Step NAPItype="NX_FLOAT32" units="degree">
+                0.2000 
+        </Step>
+        <no_of_steps NAPItype="NX_INT32">
+                   400 
+        </no_of_steps>
+        <lambda NAPItype="NX_FLOAT32" units="Angstroem">
+                2.5666 
+        </lambda>
+      </NXdata>
+    </NXentry>
+  </NXroot>
diff --git a/test/data/dmc02.h5 b/test/data/dmc02.h5
new file mode 100644
index 0000000..cb01760
Binary files /dev/null and b/test/data/dmc02.h5 differ
diff --git a/test/data/dmc02.hdf b/test/data/dmc02.hdf
new file mode 100644
index 0000000..be78445
Binary files /dev/null and b/test/data/dmc02.hdf differ
diff --git a/test/data/dmc02.xml b/test/data/dmc02.xml
new file mode 100644
index 0000000..dc7dc43
--- /dev/null
+++ b/test/data/dmc02.xml
@@ -0,0 +1,245 @@
+<?xml version="1.0"?>
+  <NXroot NeXus_version="3.0.0"
+HDF_version="NCSA HDF Version 4.2 Release 0, December 2, 2003"
+file_name="/home/dmc/data/2005/003/dmc2005n003078.hdf"
+file_time="2005-05-27 05:48:56" instrument="DMC" owner="keller"
+owner_telephone_number="UNKNOWN" owner_fax_number="UNKNOWN"
+owner_email="UNKNOWN" owner_address="UNKNOWN">
+    <NXentry name="entry1">
+      <title>Ga0.94Mn0.04Sb_8mm 2.567A T=4</title>
+      <start_time>2005-05-27 05:48:56</start_time>
+      <NXinstrument name="DMC">
+        <name>DMC at SINQ</name>
+        <NXsource name="SINQ">
+          <name>SINQ</name>
+          <type>Continuous flux spallation source</type>
+        </NXsource>
+        <NXcrystal name="Monochromator">
+          <type>Pyrolithic Graphite 002</type>
+          <theta NAPItype="NX_FLOAT32">22.430000</theta>
+          <two_theta NAPItype="NX_FLOAT32">44.869999</two_theta>
+          <lambda NAPItype="NX_FLOAT32" units="Angstroem">2.566600</lambda>
+          <curvature NAPItype="NX_FLOAT32">14.000000</curvature>
+          <x_translation NAPItype="NX_FLOAT32">0.940000</x_translation>
+          <y_translation NAPItype="NX_FLOAT32">0.210000</y_translation>
+          <chi NAPItype="NX_FLOAT32">0.356000</chi>
+          <phi NAPItype="NX_FLOAT32">-0.002000</phi>
+          <d_spacing NAPItype="NX_FLOAT32" units="Angstroem">3.353700</d_spacing>
+        </NXcrystal>
+        <NXpsd name="DMC-BF3-Detector">
+          <Preset NAPItype="NX_INT32">1094713344</Preset>
+          <CounterMode>monitor</CounterMode>
+          <time NAPItype="NX_FLOAT32">267.199005</time>
+          <beam_monitor NAPItype="NX_INT32" units="counts">2328990</beam_monitor>
+          <Monitor NAPItype="NX_INT32" units="counts">12000</Monitor>
+          <proton_monitor NAPItype="NX_INT32" units="counts">32704151</proton_monitor>
+          <two_theta_start NAPItype="NX_FLOAT32" units="degree">18.400000</two_theta_start>
+          <Step NAPItype="NX_FLOAT32" units="degree">0.200000</Step>
+          <no_of_steps NAPItype="NX_INT32">400</no_of_steps>
+          <two_theta NAPItype="NX_FLOAT32[400]" axis="1" units="degree">
+             18.400000 18.600000 18.799999 19.000000 19.200001 19.400000 19.600000 19.799999
+             20.000000 20.200001 20.400000 20.600000 20.799999 21.000000 21.200001 21.400000
+             21.600000 21.799999 22.000000 22.200001 22.400000 22.600000 22.799999 23.000000
+             23.200001 23.400000 23.600000 23.799999 24.000000 24.200001 24.400000 24.600000
+             24.799999 25.000000 25.200001 25.400000 25.600000 25.799999 26.000000 26.200001
+             26.400000 26.600000 26.799999 27.000000 27.200001 27.400000 27.600000 27.799999
+             28.000000 28.200001 28.400000 28.600000 28.799999 29.000000 29.200001 29.400000
+             29.600000 29.799999 30.000000 30.200001 30.400000 30.600000 30.799999 31.000000
+             31.200001 31.400000 31.600000 31.799999 32.000000 32.200001 32.400002 32.599998
+             32.799999 33.000000 33.200001 33.400002 33.599998 33.799999 34.000000 34.200001
+             34.400002 34.599998 34.799999 35.000000 35.200001 35.400002 35.599998 35.799999
+             36.000000 36.200001 36.400002 36.599998 36.799999 37.000000 37.200001 37.400002
+             37.599998 37.799999 38.000000 38.200001 38.400002 38.599998 38.799999 39.000000
+             39.200001 39.400002 39.599998 39.799999 40.000000 40.200001 40.400002 40.599998
+             40.799999 41.000000 41.200001 41.400002 41.599998 41.799999 42.000000 42.200001
+             42.400002 42.599998 42.799999 43.000000 43.200001 43.400002 43.599998 43.799999
+             44.000000 44.200001 44.400002 44.599998 44.799999 45.000000 45.200001 45.400002
+             45.599998 45.799999 46.000000 46.200001 46.400002 46.599998 46.799999 47.000000
+             47.200001 47.400002 47.599998 47.799999 48.000000 48.200001 48.400002 48.599998
+             48.799999 49.000000 49.200001 49.400002 49.599998 49.799999 50.000000 50.200001
+             50.400002 50.599998 50.799999 51.000000 51.200001 51.400002 51.599998 51.799999
+             52.000000 52.200001 52.400002 52.599998 52.799999 53.000000 53.200001 53.400002
+             53.599998 53.799999 54.000000 54.200001 54.400002 54.599998 54.799999 55.000000
+             55.200001 55.400002 55.599998 55.799999 56.000000 56.200001 56.400002 56.599998
+             56.799999 57.000000 57.200001 57.400002 57.599998 57.799999 58.000000 58.200001
+             58.400002 58.599998 58.799999 59.000000 59.200001 59.400002 59.599998 59.799999
+             60.000000 60.200001 60.400002 60.599998 60.799999 61.000000 61.200001 61.400002
+             61.599998 61.799999 62.000000 62.200001 62.400002 62.599998 62.799999 63.000000
+             63.200001 63.400002 63.599998 63.799999 64.000000 64.199997 64.400002 64.599998
+             64.800003 65.000000 65.199997 65.400002 65.599998 65.800003 66.000000 66.199997
+             66.400002 66.599998 66.800003 67.000000 67.199997 67.400002 67.599998 67.800003
+             68.000000 68.199997 68.400002 68.599998 68.800003 69.000000 69.199997 69.400002
+             69.599998 69.800003 70.000000 70.199997 70.400002 70.599998 70.800003 71.000000
+             71.199997 71.400002 71.599998 71.800003 72.000000 72.199997 72.400002 72.599998
+             72.800003 73.000000 73.199997 73.400002 73.599998 73.800003 74.000000 74.199997
+             74.400002 74.599998 74.800003 75.000000 75.199997 75.400002 75.599998 75.800003
+             76.000000 76.199997 76.400002 76.599998 76.800003 77.000000 77.199997 77.400002
+             77.599998 77.800003 78.000000 78.199997 78.400002 78.599998 78.800003 79.000000
+             79.199997 79.400002 79.599998 79.800003 80.000000 80.199997 80.400002 80.599998
+             80.800003 81.000000 81.199997 81.400002 81.599998 81.800003 82.000000 82.199997
+             82.400002 82.599998 82.800003 83.000000 83.199997 83.400002 83.599998 83.800003
+             84.000000 84.199997 84.400002 84.599998 84.800003 85.000000 85.199997 85.400002
+             85.599998 85.800003 86.000000 86.199997 86.400002 86.599998 86.800003 87.000000
+             87.199997 87.400002 87.599998 87.800003 88.000000 88.199997 88.400002 88.599998
+             88.800003 89.000000 89.199997 89.400002 89.599998 89.800003 90.000000 90.199997
+             90.400002 90.599998 90.800003 91.000000 91.199997 91.400002 91.599998 91.800003
+             92.000000 92.199997 92.400002 92.599998 92.800003 93.000000 93.199997 93.400002
+             93.599998 93.800003 94.000000 94.199997 94.400002 94.599998 94.800003 95.000000
+             95.199997 95.400002 95.599998 95.800003 96.000000 96.199997 96.400002 96.599998
+             96.800003 97.000000 97.199997 97.400002 97.599998 97.800003 98.000000 98.199997
+            </two_theta>
+          <counts NAPItype="NX_INT32[400]" signal="1">
+             114 102 107 106 90 102 99 95 80 104
+             119 101 100 109 101 98 90 93 102 112
+             104 84 87 98 95 86 100 104 90 99
+             67 92 100 99 81 103 94 90 75 100
+             107 75 86 101 107 92 83 76 95 101
+             79 101 108 90 78 104 85 85 88 104
+             113 106 92 100 96 92 107 94 97 96
+             93 96 96 109 96 89 89 76 99 131
+             88 101 103 98 90 89 130 93 122 108
+             97 94 117 79 94 106 99 90 98 105
+             88 89 92 94 99 92 104 103 101 101
+             115 111 87 120 108 123 115 202 264 316
+             1036 3216 3380 1958 341 149 100 107 116 119
+             102 98 103 102 89 92 81 98 100 97
+             109 117 103 99 114 101 107 104 114 112
+             102 109 90 102 109 154 166 202 198 197
+             103 100 116 97 96 108 94 105 86 115
+             109 136 139 135 108 98 101 96 75 103
+             86 112 86 88 101 85 100 112 103 101
+             95 92 76 102 97 96 71 89 92 98
+             90 100 102 96 82 83 92 105 94 101
+             80 111 83 93 99 98 115 93 105 88
+             113 85 97 102 100 92 96 81 92 92
+             86 99 90 86 88 104 94 98 90 82
+             108 89 95 75 100 115 103 106 102 111
+             111 89 92 108 106 116 154 129 134 120
+             112 121 103 104 94 102 126 122 125 153
+             460 1292 1855 2198 2195 2030 1030 379 171 126
+             120 132 95 115 102 90 100 117 104 102
+             91 117 122 96 92 97 97 108 108 95
+             132 117 103 85 118 91 84 101 95 103
+             83 115 92 87 94 94 98 87 102 95
+             122 96 101 73 103 86 104 92 106 82
+             90 90 94 114 127 100 88 96 109 116
+             103 124 102 111 124 159 289 608 970 1573
+             1741 1989 1689 1365 884 460 241 165 142 124
+             132 123 105 127 113 116 126 122 111 122
+             108 113 114 112 105 122 120 107 126 108
+             125 104 123 102 126 112 85 114 115 102
+             103 116 101 130 106 99 99 112 105 116
+            </counts>
+        </NXpsd>
+      </NXinstrument>
+      <NXsample name="sample">
+        <sample_name>Ga0.94Mn0.04Sb_8mm</sample_name>
+        <sample_table_rotation NAPItype="NX_FLOAT32" units="degree">297.209991</sample_table_rotation>
+        <sample_temperature NAPItype="NX_FLOAT32" units="K">4.001050</sample_temperature>
+        <device_name>ccr4k</device_name>
+        <temperature_mean NAPItype="NX_FLOAT32" units="K">4.000000</temperature_mean>
+        <temperature_stddev NAPItype="NX_FLOAT32" units="K">0.000000</temperature_stddev>
+        <sample_mur NAPItype="NX_FLOAT32" units="degree">0.000000</sample_mur>
+      </NXsample>
+      <NXdata name="data1">
+        <counts NAPItype="NX_INT32[400]" signal="1">
+          114 102 107 106 90 102 99 95 80 104
+          119 101 100 109 101 98 90 93 102 112
+          104 84 87 98 95 86 100 104 90 99
+          67 92 100 99 81 103 94 90 75 100
+          107 75 86 101 107 92 83 76 95 101
+          79 101 108 90 78 104 85 85 88 104
+          113 106 92 100 96 92 107 94 97 96
+          93 96 96 109 96 89 89 76 99 131
+          88 101 103 98 90 89 130 93 122 108
+          97 94 117 79 94 106 99 90 98 105
+          88 89 92 94 99 92 104 103 101 101
+          115 111 87 120 108 123 115 202 264 316
+          1036 3216 3380 1958 341 149 100 107 116 119
+          102 98 103 102 89 92 81 98 100 97
+          109 117 103 99 114 101 107 104 114 112
+          102 109 90 102 109 154 166 202 198 197
+          103 100 116 97 96 108 94 105 86 115
+          109 136 139 135 108 98 101 96 75 103
+          86 112 86 88 101 85 100 112 103 101
+          95 92 76 102 97 96 71 89 92 98
+          90 100 102 96 82 83 92 105 94 101
+          80 111 83 93 99 98 115 93 105 88
+          113 85 97 102 100 92 96 81 92 92
+          86 99 90 86 88 104 94 98 90 82
+          108 89 95 75 100 115 103 106 102 111
+          111 89 92 108 106 116 154 129 134 120
+          112 121 103 104 94 102 126 122 125 153
+          460 1292 1855 2198 2195 2030 1030 379 171 126
+          120 132 95 115 102 90 100 117 104 102
+          91 117 122 96 92 97 97 108 108 95
+          132 117 103 85 118 91 84 101 95 103
+          83 115 92 87 94 94 98 87 102 95
+          122 96 101 73 103 86 104 92 106 82
+          90 90 94 114 127 100 88 96 109 116
+          103 124 102 111 124 159 289 608 970 1573
+          1741 1989 1689 1365 884 460 241 165 142 124
+          132 123 105 127 113 116 126 122 111 122
+          108 113 114 112 105 122 120 107 126 108
+          125 104 123 102 126 112 85 114 115 102
+          103 116 101 130 106 99 99 112 105 116
+         </counts>
+        <two_theta NAPItype="NX_FLOAT32[400]" axis="1" units="degree">
+          18.400000 18.600000 18.799999 19.000000 19.200001 19.400000 19.600000 19.799999
+          20.000000 20.200001 20.400000 20.600000 20.799999 21.000000 21.200001 21.400000
+          21.600000 21.799999 22.000000 22.200001 22.400000 22.600000 22.799999 23.000000
+          23.200001 23.400000 23.600000 23.799999 24.000000 24.200001 24.400000 24.600000
+          24.799999 25.000000 25.200001 25.400000 25.600000 25.799999 26.000000 26.200001
+          26.400000 26.600000 26.799999 27.000000 27.200001 27.400000 27.600000 27.799999
+          28.000000 28.200001 28.400000 28.600000 28.799999 29.000000 29.200001 29.400000
+          29.600000 29.799999 30.000000 30.200001 30.400000 30.600000 30.799999 31.000000
+          31.200001 31.400000 31.600000 31.799999 32.000000 32.200001 32.400002 32.599998
+          32.799999 33.000000 33.200001 33.400002 33.599998 33.799999 34.000000 34.200001
+          34.400002 34.599998 34.799999 35.000000 35.200001 35.400002 35.599998 35.799999
+          36.000000 36.200001 36.400002 36.599998 36.799999 37.000000 37.200001 37.400002
+          37.599998 37.799999 38.000000 38.200001 38.400002 38.599998 38.799999 39.000000
+          39.200001 39.400002 39.599998 39.799999 40.000000 40.200001 40.400002 40.599998
+          40.799999 41.000000 41.200001 41.400002 41.599998 41.799999 42.000000 42.200001
+          42.400002 42.599998 42.799999 43.000000 43.200001 43.400002 43.599998 43.799999
+          44.000000 44.200001 44.400002 44.599998 44.799999 45.000000 45.200001 45.400002
+          45.599998 45.799999 46.000000 46.200001 46.400002 46.599998 46.799999 47.000000
+          47.200001 47.400002 47.599998 47.799999 48.000000 48.200001 48.400002 48.599998
+          48.799999 49.000000 49.200001 49.400002 49.599998 49.799999 50.000000 50.200001
+          50.400002 50.599998 50.799999 51.000000 51.200001 51.400002 51.599998 51.799999
+          52.000000 52.200001 52.400002 52.599998 52.799999 53.000000 53.200001 53.400002
+          53.599998 53.799999 54.000000 54.200001 54.400002 54.599998 54.799999 55.000000
+          55.200001 55.400002 55.599998 55.799999 56.000000 56.200001 56.400002 56.599998
+          56.799999 57.000000 57.200001 57.400002 57.599998 57.799999 58.000000 58.200001
+          58.400002 58.599998 58.799999 59.000000 59.200001 59.400002 59.599998 59.799999
+          60.000000 60.200001 60.400002 60.599998 60.799999 61.000000 61.200001 61.400002
+          61.599998 61.799999 62.000000 62.200001 62.400002 62.599998 62.799999 63.000000
+          63.200001 63.400002 63.599998 63.799999 64.000000 64.199997 64.400002 64.599998
+          64.800003 65.000000 65.199997 65.400002 65.599998 65.800003 66.000000 66.199997
+          66.400002 66.599998 66.800003 67.000000 67.199997 67.400002 67.599998 67.800003
+          68.000000 68.199997 68.400002 68.599998 68.800003 69.000000 69.199997 69.400002
+          69.599998 69.800003 70.000000 70.199997 70.400002 70.599998 70.800003 71.000000
+          71.199997 71.400002 71.599998 71.800003 72.000000 72.199997 72.400002 72.599998
+          72.800003 73.000000 73.199997 73.400002 73.599998 73.800003 74.000000 74.199997
+          74.400002 74.599998 74.800003 75.000000 75.199997 75.400002 75.599998 75.800003
+          76.000000 76.199997 76.400002 76.599998 76.800003 77.000000 77.199997 77.400002
+          77.599998 77.800003 78.000000 78.199997 78.400002 78.599998 78.800003 79.000000
+          79.199997 79.400002 79.599998 79.800003 80.000000 80.199997 80.400002 80.599998
+          80.800003 81.000000 81.199997 81.400002 81.599998 81.800003 82.000000 82.199997
+          82.400002 82.599998 82.800003 83.000000 83.199997 83.400002 83.599998 83.800003
+          84.000000 84.199997 84.400002 84.599998 84.800003 85.000000 85.199997 85.400002
+          85.599998 85.800003 86.000000 86.199997 86.400002 86.599998 86.800003 87.000000
+          87.199997 87.400002 87.599998 87.800003 88.000000 88.199997 88.400002 88.599998
+          88.800003 89.000000 89.199997 89.400002 89.599998 89.800003 90.000000 90.199997
+          90.400002 90.599998 90.800003 91.000000 91.199997 91.400002 91.599998 91.800003
+          92.000000 92.199997 92.400002 92.599998 92.800003 93.000000 93.199997 93.400002
+          93.599998 93.800003 94.000000 94.199997 94.400002 94.599998 94.800003 95.000000
+          95.199997 95.400002 95.599998 95.800003 96.000000 96.199997 96.400002 96.599998
+          96.800003 97.000000 97.199997 97.400002 97.599998 97.800003 98.000000 98.199997
+         </two_theta>
+        <two_theta_start NAPItype="NX_FLOAT32" units="degree">18.400000</two_theta_start>
+        <Step NAPItype="NX_FLOAT32" units="degree">0.200000</Step>
+        <no_of_steps NAPItype="NX_INT32">400</no_of_steps>
+        <lambda NAPItype="NX_FLOAT32" units="Angstroem">2.566600</lambda>
+      </NXdata>
+    </NXentry>
+  </NXroot>
diff --git a/test/dummy.c b/test/dummy.c
new file mode 100644
index 0000000..73a072a
--- /dev/null
+++ b/test/dummy.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+	return 77;
+}
diff --git a/test/leak_test1.c b/test/leak_test1.c
new file mode 100644
index 0000000..6f75433
--- /dev/null
+++ b/test/leak_test1.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <napi.h>
+
+int main (int argc, char* argv[])
+{
+	NXaccess access_mode = NXACC_CREATE5;
+        const int nReOpen = 1000;
+	printf("Running for %d iterations\n", nReOpen);
+        int iReOpen;
+        const char* szFile = "leak_test1.nxs";
+
+        NXhandle fileid;
+	unlink(szFile);
+        if (NXopen(szFile, access_mode, &fileid) != NX_OK) return 1;
+        if( NXclose(&fileid) != NX_OK) return 1;
+        for( iReOpen = 0; iReOpen < nReOpen; iReOpen++ )
+        {
+                if( 0 == iReOpen % 100 )
+                        printf("loop count %d\n", iReOpen);
+                if( NXopen(szFile, NXACC_RDWR, &fileid ) != NX_OK) return 1;
+                if( NXclose(&fileid) != NX_OK ) return 1;
+        }      
+	unlink(szFile);
+	fileid = NULL;
+	_exit(EXIT_FAILURE);
+        return 0;
+}
diff --git a/test/leak_test2.cxx b/test/leak_test2.cxx
new file mode 100644
index 0000000..abdf17c
--- /dev/null
+++ b/test/leak_test2.cxx
@@ -0,0 +1,62 @@
+#include <sstream>
+#include <cstdlib>
+#include <cstdio>
+#include <napi.h>
+#include <unistd.h>
+
+#define PSZ(s) (s).c_str()
+
+const int nFiles = 10;
+const int nEntry = 10;
+const int nData = 10;
+int array_dims[2] = {5, 4};
+short int i2_array[4] = {1000, 2000, 3000, 4000}; int iFile, iReOpen, iEntry, iData, iNXdata, iSimpleArraySize = 4; 
+
+int main (int argc, char* argv[])
+{
+    printf("Running for %d iterations\n", nFiles);
+    NXaccess access_mode = NXACC_CREATE5;
+    char strFile[512];
+        for( iFile = 0; iFile < nFiles; iFile++ )
+        {
+                sprintf(strFile, "leak_test2_%03d.nxs", iFile);
+                remove(strFile);
+                printf("file %s\n", strFile);
+                NXhandle fileid;
+                if (NXopen(strFile, access_mode, &fileid) != NX_OK) return 1;
+
+                for( iEntry = 0; iEntry < nEntry; iEntry++ )
+                {
+                        std::ostringstream oss;
+                oss << "entry_" << iEntry;
+                        if (NXmakegroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK) return 1;
+                        if (NXopengroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK) return 1;
+                        for( iNXdata = 0; iNXdata < nData; iNXdata++ )
+                        {
+                                std::ostringstream oss;
+                                oss << "data_" << iNXdata;
+                                if (NXmakegroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK) return 1;
+                                if (NXopengroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK) return 1;
+                                for( iData = 0; iData < nData; iData++ )
+                                {
+                                        std::ostringstream oss;
+                                        oss << "i2_data_" << iData;
+                                        if (NXmakedata (fileid, PSZ(oss.str()), NX_INT16, 1, &array_dims[1]) != NX_OK) return 1;
+                                        if (NXopendata (fileid, PSZ(oss.str())) != NX_OK) return 1;
+                                        if (NXputdata (fileid, i2_array) != NX_OK) return 1;
+                                        if (NXclosedata (fileid) != NX_OK) return 1;
+                                }
+                                if (NXclosegroup (fileid) != NX_OK) return 1;
+                        }
+                        if (NXclosegroup (fileid) != NX_OK) return 1;
+                }
+                if (NXclose (&fileid) != NX_OK) return 1;
+		fileid = NULL;
+
+                // Delete file
+                remove(strFile);
+        }
+	_exit(EXIT_FAILURE);
+	return 0;
+}
+
diff --git a/test/leak_test3.cxx b/test/leak_test3.cxx
new file mode 100644
index 0000000..c3484af
--- /dev/null
+++ b/test/leak_test3.cxx
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sstream>
+#include <unistd.h>
+#include <napi.h>
+
+#define PSZ(s) (s).c_str()
+
+using namespace std;
+
+const int nFiles = 10;
+const int nEntry = 2;
+const int nData = 2;
+int array_dims[2] = {512, 512};
+const char szFile[] = "leak_test.nxs";
+const int iBinarySize = 512*512;
+int aiBinaryData[iBinarySize];
+
+int main ()
+{
+  int i, iFile, iEntry, iData, iNXdata;
+ 
+  for(i=0; i < iBinarySize; i++)
+  {
+	aiBinaryData[i] = rand();
+  }	
+  for( iFile = 0; iFile < nFiles; iFile++ )
+  {
+    printf("file %d\n", iFile);
+	
+    NXhandle fileid;
+    NXlink aLink;
+    if( NXopen(szFile, NXACC_CREATE5, &fileid ) != NX_OK) return 1;
+    for( iEntry = 0; iEntry < nEntry; iEntry++ )
+    {
+      ostringstream oss;
+      oss << "entry_" << iEntry;
+      if (NXmakegroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK) return 1;
+      if (NXopengroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK) return 1;
+      for( iNXdata = 0; iNXdata < nData; iNXdata++ )
+      {
+        ostringstream oss;
+        oss << "data_" << iNXdata;
+        if (NXmakegroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK) return 1;
+        if (NXopengroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK) return 1;
+        NXgetgroupID(fileid, &aLink);
+        for( iData = 0; iData < nData; iData++ )
+        {
+          ostringstream oss;
+          oss << "i2_data_" << iData;
+          if (NXcompmakedata (fileid, PSZ(oss.str()), NX_INT16, 2, array_dims, NX_COMP_LZW, array_dims) != NX_OK)
+//          if (NXmakedata (fileid, PSZ(oss.str()), NX_INT16, 2, array_dims) != NX_OK)
+	  	return 1;
+          if (NXopendata (fileid, PSZ(oss.str())) != NX_OK) return 1;
+            if (NXputdata (fileid, aiBinaryData) != NX_OK) return 1;
+          if (NXclosedata (fileid) != NX_OK) return 1;
+        }
+        if (NXclosegroup (fileid) != NX_OK) return 1;
+      }
+      if (NXclosegroup (fileid) != NX_OK) return 1;
+    }
+    if (NXclose (&fileid) != NX_OK) return 1;
+
+    // Delete file
+    remove(szFile);
+  }
+
+  printf("done...\n");
+  _exit(EXIT_FAILURE);
+}
+
+
diff --git a/test/napi_test.c b/test/napi_test.c
new file mode 100644
index 0000000..871d922
--- /dev/null
+++ b/test/napi_test.c
@@ -0,0 +1,693 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  Test program for C API 
+  
+  Copyright (C) 1997-2011 Freddie Akeroyd
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+             
+  For further information, see <http://www.nexusformat.org>
+
+  $Id$
+
+----------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include "napi.h"
+#include "napiconfig.h"
+
+static void print_data (const char *prefix, void *data, int type, int num);
+static int testLoadPath();
+static int testExternal(char *progName);
+
+static const char *relativePathOf(const char* filename) {
+  char cwd[1024];
+
+  getcwd(cwd, sizeof(cwd));
+  
+  if (strncmp(filename, cwd, strlen(cwd)) == 0) 
+  {
+	return filename+strlen(cwd)+1;
+  }
+  else
+  {
+  	return filename;
+  }
+}
+
+int main (int argc, char *argv[])
+{
+  int i, j, k, n, NXrank, NXdims[32], NXtype, NXlen, entry_status, attr_status;
+  float r;
+  void *data_buffer;
+  unsigned char i1_array[4] = {1, 2, 3, 4};
+  short int i2_array[4] = {1000, 2000, 3000, 4000};
+  int i4_array[4] = {1000000, 2000000, 3000000, 4000000};
+  float r4_array[5][4] =
+  {{1., 2., 3., 4.}, {5., 6., 7., 8.}, {9., 10., 11., 12.}, {13., 14., 15., 16.}, {17., 18., 19., 20.}};
+  double r8_array[5][4] =
+  {{1., 2., 3., 4.}, {5., 6., 7., 8.}, {9., 10., 11., 12.}, {13., 14., 15., 16.}, {17., 18., 19., 20.}};
+  int array_dims[2] = {5, 4};
+  int unlimited_dims[1] = {NX_UNLIMITED};
+  int chunk_size[2]={5,4};
+  int slab_start[2], slab_size[2];
+  char name[64], char_class[64], char_buffer[128];
+  char group_name[64], class_name[64];
+  char c1_array[5][4] = {{'a', 'b', 'c' ,'d'}, {'e', 'f', 'g' ,'h'}, 
+     {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'}, {'q', 'r', 's' , 't'}};
+  int unlimited_cdims[2] = {NX_UNLIMITED, 4};
+  NXhandle fileid, clone_fileid;
+  NXlink glink, dlink, blink;
+  int comp_array[100][20];
+  int dims[2];
+  int cdims[2];
+  int nx_creation_code;
+  char nxFile[80];
+  char filename[256];
+  int64_t grossezahl[4];
+  const char* ch_test_data = "NeXus ><}&{'\\&\" Data";
+  char path[512];
+
+  grossezahl[0] = 12;
+  grossezahl[2] = 23;
+#if HAVE_LONG_LONG_INT
+  grossezahl[1] = (int64_t)555555555555LL;
+  grossezahl[3] = (int64_t)777777777777LL;
+#else
+  grossezahl[1] = (int64_t)555555555555;
+  grossezahl[3] = (int64_t)777777777777;
+#endif /* HAVE_LONG_LONG_INT */
+
+  if(strstr(argv[0],"napi_test-hdf5") != NULL){
+    nx_creation_code = NXACC_CREATE5;
+    strcpy(nxFile,"NXtest.h5");
+  }else if(strstr(argv[0],"napi_test-xml-table") != NULL){
+    nx_creation_code = NXACC_CREATEXML | NXACC_TABLE;
+    strcpy(nxFile,"NXtest-table.xml");
+  }else if(strstr(argv[0],"napi_test-xml") != NULL){
+    nx_creation_code = NXACC_CREATEXML;
+    strcpy(nxFile,"NXtest.xml");
+  } else {
+    nx_creation_code = NXACC_CREATE;
+    strcpy(nxFile,"NXtest.hdf");
+  }
+
+/* create file */
+  if (NXopen (nxFile, nx_creation_code, &fileid) != NX_OK) return 1;
+  if (nx_creation_code == NXACC_CREATE5)
+  {
+    if (NXreopen (fileid, &clone_fileid) != NX_OK) return 1;
+  }
+  NXsetnumberformat(fileid,NX_FLOAT32,"%9.3f");
+  if (NXmakegroup (fileid, "entry", "NXentry") != NX_OK) return 1;
+  if (NXopengroup (fileid, "entry", "NXentry") != NX_OK) return 1;
+  if(NXputattr(fileid,"hugo","namenlos",strlen("namenlos"), NX_CHAR) != NX_OK) return 1;
+  if(NXputattr(fileid,"cucumber","passion",strlen("passion"), NX_CHAR) != NX_OK) return 1;
+     NXlen = strlen(ch_test_data);
+     if (NXmakedata (fileid, "ch_data", NX_CHAR, 1, &NXlen) != NX_OK) return 1;
+     if (NXopendata (fileid, "ch_data") != NX_OK) return 1;
+        if (NXputdata (fileid, ch_test_data) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     if (NXmakedata (fileid, "c1_data", NX_CHAR, 2, array_dims) != NX_OK) return 1;
+     if (NXopendata (fileid, "c1_data") != NX_OK) return 1;
+        if (NXputdata (fileid, c1_array) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     if (NXmakedata (fileid, "i1_data", NX_INT8, 1, &array_dims[1]) != NX_OK) return 1;
+     if (NXopendata (fileid, "i1_data") != NX_OK) return 1;
+        if (NXputdata (fileid, i1_array) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     if (NXmakedata (fileid, "i2_data", NX_INT16, 1, &array_dims[1]) != NX_OK) return 1;
+     if (NXopendata (fileid, "i2_data") != NX_OK) return 1;
+        if (NXputdata (fileid, i2_array) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     if (NXmakedata (fileid, "i4_data", NX_INT32, 1, &array_dims[1]) != NX_OK) return 1;
+     if (NXopendata (fileid, "i4_data") != NX_OK) return 1;
+        if (NXputdata (fileid, i4_array) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     if (NXcompmakedata (fileid, "r4_data", NX_FLOAT32, 2, array_dims,NX_COMP_LZW,chunk_size) != NX_OK) return 1;
+     if (NXopendata (fileid, "r4_data") != NX_OK) return 1;
+        if (NXputdata (fileid, r4_array) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     if (NXmakedata (fileid, "r8_data", NX_FLOAT64, 2, array_dims) != NX_OK) return 1;
+     if (NXopendata (fileid, "r8_data") != NX_OK) return 1;
+        slab_start[0] = 4; slab_start[1] = 0; slab_size[0] = 1; slab_size[1] = 4;
+        if (NXputslab (fileid, (double*)r8_array + 16, slab_start, slab_size) != NX_OK) return 1;
+        slab_start[0] = 0; slab_start[1] = 0; slab_size[0] = 4; slab_size[1] = 4;
+        if (NXputslab (fileid, r8_array, slab_start, slab_size) != NX_OK) return 1;
+        if (NXputattr (fileid, "ch_attribute", ch_test_data, strlen (ch_test_data), NX_CHAR) != NX_OK) return 1;
+        i = 42;
+        if (NXputattr (fileid, "i4_attribute", &i, 1, NX_INT32) != NX_OK) return 1;
+        r = 3.14159265;
+        if (NXputattr (fileid, "r4_attribute", &r, 1, NX_FLOAT32) != NX_OK) return 1;
+        if (NXgetdataID (fileid, &dlink) != NX_OK) return 1;
+     if (NXclosedata (fileid) != NX_OK) return 1;
+     dims[0] = 4;
+     if (nx_creation_code != NXACC_CREATE)
+     {
+       if (NXmakedata (fileid, "grosse_zahl", NX_INT64, 1,dims) == NX_OK) {
+         if (NXopendata (fileid, "grosse_zahl") != NX_OK) return 1;
+         if (NXputdata (fileid, grossezahl) != NX_OK) return 1;
+         if (NXclosedata (fileid) != NX_OK) return 1;  
+       }
+     }
+     if (NXmakegroup (fileid, "data", "NXdata") != NX_OK) return 1;
+     if (NXopengroup (fileid, "data", "NXdata") != NX_OK) return 1;
+        if (NXmakelink (fileid, &dlink) != NX_OK) return 1;
+        dims[0] = 100;
+        dims[1] = 20;
+        for(i = 0; i < 100; i++)
+            {
+            for(j = 0; j < 20; j++)
+               {
+                 comp_array[i][j] = i;
+               }
+            }
+        cdims[0] = 20;
+        cdims[1] = 20;
+        if (NXcompmakedata (fileid, "comp_data", NX_INT32, 2, dims, NX_COMP_LZW, cdims) != NX_OK) return 1;
+        if (NXopendata (fileid, "comp_data") != NX_OK) return 1;
+           if (NXputdata (fileid, comp_array) != NX_OK) return 1;
+        if (NXclosedata (fileid) != NX_OK) return 1;  
+        if (NXflush (&fileid) != NX_OK) return 1;
+	if (NXmakedata (fileid, "flush_data", NX_INT32, 1, unlimited_dims) != NX_OK) return 1;
+	slab_size[0] = 1;
+	for (i = 0; i < 7; i++)
+	    {
+	      slab_start[0] = i;
+	      if (NXopendata (fileid, "flush_data") != NX_OK) return 1;
+	        if (NXputslab (fileid, &i, slab_start, slab_size) != NX_OK) return 1;
+		if (NXflush (&fileid) != NX_OK) return 1;
+	}
+     if (NXclosegroup (fileid) != NX_OK) return 1;
+     if (NXmakegroup (fileid, "sample", "NXsample") != NX_OK) return 1;
+     if (NXopengroup (fileid, "sample", "NXsample") != NX_OK) return 1;
+        NXlen = 12;
+        if (NXmakedata (fileid, "ch_data", NX_CHAR, 1, &NXlen) != NX_OK) return 1;
+        if (NXopendata (fileid, "ch_data") != NX_OK) return 1;
+           if (NXputdata (fileid, "NeXus sample") != NX_OK) return 1;
+        if (NXclosedata (fileid) != NX_OK) return 1;
+        if (NXgetgroupID (fileid, &glink) != NX_OK) return 1;
+        if (( nx_creation_code & NXACC_CREATEXML) == 0 ) {
+            if (NXmakedata (fileid, "cdata_unlimited", NX_CHAR, 2, unlimited_cdims) != NX_OK) return 1;
+	    if (NXopendata (fileid, "cdata_unlimited") != NX_OK) return 1;
+	    slab_size[0] = 1;
+	    slab_size[1] = 4;
+	    slab_start[1] = 0;
+            for (i = 0; i < 5; i++)
+            {
+	       slab_start[0] = i;
+               if (NXputslab (fileid, &(c1_array[i][0]), slab_start, slab_size) != NX_OK) return 1;
+            }
+            if (NXclosedata (fileid) != NX_OK) return 1;
+        }
+     if (NXclosegroup (fileid) != NX_OK) return 1;
+  if (NXclosegroup (fileid) != NX_OK) return 1;
+  if (NXmakegroup (fileid, "link", "NXentry") != NX_OK) return 1;
+  if (NXopengroup (fileid, "link", "NXentry") != NX_OK) return 1;
+     if (NXmakelink (fileid, &glink) != NX_OK) return 1;
+     if (NXmakenamedlink (fileid,"renLinkGroup", &glink) != NX_OK) return 1;
+     if (NXmakenamedlink (fileid, "renLinkData", &dlink) != NX_OK) return 1;
+  if (NXclosegroup (fileid) != NX_OK) return 1;
+  if (NXclose (&fileid) != NX_OK) return 1;
+
+  if ( (argc >= 2) && !strcmp(argv[1], "-q") )
+  {
+     return 0;	/* create only */
+  }
+  /*
+    read test
+  */
+  if (NXopen (nxFile, NXACC_RDWR,&fileid) != NX_OK) return 1;
+  if(NXinquirefile(fileid,filename,256) != NX_OK){
+    return 1;
+  }
+  printf("NXinquirefile found: %s\n", relativePathOf(filename));
+  NXgetattrinfo (fileid, &i);
+  if (i > 0) {
+     printf ("Number of global attributes: %d\n", i);
+  }
+  do { 
+     attr_status = NXgetnextattr (fileid, name, NXdims, &NXtype);
+     if (attr_status == NX_ERROR) return 1;
+     if (attr_status == NX_OK) {
+        switch (NXtype) {
+           case NX_CHAR:
+              NXlen = sizeof (char_buffer);
+              if (NXgetattr (fileid, name, char_buffer, &NXlen, &NXtype) 
+		  != NX_OK) return 1;
+		if ( strcmp(name, "file_time") &&
+		     strcmp(name, "HDF_version") &&
+		     strcmp(name, "HDF5_Version") &&
+		     strcmp(name, "XML_version") )
+		{
+                 printf ("   %s = %s\n", name, char_buffer);
+		}
+              break;
+        }
+     }
+  } while (attr_status == NX_OK);
+  if (NXopengroup (fileid, "entry", "NXentry") != NX_OK) return 1;
+  NXgetattrinfo(fileid,&i);
+  printf("Number of group attributes: %d\n", i);
+  if(NXgetpath(fileid,path,512) != NX_OK)return 1;
+  printf("NXentry path %s\n", path);
+  do { 
+     attr_status = NXgetnextattr (fileid, name, NXdims, &NXtype);
+     if (attr_status == NX_ERROR) return 1;
+     if (attr_status == NX_OK) {
+        switch (NXtype) {
+           case NX_CHAR:
+              NXlen = sizeof (char_buffer);
+              if (NXgetattr (fileid, name, char_buffer, &NXlen, &NXtype) 
+		  != NX_OK) return 1;
+                 printf ("   %s = %s\n", name, char_buffer);
+        }
+     }
+  } while (attr_status == NX_OK);
+  if (NXgetgroupinfo (fileid, &i, group_name, class_name) != NX_OK) return 1;
+     printf ("Group: %s(%s) contains %d items\n", group_name, class_name, i);
+  do {
+     entry_status = NXgetnextentry (fileid, name, char_class, &NXtype);
+     if (entry_status == NX_ERROR) return 1;
+     if (strcmp(char_class,"SDS") != 0) {
+        if (entry_status != NX_EOD) {
+           printf ("   Subgroup: %s(%s)\n", name, char_class);
+           entry_status = NX_OK;
+        }
+     } else {
+        if (entry_status == NX_OK) {
+           if (NXopendata (fileid, name) != NX_OK) return 1;
+	    if(NXgetpath(fileid,path,512) != NX_OK)return 1;
+	    printf("Data path %s\n", path);
+	    if (NXgetinfo (fileid, &NXrank, NXdims, &NXtype) != NX_OK) return 1;
+                 printf ("   %s(%d)", name, NXtype);
+              if (NXmalloc ((void **) &data_buffer, NXrank, NXdims, NXtype) != NX_OK) return 1;
+	      n = 1;
+              for(k=0; k<NXrank; k++)
+	      {
+                  n *= NXdims[k];
+              }
+              if (NXtype == NX_CHAR) {
+                 if (NXgetdata (fileid, data_buffer) != NX_OK) return 1;
+                    print_data (" = ", data_buffer, NXtype, n);
+              } else if (NXtype != NX_FLOAT32 && NXtype != NX_FLOAT64) {
+                 if (NXgetdata (fileid, data_buffer) != NX_OK) return 1;
+                    print_data (" = ", data_buffer, NXtype, n);
+              } else {
+                 slab_start[0] = 0;
+                 slab_start[1] = 0;
+                 slab_size[0] = 1;
+                 slab_size[1] = 4;
+                 if (NXgetslab (fileid, data_buffer, slab_start, slab_size) != NX_OK) return 1;
+                    print_data ("\n      ", data_buffer, NXtype, 4);
+                 slab_start[0] = 1;
+                 if (NXgetslab (fileid, data_buffer, slab_start, slab_size) != NX_OK) return 1;
+                    print_data ("      ", data_buffer, NXtype, 4);
+                 slab_start[0] = 2;
+                 if (NXgetslab (fileid, data_buffer, slab_start, slab_size) != NX_OK) return 1;
+                    print_data ("      ", data_buffer, NXtype, 4);
+                 slab_start[0] = 3;
+                 if (NXgetslab (fileid, data_buffer, slab_start, slab_size) != NX_OK) return 1;
+                    print_data ("      ", data_buffer, NXtype, 4);
+                 slab_start[0] = 4;
+                 if (NXgetslab (fileid, data_buffer, slab_start, slab_size) != NX_OK) return 1;
+                    print_data ("      ", data_buffer, NXtype, 4);
+                 if (NXgetattrinfo (fileid, &i) != NX_OK) return 1;
+                 if (i > 0) {
+                    printf ("      Number of attributes : %d\n", i);
+                 }
+                 do {
+                    attr_status = NXgetnextattr (fileid, name, NXdims, &NXtype);
+                    if (attr_status == NX_ERROR) return 1;
+                    if (attr_status == NX_OK) {
+                       switch (NXtype) {
+                          case NX_INT32:
+                             NXlen = 1;
+                             if (NXgetattr (fileid, name, &i, &NXlen, &NXtype) != NX_OK) return 1;
+                                printf ("         %s : %d\n", name, i);
+                             break;
+                          case NX_FLOAT32:
+                             NXlen = 1;
+                             if (NXgetattr (fileid, name, &r, &NXlen, &NXtype) != NX_OK) return 1;
+                                printf ("         %s : %f\n", name, r);
+                             break;
+                          case NX_CHAR:
+                             NXlen = sizeof (char_buffer);
+                             if (NXgetattr (fileid, name, char_buffer, &NXlen, &NXtype) != NX_OK) return 1;
+                                printf ("         %s : %s\n", name, char_buffer);
+                             break;
+                       }
+                    } 
+                 } while (attr_status == NX_OK);
+              }
+           if (NXclosedata (fileid) != NX_OK) return 1;
+           if (NXfree ((void **) &data_buffer) != NX_OK) return 1;
+        }
+     }
+  } while (entry_status == NX_OK);
+  if (NXclosegroup (fileid) != NX_OK) return 1;
+/*
+ * check links
+ */
+  if (NXopengroup (fileid, "entry", "NXentry") != NX_OK) return 1;
+    if (NXopengroup (fileid, "sample", "NXsample") != NX_OK) return 1;
+      if (NXgetgroupID (fileid, &glink) != NX_OK) return 1;
+    if (NXclosegroup (fileid) != NX_OK) return 1;
+    if (NXopengroup (fileid, "data", "NXdata") != NX_OK) return 1;
+      if (NXopendata (fileid, "r8_data") != NX_OK) return 1;
+        if (NXgetdataID (fileid, &dlink) != NX_OK) return 1;
+      if (NXclosedata (fileid) != NX_OK) return 1;
+    if (NXclosegroup (fileid) != NX_OK) return 1;
+    if (NXopendata (fileid, "r8_data") != NX_OK) return 1;
+      if (NXgetdataID (fileid, &blink) != NX_OK) return 1;
+    if (NXclosedata (fileid) != NX_OK) return 1;
+    if (NXsameID(fileid, &dlink, &blink) != NX_OK)
+    {
+         printf ("Link check FAILED (r8_data)\n");
+         printf ("original data\n");
+	 NXIprintlink(fileid, &dlink);
+         printf ("linked data\n");
+	 NXIprintlink(fileid, &blink);
+	 return 1;
+    }
+  if (NXclosegroup (fileid) != NX_OK) return 1;
+
+  if (NXopengroup (fileid, "link", "NXentry") != NX_OK) return 1;
+    if (NXopengroup (fileid, "sample", "NXsample") != NX_OK) return 1;
+    if(NXgetpath(fileid,path,512) != NX_OK)return 1;
+    printf("Group path %s\n", path);
+      if (NXgetgroupID (fileid, &blink) != NX_OK) return 1;
+        if (NXsameID(fileid, &glink, &blink) != NX_OK)
+	{
+             printf ("Link check FAILED (sample)\n");
+             printf ("original group\n");
+	     NXIprintlink(fileid, &glink);
+             printf ("linked group\n");
+	     NXIprintlink(fileid, &blink);
+	     return 1;
+	}
+      if (NXclosegroup (fileid) != NX_OK) return 1;
+
+    if (NXopengroup (fileid, "renLinkGroup", "NXsample") != NX_OK) return 1;
+      if (NXgetgroupID (fileid, &blink) != NX_OK) return 1;
+        if (NXsameID(fileid, &glink, &blink) != NX_OK)
+	{
+             printf ("Link check FAILED (renLinkGroup)\n");
+             printf ("original group\n");
+	     NXIprintlink(fileid, &glink);
+             printf ("linked group\n");
+	     NXIprintlink(fileid, &blink);
+	     return 1;
+	}
+      if (NXclosegroup (fileid) != NX_OK) return 1;
+
+    if(NXopendata(fileid,"renLinkData") != NX_OK) return 1;
+      if(NXgetdataID(fileid,&blink) != NX_OK) return 1;
+        if (NXsameID(fileid, &dlink, &blink) != NX_OK)
+	{
+             printf ("Link check FAILED (renLinkData)\n");
+             printf ("original group\n");
+	     NXIprintlink(fileid, &glink);
+             printf ("linked group\n");
+	     NXIprintlink(fileid, &blink);
+	     return 1;
+	}
+    if(NXclosedata(fileid) != NX_OK) return 1;	
+  if (NXclosegroup (fileid) != NX_OK) return 1;
+  printf ("Link check OK\n");
+
+  /*
+    tests for NXopenpath
+  */
+  if(NXopenpath(fileid,"/entry/data/comp_data") != NX_OK){
+    printf("Failure on NXopenpath\n");
+    return 0;
+  }
+  if(NXopenpath(fileid,"/entry/data/comp_data") != NX_OK){
+    printf("Failure on NXopenpath\n");
+    return 0;
+  }
+  if(NXopenpath(fileid,"../r8_data") != NX_OK){
+    printf("Failure on NXopenpath\n");
+    return 0;
+  }
+  if(NXopengrouppath(fileid,"/entry/data/comp_data") != NX_OK){
+    printf("Failure on NXopengrouppath\n");
+    return 0;
+  }
+  if(NXopenpath(fileid,"/entry/data/r8_data") != NX_OK){
+    printf("Failure on NXopenpath\n");
+    return 0;
+  }
+  printf("NXopenpath checks OK\n");
+
+  if (NXclose (&fileid) != NX_OK) return 1;
+
+  printf("before load path tests\n");
+  if(testLoadPath() != 0) return 1;
+
+  printf("before external link tests\n");
+  if(testExternal(argv[0]) != 0) {
+    return 1;
+  }
+
+  printf("all ok - done\n");
+  return 0;
+}
+/*---------------------------------------------------------------------*/
+static int testLoadPath() {
+  NXhandle h;
+
+  if(getenv("NX_LOAD_PATH") != NULL){
+    if (NXopen ("dmc01.hdf", NXACC_RDWR,&h) != NX_OK) {
+      printf("Loading NeXus file dmc01.hdf from path %s FAILED\n", getenv("NX_LOAD_PATH"));   
+      return 1;
+    } else {
+      printf("Success loading NeXus file from path\n");
+      NXclose(&h);
+      return 0;
+    }
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------*/
+static int testExternal(char *progName){
+  char nxfile[255], ext[5], testFile[80], time[132], filename[256];
+  int create;
+  NXhandle hfil;
+  int dummylen = 1;
+  float dummyfloat = 1;
+  float temperature;
+
+  if(strstr(progName,"hdf4") != NULL){
+    strcpy(ext,"hdf");
+    create = NXACC_CREATE;
+  } else if(strstr(progName,"hdf5") != NULL){
+    strcpy(ext,"h5");
+    create = NXACC_CREATE5;
+  } else if(strstr(progName,"xml") != NULL){
+    strcpy(ext,"xml");
+    create = NXACC_CREATEXML;
+  } else {
+    printf("Failed to recognise napi_test program in testExternal\n");
+    return 1;
+  }
+
+  sprintf(testFile,"nxext.%s", ext);
+
+  /*
+    create the test file
+  */
+  if(NXopen(testFile,create,&hfil) != NX_OK){
+    return 1;
+  }
+  /*if(NXmakegroup(hfil,"entry1","NXentry") != NX_OK){
+    return 1;
+  }*/
+  sprintf(nxfile,"nxfile://data/dmc01.%s#/entry1",ext);
+  if(NXlinkexternal(hfil,"entry1","NXentry",nxfile) != NX_OK){
+    return 1;
+  }
+  /*if(NXmakegroup(hfil,"entry2","NXentry") != NX_OK){
+    return 1;
+  }*/
+  sprintf(nxfile,"nxfile://data/dmc02.%s#/entry1",ext);
+  if(NXlinkexternal(hfil,"entry2","NXentry",nxfile) != NX_OK){
+    return 1;
+  }
+  if(NXmakegroup(hfil,"entry3","NXentry") != NX_OK){
+    return 1;
+  }
+  if(NXopengroup(hfil,"entry3","NXentry") != NX_OK){
+    return 1;
+  }
+  /* force create old style external link */
+  if (NXmakedata (hfil, "extlinkdata", NX_FLOAT32, 1, &dummylen) != NX_OK) return 1;
+  if (NXopendata (hfil, "extlinkdata") != NX_OK) return 1;
+  if (NXputdata (hfil, &dummyfloat) != NX_OK) return 1;
+  sprintf(nxfile,"nxfile://data/dmc01.%s#/entry1/sample/temperature_mean",ext);
+  if(NXputattr(hfil,"napimount",nxfile,strlen(nxfile), NX_CHAR) != NX_OK) return 1;
+  /* this would segfault because we are tricking the napi stack
+  if(NXclosedata(&hfil) != NX_OK){
+    return 1;
+  }
+  */
+  if(NXopenpath(hfil,"/entry3") != NX_OK){
+    return 1;
+  }
+  /* create new style external link on hdf5 , equivalent to the above on other backends */
+  if (NXlinkexternaldataset(hfil, "extlinknative", nxfile) != NX_OK) return 1;
+
+  if(NXclose(&hfil) != NX_OK){
+    return 1;
+  }
+
+  /*
+    actually test linking
+  */
+  if(NXopen(testFile,NXACC_RDWR,&hfil) != NX_OK){
+    return 1;
+  }
+  if(NXopenpath(hfil,"/entry1/start_time") != NX_OK){
+    return 1;
+  }
+  memset(time,0,132);
+  if(NXgetdata(hfil,time) != NX_OK){
+    return 1;
+  }
+  printf("First file time: %s\n", time);
+
+  if(NXinquirefile(hfil,filename,256) != NX_OK){
+    return 1;
+  }
+  printf("NXinquirefile found: %s\n", relativePathOf(filename));
+
+  if(NXopenpath(hfil,"/entry2/sample/sample_name") != NX_OK){
+    return 1;
+  }
+  memset(time,0,132);
+  if(NXgetdata(hfil,time) != NX_OK){
+    return 1;
+  }
+  printf("Second file sample: %s\n", time);
+  if(NXinquirefile(hfil,filename,256) != NX_OK){
+    return 1;
+  }
+  printf("NXinquirefile found: %s\n", relativePathOf(filename));
+
+  if(NXopenpath(hfil,"/entry2/start_time") != NX_OK){
+    return 1;
+  }
+  memset(time,0,132);
+  if(NXgetdata(hfil,time) != NX_OK){
+    return 1;
+  }
+  printf("Second file time: %s\n", time);
+  NXopenpath(hfil,"/");
+  if(NXisexternalgroup(hfil,"entry1","NXentry",filename,255) != NX_OK){
+    return 1;
+  } else {
+    printf("entry1 external URL = %s\n", filename);
+  }
+
+  printf("testing link to external data set\n");
+  if(NXopenpath(hfil,"/entry3") != NX_OK){
+    return 1;
+  }
+  if(NXisexternaldataset(hfil,"extlinkdata",filename,255) != NX_OK){
+    printf("extlinkdata should be external link\n");
+    return 1;
+  } else {
+    printf("extlinkdata external URL = %s\n", filename);
+  }
+  if (NXopendata (hfil, "extlinkdata") != NX_OK) return 1;
+  memset(&temperature,0,4);
+  if(NXgetdata(hfil,&temperature) != NX_OK){
+    return 1;
+  }
+  printf("value retrieved: %4.2f\n", temperature);
+
+  if(NXopenpath(hfil,"/entry3") != NX_OK){
+    return 1;
+  }
+  if(NXisexternaldataset(hfil,"extlinknative",filename,255) != NX_OK){
+    printf("extlinknative should be external link\n");
+    return 1;
+  } else {
+    printf("extlinknative external URL = %s\n", filename);
+  }
+  if (NXopendata (hfil, "extlinknative") != NX_OK) return 1;
+  memset(&temperature,0,4);
+  if(NXgetdata(hfil,&temperature) != NX_OK){
+    return 1;
+  }
+  printf("value retrieved: %4.2f\n", temperature);
+
+  NXclose(&hfil);
+  printf("External File Linking tested OK\n");
+  return 0;
+}
+/*----------------------------------------------------------------------*/
+static void
+print_data (const char *prefix, void *data, int type, int num)
+{
+  int i;
+  printf ("%s", prefix);
+  for (i = 0; i < num; i++) {
+      switch (type) {
+        case NX_CHAR:
+           printf ("%c", ((char *) data)[i]);
+           break;
+
+        case NX_INT8:
+           printf (" %d", ((unsigned char *) data)[i]);
+           break;
+
+        case NX_INT16:
+           printf (" %d", ((short *) data)[i]);
+           break;
+
+        case NX_INT32:
+           printf (" %d", ((int *) data)[i]);
+           break;
+
+        case NX_INT64:
+           printf (" %lld", (long long)((int64_t *) data)[i]);
+           break;
+
+        case NX_UINT64:
+           printf (" %llu", (unsigned long long)((uint64_t *) data)[i]);
+           break;
+
+        case NX_FLOAT32:
+           printf (" %f", ((float *) data)[i]);
+           break;
+
+        case NX_FLOAT64:
+           printf (" %f", ((double *) data)[i]);
+           break;
+
+        default:
+           printf ("print_data: invalid type");
+           break;
+        }
+     }
+  printf ("\n");
+}
diff --git a/test/napi_test_cpp.cxx b/test/napi_test_cpp.cxx
new file mode 100644
index 0000000..7992652
--- /dev/null
+++ b/test/napi_test_cpp.cxx
@@ -0,0 +1,636 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
+#include <vector>
+#include <map>
+#include "napiconfig.h"
+#include "NeXusFile.hpp"
+#include <unistd.h>
+
+using std::cout;
+using std::endl;
+using std::map;
+using std::multimap;
+using std::string;
+using std::vector;
+
+static std::string relativePathOf(const std::string& filenamestr) {
+  char cwd[1024];
+
+  getcwd(cwd, sizeof(cwd));
+  
+  if ( filenamestr.compare(0, strlen(cwd), cwd) == 0 )
+  {
+      return filenamestr.substr(strlen(cwd)+1);  // +1 to skip trailing /
+  }
+  else
+  {
+      return filenamestr;
+  }
+}
+
+static int writeTest(const string& filename, NXaccess create_code) {
+  NeXus::File file(filename, create_code);
+  // create group
+  file.makeGroup("entry", "NXentry", true);
+  // group attributes
+  file.putAttr("hugo", "namenlos");
+  file.putAttr("cucumber", "passion");
+  // put string
+  file.writeData("ch_data", "NeXus_data");
+
+  // 2d array
+  vector<int> array_dims;
+  array_dims.push_back(5);
+  array_dims.push_back(4);
+  char c1_array[5][4] = {{'a', 'b', 'c' ,'d'}, {'e', 'f', 'g' ,'h'}, 
+                         {'i', 'j', 'k', 'l'}, {'m', 'n', 'o', 'p'},
+                         {'q', 'r', 's' , 't'}};
+  file.makeData("c1_data", NeXus::CHAR, array_dims, true);
+  file.putData(c1_array);
+  file.closeData();
+
+  // 1d uint8 array
+  vector<uint8_t> i1_array;
+  for (size_t i = 0; i < 4; i++) {
+    i1_array.push_back(static_cast<uint8_t>(i+1));
+  }
+  file.writeData("i1_data", i1_array);
+
+  // 1d int16 array
+  vector<int16_t> i2_array;
+  for (size_t i = 0; i < 4; i++) {
+    i2_array.push_back(1000*(i+1));
+  }
+  file.writeData("i2_data", i2_array);
+
+  // 1d int32 data
+  vector<int32_t> i4_array;
+  for (size_t i = 0; i < 4; i++) {
+    i4_array.push_back(1000000*(i+1));
+  }
+  file.writeData("i4_data", i4_array);
+
+  // 2d float data
+  vector<float> r4_array;
+  for (size_t i = 0; i < 5*4; i++) {
+    r4_array.push_back(static_cast<float>(i));
+  }
+  file.writeData("r4_data", r4_array, array_dims);
+
+  // 2d double data - slab test
+  vector<double> r8_array;
+  for (size_t i = 0; i < 5*4; i++) {
+    r8_array.push_back(static_cast<double>(i+20));
+  }
+  file.makeData("r8_data", NeXus::FLOAT64, array_dims, true);
+  vector<int> slab_start;
+  slab_start.push_back(4);
+  slab_start.push_back(0);
+  vector<int> slab_size;
+  slab_size.push_back(1);
+  slab_size.push_back(4);
+  file.putSlab(&(r8_array[16]), slab_start, slab_size);
+  slab_start[0] = 0;
+  slab_start[1] = 0;
+  slab_size[0]=4;
+  slab_size[1]=4;
+  file.putSlab(&(r8_array[0]), slab_start, slab_size);
+
+  // add some attributes
+  file.putAttr("ch_attribute", "NeXus");
+  file.putAttr("i4_attribute", 42);
+  file.putAttr("r4_attribute", 3.14159265);
+
+  // set up for creating a link
+  NXlink link = file.getDataID();
+  file.closeData();
+
+  // int64 tests
+  vector<int64_t> grossezahl;
+#if HAVE_LONG_LONG_INT
+  grossezahl.push_back(12);
+  grossezahl.push_back(555555555555LL);
+  grossezahl.push_back(23);
+  grossezahl.push_back(777777777777LL);
+#else
+  grossezahl.push_back(12);
+  grossezahl.push_back(555555);
+  grossezahl.push_back(23);
+  grossezahl.push_back(77777);
+#endif
+  if (create_code != NXACC_CREATE) {
+    file.writeData("grosszahl", grossezahl);
+  }
+
+  // create a new group inside this one
+  file.makeGroup("data", "NXdata", true);
+
+  // create a link
+  file.makeLink(link);
+
+  // compressed data
+  array_dims[0] = 100;
+  array_dims[1] = 20;
+  vector<int> comp_array;
+  for (int i = 0; i < array_dims[0]; i++) {
+    for (int j = 0; j < array_dims[1]; j++) {
+      comp_array.push_back(i);
+    }
+  }
+  vector<int> cdims;
+  cdims.push_back(20);
+  cdims.push_back(20);
+  file.writeCompData("comp_data", comp_array, array_dims, NeXus::LZW, cdims);
+
+  // ---------- Test write Extendible Data --------------------------
+  std::vector<int> data(10, 123);
+  file.makeGroup("extendible_data", "NXdata", 1);
+  file.writeExtendibleData("mydata1", data);
+  file.writeExtendibleData("mydata2", data, 1000);
+  std::vector<int64_t> dims(2);
+  dims[0] = 5;
+  dims[1] = 2;
+  std::vector<int64_t> chunk(2, 2);
+  file.writeExtendibleData("my2Ddata", data, dims, chunk);
+  file.putAttr("string_attrib", "some short string");
+
+  // Data vector can grow
+  for (size_t i=0; i<6; i++)
+    data.push_back(456);
+  data[0]=789;
+  file.writeUpdatedData("mydata1", data);
+
+  dims[0] = 8;
+  dims[1] = 2;
+  file.writeUpdatedData("my2Ddata", data, dims);
+
+  // Data vector can also shrink!
+  data.clear();
+  data.resize(5, 234);
+  file.writeUpdatedData("mydata2", data);
+
+  // Exit the group
+  file.closeGroup();
+  // ---------- End Test write Extendible Data --------------------------
+
+  // simple flush test
+  file.flush();
+
+  // real flush test
+  file.makeData("flush_data", NeXus::getType<int>(), NX_UNLIMITED, true);
+  vector<int> slab_array;
+  slab_array.push_back(0);
+  for (int i = 0 ; i < 7; i++) {
+    slab_array[0] = i;
+    file.putSlab(slab_array, i, 1);
+    file.flush();
+    file.openData("flush_data");
+  }
+  file.closeData();
+  file.closeGroup();
+
+  // create a sample
+  file.makeGroup("sample", "NXsample", true);
+  file.writeData("ch_data", "NeXus sample");
+
+  // make more links
+  NXlink glink = file.getGroupID();
+  file.openPath("/");
+  file.makeGroup("link", "NXentry", true);
+  file.makeLink(glink);
+  file.makeNamedLink("renLinkGroup", glink);
+  file.makeNamedLink("renLinkData", link);
+
+  return 0;
+}
+
+template <typename NumT>
+string toString(const vector<NumT> & data) {
+  std::stringstream result;
+  result << "[";
+  size_t size = data.size();
+  for (size_t i = 0; i < size; i++) {
+    result << data[i];
+    if (i+1 < size) {
+      result << ",";
+    }
+  }
+  result << "]";
+  return result.str();
+}
+
+int readTest(const string & filename) {
+  const string SDS("SDS");
+  // top level file information
+  NeXus::File file(filename);
+  cout << "NXinquirefile found: " << relativePathOf(file.inquireFile()) << endl;
+  vector<NeXus::AttrInfo> attr_infos = file.getAttrInfos();
+  cout << "Number of global attributes: " << attr_infos.size() << endl;
+  for (vector<NeXus::AttrInfo>::iterator it = attr_infos.begin();
+       it != attr_infos.end(); it++) {
+    if (it->name != "file_time" && it->name != "HDF_version" && it->name !=  "HDF5_Version" && it->name != "XML_version") {
+        cout << "   " << it->name << " = ";
+        if (it->type == NeXus::CHAR) {
+          cout << file.getStrAttr(*it);
+        }
+        cout << endl;
+    }
+  }
+
+  // check group attributes
+  file.openGroup("entry", "NXentry");
+  attr_infos = file.getAttrInfos();
+  cout << "Number of group attributes: " << attr_infos.size() << endl;
+  for (vector<NeXus::AttrInfo>::iterator it = attr_infos.begin();
+       it != attr_infos.end(); it++) {
+    cout << "   " << it->name << " = ";
+    if (it->type == NeXus::CHAR) {
+      cout << file.getStrAttr(*it);
+    }
+    cout << endl;
+  }
+
+  // print out the entry level fields
+  map<string, string> entries = file.getEntries();
+  cout << "Group contains " << entries.size() << " items" << endl;
+  NeXus::Info info;
+  for (map<string,string>::const_iterator it = entries.begin();
+       it != entries.end(); it++) {
+    cout << "   " << it->first;
+    if (it->second == SDS) {
+      file.openData(it->first);
+      info = file.getInfo();
+      cout << toString(info.dims) << " = ";
+      if (info.type == NeXus::CHAR) {
+        if (info.dims.size()==1) {
+          cout << file.getStrData();
+        }
+        else {
+          cout << "2d character array";
+        }
+      }
+      else if (info.type == NeXus::FLOAT32) {
+        vector<float> * result = file.getData<float>();
+        cout << toString(*result);
+        delete result;
+      }
+      else if (info.type == NeXus::FLOAT64) {
+        vector<double>  * result = file.getData<double>();
+        cout << toString(*result);
+        delete result;
+      }
+      else if (info.type == NeXus::INT8) {
+        vector<int8_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::UINT8) {
+        vector<uint8_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::INT16) {
+        vector<int16_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::UINT16) {
+        vector<uint16_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::INT32) {
+        vector<int32_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::UINT32) {
+        vector<uint32_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::INT64) {
+        vector<int64_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      else if (info.type == NeXus::UINT64) {
+        vector<uint64_t> result;
+	file.getData(result);
+        cout << toString(result);
+      }
+      cout <<  endl;
+      cout << "   Path = " << file.getPath() << endl;
+      file.closeData();
+    }
+    else {
+      cout << ":" << it->second << endl;
+    }
+  }
+
+	// Test getDataCoerce() -------------------
+	std::vector<int> ints;
+	std::vector<double> doubles;
+	
+	ints.clear();
+	file.openData("i1_data");
+	file.getDataCoerce(ints);
+	if (ints.size() != 4) return 1;
+	if (ints[0] != 1) return 1;
+	file.closeData();
+
+	ints.clear();
+	file.openData("i2_data");
+	file.getDataCoerce(ints);
+	if (ints.size() != 4) return 1;
+	if (ints[0] != 1000) return 1;
+	file.closeData();
+
+	ints.clear();
+	file.openData("i4_data");
+	file.getDataCoerce(ints);
+	if (ints.size() != 4) return 1;
+	if (ints[0] != 1000000) return 1;
+	file.closeData();
+
+	doubles.clear();
+	file.openData("r4_data");
+	file.getDataCoerce(doubles);
+	if (doubles.size() != 20) return 1;
+	if (doubles[1] != 1.0) return 1;
+	file.closeData();
+
+	doubles.clear();
+	file.openData("r8_data");
+	file.getDataCoerce(doubles);
+	if (doubles.size() != 20) return 1;
+	if (doubles[1] != 21.0) return 1;
+	file.closeData();
+
+	// Throws when you coerce to int from a real/double source
+	bool didThrow = false;
+	try 
+	{
+		ints.clear();
+		file.openData("r8_data");
+		file.getDataCoerce(ints);
+		file.closeData();
+		cout << "getDataCoerce(int) of doubles did not throw (it is supposed to throw)." << endl;
+	}
+	catch (...)
+	{
+		// Good! It is supposed to throw
+		didThrow = true;
+		file.closeData();
+	}
+	if (!didThrow) return 1;
+
+
+  // Close the "entry" group
+  file.closeGroup();
+
+  // check links
+  file.openGroup("entry", "NXentry");
+  file.openGroup("sample", "NXsample");
+  NXlink glink = file.getGroupID();
+  file.closeGroup();
+  file.openGroup("data", "NXdata");
+  file.openData("r8_data");
+  NXlink dlink = file.getDataID();
+  file.closeData();
+  file.closeGroup();
+  file.openData("r8_data");
+  NXlink d2link = file.getDataID();
+  file.closeData();
+  if (!file.sameID(dlink, d2link)) {
+    cout << "Link check FAILED (r8_data)" << endl;
+    cout << "     original data = ";
+    file.printLink(dlink);
+    cout << "     linked data = ";
+    file.printLink(d2link);
+    return 1;
+  }
+  file.closeGroup();
+
+  file.openGroup("link", "NXentry");
+  file.openGroup("sample", "NXsample");
+  NXlink g2link = file.getGroupID();
+  if (!file.sameID(glink, g2link)) {
+    cout << "Link check FAILED (sample)" << endl;
+    cout << "     original group = ";
+    file.printLink(glink);
+    cout << "     linked group = ";
+    file.printLink(g2link);
+    return 1;
+  }
+  file.closeGroup();
+
+  file.openGroup("renLinkGroup", "NXsample");
+  g2link = file.getGroupID();
+  file.closeGroup();
+  if (!file.sameID(glink, g2link)) {
+    cout << "Link check FAILED (renLinkGroup)" << endl;
+    cout << "     original group = ";
+    file.printLink(glink);
+    cout << "     linked group = ";
+    file.printLink(g2link);
+    return 1;
+  }
+
+  file.openData("renLinkData");
+  d2link = file.getDataID();
+  file.closeData();
+  if (!file.sameID(dlink, d2link)) {
+    cout << "Link check FAILED (renLinkData)" << endl;
+    cout << "     original data = ";
+    file.printLink(dlink);
+    cout << "     linked data = ";
+    file.printLink(d2link);
+    return 1;
+  }
+
+  file.closeGroup();
+  cout << "Link check OK" << endl;
+
+  // openpath checks
+  file.openPath("/entry/data/comp_data");
+  file.openPath("/entry/data/comp_data");
+  file.openPath("../r8_data");
+  printf("NXopenpath checks OK\n");
+
+  // everything went fine
+  return 0;
+}
+
+int testLoadPath(const string & filename) {
+  if(getenv("NX_LOAD_PATH") != NULL){
+    NeXus::File file(filename);
+    cout << "Success loading NeXus file from path" << endl;
+    // cout << file.inquireFile() << endl; // DEBUG print
+  }
+  return 0;
+}
+
+int testExternal(const string & fileext, NXaccess create_code){
+  string filename("nxext_cpp" + fileext);
+  string exturl1("nxfile://data/dmc01" + fileext+"#entry1");
+  string exturl2("nxfile://data/dmc02" + fileext+"#entry1");
+
+  // create the external link
+  NeXus::File fileout(filename, create_code);
+  fileout.linkExternal("entry1", "NXentry", exturl1);
+  fileout.linkExternal("entry2", "NXentry", exturl2);
+  fileout.close();
+
+  // read the file to make sure things worked
+  NeXus::File filein(filename);
+  filein.openPath("/entry1/start_time");
+  cout << "First file time: " << filein.getStrData() << endl;
+  cout << "NXinquirefile found: " << relativePathOf(filein.inquireFile()) << endl;
+  filein.openPath("/entry2/sample/sample_name");
+  cout << "Second file sample: " << filein.getStrData() << endl;
+  cout << "NXinquirefile found: " << relativePathOf(filein.inquireFile()) << endl;
+  filein.openPath("/entry2/start_time");
+  cout << "Second file time: " << filein.getStrData() << endl;
+  filein.openPath("/");
+  cout << "entry1 external URL = "
+       << filein.isExternalGroup("entry1", "NXentry") << endl;
+
+  return 0;
+}
+
+static int streamTest(const std::string& fname, NXaccess create_mode)
+{
+    using namespace NeXus;
+    using namespace NeXus::Stream;
+    std::vector<double> w;
+    std::vector<double> w1;
+    w.push_back(1.0);
+    double d, d1;
+    int i;
+    // create an entry and a data item
+    File nf(fname, create_mode);
+    nf << Group("entry1", "NXentry") << Data("dat1", w, "int_attr", 3);
+    nf.close();
+    File nf1(fname, NXACC_RDWR);
+    // add a double_attr to an existing setup
+    nf1 >> Group("entry1", "NXentry") >> Data("dat1") << Attr("double_attr", 6.0) << Close;
+    nf1.close();
+    // read back data items
+    File nf2(fname, NXACC_READ);
+    nf2 >> Group("entry1", "NXentry") >> Data("dat1", w1, "int_attr", i, "double_attr", d);
+    // alternative way to read d1
+    nf2 >> Data("dat1") >> Attr("double_attr", d1);
+    nf2.close();
+    if (i != 3 || w != w1 || d != 6.0 || d1 != 6.0)
+    {
+	return 1;
+    }
+    return 0;
+}
+
+int testTypeMap(const std::string &fname)
+{
+	NeXus::File file(fname);
+	multimap<string, string> *map = file.getTypeMap();
+	size_t mapsize = 25;
+	// HDF4 does not have int64 capability, so resulting map is one shorter than HDF5 and XML files
+	if (fname == string("napi_test_cpp.hdf")) {
+		if (map->size() != (mapsize - 1))
+		{
+			cout << "TypeMap is incorrect" << endl;
+			return 1;
+		}
+	}
+	else {
+		if (map->size() != mapsize)
+		{
+			cout << "TypeMap is incorrect" << endl;
+			return 1;
+		}
+	}
+
+	cout << "TypeMap is correct size" << endl;
+
+	return 0;
+}
+
+int main(int argc, char** argv)
+{
+  NXaccess nx_creation_code;
+  string filename;
+  string extfile_ext;
+  if(strstr(argv[0],"napi_test_cpp-hdf5") != NULL){
+    nx_creation_code = NXACC_CREATE5;
+    filename = "napi_test_cpp.h5";
+    extfile_ext = ".h5";
+  }else if(strstr(argv[0],"napi_test_cpp-xml-table") != NULL){
+    nx_creation_code = NXACC_CREATEXML | NXACC_TABLE;
+    filename = "napi_test_cpp-table.xml";
+    extfile_ext = "-table.xml";
+  }else if(strstr(argv[0],"napi_test_cpp-xml") != NULL){
+    nx_creation_code = NXACC_CREATEXML;
+    filename = "napi_test_cpp.xml";
+    extfile_ext = ".xml";
+  } else {
+    nx_creation_code = NXACC_CREATE;
+    filename = "napi_test_cpp.hdf";
+    extfile_ext = ".hdf";
+  }
+
+  int result;
+  result = writeTest(filename, nx_creation_code);
+  if (result) {
+    cout << "writeTest failed" << endl;
+    return result;
+  }
+  if ( (argc >= 2) && !strcmp(argv[1], "-q") )
+  {
+    return 0;	//
+  }
+
+  // try reading a file
+  result = readTest(filename);
+  if (result) {
+    cout << "readTest failed" << endl;
+    return result;
+  }
+
+  // try using the load path
+  result = testLoadPath("dmc01.hdf");
+  if (result) {
+    cout << "testLoadPath failed" << endl;
+    return result;
+  }
+
+  // try external linking
+  result = testExternal(extfile_ext, nx_creation_code);
+  if (result) {
+    cout << "testExternal failed" << endl;
+    return result;
+  }
+
+
+  // quick test of stream interface
+  std::string fname = string("stream_test") + extfile_ext;
+  result = streamTest(fname, nx_creation_code);
+  remove(fname.c_str());
+  if (result) {
+    cout << "streamTest failed" << endl;
+    return result;
+  }
+
+  // test of typemap generation
+  result = testTypeMap(filename);
+  if (result) {
+	  cout << "testTypeMap failed" << endl;
+	  return result;
+  }
+
+  // everything went ok
+  return 0;
+}
diff --git a/test/napif4_test.f b/test/napif4_test.f
new file mode 100644
index 0000000..3a405e2
--- /dev/null
+++ b/test/napif4_test.f
@@ -0,0 +1,326 @@
+C------------------------------------------------------------------------------
+C NeXus - Neutron & X-ray Common Data Format
+C  
+C Test program for NeXus FORTRAN 77 interface
+C
+C Copyright (C) 1997-2002, Freddie Akeroyd
+C
+C This library is free software; you can redistribute it and/or
+C modify it under the terms of the GNU Lesser General Public
+C License as published by the Free Software Foundation; either
+C version 2 of the License, or (at your option) any later version.
+C
+C This library is distributed in the hope that it will be useful,
+C but WITHOUT ANY WARRANTY; without even the implied warranty of
+C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+C Lesser General Public License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public
+C License along with this library; if not, write to the Free Software
+C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+C
+C  For further information, see <http://www.nexusformat.org>
+C
+C $Id$
+C------------------------------------------------------------------------------
+
+      INCLUDE 'napif.inc'
+      INTEGER NXRANK, NXDIMS(NX_MAXRANK), NXTYPE, NXLEN
+      INTEGER ENTRY_STATUS, ATTR_STATUS, STAT
+      INTEGER*4 I, J
+      REAL*4 R
+      INTEGER*1 I1_ARRAY(4)
+      INTEGER*2 I2_ARRAY(4)
+      INTEGER*4 I4_ARRAY(4) 
+      REAL*4 R4_ARRAY(4,5)
+      REAL*8 R8_ARRAY(4,5)
+      INTEGER*4 ARRAY_DIMS(2), UNLIMITED_DIMS(1)
+      INTEGER*4 CHUNK_SIZE(2)
+      INTEGER*4 SLAB_START(2), SLAB_SIZE(2)
+      CHARACTER*64 NAME, CLASS
+      CHARACTER*128 CHAR_BUFFER
+      INTEGER*1 CHAR_BUFFER_B(128)
+      CHARACTER*64 GROUP_NAME, CLASS_NAME, PATH
+      INTEGER FILEID(NXHANDLESIZE)
+      INTEGER GLINK(NXLINKSIZE), DLINK(NXLINKSIZE), BLINK(NXLINKSIZE)
+      INTEGER*4 COMP_ARRAY(20,100)
+      INTEGER*4 DIMS(2), CDIMS(2), UDIMS(1)
+      INTEGER*1 I1_BUFFER(4)
+      INTEGER*2 I2_BUFFER(4)
+      INTEGER*4 I4_BUFFER(4), U_BUFFER(7)
+      REAL*4 R4_BUFFER(4)
+      REAL*8 R8_BUFFER(16)
+      DATA I1_ARRAY /1, 2, 3, 4/
+      DATA I2_ARRAY /1000, 2000, 3000, 4000/
+      DATA I4_ARRAY /1000000, 2000000, 3000000, 4000000/
+      DATA R4_ARRAY /1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA R8_ARRAY/1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA ARRAY_DIMS /4, 5/
+      DATA CHUNK_SIZE /4, 5/
+      DATA U_BUFFER /0,1,2,3,4,5,6/
+      EQUIVALENCE (CHAR_BUFFER, CHAR_BUFFER_B)
+
+      IF (NXOPEN('NXtest.nxs', NXACC_CREATE, FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 10) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus data') .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i1_data', NX_INT8, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i1_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I1_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i2_data', NX_INT16, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i2_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I2_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i4_data', NX_INT32, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXCOMPMAKEDATA(FILEID, 'r4_data', NX_FLOAT32, 2, 
+     +        ARRAY_DIMS, NX_COMP_LZW, CHUNK_SIZE) .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, R4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'r8_data', NX_FLOAT64, 2, ARRAY_DIMS) 
+     +        .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r8_data') .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 5
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXPUTSLAB(FILEID, R8_ARRAY(1,5), SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 4
+            IF (NXPUTSLAB(FILEID, R8_ARRAY, SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTCHARATTR(FILEID, 'ch_attribute', 'NeXus',5,NX_CHAR) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'i4_attribute', 42, 1, NX_INT32) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'r4_attribute', 3.14159265, 1, 
+     +        NX_FLOAT32) .NE. NX_OK) STOP
+            IF (NXGETDATAID(FILEID, DLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+            IF (NXMAKELINK(FILEID, DLINK) .NE. NX_OK) STOP
+            DIMS(1) = 20
+            DIMS(2) = 100
+            DO I = 1,100
+               DO J = 1,20
+                  COMP_ARRAY(J,I) = I-1
+               END DO
+            END DO
+            CDIMS(1) = 20
+            CDIMS(2) = 20
+            IF (NXCOMPMAKEDATA(FILEID, 'comp_data', NX_INT32, 2, DIMS, 
+     +        NX_COMP_LZW, CDIMS) .NE. NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'comp_data') .NE. NX_OK) STOP
+               IF (NXPUTDATA(FILEID, COMP_ARRAY) .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+            UDIMS(1) = NX_UNLIMITED
+            IF (NXMAKEDATA(FILEID, 'flush_data', NX_INT32, 1, UDIMS) 
+     +        .NE. NX_OK) STOP
+               SLAB_SIZE(1) = 1
+               DO I = 1,7
+                  SLAB_START(1) = I
+                  IF (NXOPENDATA(FILEID, 'flush_data') .NE. NX_OK) STOP
+                     IF (NXPUTSLAB(FILEID, U_BUFFER(I), SLAB_START, 
+     +                 SLAB_SIZE) .NE. NX_OK) STOP
+                     STAT = NXCLOSEDATA(FILEID)
+                     IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+               END DO
+         IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+            IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 12) .NE. 
+     +        NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus sample') .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXMAKELINK (fileid, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+C *** read data
+      IF (NXOPEN('NXtest.nxs', NXACC_READ, FILEID) .NE. NX_OK) STOP
+      IF (NXGETATTRINFO(FILEID, J) .NE. NX_OK) STOP
+      IF (J .GT. 0) WRITE(*,'(1X,A,I2)') 
+     +  'Number of global attributes: ', J
+      DO I = 1,J
+         ATTR_STATUS = NXGETNEXTATTR(FILEID,NAME,NXDIMS,NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) THEN
+            STOP
+         ELSE IF (ATTR_STATUS .EQ. NX_OK) THEN
+            NXLEN = LEN(CHAR_BUFFER)
+            IF (NXGETCHARATTR(FILEID, NAME, CHAR_BUFFER, NXLEN, NXTYPE)
+     +        .NE. NX_OK) STOP
+	    IF ((NAME .NE. 'HDF_version') .AND. 
+     +                       (NAME .NE. 'file_time')) THEN
+               WRITE(*,'(4X,A)') NAME(1:LEN_TRIM(NAME))//' = '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+	    END IF
+         END IF
+      END DO
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXGETGROUPINFO(FILEID, I, GROUP_NAME, CLASS_NAME) .NE. 
+     +     NX_OK) STOP
+         WRITE(*,'(1X,A,I2,A)') 'Group: '
+     +     //GROUP_NAME(1:LEN_TRIM(GROUP_NAME))//'('
+     +     //CLASS_NAME(1:LEN_TRIM(CLASS_NAME))
+     +     //') contains ',I,' items'
+  100 ENTRY_STATUS=NXGETNEXTENTRY(FILEID,NAME,CLASS,NXTYPE)
+      IF (ENTRY_STATUS .EQ. NX_ERROR) STOP
+      IF (CLASS(1:LEN_TRIM(CLASS)) .NE. 'SDS') THEN
+         IF (ENTRY_STATUS .NE. NX_EOD) THEN
+            WRITE(*,'(4X,A)') 'Subgroup: '//NAME(1:LEN_TRIM(NAME))//'('
+     +        //CLASS(1:LEN_TRIM(CLASS))//')'
+            ENTRY_STATUS = NX_OK
+         END IF
+      ELSE IF (ENTRY_STATUS .EQ. NX_OK) THEN
+         IF (NXOPENDATA(FILEID,NAME) .NE. NX_OK) STOP
+         IF(NXGETPATH(FILEID,PATH) .NE. NX_OK) STOP
+         WRITE(*,FMT='(1X,A,A)') 'Path = ', PATH(1:LEN_TRIM(PATH))
+         IF (NXGETINFO(FILEID,NXRANK,NXDIMS,NXTYPE) .NE. NX_OK) STOP
+         WRITE(*,FMT='(4X,A,I2,A)') NAME(1:LEN_TRIM(NAME))//'(', 
+     +     NXTYPE,')'
+         IF (NXTYPE .EQ. NX_CHAR) THEN
+            IF (NXGETCHARDATA(FILEID,CHAR_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A)') 
+     +        'Values : '//CHAR_BUFFER(1:NXDIMS(1))
+         ELSE IF (NXTYPE .EQ. NX_INT8) THEN
+            IF (NXGETDATA(FILEID,I1_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I3)') 'Values : ', I1_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT16) THEN
+            IF (NXGETDATA(FILEID,I2_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I6)') 'Values : ', I2_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+            IF (NXGETDATA(FILEID,I4_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I12)') 'Values : ', I4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', R4_BUFFER
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT64) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', 
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', 
+     +        (R8_BUFFER(I), I=1,4)
+         END IF
+  200    ATTR_STATUS = NXGETNEXTATTR (FILEID, NAME, NXDIMS, NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) STOP
+         IF (ATTR_STATUS .EQ. NX_OK) THEN
+            IF (NXTYPE .EQ. NX_CHAR) THEN
+               LENGTH=LEN(CHAR_BUFFER)
+               IF (NXGETCHARATTR(FILEID,NAME,CHAR_BUFFER,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A)') NAME(1:LEN_TRIM(NAME))//' : '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+            ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,I,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,I5)') NAME(1:LEN_TRIM(NAME))//' : ',
+     +           I
+            ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,R,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,F10.6)') NAME(1:LEN_TRIM(NAME))
+     +           //' : ', R
+            END IF
+         END IF
+         IF (ATTR_STATUS .NE. NX_EOD) GOTO 200
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+      END IF
+      IF (ENTRY_STATUS .NE. NX_EOD) GOTO 100
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, BLINK) .NE. NX_OK) STOP
+         IF (NXSAMEID(FILEID, GLINK, BLINK)) THEN
+            WRITE(*,*) 'Link Check OK'
+         ELSE
+            WRITE(*,*) 'Link Check Failed'
+         ENDIF
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+      END
+C----------------------------------------------------------------------
+C     LEN_TRIM trims remaining blanks and tabs from the end of "string"
+C      INTEGER FUNCTION LEN_TRIM (STRING)
+C      INTEGER I
+C      CHARACTER*(*) STRING
+C      I = LEN(STRING)
+C      DO WHILE (I .GE. 1 .AND. 
+C     +(STRING(I:I).EQ.' '.OR. STRING(I:I).EQ.CHAR(0).OR.
+C     + STRING(I:I).EQ.CHAR(9)))
+C         I = I - 1
+C      END DO
+C      LEN_TRIM = MIN(I,LEN(STRING))
+C      RETURN
+C      END
+
diff --git a/test/napif5_test.f b/test/napif5_test.f
new file mode 100644
index 0000000..b3a3c0b
--- /dev/null
+++ b/test/napif5_test.f
@@ -0,0 +1,327 @@
+C------------------------------------------------------------------------------
+C NeXus - Neutron & X-ray Common Data Format
+C  
+C Test program for NeXus FORTRAN 77 interface
+C
+C Copyright (C) 1997-2002, Freddie Akeroyd
+C
+C This library is free software; you can redistribute it and/or
+C modify it under the terms of the GNU Lesser General Public
+C License as published by the Free Software Foundation; either
+C version 2 of the License, or (at your option) any later version.
+C
+C This library is distributed in the hope that it will be useful,
+C but WITHOUT ANY WARRANTY; without even the implied warranty of
+C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+C Lesser General Public License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public
+C License along with this library; if not, write to the Free Software
+C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+C
+C  For further information, see <http://www.nexusformat.org>
+C
+C $Id$
+C------------------------------------------------------------------------------
+
+      INCLUDE 'napif.inc'
+      INTEGER NXRANK, NXDIMS(NX_MAXRANK), NXTYPE, NXLEN
+      INTEGER ENTRY_STATUS, ATTR_STATUS, STAT
+      INTEGER*4 I, J
+      REAL*4 R
+      INTEGER*1 I1_ARRAY(4)
+      INTEGER*2 I2_ARRAY(4)
+      INTEGER*4 I4_ARRAY(4) 
+      REAL*4 R4_ARRAY(4,5)
+      REAL*8 R8_ARRAY(4,5)
+      INTEGER*4 ARRAY_DIMS(2), UNLIMITED_DIMS(1)
+      INTEGER*4 CHUNK_SIZE(2)
+      INTEGER*4 SLAB_START(2), SLAB_SIZE(2)
+      CHARACTER*64 NAME, CLASS
+      CHARACTER*128 CHAR_BUFFER
+      INTEGER*1 CHAR_BUFFER_B(128)
+      CHARACTER*64 GROUP_NAME, CLASS_NAME
+      CHARACTER*70 PATH
+      INTEGER FILEID(NXHANDLESIZE)
+      INTEGER GLINK(NXLINKSIZE), DLINK(NXLINKSIZE), BLINK(NXLINKSIZE)
+      INTEGER*4 COMP_ARRAY(20,100)
+      INTEGER*4 DIMS(2), CDIMS(2), UDIMS(1)
+      INTEGER*1 I1_BUFFER(4)
+      INTEGER*2 I2_BUFFER(4)
+      INTEGER*4 I4_BUFFER(4), U_BUFFER(7)
+      REAL*4 R4_BUFFER(4)
+      REAL*8 R8_BUFFER(16)
+      DATA I1_ARRAY /1, 2, 3, 4/
+      DATA I2_ARRAY /1000, 2000, 3000, 4000/
+      DATA I4_ARRAY /1000000, 2000000, 3000000, 4000000/
+      DATA R4_ARRAY /1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA R8_ARRAY/1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA ARRAY_DIMS /4, 5/
+      DATA CHUNK_SIZE /4, 5/
+      DATA U_BUFFER /0,1,2,3,4,5,6/
+      EQUIVALENCE (CHAR_BUFFER, CHAR_BUFFER_B)
+
+      IF (NXOPEN('NXtest.nxs', NXACC_CREATE5, FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 10) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus data') .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i1_data', NX_INT8, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i1_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I1_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i2_data', NX_INT16, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i2_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I2_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i4_data', NX_INT32, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXCOMPMAKEDATA(FILEID, 'r4_data', NX_FLOAT32, 2, 
+     +        ARRAY_DIMS, NX_COMP_LZW, CHUNK_SIZE) .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, R4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'r8_data', NX_FLOAT64, 2, ARRAY_DIMS) 
+     +        .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r8_data') .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 5
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXPUTSLAB(FILEID, R8_ARRAY(1,5), SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 4
+            IF (NXPUTSLAB(FILEID, R8_ARRAY, SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTCHARATTR(FILEID, 'ch_attribute', 'NeXus',5,NX_CHAR) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'i4_attribute', 42, 1, NX_INT32) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'r4_attribute', 3.14159265, 1, 
+     +        NX_FLOAT32) .NE. NX_OK) STOP
+            IF (NXGETDATAID(FILEID, DLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+            IF (NXMAKELINK(FILEID, DLINK) .NE. NX_OK) STOP
+            DIMS(1) = 20
+            DIMS(2) = 100
+            DO I = 1,100
+               DO J = 1,20
+                  COMP_ARRAY(J,I) = I-1
+               END DO
+            END DO
+            CDIMS(1) = 20
+            CDIMS(2) = 20
+            IF (NXCOMPMAKEDATA(FILEID, 'comp_data', NX_INT32, 2, DIMS, 
+     +        NX_COMP_LZW, CDIMS) .NE. NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'comp_data') .NE. NX_OK) STOP
+               IF (NXPUTDATA(FILEID, COMP_ARRAY) .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+            UDIMS(1) = NX_UNLIMITED
+            IF (NXMAKEDATA(FILEID, 'flush_data', NX_INT32, 1, UDIMS) 
+     +        .NE. NX_OK) STOP
+               SLAB_SIZE(1) = 1
+               DO I = 1,7
+                  SLAB_START(1) = I
+                  IF (NXOPENDATA(FILEID, 'flush_data') .NE. NX_OK) STOP
+                     IF (NXPUTSLAB(FILEID, U_BUFFER(I), SLAB_START, 
+     +                 SLAB_SIZE) .NE. NX_OK) STOP
+                     STAT = NXCLOSEDATA(FILEID)
+                     IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+               END DO
+         IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+            IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 12) .NE. 
+     +        NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus sample') .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXMAKELINK (fileid, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+C *** read data
+      IF (NXOPEN('NXtest.nxs', NXACC_READ, FILEID) .NE. NX_OK) STOP
+      IF (NXGETATTRINFO(FILEID, J) .NE. NX_OK) STOP
+      IF (J .GT. 0) WRITE(*,'(1X,A,I2)') 
+     +  'Number of global attributes: ', J
+      DO I = 1,J
+         ATTR_STATUS = NXGETNEXTATTR(FILEID,NAME,NXDIMS,NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) THEN
+            STOP
+         ELSE IF (ATTR_STATUS .EQ. NX_OK) THEN
+            NXLEN = LEN(CHAR_BUFFER)
+            IF (NXGETCHARATTR(FILEID, NAME, CHAR_BUFFER, NXLEN, NXTYPE)
+     +        .NE. NX_OK) STOP
+	    IF ((NAME .NE. 'HDF5_Version') .AND. 
+     +          (NAME .NE. 'file_time')) THEN
+               WRITE(*,'(4X,A)') NAME(1:LEN_TRIM(NAME))//' = '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+	    END IF
+         END IF
+      END DO
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXGETGROUPINFO(FILEID, I, GROUP_NAME, CLASS_NAME) .NE. 
+     +     NX_OK) STOP
+         WRITE(*,'(1X,A,I2,A)') 'Group: '
+     +     //GROUP_NAME(1:LEN_TRIM(GROUP_NAME))//'('
+     +     //CLASS_NAME(1:LEN_TRIM(CLASS_NAME))
+     +     //') contains ',I,' items'
+  100 ENTRY_STATUS=NXGETNEXTENTRY(FILEID,NAME,CLASS,NXTYPE)
+      IF (ENTRY_STATUS .EQ. NX_ERROR) STOP
+      IF (CLASS(1:LEN_TRIM(CLASS)) .NE. 'SDS') THEN
+         IF (ENTRY_STATUS .NE. NX_EOD) THEN
+            WRITE(*,'(4X,A)') 'Subgroup: '//NAME(1:LEN_TRIM(NAME))//'('
+     +        //CLASS(1:LEN_TRIM(CLASS))//')'
+            ENTRY_STATUS = NX_OK
+         END IF
+      ELSE IF (ENTRY_STATUS .EQ. NX_OK) THEN
+         IF (NXOPENDATA(FILEID,NAME) .NE. NX_OK) STOP
+         IF(NXGETPATH(FILEID,PATH) .NE. NX_OK) STOP
+         WRITE(*,FMT='(1X,A,A)') 'Path = ', PATH(1:LEN_TRIM(PATH))
+         IF (NXGETINFO(FILEID,NXRANK,NXDIMS,NXTYPE) .NE. NX_OK) STOP
+         WRITE(*,FMT='(4X,A,I2,A)') NAME(1:LEN_TRIM(NAME))//'(', 
+     +     NXTYPE,')'
+         IF (NXTYPE .EQ. NX_CHAR) THEN
+            IF (NXGETCHARDATA(FILEID,CHAR_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A)') 
+     +        'Values : '//CHAR_BUFFER(1:NXDIMS(1))
+         ELSE IF (NXTYPE .EQ. NX_INT8) THEN
+            IF (NXGETDATA(FILEID,I1_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I3)') 'Values : ', I1_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT16) THEN
+            IF (NXGETDATA(FILEID,I2_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I6)') 'Values : ', I2_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+            IF (NXGETDATA(FILEID,I4_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I12)') 'Values : ', I4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', R4_BUFFER
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT64) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', 
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', 
+     +        (R8_BUFFER(I), I=1,4)
+         END IF
+  200    ATTR_STATUS = NXGETNEXTATTR (FILEID, NAME, NXDIMS, NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) STOP
+         IF (ATTR_STATUS .EQ. NX_OK) THEN
+            IF (NXTYPE .EQ. NX_CHAR) THEN
+               LENGTH=LEN(CHAR_BUFFER)
+               IF (NXGETCHARATTR(FILEID,NAME,CHAR_BUFFER,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A)') NAME(1:LEN_TRIM(NAME))//' : '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+            ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,I,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,I5)') NAME(1:LEN_TRIM(NAME))//' : ',
+     +           I
+            ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,R,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,F10.6)') NAME(1:LEN_TRIM(NAME))
+     +           //' : ', R
+            END IF
+         END IF
+         IF (ATTR_STATUS .NE. NX_EOD) GOTO 200
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+      END IF
+      IF (ENTRY_STATUS .NE. NX_EOD) GOTO 100
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, BLINK) .NE. NX_OK) STOP
+         IF (NXSAMEID(FILEID, GLINK, BLINK)) THEN
+            WRITE(*,*) 'Link Check OK'
+         ELSE
+            WRITE(*,*) 'Link Check Failed'
+         ENDIF
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+      END
+C----------------------------------------------------------------------
+C     LEN_TRIM trims remaining blanks and tabs from the end of "string"
+C      INTEGER FUNCTION LEN_TRIM (STRING)
+C      INTEGER I
+C      CHARACTER*(*) STRING
+C      I = LEN(STRING)
+C      DO WHILE (I .GE. 1 .AND. 
+C     +(STRING(I:I).EQ.' '.OR. STRING(I:I).EQ.CHAR(0).OR.
+C     + STRING(I:I).EQ.CHAR(9)))
+C         I = I - 1
+C      END DO
+C      LEN_TRIM = MIN(I,LEN(STRING))
+C      RETURN
+C      END
+
diff --git a/test/napif_test.f b/test/napif_test.f
new file mode 100644
index 0000000..1a1d7a0
--- /dev/null
+++ b/test/napif_test.f
@@ -0,0 +1,327 @@
+C------------------------------------------------------------------------------
+C NeXus - Neutron & X-ray Common Data Format
+C  
+C Test program for NeXus FORTRAN 77 interface
+C
+C Copyright (C) 1997-2002, Freddie Akeroyd
+C
+C This library is free software; you can redistribute it and/or
+C modify it under the terms of the GNU Lesser General Public
+C License as published by the Free Software Foundation; either
+C version 2 of the License, or (at your option) any later version.
+C
+C This library is distributed in the hope that it will be useful,
+C but WITHOUT ANY WARRANTY; without even the implied warranty of
+C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+C Lesser General Public License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public
+C License along with this library; if not, write to the Free Software
+C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+C
+C  For further information, see <http://www.nexusformat.org>
+C
+C $Id$
+C------------------------------------------------------------------------------
+
+      INCLUDE 'napif.inc'
+      INTEGER NXRANK, NXDIMS(NX_MAXRANK), NXTYPE, NXLEN
+      INTEGER ENTRY_STATUS, ATTR_STATUS
+      INTEGER*4 I, J
+      REAL*4 R
+      INTEGER*1 I1_ARRAY(4)
+      INTEGER*2 I2_ARRAY(4)
+      INTEGER*4 I4_ARRAY(4) 
+      REAL*4 R4_ARRAY(4,5)
+      REAL*8 R8_ARRAY(4,5)
+      INTEGER*4 ARRAY_DIMS(2), UNLIMITED_DIMS(1)
+      INTEGER*4 CHUNK_SIZE(2)
+      INTEGER*4 SLAB_START(2), SLAB_SIZE(2)
+      CHARACTER*64 NAME, CLASS
+      CHARACTER*128 CHAR_BUFFER
+      INTEGER*1 CHAR_BUFFER_B(128)
+      CHARACTER*64 GROUP_NAME, CLASS_NAME
+      CHARACTER*70 PATH
+      INTEGER FILEID(NXHANDLESIZE)
+      INTEGER GLINK(NXLINKSIZE), DLINK(NXLINKSIZE), BLINK(NXLINKSIZE)
+      INTEGER*4 COMP_ARRAY(20,100)
+      INTEGER*4 DIMS(2), CDIMS(2), UDIMS(1)
+      INTEGER*1 I1_BUFFER(4)
+      INTEGER*2 I2_BUFFER(4)
+      INTEGER*4 I4_BUFFER(4), U_BUFFER(7)
+      REAL*4 R4_BUFFER(4)
+      REAL*8 R8_BUFFER(16)
+      DATA I1_ARRAY /1, 2, 3, 4/
+      DATA I2_ARRAY /1000, 2000, 3000, 4000/
+      DATA I4_ARRAY /1000000, 2000000, 3000000, 4000000/
+      DATA R4_ARRAY /1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA R8_ARRAY/1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,
+     +  15.,16.,17.,18.,19.,20./
+      DATA ARRAY_DIMS /4, 5/
+      DATA CHUNK_SIZE /4, 5/
+      DATA U_BUFFER /0,1,2,3,4,5,6/
+      EQUIVALENCE (CHAR_BUFFER, CHAR_BUFFER_B)
+
+      IF (NXOPEN('NXtest.nxs', NXACC_CREATE, FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 10) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus data') .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i1_data', NX_INT8, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i1_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I1_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i2_data', NX_INT16, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i2_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I2_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'i4_data', NX_INT32, 1, 4) .NE. NX_OK) 
+     +        STOP
+         IF (NXOPENDATA(FILEID, 'i4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, I4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXCOMPMAKEDATA(FILEID, 'r4_data', NX_FLOAT32, 2, 
+     +        ARRAY_DIMS, NX_COMP_LZW, CHUNK_SIZE) .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r4_data') .NE. NX_OK) STOP
+            IF (NXPUTDATA(FILEID, R4_ARRAY) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEDATA(FILEID, 'r8_data', NX_FLOAT64, 2, ARRAY_DIMS) 
+     +        .NE. NX_OK) STOP
+         IF (NXOPENDATA(FILEID, 'r8_data') .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 5
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXPUTSLAB(FILEID, R8_ARRAY(1,5), SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 4
+            IF (NXPUTSLAB(FILEID, R8_ARRAY, SLAB_START, SLAB_SIZE) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTCHARATTR(FILEID, 'ch_attribute', 'NeXus',5,NX_CHAR) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'i4_attribute', 42, 1, NX_INT32) 
+     +        .NE. NX_OK) STOP
+            IF (NXPUTATTR(FILEID, 'r4_attribute', 3.14159265, 1, 
+     +        NX_FLOAT32) .NE. NX_OK) STOP
+            IF (NXGETDATAID(FILEID, DLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'data', 'NXdata') .NE. NX_OK) STOP
+            IF (NXMAKELINK(FILEID, DLINK) .NE. NX_OK) STOP
+            DIMS(1) = 20
+            DIMS(2) = 100
+            DO I = 1,100
+               DO J = 1,20
+                  COMP_ARRAY(J,I) = I-1
+               END DO
+            END DO
+            CDIMS(1) = 20
+            CDIMS(2) = 20
+            IF (NXCOMPMAKEDATA(FILEID, 'comp_data', NX_INT32, 2, DIMS, 
+     +        NX_COMP_LZW, CDIMS) .NE. NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'comp_data') .NE. NX_OK) STOP
+               IF (NXPUTDATA(FILEID, COMP_ARRAY) .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+            UDIMS(1) = NX_UNLIMITED
+            IF (NXMAKEDATA(FILEID, 'flush_data', NX_INT32, 1, UDIMS) 
+     +        .NE. NX_OK) STOP
+               SLAB_SIZE(1) = 1
+               DO I = 1,7
+                  SLAB_START(1) = I
+                  IF (NXOPENDATA(FILEID, 'flush_data') .NE. NX_OK) STOP
+                     IF (NXPUTSLAB(FILEID, U_BUFFER(I), SLAB_START, 
+     +                 SLAB_SIZE) .NE. NX_OK) STOP
+                     IF (NXFLUSH(FILEID) .NE. NX_OK) STOP
+               END DO
+         IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+         IF (NXMAKEGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+         IF (NXOPENGROUP(FILEID, 'sample', 'NXsample') .NE. NX_OK) STOP
+            IF (NXMAKEDATA(FILEID, 'ch_data', NX_CHAR, 1, 12) .NE. 
+     +        NX_OK) STOP
+            IF (NXOPENDATA(FILEID, 'ch_data') .NE. NX_OK) STOP
+            IF (NXPUTCHARDATA(FILEID, 'NeXus sample') .NE. NX_OK) STOP
+            IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+            IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+         IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXMAKEGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXMAKELINK (fileid, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+C *** read data
+      IF (NXOPEN('NXtest.nxs', NXACC_READ, FILEID) .NE. NX_OK) STOP
+      IF (NXGETATTRINFO(FILEID, J) .NE. NX_OK) STOP
+      IF (J .GT. 0) WRITE(*,'(1X,A,I2)') 
+     +  'Number of global attributes: ', J
+      DO I = 1,J
+         ATTR_STATUS = NXGETNEXTATTR(FILEID,NAME,NXDIMS,NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) THEN
+            STOP
+         ELSE IF (ATTR_STATUS .EQ. NX_OK) THEN
+            NXLEN = LEN(CHAR_BUFFER)
+            IF (NXGETCHARATTR(FILEID, NAME, CHAR_BUFFER, NXLEN, NXTYPE)
+     +        .NE. NX_OK) STOP
+	    IF ((NAME .NE. 'HDF_version') .AND. 
+     +          (NAME .NE. 'file_time')) THEN
+               WRITE(*,'(4X,A)') NAME(1:LEN_TRIM(NAME))//' = '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+	    END IF
+         END IF
+      END DO
+      IF (NXOPENGROUP(FILEID, 'entry', 'NXentry') .NE. NX_OK) STOP
+         IF (NXGETGROUPINFO(FILEID, I, GROUP_NAME, CLASS_NAME) .NE. 
+     +     NX_OK) STOP
+         WRITE(*,'(1X,A,I2,A)') 'Group: '
+     +     //GROUP_NAME(1:LEN_TRIM(GROUP_NAME))//'('
+     +     //CLASS_NAME(1:LEN_TRIM(CLASS_NAME))
+     +     //') contains ',I,' items'
+  100 ENTRY_STATUS=NXGETNEXTENTRY(FILEID,NAME,CLASS,NXTYPE)
+      IF (ENTRY_STATUS .EQ. NX_ERROR) STOP
+      IF (CLASS(1:LEN_TRIM(CLASS)) .NE. 'SDS') THEN
+         IF (ENTRY_STATUS .NE. NX_EOD) THEN
+            WRITE(*,'(4X,A)') 'Subgroup: '//NAME(1:LEN_TRIM(NAME))//'('
+     +        //CLASS(1:LEN_TRIM(CLASS))//')'
+            ENTRY_STATUS = NX_OK
+         END IF
+      ELSE IF (ENTRY_STATUS .EQ. NX_OK) THEN
+         IF (NXOPENDATA(FILEID,NAME) .NE. NX_OK) STOP
+         IF (NXGETPATH(FILEID,PATH) .NE. NX_OK)STOP
+         WRITE(*,FMT='(1X,A,A)') 'Path = ', PATH(1:LEN_TRIM(PATH))
+         IF (NXGETINFO(FILEID,NXRANK,NXDIMS,NXTYPE) .NE. NX_OK) STOP
+         WRITE(*,FMT='(4X,A,I2,A)') NAME(1:LEN_TRIM(NAME))//'(', 
+     +     NXTYPE,')'
+         IF (NXTYPE .EQ. NX_CHAR) THEN
+            IF (NXGETCHARDATA(FILEID,CHAR_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A)') 
+     +        'Values : '//CHAR_BUFFER(1:NXDIMS(1))
+         ELSE IF (NXTYPE .EQ. NX_INT8) THEN
+            IF (NXGETDATA(FILEID,I1_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I3)') 'Values : ', I1_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT16) THEN
+            IF (NXGETDATA(FILEID,I2_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I6)') 'Values : ', I2_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+            IF (NXGETDATA(FILEID,I4_BUFFER) .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4I12)') 'Values : ', I4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', R4_BUFFER
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R4_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', R4_BUFFER
+         ELSE IF (NXTYPE .EQ. NX_FLOAT64) THEN
+            SLAB_START(1) = 1
+            SLAB_START(2) = 1
+            SLAB_SIZE(1) = 4
+            SLAB_SIZE(2) = 1
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') 'Values : ', 
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 2
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 3
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 4
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ',  
+     +        (R8_BUFFER(I), I=1,4)
+            SLAB_START(2) = 5
+            IF (NXGETSLAB(FILEID, R8_BUFFER, SLAB_START, SLAB_SIZE) 
+     +            .NE. NX_OK) STOP
+            WRITE(*,FMT='(4X,A,4F7.2)') '       : ', 
+     +        (R8_BUFFER(I), I=1,4)
+         END IF
+  200    ATTR_STATUS = NXGETNEXTATTR (FILEID, NAME, NXDIMS, NXTYPE)
+         IF (ATTR_STATUS .EQ. NX_ERROR) STOP
+         IF (ATTR_STATUS .EQ. NX_OK) THEN
+            IF (NXTYPE .EQ. NX_CHAR) THEN
+               LENGTH=LEN(CHAR_BUFFER)
+               IF (NXGETCHARATTR(FILEID,NAME,CHAR_BUFFER,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A)') NAME(1:LEN_TRIM(NAME))//' : '
+     +           //CHAR_BUFFER(1:LEN_TRIM(CHAR_BUFFER))
+            ELSE IF (NXTYPE .EQ. NX_INT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,I,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,I5)') NAME(1:LEN_TRIM(NAME))//' : ',
+     +           I
+            ELSE IF (NXTYPE .EQ. NX_FLOAT32) THEN
+               LENGTH=1
+               IF (NXGETATTR(FILEID,NAME,R,LENGTH,NXTYPE) 
+     +               .NE. NX_OK) STOP
+               WRITE(*,FMT='(7X,A,F10.6)') NAME(1:LEN_TRIM(NAME))
+     +           //' : ', R
+            END IF
+         END IF
+         IF (ATTR_STATUS .NE. NX_EOD) GOTO 200
+         IF (NXCLOSEDATA(FILEID) .NE. NX_OK) STOP
+      END IF
+      IF (ENTRY_STATUS .NE. NX_EOD) GOTO 100
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, GLINK) .NE. NX_OK) STOP
+      IF (NXCLOSEGROUP (FILEID) .NE. NX_OK) STOP
+      IF (NXOPENGROUP (FILEID, "link", "NXentry") .NE. NX_OK) STOP
+         IF (NXGETGROUPID (FILEID, BLINK) .NE. NX_OK) STOP
+         IF (NXSAMEID(FILEID, GLINK, BLINK)) THEN
+            WRITE(*,*) 'Link Check OK'
+         ELSE
+            WRITE(*,*) 'Link Check Failed'
+         ENDIF
+      IF (NXCLOSEGROUP(FILEID) .NE. NX_OK) STOP
+      IF (NXCLOSE(FILEID) .NE. NX_OK) STOP
+      STOP
+      END
+C----------------------------------------------------------------------
+C     LEN_TRIM trims remaining blanks and tabs from the end of "string"
+C      INTEGER FUNCTION LEN_TRIM (STRING)
+C      INTEGER I
+C      CHARACTER*(*) STRING
+C      I = LEN(STRING)
+C      DO WHILE (I .GE. 1 .AND. 
+C     +(STRING(I:I).EQ.' '.OR. STRING(I:I).EQ.CHAR(0).OR.
+C     + STRING(I:I).EQ.CHAR(9)))
+C         I = I - 1
+C      END DO
+C      LEN_TRIM = MIN(I,LEN(STRING))
+C      RETURN
+C      END
+
diff --git a/test/nxbrowse.txt b/test/nxbrowse.txt
new file mode 100644
index 0000000..764cd8c
--- /dev/null
+++ b/test/nxbrowse.txt
@@ -0,0 +1,2 @@
+DIR
+EXIT
diff --git a/test/run_leak_test b/test/run_leak_test
new file mode 100755
index 0000000..96ebbea
--- /dev/null
+++ b/test/run_leak_test
@@ -0,0 +1,13 @@
+#!/bin/sh
+comm="valgrind --leak-check=full --show-reachable=yes --leak-resolution=high --num-callers=40"
+echo ">>> Running valgrind on \"leak_test1\" - results sent to \"leak_test1.log\""
+$comm --log-file-exactly=leak_test1.log ./leak_test1
+echo ">>> Test1 done"
+echo " "
+echo ">>> Running valgrind on \"leak_test2\" - results sent to \"leak_test2.log\""
+$comm --log-file-exactly=leak_test2.log ./leak_test2
+echo ">>> Test2 done"
+echo " "
+echo ">>> Running valgrind on \"leak_test3\" - results sent to \"leak_test3.log\""
+$comm --log-file-exactly=leak_test3.log ./leak_test3
+echo ">>> Test3 done"
diff --git a/test/run_test.c b/test/run_test.c
new file mode 100644
index 0000000..6fcc67a
--- /dev/null
+++ b/test/run_test.c
@@ -0,0 +1,4 @@
+int main(int argc, char* argv[])
+{
+	return 0;
+}
diff --git a/test/setup_test b/test/setup_test
new file mode 100755
index 0000000..7678221
--- /dev/null
+++ b/test/setup_test
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# $1 is abs_srcdir
+#
+test -e data || mkdir data
+cp $1/data/dmc* data
+chmod 0644 data/*
diff --git a/test/skip_test.c b/test/skip_test.c
new file mode 100644
index 0000000..d063ae9
--- /dev/null
+++ b/test/skip_test.c
@@ -0,0 +1,4 @@
+int main(int argc, char* argv[])
+{
+	return 77;
+}
diff --git a/test/test_nxunlimited.c b/test/test_nxunlimited.c
new file mode 100644
index 0000000..b665990
--- /dev/null
+++ b/test/test_nxunlimited.c
@@ -0,0 +1,78 @@
+/*---------------------------------------------------------------------------
+  NeXus - Neutron & X-ray Common Data Format
+  
+  Test program for C API
+  
+  Copyright (C) 1997-2009 Freddie Akeroyd
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+ 
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+             
+  For further information, see <http://www.nexusformat.org>
+
+  $Id: napi_test.c 1178 2009-01-21 12:28:55Z Freddie Akeroyd $
+
+----------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "napi.h"
+#include "napiconfig.h"
+
+#define DATA_SIZE 200000
+
+int test_unlimited(int file_type, const char* filename)
+{
+    static double d[DATA_SIZE];
+    int dims[2] = { NX_UNLIMITED, DATA_SIZE };
+    int i, slab_start[2], slab_size[2];
+    NXhandle file_id = NULL;
+      remove(filename);
+      NXopen (filename, file_type, &file_id);
+       NXmakegroup(file_id,"entry1","NXentry");
+       NXopengroup(file_id,"entry1","NXentry");
+          NXmakedata (file_id, "data", NX_FLOAT64, 2, dims);
+          NXopendata (file_id, "data");
+          slab_start[1] = 0;
+          slab_size[0] = 1;
+          slab_size[1] = DATA_SIZE;
+	  for(i=0; i<2; i++)
+          {
+              slab_start[0] = i;
+              NXputslab (file_id, d, slab_start, slab_size);
+          }
+          NXclosedata (file_id);
+       NXclosegroup(file_id);
+      NXclose (&file_id);
+    return 0;
+}
+
+int main(int argc, char* argv[])
+{
+    time_t tim;
+    printf("Testing HDF4\n");
+    time(&tim);
+    test_unlimited(NXACC_CREATE4, "test_unlimited.nx4");
+    printf("Took %u seconds\n", (unsigned)(time(NULL) - tim));
+    printf("Testing XML\n");
+    time(&tim);
+    test_unlimited(NXACC_CREATEXML, "test_unlimited.xml");
+    printf("Took %u seconds\n", (unsigned)(time(NULL) - tim));
+    printf("Testing HDF5\n");
+    time(&tim);
+    test_unlimited(NXACC_CREATE5, "test_unlimited.nx5");
+    printf("Took %u seconds\n", (unsigned)(time(NULL) - tim));
+    return 0;
+}
diff --git a/test/testsuite.at b/test/testsuite.at
new file mode 100644
index 0000000..7fa8b67
--- /dev/null
+++ b/test/testsuite.at
@@ -0,0 +1,2161 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for NeXus.
+# Copyright (C) Jens Krueger, jens.krueger at frm2.tum.de.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# We need a recent Autotest.
+m4_version_prereq([2.56])
+
+AT_INIT
+dnl AT_TESTED(NXtest.f90)
+
+AT_BANNER([[Testing the NeXus C library.]])
+
+AT_SETUP([Check the C binding using HDF4])
+AT_CHECK([ $HAVE_HDF4 && $SETUP_TEST && napi_test-hdf4 | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest.hdf
+Number of global attributes: 4
+   NeXus_version = 4.3.2
+   file_name = NXtest.hdf
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 9 items
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+   Subgroup: data(NXdata)
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.hdf
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.hdf
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.hdf#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.hdf#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.hdf#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the C binding using HDF5])
+AT_CHECK([ $HAVE_HDF5 && $SETUP_TEST && napi_test-hdf5 | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest.h5
+Number of global attributes: 4
+   NeXus_version = 4.3.2
+   file_name = NXtest.h5
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 10 items
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+   Subgroup: data(NXdata)
+Data path /entry/grosse_zahl
+   grosse_zahl(26) =  12 555555555555 23 777777777777
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.h5
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.h5
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.h5#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.h5#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.h5#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the C binding using HDF4 (static library)])
+AT_CHECK([ $HAVE_HDF4 && $SETUP_TEST && napi_test-hdf4-static | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest.hdf
+Number of global attributes: 4
+   NeXus_version = 4.3.2
+   file_name = NXtest.hdf
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 9 items
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+   Subgroup: data(NXdata)
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.hdf
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.hdf
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.hdf#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.hdf#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.hdf#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the C binding using HDF5 (static library)])
+AT_CHECK([ $HAVE_HDF5 && $SETUP_TEST && napi_test-hdf5-static | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest.h5
+Number of global attributes: 4
+   NeXus_version = 4.3.2
+   file_name = NXtest.h5
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 10 items
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+   Subgroup: data(NXdata)
+Data path /entry/grosse_zahl
+   grosse_zahl(26) =  12 555555555555 23 777777777777
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.h5
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.h5
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.h5#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.h5#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.h5#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the C binding using XML])
+AT_CHECK([ $HAVE_XML && $SETUP_TEST && napi_test-xml | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest.xml
+Number of global attributes: 7
+   NeXus_version = 4.3.2
+   file_name = NXtest.xml
+   xmlns = http://definition.nexusformat.org/schema/3.1
+   xmlns:xsi = http://www.w3.org/2001/XMLSchema-instance
+   xsi:schemaLocation = http://definition.nexusformat.org/schema/3.1 http://definition.nexusformat.org/schema/3.1/BASE.xsd
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 10 items
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+Data path /entry/grosse_zahl
+   grosse_zahl(26) =  12 555555555555 23 777777777777
+   Subgroup: data(NXdata)
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.xml
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.xml
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.xml#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.xml#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.xml#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the C binding using XML (static library)])
+AT_CHECK([ $HAVE_XML && $SETUP_TEST && napi_test-xml-static | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest.xml
+Number of global attributes: 7
+   NeXus_version = 4.3.2
+   file_name = NXtest.xml
+   xmlns = http://definition.nexusformat.org/schema/3.1
+   xmlns:xsi = http://www.w3.org/2001/XMLSchema-instance
+   xsi:schemaLocation = http://definition.nexusformat.org/schema/3.1 http://definition.nexusformat.org/schema/3.1/BASE.xsd
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 10 items
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+Data path /entry/grosse_zahl
+   grosse_zahl(26) =  12 555555555555 23 777777777777
+   Subgroup: data(NXdata)
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.xml
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.xml
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.xml#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.xml#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.xml#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the C binding using XML table (static library)])
+AT_CHECK([ $HAVE_XML && $SETUP_TEST && napi_test-xml-table-static | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: NXtest-table.xml
+Number of global attributes: 7
+   NeXus_version = 4.3.2
+   file_name = NXtest-table.xml
+   xmlns = http://definition.nexusformat.org/schema/3.1
+   xmlns:xsi = http://www.w3.org/2001/XMLSchema-instance
+   xsi:schemaLocation = http://definition.nexusformat.org/schema/3.1 http://definition.nexusformat.org/schema/3.1/BASE.xsd
+Number of group attributes: 2
+NXentry path /entry
+   hugo = namenlos
+   cucumber = passion
+Group: entry(NXentry) contains 10 items
+Data path /entry/ch_data
+   ch_data(4) = NeXus ><}&{'\&" Data
+Data path /entry/c1_data
+   c1_data(4) = abcdefghijklmnopqrst
+Data path /entry/i1_data
+   i1_data(20) =  1 2 3 4
+Data path /entry/i2_data
+   i2_data(22) =  1000 2000 3000 4000
+Data path /entry/i4_data
+   i4_data(24) =  1000000 2000000 3000000 4000000
+Data path /entry/grosse_zahl
+   grosse_zahl(26) =  12 555555555555 23 777777777777
+Data path /entry/r4_data
+   r4_data(5)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+Data path /entry/r8_data
+   r8_data(6)
+       1.000000 2.000000 3.000000 4.000000
+       5.000000 6.000000 7.000000 8.000000
+       9.000000 10.000000 11.000000 12.000000
+       13.000000 14.000000 15.000000 16.000000
+       17.000000 18.000000 19.000000 20.000000
+      Number of attributes : 4
+         ch_attribute : NeXus ><}&{'\&" Data
+         i4_attribute : 42
+         r4_attribute : 3.141593
+         target : /entry/r8_data
+   Subgroup: data(NXdata)
+   Subgroup: sample(NXsample)
+Group path /link/sample
+Link check OK
+NXopenpath checks OK
+before load path tests
+before external link tests
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.xml
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.xml
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.xml#/entry1
+testing link to external data set
+extlinkdata external URL = nxfile://data/dmc01.xml#/entry1/sample/temperature_mean
+value retrieved: 4.00
+extlinknative external URL = nxfile://data/dmc01.xml#/entry1/sample/temperature_mean
+value retrieved: 4.00
+External File Linking tested OK
+all ok - done
+]])
+AT_CLEANUP
+
+AT_BANNER([Check the FORTRAN binding.])
+
+AT_SETUP([Check the F77 binding using HDF4.])
+AT_CHECK([ $HAVE_F77 && $HAVE_HDF4 && $SETUP_TEST && napif_test-hdf4 | sed -e 's/\r$//' ], [], 
+[[ Number of global attributes:  4
+    NeXus_version = 4.3.2
+    file_name = NXtest.nxs
+ Group: entry(NXentry) contains  8 items
+ Path = /entry/ch_data
+    ch_data( 4)
+    Values : NeXus data
+ Path = /entry/i1_data
+    i1_data(20)
+    Values :   1  2  3  4
+ Path = /entry/i2_data
+    i2_data(22)
+    Values :   1000  2000  3000  4000
+ Path = /entry/i4_data
+    i4_data(24)
+    Values :      1000000     2000000     3000000     4000000
+ Path = /entry/r4_data
+    r4_data( 5)
+    Values :    1.00   2.00   3.00   4.00
+           :    5.00   6.00   7.00   8.00
+           :    9.00  10.00  11.00  12.00
+           :   13.00  14.00  15.00  16.00
+           :   17.00  18.00  19.00  20.00
+ Path = /entry/r8_data
+    r8_data( 6)
+    Values :    1.00   2.00   3.00   4.00
+           :    5.00   6.00   7.00   8.00
+           :    9.00  10.00  11.00  12.00
+           :   13.00  14.00  15.00  16.00
+           :   17.00  18.00  19.00  20.00
+       ch_attribute : NeXus
+       i4_attribute :    42
+       r4_attribute :   3.141593
+       target : /entry/r8_data
+    Subgroup: data(NXdata)
+    Subgroup: sample(NXsample)
+ Link Check OK
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the F77 binding using HDF5.])
+AT_CHECK([ $HAVE_F77 && $HAVE_HDF5 && $SETUP_TEST && napif_test-hdf5 | sed -e 's/\r$//' ], [], 
+[[ Number of global attributes:  4
+    NeXus_version = 4.3.2
+    file_name = NXtest.nxs
+ Group: entry(NXentry) contains  8 items
+ Path = /entry/ch_data
+    ch_data( 4)
+    Values : NeXus data
+    Subgroup: data(NXdata)
+ Path = /entry/i1_data
+    i1_data(20)
+    Values :   1  2  3  4
+ Path = /entry/i2_data
+    i2_data(22)
+    Values :   1000  2000  3000  4000
+ Path = /entry/i4_data
+    i4_data(24)
+    Values :      1000000     2000000     3000000     4000000
+ Path = /entry/r4_data
+    r4_data( 5)
+    Values :    1.00   2.00   3.00   4.00
+           :    5.00   6.00   7.00   8.00
+           :    9.00  10.00  11.00  12.00
+           :   13.00  14.00  15.00  16.00
+           :   17.00  18.00  19.00  20.00
+ Path = /entry/r8_data
+    r8_data( 6)
+    Values :    1.00   2.00   3.00   4.00
+           :    5.00   6.00   7.00   8.00
+           :    9.00  10.00  11.00  12.00
+           :   13.00  14.00  15.00  16.00
+           :   17.00  18.00  19.00  20.00
+       ch_attribute : NeXus
+       i4_attribute :    42
+       r4_attribute :   3.141593
+       target : /entry/r8_data
+    Subgroup: sample(NXsample)
+ Link Check OK
+]])
+AT_CLEANUP
+
+AT_SETUP([Check the F90 binding using HDF5.])
+AT_CHECK([ $HAVE_F90 && $HAVE_HDF5 && $SETUP_TEST && NXtest | sed -e 's/\r$//' ], [], 
+[[Writing character data
+Number of global attributes:        4
+   NeXus_version = 4.3.2
+   file_name = NXtest.nxs
+Group: entry(NXentry) contains        8 items
+   ch_data : NX_CHAR
+   Values : NeXus data
+   Subgroup: data(NXdata)
+   i1_data : NX_INT8
+   Values :        1       2       3       4
+   i2_data : NX_INT16
+   Values :     1000    2000    3000    4000
+   i4_data : NX_INT32
+   Values :  1000000 2000000 3000000 4000000
+   r4_data : NX_FLOAT32
+   Values :    1.0000000   2.0000000   3.0000000   4.0000000
+          :    5.0000000   6.0000000   7.0000000   8.0000000
+          :    9.0000000  10.0000000  11.0000000  12.0000000
+          :   13.0000000  14.0000000  15.0000000  16.0000000
+          :   17.0000000  18.0000000  19.0000000  20.0000000
+   r8_data : NX_FLOAT64
+   Values :    1.0000000   2.0000000   3.0000000   4.0000000
+          :    5.0000000   6.0000000   7.0000000   8.0000000
+          :    9.0000000  10.0000000  11.0000000  12.0000000
+          :   13.0000000  14.0000000  15.0000000  16.0000000
+          :   17.0000000  18.0000000  19.0000000  20.0000000
+   ch_attribute : NeXus
+   i4_attribute :       42
+   r4_attribute :    3.1415930
+   target : /entry/r8_data
+   Subgroup: sample(NXsample)
+Link Check OK
+]])
+AT_CLEANUP
+
+AT_BANNER([Check the C++ binding.])
+AT_SETUP([Check the C++ binding using HDF4.])
+AT_CHECK([ $HAVE_HDF4 && $SETUP_TEST && napi_test_cpp-hdf4 | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: napi_test_cpp.hdf
+Number of global attributes: 4
+   NeXus_version = 4.3.2
+   file_name = napi_test_cpp.hdf
+Number of group attributes: 2
+   hugo = namenlos
+   cucumber = passion
+Group contains 9 items
+   c1_data[5,4] = 2d character array
+   Path = /entry/c1_data
+   ch_data[10] = NeXus_data
+   Path = /entry/ch_data
+   data:NXdata
+   i1_data[4] = [,,,]
+   Path = /entry/i1_data
+   i2_data[4] = [1000,2000,3000,4000]
+   Path = /entry/i2_data
+   i4_data[4] = [1000000,2000000,3000000,4000000]
+   Path = /entry/i4_data
+   r4_data[5,4] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
+   Path = /entry/r4_data
+   r8_data[5,4] = [20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39]
+   Path = /entry/r8_data
+   sample:NXsample
+Link check OK
+NXopenpath checks OK
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.hdf
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.hdf
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.hdf#entry1
+TypeMap is correct size
+]])
+AT_CLEANUP
+AT_SETUP([Check the C++ binding using HDF5.])
+AT_CHECK([ $HAVE_HDF5 && $SETUP_TEST && napi_test_cpp-hdf5 | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: napi_test_cpp.h5
+Number of global attributes: 4
+   NeXus_version = 4.3.2
+   file_name = napi_test_cpp.h5
+Number of group attributes: 2
+   hugo = namenlos
+   cucumber = passion
+Group contains 10 items
+   c1_data[5,4] = 2d character array
+   Path = /entry/c1_data
+   ch_data[10] = NeXus_data
+   Path = /entry/ch_data
+   data:NXdata
+   grosszahl[4] = [12,555555555555,23,777777777777]
+   Path = /entry/grosszahl
+   i1_data[4] = [,,,]
+   Path = /entry/i1_data
+   i2_data[4] = [1000,2000,3000,4000]
+   Path = /entry/i2_data
+   i4_data[4] = [1000000,2000000,3000000,4000000]
+   Path = /entry/i4_data
+   r4_data[5,4] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
+   Path = /entry/r4_data
+   r8_data[5,4] = [20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39]
+   Path = /entry/r8_data
+   sample:NXsample
+Link check OK
+NXopenpath checks OK
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.h5
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.h5
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.h5#entry1
+TypeMap is correct size
+]])
+AT_CLEANUP
+AT_SETUP([Check the C++ binding using xml.])
+AT_CHECK([ $HAVE_XML && $SETUP_TEST && napi_test_cpp-xml | sed -e 's/\r$//' ], [], 
+[[NXinquirefile found: napi_test_cpp.xml
+Number of global attributes: 7
+   NeXus_version = 4.3.2
+   file_name = napi_test_cpp.xml
+   xmlns = http://definition.nexusformat.org/schema/3.1
+   xmlns:xsi = http://www.w3.org/2001/XMLSchema-instance
+   xsi:schemaLocation = http://definition.nexusformat.org/schema/3.1 http://definition.nexusformat.org/schema/3.1/BASE.xsd
+Number of group attributes: 2
+   hugo = namenlos
+   cucumber = passion
+Group contains 10 items
+   c1_data[5,4] = 2d character array
+   Path = /entry/c1_data
+   ch_data[10] = NeXus_data
+   Path = /entry/ch_data
+   data:NXdata
+   grosszahl[4] = [12,555555555555,23,777777777777]
+   Path = /entry/grosszahl
+   i1_data[4] = [,,,]
+   Path = /entry/i1_data
+   i2_data[4] = [1000,2000,3000,4000]
+   Path = /entry/i2_data
+   i4_data[4] = [1000000,2000000,3000000,4000000]
+   Path = /entry/i4_data
+   r4_data[5,4] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
+   Path = /entry/r4_data
+   r8_data[5,4] = [20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39]
+   Path = /entry/r8_data
+   sample:NXsample
+Link check OK
+NXopenpath checks OK
+First file time: 2005-05-27 05:44:13
+NXinquirefile found: data/dmc01.xml
+Second file sample: Ga0.94Mn0.04Sb_8mm
+NXinquirefile found: data/dmc02.xml
+Second file time: 2005-05-27 05:48:56
+entry1 external URL = nxfile://data/dmc01.xml#entry1
+TypeMap is correct size
+]])
+AT_CLEANUP
+
+AT_BANNER([[Testing the Python bindings.]])
+AT_SETUP([Checking python binding using HDF4])
+AT_CHECK([skip_test && $HAVE_HDF4 && $HAVE_PYTHON && $PYTHON $abs_srcdir/../bindings/python/nxstest.py -q hdf4 | sed -e 's/\r$//' ],[], 
+[[]])
+AT_CLEANUP
+AT_SETUP([Checking python binding using HDF5])
+AT_CHECK([$HAVE_HDF5 && $HAVE_PYTHON && $PYTHON $abs_srcdir/../bindings/python/nxstest.py -q hdf5 | sed -e 's/\r$//' ],[], 
+[[]])
+AT_CLEANUP
+AT_SETUP([Checking python binding using XML])
+AT_CHECK([$HAVE_XML && $HAVE_PYTHON && $PYTHON $abs_srcdir/../bindings/python/nxstest.py -q xml | sed -e 's/\r$//' ],[], 
+[[]])
+AT_CLEANUP
+
+AT_BANNER([[Testing the IDL bindings.]])
+AT_SETUP([Checking IDL binding using HDF4])
+AT_CHECK([skip_test && $HAVE_HDF4 && $HAVE_IDL && $SETUP_TEST && $SHELL $abs_srcdir/../bindings/idl/testidlnapi "'hdf4'" | sed -e 's/\r$//' ],[], 
+[['hdf4'
+NeXus IDL Api Write test
+Using HDF4
+% Loaded DLM: NEXUSIDL-API.
+nxopen status:        1
+nxsetnumberformat status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxputattr status:        1
+nxputattr status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       0
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputslab status:       1
+nxputattr status :        1
+nxputattr status :        1
+nxputattr status :        1
+nxgetdataid status:        1
+nxclosedata status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakelink status:        1
+nxmakecompdata status:       1
+opendata status:        1
+nxputdata status:       0
+nxclosedata status:        1
+nxflush status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputslab            1 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            2 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            3 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            4 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            5 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            6 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            7 status:       1
+nxflush status:        1
+nxclosegroup status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxgetgroupid status:        1
+groupid handle:        2
+nxclosegroup status:        1
+nxclosegroup status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakelink status:        1
+groupid handle       2
+nxmakenamedlink status :        1
+dataid handle       1
+nxmakenamedlink status :        1
+nxclosegroup status:        1
+nxclose status:        1
+
+ ####################  Test external linking  ######################
+
+nxopen status:        1
+nxmakegroup status:        1
+nxlinkexternal:        1
+nxmakegroup status:        1
+nxlinkexternal:        1
+nxclose status:        1
+nxopen status:        1
+nxopenpath status       1
+
+nxget data status:        1
+First file time :
+2005-05-27 05:44:13
+
+nxinquirefile status:        1
+current file: data/dmc01.hdf
+nxopenpath status       1
+nxget data status:        1
+Second file sample :
+Ga0.94Mn0.04Sb_8mm
+
+nxinquirefile status:        1
+current file: data/dmc01.hdf
+nxopenpath status       1
+nxget data status:        1
+Second file time :
+2005-05-27 05:44:13
+
+nxisexternalgroup status       1
+entry1 external URL =
+nxclose status:        1
+% Compiled module: READ_TEST.
+Opening file: NXtest.hdf
+nxopen status:        1
+nxinquirefile status:        1
+nxinquirefile found: NXtest.hdf
+nxgetattrinfo status:       1
+Number of global attributes:        4
+
+NXgetnextattr status:        1
+
+attribute name: NeXus_version
+attribute value: 4.3.2
+
+NXgetnextattr status:        1
+
+attribute name: HDF_version
+attribute value: NCSA HDF Version 4.2 Release 2, October 4, 2007
+
+NXgetnextattr status:        1
+
+attribute name: file_name
+attribute value: NXtest.hdf
+
+NXgetnextattr status:        1
+
+
+NXgetnextattr status:       -1
+
+nxopengroup status:       1
+nxgetattrinfo status:       1
+Number of group attributes:        2
+NXgetnextattr status:        1
+nxgetattr status       1
+attribute name: hugo
+attrubute lenght:        8
+attribute type:        4
+attribute value: namenlos
+
+NXgetnextattr status:        1
+nxgetattr status       1
+attribute name: cucumber
+attrubute lenght:        7
+attribute type:        4
+attribute value: passion
+
+NXgetnextattr status:       -1
+nxgetgroupinfo status       1
+current group name: entry
+current group class: NXentry
+number of items in group:        7
+
+nxgetnextentry status:        1
+nxgetnextentry name: ch_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       4
+
+opening data: ch_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       1
+Dim [       0]:      10
+Data Type:       4
+
+nxget data status:        1
+data :
+NeXus Data
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: i1_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type      21
+
+opening data: i1_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:      21
+
+nxgetslab status:        1
+data :
+   0   4   8  12
+
+nxgetslab status:        1
+data :
+   1   5   9  13
+
+nxgetslab status:        1
+data :
+   2   6  10  14
+
+nxgetslab status:        1
+data :
+   4   7  11  15
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: i4_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type      24
+
+opening data: i4_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:      24
+
+nxgetslab status:        1
+data :
+           0           4           8          12
+
+nxgetslab status:        1
+data :
+           1           5           9          13
+
+nxgetslab status:        1
+data :
+           2           6          10          14
+
+nxgetslab status:        1
+data :
+           3           7          11          15
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: r4_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       5
+
+opening data: r4_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:       5
+
+nxgetslab status:        1
+data :
+  9.96921e+36  9.96921e+36  9.96921e+36  9.96921e+36
+
+nxgetslab status:        1
+data :
+  9.96921e+36  9.96921e+36  9.96921e+36  9.96921e+36
+
+nxgetslab status:        1
+data :
+  9.96921e+36  9.96921e+36  9.96921e+36  9.96921e+36
+
+nxgetslab status:        1
+data :
+  9.96921e+36  9.96921e+36  9.96921e+36  9.96921e+36
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: r8_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       6
+
+opening data: r8_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:       6
+
+nxgetslab status:        1
+data :
+   9.9692100e+36   9.9692100e+36   9.9692100e+36   9.9692100e+36
+
+nxgetslab status:        1
+data :
+   9.9692100e+36   9.9692100e+36   9.9692100e+36   9.9692100e+36
+
+nxgetslab status:        1
+data :
+     0.011111200     0.021222220      0.23333333      0.34444444
+
+nxgetslab status:        1
+data :
+   9.9692100e+36   9.9692100e+36   9.9692100e+36   9.9692100e+36
+
+nxgetattrinfo status:       1
+Number of group attributes:        4
+Number of global attributes:        4
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: ch_attribute
+attribute value: NeXus
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: i4_attribute
+attribute value:           42
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: r4_attribute
+attribute value:       3.14159
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: target
+attribute value: /entry/r8_data
+
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: data
+nxgetnextentry class: NXdata
+nxgetnextentry data_type    1965
+
+nxgetnextentry status:        1
+nxgetnextentry name: sample
+nxgetnextentry class: NXsample
+nxgetnextentry data_type    1965
+
+nxgetnextentry status:       -1
+nxclosegroup status:        1
+
+#######################  Checking Links ###########################
+
+nxopengroup status:       1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+groupid handle:        1
+
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+nxclosedata status:        1
+nxclosegroup status:        1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+nxclosedata status:        1
+debug
+nxsamid status:        1
+Data id: Link check succesfull
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+
+Group Id: Link check succesfull
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+
+Group Id Named: Link check succesfull
+
+nxclosegroup status:        1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+Data Id Named: Link check succesfull
+nxclosedata status:        1
+Openpath succesfull (/entry/data/comp_data)
+Openpath on a relative path  (../r8_data) succesfull
+nxclose status:        1
+finished napi test
+]])
+AT_CLEANUP
+AT_SETUP([Checking IDL binding using HDF5])
+AT_CHECK([$HAVE_HDF5 && $HAVE_IDL && $SETUP_TEST && $SHELL $abs_srcdir/../bindings/idl/testidlnapi "'hdf5'" | sed -e 's/\r$//' ],[], 
+[['hdf5'
+NeXus IDL Api Write test
+Using HDF5
+% Loaded DLM: NEXUSIDL-API.
+nxopen status:        1
+nxsetnumberformat status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxputattr status:        1
+nxputattr status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputslab status:       1
+nxputattr status :        1
+nxputattr status :        1
+nxputattr status :        1
+nxgetdataid status:        1
+nxclosedata status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakelink status:        1
+nxmakecompdata status:       1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxflush status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputslab            1 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            2 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            3 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            4 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            5 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            6 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            7 status:       1
+nxflush status:        1
+nxclosegroup status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxgetgroupid status:        1
+groupid handle:        2
+nxclosegroup status:        1
+nxclosegroup status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakelink status:        1
+groupid handle       2
+nxmakenamedlink status :        1
+dataid handle       1
+nxmakenamedlink status :        1
+nxclosegroup status:        1
+nxclose status:        1
+
+ ####################  Test external linking  ######################
+
+nxopen status:        1
+nxmakegroup status:        1
+nxlinkexternal:        1
+nxmakegroup status:        1
+nxlinkexternal:        1
+nxclose status:        1
+nxopen status:        1
+nxopenpath status       1
+
+nxget data status:        1
+First file time :
+2005-05-27 05:44:13
+
+nxinquirefile status:        1
+current file: data/dmc01.h5
+nxopenpath status       1
+nxget data status:        1
+Second file sample :
+Ga0.94Mn0.04Sb_8mm
+
+nxinquirefile status:        1
+current file: data/dmc01.h5
+nxopenpath status       1
+nxget data status:        1
+Second file time :
+2005-05-27 05:44:13
+
+nxisexternalgroup status       1
+entry1 external URL =
+nxclose status:        1
+% Compiled module: READ_TEST.
+Opening file: NXtest.h5
+nxopen status:        1
+nxinquirefile status:        1
+nxinquirefile found: NXtest.h5
+nxgetattrinfo status:       1
+Number of global attributes:        4
+
+NXgetnextattr status:        1
+
+attribute name: NeXus_version
+attribute value: 4.3.2
+
+NXgetnextattr status:        1
+
+attribute name: file_name
+attribute value: NXtest.h5
+
+NXgetnextattr status:        1
+
+attribute name: HDF5_Version
+attribute value: 1.6.8
+
+NXgetnextattr status:        1
+
+
+NXgetnextattr status:       -1
+
+nxopengroup status:       1
+nxgetattrinfo status:       1
+Number of group attributes:        2
+NXgetnextattr status:        1
+nxgetattr status       1
+attribute name: hugo
+attrubute lenght:        8
+attribute type:        4
+attribute value: namenlos
+
+NXgetnextattr status:        1
+nxgetattr status       1
+attribute name: cucumber
+attrubute lenght:        7
+attribute type:        4
+attribute value: passion
+
+NXgetnextattr status:       -1
+nxgetgroupinfo status       1
+current group name: entry
+current group class: NXentry
+number of items in group:        7
+
+nxgetnextentry status:        1
+nxgetnextentry name: ch_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       4
+
+opening data: ch_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       1
+Dim [       0]:      10
+Data Type:       4
+
+nxget data status:        1
+data :
+NeXus Data
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: data
+nxgetnextentry class: NXdata
+nxgetnextentry data_type       0
+
+nxgetnextentry status:        1
+nxgetnextentry name: i1_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type      21
+
+opening data: i1_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:      21
+
+nxgetslab status:        1
+data :
+   0   4   8  12
+
+nxgetslab status:        1
+data :
+   1   5   9  13
+
+nxgetslab status:        1
+data :
+   2   6  10  14
+
+nxgetslab status:        1
+data :
+   4   7  11  15
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: i4_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type      24
+
+opening data: i4_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:      24
+
+nxgetslab status:        1
+data :
+           0           4           8          12
+
+nxgetslab status:        1
+data :
+           1           5           9          13
+
+nxgetslab status:        1
+data :
+           2           6          10          14
+
+nxgetslab status:        1
+data :
+           3           7          11          15
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: r4_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       5
+
+opening data: r4_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:       5
+
+nxgetslab status:        1
+data :
+    0.0111112     0.344333     0.666669     -12.2000
+
+nxgetslab status:        1
+data :
+    0.0212222     0.555556      1.00000     -13.4444
+
+nxgetslab status:        1
+data :
+     0.233333     0.666667      10.1000     -14.2222
+
+nxgetslab status:        1
+data :
+     0.344444     0.777773      11.2222     -15.4444
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: r8_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       6
+
+opening data: r8_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:       6
+
+nxgetslab status:        1
+data :
+       0.0000000       0.0000000       0.0000000       0.0000000
+
+nxgetslab status:        1
+data :
+       0.0000000       0.0000000       0.0000000       0.0000000
+
+nxgetslab status:        1
+data :
+     0.011111200     0.021222220      0.23333333      0.34444444
+
+nxgetslab status:        1
+data :
+       0.0000000       0.0000000       0.0000000       0.0000000
+
+nxgetattrinfo status:       1
+Number of group attributes:        4
+Number of global attributes:        4
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: ch_attribute
+attribute value: NeXus
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: i4_attribute
+attribute value:           42
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: r4_attribute
+attribute value:       3.14159
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: target
+attribute value: /entry/r8_data
+
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: sample
+nxgetnextentry class: NXsample
+nxgetnextentry data_type       0
+
+nxgetnextentry status:       -1
+nxclosegroup status:        1
+
+#######################  Checking Links ###########################
+
+nxopengroup status:       1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+groupid handle:        1
+
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+nxclosedata status:        1
+nxclosegroup status:        1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+nxclosedata status:        1
+debug
+nxsamid status:        1
+Data id: Link check succesfull
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+
+Group Id: Link check succesfull
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+
+Group Id Named: Link check succesfull
+
+nxclosegroup status:        1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+Data Id Named: Link check succesfull
+nxclosedata status:        1
+Openpath succesfull (/entry/data/comp_data)
+Openpath on a relative path  (../r8_data) succesfull
+nxclose status:        1
+finished napi test
+]])
+AT_CLEANUP
+AT_SETUP([Checking IDL binding using XML])
+AT_CHECK([$HAVE_XML && $HAVE_IDL && $SETUP_TEST && $SHELL $abs_srcdir/../bindings/idl/testidlnapi "'xml'" | sed -e 's/\r$//' ],[], 
+[['xml'
+NeXus IDL Api Write test
+Using XML
+% Loaded DLM: NEXUSIDL-API.
+nxopen status:        1
+nxsetnumberformat status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxputattr status:        1
+nxputattr status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputslab status:       1
+nxputattr status :        1
+nxputattr status :        1
+nxputattr status :        1
+nxgetdataid status:        1
+nxclosedata status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakelink status:        1
+nxmakecompdata status:       1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxflush status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputslab            1 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            2 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            3 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            4 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            5 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            6 status:       1
+nxflush status:        1
+opendata status:        1
+nxputslab            7 status:       1
+nxflush status:        1
+nxclosegroup status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakedata status:        1
+opendata status:        1
+nxputdata status:       1
+nxclosedata status:        1
+nxgetgroupid status:        1
+groupid handle:        2
+nxclosegroup status:        1
+nxclosegroup status:        1
+nxmakegroup status:        1
+nxopengroup status:        1
+nxmakelink status:        1
+groupid handle       2
+nxmakenamedlink status :        1
+dataid handle       1
+nxmakenamedlink status :        1
+nxclosegroup status:        1
+nxclose status:        1
+
+ ####################  Test external linking  ######################
+
+nxopen status:        1
+nxmakegroup status:        1
+nxlinkexternal:        1
+nxmakegroup status:        1
+nxlinkexternal:        1
+nxclose status:        1
+nxopen status:        1
+nxopenpath status       1
+
+nxget data status:        1
+First file time :
+2005-05-27 05:44:13
+
+nxinquirefile status:        1
+current file: data/dmc01.xml
+nxopenpath status       1
+nxget data status:        1
+Second file sample :
+Ga0.94Mn0.04Sb_8mm
+
+nxinquirefile status:        1
+current file: data/dmc01.xml
+nxopenpath status       1
+nxget data status:        1
+Second file time :
+2005-05-27 05:44:13
+
+nxisexternalgroup status       1
+entry1 external URL =
+nxclose status:        1
+% Compiled module: READ_TEST.
+Opening file: NXtest.xml
+nxopen status:        1
+nxinquirefile status:        1
+nxinquirefile found: NXtest.xml
+nxgetattrinfo status:       1
+Number of global attributes:        7
+
+NXgetnextattr status:        1
+
+attribute name: NeXus_version
+attribute value: 4.3.2
+
+NXgetnextattr status:        1
+
+attribute name: XML_version
+attribute value: mxml
+
+NXgetnextattr status:        1
+
+attribute name: file_name
+attribute value: NXtest.xml
+
+NXgetnextattr status:        1
+
+attribute name: xmlns
+attribute value: http://definition.nexusformat.org/schema/3.1
+
+NXgetnextattr status:        1
+
+attribute name: xmlns:xsi
+attribute value: http://www.w3.org/2001/XMLSchema-instance
+
+NXgetnextattr status:        1
+
+attribute name: xsi:schemaLocation
+attribute value: http://definition.nexusformat.org/schema/3.1 http://definition.nexusformat.org/schema/3.0/BASE.xsd
+
+NXgetnextattr status:        1
+
+
+NXgetnextattr status:       -1
+
+nxopengroup status:       1
+nxgetattrinfo status:       1
+Number of group attributes:        2
+NXgetnextattr status:        1
+nxgetattr status       1
+attribute name: hugo
+attrubute lenght:        8
+attribute type:        4
+attribute value: namenlos
+
+NXgetnextattr status:        1
+nxgetattr status       1
+attribute name: cucumber
+attrubute lenght:        7
+attribute type:        4
+attribute value: passion
+
+NXgetnextattr status:       -1
+nxgetgroupinfo status       1
+current group name: entry
+current group class: NXentry
+number of items in group:        7
+
+nxgetnextentry status:        1
+nxgetnextentry name: ch_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       4
+
+opening data: ch_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       1
+Dim [       0]:      10
+Data Type:       4
+
+nxget data status:        1
+data :
+NeXus Data
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: i1_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type      21
+
+opening data: i1_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:      21
+
+nxgetslab status:        1
+data :
+   0   4   8  12
+
+nxgetslab status:        1
+data :
+   1   5   9  13
+
+nxgetslab status:        1
+data :
+   2   6  10  14
+
+nxgetslab status:        1
+data :
+   4   7  11  15
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: i4_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type      24
+
+opening data: i4_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:      24
+
+nxgetslab status:        1
+data :
+           0           4           8          12
+
+nxgetslab status:        1
+data :
+           1           5           9          13
+
+nxgetslab status:        1
+data :
+           2           6          10          14
+
+nxgetslab status:        1
+data :
+           3           7          11          15
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: r4_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       5
+
+opening data: r4_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:       5
+
+nxgetslab status:        1
+data :
+    0.0110000     0.344000     0.667000     -12.2000
+
+nxgetslab status:        1
+data :
+    0.0210000     0.556000      1.00000     -13.4440
+
+nxgetslab status:        1
+data :
+     0.233000     0.667000      10.1000     -14.2220
+
+nxgetslab status:        1
+data :
+     0.344000     0.778000      11.2220     -15.4440
+
+nxgetattrinfo status:       1
+Number of group attributes:        0
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: r8_data
+nxgetnextentry class: SDS
+nxgetnextentry data_type       6
+
+opening data: r8_data
+nxopendata status:        1
+
+nxgetinfo Status:       1
+Rank:       2
+Dim [       0]:       4
+Dim [       1]:       4
+Data Type:       6
+
+nxgetslab status:        1
+data :
+       0.0000000       0.0000000       0.0000000       0.0000000
+
+nxgetslab status:        1
+data :
+       0.0000000       0.0000000       0.0000000       0.0000000
+
+nxgetslab status:        1
+data :
+     0.011110000     0.021220000      0.23333000      0.34444000
+
+nxgetslab status:        1
+data :
+       0.0000000       0.0000000       0.0000000       0.0000000
+
+nxgetattrinfo status:       1
+Number of group attributes:        4
+Number of global attributes:        4
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: ch_attribute
+attribute value: NeXus
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: i4_attribute
+attribute value:           42
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: r4_attribute
+attribute value:       3.14159
+
+nxgetnextattr status:        1
+nxgetattr status       1
+attribute name: target
+attribute value: /entry/r8_data
+
+nxgetnextattr status:       -1
+nxclosedata status:        1
+nxgetnextentry status:        1
+nxgetnextentry name: data
+nxgetnextentry class: NXdata
+nxgetnextentry data_type       0
+
+nxgetnextentry status:        1
+nxgetnextentry name: sample
+nxgetnextentry class: NXsample
+nxgetnextentry data_type       0
+
+nxgetnextentry status:       -1
+nxclosegroup status:        1
+
+#######################  Checking Links ###########################
+
+nxopengroup status:       1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+groupid handle:        1
+
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+nxclosedata status:        1
+nxclosegroup status:        1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+nxclosedata status:        1
+debug
+nxsamid status:        1
+Data id: Link check succesfull
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+
+Group Id: Link check succesfull
+nxclosegroup status:        1
+
+nxopengroup status:       1
+
+nxgetgroupid status:        1
+
+Group Id Named: Link check succesfull
+
+nxclosegroup status:        1
+
+nxopendata status:        1
+
+nxgetdataid status:        1
+Data Id Named: Link check succesfull
+nxclosedata status:        1
+Openpath succesfull (/entry/data/comp_data)
+Openpath on a relative path  (../r8_data) succesfull
+nxclose status:        1
+finished napi test
+]])
+AT_CLEANUP
+
+AT_BANNER([[Testing the NeXus File Converter.]])
+AT_SETUP([Checking nxconvert HDF4 -> HDF4 ])
+AT_CHECK([$HAVE_HDF4 && nxconvert --hdf 4 NXtest.hdf a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.hdf to HDF4 NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxconvert HDF4 -> HDF5 ])
+AT_CHECK([$HAVE_HDF4 && $HAVE_HDF5 && nxconvert --hdf 5 NXtest.hdf a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.hdf to HDF5 NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxconvert HDF4 -> XML ])
+AT_CHECK([$HAVE_HDF4 && $HAVE_XML && nxconvert -x NXtest.hdf a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.hdf to XML NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+#AT_SETUP([Checking nxconvert HDF5 -> HDF4 ])
+#AT_CHECK([$HAVE_HDF5 && $HAVE_HDF4 && nxconvert --hdf 4 NXtest.h5 a.a | sed -e 's/\r$//' ],[], 
+#[[Converting NXtest.h5 to HDF4 NeXus file a.a
+#Convertion successful.
+#]])
+#AT_CLEANUP
+AT_SETUP([Checking nxconvert HDF5 -> HDF5 ])
+AT_CHECK([$HAVE_HDF5 && nxconvert --hdf 5 NXtest.h5 a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.h5 to HDF5 NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxconvert HDF5 -> XML ])
+AT_CHECK([$HAVE_HDF5 && $HAVE_XML && nxconvert -x NXtest.h5 a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.h5 to XML NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+#AT_SETUP([Checking nxconvert XML -> HDF4 ])
+#AT_CHECK([$HAVE_XML && $HAVE_HDF4 && nxconvert --hdf 4 NXtest.xml a.a | sed -e 's/\r$//' ],[], 
+#[[Converting NXtest.xml to HDF4 NeXus file a.a
+#Convertion successful.
+#]])
+#AT_CLEANUP
+AT_SETUP([Checking nxconvert XML -> HDF5 ])
+AT_CHECK([$HAVE_XML && $HAVE_HDF5 && nxconvert --hdf 5 NXtest.xml a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.xml to HDF5 NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxconvert XML -> XML ])
+AT_CHECK([$HAVE_XML && nxconvert -x NXtest.xml a.a | sed -e 's/\r$//' ],[], 
+[[Converting NXtest.xml to XML NeXus file a.a
+Convertion successful.
+]])
+AT_CLEANUP
+
+AT_BANNER([[Testing NXsummary Tool.]])
+AT_SETUP([Checking nxsummary HDF4 test file])
+AT_CHECK([$HAVE_HDF4 && $HAVE_NXSUMMARY && nxsummary --config NONE NXtest.hdf | sed -e 's/\r$//' ],[], 
+[[SAMPLE:
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxsummary HDF5 test file])
+AT_CHECK([$HAVE_HDF5 && $HAVE_NXSUMMARY && nxsummary --config NONE NXtest.h5 | sed -e 's/\r$//' ],[], 
+[[SAMPLE:
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxsummary XML test file])
+AT_CHECK([$HAVE_XML && $HAVE_NXSUMMARY && nxsummary --config NONE NXtest.xml | sed -e 's/\r$//' ],[], 
+[[SAMPLE:
+]])
+AT_CLEANUP
+
+AT_BANNER([[Testing NXbrowse Tool.]])
+AT_SETUP([Checking nxbrowse HDF4 test file])
+AT_CHECK([$HAVE_HDF4 && env NO_READLINE=1 nxbrowse NXtest.hdf  < ${abs_srcdir}/nxbrowse.txt | grep -v 'HDF_version = ' | grep -v 'file_time = ' | grep -v 'readline support' | sed -e 's/\r$//' | sed -e 's/[ ]*$//' ],[], 
+[[NXBrowse 4.3.2 Copyright (C) 2009 NeXus Data Format
+    NeXus_version = 4.3.2
+    file_name = NXtest.hdf
+NX>   NX Group : entry (NXentry)
+             entry attribute: hugo = namenlos
+             entry attribute: cucumber = passion
+  NX Group : link (NXentry)
+NX>
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxbrowse HDF5 test file])
+AT_CHECK([$HAVE_HDF5 && env NO_READLINE=1 nxbrowse NXtest.h5  < ${abs_srcdir}/nxbrowse.txt | grep -v 'HDF5_Version = ' | grep -v 'file_time = ' | grep -v 'readline support' | sed -e 's/\r$//' | sed -e 's/[ ]*$//' ],[], 
+[[NXBrowse 4.3.2 Copyright (C) 2009 NeXus Data Format
+    NeXus_version = 4.3.2
+    file_name = NXtest.h5
+NX>   NX Group : entry (NXentry)
+             entry attribute: hugo = namenlos
+             entry attribute: cucumber = passion
+  NX Group : link (NXentry)
+NX>
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxbrowse XML test file])
+AT_CHECK([$HAVE_XML && env NO_READLINE=1 nxbrowse NXtest.xml  < ${abs_srcdir}/nxbrowse.txt | grep -v 'file_time = ' | grep -v 'XML_version = ' | grep -v 'readline support' | sed -e 's/\r$//' | sed -e 's/[ ]*$//' ],[], 
+[[NXBrowse 4.3.2 Copyright (C) 2009 NeXus Data Format
+    NeXus_version = 4.3.2
+    file_name = NXtest.xml
+    xmlns = http://definition.nexusformat.org/schema/3.1
+    xmlns:xsi = http://www.w3.org/2001/XMLSchema-instance
+    xsi:schemaLocation = http://definition.nexusformat.org/schema/3.1 http://definition.nexusformat.org/schema/3.1/BASE.xsd
+NX>   NX Group : entry (NXentry)
+             entry attribute: hugo = namenlos
+             entry attribute: cucumber = passion
+  NX Group : link (NXentry)
+NX>
+]])
+AT_CLEANUP
+
+AT_BANNER([[Testing NXdir Tool.]])
+AT_SETUP([Checking nxdir HDF4 test file])
+AT_CHECK([$HAVE_HDF4 && nxdir NXtest.hdf | sed -e 's/\r$//' ],[], 
+[[/entry/
+/link/
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxdir HDF5 test file])
+AT_CHECK([$HAVE_HDF5 && nxdir NXtest.h5 | sed -e 's/\r$//' ],[], 
+[[/entry/
+/link/
+]])
+AT_CLEANUP
+AT_SETUP([Checking nxdir XML test file])
+AT_CHECK([$HAVE_XML && nxdir NXtest.xml | sed -e 's/\r$//' ],[], 
+[[/entry/
+/link/
+]])
+AT_CLEANUP
+
+
+dnl AT_BANNER([[Testing validating files with the nxvalidate tool.]])
+dnl AT_SETUP([Checking HDF4 test file via web (wget)])
+dnl AT_CHECK([$HAVE_HDF4 && $HAVE_WGET && $SETUP_TEST && napi_test-hdf4 -q && nxvalidate -q -w NXtest.hdf | sed -e 's/\r$//' ],[], 
+dnl 
+dnl AT_CLEANUP
+dnl AT_SETUP([Checking HDF5 test file via web (wget)])
+dnl AT_CHECK([$HAVE_HDF4 && $HAVE_WGET && $SETUP_TEST && napi_test-hdf5 -q && nxvalidate -q -w NXtest.h5 | sed -e 's/\r$//' ],[], 
+dnl 
+dnl AT_CLEANUP
+dnl AT_SETUP([Checking XML test file via web (wget)])
+dnl AT_CHECK([$HAVE_HDF4 && $HAVE_WGET && $SETUP_TEST && napi_test-xml -q && nxvalidate -q -w NXtest.xml | sed -e 's/\r$//' ],[], 
+dnl 
+dnl AT_CLEANUP
diff --git a/test/testsuitetojunit.py b/test/testsuitetojunit.py
new file mode 100755
index 0000000..b924d0c
--- /dev/null
+++ b/test/testsuitetojunit.py
@@ -0,0 +1,188 @@
+#!/bin/env python
+filenamein = "testsuite.log"
+filenameout = "testsuite.xml"
+verbose = 0
+
+import os
+import sys
+
+def getSourceDir():
+    """Returns the location of the source code."""
+    script = os.path.abspath(sys.argv[0])
+    if os.path.islink(script):
+        script = os.path.realpath(script)
+    return os.path.dirname(script)
+
+class Test:
+    def __init__(self, text, verbose):
+        if verbose > 1:
+            print "*****", text
+        self.__time = 0.
+        self.__totaltime = 0.
+        self.__getStatus(text)
+        self.__getTimes(text)
+
+        # trim down the text to just what we need for line number
+        start = text.find("testsuite.at")
+        stop = text.find(": ", start)
+        lineref = text[start:stop]
+        index = lineref.find(":")
+        self.__line = int(lineref[index+1:-1])
+
+        # get the group and name
+        self.__group = "unknown"
+        self.__name = "dob"
+
+        text = text[:start-1]
+        index = text.find(" ")
+        text = text[index:].strip()
+        text = text.replace("Checking", "")
+        text = text.replace("Check the", "")
+        text = text.replace("C++", "CXX")
+        text = text.replace("->", "to")
+        text = text.replace("(", "")
+        text = text.replace(")", "")
+        text = text.replace("xml", "XML")
+        text = text.strip()
+        if text.endswith('.'):
+            text = text[:-1]
+        text = "_".join(text.split())
+
+        (self.__group, self.__name) = self.__splitGroup(text)
+        if verbose > 1:
+            print text, "->", (self.__group, self.__name)
+
+    def __splitGroup(self, text):
+        # is it a binding
+        if "binding" in text:
+            splitted = text.split('_')
+            if splitted[0] in ("C", "CXX", "F77", "F90", "python", "IDL"):
+                return (splitted[0], "_".join(splitted[3:]))
+
+        # is it an application
+        app = text.split('_')[0]
+        if app in ("nxconvert", "nxbrowse", "nxdir", "nxsummary"):
+            return (app, text.replace(app+"_", ""))
+
+        # give up
+        return ("unknown", text)
+
+    def __getStatus(self,text):
+        self.__msg = "<![CDATA[" + text + "]]>"
+        self.status = "failed"
+        if "skipped" in text:
+            self.status = "skipped"
+        elif "ok   " in text:
+            self.status = "passed"
+        
+    def __getTimes(self, text):
+        if self.status == "skipped":
+            return # there is no time
+
+        splitted = text.split()[-2:]
+        splitted[0] = splitted[0][1:]
+        splitted[1] = splitted[1][:-1]
+        splitted = [item[:-1] for item in splitted]
+        splitted = [item.split('m') for item in splitted]
+        self.__totaltime = float(splitted[0][0]) * 60. + float(splitted[0][1])
+        self.__time = float(splitted[1][0]) * 60. + float(splitted[1][1])
+
+    def write(self, handle):
+        handle.write('<testcase classname="%s" name="%s" ' % \
+                     (self.__group, self.__name))
+        handle.write('line="%d" ' % self.__line)
+        handle.write('time="%f" ' % self.__time)
+        handle.write('totalTime="%f"' % self.__totaltime)
+        if self.status == "passed":
+            handle.write('/>\n')
+            return
+
+        handle.write('>\n')
+
+        handle.write('<%s>\n' % self.status)
+        handle.write(self.__msg)
+        handle.write('</%s>\n' % self.status)
+
+        handle.write('</testcase>\n')
+
+class TestSuite:
+    def __init__(self, data, verbose):
+        self.__suitename = "NeXus"
+        self.__tests = []
+        self.__success = 0
+        self.__failures = 0
+        self.__skipped = 0
+        self.__totaltime = 0
+
+        # find the total execution time
+        for (i, line) in zip(range(len(data)), data):
+            if line.startswith('testsuite:') and 'duration' in line:
+                splitted = line.split()
+                splitted = splitted[-3:]
+                splitted = [float(item[:-1]) for item in splitted]
+                (h,m,s) = splitted
+                self.__totaltime = s + 60 * m + 3600 * h
+                lastindex = i
+
+        # trim the data down again
+        data = data[:lastindex-1]
+
+        # create the individual tests
+        for line in data:
+            test = Test(line, verbose)
+            self.__tests.append(test)
+            if test.status == "skipped":
+                self.__skipped += 1
+            elif test.status == "passed":
+                self.__success += 1
+            else:
+                self.__failures += 1
+
+    def write(self, filename):
+        handle = file(filename, 'w')
+        handle.write('<?xml version="1.0" encoding="UTF-8" ?>\n')
+
+        handle.write('<testsuite name="%s" ' % self.__suitename)
+        handle.write('tests="%d" ' % len(self.__tests))
+        handle.write('failures="%d" ' % self.__failures)
+        handle.write('skipped="%d" ' % self.__skipped)
+        handle.write('package="%s" ' % self.__suitename)
+        handle.write('time="%f" ' % self.__totaltime)
+        handle.write('>\n')
+
+        for test in self.__tests:
+            test.write(handle)
+
+        handle.write('</testsuite>\n')
+
+
+def getTests(filename, verbose):
+    handle = file(filename, 'r')
+
+    data = handle.readlines()
+    data = [line.strip() for line in data]
+    handle.close()
+    for (i, line) in zip(range(len(data)), data):
+        if line.startswith("## Running the tests. ##"):
+            startindex = i
+            break
+    data = data[startindex+3:]
+    if verbose > 3:
+        print "\n".join(data)
+
+    tests = TestSuite(data, verbose)
+
+    return tests
+
+if __name__ == "__main__":
+    sourceDir = getSourceDir()
+    filenamein = os.path.join(sourceDir, filenamein)
+    filenameout = os.path.join(sourceDir, filenameout)
+    
+    print "Converting '%s' to '%s'" % (filenamein, filenameout)
+    if verbose:
+        print "Reading in", filenamein
+    tests = getTests(filenamein, verbose)
+    if verbose:
+        print "Writing out", filenameout
+    tests.write(filenameout)
diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt
new file mode 100644
index 0000000..803d622
--- /dev/null
+++ b/third_party/CMakeLists.txt
@@ -0,0 +1,32 @@
+## Process this file with cmake
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  CMakeLists for building the NeXus library and applications.
+#
+#  Copyright (C) 2011 Stephen Rankin
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#
+#====================================================================
+
+add_subdirectory (tclap)
+if(HAVE_XML)
+add_subdirectory (mxml-2.6)
+endif(HAVE_XML)
\ No newline at end of file
diff --git a/third_party/Makefile.am b/third_party/Makefile.am
new file mode 100644
index 0000000..143b89a
--- /dev/null
+++ b/third_party/Makefile.am
@@ -0,0 +1,31 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  $Id: Makefile.am 1247 2009-04-21 18:14:24Z Freddie Akeroyd $
+#
+#  Top level Makefile for coordinating NeXus build
+#  
+#  Copyright (C) 2004 Freddie Akeroyd
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#  @configure_input@
+#
+#====================================================================
+
+SUBDIRS=tclap
diff --git a/third_party/README.txt b/third_party/README.txt
new file mode 100644
index 0000000..2ad7bdd
--- /dev/null
+++ b/third_party/README.txt
@@ -0,0 +1,4 @@
+mxml: Mini-XML 2.6 from www.minixml.org
+HDF5: HDF5-1.8.7 from www.hdfgroup.org with some bits removed (e.g. examples, applications, fortran, C++, HDF5 high level API)
+
+$Id: $
\ No newline at end of file
diff --git a/third_party/tclap/AUTHORS b/third_party/tclap/AUTHORS
new file mode 100644
index 0000000..875a852
--- /dev/null
+++ b/third_party/tclap/AUTHORS
@@ -0,0 +1,6 @@
+
+original author: Michael E. Smoot
+invaluable contributions: Daniel Aarno
+more contributions: Erik Zeek
+more contributions: Fabien Carmagnac (Tinbergen-AM)
+outstanding editing: Carol Smoot
diff --git a/third_party/tclap/Arg.h b/third_party/tclap/Arg.h
new file mode 100644
index 0000000..16e0560
--- /dev/null
+++ b/third_party/tclap/Arg.h
@@ -0,0 +1,672 @@
+// -*- 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:
+
+		/**
+		 * 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.  Currently '-'.
+		 */
+		static char flagStartChar() { return '-'; }
+
+		/**
+		 * The sting that indicates the beginning of a flag.  Currently "-".
+		 * Should be identical to flagStartChar.
+		 */
+		static const std::string flagStartString() { return "-"; }
+
+		/**
+		 * The sting that indicates the beginning of a name.  Currently "--".
+		 * Should be flagStartChar twice.
+		 */
+		static const std::string nameStartString() { return "--"; }
+
+		/**
+		 * 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/third_party/tclap/ArgException.h b/third_party/tclap/ArgException.h
new file mode 100644
index 0000000..3411aa9
--- /dev/null
+++ b/third_party/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/third_party/tclap/ArgTraits.h b/third_party/tclap/ArgTraits.h
new file mode 100644
index 0000000..a89ed12
--- /dev/null
+++ b/third_party/tclap/ArgTraits.h
@@ -0,0 +1,81 @@
+// -*- 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;
+};
+
+/**
+ * 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 {};
+
+/**
+ * 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;
+};
+
+/**
+ * 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;
+};
+
+/**
+ * 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 string like and value like.
+ */
+template<typename T>
+struct ArgTraits {
+    typedef typename T::ValueCategory ValueCategory;
+    //typedef ValueLike ValueCategory;
+};
+
+#endif
+
+} // namespace
diff --git a/third_party/tclap/CMakeLists.txt b/third_party/tclap/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/third_party/tclap/COPYING b/third_party/tclap/COPYING
new file mode 100644
index 0000000..987be0c
--- /dev/null
+++ b/third_party/tclap/COPYING
@@ -0,0 +1,25 @@
+
+
+Copyright (c) 2003 Michael E. Smoot 
+
+Permission is hereby granted, free of charge, to any person 
+obtaining a copy of this software and associated documentation 
+files (the "Software"), to deal in the Software without restriction, 
+including without limitation the rights to use, copy, modify, merge, 
+publish, distribute, sublicense, and/or sell copies of the Software, 
+and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be 
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+THE SOFTWARE.
+
+
diff --git a/third_party/tclap/ChangeLog b/third_party/tclap/ChangeLog
new file mode 100644
index 0000000..3bdb2ad
--- /dev/null
+++ b/third_party/tclap/ChangeLog
@@ -0,0 +1,1199 @@
+2006-02-21  <>
+	Generated with cvs2cl. 
+
+2005-09-10 19:25  mes5k
+
+	* config/stamp-h1, examples/test2.cpp, examples/test3.cpp,
+	  examples/test5.cpp, examples/test8.cpp, include/tclap/Arg.h,
+	  include/tclap/CmdLine.h, include/tclap/MultiArg.h,
+	  include/tclap/StdOutput.h, include/tclap/UnlabeledMultiArg.h,
+	  include/tclap/UnlabeledValueArg.h, include/tclap/ValueArg.h,
+	  include/tclap/XorHandler.h: added gcc warning patch
+
+2005-07-12 23:36  zeekec
+
+	* examples/Makefile.am: Set INCLUDES to top_srcdir for out of
+	  source builds.
+
+2005-07-12 23:33  zeekec
+
+	* include/tclap/: UnlabeledMultiArg.h, UnlabeledValueArg.h: Add
+	  using toString statements (for gcc >= 3.4).
+
+2005-07-12 23:31  zeekec
+
+	* config/bb_enable_doxygen.m4: Properly quote BB_ENABLE_DOXYGEN.
+
+2005-06-29 18:04  mes5k
+
+	* include/tclap/Arg.h: merged some new changes
+
+2005-06-08 11:28  mes5k
+
+	* docs/index.html: fixed spelling mistake
+
+2005-06-02 22:35  mes5k
+
+	* include/tclap/: Makefile.am, OptionalUnlabeledTracker.h,
+	  UnlabeledMultiArg.h, UnlabeledValueArg.h: fix to handle optional
+	  unlabeled args
+
+2005-06-02 22:33  mes5k
+
+	* examples/: test2.cpp, test3.cpp, test7.cpp, test8.cpp, test9.cpp:
+	  Unlabeled changes
+
+2005-02-03 18:04  mes5k
+
+	* include/tclap/: Arg.h, DocBookOutput.h, MultiArg.h: updated
+	  docbook output
+
+2005-02-03 11:08  mes5k
+
+	* include/tclap/: ValuesConstraint.h, XorHandler.h: add std::
+	  prefix to some finds
+
+2005-02-01 16:35  zeekec
+
+	* include/tclap/CmdLine.h: Made deleteOnExit's protected to
+	  facilitate derivation.
+
+2005-02-01 16:30  zeekec
+
+	* config/config.h.in: Removed autotools generated file.
+
+2005-01-28 16:26  zeekec
+
+	* configure.in, docs/Doxyfile.in, tests/Makefile.am,
+	  tests/test1.sh, tests/test10.sh, tests/test11.sh,
+	  tests/test12.sh, tests/test13.sh, tests/test14.sh,
+	  tests/test15.sh, tests/test16.sh, tests/test17.sh,
+	  tests/test18.sh, tests/test19.sh, tests/test2.sh,
+	  tests/test20.sh, tests/test21.sh, tests/test22.sh,
+	  tests/test23.sh, tests/test24.sh, tests/test25.sh,
+	  tests/test26.sh, tests/test27.sh, tests/test28.sh,
+	  tests/test29.sh, tests/test3.sh, tests/test30.sh,
+	  tests/test31.sh, tests/test32.sh, tests/test33.sh,
+	  tests/test34.sh, tests/test35.sh, tests/test36.sh,
+	  tests/test37.sh, tests/test38.sh, tests/test39.sh,
+	  tests/test4.sh, tests/test40.sh, tests/test41.sh,
+	  tests/test42.sh, tests/test43.sh, tests/test44.sh,
+	  tests/test45.sh, tests/test46.sh, tests/test47.sh,
+	  tests/test48.sh, tests/test49.sh, tests/test5.sh,
+	  tests/test50.sh, tests/test51.sh, tests/test52.sh,
+	  tests/test53.sh, tests/test54.sh, tests/test55.sh,
+	  tests/test56.sh, tests/test57.sh, tests/test58.sh,
+	  tests/test59.sh, tests/test6.sh, tests/test60.sh, tests/test7.sh,
+	  tests/test8.sh, tests/test9.sh: Made changes to directory
+	  references to allow out of source builds.
+
+2005-01-26 13:25  mes5k
+
+	* aclocal.m4: doh
+
+2005-01-23 22:18  mes5k
+
+	* include/tclap/CmdLine.h: removed -v from version switch
+
+2005-01-23 22:14  mes5k
+
+	* include/tclap/Arg.h: removed value required
+
+2005-01-23 22:03  mes5k
+
+	* examples/: test2.cpp, test3.cpp, test6.cpp, test8.cpp, test9.cpp:
+	  UnlabeledValueArg change
+
+2005-01-23 22:02  mes5k
+
+	* tests/: test10.out, test11.out, test12.out, test15.out,
+	  test16.out, test17.out, test22.out, test23.out, test24.out,
+	  test26.out, test27.out, test28.out, test29.out, test30.out,
+	  test31.out, test32.out, test35.out, test36.out, test38.out,
+	  test39.out, test4.out, test40.out, test41.out, test42.out,
+	  test43.out, test44.out, test45.out, test46.out, test49.out,
+	  test50.out, test51.out, test52.out, test53.out, test54.out,
+	  test57.out, test59.out, test60.out, test7.out: new output for
+	  default version and value required
+
+2005-01-23 22:01  mes5k
+
+	* tests/: test59.sh, test8.sh: new style version and required
+	  UnlabeledValueArgs
+
+2005-01-23 21:59  mes5k
+
+	* tests/testCheck.sh: a script to compare test output
+
+2005-01-23 20:54  mes5k
+
+	* include/tclap/UnlabeledValueArg.h: now optionally required
+
+2005-01-23 19:33  mes5k
+
+	* tests/: test58.out, test59.out, test58.sh, test59.sh, test60.out,
+	  test60.sh, Makefile.am: tests for MultiSwitchArg
+
+2005-01-23 19:27  mes5k
+
+	* include/tclap/Makefile.am, examples/Makefile.am,
+	  examples/test9.cpp: MultiSwitchArg
+
+2005-01-23 19:26  mes5k
+
+	* include/tclap/: CmdLine.h, CmdLineInterface.h, StdOutput.h: added
+	  a bool to the constructor that allows automatic -h and -v to be
+	  turned off
+
+2005-01-23 17:57  mes5k
+
+	* docs/: manual.html, manual.xml: added MultiSwitchArg docs
+
+2005-01-23 17:33  mes5k
+
+	* include/tclap/MultiSwitchArg.h: fixed typo
+
+2005-01-23 17:29  mes5k
+
+	* include/tclap/SwitchArg.h: Fixed minor bug involving combined
+	  switch error messages: now they're consistent.
+
+2005-01-23 17:28  mes5k
+
+	* include/tclap/MultiSwitchArg.h: initial checkin
+
+2005-01-22 23:41  mes5k
+
+	* include/tclap/UnlabeledMultiArg.h: added alreadySet
+
+2005-01-20 23:13  mes5k
+
+	* tests/Makefile.am: xor test
+
+2005-01-20 23:04  mes5k
+
+	* examples/test5.cpp: change for xor bug
+
+2005-01-20 23:04  mes5k
+
+	* tests/: test20.out, runtests.sh, test20.sh, test21.out,
+	  test21.sh, test22.out, test23.out, test24.out, test25.out,
+	  test25.sh, test33.out, test33.sh, test44.out, test57.out,
+	  test57.sh: changes for xor bug
+
+2005-01-20 23:03  mes5k
+
+	* include/tclap/: Arg.h, MultiArg.h, UnlabeledMultiArg.h,
+	  XorHandler.h: fixed xor bug
+
+2005-01-17 15:48  macbishop
+
+	* include/tclap/Arg.h: Removed check on description in
+	  Arg::operator== since multiple args should be able to have the
+	  same description.
+
+2005-01-06 23:41  mes5k
+
+	* NEWS: updated for constraints
+
+2005-01-06 23:37  mes5k
+
+	* docs/: manual.html, manual.xml: updated for constraints
+
+2005-01-06 23:05  mes5k
+
+	* examples/test7.cpp: changed for constraint
+
+2005-01-06 23:00  mes5k
+
+	* include/tclap/: MultiArg.h, ValueArg.h: fixed exceptions and
+	  typeDesc for constraints
+
+2005-01-06 22:59  mes5k
+
+	* tests/: test35.out, test36.out, test38.out, test39.out: changed
+	  for constraints
+
+2005-01-06 22:07  mes5k
+
+	* examples/test6.cpp: changed to constraint
+
+2005-01-06 22:06  mes5k
+
+	* include/tclap/Makefile.am: added constraints
+
+2005-01-06 22:05  mes5k
+
+	* include/tclap/: Constraint.h, ValuesConstraint.h: initial checkin
+
+2005-01-06 22:05  mes5k
+
+	* include/tclap/StdOutput.h: comment change
+
+2005-01-06 22:01  mes5k
+
+	* include/tclap/CmdLine.h: added Constraint includes
+
+2005-01-06 21:55  mes5k
+
+	* include/tclap/: MultiArg.h, UnlabeledMultiArg.h,
+	  UnlabeledValueArg.h, ValueArg.h: Changed allowedList to
+	  Constraint
+
+2005-01-05 19:08  mes5k
+
+	* configure.in: next vers
+
+2005-01-05 15:13  mes5k
+
+	* NEWS: update
+
+2005-01-05 13:51  mes5k
+
+	* docs/: manual.html, manual.xml: fixed output override bug
+
+2005-01-05 13:45  mes5k
+
+	* tests/: test18.out, test43.out: change for output override bug
+
+2005-01-05 13:28  mes5k
+
+	* examples/test4.cpp: fixed output override bug
+
+2005-01-05 13:22  mes5k
+
+	* include/tclap/: CmdLine.h, HelpVisitor.h, VersionVisitor.h: fixed
+	  output bug
+
+2005-01-04 17:01  mes5k
+
+	* configure.in: 1.0.4
+
+2005-01-04 16:16  mes5k
+
+	* examples/test7.cpp: changed for long prog names bug
+
+2005-01-04 16:15  mes5k
+
+	* tests/: test38.out, test39.out, test46.out: changed test7 for
+	  long prog names
+
+2005-01-04 15:31  mes5k
+
+	* NEWS: updates for 1.0.3a
+
+2005-01-04 15:21  mes5k
+
+	* docs/manual.html, docs/manual.xml, include/tclap/CmdLine.h: fixed
+	  output memory leak
+
+2004-12-09 00:10  mes5k
+
+	* include/tclap/StdOutput.h: hacky fix to long prog name bug
+
+2004-12-07 22:57  mes5k
+
+	* configure.in: 1.0.3a
+
+2004-12-07 22:53  mes5k
+
+	* tests/: Makefile.am, test15.out, test16.out, test17.out,
+	  test31.out, test32.out, test13.sh, test14.sh, test15.sh,
+	  test16.sh, test17.sh, test42.out, test55.out, test55.sh,
+	  test56.out, test56.sh: updated for - arg bug
+
+2004-12-07 22:51  mes5k
+
+	* examples/test3.cpp: tweaked to support tests for '-' arg bug
+
+2004-12-07 21:16  mes5k
+
+	* include/tclap/Arg.h: fixed a bug involving blank _flags and - as
+	  an UnlabeledValueArg
+
+2004-12-03 15:19  mes5k
+
+	* docs/style.css: minor tweak for h1
+
+2004-12-03 15:10  mes5k
+
+	* NEWS: update
+
+2004-12-03 14:39  mes5k
+
+	* include/tclap/CmdLine.h: removed ostream include
+
+2004-11-30 22:11  mes5k
+
+	* include/tclap/: Arg.h, CmdLine.h, CmdLineOutput.h, StdOutput.h:
+	  cleaned up iterator names
+
+2004-11-30 22:10  mes5k
+
+	* include/tclap/DocBookOutput.h: removed ostream
+
+2004-11-30 21:35  mes5k
+
+	* configure.in, docs/Doxyfile.in: added dot check
+
+2004-11-24 22:58  mes5k
+
+	* configure.in: 1.0.3
+
+2004-11-24 22:57  mes5k
+
+	* include/tclap/: UnlabeledMultiArg.h, UnlabeledValueArg.h: removed
+	  two stage lookup ifdefs
+
+2004-11-24 22:56  mes5k
+
+	* docs/index.html: updated
+
+2004-11-24 22:45  mes5k
+
+	* docs/: manual.html, manual.xml: updates for using stuff and new
+	  output
+
+2004-11-06 00:05  mes5k
+
+	* include/tclap/: DocBookOutput.h, Makefile.am: adding docbook
+	  stuff
+
+2004-11-05 00:07  mes5k
+
+	* examples/test4.cpp: reflects new output handling
+
+2004-11-05 00:07  mes5k
+
+	* include/tclap/: Arg.h, CmdLine.h, CmdLineInterface.h,
+	  CmdLineOutput.h, HelpVisitor.h, Makefile.am, StdOutput.h,
+	  VersionVisitor.h, XorHandler.h: changed output around
+
+2004-11-05 00:06  mes5k
+
+	* include/tclap/PrintSensibly.h: subsumed by StdOutput
+
+2004-10-31 17:13  mes5k
+
+	* docs/manual.html: tweak
+
+2004-10-30 18:58  mes5k
+
+	* NEWS, README: updates
+
+2004-10-30 18:51  mes5k
+
+	* docs/Makefile.am: added manual.xml
+
+2004-10-30 18:47  mes5k
+
+	* docs/: manual.html, manual.xml, style.css: minor tweaks
+
+2004-10-30 18:34  mes5k
+
+	* configure.in: 1.0.2
+
+2004-10-30 18:30  mes5k
+
+	* docs/README: init
+
+2004-10-30 18:30  mes5k
+
+	* docs/style.css: new style
+
+2004-10-30 18:30  mes5k
+
+	* docs/: manual.html, manual.xml: manual.html is now generated from
+	  manual.xml
+
+2004-10-30 18:26  mes5k
+
+	* include/tclap/: MultiArg.h, ValueArg.h: yet another fix for
+	  HAVE_SSTREAM stuff
+
+2004-10-30 11:42  mes5k
+
+	* NEWS: 1.0.1
+
+2004-10-30 11:03  mes5k
+
+	* configure.in: new release
+
+2004-10-28 12:41  mes5k
+
+	* include/tclap/: ValueArg.h, MultiArg.h: fixed config.h problems
+
+2004-10-27 22:44  mes5k
+
+	* docs/manual.xml: manual as docbook
+
+2004-10-22 11:56  mes5k
+
+	* docs/style.css: added visited color to links
+
+2004-10-22 10:38  mes5k
+
+	* docs/index.html: fixed mailto
+
+2004-10-21 21:58  mes5k
+
+	* docs/: manual.html: minor tweaks
+
+2004-10-21 21:13  mes5k
+
+	* docs/manual.html: updated for new test1
+
+2004-10-21 21:02  mes5k
+
+	* include/tclap/CmdLine.h: catch by ref
+
+2004-10-21 21:01  mes5k
+
+	* examples/: test1.cpp, test2.cpp, test3.cpp, test4.cpp, test5.cpp,
+	  test6.cpp, test7.cpp, test8.cpp: changed test1 and now catching
+	  exceptions by ref
+
+2004-10-21 20:38  mes5k
+
+	* tests/: test1.out, test1.sh, test2.out, test3.out, test3.sh,
+	  test4.out, test40.out: changes for new test1
+
+2004-10-21 18:50  mes5k
+
+	* examples/test1.cpp: fixed includes
+
+2004-10-21 13:03  mes5k
+
+	* docs/index.html: changed link
+
+2004-10-21 12:02  mes5k
+
+	* include/tclap/: ValueArg.h, MultiArg.h: changed enum names
+	  because of alpha conflicts
+
+2004-10-20 23:04  mes5k
+
+	* include/tclap/: CmdLine.h, CmdLineInterface.h, MultiArg.h,
+	  PrintSensibly.h, SwitchArg.h, UnlabeledMultiArg.h,
+	  UnlabeledValueArg.h, ValueArg.h, XorHandler.h: cleaned up some
+	  includes and added ifdefs for sstream
+
+2004-10-20 22:00  mes5k
+
+	* examples/test5.cpp: fixed a bizarre bug
+
+2004-10-20 21:59  mes5k
+
+	* tests/: test20.out, test21.out, test25.out, test33.out: fixed a
+	  test5 bug
+
+2004-10-20 19:17  mes5k
+
+	* Makefile.am: added msc
+
+2004-10-20 19:06  mes5k
+
+	* configure.in: added msc stuff
+
+2004-10-20 19:05  mes5k
+
+	* msc/: examples/Makefile.am, Makefile.am: init
+
+2004-10-20 19:00  mes5k
+
+	* NEWS: update
+
+2004-10-20 18:58  mes5k
+
+	* msc/README: init
+
+2004-10-20 18:47  mes5k
+
+	* msc/: tclap-beta.ncb, tclap-beta.sln, tclap-beta.suo,
+	  tclap-beta.vcproj, examples/test1.vcproj, examples/test2.vcproj,
+	  examples/test3.vcproj, examples/test4.vcproj,
+	  examples/test5.vcproj, examples/test6.vcproj,
+	  examples/test7.vcproj, examples/test8.vcproj: init
+
+2004-10-19 14:18  mes5k
+
+	* docs/Makefile.am: added stylesheet
+
+2004-10-19 13:51  mes5k
+
+	* AUTHORS: more
+
+2004-10-19 13:39  mes5k
+
+	* NEWS, AUTHORS: added 1.0 notes
+
+2004-10-14 16:04  mes5k
+
+	* examples/test4.cpp: shows how to alter output
+
+2004-10-14 16:03  mes5k
+
+	* tests/test18.out: updated output
+
+2004-10-14 15:03  mes5k
+
+	* include/tclap/CmdLineInterface.h: added failure to the interface
+
+2004-10-14 14:07  mes5k
+
+	* include/tclap/ArgException.h: doh. now what() is proper
+
+2004-10-14 13:44  mes5k
+
+	* include/tclap/CmdLine.h: made destructor virtual
+
+2004-10-14 13:20  mes5k
+
+	* include/tclap/CmdLine.h: moved all output handling into separate
+	  methods
+
+2004-10-14 13:19  mes5k
+
+	* include/tclap/Arg.h: made processArg pure virtual
+
+2004-10-14 13:19  mes5k
+
+	* include/tclap/ArgException.h: fixed documentation omission
+
+2004-10-12 17:09  mes5k
+
+	* docs/style.css: tweak
+
+2004-10-07 14:22  mes5k
+
+	* docs/style.css: color change
+
+2004-10-01 13:54  mes5k
+
+	* include/tclap/ArgException.h: added type description
+
+2004-09-30 21:16  mes5k
+
+	* docs/: index.html, manual.html, style.css: added CSS style
+
+2004-09-30 12:17  mes5k
+
+	* docs/manual.html: more updates
+
+2004-09-29 11:24  mes5k
+
+	* docs/: index.html, manual.html: proofing updates
+
+2004-09-27 17:37  mes5k
+
+	* docs/: index.html, manual.html: xhtml and tidied
+
+2004-09-27 17:36  mes5k
+
+	* docs/Doxyfile.in: added dot  handling
+
+2004-09-27 17:30  mes5k
+
+	* include/tclap/: Arg.h, ArgException.h, CmdLine.h, MultiArg.h,
+	  SwitchArg.h, ValueArg.h: added new Exception classes
+
+2004-09-27 15:53  mes5k
+
+	* include/tclap/ArgException.h: minor tweaks
+
+2004-09-26 22:32  mes5k
+
+	* docs/manual.html: updates yet again
+
+2004-09-26 22:00  mes5k
+
+	* docs/manual.html: updates
+
+2004-09-26 21:50  mes5k
+
+	* docs/manual.html: substantial updates
+
+2004-09-26 19:54  mes5k
+
+	* include/tclap/: Arg.h, CmdLine.h, CmdLineInterface.h, MultiArg.h,
+	  PrintSensibly.h, ValueArg.h: minor formatting
+
+2004-09-26 18:50  mes5k
+
+	* docs/manual.html: updates
+
+2004-09-26 18:17  mes5k
+
+	* tests/runtests.sh: minor fix so that we run all tests
+
+2004-09-26 14:51  macbishop
+
+	* docs/Doxyfile.in: Removed src subdir
+
+2004-09-26 14:49  macbishop
+
+	* examples/Makefile.am: Removed libtclap.a deps
+
+2004-09-26 14:46  macbishop
+
+	* configure.in: Removed creation of src/Makefile
+
+2004-09-26 14:34  macbishop
+
+	* Makefile.am: Removed src subdir
+
+2004-09-26 14:27  macbishop
+
+	* include/tclap/: Arg.h, ArgException.h, CmdLine.h, HelpVisitor.h,
+	  Makefile.am, MultiArg.h, PrintSensibly.h, SwitchArg.h,
+	  UnlabeledMultiArg.h, UnlabeledValueArg.h, ValueArg.h,
+	  VersionVisitor.h, XorHandler.h, CmdLineInterface.h,
+	  CommandLine.h: Moving the implementation of tclap to the header
+	  files presented me with two major problems. 1) There where static
+	  functions and variables that could cause link errors if tclap
+	  where used in different files (e.g. file1.cc and file2.cc
+	  included tclap then compiling both files would give hard symbols
+	  for some variables which would produce multiple definition when
+	  linking) 2) The dependencies of tclap was a bit strange (CmdLine
+	  depends on Args and Args depends on CmdLine for instance)
+
+	  The first problem I solved by removing all static variables
+	  putting them in static member functions (which are weak-symbols).
+	  So for instance every where there previously was something like x
+	  = _delimiter there now is x = delimiter() or in case of write
+	  acces delimiterRef() = x instead of _delimiter = x (I had to
+	  append the Ref because there where already functions with the
+	  same name as the variables). To solve the problem with static
+	  functions I simply inlined them. This causes the compiler to
+	  produce a weak symbol or inline if appropriate. We can put the
+	  functions inside the class declaration later to make the code
+	  look better. This worked fine in all but two cases. In the
+	  ValueArg and MultiArg classes I had to do a "hack" to work around
+	  the specialization template for extractValue<std::string>. The
+	  code for this is very simple but it might look strange an stupid
+	  at first but it is only to resolve the specialisation to a weak
+	  symbol. What I did was I put the implementations of extractValue
+	  in a helper class and I could then create a specialized class
+	  instead of function and everything worked out. I think now in
+	  retrospect there might be better solutions to this but I'll think
+	  a bit more on it (maybe some type of inlining on the specialized
+	  version would suffice but I'm not sure).
+
+	  To handle the dependencies I had to do some rewriting. The first
+	  step was to introduce a new class CmdLineInterface that is a
+	  purely abstract base of CmdLine that specifies the functions
+	  needed by Arg and friends. Thus Arg classes now takes an
+	  CmdLineInterface object as input instead (however only CmdLine
+	  can ever be instantiated of-course). With this extra class
+	  cleaning up the dependencies was quite simple, I've attached a
+	  dependency graph to the mail (depgraph.png). I also cleaned up
+	  the #includes so now only what actually needs inclusion is
+	  included. A nice side effect of this is that the impl. of CmdLine
+	  is now put back into CmdLine.h (where I guess you wanted it)
+	  which (recursivly) includes everything else needed.
+
+	  Just to make things clear for myself regarding the class
+	  dependencies I made a class TCLAP::Exception that inherits from
+	  std::exception and is a base of ArgException (Exception does
+	  nothing currently). If we don't want the Exception class it can
+	  be removed, however I think it could be a nice logic to have a
+	  base Exception class that every exception inherits from, but we
+	  can discuss that when we decide how to handle exceptions.
+
+2004-09-26 11:07  macbishop
+
+	* tests/runtests.sh: Now return 0 if all tests fail and 1 if any
+	  test fail
+
+2004-09-26 10:58  macbishop
+
+	* tests/runtests.sh: Runs all tests and sumarizes the result
+
+2004-09-20 20:09  mes5k
+
+	* include/tclap/CommandLine.h: added some comments
+
+2004-09-20 13:05  macbishop
+
+	* include/tclap/CommandLine.h: Recommit because something is
+	  strange. The changes are that memory allocated in _construct is
+	  deallocated when the CmdLine obj is destroyed
+
+2004-09-18 12:54  mes5k
+
+	* include/tclap/: Arg.h, ArgException.h, CmdLine.h, CommandLine.h,
+	  HelpVisitor.h, IgnoreRestVisitor.h, MultiArg.h, PrintSensibly.h,
+	  SwitchArg.h, UnlabeledMultiArg.h, UnlabeledValueArg.h,
+	  ValueArg.h, VersionVisitor.h, Visitor.h, XorHandler.h: changed
+	  ifndef labels
+
+2004-09-18 10:53  macbishop
+
+	* include/tclap/Arg.h: Had to make ~Arg() public because it won't
+	  be possible to delete Arg*s if it is not, and we want that (I
+	  think).
+
+2004-09-16 00:24  mes5k
+
+	* configure.in: version 1.0.0
+
+2004-09-15 23:54  mes5k
+
+	* include/tclap/: Arg.h, ArgException.h, HelpVisitor.h,
+	  IgnoreRestVisitor.h, MultiArg.h, SwitchArg.h,
+	  UnlabeledMultiArg.h, ValueArg.h, VersionVisitor.h, Visitor.h:
+	  cleaned up a bunch of things
+
+2004-09-11 22:35  mes5k
+
+	* tests/: Makefile.am, test47.out, test47.sh, test48.out,
+	  test48.sh, test49.out, test49.sh, test50.out, test50.sh,
+	  test51.out, test51.sh, test52.out, test52.sh, test53.out,
+	  test53.sh, test54.out, test54.sh: added tests for CmdLine arg
+
+2004-09-11 22:33  mes5k
+
+	* examples/: Makefile.am, test8.cpp: added new test for CmdLine arg
+
+2004-09-11 22:32  mes5k
+
+	* include/tclap/: Arg.h, MultiArg.h, SwitchArg.h,
+	  UnlabeledMultiArg.h, UnlabeledValueArg.h, ValueArg.h: got CmdLine
+	  arg working
+
+2004-09-09 22:08  mes5k
+
+	* configure: shouldn't be in cvs
+
+2004-09-09 15:55  macbishop
+
+	* include/tclap/: Arg.h, MultiArg.h, SwitchArg.h,
+	  UnlabeledMultiArg.h, UnlabeledValueArg.h, ValueArg.h: Support for
+	  automatic addition to a CmdLine parser
+
+2004-09-07 19:11  mes5k
+
+	* include/tclap/Makefile.in, docs/Makefile.in,
+	  examples/Makefile.in, tests/Makefile.in: not needed
+
+2004-09-07 19:08  mes5k
+
+	* Makefile.in, include/Makefile.in: not needed
+
+2004-09-07 18:12  mes5k
+
+	* examples/test4.cpp, examples/test7.cpp, tests/test38.out,
+	  tests/test39.out, tests/test43.out, tests/test46.out: fixed to
+	  handle new exception on matching names/flags/desc
+
+2004-09-07 16:25  mes5k
+
+	* docs/Doxyfile.in: updated Doxyfile for newer doxygen
+
+2004-09-07 14:25  mes5k
+
+	* examples/test7.cpp: added more args to better test output
+	  printing
+
+2004-09-07 14:25  mes5k
+
+	* include/tclap/Arg.h, include/tclap/ArgException.h,
+	  include/tclap/CommandLine.h, include/tclap/MultiArg.h,
+	  include/tclap/PrintSensibly.h, include/tclap/SwitchArg.h,
+	  include/tclap/UnlabeledMultiArg.h,
+	  include/tclap/UnlabeledValueArg.h, include/tclap/ValueArg.h,
+	  include/tclap/XorHandler.h, examples/test1.cpp,
+	  examples/test2.cpp, examples/test3.cpp, examples/test4.cpp,
+	  examples/test5.cpp, examples/test6.cpp: changed namespace std
+	  handling
+
+2004-09-07 14:24  mes5k
+
+	* tests/: test15.out, test16.out, test17.out, test22.out,
+	  test23.out, test24.out, test31.out, test32.out, test38.out,
+	  test39.out, test42.out, test44.out, test46.out: fixed test output
+	  for new formatting
+
+2004-09-04 17:09  macbishop
+
+	* include/tclap/: UnlabeledMultiArg.h, UnlabeledValueArg.h:
+	  Compilation was broken due to undef. symbols in compilers with 2
+	  stage name-lookup (such as gcc >= 3.4). The fix for this is to
+	  tell the compiler what symbols to use withlines like: using
+	  MultiArg<T>::_name;
+
+	  This is now done and everything compiles fine. Since I'm not sure
+	  about the support for things like using MultiArg<T>::_name; on
+	  all compilers it is ifdef:ed away by default. To get 2 stage
+	  name-lookup to work you have to add -DTWO_STAGE_NAME_LOOKUP to
+	  your CXXFLAGS before running configure.
+
+2004-08-10 23:32  mes5k
+
+	* autotools.sh: made path explicit
+
+2004-08-10 23:05  mes5k
+
+	* include/tclap/: MultiArg.h, ValueArg.h: changed allowed separator
+
+2004-08-10 22:53  mes5k
+
+	* tests/: Makefile.am, test10.out, test11.out, test12.out,
+	  test15.out, test16.out, test17.out, test18.out, test22.out,
+	  test23.out, test24.out, test26.out, test27.out, test28.out,
+	  test29.out, test30.out, test31.out, test32.out, test35.out,
+	  test36.out, test38.out, test39.out, test4.out, test40.out,
+	  test40.sh, test41.out, test41.sh, test42.out, test42.sh,
+	  test43.out, test43.sh, test44.out, test44.sh, test45.out,
+	  test45.sh, test46.out, test46.sh, test7.out, test7.sh: changed
+	  error output and added usage stuff
+
+2004-08-10 22:52  mes5k
+
+	* NEWS, README: updated
+
+2004-08-10 22:47  mes5k
+
+	* configure.in: changed to 0.9.9
+
+2004-08-10 22:46  mes5k
+
+	* examples/test7.cpp: tweaked for usage
+
+2004-08-10 22:45  mes5k
+
+	* include/tclap/: CmdLine.h, CommandLine.h, Makefile.am,
+	  PrintSensibly.h, XorHandler.h: added usage stuff
+
+2004-07-05 22:02  mes5k
+
+	* docs/manual.html: updated for allowed
+
+2004-07-03 23:01  mes5k
+
+	* tests/: test34.out, test34.sh, test35.out, test35.sh, test36.out,
+	  test36.sh, test37.out, test37.sh, test38.out, test38.sh,
+	  test39.out, test39.sh, Makefile.am: allow tests
+
+2004-07-03 22:56  mes5k
+
+	* include/tclap/ValueArg.h: doh
+
+2004-07-03 22:34  mes5k
+
+	* NEWS: allow
+
+2004-07-03 22:31  mes5k
+
+	* include/tclap/Arg.h: made isReq virtual
+
+2004-07-03 22:30  mes5k
+
+	* include/tclap/: MultiArg.h, UnlabeledMultiArg.h,
+	  UnlabeledValueArg.h, ValueArg.h: added allow
+
+2004-07-03 22:29  mes5k
+
+	* examples/: Makefile.am, test6.cpp, test7.cpp: added tests for
+	  allowed
+
+2004-07-03 22:28  mes5k
+
+	* docs/: index.html, manual.html: minor typos
+
+2004-04-26 11:18  mes5k
+
+	* Makefile.am, autotools.sh, examples/Makefile.am: fixed for
+	  autotools for mandrake
+
+2004-02-13 23:09  mes5k
+
+	* configure.in: 0.9.8a
+
+2004-02-13 18:23  mes5k
+
+	* tests/: test22.out, test23.out, test24.out: output updates
+
+2004-02-13 18:21  mes5k
+
+	* include/tclap/: Arg.h, UnlabeledMultiArg.h, UnlabeledValueArg.h:
+	  now the Arg adds itself to the CmdLine arglist
+
+2004-02-10 11:52  mes5k
+
+	* NEWS: update
+
+2004-02-10 00:04  mes5k
+
+	* examples/test5.cpp: change
+
+2004-02-09 23:54  mes5k
+
+	* configure.in: 0.9.8
+
+2004-02-09 23:52  mes5k
+
+	* tests/: Makefile.am, test20.out, test21.out, test22.out,
+	  test23.out, test24.out, test25.out, test33.out, test33.sh:
+	  updates
+
+2004-02-09 23:39  mes5k
+
+	* docs/manual.html: blank args
+
+2004-02-09 23:16  mes5k
+
+	* tests/: test15.out, test16.out, test17.out, test20.out,
+	  test20.sh, test21.out, test21.sh, test22.out, test23.out,
+	  test24.out, test25.out, test25.sh, test31.out, test32.out:
+	  updates
+
+2004-02-09 23:05  mes5k
+
+	* examples/: test5.cpp, test3.cpp: minor fixes and new args
+
+2004-02-09 22:56  mes5k
+
+	* include/tclap/Arg.h: added new var
+
+2004-02-06 20:41  mes5k
+
+	* NEWS: added info
+
+2004-02-06 20:24  mes5k
+
+	* tests/: test12.out, test15.out, test16.out, test17.out: fixed
+	  test3 stuff
+
+2004-02-06 20:20  mes5k
+
+	* tests/: test26.out, test26.sh, test27.out, test27.sh, test28.out,
+	  test28.sh, test29.out, test29.sh, test30.out, test30.sh,
+	  test31.out, test31.sh, test32.out, test32.sh, Makefile.am: added
+	  tests for reading extra incorrect values from arg
+
+2004-02-06 20:18  mes5k
+
+	* examples/test3.cpp: add multi float
+
+2004-02-06 20:18  mes5k
+
+	* include/tclap/: MultiArg.h, ValueArg.h: fixed error reading
+	  incorrect extra values in an arg
+
+2004-02-04 21:56  mes5k
+
+	* include/tclap/XorHandler.h: added include
+
+2004-02-03 23:21  mes5k
+
+	* include/tclap/XorHandler.h: added doxyen
+
+2004-02-03 23:00  mes5k
+
+	* docs/manual.html: xor stuff
+
+2004-02-03 22:56  mes5k
+
+	* examples/test5.cpp: prettified
+
+2004-02-03 22:27  mes5k
+
+	* examples/: Makefile.am, test5.cpp: xor stuff
+
+2004-02-03 22:24  mes5k
+
+	* configure.in: 0.9.7
+
+2004-02-03 22:20  mes5k
+
+	* include/tclap/: Arg.h, CmdLine.h, CommandLine.h,
+	  UnlabeledValueArg.h, XorHandler.h, Makefile.am: xor stuff
+
+2004-02-03 22:14  mes5k
+
+	* tests/: test1.sh, test10.sh, test11.sh, test12.sh, test13.sh,
+	  test14.sh, test15.sh, test16.sh, test17.sh, test18.sh, test19.sh,
+	  test2.sh, test20.sh, test21.sh, test22.sh, test23.sh, test24.sh,
+	  test25.sh, test3.sh, test4.sh, test5.sh, test6.sh, test7.sh,
+	  test8.sh, test9.sh, Makefile.am, test20.out, test21.out,
+	  test22.out, test23.out, test24.out, test25.out: added new tests
+	  and comments
+
+2004-01-29 23:36  mes5k
+
+	* include/tclap/: CmdLine.h, CommandLine.h, MultiArg.h, ValueArg.h:
+	  fix for strings with spaces
+
+2004-01-10 12:39  mes5k
+
+	* docs/index.html: spelling
+
+2004-01-08 01:18  mes5k
+
+	* docs/: index.html, manual.html: updates
+
+2004-01-08 00:51  mes5k
+
+	* NEWS: update
+
+2004-01-08 00:30  mes5k
+
+	* include/tclap/CmdLine.h: added backward compatibility
+
+2004-01-08 00:04  mes5k
+
+	* examples/: Makefile.am, test4.cpp: added new test
+
+2004-01-08 00:00  mes5k
+
+	* tests/Makefile.am: added two new tests
+
+2004-01-07 23:59  mes5k
+
+	* include/tclap/: Arg.h, ArgException.h, CmdLine.h, HelpVisitor.h,
+	  IgnoreRestVisitor.h, MultiArg.h, SwitchArg.h,
+	  UnlabeledMultiArg.h, UnlabeledValueArg.h, ValueArg.h,
+	  VersionVisitor.h, Visitor.h: fixed combined switch stuff and
+	  added doxygen comments
+
+2004-01-07 23:50  mes5k
+
+	* tests/: test18.out, test18.sh, test19.out, test19.sh: new tests
+
+2003-12-21 21:32  mes5k
+
+	* autotools.sh: init
+
+2003-12-21 21:31  mes5k
+
+	* include/tclap/UnlabeledMultiArg.h: delim stuff
+
+2003-12-21 21:14  mes5k
+
+	* examples/test1.cpp: new fangled
+
+2003-12-21 21:11  mes5k
+
+	* configure.in: 0.9.6
+
+2003-12-21 21:10  mes5k
+
+	* tests/: test13.sh, test14.sh: updated
+
+2003-12-21 21:09  mes5k
+
+	* tests/: test10.out, test11.out, test12.out, test13.out,
+	  test14.out, test15.out, test16.out, test4.out: updates
+
+2003-12-21 21:07  mes5k
+
+	* tests/Makefile.am: added test
+
+2003-12-21 21:06  mes5k
+
+	* tests/: test17.out, test17.sh: first checkin
+
+2003-12-21 20:59  mes5k
+
+	* examples/Makefile.am: added warnings
+
+2003-12-21 20:58  mes5k
+
+	* examples/: test2.cpp, test3.cpp: fixed warnings
+
+2003-12-21 20:53  mes5k
+
+	* Makefile.am: added warnings
+
+2003-12-21 20:52  mes5k
+
+	* examples/test3.cpp: added delimiter
+
+2003-12-21 20:48  mes5k
+
+	* include/tclap/: Arg.h, ArgException.h, CmdLine.h, MultiArg.h,
+	  UnlabeledValueArg.h, ValueArg.h: delimiter changes
+
+2003-04-03 13:26  mes5k
+
+	* include/tclap/Makefile.am: added new visitor
+
+2003-04-03 13:20  mes5k
+
+	* include/tclap/Makefile.am: updates
+
+2003-04-03 13:13  mes5k
+
+	* config/: mkinstalldirs, install-sh, missing, depcomp: init
+	  checkin
+
+2003-04-03 13:11  mes5k
+
+	* NEWS: update
+
+2003-04-03 13:06  mes5k
+
+	* examples/Makefile.am, examples/test1.cpp, examples/test2.cpp,
+	  examples/test3.cpp, INSTALL, Makefile.in: updates
+
+2003-04-03 13:01  mes5k
+
+	* Makefile.am, configure.in: added tests
+
+2003-04-03 13:00  mes5k
+
+	* docs/: index.html, manual.html: updated docs
+
+2003-04-03 12:59  mes5k
+
+	* include/tclap/: Arg.h, CmdLine.h, IgnoreRestVisitor.h,
+	  MultiArg.h, SwitchArg.h, UnlabeledMultiArg.h,
+	  UnlabeledValueArg.h, ValueArg.h: big update
+
+2003-04-03 12:56  mes5k
+
+	* tests/: test10.sh, test11.sh, test12.sh, test1.sh, test13.sh,
+	  test14.sh, test15.sh, test16.sh, test2.sh, test3.sh, test4.sh,
+	  test5.sh, test6.sh, test7.sh, test8.sh, test9.sh, test10.out,
+	  test11.out, test12.out, test13.out, test14.out, test15.out,
+	  test16.out, test1.out, test2.out, test3.out, test4.out,
+	  test5.out, test6.out, test7.out, Makefile.am, test8.out,
+	  test9.out, Makefile.in, genOut.pl: initial checkin
+
+2003-03-18 21:39  mes5k
+
+	* NEWS, configure.in, AUTHORS, COPYING, ChangeLog, Makefile.am,
+	  Makefile.in, README, aclocal.m4, configure,
+	  config/ac_cxx_have_sstream.m4, config/ac_cxx_have_strstream.m4,
+	  config/ac_cxx_namespaces.m4, config/bb_enable_doxygen.m4,
+	  config/config.h.in, config/stamp-h.in, config/stamp-h1,
+	  examples/Makefile.am, examples/Makefile.in, examples/test1.cpp,
+	  examples/test2.cpp, include/Makefile.am, include/Makefile.in,
+	  include/tclap/Arg.h, include/tclap/ArgException.h,
+	  include/tclap/CmdLine.h, include/tclap/HelpVisitor.h,
+	  include/tclap/MultiArg.h, docs/Doxyfile.in, docs/Makefile.am,
+	  docs/Makefile.in, docs/index.html, docs/manual.html,
+	  include/tclap/Makefile.am, include/tclap/Makefile.in,
+	  include/tclap/SwitchArg.h, include/tclap/ValueArg.h,
+	  include/tclap/VersionVisitor.h, include/tclap/Visitor.h: Initial
+	  revision
+
+2003-03-18 21:39  mes5k
+
+	* NEWS, configure.in, AUTHORS, COPYING, ChangeLog, Makefile.am,
+	  Makefile.in, README, aclocal.m4, configure,
+	  config/ac_cxx_have_sstream.m4, config/ac_cxx_have_strstream.m4,
+	  config/ac_cxx_namespaces.m4, config/bb_enable_doxygen.m4,
+	  config/config.h.in, config/stamp-h.in, config/stamp-h1,
+	  examples/Makefile.am, examples/Makefile.in, examples/test1.cpp,
+	  examples/test2.cpp, include/Makefile.am, include/Makefile.in,
+	  include/tclap/Arg.h, include/tclap/ArgException.h,
+	  include/tclap/CmdLine.h, include/tclap/HelpVisitor.h,
+	  include/tclap/MultiArg.h, docs/Doxyfile.in, docs/Makefile.am,
+	  docs/Makefile.in, docs/index.html, docs/manual.html,
+	  include/tclap/Makefile.am, include/tclap/Makefile.in,
+	  include/tclap/SwitchArg.h, include/tclap/ValueArg.h,
+	  include/tclap/VersionVisitor.h, include/tclap/Visitor.h: initial
+	  release
+
diff --git a/third_party/tclap/CmdLine.h b/third_party/tclap/CmdLine.h
new file mode 100644
index 0000000..90d0e65
--- /dev/null
+++ b/third_party/tclap/CmdLine.h
@@ -0,0 +1,621 @@
+// -*- 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:
+
+		/**
+		 * 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 )
+: _progName("not_set_yet"),
+  _message(m),
+  _version(v),
+  _numRequired(0),
+  _delimiter(delim),
+  _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)
+{
+	_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/third_party/tclap/CmdLineInterface.h b/third_party/tclap/CmdLineInterface.h
new file mode 100644
index 0000000..1b25e9b
--- /dev/null
+++ b/third_party/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/third_party/tclap/CmdLineOutput.h b/third_party/tclap/CmdLineOutput.h
new file mode 100644
index 0000000..71ee5a3
--- /dev/null
+++ b/third_party/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/third_party/tclap/Constraint.h b/third_party/tclap/Constraint.h
new file mode 100644
index 0000000..a92acf9
--- /dev/null
+++ b/third_party/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/third_party/tclap/DocBookOutput.h b/third_party/tclap/DocBookOutput.h
new file mode 100644
index 0000000..d2f1290
--- /dev/null
+++ b/third_party/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 version = _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 << version << 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 = "<"; 
+	std::string 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 = "<"; 
+	std::string 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/third_party/tclap/HelpVisitor.h b/third_party/tclap/HelpVisitor.h
new file mode 100644
index 0000000..2cdb997
--- /dev/null
+++ b/third_party/tclap/HelpVisitor.h
@@ -0,0 +1,69 @@
+
+/****************************************************************************** 
+ * 
+ *  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
+{
+	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/third_party/tclap/IgnoreRestVisitor.h b/third_party/tclap/IgnoreRestVisitor.h
new file mode 100644
index 0000000..e328649
--- /dev/null
+++ b/third_party/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/third_party/tclap/Makefile.am b/third_party/tclap/Makefile.am
new file mode 100644
index 0000000..8791f53
--- /dev/null
+++ b/third_party/tclap/Makefile.am
@@ -0,0 +1,28 @@
+
+#libtclapincludedir = $(includedir)/tclap
+
+noinst_HEADERS = \
+			 CmdLineInterface.h \
+			 ArgException.h \
+			 CmdLine.h \
+			 XorHandler.h \
+			 MultiArg.h \
+			 UnlabeledMultiArg.h \
+			 ValueArg.h \
+			 UnlabeledValueArg.h \
+			 Visitor.h Arg.h \
+			 HelpVisitor.h \
+			 SwitchArg.h \
+			 MultiSwitchArg.h \
+			 VersionVisitor.h \
+			 IgnoreRestVisitor.h \
+			 CmdLineOutput.h \
+			 StdOutput.h \
+			 DocBookOutput.h \
+			 ZshCompletionOutput.h \
+			 OptionalUnlabeledTracker.h \
+			 Constraint.h \
+			 ValuesConstraint.h \
+			 ArgTraits.h \
+			 StandardTraits.h
+
diff --git a/third_party/tclap/MultiArg.h b/third_party/tclap/MultiArg.h
new file mode 100644
index 0000000..460e5cb
--- /dev/null
+++ b/third_party/tclap/MultiArg.h
@@ -0,0 +1,422 @@
+/****************************************************************************** 
+ * 
+ *  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();
+
+};
+
+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 ),
+  _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 ),
+  _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 ),
+  _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 ),
+  _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/third_party/tclap/MultiSwitchArg.h b/third_party/tclap/MultiSwitchArg.h
new file mode 100644
index 0000000..8820b64
--- /dev/null
+++ b/third_party/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/third_party/tclap/NEWS b/third_party/tclap/NEWS
new file mode 100644
index 0000000..08902cd
--- /dev/null
+++ b/third_party/tclap/NEWS
@@ -0,0 +1,93 @@
+
+4/3/03 -  Checked in a good sized update that move support of the library
+closer to that of the POSIX/GNU standards.  Switches can now be combined into
+single arguments, -- is supported and MultiArgs now allow for multiple labeled
+args.  I've also changed things a bit by subclassing MultiArg and ValueArg
+to get unlabeled versions of these classes.  I think this is a bit cleaner
+design, despite two new classes.
+
+1/7/04 - ... and with great trepidation, I release 0.9.6.  Loads of changes.  
+The big change is that you can now define the delimiter used to separate 
+argument flags and argument values. So if you prefer arguments of the style 
+"-s=asdf"  instead of "-s asdf", you can do so.  I've also fixed a number of 
+warnings generated and fixed a few pathologic bugs related to combined
+switches.  That said, I suspect that there may be a few significant bugs
+in this release that I haven't uncovered yet.  Please let me know ASAP if
+you find any.
+
+2/6/04 - Another big release: 0.9.7.  First is a bugfix submitted by 
+Matthias Stiller that specializes the _extractValue method in a couple of
+places that allows strings with spaces to be correctly read by tclap.  A
+second bug found by John Ling has been fixed so that exceptions are thrown 
+if more than one value is parsed from a single arg or if the second value 
+parsed is invalid.   A big new feature has been added that allows args to
+be xor'd.  This means that two (or more) args can be specified such that
+one and only one of the args is required.  If a second arg is found an
+exception is thrown.  See the manual for details.  As always, let me know
+if you run into any problems.
+
+2/10/04 - A minor release: 0.9.8.  A couple of bug fixes for 0.9.7 are
+included and a feature has been added that allows Args to be specified 
+without short options, meaning the user is forced to use only long options.
+This is useful for programs with more options than map sensibly to single
+chars.
+
+7/3/04 - Added a new constructor and handling to the various value args
+that allows the user to provide a list of values that the input arg values 
+should be restricted to.  
+
+8/9/04 - Created a function to print the output nicely, meaning line wraps
+are handled somewhat sensibly now.  Also changed error handling slightly. 
+Instead of printing the entire usage, I just print a short usage.  If
+someone really hates this, its easy to change back.  Let me know if this 
+causes problems.  I think this equals release 0.9.9!
+
+10/19/04 - A number of changes that should substantially improve the library.
+The most important being that we've moved the implementation of the library
+entirely into the header files.  This means there is no longer a library to
+complile against, you simply have to #include <tclap/CmdLine.h>.  New
+constructors have been added to the various Arg classes that allow them to 
+be constructed with a CmdLine reference so that you no longer need to call
+the add method if you prefer it that way.  The output generated by the library
+has been confined to a few methods in the CmdLine class.  This means to 
+generate different output you can extend CmdLine and override the offending
+methods.  A number of style changes have been made in the code base to 
+conform better to C++ best practices.   A thoughtful user has contributed
+project files for the building the examples Microsoft Visual Studio.  See
+the README file in the msc directory for more details
+
+And so we have release 1.0!
+
+10/30/04 - A few bugfixes.  Now checking for include.h before including it. 
+This will help Windows users who don't have it.  Also changed test1 so that 
+it doesn't use toupper, which apparently causes problem for non-ASCII 
+character sets.
+
+10/31/04 - A few more tweaks, none of which should be noticeable to people
+who are already using the lib without trouble. Maybe I shouldn't release 
+things early in the morning!  Also note that manual.html is now generated 
+from manual.xml.  If you have your own docbook xsl style that you prefer, 
+then have at it.
+
+12/3/04 - Some minor bug fixes including the removal of the two stage name
+lookup ifdefs which means that the software should work out of the box 
+for gcc 3.4+.  Isolated output in a separate class that should make
+customization of output easier.  I also included a rudimentary output class
+that generated a (bad) Docbook command summary when used. 
+
+1/4/05 - Several bug fixes, but no new features. Fixed a bug when mandatory 
+long args and unlabeled args were used together and weren't working properly.
+Now they can be used together. Fixed another bug in spacePrint where long 
+program names caused an infinite loop.  Finally, fixed a small memory leak.
+
+1/6/05 - Fixed a bug where setting the output object for a CmdLine didn't
+register for version or usage generation. Doh!  Created a Constraint interface
+that should facilitate the creation of different constraints on Args.
+This has involved changing the constructor interface, so if you've been using
+allowed lists, you'll need to make a small modification to your existing code.
+See examples/test6.cpp for details.
+
+9/26/09 - Whoa, long break.  Primarily a bug-fix release, but we did switch 
+to using traits, which necessitates the minor version bump. Take a look 
+at test11.cpp and test12.cpp for examples on using ArgTraits for extending 
+tclap for different types.
diff --git a/third_party/tclap/OptionalUnlabeledTracker.h b/third_party/tclap/OptionalUnlabeledTracker.h
new file mode 100644
index 0000000..8174c5f
--- /dev/null
+++ b/third_party/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/third_party/tclap/README b/third_party/tclap/README
new file mode 100644
index 0000000..225e33f
--- /dev/null
+++ b/third_party/tclap/README
@@ -0,0 +1,16 @@
+
+TCLAP - Templatized Command Line Argument Parser
+
+This is a simple C++ library that facilitates parsing command line
+arguments in a type independent manner.  It doesn't conform exactly
+to either the GNU or POSIX standards, although it is close.  See
+docs/manual.html for descriptions of how things work or look at the
+simple examples in the examples dir.
+
+To find out what the latest changes are read the NEWS file in this directory.
+
+
+Any and all feedback is welcome to:  Mike Smoot <mes at aescon.com>
+
+
+
diff --git a/third_party/tclap/StandardTraits.h b/third_party/tclap/StandardTraits.h
new file mode 100644
index 0000000..0819438
--- /dev/null
+++ b/third_party/tclap/StandardTraits.h
@@ -0,0 +1,184 @@
+// -*- 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
+
+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;
+};
+
+#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.
+ */
+template<>
+struct ArgTraits<wchar_t> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * 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/third_party/tclap/StdOutput.h b/third_party/tclap/StdOutput.h
new file mode 100644
index 0000000..9ceac0c
--- /dev/null
+++ b/third_party/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 version = _cmd.getVersion();
+
+	std::cout << std::endl << progName << "  version: " 
+			  << version << 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/third_party/tclap/SwitchArg.h b/third_party/tclap/SwitchArg.h
new file mode 100644
index 0000000..dc4952e
--- /dev/null
+++ b/third_party/tclap/SwitchArg.h
@@ -0,0 +1,228 @@
+
+/****************************************************************************** 
+ * 
+ *  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();
+
+};
+
+//////////////////////////////////////////////////////////////////////
+//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::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 bool SwitchArg::processArg(int *i, std::vector<std::string>& args)
+{
+	if ( _ignoreable && Arg::ignoreRest() )
+		return false;
+
+	if ( argMatches( args[*i] ) || combinedSwitchesMatch( args[*i] ) )
+	{
+		// If we match on a combined switch, then we want to return false
+		// so that other switches in the combination will also have a
+		// chance to match.
+		bool ret = false;
+		if ( argMatches( args[*i] ) )
+			ret = true;
+
+		if ( _alreadySet || ( !ret && combinedSwitchesMatch( args[*i] ) ) )
+			throw(CmdLineParseException("Argument already set!", toString()));	
+
+		_alreadySet = true;
+
+		if ( _value == true )
+			_value = false;
+		else
+			_value = true;
+
+		_checkWithVisitor();
+
+		return ret;
+	}
+	else
+		return false;
+}
+
+inline void SwitchArg::reset()
+{
+	Arg::reset();
+	_value = _default;  
+}
+//////////////////////////////////////////////////////////////////////
+//End SwitchArg.cpp
+//////////////////////////////////////////////////////////////////////
+
+} //namespace TCLAP
+
+#endif
diff --git a/third_party/tclap/UnlabeledMultiArg.h b/third_party/tclap/UnlabeledMultiArg.h
new file mode 100644
index 0000000..d5e1781
--- /dev/null
+++ b/third_party/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/third_party/tclap/UnlabeledValueArg.h b/third_party/tclap/UnlabeledValueArg.h
new file mode 100644
index 0000000..5721d61
--- /dev/null
+++ b/third_party/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/third_party/tclap/ValueArg.h b/third_party/tclap/ValueArg.h
new file mode 100644
index 0000000..28117f6
--- /dev/null
+++ b/third_party/tclap/ValueArg.h
@@ -0,0 +1,411 @@
+/****************************************************************************** 
+ * 
+ *  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() ;
+
+};
+
+
+/**
+ * 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 )
+			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/third_party/tclap/ValuesConstraint.h b/third_party/tclap/ValuesConstraint.h
new file mode 100644
index 0000000..4cceea1
--- /dev/null
+++ b/third_party/tclap/ValuesConstraint.h
@@ -0,0 +1,147 @@
+
+
+/****************************************************************************** 
+ * 
+ *  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)
+{ 
+    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/third_party/tclap/VersionVisitor.h b/third_party/tclap/VersionVisitor.h
new file mode 100644
index 0000000..3e55921
--- /dev/null
+++ b/third_party/tclap/VersionVisitor.h
@@ -0,0 +1,74 @@
+// -*- 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
+{
+	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/third_party/tclap/Visitor.h b/third_party/tclap/Visitor.h
new file mode 100644
index 0000000..38ddcbd
--- /dev/null
+++ b/third_party/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/third_party/tclap/XorHandler.h b/third_party/tclap/XorHandler.h
new file mode 100644
index 0000000..af68943
--- /dev/null
+++ b/third_party/tclap/XorHandler.h
@@ -0,0 +1,156 @@
+
+/****************************************************************************** 
+ * 
+ *  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( ) {}
+
+		/**
+		 * 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() )
+		{
+			// 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/third_party/tclap/ZshCompletionOutput.h b/third_party/tclap/ZshCompletionOutput.h
new file mode 100644
index 0000000..1ed4381
--- /dev/null
+++ b/third_party/tclap/ZshCompletionOutput.h
@@ -0,0 +1,321 @@
+// -*- 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["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 version = _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/utils/build_kit_from_svn b/utils/build_kit_from_svn
new file mode 100755
index 0000000..b2bc64f
--- /dev/null
+++ b/utils/build_kit_from_svn
@@ -0,0 +1,120 @@
+#!/bin/bash
+#
+#  $Id$
+#
+#  Copyright (C) 2011 Freddie Akeroyd, STFC ISIS Facility
+#  
+# $1 is tags, branches or trunk
+# $2 is version e.g. 4.0rc1
+# 
+# -c options for configure
+# -r build rpms with this release number
+# -t svn parent directory (tags, branches or trunk)
+# -v svn sub directory (e.g. 4.0) - not needed for trunk
+# -d temporary directory for building (/tmp if not specified)
+# -s svn revision to check out
+
+WORK_DIR="/tmp"
+OUTPUT_DIR="/tmp"
+CONFIGURE_OPTS=""
+AUTOGEN_ARGS=""
+REP_TOP="trunk"
+REP_SUB=""
+BUILD_RPM="no"
+SVN_REVISION="HEAD"
+PACKAGE_RELEASE=""
+while getopts "a:c:o:d:t:v:s:r" opt; do
+  case $opt in
+    a)
+      AUTOGEN_ARGS="$OPTARG"
+      ;;
+    c)
+      CONFIGURE_OPTS="$OPTARG"
+      ;;
+    o)
+      OUTPUT_DIR="$OPTARG"
+      ;;
+    d)
+      WORK_DIR="$OPTARG"
+      ;;
+    t)
+      REP_TOP="$OPTARG"
+      ;;
+    v)
+      REP_SUB="$OPTARG"
+      ;;
+    s)
+      SVN_REVISION="$OPTARG"
+      ;;
+    r)
+      BUILD_RPM="yes"
+      ;;
+    \?)
+      echo "Invalid option: -$OPTARG" >&2
+      ;;
+  esac
+done
+
+cd "$WORK_DIR"
+NXDIR=nexus-$$
+rep_url="http://svn.nexusformat.org/code/$REP_TOP"
+if test ! -z "$REP_SUB"; then 
+    rep_url="$rep_url/$REP_SUB"
+fi
+svn co --non-interactive -r "$SVN_REVISION" -q "$rep_url" "$NXDIR"
+cd "$NXDIR"
+SVN_REVISION=`svnversion`
+iso_date=`date +%Y%m%d`
+
+sh ./autogen.sh $AUTOGEN_ARGS
+sh ./configure $CONFIGURE_OPTS
+
+package_tarname=`grep "PACKAGE_TARNAME" include/nxconfig.h | awk '{print $3}' | sed -e 's/\"//g'`
+package_version=`grep "PACKAGE_VERSION" include/nxconfig.h | awk '{print $3}' | sed -e 's/\"//g'`
+tar_file="${package_tarname}-${package_version}.tar.gz"
+
+nexus_version=`grep "NEXUS_VERSION=" configure | awk -F= '{print $2}' | sed -e 's/\"//g'`
+nexus_release=`grep "NEXUS_RELEASE=" configure | awk -F= '{print $2}' | sed -e 's/\"//g'`
+package_release=`grep "PACKAGE_RELEASE=" configure | awk -F= '{print $2}' | sed -e 's/\"//g'`
+rpm_base="${package_tarname}-${nexus_version}-${package_release}.${nexus_release}"
+rpm_debuginfo_base="${package_tarname}-debuginfo-${nexus_version}-${package_release}.${nexus_release}"
+
+make
+make dist
+
+cp -f $tar_file $OUTPUT_DIR
+
+if test "$BUILD_RPM" = "no"; then
+    cd ..
+    rm -fr "$NXDIR"
+    exit
+fi
+
+topdir=`rpm --showrc|grep topdir| awk '{print $3}' | tail -1`
+if test ! -e "$topdir"; then
+    echo "Unable to determine RPM topdir from rpmrc; assuming $HOME/rpmbuild"
+    topdir="$HOME/rpmbuild"
+fi
+if test ! -w "$topdir"; then
+    echo "ERROR: RPM build directory not writable - check README.rpm"
+    cd ..
+    rm -fr "$NXDIR"
+    exit
+fi
+#
+rpm_match="${package_tarname}*-${nexus_version}-${package_release}.${nexus_release}*.rpm"
+
+my_rpm_build_root="$topdir"
+for i in SRPMS RPMS; do
+    find $my_rpm_build_root/$i -name "${rpm_match}" -exec rm -f {} \;
+done
+rm -fr $my_rpm_build_root/BUILD/${rpm_base}*
+rm -f $my_rpm_build_root/SOURCES/${tar_file} 
+
+sh build_rpm "$CONFIGURE_OPTS"
+
+for i in SRPMS RPMS; do
+    find $my_rpm_build_root/$i -name "${rpm_match}" -exec cp -f {} $OUTPUT_DIR \;
+done
+cd ..
+rm -fr "$NXDIR"
diff --git a/vms/make_vms.com b/vms/make_vms.com
new file mode 100644
index 0000000..87778d9
--- /dev/null
+++ b/vms/make_vms.com
@@ -0,0 +1,44 @@
+$!
+$! $Id$
+$!
+$! Build command file for VMS
+$!
+$! Freddie Akeroyd, ISIS facility, CCLRC Rutherford Appleton Laboratory
+$!
+$! Choose either the Fortran 77 or Fortran 90 versions 
+$! by commenting out the alternative (i.e. start the line with $!)
+$!
+$ SET VERIFY
+$ DEFINE HDF_ROOT AXPLIB$DISK:[4_1R3_ALPHAVMS7_1.]   ! where you installed HDF, trailing "." is needed
+$!=======================================================================
+$! Create library NEXUS.OLB and/or NEXUS90.OLB 
+$! (comment out Fortran 77 or Fortran 90 versions if necessary)
+$ CC/INCLUDE=HDF_ROOT:[INCLUDE]/DEFINE=("NEXUS_LIBRARY=1","HDF4=1") NAPI.C
+$!=======================================================================
+$!Fortran 77 Library
+$ FORTRAN NAPIF.F
+$ LIBRARY/CREATE/OBJECT SYS$DISK:[]NEXUS.OLB NAPI,NAPIF
+$!=======================================================================
+$!Fortran 90 Library
+$ F90 NXmodule, NXUmodule
+$ LIBRARY/CREATE/OBJECT SYS$DISK:[]NEXUS90.OLB NAPI,NXmodule,NXUmodule
+$!=======================================================================
+$! Compile and link C test programs
+$ CC/INCLUDE=HDF_ROOT:[INCLUDE]/DEFINE=("HDF4=1") NAPI4_TEST.C
+$ LINK NAPI4_TEST,SYS$DISK:[]NEXUS.OLB/LIB,HDF_ROOT:[LIB]MFHDF/LIB,DF/LIB,LIBZ/LIB,LIBJPEG/LIB
+$!=======================================================================
+$! Compile and link FORTRAN 77 test program
+$ FORTRAN NAPIF_TEST.F
+$ LINK NAPIF_TEST,SYS$DISK:[]NEXUS.OLB/LIB,HDF_ROOT:[LIB]MFHDF/LIB,DF/LIB,LIBZ/LIB,LIBJPEG/LIB
+$!=======================================================================
+$! Compile and link Fortran 90 test program
+$ F90 NXtest
+$ LINK NXtest,SYS$DISK:[]NEXUS90/LIB,HDF_ROOT:[LIB]MFHDF/LIB,DF/LIB,LIBZ/LIB,LIBJPEG/LIB
+$!=======================================================================
+$! Compile and link NeXus utilities
+$ CC/INCLUDE=HDF_ROOT:[INCLUDE]/DEFINE=("HDF4=1") NXbrowse
+$ LINK NXbrowse,SYS$DISK:[]NEXUS/LIB,HDF_ROOT:[LIB]MFHDF/LIB,DF/LIB,LIBZ/LIB,LIBJPEG/LIB
+$ CC/INCLUDE=HDF_ROOT:[INCLUDE]/DEFINE=("HDF4=1") NXtoXML
+$ LINK NXtoXML,SYS$DISK:[]NEXUS/LIB,HDF_ROOT:[LIB]MFHDF/LIB,DF/LIB,LIBZ/LIB,LIBJPEG/LIB
+$ CC/INCLUDE=HDF_ROOT:[INCLUDE]/DEFINE=("HDF4=1") NXtoDTD
+$ LINK NXtoDTD,SYS$DISK:[]NEXUS/LIB,HDF_ROOT:[LIB]MFHDF/LIB,DF/LIB,LIBZ/LIB,LIBJPEG/LIB
diff --git a/windows/README.txt b/windows/README.txt
new file mode 100644
index 0000000..7399ecb
--- /dev/null
+++ b/windows/README.txt
@@ -0,0 +1,103 @@
+Building NeXus with Visual Studio
+---------------------------------
+
+Setup
+-----
+
+You need to define several Windows environment variables
+HDF4ROOT and HDF5ROOT to point to top of unpacked HDF distributions
+e.g. 
+
+    HDF4ROOT=c:\program files\hdf42r1 
+    HDF5ROOT=C:\program Files\HDF5-164
+
+Note that you do not need the HDF5 version with F90 support even to build the nexus F90 API
+The above the the latest version of HDF as available from the NCSA site and
+reaquire several external libraries: zlin 1.2.2, jpeg-6b and szip-2.0 (encoder enabled)
+The location of these external libraries is isdicated by the following variables e.g.
+
+    JPEGROOT=c:\program files\jpeg-6b
+    ZLIBROOT=c:\program fiules\zlib122
+    SZIPROOT=c:\program files\szip20
+
+the HDF4 includes will be in %HDFROOT%\debug\include and %HDF5ROOT%\release\include and
+similarly HDF5 includes in %HDF5ROOT%\debug\include and %HDF5ROOT%\release\include 
+
+All the visual studio project files make use of these variables and so should not
+depend on the location HDF files are installed in.
+
+Currently ZLIB only works as a DLL so your programs will require zlib1.dll
+
+Building
+--------
+
+Open nexus.dsw, and then select a project to build
+
+nexus4, nexus5 and nexus45 - Static NeXus libraries with HDF4, HDF5, and both HDF4/HDF5 support
+nx45dll                    - Dynamic Link Library (DLL) version of the NeXus library with HDF4 and HDF5 support
+napi*_test                 - the various test programs 
+nxbrowse                   - the nexus file browser with static libraru
+nxbrowse_dll		   - NeXus file browser using nx45dll.dll
+
+
+Building your own projects with static libraries
+------------------------------------------------
+
+To make use of the HDF4ROOT and HDF5ROOT variables from within Visual Studio,
+you refer to them as $(HDF4ROOT) and $(HDF5ROOT). When building a 
+program using the NeXus library you will need to do the following to the 
+project settings:
+
+* Add  HDF4  and/or  HDF5  to the C "preprocessor definitions"
+* Add either  $(HDF4ROOT)\debug\include,$(HDF5ROOT)\debug\include  or   
+     $(HDF4ROOT)\debug\include,$(HDF5ROOT)\release\include   to the C "additional include directories"
+     depending on whether you are building a debug or release project
+* For a C project add either   $(HDF4ROOT)\debug\lib,$(HDF5ROOT)\debug\lib   or
+                      $(HDF4ROOT)\release\lib,$(HDF5ROOT)\release\lib
+     to the "additional library path" in the "input" section of the "link" settings
+* For a FORTRAN project add either  $(HDF4ROOT)\debug\lib,$(HDF5ROOT)\debug\lib   or
+                      $(HDF4ROOT)\debug\lib,$(HDF5ROOT)\release\lib
+     to the "additional library path" in the "input" section of the "link" settings
+* Add "wsock32.lib" (for the _htons at 4 symbols etc.) and "hdf5.lib"  to the list of
+  library modules to load.
+ 
+For a debug build only, you will have to add "libc.lib" to the list of library modules to ignore
+on the link input tab.
+
+Building your own projects with dynamic link libraries (DLL)
+------------------------------------------------------------
+
+For a working example, see the nxbrowse_dll project
+
+When building a program using the DLL version of the NeXus library 
+(NX45DLL.DLL) you will need to do the following to the project settings:
+
+* Set your C code generation options to use "debug multithreaded DLL" or "multithreaded DLL" libraries
+* set the FORTRAN libraries option to DLL
+* Add  HDF4  and/or  HDF5  to the C "preprocessor definitions"
+* Add either  $(HDF4ROOT)\include,$(HDF5ROOT)\c\debug\include  or   
+     $(HDF4ROOT)\include,$(HDF5ROOT)\c\release\include   to the C "additional include directories"
+     depending on whether you are building a debug or release project
+* For a C project add either   $(HDF4ROOT)\dlllibdbg,$(HDF5ROOT)\c\debug\dll   or
+                      $(HDF4ROOT)\dlllib,$(HDF5ROOT)\c\release\dll
+     to the "additional library path" in the "input" section of the "link" settings
+* For a FORTRAN project add either  $(HDF4ROOT)\dllibdbg,$(HDF5ROOT)\f90\debug\dll   or
+                      $(HDF4ROOT)\dlllib,$(HDF5ROOT)\f90\release\dll
+     to the "additional library path" in the "input" section of the "link" settings
+* Add "wsock32.lib" (for the _htons at 4 symbols etc.) and either "hdf5ddll.lib"  or  "hdf5dll.lib"
+  (depending on debug/release configuration) to the list of library modules to load.
+* Either add "nx45dll.lib" to the list of library modules to load in the link tab
+  or make your project "depend" on the "nx45dll" project (in which case it links to nx45dll.lib automatically)
+
+For a debug build only, you will have to add "msvcrt.lib" to the list of library 
+modules to ignore on the link input tab.
+
+When you run the program, you either need to have the DLL files in the same directory as the EXE file
+or you need to add the directories containing the DLL files to the PATH environment variable.
+
+Freddie Akeroyd (Freddie.Akeroyd at rl.ac.uk)
+ISIS Facility
+Rutherford Appleton Laboratory
+GB
+
+$Id$
\ No newline at end of file
diff --git a/windows/applications/nxbrowse/nxbrowse.vcproj b/windows/applications/nxbrowse/nxbrowse.vcproj
new file mode 100644
index 0000000..32e44c6
--- /dev/null
+++ b/windows/applications/nxbrowse/nxbrowse.vcproj
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxbrowse"
+	ProjectGUID="{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2}"
+	RootNamespace="nxbrowse"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXbrowse\NXbrowse.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/applications/nxconvert/nxconvert.vcproj b/windows/applications/nxconvert/nxconvert.vcproj
new file mode 100644
index 0000000..4738ee1
--- /dev/null
+++ b/windows/applications/nxconvert/nxconvert.vcproj
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxconvert"
+	ProjectGUID="{18711F84-2AB9-485F-83E1-6D497B99AE46}"
+	RootNamespace="nxconvert"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..;..\..\..\include;..\..\..\Windows_extra\include;..\..\..\bindings\cpp;..\..\..\third_party"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;HAVE_STRING_H"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..;..\..\..\include;..\..\..\Windows_extra\include;..\..\..\bindings\cpp;..\..\..\third_party"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;HAVE_STRING_H"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXconvert\nxconvert.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXconvert\nxconvert_common.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXconvert\nxconvert_common.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="windows"
+			>
+			<File
+				RelativePath="..\..\getopt.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\getopt.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/applications/nxdir/nxdir.vcproj b/windows/applications/nxdir/nxdir.vcproj
new file mode 100644
index 0000000..e1fb045
--- /dev/null
+++ b/windows/applications/nxdir/nxdir.vcproj
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxdir"
+	ProjectGUID="{F8522166-C439-4A12-8F5D-21FBF9752D9A}"
+	RootNamespace="nxdir"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXdir\data.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXdir\data_writer.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXdir\main.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXdir\string_util.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXdir\tree.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXdir\nxdir.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXdir\nxdir_help.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/applications/nxingest/nxingest.vcproj b/windows/applications/nxingest/nxingest.vcproj
new file mode 100644
index 0000000..a0aff28
--- /dev/null
+++ b/windows/applications/nxingest/nxingest.vcproj
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxingest"
+	ProjectGUID="{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F}"
+	RootNamespace="nxingest"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\..\mxml-2.6"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP) $(LIB_MXML)"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\..\mxml-2.6"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP) $(LIB_MXML)"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_debug.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_main.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_nexus.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_parse.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_time.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_utils.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_debug.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_main.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_nexus.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_parse.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_time.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\nxingest\nxingest_utils.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath="..\..\..\applications\nxingest\nxingest.txt"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/applications/nxsummary/nxsummary.vcproj b/windows/applications/nxsummary/nxsummary.vcproj
new file mode 100644
index 0000000..7d92b18
--- /dev/null
+++ b/windows/applications/nxsummary/nxsummary.vcproj
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxsummary"
+	ProjectGUID="{36209676-6DCA-4A3D-A092-C3858525691E}"
+	RootNamespace="nxsummary"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\;..\..\..\include;..\..\..\Windows_extra\include;..\..\..\..\libxml2-2.7.6\include;..\..\..\third_party;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;HAVE_STDINT_H"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wsock32.lib ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP) $(LIB_XML) "
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\;..\..\..\include;..\..\..\Windows_extra\include;..\..\..\..\libxml2-2.7.6\include;..\..\..\third_party;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;HAVE_STDINT_H"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wsock32.lib ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\data_util.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\main.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\output.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\preferences.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\string_util.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\data_util.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\nxsummary.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\output.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\preferences.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\string_util.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXsummary\xml_util.hpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="windows"
+			>
+			<File
+				RelativePath="..\..\stdint.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/applications/nxtranslate/nxtranslate.vcproj b/windows/applications/nxtranslate/nxtranslate.vcproj
new file mode 100644
index 0000000..338b06f
--- /dev/null
+++ b/windows/applications/nxtranslate/nxtranslate.vcproj
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxtranslate"
+	ProjectGUID="{24257BE2-5D00-47E6-9646-5DA534EA42DA}"
+	RootNamespace="nxtranslate"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include;..\..\..\..\libxml2-2.7.6\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wsock32.lib ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)  $(LIB_XML) "
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include;..\..\..\..\libxml2-2.7.6\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wsock32.lib ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)  $(LIB_XML) "
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\attr.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\dynamic_retriever.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\main.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\nexus_retriever.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\nexus_util.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\node.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\node_util.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\retriever.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\string_util.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\xml_parser.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\xml_util.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\attr.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\dynamic_retriever.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\nexus_retriever.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\nexus_util.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\node.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\node_util.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\nxtranslate_debug.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\Ptr.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\retriever.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\string_util.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\tree.hh"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\xml_parser.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\applications\NXtranslate\xml_util.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/applications/nxtraverse/nxtraverse.vcproj b/windows/applications/nxtraverse/nxtraverse.vcproj
new file mode 100644
index 0000000..ee422a9
--- /dev/null
+++ b/windows/applications/nxtraverse/nxtraverse.vcproj
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nxtraverse"
+	ProjectGUID="{29E8655E-4EC7-4574-B6A5-503E645ACC8C}"
+	RootNamespace="nxtraverse"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib $(LIB_HDF5) $(LIB_ZLIB) $(LIB_SZIP)"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath="..\..\..\applications\NXtraverse\main.cpp"
+			>
+		</File>
+		<File
+			RelativePath="..\..\..\applications\NXtraverse\nxtraverse.cpp"
+			>
+		</File>
+		<File
+			RelativePath="..\..\..\applications\NXtraverse\nxtraverse.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/bindings/cpp/nexusCPP.vcproj b/windows/bindings/cpp/nexusCPP.vcproj
new file mode 100644
index 0000000..9d73f28
--- /dev/null
+++ b/windows/bindings/cpp/nexusCPP.vcproj
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nexusCPP"
+	ProjectGUID="{7B8601AD-2E15-4091-9987-13D3A3E9D001}"
+	RootNamespace="nexusCPP"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\..\include;..\..\..\Windows_extra\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\bindings\cpp\NeXusException.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\bindings\cpp\NeXusFile.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\bindings\cpp\NeXusStream.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\bindings\cpp\NeXusException.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\bindings\cpp\NeXusFile.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\bindings\cpp\NeXusStream.hpp"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/getopt.c b/windows/getopt.c
new file mode 100644
index 0000000..82e4f56
--- /dev/null
+++ b/windows/getopt.c
@@ -0,0 +1,1052 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper at gnu.org
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+   	Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+

+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+# ifdef HAVE_LIBINTL_H
+#  include <libintl.h>
+#  define _(msgid)	gettext (msgid)
+# else
+#  define _(msgid)	(msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+

+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index	strchr
+#else
+
+# if HAVE_STRING_H
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+

+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)						      \
+    {									      \
+      char __tmp = __getopt_nonoption_flags[ch1];			      \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \
+      __getopt_nonoption_flags[ch2] = __tmp;				      \
+    }
+#else	/* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif	/* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+	 presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+	nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+	{
+	  memset (__mempcpy (new_str, __getopt_nonoption_flags,
+			     nonoption_flags_max_len),
+		  '\0', top + 1 - nonoption_flags_max_len);
+	  nonoption_flags_max_len = top + 1;
+	  __getopt_nonoption_flags = new_str;
+	}
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	      SWAP_FLAGS (bottom + i, middle + i);
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+	{
+	  if (__getopt_nonoption_flags == NULL
+	      || __getopt_nonoption_flags[0] == '\0')
+	    nonoption_flags_max_len = -1;
+	  else
+	    {
+	      const char *orig_str = __getopt_nonoption_flags;
+	      int len = nonoption_flags_max_len = strlen (orig_str);
+	      if (nonoption_flags_max_len < argc)
+		nonoption_flags_max_len = argc;
+	      __getopt_nonoption_flags =
+		(char *) malloc (nonoption_flags_max_len);
+	      if (__getopt_nonoption_flags == NULL)
+		nonoption_flags_max_len = -1;
+	      else
+		memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+			'\0', nonoption_flags_max_len - len);
+	    }
+	}
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+

+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int print_errors = opterr;
+  if (optstring[0] == ':')
+    print_errors = 0;
+
+  optarg = NULL;
+
+  if (optind == 0 || !__getopt_initialized)
+    {
+      if (optind == 0)
+	optind = 1;	/* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		      || (optind < nonoption_flags_len			      \
+			  && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+	last_nonopt = optind;
+      if (first_nonopt > optind)
+	first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc && NONOPTION_P)
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((unsigned int) (nameend - nextchar)
+		== (unsigned int) strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (print_errors)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (print_errors)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+				 _("%s: option `--%s' doesn't allow an argument\n"),
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+				 _("%s: option `%c%s' doesn't allow an argument\n"),
+				 argv[0], argv[optind - 1][0], pfound->name);
+		    }
+
+		  nextchar += strlen (nextchar);
+
+		  optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (print_errors)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (print_errors)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (print_errors)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct option *p;
+	const struct option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    optind++;
+	  }
+	else if (optind == argc)
+	  {
+	    if (print_errors)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  optarg = argv[optind++];
+
+	/* optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (print_errors)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[optind]);
+	    nextchar += strlen (nextchar);
+	    optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  optarg = nameend + 1;
+		else
+		  {
+		    if (print_errors)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (optind < argc)
+		  optarg = argv[optind++];
+		else
+		  {
+		    if (print_errors)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (print_errors)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			     _("%s: option requires an argument -- %c\n"),
+			     argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt ( int argc, char *const *argv, const char *optstring)
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* Not ELIDE_CODE.  */
+

+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/windows/getopt.h b/windows/getopt.h
new file mode 100644
index 0000000..91643cc
--- /dev/null
+++ b/windows/getopt.h
@@ -0,0 +1,170 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public
+   License along with the GNU C Library; see the file COPYING.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+
+#ifndef __need_getopt
+# define _GETOPT_H 1
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+#ifndef __need_getopt
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+# if defined __STDC__ && __STDC__
+  const char *name;
+# else
+  char *name;
+# endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+# define no_argument		0
+# define required_argument	1
+# define optional_argument	2
+#endif	/* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+   arguments in ARGV (ARGC of them, minus the program name) for
+   options given in OPTS.
+
+   Return the option character from OPTS just read.  Return -1 when
+   there are no more options.  For unrecognized options, or options
+   missing arguments, `optopt' is set to the option letter, and '?' is
+   returned.
+
+   The OPTS string is a list of characters which are recognized option
+   letters, optionally followed by colons, specifying that that letter
+   takes an argument, to be placed in `optarg'.
+
+   If a letter in OPTS is followed by two colons, its argument is
+   optional.  This behavior is specific to the GNU `getopt'.
+
+   The argument `--' causes premature termination of argument
+   scanning, explicitly telling `getopt' that there are no more
+   options.
+
+   If OPTS begins with `--', then non-option arguments are treated as
+   arguments to the option '\0'.  This behavior is specific to the GNU
+   `getopt'.  */
+
+#if defined __STDC__ && __STDC__
+# ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
+# else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+# endif /* __GNU_LIBRARY__ */
+
+# ifndef __need_getopt
+extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
+		        const struct option *__longopts, int *__longind);
+extern int getopt_long_only (int __argc, char *const *__argv,
+			     const char *__shortopts,
+		             const struct option *__longopts, int *__longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int __argc, char *const *__argv,
+			     const char *__shortopts,
+		             const struct option *__longopts, int *__longind,
+			     int __long_only);
+# endif
+#else /* not __STDC__ */
+extern int
+getopt ( int argc, char *const *argv, const char *optstring);
+# ifndef __need_getopt
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+# endif
+#endif /* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations.  */
+#undef __need_getopt
+
+#endif /* getopt.h */
diff --git a/windows/makefile.mingw b/windows/makefile.mingw
new file mode 100644
index 0000000..34fa3ee
--- /dev/null
+++ b/windows/makefile.mingw
@@ -0,0 +1,89 @@
+#====================================================================
+#  NeXus - Neutron & X-ray Common Data Format
+#  
+#  Makefile for compiling NeXus with MinGW gcc/g77 distribution 
+#  (see http://www.mingw.org/ for compiler details)
+#
+#  run this file with:      mingw32-make -f makefile.mingw
+#  
+#  Copyright (C) 2002 Freddie Akeroyd, CCLRC Rutherford Appleton Laboratory
+#  
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+# 
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+# 
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free 
+#  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+#  MA  02111-1307  USA
+#             
+#  For further information, see <http://www.nexusformat.org>
+#
+#  $Id$
+#
+#====================================================================
+
+#
+# set these values for your HDF distribution
+#
+HDF4ROOT=c:\program files\hdf41r5
+HDFLIBS=-lhm415m -lhd415m
+
+#
+# these should not need to be changed
+#
+LIBNEXUS_OBJ=napi.o napif.o
+TEST4_OBJ=napi4_test.o
+NXBROWSE_OBJ=NXbrowse.o
+NXTOXML_OBJ=NXtoXML.o
+NXTODTD_OBJ=NXtoDTD.o
+CC=gcc
+FC=g77
+EXTRA_LIBS=-lwsock32 -lg2c
+#
+
+all: nexusdll.lib napif_test napi4_test NXbrowse NXtoXML NXtoDTD
+
+napi.o : napi.c
+	$(CC) -c -DHDF4 -D__unix -D_WIN32 -D_DLL -DNX45DLL_EXPORTS -I"$(HDF4ROOT)\include" $<
+
+.c.o :
+	$(CC) -c -DHDF4 -D__unix -D_WIN32 -D_DLL -I"$(HDF4ROOT)\include" $<
+
+.f.o :
+	g77 -c $<
+
+#
+# nexusdll.lib is the DLL import library to link your program against.
+# At run time, your program will then need access to nexus.dll
+#
+nexusdll.lib : $(LIBNEXUS_OBJ)
+	- rm -f $@
+	dllwrap --output-lib=$@ --export-all-symbols --dllname=nexus.dll --driver-name=gcc \
+		$(LIBNEXUS_OBJ) -L"$(HDF4ROOT)\dlllib" $(HDFLIBS) $(EXTRA_LIBS)
+	
+napi4_test : nexusdll.lib $(TEST4_OBJ)
+	$(CC) $(CFLAGS) -o napi4_test $(TEST4_OBJ) nexusdll.lib \
+	-L"$(HDF4ROOT)\dlllib" $(HDFLIBS) $(EXTRA_LIBS) 
+
+napif_test: nexusdll.lib napif_test.o
+	$(FC) $(FFLAGS) -o napif_test napif_test.o nexusdll.lib \
+	-L"$(HDF4ROOT)\dlllib" -lfrtbegin $(HDFLIBS) $(EXTRA_LIBS)
+	
+NXbrowse: nexusdll.lib $(NXBROWSE_OBJ) 
+	$(CC) $(CFLAGS) -o NXbrowse $(NXBROWSE_OBJ) nexusdll.lib \
+	-L"$(HDF4ROOT)\dlllib" $(HDFLIBS) $(EXTRA_LIBS) 
+
+NXtoXML: nexusdll.lib $(NXTOXML_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoXML $(NXTOXML_OBJ) nexusdll.lib \
+	-L"$(HDF4ROOT)\dlllib" $(HDFLIBS) $(EXTRA_LIBS)
+
+NXtoDTD: nexusdll.lib $(NXTODTD_OBJ) 
+	$(CC) $(CFLAGS) -o NXtoDTD $(NXTODTD_OBJ) nexusdll.lib \
+	-L"$(HDF4ROOT)\dlllib" $(HDFLIBS) $(EXTRA_LIBS)
diff --git a/windows/napi4_test/napi4_test.dsp b/windows/napi4_test/napi4_test.dsp
new file mode 100644
index 0000000..91d5f6c
--- /dev/null
+++ b/windows/napi4_test/napi4_test.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="napi4_test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=napi4_test - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "napi4_test.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "napi4_test.mak" CFG="napi4_test - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "napi4_test - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "napi4_test - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "napi4_test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF4ROOT)\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386 /libpath:"$(hdf4root)\lib"
+
+!ELSEIF  "$(CFG)" == "napi4_test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF4ROOT)\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"$(hdf4root)\libdbg"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "napi4_test - Win32 Release"
+# Name "napi4_test - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\napi4_test.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/napi5_test/napi5_test.dsp b/windows/napi5_test/napi5_test.dsp
new file mode 100644
index 0000000..68b5e5a
--- /dev/null
+++ b/windows/napi5_test/napi5_test.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="napi5_test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=napi5_test - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "napi5_test.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "napi5_test.mak" CFG="napi5_test - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "napi5_test - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "napi5_test - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "napi5_test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF5ROOT)\c\release\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib zlib.lib /nologo /subsystem:console /machine:I386 /libpath:"$(HDF5ROOT)\c\release\lib" /libpath:"$(HDF4ROOT)\lib"
+
+!ELSEIF  "$(CFG)" == "napi5_test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF5ROOT)\c\debug\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib zlib.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"$(HDF5ROOT)\c\debug\lib" /libpath:"$(HDF4ROOT)\libdbg"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "napi5_test - Win32 Release"
+# Name "napi5_test - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\napi5_test.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/napif_test/napif_test.dsp b/windows/napif_test/napif_test.dsp
new file mode 100644
index 0000000..db3f65f
--- /dev/null
+++ b/windows/napif_test/napif_test.dsp
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="napif_test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=napif_test - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "napif_test.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "napif_test.mak" CFG="napif_test - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "napif_test - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "napif_test - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "napif_test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib /nologo /subsystem:console /machine:I386 /libpath:"$(hdf4root)\lib" /libpath:"$(hdf5root)\f90\release\lib"
+
+!ELSEIF  "$(CFG)" == "napif_test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /include:"..\..\bindings\f77" /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib szlib.lib zdll.lib libjpeg.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\lib" /libpath:"$(HDF5ROOT)\debug\lib" /libpath:"$(SZIPROOT)\lib" /libpath:"$(ZLIBROOT)\lib" /libpath:"$(JPEGROOT)"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "napif_test - Win32 Release"
+# Name "napif_test - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\test\napif_test.f
+DEP_F90_NAPIF=\
+	"..\..\bindings\f77\napif.inc"\
+	
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\bindings\f77\napif.inc
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/nexus.dsw b/windows/nexus.dsw
new file mode 100644
index 0000000..1426763
--- /dev/null
+++ b/windows/nexus.dsw
@@ -0,0 +1,182 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "napi_test"=.\napi_test\napi_test.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nexus45
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "napif_test"=.\napif_test\napif_test.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nexus45
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "nexus4"=.\nexus4\nexus4.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "nexus45"=.\nexus45\nexus45.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "nexus5"=.\nexus5\nexus5.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "nexusf90"=.\nexusf90\nexusf90.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "nx45dll"=.\nx45dll\nx45dll.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "nxbrowse"=.\nxbrowse\nxbrowse.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nexus45
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "nxbrowse_dll"=.\nxbrowse_dll\nxbrowse_dll.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nx45dll
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "nxtest90"=.\nxtest90\nxtest90.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nexusf90
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "nxtodtd"=.\nxtodtd\nxtodtd.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nexus45
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "nxtoxml"=.\nxtoxml\nxtoxml.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name nexus45
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/windows/nexus.sln b/windows/nexus.sln
new file mode 100644
index 0000000..c9fb7db
--- /dev/null
+++ b/windows/nexus.sln
@@ -0,0 +1,109 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nexus", "nexus", "{B801D71F-83AF-450C-BD44-CB83A6D71F7B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "applications", "applications", "{0CF0043F-0D45-45FF-AB21-8937A6F234C5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C51F72F9-9962-4BC6-8184-41E42AF0D2D4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nexus", "nexus\nexus.vcproj", "{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxbrowse", "applications\nxbrowse\nxbrowse.vcproj", "{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2}"
+	ProjectSection(ProjectDependencies) = postProject
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bindings", "bindings", "{AAE7C9A7-CE8A-4BE6-9AA4-7914C6425AF6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxdir", "applications\nxdir\nxdir.vcproj", "{F8522166-C439-4A12-8F5D-21FBF9752D9A}"
+	ProjectSection(ProjectDependencies) = postProject
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nexusCPP", "bindings\cpp\nexusCPP.vcproj", "{7B8601AD-2E15-4091-9987-13D3A3E9D001}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxconvert", "applications\nxconvert\nxconvert.vcproj", "{18711F84-2AB9-485F-83E1-6D497B99AE46}"
+	ProjectSection(ProjectDependencies) = postProject
+		{7B8601AD-2E15-4091-9987-13D3A3E9D001} = {7B8601AD-2E15-4091-9987-13D3A3E9D001}
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxingest", "applications\nxingest\nxingest.vcproj", "{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F}"
+	ProjectSection(ProjectDependencies) = postProject
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxsummary", "applications\nxsummary\nxsummary.vcproj", "{36209676-6DCA-4A3D-A092-C3858525691E}"
+	ProjectSection(ProjectDependencies) = postProject
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxtranslate", "applications\nxtranslate\nxtranslate.vcproj", "{24257BE2-5D00-47E6-9646-5DA534EA42DA}"
+	ProjectSection(ProjectDependencies) = postProject
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nxtraverse", "applications\nxtraverse\nxtraverse.vcproj", "{29E8655E-4EC7-4574-B6A5-503E645ACC8C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}.Debug|Win32.Build.0 = Debug|Win32
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}.Release|Win32.ActiveCfg = Release|Win32
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}.Release|Win32.Build.0 = Release|Win32
+		{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2}.Debug|Win32.Build.0 = Debug|Win32
+		{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2}.Release|Win32.ActiveCfg = Release|Win32
+		{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2}.Release|Win32.Build.0 = Release|Win32
+		{F8522166-C439-4A12-8F5D-21FBF9752D9A}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F8522166-C439-4A12-8F5D-21FBF9752D9A}.Debug|Win32.Build.0 = Debug|Win32
+		{F8522166-C439-4A12-8F5D-21FBF9752D9A}.Release|Win32.ActiveCfg = Release|Win32
+		{F8522166-C439-4A12-8F5D-21FBF9752D9A}.Release|Win32.Build.0 = Release|Win32
+		{7B8601AD-2E15-4091-9987-13D3A3E9D001}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7B8601AD-2E15-4091-9987-13D3A3E9D001}.Debug|Win32.Build.0 = Debug|Win32
+		{7B8601AD-2E15-4091-9987-13D3A3E9D001}.Release|Win32.ActiveCfg = Release|Win32
+		{7B8601AD-2E15-4091-9987-13D3A3E9D001}.Release|Win32.Build.0 = Release|Win32
+		{18711F84-2AB9-485F-83E1-6D497B99AE46}.Debug|Win32.ActiveCfg = Debug|Win32
+		{18711F84-2AB9-485F-83E1-6D497B99AE46}.Debug|Win32.Build.0 = Debug|Win32
+		{18711F84-2AB9-485F-83E1-6D497B99AE46}.Release|Win32.ActiveCfg = Release|Win32
+		{18711F84-2AB9-485F-83E1-6D497B99AE46}.Release|Win32.Build.0 = Release|Win32
+		{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F}.Debug|Win32.Build.0 = Debug|Win32
+		{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F}.Release|Win32.ActiveCfg = Release|Win32
+		{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F}.Release|Win32.Build.0 = Release|Win32
+		{36209676-6DCA-4A3D-A092-C3858525691E}.Debug|Win32.ActiveCfg = Debug|Win32
+		{36209676-6DCA-4A3D-A092-C3858525691E}.Debug|Win32.Build.0 = Debug|Win32
+		{36209676-6DCA-4A3D-A092-C3858525691E}.Release|Win32.ActiveCfg = Release|Win32
+		{36209676-6DCA-4A3D-A092-C3858525691E}.Release|Win32.Build.0 = Release|Win32
+		{24257BE2-5D00-47E6-9646-5DA534EA42DA}.Debug|Win32.ActiveCfg = Debug|Win32
+		{24257BE2-5D00-47E6-9646-5DA534EA42DA}.Debug|Win32.Build.0 = Debug|Win32
+		{24257BE2-5D00-47E6-9646-5DA534EA42DA}.Release|Win32.ActiveCfg = Release|Win32
+		{24257BE2-5D00-47E6-9646-5DA534EA42DA}.Release|Win32.Build.0 = Release|Win32
+		{29E8655E-4EC7-4574-B6A5-503E645ACC8C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{29E8655E-4EC7-4574-B6A5-503E645ACC8C}.Debug|Win32.Build.0 = Debug|Win32
+		{29E8655E-4EC7-4574-B6A5-503E645ACC8C}.Release|Win32.ActiveCfg = Release|Win32
+		{29E8655E-4EC7-4574-B6A5-503E645ACC8C}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C} = {B801D71F-83AF-450C-BD44-CB83A6D71F7B}
+		{C6712742-F924-4CD0-B6AD-7E5EA41B5AF2} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{F8522166-C439-4A12-8F5D-21FBF9752D9A} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{18711F84-2AB9-485F-83E1-6D497B99AE46} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{513664B0-C41F-4F75-A8A4-8A8F1BB57E6F} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{36209676-6DCA-4A3D-A092-C3858525691E} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{24257BE2-5D00-47E6-9646-5DA534EA42DA} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{29E8655E-4EC7-4574-B6A5-503E645ACC8C} = {0CF0043F-0D45-45FF-AB21-8937A6F234C5}
+		{7B8601AD-2E15-4091-9987-13D3A3E9D001} = {AAE7C9A7-CE8A-4BE6-9AA4-7914C6425AF6}
+	EndGlobalSection
+EndGlobal
diff --git a/windows/nexus/nexus.vcproj b/windows/nexus/nexus.vcproj
new file mode 100644
index 0000000..ad1f0c8
--- /dev/null
+++ b/windows/nexus/nexus.vcproj
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="nexus"
+	ProjectGUID="{143DDBCE-F277-4D1A-9B4B-94BE2ECEAD7C}"
+	RootNamespace="nexus"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=" $(HEADER_HDF5) ;..\..\include;..\..\Windows_extra\include"
+				PreprocessorDefinitions="HDF5;H5_USE_16_API;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\Windows_extra\include"
+				PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="src"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\napi.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\napi4.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\napi5.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\napiu.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxdataset.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxio.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxstack.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxxml.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\stptok.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="header"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\src\nx_stptok.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxdataset.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxio.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\nxstack.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="include"
+			>
+			<File
+				RelativePath="..\..\include\napi.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\napi4.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\napi5.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\napiconfig.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\napiu.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\nxxml.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Windows_extra"
+			>
+			<Filter
+				Name="include"
+				>
+				<File
+					RelativePath="..\..\Windows_extra\include\nxconfig.h"
+					>
+				</File>
+			</Filter>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/windows/nexus4/nexus4.dsp b/windows/nexus4/nexus4.dsp
new file mode 100644
index 0000000..492087c
--- /dev/null
+++ b/windows/nexus4/nexus4.dsp
@@ -0,0 +1,125 @@
+# Microsoft Developer Studio Project File - Name="nexus4" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=nexus4 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nexus4.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nexus4.mak" CFG="nexus4 - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nexus4 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "nexus4 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nexus4 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF4ROOT)\release\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HDF4" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "nexus4 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF4ROOT)\debug\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HDF4" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nexus4 - Win32 Release"
+# Name "nexus4 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\src\napi.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi4.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f77\napif.f
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napiu.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napiu.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/windows/nexus45/nexus45.dsp b/windows/nexus45/nexus45.dsp
new file mode 100644
index 0000000..eceffdd
--- /dev/null
+++ b/windows/nexus45/nexus45.dsp
@@ -0,0 +1,133 @@
+# Microsoft Developer Studio Project File - Name="nexus45" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=nexus45 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nexus45.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nexus45.mak" CFG="nexus45 - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nexus45 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "nexus45 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nexus45 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF5ROOT)\release\include" /I "$(HDF4ROOT)\release\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HDF4" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "nexus45 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF5ROOT)\debug\include" /I "$(HDF4ROOT)\debug\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HDF4" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nexus45 - Win32 Release"
+# Name "nexus45 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\src\napi.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi4.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f77\napif.f
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napiu.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napiu.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/windows/nexus5/nexus5.dsp b/windows/nexus5/nexus5.dsp
new file mode 100644
index 0000000..b5d2932
--- /dev/null
+++ b/windows/nexus5/nexus5.dsp
@@ -0,0 +1,129 @@
+# Microsoft Developer Studio Project File - Name="nexus5" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=nexus5 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nexus5.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nexus5.mak" CFG="nexus5 - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nexus5 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "nexus5 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nexus5 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF5ROOT)\release\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "nexus5 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF5ROOT)\debug\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nexus5 - Win32 Release"
+# Name "nexus5 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\src\napi.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f77\napif.f
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napiu.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napiu.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/windows/nexusf90/nexusf90.dsp b/windows/nexusf90/nexusf90.dsp
new file mode 100644
index 0000000..3d0b450
--- /dev/null
+++ b/windows/nexusf90/nexusf90.dsp
@@ -0,0 +1,144 @@
+# Microsoft Developer Studio Project File - Name="nexusf90" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=nexusf90 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nexusf90.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nexusf90.mak" CFG="nexusf90 - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nexusf90 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "nexusf90 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nexusf90 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /I "$(HDF5ROOT)\release\include" /I "$(HDF4ROOT)\release\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "nexusf90 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\include" /I "$(HDF4ROOT)\debug\include" /I "$(HDF5ROOT)\debug\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nexusf90 - Win32 Release"
+# Name "nexusf90 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\src\napi.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi4.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f77\napif.f
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napiu.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f90\NXmodule.f90
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f90\NXUmodule.f90
+DEP_F90_NXUMO=\
+	".\Debug\NXmodule.mod"\
+	
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napiu.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/windows/nx45dll/nx45dll.dsp b/windows/nx45dll/nx45dll.dsp
new file mode 100644
index 0000000..925411f
--- /dev/null
+++ b/windows/nx45dll/nx45dll.dsp
@@ -0,0 +1,144 @@
+# Microsoft Developer Studio Project File - Name="nx45dll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=nx45dll - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nx45dll.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nx45dll.mak" CFG="nx45dll - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nx45dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "nx45dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nx45dll - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /dll /nologo /warn:nofileopt
+# ADD F90 /compile_only /dll /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NX45DLL_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "$(HDF4ROOT)\release\include" /I "$(HDF5ROOT)\release\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NX45DLL_EXPORTS" /D "HDF4" /D "HDF5" /D "_HDF5USEDLL_" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5dll.lib /nologo /dll /machine:I386 /libpath:"$(HDF4ROOT)\dlllib" /libpath:"$(HDF5ROOT)\dll"
+
+!ELSEIF  "$(CFG)" == "nx45dll - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /dll /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /dll /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NX45DLL_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "$(HDF4ROOT)\debug\include" /I "$(HDF5ROOT)\debug\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NX45DLL_EXPORTS" /D "HDF4" /D "HDF5" /D "_HDF5USEDLL_" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5dll.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\dll" /libpath:"$(HDF5ROOT)\debug\dll"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nx45dll - Win32 Release"
+# Name "nx45dll - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\src\napi.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi4.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napi5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bindings\f77\napif.f
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\napiu.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napi5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\napiu.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/nxbrowse/nxbrowse.dsp b/windows/nxbrowse/nxbrowse.dsp
new file mode 100644
index 0000000..0bbc434
--- /dev/null
+++ b/windows/nxbrowse/nxbrowse.dsp
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="nxbrowse" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=nxbrowse - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nxbrowse.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nxbrowse.mak" CFG="nxbrowse - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nxbrowse - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "nxbrowse - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nxbrowse - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF4ROOT)\release\include" /I "$(HDF5ROOT)\release\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib /nologo /subsystem:console /machine:I386 /libpath:"$(HDF4ROOT)\lib" /libpath:"$(HDF5ROOT)\c\release\lib"
+
+!ELSEIF  "$(CFG)" == "nxbrowse - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF4ROOT)\debug\include" /I "$(HDF5ROOT)\debug\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib  hdf5.lib szlib.lib zdll.lib libjpeg.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\lib" /libpath:"$(HDF5ROOT)\de [...]
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nxbrowse - Win32 Release"
+# Name "nxbrowse - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\applications\NXbrowse.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/nxbrowse_dll/nxbrowse_dll.dsp b/windows/nxbrowse_dll/nxbrowse_dll.dsp
new file mode 100644
index 0000000..d419b8c
--- /dev/null
+++ b/windows/nxbrowse_dll/nxbrowse_dll.dsp
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="nxbrowse_dll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=nxbrowse_dll - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nxbrowse_dll.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nxbrowse_dll.mak" CFG="nxbrowse_dll - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nxbrowse_dll - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "nxbrowse_dll - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nxbrowse_dll - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "$(HDF4ROOT)\release\include" /I "$(HDF5ROOT)\release\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5dll.lib /nologo /subsystem:console /machine:I386 /libpath:"$(HDF4ROOT)\dlllib" /libpath:"$(HDF5ROOT)\c\release\dll"
+
+!ELSEIF  "$(CFG)" == "nxbrowse_dll - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "$(HDF4ROOT)\debug\include" /I "$(HDF5ROOT)\debug\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5dll.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\dll" /libpath:"$(HDF5ROOT)\debug\dll" /libpath:"$(SZIPRO [...]
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy ..\nx45dll\debug\nx45dll.dll debug
+# End Special Build Tool
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nxbrowse_dll - Win32 Release"
+# Name "nxbrowse_dll - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\applications\NXbrowse.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/nxtest90/nxtest90.dsp b/windows/nxtest90/nxtest90.dsp
new file mode 100644
index 0000000..43da861
--- /dev/null
+++ b/windows/nxtest90/nxtest90.dsp
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="nxtest90" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=nxtest90 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nxtest90.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nxtest90.mak" CFG="nxtest90 - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nxtest90 - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "nxtest90 - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nxtest90 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib /nologo /subsystem:console /machine:I386 /libpath:"$(HDF4ROOT)/lib" /libpath:"$(HDF5ROOT)\f90\release\lib"
+
+!ELSEIF  "$(CFG)" == "nxtest90 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /include:"..\nexusf90\debug" /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib  hdf5.lib szlib.lib zdll.lib libjpeg.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\lib" /libpath:"$(HDF5ROOT)\debug\lib" /libpath:"$(SZIPROOT)\lib" /libpath:"$(ZLIBROOT)\lib" /libpath:"$(JPEGROOT)"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nxtest90 - Win32 Release"
+# Name "nxtest90 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\test\NXtest.f90
+NODEP_F90_NXTES=\
+	".\Debug\NXmodule.mod"\
+	
+
+!IF  "$(CFG)" == "nxtest90 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "nxtest90 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/nxtodtd/nxtodtd.dsp b/windows/nxtodtd/nxtodtd.dsp
new file mode 100644
index 0000000..f585890
--- /dev/null
+++ b/windows/nxtodtd/nxtodtd.dsp
@@ -0,0 +1,109 @@
+# Microsoft Developer Studio Project File - Name="nxtodtd" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=nxtodtd - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nxtodtd.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nxtodtd.mak" CFG="nxtodtd - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nxtodtd - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "nxtodtd - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nxtodtd - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF4ROOT)\release\include" /I "$(HDF5ROOT)\release\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib /nologo /subsystem:console /machine:I386 /libpath:"$(HDF4ROOT)\lib" /libpath:"$(HDF5ROOT)\c\release\lib"
+
+!ELSEIF  "$(CFG)" == "nxtodtd - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\include" /I "$(HDF4ROOT)\debug\include" /I "$(HDF5ROOT)\debug\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  wsock32.lib  hdf5.lib szlib.lib zdll.lib libjpeg.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\lib" /libpath:"$(HDF5ROOT)\d [...]
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nxtodtd - Win32 Release"
+# Name "nxtodtd - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\applications\NXtoDTD.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/nxtoxml/nxtoxml.dsp b/windows/nxtoxml/nxtoxml.dsp
new file mode 100644
index 0000000..45eb051
--- /dev/null
+++ b/windows/nxtoxml/nxtoxml.dsp
@@ -0,0 +1,109 @@
+# Microsoft Developer Studio Project File - Name="nxtoxml" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=nxtoxml - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nxtoxml.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nxtoxml.mak" CFG="nxtoxml - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nxtoxml - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "nxtoxml - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+F90=df.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nxtoxml - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE F90 /compile_only /nologo /warn:nofileopt
+# ADD F90 /compile_only /nologo /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "$(HDF4ROOT)\release\include" /I "$(HDF5ROOT)\release\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib hdf5.lib /nologo /subsystem:console /machine:I386 /libpath:"$(HDF4ROOT)\lib" /libpath:"$(HDF5ROOT)\c\release\lib"
+
+!ELSEIF  "$(CFG)" == "nxtoxml - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD F90 /check:bounds /compile_only /debug:full /nologo /traceback /warn:argument_checking /warn:nofileopt
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "$(HDF4ROOT)\debug\include" /I "$(HDF5ROOT)\debug\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HDF4" /D "HDF5" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  wsock32.lib  hdf5.lib szlib.lib zdll.lib libjpeg.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"$(HDF4ROOT)\debug\lib" /libpath:"$(HDF5ROOT)\d [...]
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nxtoxml - Win32 Release"
+# Name "nxtoxml - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
+# Begin Source File
+
+SOURCE=..\..\applications\NXtoXML.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=..\..\include\napi.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/windows/stdint.h b/windows/stdint.h
new file mode 100644
index 0000000..48914d3
--- /dev/null
+++ b/windows/stdint.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, P.Vicente <pedro.vicente at space-research.org>
+ *               
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#ifndef STD_INT_H
+#define STD_INT_H
+
+typedef signed char             int8_t;
+typedef short int               int16_t;
+typedef int                     int32_t;
+typedef unsigned char           uint8_t;
+typedef unsigned short int      uint16_t;
+typedef unsigned int            uint32_t;
+#ifdef _MSC_VER
+typedef signed __int64          int64_t; 
+typedef unsigned __int64        uint64_t;
+#endif //_MSC_VER
+
+#endif //H5_NEXUS_H

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/nexus.git



More information about the debian-science-commits mailing list